Files
wanderbooks/AGENTS.md
T
swaitsandClaude Opus 5.5 ad572ae89d docs(spec): every rule traced to an authority; public-domain sources vendored
Stephen asked that specs come from recognized documents, not from
anyone's memory. There is no single US bookkeeping bible; authority is
layered, and this records it:

- docs/spec/sources/: verbatim excerpts (whitespace normalized), each
  with URL, retrieval date, and the SHA-256 of the fetched file, of
  public-domain texts: Pacioli's 1494 treatise in Geijsbeek's 1914
  translation (double entry, the trial balance, one money, write only
  forward, correct by opposite entry, close into capital); IRS Pub. 583,
  538, 946, 15; the 1099-MISC/NEC instructions (2025 and 2026); 26 U.S.C.
  §6041, §6041A, §704; Treas. Reg. §1.263(a)-1(f) and -4(f); Notice
  2015-82; Rev. Proc. 98-25; Form 1065 instructions; 17 U.S.C. §105. The
  excerpts were extracted by matching each passage against the fetched
  file, so none can contain text the source doesn't.
- docs/spec/rules.md: the rule catalog, B-1 to B-22. Each rule says
  AUTHORITY, CONVENTION, or DECISION; cites its sources (FASB's
  Codification and Concepts Statement 8 and OpenStax quoted briefly,
  never copied: copyright and CC BY-NC-SA); and names the code that
  enforces it and the tests and proofs that check it.
- Spec blocks in the code now carry SOURCE: lines into the catalog;
  AGENTS.md makes sourcing rule 0 of the formal-methods bar.

Corrections the sources turned up: the de minimis limit is $500 in the
regulation and $2,500 by Notice 2015-82 (both now cited); 1099
thresholds after 2026 are inflation-indexed, so the engine's flat
$2,000 for 2027+ is an open question (B-19). Unverified ASC paragraphs
(360-10-35-4, 340-10, 230-10-45-10, 606-10-55-37B, 210) are listed in
docs/spec/README.md until someone with a FASB basic-view login reads
them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
2026-10-13 12:18:57 -06:00

10 KiB

AGENTS.md — wanderbooks

Operating manual for agents working in this repo. Read this first, then the docs it points to. The short version: this is an engine-first, clean-room rebuild of canonical double-entry bookkeeping, done the storytold way — agents verify against oracles, track parity automatically, and never ship what they haven't demonstrated.

What this is

wanderbooks is a from-scratch implementation of double-entry bookkeeping semantics, built to become a full bookkeeping application (engine now, UI later). The reference points:

  • Spec: accounting principles, written down as proofs (docs/verification.md). That is the only authority.
  • Cross-check oracles: GnuCash (open source, open file formats), the old Google Sheet, QBO/Xero exports. Useful to diff against, never trusted to be right: a disagreement is adjudicated from principles, and nothing may rest on another program's behavior alone. See docs/oracle.md, "Who is right".
  • Workflow reference: QuickBooks Online and Xero — for what the UI must do, never for code. We observe behavior; we write our own implementation.
  • Method reference: storytold/ArtCraft's app-cloning pipeline (screenshot-in-the-loop, render oracles, automated parity floors). We adapt it to accounting: semantic oracles instead of pixel oracles.

The non-negotiables

  1. Money is Money. Exact Decimal plus a currency code. Binary floats (f32/f64) never appear in money paths — not for amounts, not for rates, not for "temporary" calculations. If you need a ratio, it is a Decimal.
  2. Every entry balances. Debits equal credits exactly. No epsilon.
  3. Posted is forever. Posted entries are immutable. Corrections are reversing entries linked by reversal_of. There is no edit, no delete.
  4. Reports are pure functions of a ledger. If a report needs state that isn't in the ledger, the ledger model is wrong — fix the model.
  5. Clean room. Build from public specs and observed behavior only: GnuCash documentation and file formats, the IFRS conceptual framework, IRS publications for tax-adjacent logic later. GnuCash itself is GPL — read its docs, never copy its code. This repo is MIT OR Apache-2.0. Never disassemble or copy from proprietary software.
  6. Accounting laws are proved, not just tested. Arithmetic that money flows through lives in kernel.rs and carries Kani proofs; the laws it serves carry Lean proofs. just prove stays green. See "Formal methods" below.

Verification protocol (read this twice)

There is no UI yet, so "seeing what it's building" means showing the numbers. The analog of storytold's screenshot-in-the-loop:

  • A green cargo test is necessary but not sufficient. Every behavior change must be demonstrated through the public API with human-readable output: print the trial balance, the P&L, the balance sheet. Show the numbers moving the way accounting says they should.
  • New behavior needs new tests in crates/ledger-core/tests/invariants.rs (or a new test file for a new crate). Tests encode accounting law, not implementation details: prefer "the accounting equation holds" over "this function returns that struct".
  • Golden files are sacred. tests/golden/*.json hold hand-verified expected reports for canonical fixtures. If a change intentionally alters output, recompute the expected numbers by hand from accounting principles, update the golden, and explain the recomputation in the commit message. Never edit a golden to match output you haven't verified — that is how oracles die.
  • The randomized invariant test (random_balanced_journals_preserve_invariants) is the always-on property oracle. Extend it when you add invariants.

Formal methods: the bar (read this three times)

Tests check the cases someone thought of; proofs check all of them. The first formal pass on this engine (2026-10, docs/verification.md) paid for itself several times over, on code that already had 190+ tests, property tests, mutation testing, and 11.5M fuzz executions:

  • Negative line amounts were accepted by the engine. Only the MCP layer refused them. Any other caller could post them.
  • A large enough amount crashed the engine (a Decimal overflow panic while summing lines) instead of returning an error.
  • Currency conversion could crash the same way.
  • The verifier itself had a soundness bug. Kani 0.68 mis-models copy_from_slice of symbolic length (model-checking/kani#4904): it reported a reversal that doesn't net to zero. We didn't wave it away. Replaying the counterexample natively, then shrinking it to a 15-line crate, proved it was the tool, not the books. Now a canary harness watches for the fix, and covers prove no proof is vacuous.
  • Writing the spec simplified the code. credit_line and closing_line turned out to be the same function. Lean also proved that no draft can exist in a closed period, the invariant that lets the store journal a post before applying it.

So the bar, for every agent, every change:

  1. Specs come from authorities, not memory. Every rule the engine enforces is in docs/spec/rules.md with its source: Pacioli for the mechanics of double entry, the IRS (vendored verbatim, public domain) for records, periods, 1099s, capitalization, partnerships, and payroll, FASB's Codification (cited, never copied) for GAAP. A rule no authority states is marked CONVENTION or DECISION, with who decided and when. Spec blocks in the code (```text GOAL/SOURCE/INVARIANTS/SCENARIOS) carry a SOURCE: line. Never write a spec from what the code happens to do, or from what you remember; find the document, or ask.

  2. Money arithmetic goes in kernel.rs, generic over Amount. If you write a sum, a sign flip, a split, or a rounding plug anywhere else, move it into the kernel. The engine calls the kernel. It never gets a second copy.

  3. Every kernel function gets a Kani harness in src/proofs.rs, on fixed arrays (no symbolic-length Vec growth, no copy_from_slice), with a kani::cover! showing the interesting case is reached.

  4. Every new law gets a Lean theorem in verify/lean. Laws about the books over time are theorems about Reachable states. A new Ledger command is a new Step constructor, with its preservation proof. No sorry, ever; Audit.lean lists every headline theorem.

  5. Every kernel instantiation gets a bridge property in tests/kernel_bridge.rs, so what Kani proved on i64 holds on Decimal.

  6. A failing proof is a finding, not an obstacle. Get the counterexample, replay it natively, and decide on evidence: bug in our code, bug in the spec, or bug in the tool. Never weaken an assertion, raise a bound, or delete a harness to make red go green without writing down why in docs/verification.md.

  7. More, not less. When you touch an area the proofs don't cover yet (A/R and A/P documents, payroll, depreciation, FX, persistence), leave it with more formal coverage than you found it. Proptest, mutation testing, fuzzing, Kani, and Lean all stack. Use all of them.

just check and just prove both pass before every commit that touches ledger-core.

Parity tracking

docs/parity.md is the parity catalog: every semantic feature we intend to clone, with status. Rules:

  • Every feature change updates docs/parity.md in the same commit.
  • The floor never decreases: the count of done items is monotonic. CI will enforce this once the catalog is machine-readable (roadmap phase 3); until then, it is enforced by review — yours.
  • Statuses are done (implemented + tested + golden-covered), partial, todo. No other statuses. done requires all three.

Engine-first architecture

  • All mutations are commands on Ledger (create_entry, add_line, post_entry, reverse_entry, add_account). Struct fields stay private; no other mutation path may exist.
  • ledger-core depends only on rust_decimal, thiserror, chrono, serde, serde_json. New dependencies need justification in the commit message. No I/O, no networking, no time-source in the core.
  • Future crates (ledger-store, ledger-import, ledger-oracle, books-app) depend inward toward the core, never the reverse. See docs/architecture.md.

Working here

  • mise install sets up every tool (pinned in mise.toml): Rust, just, Kani, Lean, cargo-mutants, cargo-fuzz. If a recipe needs a tool, it goes in mise.toml; nothing gets installed by hand.
  • Rust stable, edition 2024. just check must pass: fmt, clippy with zero warnings, every test. just prove must pass for core changes.
  • Conventional commits: feat:, fix:, docs:, test:, refactor:. One logical change per commit. The commit message explains the accounting reasoning, not just the code.
  • You have a very large context window. Use it: when working on semantics, load the whole ledger-core crate plus docs/requirements.md rather than guessing from snippets.
  • If a requirement in docs/requirements.md conflicts with code, the requirement wins — then fix the code, and say so.

Docs index

Read this When you need
docs/requirements.md What the engine must do (R-1…), what is future work
docs/architecture.md Crate layout, command pattern, dependency rules
docs/oracle.md How we check correctness: golden files, property tests, fuzzing, cross-checks against other implementations (and who is right)
docs/spec/ The authorities every rule comes from (rules.md), with public-domain sources vendored verbatim
docs/verification.md The formal proofs: every accounting law, its Kani harness and Lean theorem, what they found
docs/parity.md Feature catalog and the non-regression floor
docs/capability-parity.md Parity vs the GSheet+GDrive system + the cutover rule
docs/mcp-interface.md The MCP tool surface: the primary interface spec
docs/receipt-store.md Blob store + ledger-store SQLite persistence spec
docs/glossary.md Debit/credit and friends, for agents new to accounting
plan/STATUS.md Where the project stands right now
plan/roadmap.md Phase plan: semantics → oracle harness → egui app → workflow parity

License

MIT OR Apache-2.0. New files carry no license headers; the license files at the repo root cover the tree.