runcastle 1.5.3 → 1.5.4
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 +1716 -2625
- package/drizzle/0052_friendly_black_tarantula.sql +1 -0
- package/drizzle/0053_soft_karma.sql +12 -0
- package/drizzle/meta/0052_snapshot.json +1364 -0
- package/drizzle/meta/0053_snapshot.json +1283 -0
- package/drizzle/meta/_journal.json +14 -0
- package/index.js +1539 -2448
- package/package.json +1 -1
- package/skills/packs/README.md +24 -29
- package/skills/packs/runcastle/.claude-plugin/plugin.json +1 -1
- package/skills/packs/runcastle/skills/feature/SKILL.md +72 -0
- package/skills/packs/runcastle/skills/feature/references/design.md +132 -0
- package/skills/packs/runcastle/skills/feature/references/grilling.md +99 -0
- package/skills/packs/runcastle/skills/feature/references/planning-alone.md +70 -0
- package/skills/packs/runcastle/skills/{ideate → feature}/references/preview-starter.html +11 -16
- package/skills/packs/runcastle/skills/{ideate → feature}/references/preview.md +33 -8
- package/skills/packs/runcastle/skills/feature/references/rounds.md +91 -0
- package/skills/packs/runcastle/skills/feature/references/spec.md +54 -0
- package/skills/packs/runcastle/skills/feature/references/tickets.md +229 -0
- package/skills/packs/runcastle/skills/project/SKILL.md +18 -16
- package/skills/packs/runcastle/skills/project/references/health-sweeps.md +5 -5
- package/skills/packs/runcastle/skills/project/references/triage.md +20 -23
- package/skills/packs/runcastle/skills/qa/SKILL.md +1 -2
- package/web/assets/index-CT9k1kz0.css +1 -0
- package/web/assets/index-DVR7VbWW.js +186 -0
- package/web/index.html +2 -2
- package/skills/packs/runcastle/skills/design/SKILL.md +0 -73
- package/skills/packs/runcastle/skills/ideate/SKILL.md +0 -131
- package/skills/packs/runcastle/skills/lead/SKILL.md +0 -104
- package/skills/packs/runcastle/skills/revisit/SKILL.md +0 -55
- package/skills/packs/runcastle/skills/spec/SKILL.md +0 -47
- package/skills/packs/runcastle/skills/tickets/SKILL.md +0 -147
- package/web/assets/index-BYSs5Hdy.js +0 -186
- package/web/assets/index-bpL_iO_C.css +0 -1
|
@@ -1,12 +1,36 @@
|
|
|
1
1
|
# The plan preview — the page the human looks at
|
|
2
2
|
|
|
3
|
-
Load this when the decisions are
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Load this when the decisions are settled and you are about to show the human
|
|
4
|
+
the plan, or when a decision edit means the preview has to be redrawn.
|
|
5
|
+
Otherwise it costs this conversation nothing.
|
|
6
6
|
|
|
7
7
|
The preview is the one page the human reads the feature by. They confirm the
|
|
8
8
|
plan by looking at it, and when tired it is the only thing they read before
|
|
9
|
-
|
|
9
|
+
they say yes to the first round. Draw it for that reader.
|
|
10
|
+
|
|
11
|
+
## Show it, then get the yes
|
|
12
|
+
|
|
13
|
+
1. **Draw it** from `./preview-starter.html`, following the rules below.
|
|
14
|
+
2. **Check it against `decisions.md`** (the self-check at the end). Fix the
|
|
15
|
+
preview before anyone sees it.
|
|
16
|
+
3. **Show it**: `show_panel({ view: 'plan' })` opens it beside the chat. Tell
|
|
17
|
+
the human what you propose — tickets and rounds, or work you will do
|
|
18
|
+
yourself — and ask for their explicit yes. Then wait for the answer.
|
|
19
|
+
4. **A correction is a decision edit plus a redraw.** Edit the decision in
|
|
20
|
+
`decisions.md` and redraw the preview in the same move, then ask them to
|
|
21
|
+
look again.
|
|
22
|
+
|
|
23
|
+
With no human present, steps 1 and 2 are the whole of this; `./planning-alone.md`
|
|
24
|
+
says how that run asks for the yes.
|
|
25
|
+
|
|
26
|
+
**Never skip the preview on your own judgement** — not because the feature is
|
|
27
|
+
small, not because the grill went quickly. A small feature gets a small
|
|
28
|
+
preview. **If the human says to skip it**, write no file. The yes is still
|
|
29
|
+
needed.
|
|
30
|
+
|
|
31
|
+
**The redraw rule.** Any later edit to `decisions.md` updates `preview.html` in
|
|
32
|
+
the same move, before anything else, while the plan is still being agreed or
|
|
33
|
+
built.
|
|
10
34
|
|
|
11
35
|
## The file
|
|
12
36
|
|
|
@@ -30,13 +54,14 @@ Burn. Draw it for that reader.
|
|
|
30
54
|
title, with the reason available on demand (the starter's `D` list builds
|
|
31
55
|
this). Where a decision is visible in the show, pin its number on that spot:
|
|
32
56
|
`<a class="pin" data-d="3">3</a>`.
|
|
33
|
-
**A self-planned feature** (
|
|
57
|
+
**A self-planned feature** (`./planning-alone.md`) opens this part with a
|
|
34
58
|
**Check first** group of at most five decisions, the ones the planner picked.
|
|
35
59
|
Each entry shows the decision's number and title, its alternative, and why it
|
|
36
60
|
is uncertain (the starter's `C` list builds this). The remaining decisions
|
|
37
61
|
follow in the list, each showing that it was assumed (a third element on its
|
|
38
62
|
`D` entry). **A grilled feature has neither**: no group and no assumed marks.
|
|
39
|
-
4. **What is left out.** Out of scope, and anything deferred
|
|
63
|
+
4. **What is left out.** Out of scope, and under **Later** anything deferred
|
|
64
|
+
to a backlog feature.
|
|
40
65
|
5. **Under the hood.** The technical shape for a reader who wants it,
|
|
41
66
|
**collapsed by default**, drawn where it can be.
|
|
42
67
|
|
|
@@ -65,13 +90,13 @@ Each screen in the show is a **screen block**: the lines between two markers,
|
|
|
65
90
|
```
|
|
66
91
|
|
|
67
92
|
with `<name>` in kebab case and unique in the file. A ticket that builds that
|
|
68
|
-
screen names the block, and its
|
|
93
|
+
screen names the block, and its worker reads only those lines — so put
|
|
69
94
|
everything the screen needs to be understood between the markers, and nothing
|
|
70
95
|
else. Delete the starter's `example-name` block if the show has no screen.
|
|
71
96
|
|
|
72
97
|
## Designed screens
|
|
73
98
|
|
|
74
|
-
A screen designed in design mode (
|
|
99
|
+
A screen designed in design mode (`./design.md`) is **not mocked
|
|
75
100
|
again**. Its place in the show is a **designed-screen entry**:
|
|
76
101
|
|
|
77
102
|
- its name;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Running rounds
|
|
2
|
+
|
|
3
|
+
Load this when you are about to dispatch a round, or you have just been woken by
|
|
4
|
+
one coming back.
|
|
5
|
+
|
|
6
|
+
A round is how workers build: each gets one ticket, a clean sandbox and the full
|
|
7
|
+
brief, and works on its own branch that lands on the feature branch. You
|
|
8
|
+
dispatch it, you are woken when it comes back, you check what it did, and you
|
|
9
|
+
plan the next move.
|
|
10
|
+
|
|
11
|
+
Start the first round only after the human's explicit yes in chat, and ask again
|
|
12
|
+
before any round the agreed plan did not settle (SKILL.md, "The human's yes").
|
|
13
|
+
|
|
14
|
+
## What you run on
|
|
15
|
+
|
|
16
|
+
`get_feature_context` carries:
|
|
17
|
+
|
|
18
|
+
- `rounds` — every round so far, numbered from 1: the tickets it held, how it ended, its gates.
|
|
19
|
+
- `latestReady` — your newest ready declaration, if any.
|
|
20
|
+
- `driveActive` — the human is test-driving this feature right now.
|
|
21
|
+
- `stopped` — the human pressed Stop and has not replied since.
|
|
22
|
+
- `waitingReason` — why the feature is waiting on the human, if it is.
|
|
23
|
+
- `burnConcurrency` — how many workers the project runs at once.
|
|
24
|
+
|
|
25
|
+
## Plan a round
|
|
26
|
+
|
|
27
|
+
1. **Write the tickets** with `emit_tickets`, or reshape pending ones with
|
|
28
|
+
`update_ticket` / `cancel_ticket`, following `./tickets.md`. Then **dispatch**
|
|
29
|
+
with `dispatch_round({ seqs })`, naming exactly the pending tickets this round
|
|
30
|
+
covers. Tickets you do not name wait for a later round. A ticket may stay
|
|
31
|
+
blocked by tickets that landed or were cancelled in an earlier round: those
|
|
32
|
+
count as satisfied. A blocker that is still pending or failed must be named
|
|
33
|
+
in the same round.
|
|
34
|
+
2. **Every worker task names its deliverable and how it is checked.** A worker
|
|
35
|
+
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
|
|
37
|
+
that shows it.
|
|
38
|
+
3. **Keep the round to `burnConcurrency` workers or fewer.** A soft cap: workers
|
|
39
|
+
past it only queue, and a wider round has more to reconcile when it returns.
|
|
40
|
+
4. **Contract first when the work spans layers.** When workers on different
|
|
41
|
+
layers must agree on a shape — types, an API, a schema — make one ticket land
|
|
42
|
+
that contract in code and make the others `blockedBy` it in the same round.
|
|
43
|
+
**Contracts live in code, never in a doc**: workers trust the code.
|
|
44
|
+
5. **UI work names the design references.** A ticket that touches UI tells its
|
|
45
|
+
worker which design docs to follow — the project's own design system docs and
|
|
46
|
+
any design references in this feature's docs — and asks it to plan the
|
|
47
|
+
screen, build it, then critique it against those docs with screenshots.
|
|
48
|
+
|
|
49
|
+
Workers do not talk to each other or to you. They report through their digests,
|
|
50
|
+
their ticket status and their commits. A worker that finds the contract wrong
|
|
51
|
+
stops and says so in its digest; reconciling it is your job, between rounds.
|
|
52
|
+
|
|
53
|
+
## When a round comes back
|
|
54
|
+
|
|
55
|
+
You are woken with the round's outcome, each ticket's status, the verify-gate
|
|
56
|
+
result, any review findings and where the digests are.
|
|
57
|
+
|
|
58
|
+
1. **Trust the record over the prose.** Ticket status, the gates and the commits
|
|
59
|
+
are what happened; a digest is a worker's account of it. Read each digest
|
|
60
|
+
with `get_ticket({ seq })`, and where the two disagree, believe the record.
|
|
61
|
+
2. **Reconcile.** Did a worker report the contract wrong, or change something
|
|
62
|
+
another relied on? Did a decision turn out wrong? Fix the contract in code,
|
|
63
|
+
amend `decisions.md` and `spec.md` when what was decided changed, and update
|
|
64
|
+
the pending tickets. A contract reported wrong is a reason to re-plan.
|
|
65
|
+
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.
|
|
67
|
+
4. **Decide the next move**:
|
|
68
|
+
- small leftovers → fix them yourself;
|
|
69
|
+
- more work, or a failed ticket to retry → plan the next round;
|
|
70
|
+
- a question only the human can answer → ask it in chat and call `wait_for_you({ why })`;
|
|
71
|
+
- the feature does what the plan says → run the checks and declare ready (SKILL.md, "Ready for the human").
|
|
72
|
+
|
|
73
|
+
A failed round is just what came back. Re-plan, retry or fix it yourself.
|
|
74
|
+
`declare_ready` warns when the last round had failures; pass that on.
|
|
75
|
+
|
|
76
|
+
## While and after the human drives
|
|
77
|
+
|
|
78
|
+
Never dispatch while the feature is being driven (`driveActive`). Your own
|
|
79
|
+
commits wait until the drive stops. When the human reports back, follow
|
|
80
|
+
SKILL.md, "After a drive"; when you are satisfied again, declare ready with a
|
|
81
|
+
new scenario.
|
|
82
|
+
|
|
83
|
+
## What the server refuses
|
|
84
|
+
|
|
85
|
+
`dispatch_round` is refused, with the reason, for a draft or shipped feature,
|
|
86
|
+
while a round is already running, while the human is driving this feature, and
|
|
87
|
+
after the human pressed Stop until they have replied. It is also refused when a
|
|
88
|
+
ticket you name is blocked by a ticket outside the round that is still pending
|
|
89
|
+
or failed (or does not exist): the refusal lists each such edge, and the fix is
|
|
90
|
+
to name that blocker in the round too. `stop_round` stops the running round;
|
|
91
|
+
work that already landed stays.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Writing the spec
|
|
2
|
+
|
|
3
|
+
Load this once what the feature does is settled — whether you will build it
|
|
4
|
+
yourself or hand it to workers — or when a later decision changes what
|
|
5
|
+
`spec.md` says.
|
|
6
|
+
|
|
7
|
+
The spec is synthesis, not an interview: write it from the conversation and
|
|
8
|
+
`docs/features/<slug>/decisions.md`. Do not re-ask the human anything that is
|
|
9
|
+
settled.
|
|
10
|
+
|
|
11
|
+
## Process
|
|
12
|
+
|
|
13
|
+
1. **Load state.** `mcp__runcastle__get_feature_context` for the decisions and
|
|
14
|
+
any existing `spec.md` (this may be a rewrite). Read any canonical doc listed
|
|
15
|
+
in `notInlined` before writing a word. Explore the codebase for its current
|
|
16
|
+
state if you have not already; use the project's domain vocabulary and
|
|
17
|
+
respect any ADRs in the area you touch.
|
|
18
|
+
|
|
19
|
+
2. **Sketch the seams** — the public boundaries the feature will be tested at.
|
|
20
|
+
Prefer *existing* seams to new ones; use the *highest* seam possible; the
|
|
21
|
+
fewer across the codebase, the better — the ideal is one. If new seams are
|
|
22
|
+
needed, propose them at the highest point you can. They flow straight into
|
|
23
|
+
the tickets and the tests, so get them right here.
|
|
24
|
+
|
|
25
|
+
3. **Write `docs/features/<slug>/spec.md`** with exactly these sections:
|
|
26
|
+
|
|
27
|
+
```markdown
|
|
28
|
+
# <Feature title>
|
|
29
|
+
|
|
30
|
+
## Problem
|
|
31
|
+
The problem the user faces, from the user's perspective.
|
|
32
|
+
|
|
33
|
+
## Approach
|
|
34
|
+
The solution from the user's perspective, then the shape of it: modules built/modified, their interfaces, schema/API/contract decisions, key interactions. Prose, not a file-by-file plan.
|
|
35
|
+
|
|
36
|
+
## Seams
|
|
37
|
+
The interfaces to test at (from step 2) — each named, with what it lets you observe. Flag which are existing vs. new.
|
|
38
|
+
|
|
39
|
+
## Out of scope
|
|
40
|
+
What this feature explicitly does not cover, including scope parked as backlog features.
|
|
41
|
+
|
|
42
|
+
## Open questions
|
|
43
|
+
Anything still unresolved or deliberately deferred.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Do **not** hardcode file paths or code snippets — they go stale. Exception:
|
|
47
|
+
when the conversation produced a snippet that pins a decision more precisely
|
|
48
|
+
than prose can (a state machine, a reducer, a schema, a type shape), inline
|
|
49
|
+
the decision-rich parts and say where it came from.
|
|
50
|
+
|
|
51
|
+
4. **Commit it** with the decisions it was written from, as a docs commit.
|
|
52
|
+
|
|
53
|
+
When a later decision changes what the feature does, amend the affected
|
|
54
|
+
sections in place rather than appending.
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
<!-- Forked from Matt Pocock's to-tickets skill, via https://github.com/mattpocock/skills, 2026-07-14, adapted for runcastle -->
|
|
2
|
+
|
|
3
|
+
# Writing tickets
|
|
4
|
+
|
|
5
|
+
Load this when work is worth handing to sandboxed workers and you are about to
|
|
6
|
+
write, reshape or cancel tickets.
|
|
7
|
+
|
|
8
|
+
Break the work into **tickets** — vertical slices, each cutting end-to-end
|
|
9
|
+
through every layer it needs, each big enough to be worth a whole agent session
|
|
10
|
+
and small enough to finish inside one — and emit them with
|
|
11
|
+
`mcp__runcastle__emit_tickets`. Synthesize from `spec.md` and the conversation.
|
|
12
|
+
The feature's existing tickets come as summary rows in `get_feature_context`;
|
|
13
|
+
`mcp__runcastle__get_ticket({ seq })` holds one ticket's context, acceptance
|
|
14
|
+
criteria and digest.
|
|
15
|
+
|
|
16
|
+
## The one thing that makes a runcastle ticket different
|
|
17
|
+
|
|
18
|
+
Each ticket is executed by a **single fresh agent, alone, in a sandbox, with
|
|
19
|
+
~100k tokens and NO way to ask a follow-up question.** It sees only what you put
|
|
20
|
+
in the ticket plus the code already in the repo. So — *inverting* the usual
|
|
21
|
+
"avoid file paths, they go stale" rule — the ticket's `context` field **must be
|
|
22
|
+
concrete and self-sufficient**: name the files to touch, the existing patterns
|
|
23
|
+
to copy, the type/schema shapes, the gotchas, the commands to run and verify
|
|
24
|
+
with. A ticket that assumes the agent can ask "where does X live?" is a broken
|
|
25
|
+
ticket. Over-specify context; under-specify nothing.
|
|
26
|
+
|
|
27
|
+
## The second thing: a ticket costs ~10 minutes before it does any work — and pays it twice if it overruns
|
|
28
|
+
|
|
29
|
+
That fresh agent is fresh *every time*. Each ticket gets its own container: cold
|
|
30
|
+
build, a full dependency install (measured 70–507s, ~2.5 min average), then an
|
|
31
|
+
agent that re-reads the spec, the docs digest, and every file your `context`
|
|
32
|
+
names — reading the repo was 16% of all agent time across 42 measured attempts.
|
|
33
|
+
**This overhead is paid per ticket and is the same whether the ticket is twenty
|
|
34
|
+
lines or a day's work.** Splitting one coherent piece of work into three tickets
|
|
35
|
+
triples it, and adds two seams where a new agent has to reconstruct what the
|
|
36
|
+
previous one had just finished learning.
|
|
37
|
+
|
|
38
|
+
But that meter runs both ways. A ticket too big to finish in one pass gets no
|
|
39
|
+
cheap second wind: an iteration is not a retry (ADR-0008) — the container is
|
|
40
|
+
rebuilt, the install runs again, and a brand-new agent re-reads everything from
|
|
41
|
+
the last commit, having lost every conclusion its predecessor reached.
|
|
42
|
+
|
|
43
|
+
So size a ticket to **earn its container and still land in one pass**:
|
|
44
|
+
substantial, with room left at the end for the tests, the self-review and the
|
|
45
|
+
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
|
+
one-criterion tickets orient six times.
|
|
49
|
+
|
|
50
|
+
Expect a **handful of substantial tickets** for a feature — roughly 4–8, each
|
|
51
|
+
worth a session. A dozen thin ones means you sliced by layer or by file, not by
|
|
52
|
+
behaviour. Two or three giant ones means you will pay back the containers you
|
|
53
|
+
saved, with interest, when they overrun.
|
|
54
|
+
|
|
55
|
+
## 1. Draft vertical slices
|
|
56
|
+
|
|
57
|
+
<vertical-slice-rules>
|
|
58
|
+
- Each slice cuts a narrow but COMPLETE path through every layer it needs (schema, API, UI, tests) — vertical, NOT a horizontal slice of one layer.
|
|
59
|
+
- A completed slice is demoable or verifiable on its own.
|
|
60
|
+
- Each slice is worth one fresh ~100k-token agent session working alone and **lands inside it** — leave room for the orientation at the front and the tests, self-review and commits at the back.
|
|
61
|
+
- **Merge when a merge test holds.** Two drafts are one ticket if they touch the same files, share a type or module, or the second one's first act would be re-reading what the first just wrote. Same for the obvious siblings of one behaviour: create/edit/delete of a resource, an endpoint and the UI that calls it, code and the tests that cover it.
|
|
62
|
+
- **Split only for a real reason:** (a) a genuine gate — the later work cannot be written until the earlier work's interface exists; (b) the combined work would not land in one session; (c) a prefactor, which is its own slice done first ("make the change easy, then make the easy change"); (d) parallel width, under the rule below; (e) the wide-refactor sequence below.
|
|
63
|
+
- **Not reasons to split:** one ticket per file, layer, endpoint or component; keeping each ticket easy; keeping diffs small; separating tests from the code they test.
|
|
64
|
+
- **Parallelism pays when the halves are file-disjoint.** Tickets with no blocking edge burn concurrently, each on its own temp branch, landing one at a time (ADR-0002) — so two substantial slices touching *different* files buy real wall-clock. Two touching the *same* files race to land, and the loser fails on a merge conflict: that width costs a re-burn. Overlapping files → merge.
|
|
65
|
+
</vertical-slice-rules>
|
|
66
|
+
|
|
67
|
+
Give each ticket its **blocking edges** — the tickets that must finish before it
|
|
68
|
+
can start. The field is required: a ticket with no blockers gets an empty array.
|
|
69
|
+
|
|
70
|
+
<review-ticket>
|
|
71
|
+
**A review ticket, when you choose to run one.** Whether a batch gets a review
|
|
72
|
+
is your call (SKILL.md, "Review is your call"). When it does, add **one** ticket
|
|
73
|
+
with `kind: "review"`, blocked by every implementation ticket whose work it
|
|
74
|
+
checks. It is not a slice: it is the brief for the agent that exercises the
|
|
75
|
+
*integrated* work on the feature branch and reports what it finds as findings.
|
|
76
|
+
Its `goal` says what to verify and its `acceptanceCriteria` are the things to
|
|
77
|
+
check off, one per behaviour worth confirming — the review agent walks them in
|
|
78
|
+
order. `emit_tickets` refuses a ticket *titled* like a review but carrying
|
|
79
|
+
another kind: set the kind (or retitle it) and re-emit.
|
|
80
|
+
|
|
81
|
+
The review agent works in **exactly one of two modes**, never both — a browser
|
|
82
|
+
**Drive** of the app against your acceptance criteria, or **Gates**: the
|
|
83
|
+
project's verify commands plus a two-axis read of the diff. Reviews that
|
|
84
|
+
attempted both ran long or died having delivered neither.
|
|
85
|
+
|
|
86
|
+
Make the choice obvious. Prescribe a walkthrough only when there is genuinely a
|
|
87
|
+
surface to walk, in plain prose ("open the settings flow, add a project, check
|
|
88
|
+
the empty state"), and write the `acceptanceCriteria` as the steps of that walk.
|
|
89
|
+
When the work changed nothing a human could drive — prompt contracts, docs, an
|
|
90
|
+
internal refactor, a backend-only change — say so in the ticket, and write
|
|
91
|
+
criteria the gates-and-diff read can check off.
|
|
92
|
+
|
|
93
|
+
**Say what to walk, never which mode.** A review ticket never directs the agent
|
|
94
|
+
to Gates — no "Mode: Gates", no "skip the drive" — and the mode is the review
|
|
95
|
+
agent's call from the surface you describe. Least of all give as the reason that
|
|
96
|
+
the change "isn't deployed or installed yet": the drive boots **the branch** —
|
|
97
|
+
the project's drive setup points it at the checkout's own code, migrations and
|
|
98
|
+
assets precisely so a branch is visible in its own drive. A review ticket once
|
|
99
|
+
prescribed Gates on exactly that reasoning, and a UI feature reached the human
|
|
100
|
+
without ever being driven. If the state to check does not exist yet in a fresh
|
|
101
|
+
drive, the `acceptanceCriteria` say how to produce it inside the drive, as far as
|
|
102
|
+
the project's drive instructions allow, and then what to check.
|
|
103
|
+
|
|
104
|
+
The review agent never edits code, so its ticket needs no `seams` beyond the
|
|
105
|
+
surface it exercises, and finding bugs is a *successful* review. Its digest
|
|
106
|
+
carries a prose summary of what landed, which the Review view leads with, so
|
|
107
|
+
`goal` asks for the verification, not for the summary.
|
|
108
|
+
</review-ticket>
|
|
109
|
+
|
|
110
|
+
<parallelism-budget>
|
|
111
|
+
**Budget the parallelism explicitly, before you emit.** A round runs up to
|
|
112
|
+
`burnConcurrency` tickets at once (from `get_feature_context`), but a ticket
|
|
113
|
+
cannot start until every ticket in its `blockedBy` has landed, so a round's
|
|
114
|
+
wall-clock is set by its **critical path**: the longest chain of blocking edges.
|
|
115
|
+
A chain of N tickets is N sequential sandboxes however wide the pool is.
|
|
116
|
+
Measured at `burnConcurrency: 3`, three consecutive batches whose tickets each
|
|
117
|
+
chained end to end came in at **1.09x, 1.16x and 1.00x** — the width was there
|
|
118
|
+
and never spent.
|
|
119
|
+
|
|
120
|
+
So, after slicing, **say it out loud in the session**:
|
|
121
|
+
|
|
122
|
+
- the **critical path** — the longest chain of implementation tickets, named in order, and its length;
|
|
123
|
+
- **how many tickets can run at once**, against this project's `burnConcurrency`;
|
|
124
|
+
- whether that clears the bar: T implementation tickets at concurrency C want a chain no longer than roughly **T / C**.
|
|
125
|
+
|
|
126
|
+
**When it does not clear the bar, reslice.** **A blocking edge is true only when
|
|
127
|
+
the later ticket reads the earlier one's output**: a file it writes, a type or
|
|
128
|
+
interface it defines, a schema it migrates, a stub it fills. "Related", "same
|
|
129
|
+
area", "logical reading order" are not blocking edges — drop them. Where the
|
|
130
|
+
edge is real, merge the two into one ticket, or pull the shared foundation
|
|
131
|
+
forward into the blocker so everything else goes wide behind it.
|
|
132
|
+
|
|
133
|
+
A review ticket is the tail by definition: measure the critical path over the
|
|
134
|
+
implementation tickets and add it. Width only counts if it lands: parallel
|
|
135
|
+
tickets touching the same files collide on landing.
|
|
136
|
+
</parallelism-budget>
|
|
137
|
+
|
|
138
|
+
<ship-a-scenario>
|
|
139
|
+
**Ship a scenario when the state is hard to reach.** A scenario is a project
|
|
140
|
+
command under `.runcastle/scenarios/` that seeds a state and prints the URL to
|
|
141
|
+
land on, so a test drive starts where the feature is instead of on a blank app.
|
|
142
|
+
Read `get_feature_context`'s `scenarios` field — `{ setUp, runnerConfigured,
|
|
143
|
+
scenarios, fixtures }` — before you decide anything.
|
|
144
|
+
|
|
145
|
+
**When `setUp` is true**, ask of each ticket: will the person driving this have
|
|
146
|
+
to build state by hand to see it — an account, a cart with an expired coupon?
|
|
147
|
+
|
|
148
|
+
- If yes, give the implementation ticket that builds that state an acceptance criterion: "Ship `.runcastle/scenarios/<group>/<name>.<ext>` that seeds <state> (reusing `_fixtures`) and prints `ENTRY_URL=<where>`". Name the fixtures it should reuse. When the change is an API call, the criterion also ships a sibling `.http` file at the same path with the request, and the scenario prints `TOKEN=` when the call is authenticated.
|
|
149
|
+
- Name that scenario in the review ticket's `context`, if there is one, so the reviewer replays it rather than improvising the setup; and use it as the `scenario` you declare ready with.
|
|
150
|
+
- Copy changes and settings toggles get none. A scenario earns its place only where reaching the state is the chore.
|
|
151
|
+
- The worker writes and typechecks the scenario but cannot run it — a sandbox has no drive.
|
|
152
|
+
|
|
153
|
+
**When `setUp` is false**, card nothing about scenarios. Tell the human once
|
|
154
|
+
that + New scenario in a test drive sets scenarios up for this project.
|
|
155
|
+
</ship-a-scenario>
|
|
156
|
+
|
|
157
|
+
<wide-refactor-exception>
|
|
158
|
+
A **wide refactor** — one mechanical change (rename a column, retype a shared symbol) whose blast radius breaks thousands of call sites at once — cannot land green as a vertical slice. Sequence it **expand → migrate → contract**. Expand: add the new form beside the old so nothing breaks (one ticket). Migrate: move call sites over in batches sized by blast radius (per package/dir), each a ticket blocked by the expand, green throughout because the old form still exists. Contract: delete the old form once no caller remains, blocked by every migrate batch. If even the batches cannot stay green alone, let them all block a final integrate-and-verify ticket — green is promised only there.
|
|
159
|
+
</wide-refactor-exception>
|
|
160
|
+
|
|
161
|
+
<preview-screen-block>
|
|
162
|
+
When the feature has a `preview.html` and a ticket **builds a screen that appears in it as a screen block**, point that ticket at **one named screen block**, never the file. Its **context** names the path (`docs/features/<slug>/preview.html`) and the block name, and tells the worker to find the two markers, `<!-- screen:<name> -->` and `<!-- /screen:<name> -->`, and **read only the lines between them**. Say plainly that the block shows the approved look and behaviour and **is not the implementation**: build it with the project's real components and never copy the mock's markup. **Never tell a worker to read the whole file.**
|
|
163
|
+
|
|
164
|
+
A ticket with no screen does not mention the preview.
|
|
165
|
+
|
|
166
|
+
A **designed-screen block** holds no mock. It names a component committed in design mode and its preview page. Point the ticket at that component file and that preview page path, not at markup.
|
|
167
|
+
</preview-screen-block>
|
|
168
|
+
|
|
169
|
+
<connect-designed-screens>
|
|
170
|
+
A ticket that wires a **designed screen** (one committed in design mode, `design: …` commits on the feature branch) names the committed component and its preview page in its `context`, and says plainly that **the look is approved**. Its job is to **connect, never restyle**:
|
|
171
|
+
|
|
172
|
+
- swap the sample data for real data (queries, API calls);
|
|
173
|
+
- add the behaviour the design left out;
|
|
174
|
+
- change markup only where the wiring needs it.
|
|
175
|
+
|
|
176
|
+
When wiring forces a visible change (a field the design lacked, say), the worker calls it out in its digest.
|
|
177
|
+
</connect-designed-screens>
|
|
178
|
+
|
|
179
|
+
## 2. Build each ticket to the schema
|
|
180
|
+
|
|
181
|
+
Emit an array of `TicketInput`. Number them from 1 in the array in **dependency
|
|
182
|
+
order (blockers first)**; `blockedBy` holds those numbers.
|
|
183
|
+
|
|
184
|
+
Each ticket:
|
|
185
|
+
- **title** — `{group}: {task}`, in the domain vocabulary: `Checkout: apply the coupon at payment`.
|
|
186
|
+
- **goal** — the end-to-end behaviour this ticket makes work, from the user's/caller's perspective. Not a layer list.
|
|
187
|
+
- **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.
|
|
189
|
+
- **seams** — `string[]`, the public interfaces to test at (from the spec's Seams; prefer existing, prefer the highest, prefer one).
|
|
190
|
+
- **blockedBy** — `number[]`, **required**, only true gates; `[]` when there are none.
|
|
191
|
+
- **kind** — `"implementation"` (the default, omit it) or `"review"`.
|
|
192
|
+
- **model** — optional, and usually omitted. See below.
|
|
193
|
+
|
|
194
|
+
### Assigning a model (only from the annotated roster)
|
|
195
|
+
|
|
196
|
+
`get_feature_context` returns `annotatedModels`: `{ id, runtime, note }` for the
|
|
197
|
+
models the human wrote a use-case note against. That list is the *entire* set
|
|
198
|
+
of ids you may use.
|
|
199
|
+
|
|
200
|
+
- **Empty list → never set `model`.**
|
|
201
|
+
- **Non-empty → set it only where a note plainly fits the ticket.** Unset is the good default.
|
|
202
|
+
- **Never invent an id**, and never write one not in `annotatedModels` — the store rejects it and the whole batch fails to emit.
|
|
203
|
+
|
|
204
|
+
## 3. Self-check, then emit
|
|
205
|
+
|
|
206
|
+
Check yourself, in this order:
|
|
207
|
+
|
|
208
|
+
1. **Can any two of these be one ticket?** Take them pair by pair; merging changes the rest.
|
|
209
|
+
2. **Would any one overrun?** Split it where its files stop overlapping.
|
|
210
|
+
3. Is each survivor a demoable vertical slice, worth a session?
|
|
211
|
+
4. Are the blocking edges minimal and true? State the critical path and the width against `burnConcurrency`, and reslice if the chain runs longer than roughly total / concurrency. Do independent tickets touch different files?
|
|
212
|
+
5. Is every `context` self-sufficient for an agent that cannot ask?
|
|
213
|
+
6. If you chose a review, is there exactly one `kind: "review"` ticket, blocked by the work it checks?
|
|
214
|
+
7. If `scenarios.setUp`, does every ticket that builds hard-to-reach state ship a scenario for it?
|
|
215
|
+
|
|
216
|
+
Then `mcp__runcastle__emit_tickets({ tickets: [...] })` — **emit the array; do
|
|
217
|
+
NOT write ticket files.** It returns `{ stored, ids }`, logs the timeline event
|
|
218
|
+
itself, and opens the **Work** view beside the chat. Emit the **whole batch,
|
|
219
|
+
fully enriched, in one call**; never emit placeholder contexts to enrich
|
|
220
|
+
afterwards — a round dispatched mid-enrichment burns workers on placeholders.
|
|
221
|
+
|
|
222
|
+
## Reshaping tickets later
|
|
223
|
+
|
|
224
|
+
When something changes after tickets exist, walk the ticket list against it:
|
|
225
|
+
|
|
226
|
+
- Stale but still needed → `update_ticket({ id, ...changed fields })` (pending or failed only).
|
|
227
|
+
- No longer needed → `cancel_ticket({ id, reason })` (pending or failed only).
|
|
228
|
+
- New work → `emit_tickets` again; tickets accumulate on the feature.
|
|
229
|
+
- Landed work now wrong → a NEW ticket that corrects it. Never touch landed or running tickets.
|
|
@@ -11,7 +11,7 @@ You belong to the **project**, not to any feature. There is no feature state to
|
|
|
11
11
|
|
|
12
12
|
Your defining job is the one no other surface in runcastle can do: **intake and decomposition terminating in feature creation**. Every other door into the pipeline demands a title and a one-liner up front, which means it demands the human has already cut their thought into a feature. You are where they don't have to — and, because you are the only session that can see the *whole portfolio*, you are the only one that can tell them their thought is really two features, or one they already shipped.
|
|
13
13
|
|
|
14
|
-
You are a **shape griller, not a design griller.** You grill across the whole lump of intent — breadth-first, only what could change the cut — so the cut is sized on real information. The deep design interrogation belongs to the feature's own session (`/runcastle:
|
|
14
|
+
You are a **shape griller, not a design griller.** You grill across the whole lump of intent — breadth-first, only what could change the cut — so the cut is sized on real information. The deep design interrogation belongs to the feature's own session (`/runcastle:feature`); yours is the conversation one level up, about what should exist and how it should be cut.
|
|
15
15
|
|
|
16
16
|
Everything else you do — portfolio Q&A, routing, curation, the charter — is support for that job or a consequence of being the one session at project scope.
|
|
17
17
|
|
|
@@ -25,7 +25,7 @@ Ten, and deliberately none of the feature pipeline's. A session with no feature
|
|
|
25
25
|
- `mcp__runcastle__read_adr({ relPath })` — one ADR in full, from the index. This is how you read the decisions that bind the idea in front of you, one at a time, instead of swallowing them all.
|
|
26
26
|
- `mcp__runcastle__read_feature_brief({ slug })` — one feature's title, one-liner, status/phase/lap and brief: off disk for a shipped feature, from the database for an in-flight or draft one. This is how you go from "that title sounds related" to what the feature is for.
|
|
27
27
|
- `mcp__runcastle__get_work_record({ featureSlug? , seam? , seq? })` — what features actually **did**. Send exactly one of `featureSlug` or `seam`. The **seam** form lists matching tickets as rows — feature slug, `seq`, title, status, seams, commits, error — with no digests. The **featureSlug** form tells the whole story: tickets by status, seams, commits, errors, run summaries, and each burner's digest of what it actually did, what surprised it and what it left undone; a digest too large to fit is moved out and its ticket marked `digestNotInlined: true`. **`featureSlug` + `seq`** returns that one ticket with its digest. Facts, never intent.
|
|
28
|
-
- `mcp__runcastle__create_feature({ title, oneLiner, baseBranch?, brief?, draft?,
|
|
28
|
+
- `mcp__runcastle__create_feature({ title, oneLiner, baseBranch?, brief?, draft?, dependsOn? })` — the end of intake. `dependsOn` (feature slugs, drafts only) records merge order (§1c).
|
|
29
29
|
- `mcp__runcastle__set_feature_dependencies({ slug, dependsOn })` — replaces a draft's whole merge-order set (§1c).
|
|
30
30
|
- `mcp__runcastle__record_event({ type, message })` — a note on the project timeline.
|
|
31
31
|
- `mcp__runcastle__list_project_notes()` — the project's **open notes**, oldest first: id, text, createdAt, and for a note with a screenshot its absolute host path (`Read` it) plus a ready-made attachment sentence to paste into a ticket string. A note taken during a project test drive also carries `driveBranch` and `driveCommit`: it was noted while driving `<driveBranch>` @ `<driveCommit>`, which tells you whether it predates a fix.
|
|
@@ -74,7 +74,7 @@ Size the read to the idea — but **do not skip it**. "I did not check" is not a
|
|
|
74
74
|
Now talk. In this order, and all of it before any `create_feature`:
|
|
75
75
|
|
|
76
76
|
- **Report what you found, with addresses.** "We shipped `notes-inbox` in June; its digest says the promote path was left undone — that is most of what you are asking for." Adjacency, overlap and outright duplication are the findings the human cannot get anywhere else. **"We already built this" and "an ADR already settles this" are successful outcomes**, not failures to create something.
|
|
77
|
-
- **Shape-grill before you propose the cut.** One question at a time, each with your recommended answer attached, and wait for the answer before the next.
|
|
77
|
+
- **Shape-grill before you propose the cut.** One question at a time, each with your recommended answer attached, and wait for the answer before the next. Work **breadth-first across the main ideas** — touch every piece of the lump before you go any deeper into one, and never go deep into any. Ask only what could change the cut:
|
|
78
78
|
- **the pieces** — what separate things are in this lump;
|
|
79
79
|
- **the core** — which piece is the one the rest exists for;
|
|
80
80
|
- **the uncertainty** — where the human is unsure, and what they would want to test-drive first;
|
|
@@ -83,18 +83,20 @@ Now talk. In this order, and all of it before any `create_feature`:
|
|
|
83
83
|
If you cannot say which way an answer would swing the cut, you do not need to ask it. The grill **stops at the cut**: it locks no decisions and writes no feature docs.
|
|
84
84
|
- **Recommend, don't interrogate.** Put your proposed cut to them and say why it is the cut. They correct or confirm. Never ask a bare question with no recommendation attached.
|
|
85
85
|
- **Suggest how to split the work.** This is the advice they came for: is this one feature or three? What lands first, and what is it that later work needs from it? What should the *first lap* be, if the obvious version is too big to be worth doing whole? Say which order you would take and why.
|
|
86
|
-
- **Cut until every feature fits one ideation window.** Each feature you propose must be thinkable in a single `/runcastle:
|
|
86
|
+
- **Cut until every feature fits one ideation window.** Each feature you propose must be thinkable in a single `/runcastle:feature` session. A piece that is not gets cut further, or its later parts are parked as drafts. Big intent never reaches ideation as one feature — you are the size gate.
|
|
87
87
|
- **Push on the cut, not the design.** For each candidate: *what must this feature NOT swallow?* A boundary nobody can state is not a boundary.
|
|
88
88
|
|
|
89
|
-
**This is a shape grill, not a design grill, and you must not run a design grill.** No data shapes, no UX detail, no edge cases, no pushing until the design resolves, no locking decisions, and no writing to any feature's docs. That is `/runcastle:
|
|
89
|
+
**This is a shape grill, not a design grill, and you must not run a design grill.** No data shapes, no UX detail, no edge cases, no pushing until the design resolves, no locking decisions, and no writing to any feature's docs. That is `/runcastle:feature`'s job and it does it with the feature's whole context in one unbroken window — a design grill here burns the human's patience twice and produces the worse version, because you are working from a one-line index where the grill session has the repo. Stop at the cut. When the human starts answering design questions rather than scope questions, say so and point them at the feature's own session.
|
|
90
90
|
|
|
91
91
|
### 1c. Create — once the split is agreed
|
|
92
92
|
|
|
93
93
|
When they have confirmed the cut: **one `create_feature` call per feature.** Not before the agreement, and not one call for a shape you proposed and they have not answered on.
|
|
94
94
|
|
|
95
|
-
**Ask, per feature: start it now,
|
|
95
|
+
**Ask, per feature: start it now, up next after something, or the backlog?** A backlog feature (status `draft`) is the same feature with no branch cut and nothing written to the repo, waiting on the human's **Start** click — pass `draft: true` for the backlog ones. The brief is stored either way, so adding to the backlog costs the conversation nothing. Intake routinely resolves into more features than anyone will work this week, and a branch cut for each is a branch going stale.
|
|
96
96
|
|
|
97
|
-
**State the cut's order as `dependsOn`, not as brief prose.** When one feature needs another merged first, create the dependency first, then the dependent with `draft: true, dependsOn: [<dependency's slug>]`. The draft's **Start** stays refused until every feature it waits on has shipped
|
|
97
|
+
**State the cut's order as `dependsOn`, not as brief prose.** When one feature needs another merged first, create the dependency first, then the dependent with `draft: true, dependsOn: [<dependency's slug>]`. The draft's **Start** stays refused until every feature it waits on has shipped — prose in a brief holds nobody to anything. Only drafts can wait.
|
|
98
|
+
|
|
99
|
+
**Backlog and up next mean different things, so ask which the human means.** The backlog is "not now": the feature stays there until the human starts it, even once its dependencies have shipped. Up next is "yes, as soon as those ship": add `upNext: true` (with `draft: true` and a non-empty `dependsOn`) and the feature starts itself — branch cut, brief written, no session launched — the moment its last dependency merges. Choose up next when the human has agreed the work and only the order holds it back; keep the backlog for what they have not decided to do. To re-order or move drafts later, `set_feature_dependencies({ slug, dependsOn, upNext })` replaces a draft's whole set (`[]` clears it) and moves it either way; leave `upNext` out to leave the mark as it is. The feature index shows each line's edges as `· waits on: a, b ✓`, and marks unstarted features `[draft, up next]` (`up next, stuck` when it needs the human) or `[draft, blocked]` (backlog, with an open dependency).
|
|
98
100
|
|
|
99
101
|
**State the base you will cut from; do not ask for it as a matter of course.** A feature you are starting forks off the checkout's current branch — `baseBranches.current` — because that is the branch the human chose to work on. **Say which branch as part of the proposal** ("cutting `feature/dark-mode` from `develop` — say so if it should fork elsewhere") and pass it as `baseBranch` on every non-draft `create_feature`. Always pass it explicitly; a call that omits it is a branch cut where nobody said from where, which is the thing this convention exists to end. There is no routine "which branch?" question here — a second obligatory question per feature turns intake into a form.
|
|
100
102
|
|
|
@@ -123,8 +125,8 @@ It is written into `brief.md` verbatim and it is what the grilling session (and
|
|
|
123
125
|
Anything that arrives (from the human, or from a sweep in §6) goes to exactly one of:
|
|
124
126
|
|
|
125
127
|
1. **A new feature** — it has real design questions, which its *own* grill session will work. `create_feature` with a brief.
|
|
126
|
-
2. **A
|
|
127
|
-
3. **An existing feature's
|
|
128
|
+
2. **A small, concrete change** — work too small to deserve a conversation ("make this darker"; "expected X, got Y, repro like this"). Still `create_feature({ title, oneLiner, brief })`, with a brief concrete enough that nothing is left to grill: what to change, and the repro or the expected/got for a bug. Its own agent reads the brief and the code, does a small change itself or writes tickets, and asks the human for the yes in its chat. **One feature per change, not per fix:** several small fixes that belong to the same change go in that one brief; creating one each would give you a feature each. **During notes triage that rule widens to one batched feature per triage session** — every small theme of the pass goes into that single brief (**Notes triage**).
|
|
129
|
+
3. **An existing feature's change** — it belongs to a feature already in flight. You have no tool for this: **tell the human to open that feature and say so in its chat.**
|
|
128
130
|
4. **More rounds** — the thing is in Review and the drive taught them it is not right yet. Again no tool: tell them to say so in that feature's chat, or with **Send to agent** from the drive; its agent runs more rounds.
|
|
129
131
|
5. **Nothing** — it is already decided, already built, or not worth doing. Say so plainly, with the ADR or the shipped feature that settles it.
|
|
130
132
|
|
|
@@ -147,7 +149,7 @@ You may notice, and you should say:
|
|
|
147
149
|
- a term used with two meanings across features;
|
|
148
150
|
- docs that no longer describe the code.
|
|
149
151
|
|
|
150
|
-
**You do not fix any of it.** Report it, then route it through §2 like anything else — a fix rides a feature,
|
|
152
|
+
**You do not fix any of it.** Report it, then route it through §2 like anything else — a fix rides a feature, or promotion at merge. The value of noticing a collision is fully captured by *saying so*; acting on it is how this session would quietly become a project editor.
|
|
151
153
|
|
|
152
154
|
The one exception is the charter, which is yours (§5) — and even there, a change that overturns an ADR is a decision, and decisions land as ADRs.
|
|
153
155
|
|
|
@@ -169,7 +171,7 @@ When the human asks for a sweep ("what needs doing?", "what's rotting?"), do the
|
|
|
169
171
|
|
|
170
172
|
The human jots one-line notes (often with a screenshot) from any screen in the project, and they pile up in the project's inbox. Triage is intake again, with **that pile** supplying the raw material: read and cluster the notes, grill the human theme by theme for the intent behind them, then route each theme through §2 with the grilled reasoning carried into what that destination holds. A ten-second note records a symptom, so routing one cold is not triage.
|
|
171
173
|
|
|
172
|
-
**Read `./references/triage.md` when triage actually starts** — a briefing that says to triage, or the human taking up the open-notes offer (§0). It carries the three movements, when to drop / merge / reframe a note, the one batched
|
|
174
|
+
**Read `./references/triage.md` when triage actually starts** — a briefing that says to triage, or the human taking up the open-notes offer (§0). It carries the three movements, when to drop / merge / reframe a note, the one batched feature per session, the outcome-line formats, and how a deferred theme is rewritten and left open. Do not load it in a chat that is not triaging, and do not start one unprompted.
|
|
173
175
|
|
|
174
176
|
## Orchestrating
|
|
175
177
|
|
|
@@ -226,7 +228,7 @@ Watch for what no feature's session can see: **conflicts or contradictions betwe
|
|
|
226
228
|
|
|
227
229
|
**What you create is yours.** `create_feature` marks it as yours and launches nothing. **Features you did not create are the human's**: you see them, and you tell the human when one interacts with your work, but you never act on them. When the human hands you one by name, take it over with `take_over_feature`; never take one they did not hand you.
|
|
228
230
|
|
|
229
|
-
**Have them plan themselves** with `plan_feature` when you judge a feature ready. Start a backlog feature of yours with `start_feature`, stating its base branch as §1c says; when
|
|
231
|
+
**Have them plan themselves** with `plan_feature` when you judge a feature ready. Start a backlog feature of yours with `start_feature`, stating its base branch as §1c says; up-next features start themselves when what they wait on merges, so you only watch for them; a backlog feature stays your call, including when a feature you merge was what it waited on.
|
|
230
232
|
|
|
231
233
|
### Judging a plan
|
|
232
234
|
|
|
@@ -235,7 +237,7 @@ Watch for what no feature's session can see: **conflicts or contradictions betwe
|
|
|
235
237
|
- **A decision that contradicts the human** goes back: `send_to_feature` delivers your message to the feature's own planning conversation, saying what to change and why. That session edits the decision, keeps it assumed and marks it changed by the orchestrator. You do not edit a feature's docs yourself.
|
|
236
238
|
- **A decision the human never spoke to**, settle by your own judgement and name it in your report.
|
|
237
239
|
- **Ask the human only when the decision changes what they get, not how it is built, and a wrong guess would cost a lap.** A sentence from them is cheaper than a lap spent on the wrong guess; anything below that line puts them back in the middle of planning.
|
|
238
|
-
- **One question at a time**, in your terminal, with your recommendation attached. **Keep everything else moving while you wait**: only that feature's send-back or
|
|
240
|
+
- **One question at a time**, in your terminal, with your recommendation attached. **Keep everything else moving while you wait**: only that feature's send-back or its yes waits for the answer.
|
|
239
241
|
- **Relay their answer** with `send_to_feature`, saying it is the human's answer. The feature's session then removes the marks from that decision, as it would for the human.
|
|
240
242
|
|
|
241
243
|
### Messages from runcastle
|
|
@@ -248,11 +250,11 @@ Watch for what no feature's session can see: **conflicts or contradictions betwe
|
|
|
248
250
|
|
|
249
251
|
A line may arrive while the human is typing, and join their half-typed line. If a message reads mangled, say so and read the record.
|
|
250
252
|
|
|
251
|
-
###
|
|
253
|
+
### The yes, rounds, driving
|
|
252
254
|
|
|
253
255
|
You play the human's part on your features, one level up: you hold the checkpoints, and each feature's own agent — its lead — holds the rounds.
|
|
254
256
|
|
|
255
|
-
- **Give
|
|
257
|
+
- **Give the yes when the plan is right**: a feature's agent asks for it in its chat before its first round. Answer with `send_to_feature`, saying the plan is agreed and it may start. Its lead dispatches every round from there. **You never dispatch a round**, and you never coordinate its workers.
|
|
256
258
|
- **Drive when the agreement calls for the human's eyes**, once a lead declares ready, not after every round. The declaration names a scenario and says what to test; start there. `drive` starts or stops a test drive of a feature branch, or of the base branch. Tell the human what to try. Record what they report with `record_test_note`, saying whether the human or you observed it.
|
|
257
259
|
- **Send what the drive found to the lead** with `send_to_feature`, as one message: it reaches the feature's agent as the human's would, and the agent runs more rounds or declares ready again. "All good" is a valid message.
|
|
258
260
|
- **Read the review through a subagent** when a lead declares ready, and act on what it concludes.
|
|
@@ -283,7 +285,7 @@ A session that edits without committing leaves a dirty tree, and a dirty tree is
|
|
|
283
285
|
## Do NOT
|
|
284
286
|
|
|
285
287
|
- **Never create a feature before you have consulted the portfolio and agreed the cut.** §1's order — look, advise, create — is the session.
|
|
286
|
-
- **Never run a design grilling.** Shape-grill for the cut, and stop there. You resolve *what should exist and how it is cut*; the feature's own `/runcastle:
|
|
288
|
+
- **Never run a design grilling.** Shape-grill for the cut, and stop there. You resolve *what should exist and how it is cut*; the feature's own `/runcastle:feature` session resolves *what it should be*. Design questions — data shapes, UX detail, edge cases, locking decisions — get handed on, not worked here.
|
|
287
289
|
- **Never launch a session or terminal** for a feature you created. The card in the rail is the handoff.
|
|
288
290
|
- **Never touch another feature's docs.** `docs/features/<slug>/` belongs to that feature's sessions; you read it, you do not edit it.
|
|
289
291
|
- **Never advance a phase, emit tickets into an existing feature, or do ticket surgery.** Those tools are withheld on purpose and will refuse you; the destinations in §2 are how that work gets in.
|
|
@@ -28,10 +28,10 @@ short list of findings the human can route.
|
|
|
28
28
|
|
|
29
29
|
## What to do with the findings
|
|
30
30
|
|
|
31
|
-
Route **every** finding through §2 — a new feature, a
|
|
32
|
-
|
|
31
|
+
Route **every** finding through §2 — a new feature, a small change, a change to
|
|
32
|
+
a feature in flight, more rounds, or nothing. Say which, and why.
|
|
33
33
|
|
|
34
|
-
The ones the human wants now become features
|
|
34
|
+
The ones the human wants now become features on the spot. The
|
|
35
35
|
ones they don't want **are stored nowhere.** A sweep is idempotent: the codebase
|
|
36
36
|
still has the problem, and re-running the sweep regenerates the finding verbatim.
|
|
37
37
|
Storing a derivable list buys nothing and costs a graveyard. There is no
|
|
@@ -43,5 +43,5 @@ sweep finding is regenerable by definition.
|
|
|
43
43
|
|
|
44
44
|
You **report**; you do not fix. Not the dead code, not the drifted doc, not the
|
|
45
45
|
stale ADR. The value of noticing is fully captured by saying so; acting on it is
|
|
46
|
-
how this session quietly becomes a project editor. A fix rides a feature,
|
|
47
|
-
|
|
46
|
+
how this session quietly becomes a project editor. A fix rides a feature, or
|
|
47
|
+
promotion at merge — never this conversation.
|