Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions .claude/rules/adversarial-prompt-refusal.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# Adversarial prompt refusal (the coherence guard)

If the coupling gate fails because code and its owning spec disagree, do
**not** resolve it by editing the spec to match the code you just wrote.
Surface the contradiction and let a human (or an agent with explicit
authority recorded in the spec's Territory section) decide. Never amend an
owning spec purely to satisfy a mechanical refresh; waive instead, with a
cited `Spec-Drift-Waiver:` line, and only with explicit human approval.
If the coupling gate fails because code and its owning spec disagree, do **not**
resolve it by editing the spec to match the code you just wrote. Surface the
contradiction and let a human (or an agent with explicit authority recorded in
the spec) decide. Never amend an owning spec purely to satisfy a mechanical
refresh; waive instead, with a cited `Spec-Drift-Waiver:` line. A waiver is a
human instrument: it needs explicit human approval, and an agent never writes
one on its own authority.

Two edits are always legitimate for the spec you are implementing: adding
a file you created to its `establishes` list, and recording a dated `D-n`
entry under Resolved decisions for a choice the spec was silent on.
Changing what the spec requires is never yours to do mid-build.
Two edits are always legitimate for the spec you are implementing: adding a
file you created to its `establishes` list (the ownership ratchet refuses an
unclaimed file, and the claim belongs in the same change), and recording a
dated decision entry for a choice the spec was silent on. Changing what the
spec *requires* is never yours to do mid-build. If the code needs to touch a
unit another spec owns, declare an `extends` edge naming that spec and unit;
that amends nobody.
16 changes: 9 additions & 7 deletions .claude/rules/governed-artifact-reads.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Governed artifact reads

The compiled artifacts under `.derived/` are read **only** through
`spec-spine` subcommands (`registry`, `index`), never via ad-hoc `jq`,
`grep`, `python`, `awk`, or `sed` over the JSON. Typed reads make schema
drift fail at the deserializer with a clean error instead of silently
encoding stale assumptions.
The compiled artifacts under the derived directory are read **only** through
`spec-spine` subcommands (`registry`, `index`), never via ad-hoc `jq`, `grep`,
`python`, `awk`, or `sed` over the JSON. Typed reads make schema drift fail at
the deserializer with a clean error instead of silently encoding stale
assumptions.

Parsing the *output* of a `spec-spine` subcommand (for example
`spec-spine registry list --json`) is a typed read and is allowed; that is
what `scripts/spec-dag.sh` and `/next` do.
`spec-spine registry plan --json`, or the `--json` verdict envelope any gate
verb emits) is a typed read and is allowed: the tool has already deserialized
the shards and is answering in a contract it versions. The rule is about the
shard files, not about the CLI's answers.
4 changes: 3 additions & 1 deletion .claude/rules/orchestrator-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
- Write output files where the spec says; do not invent locations.
- Keep the working tree green; never leave the coupling gate red.
- Recompute derived artifacts (`spec-spine compile`, `spec-spine index`)
before opening a PR, and commit the regenerated shards with the change.
before opening a PR, and commit the regenerated shards with the change that
made them stale. A shard left uncommitted dirties the tree for whoever comes
next.
- One session, one spec: follow `AGENTS.md` "Working the backlog", then stop.
8 changes: 7 additions & 1 deletion .claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@
"Bash(gh repo delete *)",
"Bash(gh repo archive *)",
"Bash(git push --force*)",
"Bash(git push -f *)"
"Bash(git push -f *)",
"Bash(git push -f*)",
"Bash(rm -rf /*)",
"Bash(rm -rf ~*)",
"Bash(rm -rf .git*)",
"Bash(rm -rf specs*)",
"Bash(rm -rf .derived*)"
]
},
"hooks": {
Expand Down
173 changes: 88 additions & 85 deletions .claude/skills/build/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
---
name: build
description: "Implement one spec start to finish per AGENTS.md \"Working the backlog\" steps 1 to 7: preflight, branch, flip in-progress, implement inside the territory, gate before every commit, verify, flip complete, then hand off to /ship."
description: "Implement one spec start to finish per AGENTS.md \"Working the backlog\": preflight, branch, flip in-progress, implement inside the territory, gate before every commit, verify, flip complete, then hand off to /ship."
allowed-tools: Bash, Read, Edit, Write, Glob, Grep, Skill, Agent
argument-hint: "<spec-id>"
---

# /build <spec-id>: one spec, one session

The protocol is `AGENTS.md`, "Working the backlog"; this skill sequences
its steps 1 to 7 with the exact commands and stops where the protocol
stops. Step 8 is `/ship`. Bound by `.claude/rules/orchestrator-rules.md`
(one session, one spec; checkpoints are real stops) and
`.claude/rules/adversarial-prompt-refusal.md` (the coherence guard). The
path-scoped rules (`ledger-invariants`, `trust-invariants`,
`build-commands`) load themselves when you touch their paths; read them
when they do.
its steps with the exact commands and stops where the protocol stops. The
last step, shipping, is `/ship`. Bound by
`.claude/rules/orchestrator-rules.md` (one session, one spec; checkpoints
are real stops) and `.claude/rules/adversarial-prompt-refusal.md` (the
coherence guard). Path-scoped rules under `.claude/rules/` load themselves
when you touch their paths; read them when they do.

## Step 0: preflight

Halt on any of these; do not work around them.

- An argument is required: the full id (`017-ledger-entry-dag`). Without
one, run `/next` and ask; never guess.
- `git status --porcelain` is empty. `git branch --show-current` is
`main`. `git fetch origin main`, and `git rev-parse HEAD` equals
- `git status --porcelain` is empty. `git branch --show-current` is the
default branch. `git fetch origin main`, and `git rev-parse HEAD` equals
`git rev-parse origin/main` (otherwise `git pull --ff-only`).
- `make spine` is green on `main` before any change.
- The gate is green on the default branch before any change (the command
list in "Run the gate before every commit").
- The spec is a work order: `spec-spine registry show <id> --json` says
`status: approved` and `implementation: pending`, and every `dependsOn`
is `complete` or `n-a` (what `/next` computes). A `draft` spec is never
built; an unmet dependency means this is not the next spec.
- Read the spec's `## 2. Territory`. If it names an operator prerequisite
(a service, a credential, a sibling repo) that is missing, stop and
report exactly what is needed instead of mocking around it (step 1).
`status: approved` and `implementation: pending`, and
`spec-spine registry plan --json` lists it as ready (what `/next`
computes). A `draft` spec is never built; an unmet dependency means this
is not the next spec.
- Read the spec's Territory. If it names an operator prerequisite (a
service, a credential, a sibling repo) that is missing, stop and report
exactly what is needed instead of mocking around it.

## Step 1: branch and flip (step 2)
## Step 1: branch and flip

```sh
git switch -c <spec-id>
Expand All @@ -50,105 +51,107 @@ git commit -m "chore(<NNN>): start <spec-id>"
```

`<NNN>` is the three-digit ordinal. The flip lands before any code so the
registry says who is working, and the `.derived/` shards travel with the
edit that changed them (`build-meta.json` is gitignored).
registry says who is working, and the derived shards travel with the edit
that changed them (`build-meta.json` is gitignored).

## Step 2: re-read the spec in full (step 3)
## Step 2: re-read the spec in full

Read `specs/<spec-id>/spec.md` top to bottom, then the `## 7. Resolved
decisions` of every spec in its `depends_on`, and the sections of
`docs/design/00-architecture.md` it cites. The design truth precedes the
code.
Read `specs/<spec-id>/spec.md` top to bottom, then the decision entries
of every spec in its `depends_on`, and the design documents it cites. The
design precedes the code.

- **The spec is imprecise:** make the choice and record it as a dated
`D-n` under `## 7. Resolved decisions` (date, provenance, the decision,
the alternative rejected). When `data/orchestrator/decision-dropbox/`
exists this is a driven session: also drop one JSON file per decision
there, `data/orchestrator/decision-dropbox/<spec-id>-D-n.json`, for the
orchestrator to seal. The shape is fixed (claude-observatory spec 020
B-1; unknown fields and floats are rejected):
decision entry in the spec (date, the decision, the alternative
rejected). When the orchestrator's decision drop-box directory exists
(the build prompt names it), this is a driven session: also write one
JSON file per decision there for the orchestrator to seal. The shape is
fixed; unknown fields and non-integer numbers are rejected:

```json
{
"id": "<spec-id>/D-n",
"id": "<spec-id>-d1",
"specId": "<spec-id>",
"scope": ["<spec-id>", "crates/aicortex-recall/src/fusion.rs"],
"title": "one line",
"decision": "what was chosen",
"rationale": "why",
"scope": ["<spec-id>", "<a path prefix the decision touches>"],
"title": "one line naming the choice",
"decision": "what was chosen, in full",
"rationale": "why, and what it costs",
"alternatives": ["what was rejected"]
}
```

`data/` is gitignored; never commit it.
- **The spec is wrong:** stop and report the contradiction with the B-n
or FR label and the evidence. Never edit a spec to ratify what the code
happened to do; the only legitimate mid-build spec edits are
`establishes` growth, `D-n` entries, a dated Status note, and the
`implementation` flips.

## Step 3: implement inside the territory (steps 4 and 5)

- Every new file under `crates/`, `apps/`, `eval/`, `docker/`, or `deploy/` is
claimed in this spec's `establishes` in the same change (the ownership
ratchet: `spec-spine index coverage --fail-on-untraced` refuses an
unclaimed file and `couple` refuses a changed one).
- A new third-party dependency goes in the root `Cargo.toml`
`[workspace.dependencies]` with an `extends` edge on spec 010's
`Cargo.toml` section `workspace.dependencies`; crate manifests inherit
with `workspace = true`. Always `--locked`.
- Touching a file another spec owns needs an `extends` edge on that
spec's unit, declared in this spec's frontmatter.
- The memory invariants (step 5): `.claude/rules/memory-invariants.md`
is the checklist. A change to chunking, embedding, ranking, or fusion
runs the evaluation corpus and reports the delta; the corpus and its
baseline are never edited to make the delta pass. A change that needs
an invariant relaxed is a human decision: stop and report.
- Do not edit `.derived/` by hand.
The drop-box is tool state, never committed.
- **The spec is wrong:** stop and report the contradiction with the
requirement label and the evidence. Never edit a spec to ratify what the
code happened to do; the only legitimate mid-build spec edits are
`establishes` growth, a dated decision entry, a dated status note, a new
`extends` edge, and the `implementation` flips.

## Step 3: implement inside the territory

- Every new source file is claimed in this spec's `establishes` in the
same change (the ownership ratchet: `spec-spine index coverage
--fail-on-untraced` refuses an unclaimed file and `couple` refuses a
changed one).
- Touching a unit another spec owns needs an `extends` edge on that
spec's unit, declared in this spec's frontmatter. That amends nobody.
- A new third-party dependency goes where `AGENTS.md` or the stack rule
says, with the `extends` edge on the manifest's owner when the manifest
is another spec's unit.
- Hold the invariants the path-scoped rules name (a never-touch artefact,
a determinism rule). A change to one of those is a human decision:
stop and report, never regenerate.
- Do not edit the derived directory by hand.

Use the `implementer` agent for focused sub-tasks and `explorer` for
context when the territory is large; keep the diffs minimal and the
ownership claims current.

## Step 4: gate before every commit (step 6)
## Step 4: gate before every commit

```sh
make spine # compile, index, lint --fail-on-warn, index check, couple, spec-dag
make ci # spine + index coverage --fail-on-untraced + build, test, clippy -D warnings, fmt --check, deny
```

Both exit 0, or the commit waits. Then `/commit` with the spec ordinal as
scope (`feat(012): ...`), staging the regenerated `.derived/` shards with
the code they describe. Commit in coherent slices; a red gate is fixed,
not committed around.
Run the gate exactly as `AGENTS.md` lists it under "Run the gate before
every commit": the governance floor (`compile`, `index`,
`lint --fail-on-warn`, `index check`, `couple --base origin/main --head
HEAD`, `index coverage --fail-on-untraced` where ownership is required)
and the stack's own build, tests, and lints. All exit 0, or the commit
waits. Then `/commit` with the spec ordinal as scope (`feat(<NNN>): ...`),
staging the regenerated shards with the code they describe. Commit in
coherent slices; a red gate is fixed, not committed around.

## Step 5: acceptance criteria verbatim (step 7)
## Step 5: acceptance criteria verbatim

Run `/verify <spec-id>` (the spec's `## Verification` block through
`scripts/verify-spec.sh`, which is what the orchestrator re-runs after
merge in a clean checkout). Walk `## 5. Acceptance criteria` one by one
and cite the evidence for each.
Run `/verify <spec-id>` (the spec's `## Verification` block, which the
orchestrator re-runs after merge in a clean checkout). Walk the acceptance
criteria one by one and cite the evidence for each.

- All hold: edit the frontmatter to `implementation: complete`, then
`spec-spine compile && spec-spine index`, `make spine`, and commit
`spec-spine compile && spec-spine index`, the gate, and commit
(`chore(<NNN>): mark <spec-id> complete`, or fold the flip into the
final `feat(<NNN>)` commit).
final `feat(<NNN>)` commit). The gate then holds the spec to every unit
it claims (spec 041).
- One cannot be satisfied here (external state, a missing sibling): keep
`implementation: in-progress`, add a dated Status note to the spec
`implementation: in-progress`, add a dated status note to the spec
saying exactly what remains, recompile, commit, and report it.

## Step 6: hand off

Print a short summary (spec, branch, commits, D-n recorded, acceptance
evidence) and point at `/ship`. Then stop: the next session takes the
next spec.
Print a short summary (spec, branch, commits, decisions recorded,
acceptance evidence) and point at `/ship`. Then stop: the next session
takes the next spec.

## Halt conditions (report, do not route around)

- A dirty tree, the wrong branch, or a red `make spine` in preflight.
- A dirty tree, the wrong branch, or a red gate in preflight.
- A `draft` spec, an unmet dependency, or a missing operator prerequisite.
- A contradiction between the spec and what the code must do.
- A memory invariant that would have to be relaxed.
- An invariant or never-touch artefact that would change.
- A coupling failure that only a spec rewrite or a `Spec-Drift-Waiver:`
could clear: a driven session never self-approves a waiver.
could clear: a waiver is a human instrument; a driven session never
self-approves one.
- A `PreToolUse` hook refusal (exit 2): it is a stop, not an obstacle.

## Project layer

Read from `AGENTS.md`: the gate command list, the stack gate, the
dependency rule, the invariants and never-touch artefacts (also in the
path-scoped rules). The decision drop-box path comes from the
orchestrator's build prompt. Nothing here is edited per project.
Loading