Every serious build accumulates invisible architecture: the decisions that didn't make it into the code, only the reasoning that produced the code. The longer you build across multiple projects, the more valuable that reasoning becomes — and the faster it disappears.
I run multiple production builds simultaneously: BoardPath, Auris Intelligence, Litt,
transparent-confidence.
Each one has architectural decisions embedded in it — choices about storage, retrieval,
schema design, layer separation, model selection. Those decisions are in the code. The
reasoning behind them is nowhere.
The specific friction that triggered this build: I couldn't answer "how have I handled OCR across projects?" without reading through the code of three separate repositories. I couldn't start a new BoardPath session and immediately know why I'd made a particular decision two weeks earlier in a different Claude Code session. Session memory in coding agents is per-agent and per-session. It doesn't answer cross-project knowledge questions. Nothing else owned that problem, so I built the thing that did.
The central design decision in ledger is the two-layer split — and the insistence that the split be real, not just described.
pip install -e ".[ai]"
Layer 1 is complete and useful on its own. It's a structured decision store backed by SQLite,
which ships with Python. No API key. No network call. No external service. You can
pip install ledger
and use it without ever configuring an AI integration.
Layer 2 sits on top. Natural-language recall uses a four-stage pipeline: structured filter
on the decision store → keyword rank to surface the most relevant candidates → bounded
hydration (top 10) into a context block → a single Anthropic Haiku synthesis call. The
default model is Haiku — it's fast enough for interactive use and 3x cheaper than Sonnet
for output tokens. Override with LEDGER_MODEL if you want deeper synthesis.
The boundary is enforced as a test, not as a comment:
test_core_imports_no_anthropic
imports the core modules and asserts that the Anthropic SDK never appears in
sys.modules.
If the boundary is ever accidentally crossed, the test fails.
That decision got its own architecture note.
The MCP server exposes four read tools: ledger_list, ledger_show,
ledger_recall, ledger_resume. It exposes no write tools. Capture
stays CLI-only — you log a decision deliberately, at the terminal, with intent. No
connected client can write to the record.
The read/write asymmetry is the philosophy enforced at the protocol boundary. Any Claude Code session can read your architectural reasoning. None can add to it without you sitting at a terminal and choosing to.
Zero runtime dependencies for Layer 1. Python's sqlite3 module ships with the standard library. Layer 1 has nothing to install and nothing to break.
Timestamp-based IDs for chronological natural sort. Decision IDs use the format YYYYMMDD-HHMM-XXXX — natural string sort equals chronological sort, no separate index required. Human-readable without a lookup table.
Keyword overlap for v1 ranking, stable interface for embedding swap. rank.score() uses term-set intersection. The interface signature is identical to what an embedding-based ranker will implement in v1.1 — the upgrade is a one-file swap with no changes to the pipeline or CLI.
Supersession as a graph, not deletion. Superseding a decision sets the old record's status to 'superseded' and links the new record via a self-referential foreign key. The decision history is a directed graph of how reasoning evolved — the amendment-chain pattern from BoardPath applied to your own build process.
This section is written after enough time has passed to have genuine perspective. Check back when v1.1 (embedding-based ranking) is complete.