Command reference
Every command, run from your site-machine clone, with the line that tells you it worked. <site-dir> is always the site's directory. Exit codes are uniform: 0 accepted, 1 refused, 2 usage or spec error.
The gate
node tools/site-step.mjs status <site-dir>
node tools/site-step.mjs next <site-dir>
node tools/site-step.mjs start <site-dir> <step> [--actor <name>]
node tools/site-step.mjs done <site-dir> <step> [--note "…"] [--evidence <path>]
node tools/site-step.mjs block <site-dir> <step> --blocker <id> --reason "<20+ chars>" [--evidence <path>]
node tools/site-step.mjs sign <site-dir> <step> --by "<name>" [--note "…"]
| Command | Success prints |
|---|---|
status | One line per step (OK, BLK, ... or blank), then N done · N blocked · N in progress · N open (of 15). |
next | <step> [<actor>] per ready step — or the HALTED — block. |
start | started <step> [<actor>] |
done | ok <label>: <detail> per predicate, then closed <step>. On refusal: cannot close <step>: N exit predicate(s) failed and the halt block on stderr. |
block | blocked <step> — <blocker> |
sign | <step> signed by <name> (<role>) and a reminder to run done. |
Preflight and attestation
node tools/doctor.mjs [<site-dir>]
node tools/attest.mjs record --by "<name>" --two-factor --token-scopes "<what was reviewed>"
node tools/attest.mjs show
Doctor: five ok lines and preflight ok — 5/5 checks passed (preflight.json written). Attest: attested — <name>, <date> (expires in a year; preflight will re-ask).
Declarations
node tools/site-context.mjs init <site-dir> [--profile site|app] [--client] [--ai-feature] [--ai-chatbot]
node tools/site-context.mjs design <site-dir> --project-id <id> --pair "--text-body on --surface-page" # text token on background token, as named in tokens.css
node tools/site-context.mjs routes <site-dir> / /about /impressum /404
node tools/site-context.mjs mail <site-dir> --sends true|false
node tools/site-context.mjs urls <site-dir> --live https://example.de --preview https://x.pages.dev/
node tools/site-context.mjs hosting <site-dir> --processor <name> --outside-eu true|false
node tools/site-context.mjs show <site-dir>
Also verify, processor, bfsg, legal, edge, jurisdiction. This is the only writer of site-context.json; edit the file by hand and the next predicate that reads it may refuse the shape.
Evidence writers
node tools/mwg-install.mjs install <site-dir>
node tools/mwg-install.mjs verify <site-dir>
node tools/measure.mjs <site-dir> <url> [--runs N]
node tools/jury.mjs dimensions
node tools/jury.mjs record <site-dir> ballots.json
node tools/publish.mjs probe <site-dir> [--step publish-preview]
node scripts/verify-receipt.mjs audit <site-dir> <url>
node scripts/verify-receipt.mjs check <site-dir>
node scripts/verify-receipt.mjs waive <site-dir> "why"
node tools/reverify.mjs --sites-root <dir> [--site <name>]
| Command | Success prints |
|---|---|
mwg-install install | ok modern-web-guidance <version> installed at .agents/skills/modern-web-guidance and the lock line with a tree hash. |
mwg-install verify | modern-web-guidance is installed and matches its lock |
measure | the floor holds — median <n>, spread <n> across 5 runs. Needs an existing run-state.json and something serving the URL. |
jury record | Per-dimension medians, then the jury holds — all 11 dimension(s) at or above 3, median of 3 scorers. A malformed filing writes nothing. |
publish probe | Per-route ok, then PASS — N route(s) at <url> — all of: x-robots-tag: noindex | content-security-policy: default-src. |
verify-receipt audit | A scorecard and PASS — receipt written. Safe to claim done. |
verify-receipt check | Nothing; exit 0. |
Dry-running a predicate
Any predicate runs by hand and writes no state. Useful while fixing, before the next done:
node tools/predicates/contrast.mjs <site-dir>
node tools/predicates/ux-review.mjs <site-dir>
node tools/predicates/security.mjs <site-dir>
Developing the machine
npm run verify # tsc --noEmit + node --test (63 files)
npm test
npm run typecheck
CI runs on Ubuntu without Chrome, gh or wrangler, so the browser predicates skip themselves there. CI green is not the same as a first run being green — run the doctor on a real machine.
Common misconceptions
Skills are prose; an agent can read them out of order or not at all.
workflow.yaml is read by site-step.mjs, and done re-checks prerequisites every time. Tests pin the skill prose to the code, not the other way round.
A person approved it, so it is done.
done closes.The signature is one predicate. The jury medians or the legal checks still have to pass in the same done.
An empty log is a clean log.
Components on disk that the ledger never saw written are violations. The likeliest cause is a session without the hooks, and the message says so.
security.mjs said all defences are in place.
"Declared, not proven live"; "required elements present". The live header check and the human reviewer exist because the file check cannot see further.
File a record saying the average was 4.
Medians are computed from three distinct scorers' ballots on the identical rubric. An asserted aggregate is never read.
Status will show what needs redoing.
Freshness bites when a step is run again: ux-review, the jury and the receipt refuse if older than the newest source file. publish-live re-checks the receipt for you; the others you re-run.
Reference card
Model: a gate — steps in a fixed order, each closed only by code verifying evidence on disk; the writer never certifies.
Parts: workflow.yaml (15 steps) · site-step.mjs (the gate) · 23 predicates · 7 actor skills · 2 hooks (log, guard) · the ledger · the receipt.
Loop: next → do the step → done. Refusal = halt; lifted only by succeeding on the same step. Escape only via a validated blocker with evidence.
State: in the site root and <site>/.claude/state/; operator state in ~/.local/state/site-machine/; nothing in the plugin.
Numbers: perf ≥ 0.90 · a11y 1.0 · LCP ≤ 2.5 s · CLS ≤ 0.1 · TBT ≤ 200 ms · ≤ 150 kB script · contrast 4.5:1 both schemes · 5 Lighthouse runs, spread ≤ 5 · jury 3 scorers, 11 dimensions, median ≥ 3 · receipt valid 24 h · 31 mandatory patterns · attestation yearly.
Rules of thumb: restart after installing · never open the plugin repo as the project when building · ${MACHINE} is YAML-only · a predicate says what it saw, never "secure" or "compliant".