logbook
A tiny CLI that gives every repo a single
logbook.mdfor "why I made this decision and what I rejected" — the architectural context that's currently scattered across your head, half-written PR descriptions, and Slack threads.
That command appends a structured entry to ./logbook.md and stages it for your next commit. Three months later, when you've forgotten why the codebase looks the way it does, logbook last or logbook search orm brings it back.
Table of contents
- Why this exists
- What it isn't
- Install
- Quickstart
- Commands
- Entry format
- Using logbook with LLM coding agents
- Comparison to alternatives
- FAQ
- Development
- Roadmap
- License
Why this exists
The code tells you what it does. git log tells you what changed. Neither tells you why you picked this design over the alternatives — and that's the context you lose first when you come back to a project after a month away.
For solo developers this is annoying. For developers working alongside an LLM coding agent (Claude Code, Cursor, Aider, …) it's worse: the agent loses state every session, and you become the human glue carrying architectural decisions in your head. logbook.md lives in the repo, so the agent can cat it at session start and inherit every decision you've made.
The fix is intentionally dumb: a single markdown file in the repo, committed in git, with a small CLI to append entries to it. No service, no database, no editor plugin, no SaaS.
What it isn't
- Not a README. READMEs explain what the project does, for users.
- Not a CHANGELOG. CHANGELOGs are for end-users tracking what shipped.
- Not a commit message. Commits say what changed in this diff.
- Not a full ADR (Architecture Decision Record) framework. ADRs are great for teams with formal review processes.
logbookis what you reach for when ADRs feel like too much ceremony. - Not a design doc. When you need diagrams, prose, or stakeholder review, write a design doc.
logbook fills the gap between commit messages and design docs: the architectural choices the code itself can't justify.
Install
macOS / Linux (Homebrew):
Any platform with Rust:
Prebuilt binary (no toolchain required):
Grab the archive for your platform from the latest release, extract it, and drop the binary on your $PATH. Prebuilt targets: x86_64-linux, aarch64-linux, x86_64-macos, aarch64-macos (Apple Silicon), x86_64-windows.
From source:
Requires Rust 1.75 or newer. After installing, logbook is on your $PATH:
Quickstart
That's it. Future entries are the same shape. The four common workflows:
| To do this | Run |
|---|---|
| Record a decision while you're making it | logbook add "title" --why "..." [--rejected ...] [--risk ...] [--tag X] --stage |
| Look up what you decided recently | logbook last or logbook list | head -50 |
| Find a specific past decision | logbook search <term> |
| Recall what you decided on a date | logbook show 2026-05-16 |
Commands
| Command | What it does |
|---|---|
logbook init |
Create the logbook file with a header. Idempotent. |
logbook add <title> --why <reason> [--rejected …] [--risk …] [--tag X]… [--stage] [--print] |
Append a new entry. --tag is repeatable. --stage runs git add. --print echoes the rendered block. |
logbook list [--tag X] [--since YYYY-MM-DD] [--until YYYY-MM-DD] |
Print entries newest-first with optional filters (all combinable). |
logbook last |
Print the most recent entry only. |
logbook show <YYYY-MM-DD> |
Print every entry from a specific date. |
logbook search <term> |
Case-insensitive substring search across all entries. |
logbook tags |
List all distinct tags with usage counts. |
logbook stats |
Total entries, date range, entries-this-month, unique tags. |
logbook where |
Print the resolved logbook file path (honors LOGBOOK_FILE). |
Run logbook --help or logbook <cmd> --help for the full flag reference.
Environment
| Variable | Effect |
|---|---|
LOGBOOK_FILE |
Override the default ./logbook.md. Useful for monorepos (LOGBOOK_FILE=docs/decisions.md), or for keeping a personal log in a fixed location across projects. |
Entry format
logbook.md is plain markdown. The CLI only ever appends — it never rewrites old content. You can edit the file by hand if you want.
Each entry follows this shape:
**why:** <reason this was chosen>
**rejected:** <alternatives considered and why not>
**risk:** <what could go wrong>
**tags:** <comma-separated tags>
Only the title and --why are required. --rejected, --risk, and --tag are optional but recommended for non-trivial decisions.
A real entry looks like:
**why:** crashes during write could leave logbook.md half-written; rename(2) is atomic on POSIX so write-then-rename guarantees the file is either fully old or fully new, never partial
**rejected:** fsync on every write (overkill for human-pace writes); fcntl file locking (overkill — we don't have multiple writers fighting)
**risk:** reads entire file into memory before rewriting — fine until logbooks have millions of entries
**tags:** robustness, io
Using logbook with LLM coding agents
A common workflow: have your agent (Claude Code, Cursor, Aider, etc.) read logbook.md at the start of every session so it inherits accumulated decisions.
For Claude Code, add to your CLAUDE.md:
At session start, run: `logbook list | head -100`
Treat every entry as an architectural constraint unless explicitly superseded.
When you make a non-obvious choice, suggest a `logbook add` command for the user to run.
For Aider, add logbook.md to your .aider.conf.yml read-only file list. For Cursor, reference it in .cursorrules.
This turns the logbook into the agent's long-term memory for the project, with zero extra infrastructure.
Comparison to alternatives
| Approach | Strength | Weakness vs logbook |
|---|---|---|
| CHANGELOG.md | End-user-facing, semver-aligned | Doesn't capture rejected alternatives or risks; written for outsiders, not the author |
docs/adr/*.md (full ADRs) |
Battle-tested by enterprises, lots of tooling | Heavyweight — one file per decision, formal status workflow, real overhead. logbook is the lite version. |
| PR descriptions | Co-located with the diff, contextual | Lost when PRs get merged and you can't find them again; not greppable from the working tree |
| Slack/Notion/Confluence | Searchable, supports rich content | Decoupled from the repo, requires login, the link rots, the agent can't read it |
| Code comments | Right next to the code | No place for rejected alternatives or cross-file decisions; rot pressure |
| Mental model + memory | Free | Lossy, doesn't transfer to teammates or to your future self |
The honest take: if your team already runs full ADRs and likes them, keep doing that. logbook exists for the much larger group of developers (and solo developers) for whom ADRs are too much.
FAQ
Why markdown over JSON/YAML?
A logbook is for humans first, machines second. Markdown renders well in cat, on GitHub, in less, in your editor, and inside an LLM's context window. The parser extracts the few structured bits we need (date, tags); the rest is intentionally free-form.
Can I edit logbook.md by hand?
Yes — the CLI never rewrites old content. As long as you keep the ## YYYY-MM-DD — title heading shape, the parser will continue to extract the date and tags correctly.
What happens if I run logbook add from two terminals simultaneously?
Each add reads the file, appends in memory, writes to a sibling tempfile, then renames on top. The rename is atomic on POSIX and Windows. Worst case, one of the two writes is lost (last-writer-wins); the file is never corrupted.
Why isn't there an --edit flag to fix typos?
Append-only is a deliberate philosophy. If a decision is reversed or refined, write a new entry that supersedes the old one — the history of how thinking changed is part of the value. If you really need to fix a typo, edit logbook.md directly.
Does it work without git?
Yes. The --stage flag invokes git add for convenience but the rest of the tool doesn't care. You can use logbook in a directory that isn't a git repo at all.
Why a custom file format instead of, say, conventional commits?
Conventional commits live in git history, which means they're harder to read all-at-once and require git tooling to query. logbook.md is one greppable file you can cat from anywhere — including from inside an LLM session.
Is this overengineered?
Honestly, no — it's the opposite. It's a single binary, three runtime dependencies (clap, chrono, thiserror), and a markdown file. The hard part wasn't writing it; the hard part was deciding not to add features (editor mode, server mode, plugins, syncing, etc.). See the roadmap's "Not on the roadmap" section.
What's the binary size? About 1.2 MB on Linux, stripped. Starts in <5 ms. Uses ~1 MB RAM. You can run it from a git pre-commit hook without noticing.
Development
Snapshot tests use insta. If you intentionally change the rendered entry format, install cargo-insta (cargo install cargo-insta) and run cargo insta review to accept the new snapshots.
Layout
The codebase is a library plus a binary, so the test suite can exercise the parser and IO directly without shelling out:
| Path | Purpose |
|---|---|
src/lib.rs |
Public re-exports, path/date helpers, constants |
src/error.rs |
Typed Error enum (NotFound, BadDate, Io, Git) |
src/parse.rs |
Pure markdown → Vec<Entry> parser (no I/O) |
src/store.rs |
File I/O including atomic_append |
src/main.rs |
clap CLI definitions and dispatch (thin) |
tests/cli.rs |
End-to-end tests via assert_cmd against tempdir sandboxes |
tests/property.rs |
proptest round-trip + insta snapshot tests |
tests/snapshots/ |
Frozen output snapshots reviewed via cargo insta review |
CI
GitHub Actions runs on every push to main and on every PR:
- Build + test on ubuntu-latest, macos-latest, and windows-latest (matrix).
- Lint:
cargo fmt --all -- --check+cargo clippy --all-targets -- -D warnings.
A push is only green when all three OSes build, all 56 tests pass, the code is rustfmt-clean, and clippy finds zero warnings.
Roadmap
0.1.x — testing & polish ✅
Test suite✅ 56 tests across 4 categoriesBetter error messages✅ typedErrorenumAtomic writes✅ shipped in 0.0.3✅ shipped in 0.0.3LOGBOOK_FILEenv varCI on three OSes✅Property + snapshot tests✅ shipped in 0.1.1Full rustdoc coverage✅ shipped in 0.1.1
0.2.x — distribution ✅ current
Publish to crates.io so✅ shipped in 0.2.0cargo install logbookworksPrebuilt binaries via GitHub Releases for macOS, Linux, Windows✅ shipped in 0.2.0 (5 targets)Homebrew tap✅ shipped in 0.2.0 (brew install jeffbai996/tap/logbook)
0.3.0 — ergonomics
logbook addopens$EDITORwhen--whyis omitted (git-commit style)logbook supersede <old-date> "new title" --why ...— formal supersession syntax linking the new entry to the old one- Colored TTY output (off when piped)
logbook export --format jsonfor tooling integrations
Maybe-someday
- Shell completion (
logbook completions bash) - A read-only web viewer that renders
logbook.mdas a timeline - Team mode: aggregate logbooks across multiple repos for retro reviews
Not on the roadmap. Editing past entries, deleting entries, server mode, GUI, plugins, multi-user sync. Scope creep is the enemy.
License
MIT. See LICENSE.