cd /news/ai-tools/show-hn-scribe-a-cli-that-builds-ai-… Β· home β€Ί topics β€Ί ai-tools β€Ί article
[ARTICLE Β· art-63179] src=getscribe.dev β†— pub= topic=ai-tools verified=true sentiment=↑ positive

Show HN: Scribe, a CLI that builds AI agent memory from your repos and sessions

Scribe, a new open-source CLI tool, automatically builds a cross-project knowledge base for AI coding agents by mining git history, Claude Code and Codex sessions, and self-sent URLs, writing a curated markdown wiki that agents query before acting. It runs entirely locally on Ollama with zero API spend, auto-commits hourly, and supports typed entity relationships to compound knowledge across projects.

read16 min views1 publishedJul 17, 2026
Show HN: Scribe, a CLI that builds AI agent memory from your repos and sessions
Image: source

Context-aware agents

scribe init

writes a handshake block into both ~/.claude/CLAUDE.md

and ~/.codex/AGENTS.md

, so every session in every project queries your KB before recommending a library or proposing an architecture.

scribe reads your git history, your Claude Code & Codex sessions, and self-sent URLs, then writes the wiki for you β€” so the next agent session already knows what you decided and why. It’s memory your agents read before they act, not a second brain you maintain and never reopen: plain markdown in git, cross-project, cron-driven, and able to run 100% locally on Ollama for zero API spend.

brew install oliver-kriska/scribe/scribe

scribe mines four input streams, filters out the noise before any LLM touches it, then fans dense sources into entity-first wiki pages. Every step runs on cron; set it up once and forget it.

Git repos, Claude Code & Codex sessions, URLs you text yourself, and drop files from other projects. scribe auto-discovers every codebase you've ever opened in either CLI and keeps the manifest fresh.

Keyword-density scoring rejects boilerplate sessions before any LLM call, so cheap sessions cost nothing. Survivors go through a two-pass absorb: pass 1 grounds atomic facts, pass 2 fans dense sources into multiple entity-first wiki pages.

Auto-generated wikilinks, backlinks JSON, and retrieval-context paragraphs spliced into every article so embeddings catch implicit entities. qmd

reindexes for semantic search, reachable from any terminal, in any directory, or from inside Claude Code via MCP.

scribe isn't RAG, it isn't Obsidian, and it isn't another LLM-on-every-session burner. It sits between them: watches your work, writes the notes for you, and compounds knowledge across every project you touch.

scribe init

writes a handshake block into both ~/.claude/CLAUDE.md

and ~/.codex/AGENTS.md

, so every session in every project queries your KB before recommending a library or proposing an architecture.

Hourly auto-commits. Every 2 hours: project extraction. 3Γ—/day: session mining. Every 30 minutes: queued URLs. Every 4 hours: self-iMessaged links. Sundays at 02:00: the full Dream consolidation, with a lighter hot-domain pass daily in between.

One cross-project KB, not siloed per repo. Solve the oban idempotency bug in project A on Monday; the agent finds your fix on Friday when the same shape comes up in project B.

Per-project extraction, two-pass absorb, Dream cycle, assess, deep, session-mine, relations migrate: every LLM op runs end-to-end against a local Ollama server. One line in scribe.yaml

flips the whole pipeline. Zero API spend.

File over app: the corpus has to outlive the pipeline. A git repo of plain markdown with YAML frontmatter. Push to your own GitHub, Gitea, or Forgejo; open in Obsidian, VS Code, vim, or mdbook. No SaaS, no vendor lock-in.

Articles connect via a closed 10-kind typed-edge schema: supersedes

, contradicts

, derived_from

, specializes

, extends

, and five more. scribe relations migrate

classifies existing related:

links into it with an LLM.

The whole surface, in numbers β€” every figure is checkable against scribe --help

and scribe.yaml

, not marketing. Local mode needs no key at all; the default Anthropic path signs in through your claude -p

CLI, not an API key.

scribe is a compiled knowledge base, not a vector database: it auto-writes a curated markdown wiki your agents query with BM25, so there's nothing to embed and nothing to host. The "second brain" debate is about notes you read. scribe isn't that. It's memory your agent reads before it decides: the reasons behind a choice, not summaries you'll never reopen. It sits between manual-notes tools (Obsidian, Notion) and unbounded LLM-on-every-query approaches (vanilla RAG, claude-memory-compiler): a curated wiki on top of raw sources kept verbatim, small enough for an agent to read whole, and cheap to query because most lookups are plain-text matches, not vector guesses.

Capability scribe RAGLangChain Β· LlamaIndex Code Insights@code-insights/cli AnythingLLM Obsidian
Auto-written from your dev work Yes You index docs Yes You upload docs You type notes
Sources captured Sessions + git + URLs Docs you feed Coding sessions only Docs you upload Notes you write
Output is portable markdown in git Yes Vector chunks SQLite dashboard Vector store Yes
Vector DB required? Not needed Required Not needed Required Not needed
Full-text (BM25) search qmd Β· FTS5 Vector recall only Dashboard analytics Vector chat Yes
Agents read it back before deciding CLAUDE.md / AGENTS.md If you wire it Human dashboard You chat with it No
Local-first, no API key (Ollama) 100% Ollama Local embeddings Ollama option Local LLM + DB AI add-ons need keys
Tool Session mining Cron-driven Density pre-filter Two-pass absorb Multi-project Local-mode
scribecurated wiki + raw sources, in git Claude + Codex launchd / systemd BM25 atomic facts β†’ pass-2 manifest-tracked 100% Ollama
claude-memory-compilerAnthropic-only, single project Claude only Β· $115 / 20min Β· issue #3 manual none single-pass single repo API only
nvk/llm-wikiLLM-built wiki, no mining user-fed manual none single-pass single repo Ollama possible
basic-memoryMCP memory server issue #669 since Mar request-driven none single-pass per-MCP-client local embeddings
RAG (LangChain, LlamaIndex)retrieve-then-prompt retrieves chunks on-query vector recall no absorb per-index local embeddings
Obsidian / Notionmanual notes tool you type it manual tag-based no absorb vault / workspace Obsidian = local, Notion = cloud

scribe is the wiki the LLM writes for you, sitting on top of raw sources kept verbatim. RAG retrieves chunks; scribe gives you a curated, named-entity wiki you can also grep. β€” project README

scribe is single-user by default and stays that way. But a small team on the same codebases can point every machine at one git-backed KB. The obvious fear with sharing agent sessions β€” a leaked secret, a private client repo, one teammate's config change reaching everyone β€” is exactly what the gates below are built to stop. Only knowledge you meant to keep crosses into the shared KB.

A trust layer pins the sensitive surface of a shared scribe.yaml

: provider, model, ingest paths, and the secret scanner itself. A pushed change that would repoint inference to a new endpoint or drain a new directory into the KB reverts to the last trusted snapshot until a human approves it.

scribe mines session transcripts, which routinely carry API keys and tokens. In team mode a deterministic secret scanner runs in the commit gate and holds flagged credentials back before anything lands in shared git history. No LLM, no network: a regex pass on the commit path.

Every scribe sync

pulls, merges, and reindexes before it extracts, and a committed ledger keeps two machines from mining the same git revision twice. Your inference bill scales with commits, not with the number of laptops pointed at the KB.

Discovered projects start pending. allowed_remotes

and source filters gate discovery by git-remote identity, and scribe projects {list,approve,ignore,review}

controls what enters the pipeline, so a side project or a client checkout never lands in the shared KB without an approve.

scribe promote <article> --to team-kb

copies a page from your personal KB into the shared one, provenance recorded. Derived and coordination files are refused as sources, so the team KB fills with what you meant to publish, not your working scratch.

The weekly Dream consolidation rewrites, merges, and prunes the whole wiki, so exactly one machine should run it. A committed leader lease in the repo elects that machine: no etcd, no lock server, and two laptops never race to rewrite the same wiki at 02:00 Sunday.

Run the whole pipeline on local Ollama for $0, point it at a hosted OpenAI-compatible API (Together, Groq, Fireworks, Hugging Face) when the laptop is running hot, or keep claude -p

for the Anthropic path. The three coexist; pick the trade per op in scribe.yaml

, and nothing reaches a paid provider without explicit config. scribe cost

then reconciles every token across providers and KBs, to the cent against the provider's own dashboard.

~ $ scribe cost

scribe cost β€” last 7 days β€” 2 KBs (personal-kb, team-kb)

  model                                             calls     ok  cancl  rate  tmout  wallclock   in-tokens  out-tokens      usd
  ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  sonnet                                              301    281      0     0      3      6h54m     250,468     789,357   $92.80
  haiku                                               151    144      0     0      7      2h21m       1,251     551,761   $10.77
  together/MiniMaxAI/MiniMax-M3                        195    195      0     0      0      1h06m   1,261,197     146,728    $0.55
  ollama/gemma3:12b                                   120    120      0     0      0      4h57m   1,037,866     138,258        β€”
  ollama/qwen3:30b-a3b-instruct-2507-q4_K_M         1,643  1,627      0     0      0     23h39m  11,317,941   1,122,293        β€”
  ollama/gemma3:4b                                    921    912      0     0      0      8h23m   2,355,608     672,157        β€”
  ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  TOTAL                                             3,331  3,279      0     0     10     47h22m  16,224,331   3,420,554  $104.12

  By provider:
  provider   calls   in-tokens  out-tokens      usd
  ─────────────────────────────────────────────────
  anthropic    452     251,719   1,341,118  $103.57
  together     195   1,261,197     146,728    $0.55
  ollama     2,684  14,711,415   1,932,708        β€”

  By KB:
  KB           calls  in-tokens  out-tokens      usd
  ──────────────────────────────────────────────────
  team-kb      1,732  7,020,329   2,211,137  $102.96
  personal-kb  1,599  9,204,002   1,209,417    $1.16

  Coverage: 3175/3331 calls had token data; the other 156 add ~$0.62 estimated, not shown above.
  usd = provider-billed spend incl. cache-write & cache-read; in is uncached input, so usd exceeds an in/out list estimate.
  cancl = sibling-canceled (rate-limit cascade).  tmout = ctx.DeadlineExceeded.

On the local path there's no claude -p

callsite in a normal scribe sync

: per-project extraction, two-pass absorb, the weekly Dream cycle, assess, deep, session-mine, and relations migrate all fire through bounded JSON-envelope subtasks against your Ollama server. A full weekly sync: 0 errors, $0.00, ~68s, 7,447 β†’ 7,472 articles. One line in scribe.yaml

flips the whole pipeline.

For developers, the expensive half of the job isn't deciding. It's rebuilding the context you already had. scribe automates that half: if your Claude Code or Codex history is already full of decisions, fixes, and library evaluations, it keeps them from evaporating between sessions.

Your agents keep re-deriving the same answers because each session starts from zero. scribe gives them durable memory.

CLAUDE.md

  • AGENTS.md

One cross-project KB means Friday's repo can pull Monday's fix. Typed edges keep the graph honest as patterns evolve.

supersedes

, contradicts

, specializes

Run the entire pipeline locally on Ollama. Plain markdown on your own git remote. No SaaS, no cloud sync, no vendor lock-in.

Two real loops from the maintainer's normal use: concrete, not marketing.

scribe had already absorbed the verdict from the prior project's session: DB-backed Gettext with a LiveView admin UX, weighed against standard .po

files and managed services. When Claude Code opened the new repo and asked the KB for translation options, the existing "skip" verdict surfaced first with the reasoning attached. No re-research; the agent cited the prior decision and moved on. The whole loop was invisible; the only thing the maintainer noticed was that the new project skipped the comparison shopping the first one did.

tools/kanta.md Β· verdict: skip

Β· surfaced via qmd query "phoenix translation library"

The fix from project A (an idempotency-key strategy for an external-call worker) got captured automatically when the post-fix session was mined into the KB. When the same race showed up in a different Phoenix app months later, the agent grepped the KB before guessing, found the prior pattern, and proposed the exact same shape with the prior trade-offs already weighed. The second fix took fifteen minutes instead of an afternoon.

solutions/oban-external-call-worker-idempotency.md

Β· linked from solutions/fly-io-oban-cron-multi-node-double-fire.md

sync --estimate

token previewdeep

/ assess

batch passes_backlinks.json

Β· orphan linking Β· qmd BM25 + vector indexallowed_remotes

Β· promote-with-provenance Β· committed leader leasescribe cost

reconciliationscribe doctor

Two commands to install. One llm

block in scribe.yaml

routes the whole pipeline local, hosted, or Anthropic. One query from any terminal.

brew tap oliver-kriska/scribe
brew install oliver-kriska/scribe/scribe

scribe init --path ~/my-kb
cd ~/my-kb
scribe cron install
scribe doctor

curl -fsSL https://raw.githubusercontent.com/oliver-kriska/scribe/main/install.sh | bash
llm:
  provider: ollama
  model: gemma3:12b            # cross-op default
  ollama_url: http://localhost:11434
  num_ctx: 16384               # keeps dense-article tails intact

ops:
  contextualize:
    model: qwen3:30b-a3b       # quality-critical (MoE, fast)
  pass2:
    model: qwen3:30b-a3b       # highest-quality writes
llm:
  provider: together          # together | groq | fireworks | huggingface
  model: MiniMaxAI/MiniMax-M3  # a real hosted model id, not a Claude alias
  api_key_env: TOGETHER_API_KEY  # only the VAR NAME lives here β€” never the key
  pricing:                      # optional, so `scribe cost` reports dollars
    "together/MiniMaxAI/MiniMax-M3": { input: 0.30, output: 1.20 }

llm:
  provider: anthropic         # the default; no API key in scribe, uses claude -p
  model: sonnet               # cross-op default

absorb:
  pass1_model: haiku         # β‰ˆ $0.0001/doc entity-list pass
  pass2_model: sonnet        # highest-quality writes

sync:
  daily_output_token_ceiling: 200000
qmd query "how did I solve the oban idempotency bug last quarter"

qmd search "unique_constraint Multi"

mcp__plugin_qmd_qmd__query
scribe doctor

scribe doctor --section localmode

cat output/runs/$(date +%Y-%m-%d).jsonl | tail -n 5

After scribe init

and scribe cron install

, the loop closes by itself. New work flows in, the KB grows, and the next Claude Code or Codex session, in any project, queries what scribe just wrote.

A single walk over ~/.claude/projects/*

and ~/.codex/sessions/*

finds every repo you've opened in either agent. Each one becomes an entry in the manifest with a stable name, last-seen timestamp, and source provenance. No config, no manual list; if you've coded there, scribe sees it.

discover()

  • cmd/scribe/codex.go: discoverCodex()

β†’ ~/.claude/projects/*

  • ~/.codex/sessions/*

β†’ manifest.Projects

scribe writes a maintained block into ~/.claude/CLAUDE.md

and ~/.codex/AGENTS.md

. Every Claude Code and Codex session, in every repo, picks up the same instructions: query the KB first, and drop reusable findings as files. The handshake is idempotent: re-run init and only that block updates.

installClaudeMD()

  • installCodexMD()

β†’ templates/claude-md-kb.md

  • templates/codex-agents-md.md

β†’ marker-fenced block in both filesThree cron entries do the boring work: sync

for session mining and per-project extraction, capture

for queued URLs and self-sent iMessage links, and sync --sessions

on a faster cadence. Drop files written by an agent in any repo are picked up on the next tick and flow through density triage β†’ contextualize β†’ atomic facts β†’ pass-2 absorb.

CronInstallCmd.Run()

β†’ launchd / systemd / crontab entries β†’ scribe sync

  • scribe capture

A separate cron entry runs scribe commit

every hour: it stages everything the absorb pipeline produced, writes a structured commit message, and pushes to your private remote (GitHub, Gitea, Forgejo, anywhere). On non-fast-forward it runs git pull --rebase

and retries once; force-push is never attempted. Your KB is version-controlled, diffable, and recoverable, with no web UI; the source of truth is markdown in git.

CommitCmd.Run()

  • cmd/scribe/gitops.go β†’ git add

Β· git commit

Β· git push origin main

Once a week the Dream cycle wakes up. It looks at what's grown, prunes stubs that never got fleshed out, merges near-duplicates, breaks down articles that got too dense, and surfaces contradictions for review. Runs entirely on local Ollama: no token spend, no third party touches your notes. The KB stays small enough to fit in an agent's context window for years.

Sun 02:00

β†’ cmd/scribe/dream.go: DreamCmd.Run()

β†’ prompts/dream-ollama.md

on gemma3:12bEvery absorb tick reindexes qmd, so the next Claude Code or Codex session, in any repo on this machine, finds what scribe just wrote. The loop closes itself, in the background, on a schedule you forget about.

Here are the ones you'll actually type. Everything else is scribe doctor

-discoverable.

$ scribe init                        # bootstrap a KB, wire the agent handshake
$ scribe sync                        # discover β†’ extract β†’ absorb β†’ reindex
$ scribe sync --sessions             # mine Claude Code + Codex transcripts
$ scribe sync --estimate             # token estimate, zero LLM calls
$ scribe doctor                      # validate setup, cron, git remote, Ollama
$ scribe commit                      # stage + push the KB to your private remote
$ scribe dream                       # weekly consolidation (Ollama-driven)
$ scribe capture                     # drain queued URLs / iMessage links
$ scribe relations migrate           # classify `related:` into typed edges
$ scribe cron install / uninstall / status

The same qmd

index is used by every consumer: your shell, Claude Code via MCP, Codex via MCP, your editor's grep, with no reindex per tool and no format conversion.

qmd query "oban idempotency pattern"

qmd search "BM25 density"

qmd query "two-pass absorb" --open
mcp__plugin_qmd_qmd__query(
  searches: [{ type: 'vec',
              query: "oban idempotency" }],
  intent: "find the prior fix"
)

claude -p

callsite in a normal scribe sync

. A single line in scribe.yaml

flips the whole pipeline. Per-op overrides still work if you want to keep some passes on Anthropic.claude -p

callsite in a normal scribe sync

, including per-project extraction and the weekly Dream cycle, runs locally. On the Anthropic-hosted path, contextualize costs roughly scribe.yaml

as untrusted by default: a pushed change that repoints inference or widens ingest paths reverts to the last trusted snapshot until a human approves it. A deterministic secret-scan gate holds API keys and tokens back before they reach shared git history (a regex pass on the commit path, no LLM, no network). allowed_remotes

gates discovery by git-remote identity, so a teammate's unrelated or client repo never leaks in. scribe promote

moves curated pages into the team KB with provenance, and a committed leader lease elects the single machine that runs the weekly consolidation: no server, no etcd.scribe cron install

; Linux gets paste-ready crontab lines from the same command. The fsnotify watcher (scribe watch

) is not cron-friendly on either OS; run it under launchd KeepAlive on macOS or systemd-user on Linux. The iMessage capture step is macOS-only because it reads chat.db

; everything else is portable.scribe init

. Push it to your own GitHub, Gitea, or Forgejo; there's no SaaS account, no cloud sync, no vendor lock-in. Open it in Obsidian, VS Code, vim, or mdbook.scribe init

and scribe cron install

, and the knowledge base grows on its own.scribe.yaml

flips every LLM op (extraction, absorb, dream, session-mine) to local. Your knowledge base is a plain git repo of markdown on your own machine, with no SaaS account and no cloud sync.qmd

for grep

it from any terminal or query it from inside your agent. The whole pipeline runs unattended on macOS LaunchAgents or Linux cron.One brew install

, one scribe init

, and your tools start writing the notes for you.

── more in #ai-tools 4 stories Β· sorted by recency
── more on @scribe 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/show-hn-scribe-a-cli…] indexed:0 read:16min 2026-07-17 Β· β€”