Recording why
Decisions as events, superseding that cannot half-apply, and documents linked to the work they explain.
The journal records what happened. Since 0.3.0 it also records why — and the reasoning cannot quietly go stale, because reversing a decision is one event rather than two edits somebody has to remember to make.
Record a decision
kadence decision add "Store sessions in a signed cookie" \
--why "The redirect drops server-side session state" \
--rejected "Server-side sessions: the redirect is where they break" \
--task KAD-1DEC-1 recorded.--why is required. Without it the record says only what changed, and git
already says that. --rejected is the field that pays for itself later: it is
what stops the next session — human or AI agent — from proposing the thing that
was already tried.
--task attaches the decision to the work it came out of, so it comes back with
kadence task show. --doc points at a document that carries the detail.
Reverse it later
kadence decision add "Signed cookie, rotated hourly" \
--why "A stolen cookie stayed valid for a week" --supersedes DEC-1DEC-2 recorded.
It replaces DEC-1, and both links were written by one event — neither side can go stale.That sentence is the whole feature. In a file-based tool, superseding is two edits: mark the old record replaced, and note in the new one what it replaces. The sources on ADR practice are blunt about what happens — somebody updates one side, and a reversed decision goes on looking authoritative. Here the backward link is derived while folding, so nobody writes the second half and nobody forgets it.
What you get back is what still holds
kadence decision list # decisions in force
kadence decision list --all # with the history
kadence decision show DEC-1DEC-1 Store sessions in a signed cookie
!! SUPERSEDED by DEC-2 — this is no longer in force.
Why: The redirect drops server-side session state
Rejected: Server-side sessions: the redirect is where they break
Task: KAD-1The default is the safe answer, because an AI agent quoting a reversed reason as
current is worse than one with no memory at all. show announces the
supersession before the reasoning, for the same reason.
DEC-N is derived, like KAD-N
Identity is the ULID; the number is assigned while folding. Two branches can each
record a decision and merge without a conflict and without a renumber — an
integration test on real git branches proves it. log4brains, a mature ADR tool,
dropped file numbering entirely to avoid exactly this conflict; keeping both is
what the event model buys.
Who wrote it
Since 0.3.1 every decision carries its author's kind — source: "human" or
"agent", taken from KADENCE_SOURCE at the moment the event was written.
kadence never guesses this when writing; the field is what makes that refusal
worth something when reading. decision list and decision show print it, and
the human output marks only agent-written records: in a repository written
mostly by people, labelling every human one would hide the exception.
DEC-3 Fold notes into prime agentDocuments, linked rather than stored
kadence task doc KAD-1 docs/design.md
kadence decision add "…" --why "…" --doc docs/auth.mdkadence does not store the document. It stays plain markdown, and git keeps versioning it. What git cannot say is that this file explains this task, and that is the only thing recorded.
A missing file is a warning, not a refusal — it may arrive in a later commit or live on another branch, and refusing would make the journal depend on what happens to be checked out.
There is deliberately no kadence doc command. The event model gives a document
nothing git does not already give it; the link is the part that was missing.
What that is worth, measured
Across five real questions in the kadence repository, a grep for the natural
term finds the answering document every time — and buries it among 10–35
candidates: 1.3 MB of candidates against 39 KB of linked documents.
The link does not save the search. It saves the sifting, and sifting is what costs a context window. The stronger argument needs no numbers: grep requires knowing the term, and a link arrives with the task.
Full write-up: Probe D.
For an AI agent
task show --json carries decisions and docs; both are always arrays, so
an agent never has to branch on their absence.
kadence decision list --json{"schema":"kadence/v1","ok":true,"decisions":[{
"label":"DEC-2","title":"Signed cookie, rotated hourly",
"why":"A stolen cookie stayed valid for a week","rejected":null,
"task":"KAD-1","docs":[],"supersedes":"DEC-1","supersededBy":null,
"superseded":false,"at":"2026-09-08T14:31:39.221Z","by":"ana@example.com"}]}The reasoning is in ADR-010.