runcastle 1.5.5 → 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/bin/runcastle.js +1597 -1518
- package/index.js +1597 -1518
- package/package.json +1 -1
- package/skills/burner/implement-ticket.md +11 -11
- package/skills/burner/resolve-conflict.md +1 -1
- package/skills/burner/review-ticket.md +3 -1
- package/skills/packs/runcastle/skills/feature/SKILL.md +1 -1
- package/skills/packs/runcastle/skills/feature/references/planning-alone.md +4 -2
- package/skills/packs/runcastle/skills/feature/references/rounds.md +6 -2
- package/skills/packs/runcastle/skills/feature/references/tickets.md +6 -4
- package/skills/packs/runcastle/skills/prepare/SKILL.md +1 -1
- package/web/assets/{index-CPgKzYyE.js → index-DJf8BQof.js} +1 -1
- package/web/index.html +1 -1
package/package.json
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
55
|
-
- **
|
|
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 (
|
|
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. **
|
|
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
|
|
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
|
|
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
|
-
|
|
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,7 +23,7 @@ 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
|
-
|
|
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
|
|
|
@@ -98,8 +98,10 @@ nothing.
|
|
|
98
98
|
## Straight through, then ask
|
|
99
99
|
|
|
100
100
|
1. Write `spec.md` (`./spec.md`) once the decisions are recorded.
|
|
101
|
-
2. Write the tickets if the work is worth handing to workers (
|
|
102
|
-
|
|
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.
|
|
103
105
|
3. Draw the preview and run its self-check (`./preview.md`).
|
|
104
106
|
4. Commit the docs.
|
|
105
107
|
5. **End with one closing chat message** that covers the plan only: that it was
|
|
@@ -35,7 +35,7 @@ an orchestrator relay never does (`./design.md`, section 8).
|
|
|
35
35
|
in the same round.
|
|
36
36
|
2. **Every worker task names its deliverable and how it is checked.** A worker
|
|
37
37
|
with no stated check reports success on its own terms. Say what is built and
|
|
38
|
-
what proves it:
|
|
38
|
+
what proves it: a test where one is worth writing, the command that passes, the screen
|
|
39
39
|
that shows it.
|
|
40
40
|
3. **Keep the round to `burnConcurrency` workers or fewer.** A soft cap: workers
|
|
41
41
|
past it only queue, and a wider round has more to reconcile when it returns.
|
|
@@ -65,7 +65,11 @@ result, any review findings and where the digests are.
|
|
|
65
65
|
amend `decisions.md` and `spec.md` when what was decided changed, and update
|
|
66
66
|
the pending tickets. A contract reported wrong is a reason to re-plan.
|
|
67
67
|
3. **Handle review findings.** A finding stays open until you resolve it: fix it
|
|
68
|
-
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.
|
|
69
73
|
4. **Decide the next move**:
|
|
70
74
|
- small leftovers → fix them yourself;
|
|
71
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
|
|
47
|
-
commits each
|
|
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
|
|
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.
|