cratis-engineering-decision-record · git:20260912.3d6412c · 2026-09-12 · sha256 5bb5d534a2ea7333

cratis-engineering-decision-record git:20260912.3d6412cA

Immutable. This exact content never changes and is served at /api/v1/blob/5bb5d534a2ea7333.

---
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.

The exact front-matter fields, the closed value sets, and the index shape are in
[record-format.md](references/record-format.md).

## 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.