The Decision Decay Problem

You’re staring at a function that was rewritten six months ago by an AI agent. The commit message says refactor: update pagination. The PR had fourteen comments, most of them automated lint suggestions. The agent’s session log? Compacted into oblivion three weeks after the PR merged. This isn’t hypothetical. As agent-assisted development scales, the ratio of code-written to reasoning-captured is diverging fast. More code, less institutional memory.

You know what changed — Git handles that. You can guess how — the diff tells a story if you read it carefully. But why this approach? What was rejected? What trade-off was made? That’s gone.

This is decision decay: the systematic loss of reasoning context as it moves from an agent’s session to a commit to a merge to the long tail of your codebase history.

Key Takeaway

Decision decay isn’t about bad documentation practices. It’s structural. The tools we use for code (Git, PRs, CI) are designed to track artifacts, not reasoning. The reasoning lives in ephemeral contexts — chat sessions, PR threads, Slack discussions — that rot by design.

What Timbers Actually Is

Timbers is a CLI tool that captures the what, why, and how of development decisions as structured JSON files in a .timbers/ directory inside your repo. It’s written in Go, installs in seconds, and has exactly one opinion: decisions should be recorded at the moment they’re made, by whoever (or whatever) made them.

The API is three fields. One is optional:

Field Purpose
what What you did, in one line
why The trade-off, the verdict
how The approach you chose
notes (optional) The journey to the decision — what was tried, what was rejected
timbers log "Switched to cursor-based pagination" \
  --why "Offset pagination skips rows when items are inserted between pages" \
  --how "Opaque cursor tokens encoding created_at + id" \
  --notes "Offset was simpler but users reported duplicate items in feeds. \
           Cursors are stable under concurrent writes."

That entry lands as a JSON file in .timbers/, committed alongside the code it documents. Portable, queryable, durable. The file-per-entry design is deliberate: atomic writes, no merge conflicts in concurrent worktrees, and no database dependency. The repo is the database.

The Agent Integration Story

Timbers was designed for agents to use natively. If your agent can run shell commands, it can use Timbers. The workflow is straightforward:

sequenceDiagram
    participant A as AI Agent
    participant T as Timbers CLI
    participant G as Git Repo

    Note over A: Session starts
    A->>T: timbers prime
    T-->>A: Ledger context + recent entries
    Note over A: Agent works on code

    A->>G: git commit -m 'Add caching layer'
    Note over A: Agent documents reasoning

    A->>T: timbers pending
    T-->>A: 1 commit awaiting documentation

    A->>T: timbers log 'Added write-through caching' --why '...' --how '...'
    T->>G: .timbers/entry.json created

    Note over A: Session ends. Reasoning persists.

The prime command is the clever bit. At session start, it injects the project’s recent decision history into the agent’s context — so the agent knows not just what the code looks like, but why it looks that way. It’s context injection for institutional memory.

Tip

Claude Code has the deepest integration via hooks that auto-inject timbers prime at session start. For other agents (Gemini CLI, Cursor, Windsurf, Codex, Aider), add the workflow to your agent’s instruction file — AGENTS.md, .cursor/rules/, etc.

From Ledger to Artifacts

Raw ledger entries are useful. Processed ledger entries are powerful. Timbers ships seven built-in templates that transform your decision history into documents:

  • changelog — Release-ready change summaries
  • decision-log — Architectural decision records extracted from your entries
  • devblog — Blog posts generated from your development story
  • pr-description — PR bodies that actually explain the why
  • release-notes — User-facing release documentation
  • sprint-report — Sprint summaries for stakeholders
  • standup — Daily standup bullets from yesterday’s work

The draft command renders these templates against your ledger. When not using the built-in --model flag, piping the output through an LLM CLI like claude -p is the expected workflow for polished results:

# Pipe to any LLM CLI (uses your subscription, not API tokens)
timbers draft changelog --since 7d | claude -p --model opus

# Or use built-in LLM execution
timbers draft standup --since 1d --model opus

# List all available templates
timbers draft --list
Definition

Decision log: The decision-log template is particularly valuable. It extracts the why behind each change into an architectural decision record — the kind of document teams mean to write but never do. Timbers generates it from data that already exists.

You can also create custom templates for project-specific needs. Templates resolve in order: .timbers/templates/~/.config/timbers/templates/ → built-in.

Why Not Just Better Commit Messages?

A reasonable objection: “Why not just write better commit messages?” Three reasons.

Structure matters. Free-text commit messages don’t separate the what from the why from the how. You can’t query “show me every decision where we chose consistency over performance” against commit messages. You can against Timbers entries.

Agents don’t write good commit messages. They write adequate ones. The reasoning that led to the commit is rich and nuanced in the agent’s session — but the commit message is a lossy compression of that reasoning. Timbers gives agents a structured place to dump the full context.

Commit messages are coupled to commits. Not every decision maps 1:1 to a commit. Sometimes one decision spans five commits. Sometimes five decisions collapse into one commit. Timbers entries decouple documentation from commit topology — but can optionally tighten it. Without hooks, timbers log creates one entry covering all commits since the last documentation point. With the optional pre-commit hook, it enforces a 1:1 cadence: one entry per commit. If commits slip through undocumented — hooks bypassed, not installed, or commits arrived via rebase — it falls back gracefully to batch mode. There’s a philosophical angle here too. Commit messages describe what happened. Timbers entries describe what was decided. These are different things, even when they overlap.

The Bigger Picture

Timbers sits in an emerging category of tools designed for a world where AI agents are first-class contributors to codebases. The assumptions are shifting:

  • Code authorship is mixed. Humans and agents co-author. Attribution and reasoning need to work for both.
  • Session context is ephemeral. Agent sessions are not permanent records. If reasoning isn’t captured during the session, it’s lost.
  • Documentation is a write-time problem. The traditional approach — document after the fact — fails when the decision-maker’s memory (the session) no longer exists.

Timbers’ bet is that capturing decisions at the moment they’re made is cheaper, more accurate, and more durable than any after-the-fact reconstruction.

Warning

Timbers doesn’t replace commit messages, PR descriptions, or design documents. It complements them by capturing the layer of reasoning that those artifacts lose. If your team already writes thorough ADRs for every change, you might not need it. If your team means to write ADRs but never does — that’s the sweet spot.

Getting Started

Installation is a one-liner:

# Linux/macOS
curl -fsSL https://raw.githubusercontent.com/gorewood/timbers/main/install.sh | bash

# Or with Go
go install github.com/gorewood/timbers/cmd/timbers@latest

Then initialize in your repo and start logging:

timbers init
timbers log "what" --why "why" --how "how"
timbers query --last 10

Every command supports --json for machine consumption. Write operations support --dry-run.


Discussion

  • How much of your team’s decision context lives in places that won’t exist in six months?
  • If your agents started logging why alongside what, would your onboarding story change?
  • What’s the right granularity for decision capture — per commit, per feature, per session?

References