kadence
Decisions

ADR-010 — Decisions as events, documents as links

Superseding that cannot half-apply, and why there is no kadence doc command — accepted 2026-09-08.

Date: 2026-09-08 · Status: accepted · Scope: event schema, CLI contract, agent interface

Context

The journal records what happened. It did not record why, and the research converged on that gap from three independent directions within two days:

  1. A practitioner working with Claude Code and Codex arrived at the format Decision: X. Why: Y. Rejected: Z. and named the mechanism — what was done survives context compaction, why it was done does not, so the next agent re-proposes what was already rejected.
  2. Context-engineering practice separates structural context (what the code does) from semantic (why it exists), and holds that without the second an agent is a pattern-matcher rather than a decision-maker.
  3. Distributed-team practice names "decisions written down where they can be found" as the first of three conditions for cheap coordination. kadence already satisfied the other two — status visible without asking, and numbers derived rather than reported.

We are not first. backlog decision and backlog doc ship today; the ADR ecosystem is adr-tools and a dozen rewrites, log4brains, MADR tooling, a Backstage plugin. So the question was never whether to have decisions, but whether our shape does something theirs cannot.

Options considered

How superseding works

OptionProsCons
Two events — decision.recorded then decision.supersededreads literallyreintroduces the two-write problem inside our own model: the second event can be missing
One event carrying supersedes, backward link derived while foldinga single write; both directions cannot fall out of stepthe backward link exists only after a fold — nothing to grep for in the files
Mutable status field on the decisionfamiliar from ADR filesedits the journal, which the whole architecture forbids

What decision list returns by default

OptionProsCons
Everythingnothing hiddenan agent quoting a reversed reason as current is worse than one with no memory
Current only, --all for historythe safe answer is the one you get without thinkinga caller who wants history must know the flag

Documents

OptionProsCons
kadence doc — create and store documentsmatches the competitor feature-for-featuregit already versions files; the event model adds nothing to a document. A wrapper around touch
Links only — a task or decision points at a pathrecords the one thing git cannot expressa link can dangle when the file moves
Nothingno new surfacemeasured cost: Probe D

Decision

Superseding is one event. decision.recorded carries supersedes; the backward link supersededBy is derived while folding. In a file-based tool this is two edits, and the sources are blunt about the result — most teams update one side and forget the other, which is how a reversed decision keeps looking authoritative. Here nobody writes the second half, so nobody forgets it.

decision list returns current decisions. History needs --all.

DEC-N is derived during the fold, from ULID order, exactly like KAD-N. log4brains deliberately dropped file numbering to avoid git merge conflicts — a mature ADR tool paying for merge safety with readable identifiers. We keep both, and an integration test proves two branches can each record a decision and merge cleanly.

Documents are linked, not stored. kadence task doc KAD-1 docs/design.md and decision add --doc <path> record a repository-relative path. There is no kadence doc command. A missing file is a warning, not a refusal: the document may arrive in a later commit, and refusing would make the journal depend on what happens to be checked out.

Consequences

  • Positive: the one property no file-based tool has — supersession that cannot half-apply — is now ours by construction rather than by discipline. Decisions travel with the branch, merge without conflict, and reach an agent through the same --json contract as everything else.
  • Cost: two new event types (decision.recorded, task.doc_linked), four commands, one error code, and two fields on the task record. The ambient instruction section grew by one line, to 182 tokens.
  • Invisible by default, and that is a known trap. Conflict-free merging was true and unnoticed until we printed a notice. So decision show announces a superseded record before its reasoning, and decision add --supersedes says that both links came from one event. Both were found missing by running the commands by hand after a green suite.
  • What architecture does not fix: ADRs died of ceremony, of having no operating model, and of having a single author. Writing the event through the same CLI that moves the work defends against the first. Nothing here defends against the other two, and no code will.
  • Revisit if: the interviews show teams have no workaround they already run for capturing why. That would mean we are selling discipline rather than a tool, and the right response is to remove this, not to promote it.

The canonical record is 010-decisions-as-events.md in the product repository. If the two ever disagree, the repository wins.

On this page