@caddis/cli 0.2.4 → 0.2.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/README.md +11 -0
- package/bundles/antigravity-plugin/agents/claude-md-curator.md +7 -4
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/skills/_registry.md +7 -0
- package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +183 -0
- package/bundles/antigravity-plugin/skills/advisory-hub/reference/context-template.md +214 -0
- package/bundles/antigravity-plugin/skills/advisory-hub/reference/hub-handbook.md +233 -0
- package/bundles/antigravity-plugin/skills/advisory-hub/reference/report-contract.md +94 -0
- package/bundles/antigravity-plugin/skills/advisory-hub/reference/succession.md +118 -0
- package/bundles/antigravity-plugin/skills/brainstorming/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/code-review/SKILL.md +7 -0
- package/bundles/antigravity-plugin/skills/context-curator/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +71 -14
- package/bundles/antigravity-plugin/skills/dashboard-perf-sweep/SKILL.md +18 -18
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +164 -9
- package/bundles/antigravity-plugin/skills/gate-preflight/SKILL.md +34 -0
- package/bundles/antigravity-plugin/skills/gate-review/SKILL.md +36 -0
- package/bundles/antigravity-plugin/skills/golden-plan/SKILL.md +22 -13
- package/bundles/antigravity-plugin/skills/handoff/SKILL.md +78 -0
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +182 -3
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/SKILL.md +57 -1
- package/bundles/antigravity-plugin/skills/park/SKILL.md +126 -0
- package/bundles/antigravity-plugin/skills/prd/SKILL.md +4 -2
- package/bundles/antigravity-plugin/skills/preflight/SKILL.md +5 -0
- package/bundles/antigravity-plugin/skills/spawn-hub/SKILL.md +320 -0
- package/bundles/antigravity-plugin/skills/spawn-session/SKILL.md +213 -0
- package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +112 -0
- package/bundles/antigravity-plugin/skills/writing-plans/SKILL.md +7 -4
- package/bundles/antigravity-plugin/warm_start_agy.py +28 -2
- package/bundles/antigravity-plugin-extras/plugin.json +1 -1
- package/bundles/antigravity-plugin-extras/skills/agent-orchestration/SKILL.md +9 -9
- package/bundles/antigravity-plugin-extras/skills/cross-review/SKILL.md +56 -6
- package/bundles/antigravity-plugin-extras/skills/requesting-code-review/SKILL.md +1 -1
- package/bundles/antigravity-plugin-extras/skills/schema-migration/SKILL.md +2 -2
- package/bundles/antigravity-plugin-extras/skills/state-tracking/SKILL.md +4 -4
- package/bundles/manifest.json +3 -3
- package/dist/cli.js +65 -6
- package/package.json +1 -1
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spawn-hub
|
|
3
|
+
description: Hand the Advisory Hub role to a fresh session — run the mechanical audit, then generate the succession prompt with a context self-check the new Hub must pass
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /caddis:spawn-hub — hand the Hub role to a fresh session
|
|
7
|
+
|
|
8
|
+
> **The Hub is a ROLE, not a conversation.** It outlives any one session and hands to the next through
|
|
9
|
+
> **files** — never chat history. This command is the handoff. Until it existed, every Hub was spawned
|
|
10
|
+
> by a hand-written prompt, which meant the pattern only worked for someone who already knew what to
|
|
11
|
+
> put in one.
|
|
12
|
+
|
|
13
|
+
**This command does not start the new session.** It leaves the outgoing Hub's context in a state a
|
|
14
|
+
fresh one can pick up, then prints the prompt to paste. The human runs it.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## When to spawn — do not guess, and do not wait for the crash
|
|
19
|
+
|
|
20
|
+
**The default seam is a MILESTONE BOUNDARY.** A milestone ends with a deploy, a smoke test and a
|
|
21
|
+
handoff; that is already the plan's own `/handoff` → `/clear` point. Carrying a Hub across a deploy is
|
|
22
|
+
where staleness bites — the outgoing Hub's picture of prod is exactly what just changed.
|
|
23
|
+
|
|
24
|
+
**Spawn at the next milestone boundary if ANY of these is true:**
|
|
25
|
+
|
|
26
|
+
- the current Hub has validated **≥5 phases**
|
|
27
|
+
- it has executed **≥2 deploys**
|
|
28
|
+
- it has done substantial work *outside* phase validation (fleet changes, tooling, plugin releases) —
|
|
29
|
+
that consumes context far faster than validation does
|
|
30
|
+
- **its own context is filling** — this one overrides the milestone seam entirely
|
|
31
|
+
|
|
32
|
+
> **Observed, not theorised:** on the reference project, Hubs 1–4 each ended because context ran out,
|
|
33
|
+
> never because a milestone did. A Hub covers roughly **4–6 phases / 1–2 milestones** before that
|
|
34
|
+
> happens. So treat the milestone as the *planned* seam and context as the *real* constraint, and run
|
|
35
|
+
> this command at whichever arrives first.
|
|
36
|
+
|
|
37
|
+
**Do not wait until context is nearly gone.** Step 1 is a real audit that needs room to run, and the
|
|
38
|
+
outgoing Hub is the only session that can do it. A handoff written from a nearly-full context is the
|
|
39
|
+
one most likely to omit exactly what the next Hub needs.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Step 0 — resolve the context file, and refuse cleanly when you cannot
|
|
44
|
+
|
|
45
|
+
Use `$ARGUMENTS` if given. Otherwise look for `<plan-stem>-advisory-context.md` beside every plan in
|
|
46
|
+
`.caddis/plans/`.
|
|
47
|
+
|
|
48
|
+
- **None found → STOP and say so.** This project is not running an Advisory Hub, so there is no role to
|
|
49
|
+
hand over. Do not scaffold one here: that decision belongs to `/caddis:feature-plan` Step 3b, at
|
|
50
|
+
planning time, when the phase count and risk are actually known.
|
|
51
|
+
- **More than one → ask which**, listing them with each plan's status. Never guess: handing over the
|
|
52
|
+
wrong plan's Hub is worse than not handing over.
|
|
53
|
+
- **Already handed over?** Check the succession table. If the last row has no end reason, this is a
|
|
54
|
+
fresh handover. **If the last row is already closed and a new one opened, STOP** — a previous run
|
|
55
|
+
completed and re-running would double-close it and re-open a duplicate. Re-running this command is
|
|
56
|
+
safe only when the tree still shows the outgoing Hub as current.
|
|
57
|
+
|
|
58
|
+
## Step 1 — the mechanical audit (MANDATORY, and it is not a formality)
|
|
59
|
+
|
|
60
|
+
**Do not ask yourself "are there gaps?" — assume there are, and find them mechanically.** The outgoing
|
|
61
|
+
Hub's instinct is always *"yes, this is ready"*, because it is judging against its own memory of the
|
|
62
|
+
session rather than against the document. **That instinct is wrong by default.** On the reference
|
|
63
|
+
project the first answer to "can we hand off" was yes; a mechanical audit then found **seven gaps** —
|
|
64
|
+
including that mutation testing, by then the single highest-value technique in use, was written down
|
|
65
|
+
nowhere a fresh Hub would find it.
|
|
66
|
+
|
|
67
|
+
1. **List every technique, decision and correction actually used this session** — from your own
|
|
68
|
+
actions, not from the context doc. Re-ran a cross-review with a second provider after a timeout?
|
|
69
|
+
Mutation-tested a seam? Fixed something directly rather than only flagging it? Corrected a gate
|
|
70
|
+
rather than the code? Each is a candidate line item.
|
|
71
|
+
2. **For each, check whether the advisory context already tells a fresh Hub to do the same thing.**
|
|
72
|
+
Not "does the word appear" — whether *the instruction* is there.
|
|
73
|
+
3. **Land every real gap as a durable rule** in the advisory context — its *Standing gotchas*,
|
|
74
|
+
*Hub techniques*, *Environment facts* or *Succession* section. **Cite sections BY NAME, never by
|
|
75
|
+
number:** numbers drift between a project's hand-grown file and the shipped template, and this
|
|
76
|
+
command previously named §7/§9/§13, which matched one project and no template.
|
|
77
|
+
**A correction that lives only in a verdict file dies with the session that wrote it.**
|
|
78
|
+
4. **Audit in BOTH directions.** As well as what is missing, look for what is now **obsolete** — a
|
|
79
|
+
gotcha since promoted to `AGENTS.md`, or one a committed test now enforces, compresses to a line
|
|
80
|
+
and a pointer. The context doc is append-only by design and every incoming Hub must read it end to
|
|
81
|
+
end; without a diet it becomes the thing it exists to prevent.
|
|
82
|
+
|
|
83
|
+
> **The caveat that will burn you: a literal-string grep over prose throws false MISSINGs.** The same
|
|
84
|
+
> audit that found seven real gaps also produced three false negatives — content that *was* present,
|
|
85
|
+
> phrased differently. `0 matches` means "not this exact string", not "not covered". Search by concept
|
|
86
|
+
> and read the surrounding paragraph.
|
|
87
|
+
|
|
88
|
+
## Step 2 — close the record
|
|
89
|
+
|
|
90
|
+
- Every validated phase has a **verdict file**, and its `verdict:` frontmatter is one of
|
|
91
|
+
`accept` / `accept-with-correction` / `reject`.
|
|
92
|
+
- Every **ACCEPT-WITH-CORRECTION** either has its corrections landed, or they are in the carried-open
|
|
93
|
+
list. An unlanded correction that nobody is tracking is the worst thing to hand over.
|
|
94
|
+
- The plan's **Tracker rows** match reality. Check them; they get silently skipped, and on the
|
|
95
|
+
reference project four completed rows were reverted to "not started" by a stray staged edit and only
|
|
96
|
+
caught two milestones later.
|
|
97
|
+
- `git status` is clean, or every uncommitted change is deliberate and named in the handoff.
|
|
98
|
+
|
|
99
|
+
## Step 3 — update the succession table
|
|
100
|
+
|
|
101
|
+
In the advisory context's succession section: close the outgoing Hub's row (what it covered, why it
|
|
102
|
+
ended) and open the next one.
|
|
103
|
+
|
|
104
|
+
**Then update the carried-open list — APPEND AND CLOSE, never rewrite.**
|
|
105
|
+
|
|
106
|
+
Each Hub used to *rewrite* this list, which means an open item can vanish between generations with
|
|
107
|
+
nothing to show it ever existed. Nobody notices, because the only evidence was the list itself.
|
|
108
|
+
|
|
109
|
+
So: every item gets a stable id and is **never deleted**.
|
|
110
|
+
|
|
111
|
+
```markdown
|
|
112
|
+
- **[C7] Break-glass is DB-engine-dependent** — raised Hub 4. <what, and enough to act on>
|
|
113
|
+
→ **CLOSED by Hub 6**: fixed in `abc1234`, verified on prod.
|
|
114
|
+
- **[C9] `files.py` sibling-prefix traversal** — raised Hub 4. <detail>
|
|
115
|
+
→ still open.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Closing an item requires **saying who closed it and why** — a line, not a deletion. That makes a
|
|
119
|
+
disappearance impossible: an item either carries a close reason or it is still open, and both are
|
|
120
|
+
visible. It also lets a later Hub see that something was closed *wrongly*, which a deletion hides
|
|
121
|
+
forever.
|
|
122
|
+
|
|
123
|
+
**ARTIFACT CONSERVATION — the same check, for the files you wrote.** The ledger check above catches
|
|
124
|
+
an id that *disappeared*. Nothing caught a file that *exists and is invisible*, which is the inverted
|
|
125
|
+
failure and just as silent:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" hub-artifacts --reports .caddis/advisory-hub-reports
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Exit 1 means you wrote a phase prompt the successor will never learn about. It will find no prompt,
|
|
132
|
+
write a fresh one, and lose whatever reasoning yours carried — plausibly and completely. Name every
|
|
133
|
+
prompt you authored in this spawn doc before handing over. (Degrades open: no handover yet, or no
|
|
134
|
+
script, means proceed.)
|
|
135
|
+
|
|
136
|
+
**CONSERVATION CHECK — mechanical, and it fails the spawn.** Every id in the predecessor's ledger
|
|
137
|
+
must appear in the outgoing one as either still-open or closed-with-a-reason. An id that is simply
|
|
138
|
+
absent is a silent loss: **stop and restore it before handing over.** Do not ask "did anything
|
|
139
|
+
vanish?" — diff the ids. That is the same design move as the handoff audit, for the same reason.
|
|
140
|
+
|
|
141
|
+
**One ledger, one home.** A verdict may *raise* an item, but it is not raised until it has an id in
|
|
142
|
+
the context doc's ledger, in the same commit. Two uncoordinated lists drift, and the drift is
|
|
143
|
+
invisible.
|
|
144
|
+
|
|
145
|
+
Carry the whole list forward, closed items included. It is short, and its history is the cheapest
|
|
146
|
+
audit trail this pattern has.
|
|
147
|
+
|
|
148
|
+
## Step 4 — generate the prompt
|
|
149
|
+
|
|
150
|
+
**"From the files, not from memory" is an instruction you cannot follow by intending to. Run the
|
|
151
|
+
generator:**
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spawn.py" preflight
|
|
155
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_inventory.py" --with-tests
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`preflight` **refuses on a dirty tree**: the incoming Hub pulls, so uncommitted work is invisible to
|
|
159
|
+
it. Commit first, or name every uncommitted file in the handover.
|
|
160
|
+
(falls back to `scripts/caddis_inventory.py` in a source checkout; skip the step if absent — it
|
|
161
|
+
degrades open like every other machine step here.)
|
|
162
|
+
|
|
163
|
+
Paste its output into the prompt as a **Repository inventory** section, verbatim. It enumerates
|
|
164
|
+
plans, PRDs, prompts, handoffs, KB notes, the parking-lot backlog, open comms, every script and its
|
|
165
|
+
purpose, and any generated artefact committed before its generator last changed. `--with-tests`
|
|
166
|
+
runs the suite instead of reporting a remembered number — one handover claimed 20 tests when there
|
|
167
|
+
were 19, and the incoming Hub found the discrepancy before anyone else.
|
|
168
|
+
|
|
169
|
+
**Why a generator and not care.** Nine corrective round trips were needed to bring one Hub to a
|
|
170
|
+
usable state, and the user caught six of the nine: no reports listed, no documents, no KB notes, no
|
|
171
|
+
scripts, planned work absent, and confusion over which of two prompts actually existed. Every one of
|
|
172
|
+
those is a directory listing. They were missed because an outgoing agent recalls *what it did*
|
|
173
|
+
rather than enumerating *what exists* — and the incoming Hub cannot know what it was not told.
|
|
174
|
+
|
|
175
|
+
Then write the judgement half yourself. It must contain:
|
|
176
|
+
|
|
177
|
+
1. **The role and the one rule** — re-derive, do not trust; validate, do not implement.
|
|
178
|
+
2. **The read order**: advisory context (all of it, especially the succession section and the
|
|
179
|
+
carried-open list) → the plan's milestones / execution protocol / tracker → the project's
|
|
180
|
+
measurement rules → the most recent 2–3 verdicts.
|
|
181
|
+
3. **A context self-check the new Hub must answer BEFORE touching a phase**, from the files, including:
|
|
182
|
+
- re-derive **one anchor number live** (not quote it)
|
|
183
|
+
- name the decisions that are **accepted but reversible**, and what would reverse them
|
|
184
|
+
- state **where the next deploy gate is and how it determined that** (read the milestone table —
|
|
185
|
+
never state a deploy boundary from memory)
|
|
186
|
+
- name **one thing a green automated check does NOT prove**, with the example that taught it
|
|
187
|
+
- **verify the tree independently** — `git fetch`, count divergence, and `git status`/diff any dirty
|
|
188
|
+
file before treating it as authority
|
|
189
|
+
4. **At least one question whose naive answer is WRONG.** This is the load-bearing part. A Hub that
|
|
190
|
+
only skimmed must fail *visibly* rather than silently.
|
|
191
|
+
|
|
192
|
+
> **USE A DIFFERENT TRAP THAN THE PREVIOUS HUB'S.** Check the last spawn prompt in
|
|
193
|
+
> `.caddis/advisory-hub-reports/` and pick a fresh one. A trap reused across generations stops
|
|
194
|
+
> testing comprehension and starts testing whether the new Hub read the old prompt — which it can
|
|
195
|
+
> pass while understanding nothing. Rotate it, and prefer a fact the *most recent* milestone
|
|
196
|
+
> established, since that is what the incoming Hub is least likely to have absorbed.
|
|
197
|
+
|
|
198
|
+
> **DERIVE the questions from what CHANGED — do not choose them.** An agent that picks its own
|
|
199
|
+
> exam picks what it remembers, which is the thing under test. Spread them: the oldest settled
|
|
200
|
+
> decisions catch a Hub that read only the recent sections; the most recent changes catch one
|
|
201
|
+
> that read only the summary; **a SUPERSEDED fact is the highest-signal question of all**,
|
|
202
|
+
> because the obvious answer is the stale one.
|
|
203
|
+
|
|
204
|
+
> **Every question must be answerable from a committed file. Prove it, do not assume it:**
|
|
205
|
+
>
|
|
206
|
+
> ```
|
|
207
|
+
> python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spawn.py" verify-question \
|
|
208
|
+
> --answer-in .caddis/kb/some-note.md --needle "the phrase that answers it"
|
|
209
|
+
> ```
|
|
210
|
+
>
|
|
211
|
+
> A question whose answer is not written down tests memory — the thing this mechanism exists to
|
|
212
|
+
> replace. It is not a harder question; it is the old failure wearing an exam's clothes.
|
|
213
|
+
|
|
214
|
+
> **Store NO answer key.** Re-derive each answer from the repo when the incoming Hub replies. A
|
|
215
|
+
> stored key freezes your belief at capture time: if you were wrong, the key is wrong and the
|
|
216
|
+
> check certifies the error. Re-deriving validates the DOCUMENT as well as the reader — which is
|
|
217
|
+
> exactly what `.caddis/parking-lot/done/004-*` found missing, where a Hub passed a
|
|
218
|
+
> thirteen-question check on a handover carrying four factual errors.
|
|
219
|
+
|
|
220
|
+
Good traps share a shape: a figure that looks obvious, a correct value that differs, and a reason
|
|
221
|
+
rooted in the data rather than in the code. On the reference project, one generation asked why the
|
|
222
|
+
funnel's `offered` is not `SUM(OfferedInd)` (naive 3,814, correct 4,783 — the raw flags do not
|
|
223
|
+
nest); the next asked why an abandonment rate moved from 7.6% to 5.9% (the old figure was not a
|
|
224
|
+
rate at all — 72% of its numerator sat outside its own denominator).
|
|
225
|
+
5. **What is carried open — INLINE THE OPEN ITEMS VERBATIM, do not link to them.** (Closed items stay
|
|
226
|
+
in the context file for the audit trail; they do not belong in the prompt.) A pointer costs a file hop at
|
|
227
|
+
exactly the moment the new Hub has least context, and a carried-open item that is not read is
|
|
228
|
+
indistinguishable from one that was closed.
|
|
229
|
+
6. **The next work**, with its batching (`Session: continue` = batchable, `fresh` = not) and any
|
|
230
|
+
standing constraint the new Hub would not otherwise know — a stalled upstream load, a deploy hold,
|
|
231
|
+
an environment that is mid-change.
|
|
232
|
+
7. **The standing authorisations**: deploys are user-authorised **every time**; a previous yes does not
|
|
233
|
+
carry.
|
|
234
|
+
8. **What comes after this, and why the order matters.** Not only what is done and what is carried
|
|
235
|
+
open — **what this is building towards**, for the next two or three phases. A Hub that does not
|
|
236
|
+
know what comes next can design the current phase in a way that blocks it, and it will never find
|
|
237
|
+
out, because nothing it can read says so. One live handover omitted a planned model comparison
|
|
238
|
+
entirely; the user caught it. A section covering only the past reads complete and is not.
|
|
239
|
+
9. **The deliverable.** Name the thing this workstream must eventually produce, and the step that
|
|
240
|
+
produces it. One handover carried every phase faithfully and never mentioned the report that was
|
|
241
|
+
the whole point of the exercise. The user caught that too.
|
|
242
|
+
10. **A standing instruction to maintain the tracker.** Put this in the prompt, in these words or
|
|
243
|
+
close to them:
|
|
244
|
+
|
|
245
|
+
> **Maintain the tracker.** Your in-session task list does not survive this session.
|
|
246
|
+
> `.caddis/relay.md` does. Mirror your working list into it as you go, and include its current
|
|
247
|
+
> state in every progress report. Anything not written there is lost.
|
|
248
|
+
|
|
249
|
+
The succession table records **who held the role**; `relay.md` records **where the work is**. The
|
|
250
|
+
table is written when a Hub *ends*, so nothing covers the hours while a Hub is *working* — which
|
|
251
|
+
is the whole period this mechanism exists to protect. A real spawned Hub read `relay.md`,
|
|
252
|
+
answered a thirteen-question context check correctly, found four genuine defects in its
|
|
253
|
+
handover, **and created no tracker at all**, because nothing asked it to.
|
|
254
|
+
|
|
255
|
+
Note for the incoming Hub: `relay.md` is gitignored and machine-local. Anything a successor **on
|
|
256
|
+
another machine** will need belongs in the advisory context or the next spawn prompt, not only
|
|
257
|
+
there.
|
|
258
|
+
11. **`.caddis/kb/environment-map.md`, INLINE AND VERBATIM.** Hosts, which login works, where other
|
|
259
|
+
repositories actually live. It is short, it is the first thing an incoming Hub needs, and it is
|
|
260
|
+
the category most often missing — one incoming Hub searched the filesystem for a repository that
|
|
261
|
+
lived in Gitea, and the user had to stop it. A pointer is not enough here: this is exactly the
|
|
262
|
+
file a cold session does not know to open.
|
|
263
|
+
|
|
264
|
+
**Write it to `.caddis/advisory-hub-reports/hub-NN.spawn.md`** (frontmatter `type: hub-spawn`,
|
|
265
|
+
`hub: NN`), then print it. Until this file existed, every succession prompt lived and died in chat —
|
|
266
|
+
which made two of this command's own instructions unimplementable: "rotate the trap by checking the
|
|
267
|
+
last spawn prompt" had nothing to check, and the ledger conservation check below had nothing to diff
|
|
268
|
+
against.
|
|
269
|
+
|
|
270
|
+
Print the prompt in a fenced block, ready to paste. **Say plainly that it starts a NEW session** — a
|
|
271
|
+
Hub spawned inside the outgoing session's context inherits exactly the staleness this whole mechanism
|
|
272
|
+
exists to shed.
|
|
273
|
+
|
|
274
|
+
### Check the prompt before you hand it over
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" handover-check \
|
|
278
|
+
--doc .caddis/advisory-hub-reports/hub-NN.spawn.md
|
|
279
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spawn.py" check \
|
|
280
|
+
--doc .caddis/advisory-hub-reports/hub-NN.spawn.md
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The second one blocks on a **commit hash or test count given as current state**. Both go stale
|
|
284
|
+
within the hour — measured twice — and the fix is never a fresher number, it is to write the command
|
|
285
|
+
that produces it. A historical hash is only noted, not blocked: those are durable, and flagging them
|
|
286
|
+
is how a check earns a reputation for crying wolf.
|
|
287
|
+
|
|
288
|
+
It fails when the prompt names a file that does not exist. **Validate the DOCUMENT, not just the
|
|
289
|
+
reader.** The context self-check in Step 4 proves the incoming Hub read carefully; it proves nothing
|
|
290
|
+
about whether what it read was true. One incoming Hub passed a thirteen-question check on a handover
|
|
291
|
+
containing four factual errors — it found them *despite* the check, not because of it.
|
|
292
|
+
|
|
293
|
+
### The single-writer rule — state it in the prompt
|
|
294
|
+
|
|
295
|
+
**The outgoing Hub stops writing to the repository the moment the succession prompt is issued.** Say
|
|
296
|
+
so in the prompt itself, so both sides know which one owns the tree.
|
|
297
|
+
|
|
298
|
+
This is not tidiness. Two sessions committed to one repository concurrently and the incoming Hub's
|
|
299
|
+
work landed inside the outgoing Hub's commit. Only committed objects are safe from another session's
|
|
300
|
+
checkout; a shared working tree is process-shared state, not session-private.
|
|
301
|
+
|
|
302
|
+
## Step 5 — report
|
|
303
|
+
|
|
304
|
+
Output: the audit result (candidates → gaps → where each landed), the succession table update, what is
|
|
305
|
+
carried open, and the prompt. Then stop.
|
|
306
|
+
|
|
307
|
+
**Do not begin validating the next phase.** You are the outgoing Hub; that work belongs to the session
|
|
308
|
+
about to be spawned, and doing it here re-creates the context problem you just solved.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Anti-patterns
|
|
313
|
+
|
|
314
|
+
- **Spawning without the audit.** The prompt will look fine and quietly omit the session's best
|
|
315
|
+
technique.
|
|
316
|
+
- **Writing the prompt from memory.** Build it from the files; memory is what is being discarded.
|
|
317
|
+
- **Handing over a stale carried-open list.** An item that was closed hours ago and still appears
|
|
318
|
+
teaches the new Hub to distrust the whole list.
|
|
319
|
+
- **Waiting until context is nearly gone.** The audit needs room. Spawn early and cheaply.
|
|
320
|
+
- **Continuing to work after generating the prompt.** Two Hubs holding the role is worse than one.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spawn-session
|
|
3
|
+
description: Hand the WORK to a fresh session — generate the handover from the repo, then validate the successor by re-deriving its answers
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /caddis:spawn-session — generate the handover, then validate the successor
|
|
7
|
+
|
|
8
|
+
Use this when a session is long enough that its own recall has become the risk. It replaces
|
|
9
|
+
`/caddis:handoff` for that case: `/handoff` writes down what you remember, and **what you remember
|
|
10
|
+
is the failure mode.**
|
|
11
|
+
|
|
12
|
+
**Sibling, not duplicate, of `/caddis:spawn-hub`.** `spawn-hub` hands over a validation ROLE;
|
|
13
|
+
this hands over the WORK. Both run on `scripts/caddis_spawn.py`, so a fix to the machinery lands in
|
|
14
|
+
both.
|
|
15
|
+
|
|
16
|
+
## The failure this exists to catch
|
|
17
|
+
|
|
18
|
+
A long session does not forget. **It recalls superseded facts fluently.** Measured in one session:
|
|
19
|
+
|
|
20
|
+
- two throughput figures the agent had **itself withdrawn**, re-quoted days later
|
|
21
|
+
- *"E8 is blocked on F1"* repeated for three days without a re-test
|
|
22
|
+
- a commit hash written into a handover that went stale **within the hour**
|
|
23
|
+
|
|
24
|
+
Each was stated with conviction and was wrong. Asking that agent what it knows cannot find any of
|
|
25
|
+
it.
|
|
26
|
+
|
|
27
|
+
The successor is what to pick up first: **$ARGUMENTS** (if empty, derive it from the parking-lot
|
|
28
|
+
and the active plan).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Round 0 — validate your OWN handover. No relay trip.
|
|
33
|
+
|
|
34
|
+
**Do this before writing the prompt.** It is the cheapest round and the one this whole command is
|
|
35
|
+
about: in the manual run, a child caught a stale hash the parent could have caught alone — a wasted
|
|
36
|
+
relay trip, and the relay trip is the expensive part.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spawn.py" preflight
|
|
40
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spawn.py" fingerprint --with-tests
|
|
41
|
+
```
|
|
42
|
+
(falls back to `scripts/caddis_spawn.py` in a source checkout.)
|
|
43
|
+
|
|
44
|
+
`preflight` **refuses on a dirty tree** — the successor pulls, so uncommitted work is invisible to
|
|
45
|
+
it and it will either redo that work or build on a state that does not exist. Commit first.
|
|
46
|
+
|
|
47
|
+
### Capture from the repo, never from recall
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_inventory.py" --with-tests
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Then add the four things the inventory cannot derive:
|
|
54
|
+
|
|
55
|
+
| Capture | Why |
|
|
56
|
+
|---|---|
|
|
57
|
+
| **Open parking-lot count** | The integrity check. A successor that revives 13 of 15 has silently dropped two, and nothing else would show it. |
|
|
58
|
+
| **WITHDRAWN and SUPERSEDED facts, as an explicit list** | Highest-value content, easiest to lose. Two withdrawn figures were re-quoted by their own author. |
|
|
59
|
+
| **Anything learned this session that lives in no file** | A screenshot of the consuming UI changed a task's priority. It existed only in the chat. |
|
|
60
|
+
| **State verified, not asserted** — run the tests, the gate, `git status` | One handover said "1,066 tests"; it was 1,090 an hour later. |
|
|
61
|
+
|
|
62
|
+
**Nothing may be written from recall.** Every number comes from a command run during this capture,
|
|
63
|
+
or from a file quoted by path.
|
|
64
|
+
|
|
65
|
+
### Then check what you wrote
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spawn.py" check --doc .caddis/spawn-session/<id>-prompt.md
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It **blocks** on a commit hash or test count given as current state, and on any path that does not
|
|
72
|
+
exist. It only **notes** a historical hash — those are durable, and flagging them was how the first
|
|
73
|
+
version produced seven findings on one document and taught the reader to skim.
|
|
74
|
+
|
|
75
|
+
**A claim that cannot be re-derived does not go in the handover.**
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Round 1 — the questions. One relay trip.
|
|
80
|
+
|
|
81
|
+
**Up to six. Derived from what changed, never chosen.** An agent that picks its own exam picks what
|
|
82
|
+
it remembers, which is the thing under test.
|
|
83
|
+
|
|
84
|
+
| Slot | Source | Catches |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| 1–2 | the **oldest** settled decisions | a successor that read only the recent sections |
|
|
87
|
+
| 3–4 | what changed **most recently** | one that read only the summary |
|
|
88
|
+
| 5 | a fact that was **SUPERSEDED** | the highest-signal question — the obvious answer is the stale one |
|
|
89
|
+
| 6 | a live **hazard or cost** | forces a consequence, not a fact |
|
|
90
|
+
|
|
91
|
+
**At least one question's obvious answer must be WRONG.** In the manual run the discriminator was
|
|
92
|
+
*"which model serves chat?"* — the answer had changed **twice**, and a successor naming only the
|
|
93
|
+
most recent replacement had not read the history.
|
|
94
|
+
|
|
95
|
+
**Every question must be answerable from a committed file. Prove it:**
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spawn.py" verify-question \
|
|
99
|
+
--answer-in .caddis/kb/some-note.md --needle "the phrase that answers it"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
A question whose answer is not written down tests memory — the thing being replaced. It is not a
|
|
103
|
+
harder question; it is the old failure wearing an exam's clothes.
|
|
104
|
+
|
|
105
|
+
### Store NO answer key
|
|
106
|
+
|
|
107
|
+
Do not write `<id>-key.md`. Two reasons, and the second is the one that matters:
|
|
108
|
+
|
|
109
|
+
1. The child can read it. Any exclusion rule is one path-glob away from failing.
|
|
110
|
+
2. **A stored key freezes your belief at capture time.** If you were wrong, the key is wrong, and
|
|
111
|
+
the check certifies the error.
|
|
112
|
+
|
|
113
|
+
**Re-derive each answer from the repo at validation time instead.** That validates the DOCUMENT and
|
|
114
|
+
the READER at once — which is exactly what `.caddis/parking-lot/done/004-*` said was missing, where
|
|
115
|
+
a successor passed a thirteen-question check on a handover containing four factual errors.
|
|
116
|
+
|
|
117
|
+
### What the child sends back
|
|
118
|
+
|
|
119
|
+
Three lines, carried by the user:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
SPAWN <id> | head <sha> | <n> tests | answers in .caddis/spawn-session/<id>-answers.md
|
|
123
|
+
Q1-Q6 answered with citations. <n> commands run. <n> facts I could not find in a file.
|
|
124
|
+
<one line: the single most important thing I believe about the current state>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The fingerprint lets you detect a stale or mismatched paste **before grading anything**.
|
|
128
|
+
|
|
129
|
+
**The third line is the real test.** A successor that understood the work states the current state
|
|
130
|
+
in one sentence. One that merely parsed the files produces a generic line, and that is visible
|
|
131
|
+
immediately.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## The verdict — three, not two
|
|
136
|
+
|
|
137
|
+
| Verdict | Condition | You write |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| **PASS** | every answer correct, citations check out | a short go-ahead naming the first task |
|
|
140
|
+
| **ACCEPT WITH CORRECTIONS** | broadly right; one or two facts stale or a citation wrong | the corrections, each with the file that proves it |
|
|
141
|
+
| **REJECT** | a settled decision misremembered, a withdrawn figure quoted, or a hazard misunderstood | an instruction to re-read named sections and re-answer. **Do not let it start work** |
|
|
142
|
+
|
|
143
|
+
**REJECT exists because a confidently wrong successor is more dangerous than a confused one.** In
|
|
144
|
+
this project the failure has never been *"I don't know"* — it has been a fluent wrong answer.
|
|
145
|
+
|
|
146
|
+
The vocabulary matches `/caddis:validate-phase` on purpose: same discipline, different object.
|
|
147
|
+
|
|
148
|
+
**Two REJECTs on one spawn means the HANDOVER is at fault, not the successor. Regenerate it** rather
|
|
149
|
+
than coaching the child through it.
|
|
150
|
+
|
|
151
|
+
### When the fault is yours, fix the class
|
|
152
|
+
|
|
153
|
+
If validation finds an error that came from your handover, **fix the source document in the same
|
|
154
|
+
turn** — and fix the class, not the instance. In the manual run a successor found a stale commit
|
|
155
|
+
hash; the fix was not a fresher hash, it was to **remove hashes from both documents** and write the
|
|
156
|
+
command instead. A handover patched per-instance goes stale again on the next commit.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Round 2 — the first task, scoped small, reviewed. One relay trip.
|
|
161
|
+
|
|
162
|
+
**Not more questions.** Two rounds of questions would be overkill; two rounds of the right things
|
|
163
|
+
are not.
|
|
164
|
+
|
|
165
|
+
**The questions validate RECALL. The first task validates JUDGEMENT** — and a successor can answer
|
|
166
|
+
six questions perfectly and still build the wrong thing. In the manual run round 2 caught a wrong
|
|
167
|
+
instruction from the parent, a wrong fact left by a predecessor, and a better design than the parent
|
|
168
|
+
had specified.
|
|
169
|
+
|
|
170
|
+
Round 1's verdict sets round 2's size:
|
|
171
|
+
|
|
172
|
+
| Round 1 | Round 2 task |
|
|
173
|
+
|---|---|
|
|
174
|
+
| PASS | a normal next item; review the outcome |
|
|
175
|
+
| ACCEPT WITH CORRECTIONS | a **small, reversible** item that writes nothing permanent; review closely |
|
|
176
|
+
| REJECT | no task — re-read and re-answer |
|
|
177
|
+
|
|
178
|
+
Review the result **by re-deriving it**, exactly as you reviewed the answers — not by reading the
|
|
179
|
+
successor's account of it.
|
|
180
|
+
|
|
181
|
+
### Then stop gating
|
|
182
|
+
|
|
183
|
+
**After round 2 passes, stop.** A successor that answered six questions with citations and then did
|
|
184
|
+
one real task correctly has demonstrated as much as a gate can. Continuing to review every item
|
|
185
|
+
turns you into a bottleneck and the successor into a relay — which is the cost this command exists
|
|
186
|
+
to remove.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Files — all three committed
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
.caddis/spawn-session/
|
|
194
|
+
<id>-prompt.md generated by you. The user pastes its "For the successor" section
|
|
195
|
+
<id>-answers.md written by the CHILD
|
|
196
|
+
<id>-verdict.md written by you, after re-deriving
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`<id>` is short, unique and sortable — `2026-08-16-a`. Two spawns on one day must not collide.
|
|
200
|
+
|
|
201
|
+
They are committed for the same reason the register is a file: **a validation that happened only in
|
|
202
|
+
chat cannot be reviewed**, and cannot be re-read when the next handover asks what good looked like.
|
|
203
|
+
|
|
204
|
+
## Refuse to
|
|
205
|
+
|
|
206
|
+
| Refusal | Why |
|
|
207
|
+
|---|---|
|
|
208
|
+
| Run with a dirty tree | uncommitted work is invisible to the successor |
|
|
209
|
+
| Write a commit hash or test count as current state | both went stale within the hour, twice |
|
|
210
|
+
| Write a question whose answer is not in a committed file | it would test memory |
|
|
211
|
+
| Store an answer key | it freezes your belief, and the child can read it |
|
|
212
|
+
| Grade your own answers | you validate; the child answers |
|
|
213
|
+
| Proceed when the open-item count is unknown | that count is the integrity check |
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: validate-phase
|
|
3
|
+
description: Advisory Hub phase validation — consume a phase report, RE-DERIVE its claims independently, and return ACCEPT / ACCEPT-WITH-CORRECTION / REJECT
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /caddis:validate-phase — the Advisory Hub validates a phase (never trusts it)
|
|
7
|
+
|
|
8
|
+
> **THE RULE: re-derive, do not trust.** A phase report is a self-assessment. Reading it and nodding
|
|
9
|
+
> makes you a rubber stamp, and a rubber stamp is worse than no check at all — it manufactures false
|
|
10
|
+
> confidence. Every step below exists to prevent exactly that. Skipping the re-derivation is the one way
|
|
11
|
+
> this command can fail at its actual job while still producing a plausible-looking verdict.
|
|
12
|
+
|
|
13
|
+
Full methodology, templates, and rationale: the **`advisory-hub`** skill. This command is the thin,
|
|
14
|
+
operational driver — run it after an implementing session (usually `/caddis:implement` in Advisory-Hub
|
|
15
|
+
mode) has filed a phase report.
|
|
16
|
+
|
|
17
|
+
## Step 0 — resolve inputs
|
|
18
|
+
|
|
19
|
+
Use **$ARGUMENTS** if given. Otherwise, find the newest `phase-*.report.md` file in
|
|
20
|
+
`.caddis/advisory-hub-reports/` that has no matching `phase-NN.verdict.md` sibling yet — that is the
|
|
21
|
+
one awaiting validation. Read its `PLAN:` and `ADVISORY CTX:` header fields and load both files.
|
|
22
|
+
|
|
23
|
+
**If no `<slug>-advisory-context.md` exists** for the plan named in the report: say so explicitly, offer
|
|
24
|
+
to bootstrap one from the `advisory-hub` skill's §A template, and continue in **degraded mode** — state in
|
|
25
|
+
the verdict exactly which checks (§4 locked-decision adjudication, §5 safety-rule re-check) were
|
|
26
|
+
unavailable without it. Never silently skip a check without recording that you skipped it.
|
|
27
|
+
|
|
28
|
+
**A degraded verdict must be machine-distinguishable, not just annotated in prose.** Write
|
|
29
|
+
`verdict: accept-degraded` (not plain `accept`) in the frontmatter. `/caddis:implement` reads only the
|
|
30
|
+
`verdict:` field to decide whether the next phase may start, so a degraded accept spelled `accept` is
|
|
31
|
+
indistinguishable from a full one — the gate cannot tell a partial check from a real one, which is
|
|
32
|
+
precisely the false confidence this whole pattern exists to prevent. Use `reject-degraded` likewise if
|
|
33
|
+
you are rejecting without the context doc.
|
|
34
|
+
|
|
35
|
+
## Step 1 — read the report once as a document
|
|
36
|
+
|
|
37
|
+
Before validating a single claim, check the report against itself: does CROSS-REVIEW agree with
|
|
38
|
+
DEVIATIONS? Does MODEL/LANE name a vendor's model that doesn't match the claimed lane? On the reference
|
|
39
|
+
run this pattern's design was validated against, two of three real findings in one phase came from
|
|
40
|
+
exactly this kind of internal contradiction — not from re-checking the code.
|
|
41
|
+
|
|
42
|
+
## Step 2 — re-derive (the Hub validation checklist)
|
|
43
|
+
|
|
44
|
+
Run every item in the `advisory-hub` skill's §D checklist yourself:
|
|
45
|
+
1. Re-derive every VALUE CHECK using the method advisory-context §3a names — actually run it, don't read
|
|
46
|
+
the reported result.
|
|
47
|
+
2. Re-run the exit gates, at minimum the fast ones (unit tests, lint, type-check).
|
|
48
|
+
3. `git log` / `git show --stat` the commits — do they match the phase's claimed touches? Anything
|
|
49
|
+
unexpected, especially tooling/config/CI that never appeared in DEVIATIONS?
|
|
50
|
+
4. Re-check every rule in advisory-context §5, or record `N/A — none declared`.
|
|
51
|
+
5. Flag any deviation that touches a §4 locked decision — this is step 3 below, not your call to make here.
|
|
52
|
+
6. Flag any surprise that contradicts the plan's `## Current state` — this is step 4 below.
|
|
53
|
+
7. If this milestone boundary ships to a real deployed environment, smoke-test it there, not in dev.
|
|
54
|
+
|
|
55
|
+
Also apply the `advisory-hub` skill's §E techniques where they fit — mutation-test any seam a new test
|
|
56
|
+
claims to prove, and if a cross-review provider timed out, try the other configured provider before
|
|
57
|
+
recording "inconclusive."
|
|
58
|
+
|
|
59
|
+
## Step 3 — adjudicate deviations
|
|
60
|
+
|
|
61
|
+
For each deviation the report lists: is it a locked decision in advisory-context §4? If so, this is a
|
|
62
|
+
**Hub decision, never the implementer's** — rule allowed / reverted / plan amended, and record the reason.
|
|
63
|
+
|
|
64
|
+
## Step 4 — plan drift
|
|
65
|
+
|
|
66
|
+
If the report's SURPRISES / CONTRADICTIONS section is non-empty: correct the plan file's
|
|
67
|
+
`## Current state` **now, in this step** — do not defer it to a note in the verdict. This is the Hub's
|
|
68
|
+
job and the step most likely to be skipped (`advisory-hub` skill §F).
|
|
69
|
+
|
|
70
|
+
## Step 5 — write the verdict
|
|
71
|
+
|
|
72
|
+
Write `.caddis/advisory-hub-reports/phase-NN.verdict.md` beside the report, using the `advisory-hub`
|
|
73
|
+
skill's §C template in full, including the mandatory **WHAT IS NOW STRUCTURAL** table.
|
|
74
|
+
|
|
75
|
+
> **Give it OKF frontmatter — `type` is REQUIRED and its absence is a defect.**
|
|
76
|
+
> Keep it flat (scalar `key: value` only; nested maps and lists defeat simple parsers):
|
|
77
|
+
> ```yaml
|
|
78
|
+
> ---
|
|
79
|
+
> type: phase-verdict
|
|
80
|
+
> plan: <path to the plan>
|
|
81
|
+
> phase: 12 # or 10-11 for a batched pair
|
|
82
|
+
> milestone: M4
|
|
83
|
+
> verdict: accept | accept-with-correction | reject
|
|
84
|
+
> ---
|
|
85
|
+
> ```
|
|
86
|
+
> `verdict` is the one field a tool can read to answer *"was this phase signed off"* without parsing prose — and a prose scraper gets that wrong quietly.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## Step 6 — push every correction into `advisory-context.md`
|
|
90
|
+
|
|
91
|
+
A correction that lives only in this verdict file dies with the session that reads it; a correction told
|
|
92
|
+
to the implementing session dies with that session too, which has already closed. Every correction in
|
|
93
|
+
"WHAT IS NOW STRUCTURAL" must actually be landed in the named section of `advisory-context.md` in this
|
|
94
|
+
step, not just described.
|
|
95
|
+
|
|
96
|
+
## Step 7 — update the reports-directory index
|
|
97
|
+
|
|
98
|
+
Add or update this phase's row in `.caddis/advisory-hub-reports/README.md` (Phase | Report | Verdict |
|
|
99
|
+
Outcome | Date).
|
|
100
|
+
|
|
101
|
+
## Rules
|
|
102
|
+
|
|
103
|
+
- **Fail closed.** A gate you could not re-run is `NOT RE-RUN`, never `PASS`. A claim you could not
|
|
104
|
+
reproduce is `UNVERIFIABLE`, never `AGREES: YES`.
|
|
105
|
+
- **Never accept a claim on the report's own word.** That is the one failure mode this command exists to
|
|
106
|
+
prevent.
|
|
107
|
+
- If a cross-review provider times out, try the other configured provider before recording
|
|
108
|
+
"inconclusive" — a single provider's outage is not grounds for skipping independent review.
|
|
109
|
+
- **The Hub is not exempt from its own contract.** If a fault traces back to advice the Hub itself gave
|
|
110
|
+
earlier, the verdict says so plainly rather than attributing it to the implementer.
|
|
111
|
+
- Read-only toward the implementing session — it has already closed. Corrections land in files
|
|
112
|
+
(`advisory-context.md`, the plan), never fed back to a session that no longer exists.
|