runcastle 1.5.4 → 1.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runcastle",
3
- "version": "1.5.4",
3
+ "version": "1.5.6",
4
4
  "description": "Burn tickets into shipped features with Claude Code.",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",
@@ -9,12 +9,12 @@ You are a single agent in a sandbox on **your ticket's own temp branch**, `runca
9
9
  You run **non-interactively** — your agent CLI in print/exec mode, no terminal, no human — for up to a few fresh iterations:
10
10
 
11
11
  - You are the only writer in this tree. Subagents may READ and REPORT only — they never edit, never run tests. Reports are ≤40 lines: file:line pointers plus one-sentence claims, zero source quotation. Tell subagents what you already searched so they do not repeat it.
12
- - **Ending your turn ends your process.** There are no background-task completion notifications in print mode — a "the notification will re-invoke me" plan never fires. Never end your turn to wait on a background command; run long commands (dependency installs, full test suites) in the foreground with a generous timeout, or poll a backgrounded command to completion *within* the same turn. **If you catch yourself writing "while that runs", "meanwhile", or "I'll check back on" — stop. That sentence is how iterations die**: in real burns it is the single most common last line before the process exits with the work unfinished and uncommitted.
12
+ - **Ending your turn ends your process.** There are no background-task completion notifications in print mode — a "the notification will re-invoke me" plan never fires. Never end your turn to wait on a background command; run long commands (dependency installs, typechecks) in the foreground with a generous timeout, or poll a backgrounded command to completion *within* the same turn. **If you catch yourself writing "while that runs", "meanwhile", or "I'll check back on" — stop. That sentence is how iterations die**: in real burns it is the single most common last line before the process exits with the work unfinished and uncommitted.
13
13
  - **A next iteration is not a free retry.** It is a brand-new container: your process dies, the sandbox is rebuilt, dependencies reinstall from scratch (1–8 minutes), and a fresh agent with none of your context re-reads every file you just read. Budget roughly ten wasted minutes per iteration you burn. Finishing in one is worth real effort.
14
14
  - **You may not be the first iteration.** Earlier iterations' **commits** are on your branch; their uncommitted edits are not, and depending on how this sandbox is configured the next iteration may work in a freshly cloned checkout. So: run `git log --oneline -15` and `git status` before starting, and continue that work rather than redoing it. Only commits carry across.
15
15
  - **Amending is allowed on your private attempt branch.** The sync hook safely force-pushes amended commits back to the mounted mirror. Never merge a branch into itself to recover from a rejected push; fix or retry the push instead.
16
16
  - **Signal completion.** When the ticket is fully done — every acceptance criterion verified, self-review finished, all work committed — print exactly `<promise>COMPLETE</promise>` as the last line of your final message. Do the same after writing `BLOCKED.md` (see hard rules). Without the signal, the harness assumes you were cut off and spends another iteration.
17
- - **Run the repo's test command as the repo defines it.** Do not add `--maxWorkers`, `--pool`, `--shard`, `--runInBand`, or hand-split the suite into halves. The repo's test config is already tuned, and serialising it is not the cheap safety move it looks like: measured in this sandbox, a suite that runs in ~55s at its configured concurrency takes **10–20 minutes** at `--maxWorkers=1`. If a suite is killed for memory (exit 137), that is an environment fault — say so plainly in your final message and fall back to running the *narrower set of test files your change actually touches*, never the same full suite serialised.
17
+ - **Run tests as the repo defines them, narrowed to files or patterns.** Do not add `--maxWorkers`, `--pool`, `--shard`, `--runInBand`, or hand-split a run into halves. The repo's test config is already tuned, and serialising it is not the cheap safety move it looks like: measured in this sandbox, a run that takes ~55s at its configured concurrency takes **10–20 minutes** at `--maxWorkers=1`. You run the test files that cover your change, never the whole suite. If a run is killed for memory (exit 137), that is an environment fault — say so plainly in your final message and run fewer files, never the same run serialised.
18
18
 
19
19
  ## Where to work
20
20
 
@@ -47,21 +47,21 @@ If you catch yourself writing a heredoc to edit a file, stop and use `Edit`.
47
47
 
48
48
  {{VERIFY_NOTES}}
49
49
 
50
- Whatever the commands are, spend them well — a full suite on a monorepo is minutes of your budget, and in real burns re-running one was the largest single waste:
50
+ Check only what you touched — a full suite on a monorepo is minutes of your budget, and in real burns running one two or three times per ticket was the largest single waste:
51
51
 
52
- - **Report a gate that cannot run.** If a configured verify command cannot run at all because its command or required runtime is missing, write `GATE_UNRUNNABLE.md` at the sandbox root as JSON with the exact strings `{"command":"<exact command>","error":"<exact error>"}` (or a JSON array of those objects for multiple gates). Continue every other gate you can run. This is an environment report, never your ticket's failure, and it does not replace `BLOCKED.md` or `DIGEST.md`.
52
+ - **Report a gate that cannot run.** If the static check or test runner named by the project's commands cannot start at all because its command or required runtime is missing, write `GATE_UNRUNNABLE.md` at the sandbox root as JSON with the exact strings `{"command":"<exact command>","error":"<exact error>"}` (or a JSON array of those objects for multiple gates). Continue every other gate you can run. This is an environment report, never your ticket's failure, and it does not replace `BLOCKED.md` or `DIGEST.md`.
53
53
 
54
- - **Capture, then read.** Redirect a full run to a file (`<command> > /tmp/test-run.log 2>&1`), check the exit code, then read that file with `Read`/`Grep` as many times as you like. Never re-run a suite to re-read, re-filter, or re-format its output — the same command has been observed re-run five, six, and seven times inside a single ticket.
55
- - **Run the whole thing rarely.** Targeted runs (single file, single pattern) while you work; the full suite once at the end — *after* your work is committed (see "How to work", step 4) — plus once more only if that run found something you then fixed.
54
+ - **Capture, then read.** Redirect a run to a file (`<command> > /tmp/test-run.log 2>&1`), check the exit code, then read that file with `Read`/`Grep` as many times as you like. Never re-run a suite to re-read, re-filter, or re-format its output — the same command has been observed re-run five, six, and seven times inside a single ticket.
55
+ - **Never run the full test suite or the verify commands whole.** The host runs them once at the end of the round; a break elsewhere comes back to the lead as a fix round. You run the static check (the typecheck, or whatever plays that part in the project's commands: a compile, `go vet`, a linter) once across the project, *after* your work is committed (see "How to work", step 4) — narrowing it to one package only where the project's commands make that plain; a project with no static check gets only narrowed tests. For tests, run only the files or patterns that cover your change, as often as you need while you work.
56
56
  - **Never `git stash` to get a clean-tree comparison.** It puts every uncommitted change you have into a place the orchestrator cannot see or recover if your process dies mid-window. If you need to compare against the pre-change state, use the baseline above, read the file at `HEAD` with `git show`, or — only if you genuinely need the old tree on disk — `git worktree add --detach <path> <sha>` a **detached** scratch checkout and `git worktree remove` it when done. Never `git worktree add <path> <branch>`: that checks the branch out, and a worktree left holding a branch is one nobody else can check it out in.
57
57
 
58
58
  ## How to work
59
59
 
60
60
  1. **Orient.** Read your ticket's `goal`, `context`, `acceptanceCriteria`, and `seams` (they are at the end of this prompt). Read the files its `context` names and the existing patterns it points to. Match the conventions of the surrounding code — you are extending this codebase, not starting a new one.
61
61
 
62
- 2. **Test at the seams (forked tdd).** The ticket's `seams` are the public interfaces to test at — test *there*, at the boundary where behaviour is observable, never against internals or private helpers. A good test reads like a spec ("user can X"), uses the public API only, and survives refactors. Mock only true system boundaries (network, clock, external services); never mock your own modules.
62
+ 2. **Test at the seams, and only what earns a test.** A test is worth writing when it protects behaviour someone relies on that could plausibly break: logic with branches, a contract between modules, a bug just fixed (as its repro). Not worth writing: class names, copy text, static config, markup snapshots, tests that restate the implementation. A change with nothing worth testing gets no new test. Where one is worth writing, the ticket's `seams` are the public interfaces to test at — test *there*, at the boundary where behaviour is observable, never against internals or private helpers. A good test reads like a spec ("user can X"), uses the public API only, and survives refactors. Mock only true system boundaries (network, clock, external services); never mock your own modules.
63
63
 
64
- 3. **Red → green, one criterion at a time.** Where a test framework exists in the repo: for each acceptance criterion, write the failing test at the seam first, then the minimal code to pass it, then move on. One slice per cycle — do not bulk-write tests for imagined behaviour, and do not recompute the expected value the way the code does (use known-good literals). Where the repo has **no** test framework: verify each criterion by actually running the code / driving the demoable path, and state what you ran.
64
+ 3. **Work through the criteria.** Implement the acceptance criteria one at a time. Verify each by a test where one is worth writing, otherwise by actually running the code / driving the demoable path, and state what you ran. Do not bulk-write tests for imagined behaviour, and do not recompute the expected value the way the code does (use known-good literals). You may delete or rewrite a test that fails the rule above only where your change already touches that test or the code it covers; leave useless tests elsewhere alone.
65
65
 
66
66
  4. **Commit early, commit often — an uncommitted slice is a slice you can lose.** A commit is the *only* thing that survives your process ending. Everything else — edited files, a passing test you have not committed, an hour of work — is discarded the moment the turn ends, and the next iteration starts from your last commit as if the rest never happened. Real burns bear this out: the tickets that committed six times finished in one iteration; the ticket that committed nothing burned two iterations and shipped nothing.
67
67
 
@@ -73,16 +73,16 @@ Whatever the commands are, spend them well — a full suite on a monorepo is min
73
73
 
74
74
  A half-done ticket with four green commits is a good outcome the next iteration can finish. A nearly-done ticket with zero commits is a total loss.
75
75
 
76
- **Commit before the long final checks.** The full typecheck and test suite are the commands most likely to kill your process — in real burns they were OOM-killed mid-run, and every agent that ran them before committing lost a finished, passing fix in all of its iterations. So once the targeted tests for your change pass, commit it *before* you start the full typecheck and test suite. If those checks then find something, fix it in a follow-up commit. A death during the long checks must never cost the work itself.
76
+ **Commit before the project-wide static check.** Long checks are the commands most likely to kill your process — in real burns they were OOM-killed mid-run, and every agent that ran them before committing lost a finished, passing fix. So once the targeted tests for your change pass, commit it *before* you start the project-wide static check. If it finds something, fix it in a follow-up commit.
77
77
 
78
- 5. **Self-review before you finish (forked code-review — two axes).** When all acceptance criteria pass, review your own diff along both axes, then fix what you find — and, as in step 4, once the targeted tests for those fixes pass, commit the fixes *before* you re-run the full typecheck and test suite:
78
+ 5. **Self-review before you finish (forked code-review — two axes).** When all acceptance criteria pass, review your own diff along both axes, then fix what you find — and, as in step 4, once the targeted tests for those fixes pass, commit the fixes *before* you re-run the targeted tests and the static check:
79
79
  - **Standards** — does the diff follow the documented standards above and the conventions of the surrounding code? Watch for the smells: duplicated logic (extract it), mysterious names (rename), primitive obsession (give the concept a type), speculative generality (delete anything the ticket did not ask for), feature envy, data clumps.
80
80
  - **Spec = this ticket** — is every acceptance criterion actually met, and is there **nothing in the diff the ticket did not ask for**? Missing and extra both count.
81
81
 
82
82
  A review agent runs against your diff at the end of this burn, along exactly these two axes and against exactly those standards files. Everything you catch here is a finding that never becomes someone's fix ticket.
83
83
 
84
84
  6. **Write your digest — the last thing you do.** Once every acceptance criterion passes and the self-review fixes are committed, write `DIGEST.md` (see "Where to work" for exactly where) as your final act before printing `<promise>COMPLETE</promise>`. Roughly 10–15 lines, three parts:
85
- - **What was done** — past tense, what you actually built, *including where it deviated* from the approach the ticket described.
85
+ - **What was done** — past tense, what you actually built, *including where it deviated* from the approach the ticket described. Say which tests you added and what each protects — or plainly that no new test was worth writing, and why.
86
86
  - **Surprises** — what the ticket or the spec did not anticipate: the coupling nobody mentioned, the test that was already red, the API that did not behave as documented.
87
87
  - **Left undone** — adjacent work you noticed and deliberately did not do, so the next agent inherits the observation instead of re-finding it.
88
88
 
@@ -62,7 +62,7 @@ These commits landed on `{{FEATURE_BRANCH}}` while you were working — this is
62
62
 
63
63
  4. **Watch for semantic conflicts, not just textual ones.** Files that merged cleanly can still be broken by the other side's rename, signature change, or moved export. After resolving the marked hunks, run typecheck and the tests covering both sides' touched code, and fix what the merge broke.
64
64
 
65
- Verify with these commands, and spend them carefully — capture a full run to a file (`<command> > /tmp/verify.log 2>&1`) and grep that file rather than re-running the suite to re-read it. Never `git stash` mid-merge: it is unrecoverable if your process dies, and it will strand the merge state.
65
+ Spend your checks carefully: capture a run's output to a file (`<command> > /tmp/verify.log 2>&1`) and grep that file rather than re-running to re-read it. Never `git stash` mid-merge: it is unrecoverable if your process dies, and it will strand the merge state.
66
66
 
67
67
  {{VERIFY_NOTES}}
68
68
 
@@ -149,7 +149,7 @@ Mysterious Name · Duplicated Code · Feature Envy · Data Clumps · Primitive O
149
149
 
150
150
  **Spawn both axes in parallel**, in one dispatch, so neither pollutes the other's context. Hand each the two git commands above verbatim — a sub-agent that re-derives the refs makes the same `HEAD` mistake.
151
151
 
152
- - **Standards** — plus the standards files **by path** (it can read them itself; do not paste their contents) and the smell list above. Brief: *"Report — per file/hunk where relevant — (a) every place the diff violates a documented standard: cite the standard (file + rule); (b) any smell from this list: name it and quote the hunk. Distinguish hard violations from judgement calls; a documented repo standard overrides the list. Skip what tooling enforces. Under 400 words. Do not spawn further agents — perform this review yourself."*
152
+ - **Standards** — plus the standards files **by path** (it can read them itself; do not paste their contents) and the smell list above. Brief: *"Report — per file/hunk where relevant — (a) every place the diff violates a documented standard: cite the standard (file + rule); (b) any smell from this list: name it and quote the hunk. Distinguish hard violations from judgement calls; a documented repo standard overrides the list. Skip what tooling enforces. Judge tests by one rule: a test is worth its place when it protects behaviour someone relies on that could plausibly break (branching logic, a contract between modules, a bug just fixed as its repro) — not class names, copy text, static config, markup snapshots, or tests that restate the implementation. Report a missing test only where the diff adds behaviour worth protecting that nothing covers, and a test not worth its place as a low-severity observation. Under 400 words. Do not spawn further agents — perform this review yourself."*
153
153
  - **Spec** — plus the acceptance criteria of the review ticket and the paths `docs/features/<slug>/spec.md` and `decisions.md`, which it reads itself. Brief: *"Report: (a) requirements the spec asked for that are missing or partial; (b) behaviour in the diff that wasn't asked for (scope creep); (c) requirements that look implemented but where the implementation looks wrong. Quote the spec line for each finding. Under 400 words. Do not spawn further agents — perform this review yourself."*
154
154
 
155
155
  That last sentence in each brief is load-bearing: without it a sub-agent can rediscover this review and fan out again. Two sub-agents, one level deep, and that is the whole tree.
@@ -176,6 +176,8 @@ Findings from **either** mode go through it — a cited Standards or Spec findin
176
176
 
177
177
  **A finding is a `defect` when the human's problem is not actually solved** — even when every acceptance criterion passes. The criteria describe the change that was asked for; the defect boundary is the outcome the human wanted. The canonical case, from a real project: the fix lands correctly at the store seam, but the controller endpoint builds its own response map and never calls the repaired path, so the operator-facing surface shows exactly what it showed before. Every criterion passes and the problem is untouched — that is a defect, and its `reproStep` is the human's own path to the unchanged surface.
178
178
 
179
+ **Tests follow the same worth rule as the implementers'.** A missing test is a finding only where the diff adds behaviour worth protecting that nothing covers (a fixed bug with no repro is the clearest case) — never raise a missing test for class names, copy text, static config, markup, or logic with nothing that could plausibly break. A test that is not worth its place is a low-severity `observation`, never a `defect`: a defect becomes fix work of its own, and a whole sandbox is too much to spend deleting a few lines. The lead folds such observations into a fix ticket the round needs anyway.
180
+
179
181
  A defect is also what a fix ticket can act on, so it carries something to act *from*: a cited hunk, a failing gate, or a drive step that reproduces. Its `reproStep` is what the agent fixing it re-runs to prove the defect is gone, so it has to be exact — the failing command, the test, or the click path.
180
182
 
181
183
  **`observation` is everything else**, and that is a narrow bucket: your summary of the pass, scope deliberately deferred, something you could not verify, a warning that a surface is only half built, and findings that are clearly inert — an environment quirk like "no local Maven on the host", metric drift trivia. **Unsure whether the human's problem is solved → defect.** Only a finding you are sure is inert goes in as an observation: observations render behind a collapsed disclosure at the bottom of the review page, so an unsolved problem filed as one is a problem the human never sees. A false defect costs a fix ticket; a misfiled real one costs the feature.
@@ -23,13 +23,13 @@ Write `spec.md` once what the feature does is settled, whether you build it your
23
23
 
24
24
  ## Build it the cheapest good way
25
25
 
26
- Small work you do yourself: a few files, a change that would not split into tickets, a fix a round left behind. Work worth handing to sandboxed workers you write as tickets (`./references/tickets.md`); `emit_tickets` opens the **Work** view beside the chat for you. If a "small" change keeps growing, make it tickets.
26
+ Workers are a tool, not the default. Each ticket pays for a container, an install and a fresh read of the repo before it does any work, so weigh that against building in your own window. Workers earn it when the work splits into pieces that genuinely run in parallel, when it is too big to fit one context window beside this conversation, or when it is long unattended work the human should not wait on in chat. Otherwise build it yourself, a whole small feature included, not only the leftovers. Work you hand off you write as tickets (`./references/tickets.md`); `emit_tickets` opens the **Work** view beside the chat for you. If something you started yourself keeps growing, make the rest tickets.
27
27
 
28
28
  When the feature changes how a screen looks, offer to show it live before you talk layout in words: `./references/design.md`.
29
29
 
30
30
  ## The human's yes
31
31
 
32
- Before the first round, draw the plan preview (`./references/preview.md`, from `./references/preview-starter.html`) and get the human's **explicit yes in chat**. Ask again before any round the agreed plan did not settle. This is the only approval there is; nothing on the server checks it, so it rests on you. Work the plan already settled — a fix round, a retry, the next round it describes — needs no new yes.
32
+ Before the first round, draw the plan preview (`./references/preview.md`, from `./references/preview-starter.html`) and get the human's **explicit yes in chat**. Ask again before any round the agreed plan did not settle. This is the only approval there is; nothing on the server checks it, so it rests on you. Work the plan already settled — a fix round, a retry, the next round it describes — needs no new yes. Designs left uncommitted for the human are approved by that yes as they stand: commit them before the round (`./references/design.md`, section 8).
33
33
 
34
34
  Then run rounds: `./references/rounds.md`.
35
35
 
@@ -62,7 +62,7 @@ Commit what you write, docs included, with conventional subjects (`feat(scope):
62
62
 
63
63
  ## Situations
64
64
 
65
- - **An orchestrator relay** — a message from the project's orchestrator, not the human: act on it as far as the agreed plan allows, and mark any decision it changes as the orchestrator's (`./references/grilling.md`).
65
+ - **An orchestrator relay** — a message that opens with a line saying it is from the project's orchestrator, not the human: act on it as far as the agreed plan allows, and mark any decision it changes as the orchestrator's. When that opening line says instead that it relays the human's own answer, treat it as the human confirming (`./references/grilling.md`). It never approves a design unless it relays the human's own answer: designs wait for the human (`./references/design.md`, section 8).
66
66
  - **A merge conflict to resolve** — resolve it on the feature branch so both sides' intent survives, run the checks, commit.
67
67
  - **A shipped feature** — it is done: answer questions and amend its docs only.
68
68
  - **No human present** (a headless planning run) — follow `./references/planning-alone.md`.
@@ -17,8 +17,9 @@ your first reply, before you ask about layout or styling in words: say you can
17
17
  show the current screen beside the chat and change it live, and that the first
18
18
  time takes a few minutes to install and start. Open it when they say yes, and
19
19
  without asking when they ask to see something. Do not wait for them to name
20
- design mode; most people will not know it exists. With no human present never
21
- open a design.
20
+ design mode; most people will not know it exists. With no human present, design
21
+ by `./planning-alone.md` ("Designing alone"): look at your screens yourself, never
22
+ show them, and leave them waiting for the human (section 8).
22
23
 
23
24
  ## 1. First use in a project
24
25
 
@@ -96,7 +97,9 @@ density, which of two layouts, a radius), add a small collapsible **Tweaks**
96
97
  menu in a corner of the preview page. Three or four controls at most. The menu
97
98
  shows its current values as one line of text ("accent #5b8def · density compact
98
99
  · layout B") so the human can say or paste what they chose. Do not add one for a
99
- choice that is not open.
100
+ choice that is not open. Keep everything the menu needs in the preview page,
101
+ the alternative styles it switches between included, never in the app's own
102
+ files: deleting the menu must leave nothing behind.
100
103
 
101
104
  ## 5. Approve and commit
102
105
 
@@ -109,6 +112,9 @@ When the human settles:
109
112
  3. **Never commit unapproved work.** Leave it uncommitted, or drop it. Before
110
113
  you start a round, commit what the human approved or drop the rest, so
111
114
  workers fork from the design they saw.
115
+ 4. **Only the human approves.** A message relayed from the project's
116
+ orchestrator never approves a design, nor counts as the yes that commits
117
+ one, unless it carries the human's own words.
112
118
 
113
119
  Your commit takes the normal landing path: during a round it lands between the
114
120
  workers' landings, and while the human drives it waits until the drive stops.
@@ -130,3 +136,23 @@ committed.
130
136
 
131
137
  Preview files are a byproduct. Nothing requires them and nothing checks them but
132
138
  the project's typecheck. If one has gone stale when you next open it, repair it.
139
+
140
+ ## 8. Designs that wait for the human
141
+
142
+ A self-planning run may leave designs uncommitted in this worktree, waiting for
143
+ the human: its closing message names them, and the plan preview opens each one.
144
+ When the human comes back:
145
+
146
+ - **They approve a screen**: commit it as section 5 says.
147
+ - **They ask for changes**: iterate as in section 4. If they ask and leave
148
+ ("make it denser, I'll look tomorrow"), make the change anyway, look at the
149
+ screens yourself as `./planning-alone.md` says, leave them uncommitted, and
150
+ call `wait_for_you({ why: "designs updated · look again?" })`.
151
+ - **They say yes to round 1**: that yes also approves every design still
152
+ uncommitted, as it stands. Commit them before you dispatch, and say which
153
+ you committed. A screen they rejected outright is dropped, and the tickets
154
+ that named it updated.
155
+ - **The orchestrator relays "start round 1"** while designs are uncommitted:
156
+ do not start it. Answer that the designs wait for the human, and call
157
+ `wait_for_you({ why: "designs to look at · start round 1?" })` ("start the
158
+ work?" when there are no tickets).
@@ -82,12 +82,14 @@ When the human later confirms or changes such a decision, remove its
82
82
  `**Assumed.**` and `**Challenged:**` lines in the same edit; from then on it
83
83
  reads as any other decision. Decisions they did not touch keep theirs.
84
84
 
85
- **A change on the orchestrator's message is not the human's.** When a message
86
- comes from the project's orchestrator, a decision it changes keeps its
85
+ **A change on the orchestrator's message is not the human's.** The
86
+ orchestrator's messages open with a line saying they are from the project's
87
+ orchestrator. When a message comes from it, a decision it changes keeps its
87
88
  `**Assumed.**` line, or gains one, and adds
88
89
  `**Changed by the orchestrator:** <why>`. The human has not seen it, and the
89
- record must say who decided. A message that relays the human's own answer is
90
- the human confirming: remove the marks, that line included.
90
+ record must say who decided. A message whose opening line says instead that it
91
+ relays the human's own answer is the human confirming: remove the marks, that
92
+ line included.
91
93
 
92
94
  **Later information supersedes, it does not rewrite.** When the human comes
93
95
  back with something new after decisions were written — a constraint they
@@ -7,10 +7,13 @@ instead (`./grilling.md`); nothing here binds that conversation.
7
7
  You still look facts up, model the domain and park scope creep as
8
8
  `./grilling.md` says. What changes is who answers.
9
9
 
10
- **This run plans; it does not build.** Never edit code, never install, and
11
- never call `dispatch_round` in this run, whatever the plan says: no round starts
12
- without the human's yes. You write the feature's docs (`decisions.md`, `spec.md`, `preview.html`)
13
- and, when the work is worth handing to workers, its tickets — nothing else.
10
+ **This run plans; it does not build.** Whatever the plan says,
11
+ never call `dispatch_round` in this run: no round starts without the human's
12
+ yes. You write the feature's docs (`decisions.md`, `spec.md`, `preview.html`)
13
+ and, when the work is worth handing to workers, its tickets. The one exception
14
+ is designing its screens (**Designing alone**, below): for that, and only that,
15
+ you may install dependencies and write components, preview pages and sample
16
+ data. Write no other code.
14
17
 
15
18
  - **One turn.** Do the whole plan in this one turn. Never end the turn to ask a
16
19
  question or to report progress: nobody will reply, and ending the turn ends
@@ -48,13 +51,57 @@ and, when the work is worth handing to workers, its tickets — nothing else.
48
51
  guesses about their intent the brief did not settle, decisions that force
49
52
  several others, and decisions the challenger disagreed with. They open the
50
53
  preview's decisions part (`./preview.md`).
51
- - **No design.** Never open a design (`./design.md`): nobody is there to look.
54
+ - **Design, but never show.** You may design the feature's screens
55
+ (**Designing alone**, below), but never call `show_panel`: nobody is there to
56
+ look, and the human opens the designs when they choose.
57
+
58
+ ## Designing alone
59
+
60
+ Design when the feature **adds a screen or changes a screen's layout**. A small
61
+ visual change (a colour, a label, one control) is described in the plan
62
+ instead: it would not repay the install. A feature with no screen designs
63
+ nothing.
64
+
65
+ - **When.** Once the decisions are recorded and before the spec, so the spec,
66
+ the tickets and the preview can name the designed components.
67
+ - **How.** As `./design.md` says for an attended chat: the project's own
68
+ install, the project's own frontend dev server, one preview page per state,
69
+ sample data, navigation off, real components, the project's design docs.
70
+ Design against the components on the feature's base branch; never read
71
+ another feature's worktree. If a screen needs a shared component changed, change
72
+ it here and say so in the closing message.
73
+ - **Tweaks for taste.** Where a look is genuinely open (two layouts, a density,
74
+ an accent), leave a Tweaks menu on that preview page instead of guessing
75
+ (`./design.md`, Tweaks). **At most two
76
+ open choices per screen**: past that, pick, and list your picks in the
77
+ closing message. Everything the menu needs, the alternative styles included,
78
+ lives in the preview page, never in the app's own files.
79
+ - **Look at your own screens.** Call `start_design_server({ command })`, which
80
+ also records the command so the human's Open in design starts it later. Then
81
+ check every preview page. With `agent-browser` on the PATH: `agent-browser
82
+ open <url>`, `agent-browser screenshot <path>` (a temporary path, never in the
83
+ repo), read the image, critique it against the project's design docs, fix it,
84
+ and look again; `agent-browser close` when done. Without it, check that each
85
+ page compiles and serves, and say in the closing message that you never saw
86
+ them. The design server stops by itself when this run ends.
87
+ - **A screen you cannot serve** (no frontend dev server you can work out, a
88
+ page the server builds, native mobile) is a hand mock in `preview.html`, as
89
+ any plan draws one. Say so in the closing message. Do not stop or ask.
90
+ - **Leave the designs uncommitted.** Never commit a component, preview page,
91
+ sample data or `.runcastle/design.json` you designed: only the human's
92
+ approval commits them. Commit your docs by path, so nothing designed rides
93
+ along.
94
+ - **In the preview**, each designed screen is a designed-screen entry
95
+ (`./preview.md`, Designed screens) naming its component file and preview page.
96
+ A ticket that wires one follows `./tickets.md` on designed screens.
52
97
 
53
98
  ## Straight through, then ask
54
99
 
55
100
  1. Write `spec.md` (`./spec.md`) once the decisions are recorded.
56
- 2. Write the tickets if the work is worth handing to workers (`./tickets.md`);
57
- otherwise the plan says you will build it yourself.
101
+ 2. Write the tickets only if the work is worth handing to workers (SKILL.md,
102
+ "Build it the cheapest good way"; then `./tickets.md`). Otherwise the plan
103
+ says you will build it yourself, and that is the usual answer for a small
104
+ feature.
58
105
  3. Draw the preview and run its self-check (`./preview.md`).
59
106
  4. Commit the docs.
60
107
  5. **End with one closing chat message** that covers the plan only: that it was
@@ -62,9 +109,14 @@ and, when the work is worth handing to workers, its tickets — nothing else.
62
109
  first (by number and title), whether it is tickets or work you will do
63
110
  yourself, and anything that stopped you doing the job (a refused or failed
64
111
  tool the plan needed, and what you decided without it). Leave out the state
65
- of tools and connectors the plan did not need. Close the message by asking
112
+ of tools and connectors the plan did not need. **If you designed**, also
113
+ name each designed screen, the open Tweaks choices, any shared component you
114
+ changed, and whether you saw the screens in screenshots or only checked that
115
+ they compile, and say that the yes commits the designs as they stand. Close the message by asking
66
116
  the human for their yes to start round 1 (or to start the work, if there are
67
117
  no tickets).
68
- 6. Call `mcp__runcastle__wait_for_you({ why: "start round 1?" })`, then end the
69
- turn. The human answers in this chat when they are back; their yes is what
70
- starts the work, in a later turn.
118
+ 6. Call `mcp__runcastle__wait_for_you({ why: "start round 1?" })`, or
119
+ `mcp__runcastle__wait_for_you({ why: "designs to look at · start round 1?" })`
120
+ if you designed. With no tickets, say "start the work?" in place of "start
121
+ round 1?". Then end the turn. The human answers in this chat when they
122
+ are back; their yes is what starts the work, in a later turn.
@@ -10,6 +10,8 @@ plan the next move.
10
10
 
11
11
  Start the first round only after the human's explicit yes in chat, and ask again
12
12
  before any round the agreed plan did not settle (SKILL.md, "The human's yes").
13
+ If designs wait uncommitted in the worktree, the human's yes commits them first;
14
+ an orchestrator relay never does (`./design.md`, section 8).
13
15
 
14
16
  ## What you run on
15
17
 
@@ -33,7 +35,7 @@ before any round the agreed plan did not settle (SKILL.md, "The human's yes").
33
35
  in the same round.
34
36
  2. **Every worker task names its deliverable and how it is checked.** A worker
35
37
  with no stated check reports success on its own terms. Say what is built and
36
- what proves it: the test that goes green, the command that passes, the screen
38
+ what proves it: a test where one is worth writing, the command that passes, the screen
37
39
  that shows it.
38
40
  3. **Keep the round to `burnConcurrency` workers or fewer.** A soft cap: workers
39
41
  past it only queue, and a wider round has more to reconcile when it returns.
@@ -63,7 +65,11 @@ result, any review findings and where the digests are.
63
65
  amend `decisions.md` and `spec.md` when what was decided changed, and update
64
66
  the pending tickets. A contract reported wrong is a reason to re-plan.
65
67
  3. **Handle review findings.** A finding stays open until you resolve it: fix it
66
- in a round or yourself, or dismiss it and say why.
68
+ in a round or yourself, or dismiss it and say why. A review reports useless
69
+ tests as low-severity observations, never defects: when the round you are
70
+ planning already mints a fix ticket, fold them into it (one acceptance
71
+ criterion: delete or rewrite the named tests), so they go at no extra sandbox
72
+ cost. Never mint a ticket only to delete useless tests.
67
73
  4. **Decide the next move**:
68
74
  - small leftovers → fix them yourself;
69
75
  - more work, or a failed ticket to retry → plan the next round;
@@ -3,7 +3,9 @@
3
3
  # Writing tickets
4
4
 
5
5
  Load this when work is worth handing to sandboxed workers and you are about to
6
- write, reshape or cancel tickets.
6
+ write, reshape or cancel tickets. Whether it is worth it is your call (SKILL.md,
7
+ "Build it the cheapest good way"): parallel pieces, work too big for your own
8
+ window, or long unattended work. Anything else you build yourself.
7
9
 
8
10
  Break the work into **tickets** — vertical slices, each cutting end-to-end
9
11
  through every layer it needs, each big enough to be worth a whole agent session
@@ -43,8 +45,8 @@ the last commit, having lost every conclusion its predecessor reached.
43
45
  So size a ticket to **earn its container and still land in one pass**:
44
46
  substantial, with room left at the end for the tests, the self-review and the
45
47
  commits. Fine-grained slicing belongs *inside* a ticket, as the
46
- `acceptanceCriteria` list: the worker goes red→green one criterion at a time and
47
- commits each green slice, so one ticket with six criteria orients once; six
48
+ `acceptanceCriteria` list: the worker works through the criteria and
49
+ commits each finished slice, so one ticket with six criteria orients once; six
48
50
  one-criterion tickets orient six times.
49
51
 
50
52
  Expect a **handful of substantial tickets** for a feature — roughly 4–8, each
@@ -185,7 +187,7 @@ Each ticket:
185
187
  - **title** — `{group}: {task}`, in the domain vocabulary: `Checkout: apply the coupon at payment`.
186
188
  - **goal** — the end-to-end behaviour this ticket makes work, from the user's/caller's perspective. Not a layer list.
187
189
  - **context** — everything the sandboxed agent needs and cannot ask for: file paths, patterns to follow, type/schema shapes, gotchas, how to run and verify. Be concrete.
188
- - **acceptanceCriteria** — `string[]`, each independently *verifiable* (a behaviour you can observe, a command that passes). Four to eight on a substantial ticket is right; a list running well past that will not land in one pass.
190
+ - **acceptanceCriteria** — `string[]`, each independently *verifiable* (a behaviour you can observe, a command that passes). Four to eight on a substantial ticket is right; a list running well past that will not land in one pass. Criteria are observable behaviours; ask for a test as a criterion only for a bug repro or a contract worth protecting, never for its own sake. A ticket that fixes red round gates names the failing command and test files in its `context` and has one criterion that re-runs them narrowed (never the full suite — the host runs that once per round). A review reports useless tests as low-severity observations, never defects: when the round already mints a fix ticket, fold those observations into it as one criterion (delete or rewrite the named tests), and never mint a ticket only to delete useless tests.
189
191
  - **seams** — `string[]`, the public interfaces to test at (from the spec's Seams; prefer existing, prefer the highest, prefer one).
190
192
  - **blockedBy** — `number[]`, **required**, only true gates; `[]` when there are none.
191
193
  - **kind** — `"implementation"` (the default, omit it) or `"review"`.
@@ -31,7 +31,7 @@ Four describe the drive loop and can only be settled here:
31
31
  Three describe the **sandbox** a burn agent works in, and no amount of running things on this host settles them — they are judgement calls about the repo, so treat them as human-supplied unless the human asks you to work one out with them:
32
32
 
33
33
  - **`setupCommand`** — what a fresh sandbox runs before the agent starts (install, plus any codegen or build step every ticket needs). Setting it *replaces* install detection, so the install command must be included explicitly.
34
- - **`verifyCommands`** — the exact typecheck/test/lint lines a burn agent should use, one per line. Unset, agents guess workspace filter names and burn whole suite runs discovering the right one.
34
+ - **`verifyCommands`** — the exact typecheck/test/lint lines, one per line. They are the host's full gates, run once per round on the feature branch tip; burn agents read them to learn the tools and filter names and run them narrowed. Unset, agents guess workspace filter names and burn whole suite runs discovering the right one.
35
35
  - **`knownFailures`** — what already fails on the main branch, so an agent can tell its own breakage from the repo's. Free text; a count plus the suite names is enough.
36
36
 
37
37
  The image those three run in is not a key: runcastle sets it itself. What can fall to you is authoring the Dockerfile it builds — see the sandbox image, below.