witness-design — spec → approved look → gate
Ground rules (every witness skill)
Resolve the CLI once per session:
WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.14.4}"
- Render the CLI's decision output verbatim and in full — every line, unmodified. Never print a command set you remember; never recompose, reformat, summarise or reorder what the CLI emitted. Which decisions are live, how they rank, and what each costs are the CLI's answers, and they change with the round, the bound, the repair grant and the content sha — a remembered set is wrong in more states than it is right.
- The human decides; you may type it. Run a
witness decide verb when the human names an option — its number or its verb — or gives a bare affirmation ("y", "ok", "go") while a CLI-rendered decision block carrying a recommended option is on screen: the affirmation selects the recommended option, and you append --via affirmation to the printed command. Otherwise the string is run byte-for-byte: never recomposed, never reformatted, never with a placeholder you resolved yourself. The moment you compose a --note or resolve an id, you are authoring their decision. A nod never takes --approve --override, --stop, a trust grant, or witness abandon — those require naming, and the CLI refuses them with nod-cannot. A block with no recommendation also requires naming. Questions you authored yourself (the brainstorm interview, the design converge step) are conversation, not a block: an affirmation there accepts your stated recommendation, with no selection entry, no journal claim and no flag. A selection does not survive session death: killed and re-run, render the block again and ask again.
- Never edit
specs/**, plans/**, or designs/**. The CLI is the sole writer of state. Author HTML in $(mktemp -d) and hand it to witness design. (The canon guard blocks direct edits; the trailer audit catches end-runs.)
- Read canon with
witness read <id>, never by path. Canon lives at the primary root; inside a worktree the files are absent by design, so a path read finds nothing and a stale copy cannot be mistaken for the contract. Fat artifacts: witness read <spec-id> --design --outline, then --lines <a>-<b>.
- Read a file before your first edit of it in this session. Relay boundaries,
verify-red's stash cycle, and worktree re-attach all change files under you — an edit against a remembered copy is how "modified since read" and partial applies happen. The CLI now prints stale-reads: when it churns the tree; treat that list as unread.
- Never invoke gate reviewers or relay verdicts.
witness gate design runs the design-critic itself and journals what it said.
- Refusal repair loop:
witness design exiting 2 prints structured violations (field · rule · got · want). Fix and retry — 3 total attempts, then stop and show the human the list verbatim.
- A refused or hook-blocked command is a stop, not a step to drop. Re-issue it on its own; if it still refuses, tell the human what was blocked and why. Never proceed by deleting the refused half of a compound command — a dropped step is silent, and silence is how a skipped check becomes a shipped defect.
- Re-entrancy: derive position from
$WITNESS next / the dashboard / log, never from conversation memory.
When you run
The /witness loop invokes you for a ui-flagged spec in a feature effort whose design is pending (missing or stale). fix/chore specs never reach you. Two modes:
- New screen —
$WITNESS read <spec-id> --design refuses no-design: there is no living look yet. Design from the spec.
- Amend a living look — the file exists but the spec was amended. Read the current look first; propose the smallest change that re-serves the (changed) behavior. If there is genuinely no visual delta, tell the human to run
witness design <spec-id> --reconfirm (re-stamps, no session).
Inputs (rebuild them, never remember them)
$WITNESS read <spec-id> # the parent spec — Behavior is your coverage contract
$WITNESS index # sibling specs, for pattern consistency
$WITNESS read <spec-id> --design # the current look, in amend mode; its `no-design`
# refusal IS the new-screen signal, so read it, don't hide it
# the repo's design canon, if configured — read docs.design from witness.config.yaml:
# docs: { design: [docs/ui/design-language.md, ...] } → read each; it is the blocking authority
The session (interactive — this stage is human judgment)
- Context. Name the screen's one job and primary user (from the spec's Motivation + Behavior). If a design canon is configured, read it — it governs hierarchy, framing, action placement, and component vocabulary. Report what you found before proposing.
- Diverge. Produce 2–3 genuinely distinct structural directions that serve the job (different hierarchies/groupings), each consistent with the canon. One idea is never enough — divergence is what surfaces a better structure than the obvious one.
- Converge. With the human, pick or synthesize the winner — and ask for that choice the same way every other decision in this pipeline is asked: a recommendation, a one-line why, the strongest alternative with when it wins and what it costs. Every behavior the spec promises must be visible and operable in the winner (the design-critic checks this as blocking coverage).
- Author the artifact. One self-contained HTML file — inline all CSS/JS, embed assets as
data: URIs, no external src/href. Give every section a stable, unique id (id="essentials", id="save-bar", …): these are the design-critic's anchors and must total ≥ 2. Data-shape anchoring: when a section renders spec data, name the id after the data it shows, not its pixels.
DIR=$(mktemp -d)
cat > "$DIR/look.html" <<'EOF'
<!doctype html>
<html><head><meta charset="utf-8"><style>/* inline tokens + layout */</style></head>
<body>
<header id="eyebrow">Bookings</header>
<main id="essentials"><!-- the 5 things that matter, dominant --></main>
<details id="advanced"><!-- tuning fields, subordinate --></details>
<footer id="save-bar"><!-- primary action, always reachable --></footer>
</body></html>
EOF
$WITNESS design <spec-id> --file "$DIR/look.html"
$WITNESS design <spec-id> --open # opens the artifact for the human — required before the gate
- Register, then show.
witness gate design refuses design-unseen until the human has been shown the artifact's current bytes, so --open is part of the flow, not a nicety. Re-authoring re-arms it: new bytes, new showing. witness next names this step by itself — follow it.
- The opener failing (
opener-failed) prints a file:// path. Give the human that path verbatim and stop; do not work around it by pointing opener: in .witness/config.local.yaml at something that does not show anything.
Gate
$WITNESS gate design <spec-id> # append --manual when the run asked for it
- The design gate always stops — the look is human judgment, same footing as ship. It refuses to run at all until
witness design <spec-id> --open has shown the human the current artifact. Render the gate output verbatim and in full, including its ranked options and run: line. END YOUR TURN. You never decide. The findings are about the design — they are never a substitute for the human being shown it.
- Re-entered after
--revise → witness decide design <spec-id> --show reconstructs the verdict + note (findings anchor to design#<id> or <spec-id> > ## Heading). Re-author the HTML, re-run witness design, re-gate. The 3-round bound is the CLI's — surface it, never fight it. --show also emits state: and exits: — a reopened or settled state means the verdict above it is history, so act on the exits: line, not on remembered findings.
- Findings implicate the slicing (the spec is wrong, not the look)? Tell the human
witness decide design <spec-id> --revise --upstream <effort> reopens decompose (scope-level changes chain to recap --amend).
- On approve the CLI stamps
design: {sha, spec} on the spec; the plan stage then requires that pin. You are done — hand back to /witness.
1---2name: witness-design3description: Produce a ui spec's living approved look — an interactive design session ending in a self-contained designs/<spec-id>.html handed to witness design, then the design gate. Normally invoked by /witness with the spec id.4---56# witness-design — spec → approved look → gate78<!-- Adapted: process from benoticed docs/ui/redesign-method.md (context phase →92-3 distinct directions → converge → change-ladder), generalized to two modes and10re-owned for witness; greenfield direction informed by Anthropic frontend-design11(Apache-2.0, LICENSES/frontend-design-Apache-2.0.txt, changes stated in NOTICE.md).12No text copied verbatim; the design-critic lens is new material. -->1314## Ground rules (every witness skill)1516Resolve the CLI once per session:1718```bash19WITNESS="${WITNESS_BIN:-npx -y @popovych.co/witness@0.14.4}"20```2122- **Render the CLI's decision output verbatim and in full — every line, unmodified.** Never print a command set you remember; never recompose, reformat, summarise or reorder what the CLI emitted. Which decisions are live, how they rank, and what each costs are the CLI's answers, and they change with the round, the bound, the repair grant and the content sha — a remembered set is wrong in more states than it is right.23- **The human decides; you may type it.** Run a `witness decide` verb when the human **names an option** — its number or its verb — or gives a bare affirmation ("y", "ok", "go") while a **CLI-rendered decision block carrying a recommended option** is on screen: the affirmation **selects the recommended option**, and you append `--via affirmation` to the printed command. Otherwise the string is run **byte-for-byte**: never recomposed, never reformatted, never with a placeholder you resolved yourself. The moment you compose a `--note` or resolve an id, you are authoring their decision. **A nod never takes** `--approve --override`, `--stop`, a trust grant, or `witness abandon` — those require naming, and the CLI refuses them with `nod-cannot`. A block with **no** recommendation also requires naming. **Questions you authored yourself** (the brainstorm interview, the design converge step) are conversation, not a block: an affirmation there accepts your stated recommendation, with no selection entry, no journal claim and no flag. A selection does not survive session death: killed and re-run, render the block again and ask again.24- **Never edit `specs/**`, `plans/**`, or `designs/**`.** The CLI is the sole writer of state. Author HTML in `$(mktemp -d)` and hand it to `witness design`. (The canon guard blocks direct edits; the trailer audit catches end-runs.)25- **Read canon with `witness read <id>`, never by path.** Canon lives at the primary root; inside a worktree the files are **absent by design**, so a path read finds nothing and a stale copy cannot be mistaken for the contract. Fat artifacts: `witness read <spec-id> --design --outline`, then `--lines <a>-<b>`.26- **Read a file before your first edit of it in this session.** Relay boundaries, `verify-red`'s stash cycle, and worktree re-attach all change files under you — an edit against a remembered copy is how "modified since read" and partial applies happen. The CLI now prints `stale-reads:` when it churns the tree; treat that list as unread.27- **Never invoke gate reviewers or relay verdicts.** `witness gate design` runs the design-critic itself and journals what it said.28- **Refusal repair loop:** `witness design` exiting 2 prints structured violations (`field · rule · got · want`). Fix and retry — **3 total attempts**, then stop and show the human the list verbatim.29- **A refused or hook-blocked command is a stop, not a step to drop.** Re-issue it on its own; if it still refuses, tell the human what was blocked and why. Never proceed by deleting the refused half of a compound command — a dropped step is silent, and silence is how a skipped check becomes a shipped defect.30- **Re-entrancy:** derive position from `$WITNESS next` / the dashboard / `log`, never from conversation memory.3132## When you run3334The `/witness` loop invokes you for a `ui`-flagged spec in a **feature** effort whose design is pending (missing or stale). fix/chore specs never reach you. Two modes:3536- **New screen** — `$WITNESS read <spec-id> --design` refuses `no-design`: there is no living look yet. Design from the spec.37- **Amend a living look** — the file exists but the spec was amended. Read the current look first; propose the *smallest* change that re-serves the (changed) behavior. If there is genuinely no visual delta, tell the human to run `witness design <spec-id> --reconfirm` (re-stamps, no session).3839## Inputs (rebuild them, never remember them)4041```bash42$WITNESS read <spec-id> # the parent spec — Behavior is your coverage contract43$WITNESS index # sibling specs, for pattern consistency44$WITNESS read <spec-id> --design # the current look, in amend mode; its `no-design`45 # refusal IS the new-screen signal, so read it, don't hide it46# the repo's design canon, if configured — read docs.design from witness.config.yaml:47# docs: { design: [docs/ui/design-language.md, ...] } → read each; it is the blocking authority48```4950## The session (interactive — this stage is human judgment)51521. **Context.** Name the screen's one job and primary user (from the spec's Motivation + Behavior). If a design canon is configured, read it — it governs hierarchy, framing, action placement, and component vocabulary. Report what you found before proposing.532. **Diverge.** Produce **2–3 genuinely distinct** structural directions that serve the job (different hierarchies/groupings), each consistent with the canon. One idea is never enough — divergence is what surfaces a better structure than the obvious one.543. **Converge.** With the human, pick or synthesize the winner — and ask for that choice the same way every other decision in this pipeline is asked: a recommendation, a one-line why, the strongest alternative with when it wins and what it costs. Every behavior the spec promises must be visible and operable in the winner (the design-critic checks this as blocking coverage).554. **Author the artifact.** One **self-contained** HTML file — inline all CSS/JS, embed assets as `data:` URIs, no external `src`/`href`. Give every section a stable, unique `id` (`id="essentials"`, `id="save-bar"`, …): these are the design-critic's anchors and must total **≥ 2**. Data-shape anchoring: when a section renders spec data, name the id after the data it shows, not its pixels.5657```bash58DIR=$(mktemp -d)59cat > "$DIR/look.html" <<'EOF'60<!doctype html>61<html><head><meta charset="utf-8"><style>/* inline tokens + layout */</style></head>62<body>63 <header id="eyebrow">Bookings</header>64 <main id="essentials"><!-- the 5 things that matter, dominant --></main>65 <details id="advanced"><!-- tuning fields, subordinate --></details>66 <footer id="save-bar"><!-- primary action, always reachable --></footer>67</body></html>68EOF69$WITNESS design <spec-id> --file "$DIR/look.html"70```7172```bash73$WITNESS design <spec-id> --open # opens the artifact for the human — required before the gate74```7576- **Register, then show.** `witness gate design` refuses `design-unseen` until the human has been shown the artifact's current bytes, so `--open` is part of the flow, not a nicety. Re-authoring re-arms it: new bytes, new showing. `witness next` names this step by itself — follow it.77- The opener failing (`opener-failed`) prints a `file://` path. Give the human that path verbatim and stop; do not work around it by pointing `opener:` in `.witness/config.local.yaml` at something that does not show anything.7879## Gate8081```bash82$WITNESS gate design <spec-id> # append --manual when the run asked for it83```8485- The design gate **always stops** — the look is human judgment, same footing as ship. It refuses to run at all until `witness design <spec-id> --open` has shown the human the current artifact. Render the gate output verbatim and in full, including its ranked options and `run:` line. **END YOUR TURN.** You never decide. The findings are *about* the design — they are never a substitute for the human being shown it.86- **Re-entered after `--revise`** → `witness decide design <spec-id> --show` reconstructs the verdict + note (findings anchor to `design#<id>` or `<spec-id> > ## Heading`). Re-author the HTML, re-run `witness design`, re-gate. The 3-round bound is the CLI's — surface it, never fight it. `--show` also emits `state:` and `exits:` — a `reopened` or `settled` state means the verdict above it is history, so act on the `exits:` line, not on remembered findings.87- Findings implicate the **slicing** (the spec is wrong, not the look)? Tell the human `witness decide design <spec-id> --revise --upstream <effort>` reopens decompose (scope-level changes chain to `recap --amend`).88- On approve the CLI stamps `design: {sha, spec}` on the spec; the plan stage then requires that pin. You are done — hand back to `/witness`.