cratis-engineering-decision-record · git:20261008.bbaa5d1 · 2026-10-08 · sha256 3a82469b77b15101
cratis-engineering-decision-record git:20261008.bbaa5d1A
Immutable. This exact content never changes and is served at /api/v1/blob/3a82469b77b15101.
---
name: cratis-engineering-decision-record
description: Consult, author, accept, and supersede decision records in a Cratis repository's decisions/ folder. Use before an architectural, contract, scope, or cross-cutting change, when a ruling has been made that later work must obey, or when an accepted decision has to be replaced. Defer product documentation, session handovers, and work-item status to their own workflows.
license: LICENSE
---
# Cratis decision records
A decision is a durable choice with a **decider** and a **date**. It is
documentation, not a work record: it lives in the repository's `decisions/`
folder and is reviewed like any other documentation. A handover may summarize a
decision; it never holds the only copy.
This skill owns the *procedure* — how to consult, author, accept, and supersede
a record. It does not decide what to decide, and it never grants acceptance. Do
not turn an implementation request, issue plan, or reversible technical choice
into an approval ceremony merely because this skill is available.
## When you need this
- You are about to make a significant architectural, contract, scope, or
cross-cutting change. Consult existing records first: a decision you did not
read still binds the change. Consulting does not imply that a new record or
human approval is required.
- A human made a durable ruling — in review, in chat, or in a meeting — that
later work has to obey. Record it in the same turn, while the reasoning is
still available.
- An accepted decision no longer holds and has to be replaced, narrowed, or
qualified.
- Your change would contradict an accepted record. Stop: supersession or a human
verdict comes first, never a workaround.
## When you do not
- **Session notes, plans, handovers, status boards.** Those are work records.
They belong in the repository's ignored local working directory, never in
`decisions/`.
- **Product or API documentation.** A record says what was chosen and why; the
documentation says how the thing works. Use the documentation workflow.
- **A work item's status.** "Blocked on X" is a work item field, not a decision.
- **A reversible choice inside your own scope that nobody will re-litigate.**
Make it and move on; see the significance test in step 3.
- **An implementation request or an issue's proposed plan.** A request to do the
work authorizes ordinary in-scope implementation; it is not automatically a
request to create or accept an architectural record. Apply the significance
test and ask only about a concrete unresolved choice with meaningfully
different consequences.
- **A decision this repository does not own.** Company-level and portfolio
decisions live in the record set that owns them. Cite that id; do not copy the
record into a repository that cannot supersede it.
## Steps
1. **List the records in force for the paths you are changing.** Read
`decisions/`, keep the records whose `applies-to` matches a path you are
about to touch and whose `status` is `accepted`, and order them newest first.
Report the count — "0 records matched" and "3 matched, none contradicted" are
different verdicts and must read differently.
2. **Cite what you relied on.** Name the ids on the work item, in the pull
request body, and as a `Decision: <id>` commit trailer. A change that
silently contradicts an accepted record is a defect even when the code is
correct.
3. **Apply the significance test before proposing a record or asking for
acceptance.** Write a record only when at least one of these holds: someone
will otherwise re-litigate the choice; it binds paths beyond the one you are
changing; reversing it would cost real migration or rework; or it rejects an
option a reasonable reader would reach for. If none holds, make the change
without a record. Do not ask the user to approve labels or abstractions they
have not been given enough context to understand.
4. **Pass the completeness gate, or open with `status: returned`.** A proposed
record states the options considered *including the one not taken and why*,
the default that applies if the question is never answered and what that
default costs, the timeline the decision has to hold to, and what is in scope
and out. A record missing any of the four is returned to its proposer for
revision — `returned` is not a rejection.
5. **Write the verification criterion before acceptance, not after.** State the
observable signal that will say the decision was actually carried out, as
`Done when` and `Verify by`. A decision whose success cannot be observed
cannot reach `stage: verified`.
6. **Open the record as `status: proposed`, `stage: none`, and regenerate the
index.** A record the index does not list is a record the consult step in
step 1 will never find.
7. **Accept only after a human makes the significant choice.** Set `status` to
`accepted`, `decided` to the date, and `decider` to a named person — never a
role, a team, or a tool. Acceptance is a human verdict: draft it, do not grant
it. If the decider is not already explicit, first explain in plain language
that the choice will become durable repository documentation and why it
passed the significance test; only then ask whose name should be recorded.
8. **Spawn the build work carrying the criterion verbatim.** The `Done when` and
`Verify by` text written in step 5 travels onto the work item unchanged, so
the thing that gets built is the thing that was decided.
9. **Move `stage` only on the evidence the next stage requires.** `none` →
`implemented` when the change exists in the tree; `implemented` → `verified`
only on a signal observed this time. Accepted is not implemented, and
implemented is not verified.
10. **Supersede rather than rewrite.** Never edit an accepted record's decision
text in place — that text is what people relied on. Correct a typo or add
context under a dated banner that says what changed and why. Change the
*choice* only with a new record.
11. **Point both ways and sweep the citations.** The new record names the one it
replaces in `supersedes`; the replaced record's `status` becomes
`superseded` and it gains a `superseded-by` pointer forward, with its
original text preserved. Then find every work item, pull request body, and
commit trailer citing the old id and point it at the new one. A reader
arriving at either record must be able to reach the other.
Read [record-format.md](references/record-format.md) when authoring or updating a record or regenerating its index; it defines the exact front-matter fields, closed value sets, and index shape.
## What breaks
- **Governance ceremony before user clarity.** Asking someone to choose between
unexplained policy labels, approve an issue plan they already asked to
implement, or name a decider before explaining the durable decision transfers
the agent's interpretation burden to the user.
- **A role in the `decider` field.** "The architecture team decided" names
nobody who can be asked what they meant or who can supersede it. The record
reads as authority but resolves to no one.
- **Decision text edited in place.** The next reader sees text nobody ever
agreed to, and the people who relied on the old wording have no way to tell
what changed. This is the failure that makes a whole `decisions/` folder
untrustworthy, because it is invisible.
- **A one-way supersession.** The new record says it supersedes the old one, but
the old one still reads as accepted. Whoever arrives from a search, a
citation, or an old pull request follows a decision that was replaced.
- **`stage: verified` set on a green build.** Compilation proves it builds, not
that the decision was carried out. The stage then lies about the only thing it
exists to say.
- **A ruling that stayed in chat.** It binds the next change and nobody can find
it. The symptom is the same argument being had a second time, with a different
outcome.
- **One record settling three questions.** It cannot be superseded for one of
them, so it survives past the point where a third of it is wrong.
- **An `applies-to` that matches nothing.** Step 1 returns zero records and reads
as "nothing binds this change" instead of "the glob is wrong". Report the count
so an empty result is visible rather than reassuring.
## How it is proven
- **Consult ran and found something specific.** The count from step 1 appears in
the report, and the ids it returned appear on the work item, in the pull
request body, and in a `Decision:` commit trailer.
- **Acceptance resolves.** The record carries a `decided` date and a `decider`
that names a person you could actually ask.
- **Supersession is traversable.** Follow `superseded-by` forward and
`supersedes` back; both land on the other record. Search the repository for
the superseded id and confirm no live citation still points only at it.
- **The stage matches the evidence.** `implemented` is confirmed by the change
being in the tree; `verified` is confirmed by naming the signal — the command,
the gate, the observed behavior — that was watched *this time*.
- **The index resolves.** Every record in `decisions/` appears in the index, and
every index entry resolves to a file.