Skip to content

majordomus decision

Record a decision that was made between real alternatives, with its reason, and read them back.

Record a decision that was made between real alternatives, with its reason, and read them back.

  • state-mutating
  • memory
  • active task optional

An entry is never edited or deleted. --supersedes records that a later decision replaced an earlier one, leaving both readable.

Syntax

majordomus decision add "<what was decided>" --why "<rationale>"

Lifecycle

  1. Set up
  2. Begin
  3. Work
  4. Verify
  5. Conclude
  6. Inspect

Other commands at this stage:context, checkpoint, question, prompt, evidence, skills, capture.

Reads

  • .ai/local/state/current.yaml
  • .ai/local/state/decisions.md

Writes

  • .ai/local/state/decisions.md
  • .ai/local/state/ledger.jsonl

Exit codes

Only the codes this command can produce. The full contract is on the commands index.

  • 0 ok
  • 2 usage
  • 12 missing artifact

Why it was done this way

A decision records a choice between real alternatives together with its reason. An entry is never edited or deleted; a later decision supersedes an earlier one and both stay readable.

Recording a decision with its reason

reason given
yes

Given this repository

# ... and an active task scoped to lib, with work done inside that scope.
. "$FIXTURE_SETUP/installed.sh"
"$MJ" start "narrow the parser" --scope lib >/dev/null
echo work >> lib/a

Run

$ majordomus decision add refuse tabs in the parser --why two encodings for one token

Output contains

  • recorded: refuse tabs in the parser

exit 0

The task id and the git head are computed and attached, so a decision can always be placed against the state of the repository when it was taken.

Reading them back

reason given
yes

Given this repository

# An active task that has already produced a checkpoint, a decision and an open question.
. "$FIXTURE_SETUP/active-task.sh"
printf 'the parser now refuses tabs\n' | "$MJ" checkpoint >/dev/null
"$MJ" decision add "refuse tabs in the parser" --why "two encodings for one token" >/dev/null
"$MJ" question add "should tabs be an error or a warning?" >/dev/null

Run

$ majordomus decision list

Output contains

  • refuse tabs in the parser
  • Why: two encodings

exit 0

The reason is part of the record, not a commit message someone may or may not have written. A decision without one is the thing a later worker cannot safely revisit.

Reference

Record or read durable decisions. One append-only file: state/decisions.md.

decision add "<what>" --why "<why>" appends an entry with the task relation and git head computed. --why is required: a decision with no recorded reason cannot be reviewed later, only re-argued. --rejected and --evidence are optional and default to -.

An entry is never edited or deleted. --supersedes "<text>" records that a later decision replaced an earlier one. The text is matched against the titles of the recorded decisions only, must identify exactly one of them, and that title is what is recorded; text matching no title, or more than one, is refused, so a supersession always points at one real decision. decision list marks a replaced entry with Superseded by: <title>.

decision list [--task <id>] [--limit <n>] prints entries newest first; decision show "<text>" prints the first entry whose title contains that text, or exits 12.

Decisions, questions, checkpoints, handovers and knowledge observe prepare attribution once. An explicit caller identity resolves its own open episode or none; an unknown identity never borrows the checkout's pointer. With no supplied identity, exactly one local open episode is unambiguous; zero or several produce an event with no session, and status may still show the pointer as a guess. A record relates the active task unless a different episode that is still open opened it (its task.started event names that episode); a task whose opener closed, or that opened outside an episode, is carried on by whoever continues it, and a handover never closes another live episode's task. Markdown uses none for an absent task; the event omits task_id. The record is still written.

The deep-work profile sets verification.decision_record_required: true; finish then refuses completed unless an entry names the task.

$ majordomus decision add "Normalise the callback URI before comparing state" \
    --why "the mismatch is a trailing-slash difference, not a forged state parameter" \
    --rejected "relaxing the comparison, which would accept genuinely forged states" \
    --evidence "test/auth/callback_test.exs:41"
recorded: Normalise the callback URI before comparing state

Evidence

Every case below runs in CI on Linux and macOS. The site refuses to build if a public command has no behavioural case, no negative case, or no demonstration.

Guarantees this command carries

Searches the titles and descriptions of every page this site publishes.