# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

@AGENTS.md

---

Above the rule: the shipped harness doc. Below: guidance for developing this repo.

## What this repo is

A Claude Code plugin (`shapeup-sdlc`). AGENTS.md is a **shipped product artifact** —
`bin/init.mjs` splices its `<!-- HARNESS_START -->…<!-- HARNESS_END -->` block into
consumer projects. Editing it is a product change: speak in skills/commands/options,
never `.mjs` paths.

## Commands

- `npm test` — Tier-0 structural suite (`tests/structural/`); zero deps, no install step.
- `claude plugin validate . --strict` (and the same for `./.claude-plugin/marketplace.json`) — CI parity.
- `claude --plugin-dir .` — load the working copy without installing.
- `npm run demo` — regenerates `docs/assets/demo-gate.svg` by running the real gate hook; never hand-edit the SVG.

## Rules that prevent breakage

- Zero dependencies is load-bearing: executable code is plain Node ESM (`.mjs`),
  `node:` builtins only, no network calls anywhere.
- Hooks fail open, never closed, unless the bad state is positively proven
  (`hooks/sandbox-guard.mjs` is the reference implementation).
- A version bump touches both `package.json` and `.claude-plugin/plugin.json`;
  release CI fails on mismatch.
- A new worker skill takes 3 steps: `SKILL.md` → declare fields in
  `kernel/schemas/domain.schema.json` → teach `harness compile` and
  `harness reduce ingest`. Step 1 alone yields a skill the orchestrator can't dispatch.
- `tools/` is repo-only and never ships; what ships is the `files` allowlist in `package.json`.
- Commit subjects: `type(scope): lowercase declarative`.

## Keeping the docs and the plugin honest

This repo is both a product and its own blueprint, and the two drift apart silently — a doc
saying "11 workers" over a 10-member enum reads perfectly. Two standing rules:

- **Derive facts from artifacts, never from prose.** Enums come from
  `kernel/schemas/domain.schema.json`, counts from the filesystem, and hook behavior
  from *executing the hook* against a fixture. A doc, a glossary and a screenshot can all agree
  with each other and all be wrong; reading any one of them just confirms the others.
- **Nothing in the shipped set may reference something the user did not receive.** No benchmark
  results, internal defect IDs (`HD-00x`), migration stage names, audit codenames, or paths into
  `docs/`, `tests/`, `tools/`, `evals/`. Keep the operative rationale, drop the evidence: a
  comment should explain *why* the code is shaped that way without citing an artifact the reader
  cannot open.

Run the **`harness-maintenance-audit`** skill (`.claude/skills/`) for both passes — before a
release, after adding or removing a skill/operation/hook/command, and after any cleanup or rename
commit, whose blast radius is routinely wider than its subject line claims. It fixes docs and
reports code defects separately, on purpose: a doc fix records reality, a code fix changes it.

Two traps it exists to catch, both of which have bitten this repo:

- A red check nobody has looked at. Run `npm test` and `npm run demo` *before* editing — a suite
  you have not run is an assumption, not a baseline. Never make a red check green by weakening it.
- A stale measured number. Trigger and acceptance rates belong to a run with a model and a date.
  If the dataset changed, say the measurement predates it — do not rescale the figure to match a
  count you just derived, which silently manufactures a measurement.

And one the audit cannot catch, because nothing run from this checkout can. Running the repo as its
own plugin puts the plugin root inside the working directory, and every experiment ends with its run
trace deleted, so two whole classes of defect are invisible here: anything gated on where the plugin
is installed, and anything that happens *after* a run ships.

**The soak is how you find those, and it is not a release gate.** Calling it one was a promise the
instrument cannot keep: on the live consumer a soak validates through BUILD and stops there, so
"soaked across two consecutive features" is evidence about the phases it reached and silence about
the rest. Run it to find defects — it has produced most of the register — and read a clean soak as
"nothing surfaced in BUILD", never as "the candidate is fit to ship".

What a release candidate *can* be held to, because it is cheap and it caught the class that worried
us: fire the changed hook from a plain `git archive` copy of the tree at some other path, with a
different project as `cwd` (this is what a marketplace clone is, and it proves a cross-directory
import resolves where the plugin actually lands), then drive one real nested session —
`claude -p --plugin-dir <repo> --permission-mode acceptEdits` — and confirm the decision reached
`decisions.jsonl`. An enforcement layer that fails to load fails OPEN and silently: exit 1, no
stdout, no ledger row, and the tool call proceeds. A missing row is the signal.
