Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

46 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ccblog

A Claude Code session toolkit: search, distill, and publish your history.

GitHub stars License: MIT Node.js


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.
  • 🧠 Learn β€” extract structured learnings from sessions so future agents can query "have we solved this before?"
  • ✍️ Publish β€” generate polished blog posts + interactive HTML viewers from any session.

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

# Learn + publish (requires an API key)
ccblog --setup               # picks Anthropic or OpenAI
ccblog                       # interactive: session β†’ blog post

Search is free and instant. Blog/learn features use Anthropic (Claude Haiku) or OpenAI (gpt-5-nano) at ~$0.001/session.

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

See a live example β†’

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.

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.

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:

  1. Phase detection β€” Identifies task boundaries and generates specific, action-oriented phase names
  2. 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
Anthropic Claude Haiku 4.5 ~$0.002 ANTHROPIC_API_KEY
OpenAI gpt-5-nano ~$0.001 OPENAI_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.

About

Transform Claude Code sessions into engaging, educational blog posts with intelligent narrative chunking and PII redaction

Resources

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages