mcp server
claude-code-blog-generator
Transform Claude Code sessions into engaging, educational blog posts with intelligent narrative chunking and PII redaction
Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- Node.js 20 or newer
{
"mcpServers": {
"claude-code-blog-generator": {
"command": "npx",
"args": [
"-y",
"claude-code-blog-generator"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 21, 2026ccblog
A Claude Code session toolkit: search, distill, and publish your history.
Why?
Your ~/.claude/projects/ is hundreds of megabytes of .jsonl transcripts — unsearchable, unreadable, and expensive to point Claude at. ccblog turns that archive into something useful:
- 🔎 Search — BM25 full-text search over every past session. Sub-ms queries. No API key needed.
- 🪞 Reflect — weekly retrospective with citations to actual sessions.
- 🛠️ Compound — mine many sessions for new skills, memories, CLAUDE.md rules, and anti-patterns to fix. Every change makes the next session faster.
- 🧠 Learn — extract structured learnings so future agents can query "have we solved this before?"
- ✍️ Publish — generate polished blog posts + interactive HTML viewers from any session.
- 📊 Telemetry — see which Skills you actually use vs. which are dead weight.
All local. All optional. Search works offline with zero network calls.
Quick Start
npm install -g github:varadhjain/claude-code-blog-generator
# Search (no API key required — fully local BM25 over SQLite FTS5)
ccblog index # one-time: build the search index
ccblog search "auth bug" # find past sessions by topic
ccblog watch # keep the index live-updated
# Reflect + compound (requires an API key)
ccblog --setup # picks Anthropic or OpenAI
ccblog reflect --since 7d # weekly retro with citations
ccblog propose-skills --since 30d # mine repeated workflows → draft skills
ccblog propose-memories --since 30d # durable facts → memory entries
ccblog anti-patterns --since 30d # rediscovery / manual-toil / wrong-tool waste
# Single-session blog
ccblog # interactive: session → blog post
Search is free and instant. Blog/learn features prefer OpenAI GPT-6 Luna, with Anthropic retained as a fallback when no OpenAI key is present.
What You Get
Session .jsonl → ccblog → 4 files:
├── SUMMARY.md Narrative blog post
├── summary.html Formatted blog
├── index.html Interactive annotated viewer
└── page-*.html Paginated full conversation
Blog summary includes:
- Session goal and outcome (synthesized, not just copied)
- ASCII flow diagram
- Phases with specific names like "Fixing token exhaustion: 1000→8000 tokens"
- Key prompts color-coded: new task / steering / pivot
- Code snippets from tool uses
- Deep links to exact conversation moments
Search (no API key)
BM25 full-text index over every session in ~/.claude/projects/ and ~/.codex/sessions/. Sub-ms queries. Zero network calls. The index lives at ~/.ccblog/session-index.db and filters out tool_result blobs (which make JSONL huge but rarely help search).
ccblog index # build/update the index (incremental)
ccblog watch # initial index + live tail on JSONL appends
ccblog search "jwt middleware" # BM25 search — ranked results + snippets
ccblog files "src/auth/middleware.ts" # every session that touched a file
ccblog sessions # 20 most recent sessions
Codex CLI support. Sessions from OpenAI's Codex CLI (~/.codex/sessions/YYYY/MM/DD/*.jsonl) are indexed alongside Claude Code sessions. Each result has a source: 'claude-code' | 'codex' field. The indexer auto-detects both — no flag required.
Current Codex rollout messages retain their timestamps without duplicate event echoes. System/developer context, analysis and tool outputs are excluded. Mind workspace transcripts, conversations explicitly mentioning the Mind domain, and Codex sessions without a known workspace are excluded from indexing and automatic proposals. Updating the reader rebuilds only derived Codex rows; original logs and Claude rows are retained.
Tuning: four BM25 field weights in src/search/weights.ts control ranking (user text, assistant text, tool calls, file paths). No reindex needed after changes.
Reflect — weekly retrospective
ccblog reflect # last 7 days, honest tone
ccblog reflect --since 14d # custom window (Nd, Nw, Nh)
ccblog reflect --project investing # narrow to one project
ccblog reflect --tone gentle # gentle / honest (default) / sharp
ccblog reflect --since 7d --dry-run # print the digest, skip the LLM
Pulls every session in the window from the search index, builds a citation-tagged digest (~3-5k tokens), and asks the LLM for a structured retrospective:
- What I worked on — projects + threads
- What went smoothly — fast resolutions, prompts that worked first-try
- Where I struggled — rework, fights with the tool, reversed decisions
- Patterns I'm repeating — only patterns supported by ≥2 sessions
- Specific things to try differently — concrete changes tied to evidence
Every claim cites sessions as [sid:msg#]. The prompt explicitly forbids generalizing beyond evidence — "you always X" is rejected if there are only 2 instances.
Artifacts save to ~/.ccblog/reflections/YYYY-WW_start_to_end.md with share_status: private in the frontmatter — reflections catalogue weaknesses and never auto-leave the machine. Cost: ~$0.05 per weekly run.
Compound — propose new skills, memories, and rules
Instead of reading one session at a time, mine the last N sessions for repeated workflows that should become permanent context. Each command shares the same digest builder and the same hard rule: every proposal cites ≥2 distinct sessions or it gets dropped before write.
ccblog propose-skills --since 30d # repeated manual workflows → draft skills
ccblog propose-memories --since 30d # durable facts/preferences → memory entries
ccblog propose-claude-md --since 30d # repeated corrections → CLAUDE.md rules
ccblog anti-patterns --since 30d # rediscovery / manual toil / wrong-tool waste
# Shared flags for all four:
# --since 30d time window (Nd / Nw / Nh)
# --project NAME narrow to one project
# --workspace ignore project filter, hint LLM toward cross-project patterns
# --min-sessions 3 stricter: require N distinct sessions (default 2)
# --dry-run print the digest, skip the LLM
Output (one file per proposal, except anti-patterns which writes one digest):
~/.ccblog/skill-proposals/2026-04-29-<slug>.md
~/.ccblog/memory-proposals/2026-04-29-<slug>.md
~/.ccblog/claude-md-proposals/2026-04-29-NN-<slug>.md
~/.ccblog/anti-patterns/2026-04-29.md
Each proposal has a frontmatter review header (citations, confidence, target install dir) and a clearly-marked "copy below this line" body. Nothing auto-installs — you review and paste.
Why this works: the LLM sees ~3-5k tokens of digested signal (user prompts, assistant decisions, tool signatures, files touched) tagged with [sid:msg#] citations. It cannot fabricate proposals — every one must cite real evidence, and the local validator drops any proposal lacking ≥N distinct session ids.
Skill telemetry — find your dead skills
Wire one PostToolUse hook and ccblog records every Skill invocation locally:
{
"hooks": {
"PostToolUse": [
{ "matcher": "Skill",
"hooks": [{ "type": "command", "command": "ccblog telemetry-hook" }] }
]
}
}
Add to ~/.claude/settings.json. The hook never blocks — telemetry failures are silently swallowed.
ccblog skills-report # all-time usage table
ccblog skills-report --since 30d # last 30 days only
Output is a ranked Markdown table (skill, count, last used, projects). Extend with knownSkills (list of declared skills) and a "Dead skills" section appears for anything declared but never invoked. Tells you what to delete to lighten context.
Storage: ~/.ccblog/telemetry/skills.jsonl — append-only, one event per line, no PII (skill name + truncated args summary only).
Privacy model — three trust zones
ccblog operates in three zones with different access rules:
| Zone | Examples | Access |
|---|---|---|
| Local-personal | ccblog search, MCP queries, learning extraction, on-demand blog generation | Always frictionless. No gates. Every learning is visible. |
| Personal outputs | Blog posts you publish, gists you upload | You author each one. Per-action consent is built into the act of publishing. |
| Outbound / admin | Future: team sync, scheduled auto-share | Hard gate. Only ever ships items you've explicitly marked share-ready. Automation cannot bypass per-item approval. |
The share_status field on each learning means "ready to leave the machine," not "ready to use." Local features ignore it entirely. New extractions default to 'local'. Run ccblog review to triage.
Lifecycle of a learning
ccblog extract
│
▼
┌─────────────┐
│ local │ ◄── default for every new learning
│ 📝 draft │ (also: re-review with --all)
└─────────────┘
│ │
share-ready keep-private
│ │
▼ ▼
┌────────────┐ ┌────────────┐
│ reviewed │ │ private │ ◄── stays here, never leaves
│ ✅ eligible│ │ 🔒 kept │
│ to share │ │ local-only│
└────────────┘ └────────────┘
▲ ▲
└─re-decide────┘ (ccblog review --all)
Who can see each state
│ local │ reviewed │ private │
─────────────────────────────────────────────────────
ccblog search │ ✓ │ ✓ │ ✓ │ Zone 1 — local
MCP search_learnings │ ✓ │ ✓ │ ✓ │ (no gate)
MCP search_sessions │ ✓ │ ✓ │ ✓ │
ccblog blog (manual) │ ✓ │ ✓ │ ✓ │
─────────────────────────────────────────────────────
You publish a gist │ ✓* │ ✓* │ ✓* │ Zone 2 — per
*consent = the act of running the publish command │ -action consent
─────────────────────────────────────────────────────
Future team sync │ ✗ │ ✓ │ ✗ │ Zone 3 — hard gate,
Future scheduled push │ ✗ │ ✓ │ ✗ │ automation can
never bypass
ccblog review # interactive triage of pending drafts
ccblog review --all # include already-decided items
ccblog status # how many drafts are pending? (--count for shell prompt)
Each item shows: type, problem, solution, files touched, what the redactor stripped (counts + categories), and current status. Choose share-ready / keep-private / edit tags / delete / skip / quit.
The outbound publisher (Notion / git / S3 / etc) is intentionally not built yet — the contract is that the gate exists before any door does. Any future publisher MUST refuse to read anything other than share_status === 'reviewed'.
As an MCP server (one server, all tools — search + learnings):
{
"mcpServers": {
"ccblog": { "command": "ccblog", "args": ["serve"] }
}
}
Exposes search_sessions, read_session_window, list_sessions_by_file, list_recent_sessions alongside the existing learnings tools. Tool descriptions instruct Claude not to persist snippets to MEMORY.md.
Usage — blog generation
# Interactive mode — pick a session, analyze, upload to Gist
ccblog
# Auto mode — analyze latest session, save draft (great for hooks)
ccblog --auto --quiet --redact
# Setup wizard
ccblog --setup
# Help
ccblog --help
Auto-capture with hooks
Generate a blog draft after every Claude Code session — zero effort:
Add to ~/.claude/settings.json:
{
"hooks": {
"PostSessionStop": [{
"command": "ccblog --auto --quiet --redact"
}]
}
}
Drafts accumulate in ~/.ccblog/drafts/. Review and publish when ready.
PII Redaction
--redact scans for and replaces:
- API keys (Anthropic, OpenAI, AWS, GitHub)
- Email addresses
- IP addresses
- Home directory paths (
/Users/yourname/) - Database connection strings
- Private keys
Auto-prompted when uploading to Gist even without the flag.
How It Works
Two-pass AI analysis:
- Phase detection — Identifies task boundaries and generates specific, action-oriented phase names
- Contextual annotations — Color-codes each message:
- 🟢 New task start
- 🟡 Clarification / steering
- 🔴 Pivot / major change
Smart summarization extracts goals, outcomes, key prompts, and code snippets. Generates deep links from summary to specific conversation messages.
Multi-Provider Support
Uses whichever API key is available (checks in order):
| Provider | Model | Cost/session | Env var |
|---|---|---|---|
| OpenAI | gpt-6-luna | usage-based | OPENAI_API_KEY |
| Anthropic | Claude Haiku 4.5 | ~$0.002 | ANTHROPIC_API_KEY |
Set in .env file or environment. The setup wizard (ccblog --setup) walks you through it.
Requirements
- Node.js 18+
- API key — Anthropic or OpenAI (only for blog/learn features; search works without)
- GitHub CLI (optional) — for Gist upload (
brew install gh)
Privacy & Security
Search is fully local. ccblog index, ccblog watch, and all search_* MCP tools make zero network calls. Your session transcripts never leave your machine for these paths. The index lives at ~/.ccblog/session-index.db (SQLite) and only stores filtered message text — tool_result blobs are dropped at ingest time.
Blog / learnings features are opt-in and use an API key you control. API keys are read from .env or the environment (never hardcoded or logged). .env and .jsonl files are gitignored. PII redaction is available for all published content.
Review generated files before uploading — sessions may contain sensitive code or credentials.
Uninstall: rm -rf ~/.ccblog clears everything this tool stored.
Development
git clone https://github.com/varadhjain/claude-code-blog-generator.git
cd claude-code-blog-generator
npm install
echo "ANTHROPIC_API_KEY=sk-ant-..." > .env # or OPENAI_API_KEY
npm run build
npm link
ccblog
License
MIT
Turn your best Claude Code sessions into content the world can learn from.