@caddis/cli 0.4.52 → 0.4.54

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.
Files changed (111) hide show
  1. package/bundles/antigravity-plugin/CADDIS-GLOSSARY.md +1 -0
  2. package/bundles/antigravity-plugin/guard_agy.py +184 -0
  3. package/bundles/antigravity-plugin/plugin.json +1 -1
  4. package/bundles/antigravity-plugin/repo_freshness.py +132 -5
  5. package/bundles/antigravity-plugin/scripts/caddis_budget.py +283 -0
  6. package/bundles/antigravity-plugin/scripts/caddis_checkout_guard.py +227 -0
  7. package/bundles/antigravity-plugin/scripts/caddis_docs_pr.py +284 -0
  8. package/bundles/antigravity-plugin/scripts/caddis_exit.py +2 -0
  9. package/bundles/antigravity-plugin/scripts/caddis_fleet.py +439 -0
  10. package/bundles/antigravity-plugin/scripts/caddis_frontmatter.py +1 -0
  11. package/bundles/antigravity-plugin/scripts/caddis_gate.py +255 -195
  12. package/bundles/antigravity-plugin/scripts/caddis_glossary.py +3 -3
  13. package/bundles/antigravity-plugin/scripts/caddis_governor.py +48 -4
  14. package/bundles/antigravity-plugin/scripts/caddis_inventory.py +38 -0
  15. package/bundles/antigravity-plugin/scripts/caddis_lanes.py +411 -127
  16. package/bundles/antigravity-plugin/scripts/caddis_lineage_publish.py +458 -0
  17. package/bundles/antigravity-plugin/scripts/caddis_merge_chain.py +237 -0
  18. package/bundles/antigravity-plugin/scripts/caddis_notify.py +125 -0
  19. package/bundles/antigravity-plugin/scripts/caddis_prod_check.py +380 -0
  20. package/bundles/antigravity-plugin/scripts/caddis_redact.py +99 -0
  21. package/bundles/antigravity-plugin/scripts/caddis_relay_git.py +2 -2
  22. package/bundles/antigravity-plugin/scripts/caddis_review.py +1309 -0
  23. package/bundles/antigravity-plugin/scripts/caddis_roadmap.py +2109 -0
  24. package/bundles/antigravity-plugin/scripts/caddis_roadmap_page.py +676 -0
  25. package/bundles/antigravity-plugin/scripts/caddis_roadmap_run.py +2605 -0
  26. package/bundles/antigravity-plugin/scripts/caddis_routing.py +7 -6
  27. package/bundles/antigravity-plugin/scripts/caddis_rows.py +476 -0
  28. package/bundles/antigravity-plugin/scripts/caddis_spawn.py +8 -9
  29. package/bundles/antigravity-plugin/scripts/caddis_spend.py +415 -0
  30. package/bundles/antigravity-plugin/scripts/caddis_tidy.py +357 -20
  31. package/bundles/antigravity-plugin/scripts/caddis_todo.py +55 -0
  32. package/bundles/antigravity-plugin/scripts/caddis_workstreams.py +178 -19
  33. package/bundles/antigravity-plugin/scripts/caddis_worktree_close.py +349 -0
  34. package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +0 -56
  35. package/bundles/antigravity-plugin/scripts/claudster_doctor.py +1 -1
  36. package/bundles/antigravity-plugin/scripts/enforcement_inventory.py +0 -1
  37. package/bundles/antigravity-plugin/scripts/oss_review.py +2 -2
  38. package/bundles/antigravity-plugin/scripts/roadmap-recheck.ps1 +89 -0
  39. package/bundles/antigravity-plugin/scripts/roadmap-run.ps1 +88 -0
  40. package/bundles/antigravity-plugin/scripts/setup_project_ai.py +43 -1
  41. package/bundles/antigravity-plugin/session_end_agy.py +3 -3
  42. package/bundles/antigravity-plugin/skills/_registry.md +4 -6
  43. package/bundles/antigravity-plugin/skills/best-practices/agents/best-practices-referencer.md +1 -1
  44. package/bundles/antigravity-plugin/skills/best-practices/agents/codebase-context-builder.md +1 -1
  45. package/bundles/antigravity-plugin/skills/best-practices/agents/task-intent-analyzer.md +1 -1
  46. package/bundles/antigravity-plugin/skills/catchup/SKILL.md +11 -0
  47. package/bundles/antigravity-plugin/skills/cloud-phases/SKILL.md +1 -1
  48. package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +5 -2
  49. package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +35 -83
  50. package/bundles/antigravity-plugin/skills/fleet-close/SKILL.md +167 -0
  51. package/bundles/antigravity-plugin/skills/fleet-open/SKILL.md +110 -0
  52. package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +2 -1
  53. package/bundles/antigravity-plugin/skills/handoff/SKILL.md +177 -48
  54. package/bundles/antigravity-plugin/skills/implement/SKILL.md +87 -147
  55. package/bundles/antigravity-plugin/skills/migrate-dir/SKILL.md +4 -3
  56. package/bundles/antigravity-plugin/skills/mmr/SKILL.md +5 -2
  57. package/bundles/antigravity-plugin/skills/office-documents-official/SKILL.md +24 -0
  58. package/bundles/antigravity-plugin/skills/park/SKILL.md +0 -1
  59. package/bundles/antigravity-plugin/skills/pr-merge/SKILL.md +28 -20
  60. package/bundles/antigravity-plugin/skills/prd/SKILL.md +2 -10
  61. package/bundles/antigravity-plugin/skills/refactoring/SKILL.md +2 -1
  62. package/bundles/antigravity-plugin/skills/review-pr/SKILL.md +1 -1
  63. package/bundles/antigravity-plugin/skills/roadmap/SKILL.md +260 -0
  64. package/bundles/antigravity-plugin/skills/roadmap/assets/plan-resume-prompt.md +77 -0
  65. package/bundles/antigravity-plugin/skills/roadmap/assets/render-check.template.mjs +68 -0
  66. package/bundles/antigravity-plugin/skills/roadmap/assets/review-protocol.md +78 -0
  67. package/bundles/antigravity-plugin/skills/roadmap/assets/roadmap.template.md +32 -0
  68. package/bundles/antigravity-plugin/skills/roadmap/assets/value-check.template.py +161 -0
  69. package/bundles/antigravity-plugin/skills/ship/SKILL.md +16 -16
  70. package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +15 -5
  71. package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +36 -16
  72. package/bundles/antigravity-plugin/skills/spawn-session/SKILL.md +4 -8
  73. package/bundles/antigravity-plugin/warm_start_agy.py +1 -3
  74. package/bundles/antigravity-plugin-extras/plugin.json +1 -1
  75. package/bundles/antigravity-plugin-extras/skills/_registry.md +1 -2
  76. package/bundles/antigravity-plugin-extras/skills/agent-orchestration/SKILL.md +5 -5
  77. package/bundles/antigravity-plugin-extras/skills/cross-review/SKILL.md +5 -2
  78. package/bundles/antigravity-plugin-extras/skills/runner-move/SKILL.md +214 -0
  79. package/bundles/codex/.codex/skills/coding/refactoring/SKILL.md +2 -1
  80. package/bundles/codex/.codex/skills/devops/gh-cli/SKILL.md +2 -1
  81. package/bundles/codex/.codex/skills/docs/office-documents-official/SKILL.md +24 -0
  82. package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md +1 -1
  83. package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md +1 -1
  84. package/bundles/codex/.codex/skills/workflow/best-practices/agents/task-intent-analyzer.md +1 -1
  85. package/bundles/codex/.codex/skills/workflow/roadmap/SKILL.md +260 -0
  86. package/bundles/codex/.codex/skills/workflow/roadmap/assets/plan-resume-prompt.md +77 -0
  87. package/bundles/codex/.codex/skills/workflow/roadmap/assets/render-check.template.mjs +68 -0
  88. package/bundles/codex/.codex/skills/workflow/roadmap/assets/review-protocol.md +78 -0
  89. package/bundles/codex/.codex/skills/workflow/roadmap/assets/roadmap.template.md +32 -0
  90. package/bundles/codex/.codex/skills/workflow/roadmap/assets/value-check.template.py +161 -0
  91. package/bundles/codex/AGENTS.md +5 -4
  92. package/bundles/manifest.json +3 -3
  93. package/package.json +1 -1
  94. package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +0 -233
  95. package/bundles/antigravity-plugin/skills/advisory-hub/reference/context-template.md +0 -214
  96. package/bundles/antigravity-plugin/skills/advisory-hub/reference/hub-handbook.md +0 -233
  97. package/bundles/antigravity-plugin/skills/advisory-hub/reference/report-contract.md +0 -94
  98. package/bundles/antigravity-plugin/skills/advisory-hub/reference/succession.md +0 -118
  99. package/bundles/antigravity-plugin/skills/resume/SKILL.md +0 -6
  100. package/bundles/antigravity-plugin/skills/review/SKILL.md +0 -6
  101. package/bundles/antigravity-plugin/skills/spawn-hub/SKILL.md +0 -341
  102. package/bundles/antigravity-plugin/skills/statusline/SKILL.md +0 -6
  103. package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +0 -143
  104. package/bundles/antigravity-plugin-extras/skills/data-lineage/SKILL.md +0 -158
  105. package/bundles/antigravity-plugin-extras/skills/data-lineage/scripts/convert_doc_to_confluence.py +0 -1430
  106. package/bundles/antigravity-plugin-extras/skills/golden-plan/SKILL.md +0 -586
  107. package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +0 -233
  108. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/context-template.md +0 -214
  109. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/hub-handbook.md +0 -233
  110. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/report-contract.md +0 -94
  111. package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/succession.md +0 -118
@@ -13,9 +13,8 @@ The plan file is the **durable spine of the harness** — it must let any future
13
13
  agent, on any tool) resume with zero re-discovery. Optimize for that.
14
14
 
15
15
  ## Headless mode
16
- When the invocation contains the marker **`HEADLESS RUN RULES`**, **or `CADDIS_HEADLESS` /
17
- `DOCKET_PLAN` / `DOCKET_BRANCH` is set in the environment** (the caddis OSS launchers export
18
- `CADDIS_HEADLESS` on claude's `-p`/`--print`; the docket runner sets the others) — a non-interactive
16
+ When the invocation contains the marker **`HEADLESS RUN RULES`**, **or `CADDIS_HEADLESS` is set in
17
+ the environment** (the caddis OSS launchers export it on claude's `-p`/`--print`) — a non-interactive
19
18
  caller spawned this session and no human is present, so the scope-check questions and any interview are
20
19
  **suspended and forbidden**. This mode exists for one-line ideas: the card may be a short title with **no
21
20
  description**, and there may be **no codebase, PROJECT-FACTS, or prior PRD** to read. That is expected —
@@ -39,13 +38,6 @@ Absolute rules in this mode (they override everything below):
39
38
  a bullet under `## Constraints & decisions` — never a question to the user.
40
39
  - **Honor the caller's output path and slug** (falling back to `.caddis/plans/<feature-slug>.md`);
41
40
  set `feature: <slug>` in the frontmatter to that slug.
42
- - **Also emit a visual companion** — a self-contained, scannable HTML page at `<artifact_dir>/<slug>.html`
43
- presenting the plan visually (a goal card, phases as cards with their steps, an affected-files table,
44
- and a risks/decisions section). **Use inline `<style>` ONLY** — the visual is rendered in a *sandboxed*
45
- iframe with no script execution, so a `<script>`/CDN (e.g. the Tailwind browser CDN) would NOT run and
46
- the page would appear unstyled. Keep it fully portable — no external `<script>`/`<link>`, no local
47
- asset files, no `/`-rooted paths. This is the visual the human reviews in docket alongside the markdown.
48
- Write it after the `.md`; the runner finds it by the matching `<slug>.html` name.
49
41
  - **Always write the plan file, then end with exactly one fenced `json` highlights block** — nothing
50
42
  after it:
51
43
  ```json
@@ -62,8 +54,14 @@ points), read it first. It's a free, token-zero project fingerprint that anchors
62
54
  exists instead of assumed. If the work fits comfortably in one session, say so and offer to just do it
63
55
  instead of planning. Only produce a plan for genuinely multi-phase work.
64
56
 
57
+ **Check upstream first when the plan builds on Claude Code behaviour** (hooks, headless `claude -p`, permission
58
+ modes, subagents, worktrees, plugins and skills, Remote Control, background sessions). Read
59
+ `.caddis/kb/claude-code-upstream-watch.md` if the repo has it, and the latest Claude Code changelog for that area
60
+ (Improvements, Bug fixes, In development). Do not plan a fix or a workaround for something Claude Code has already
61
+ changed, fixed or announced; cite the release in **Constraints & decisions** instead.
62
+
65
63
  ### Evidence gate — do not write plan content while a BLOCKER is unresolved
66
- Absorbed from `golden-plan`, whose strongest idea this is, and the direct counter to the failure
64
+ This is the direct counter to the failure
67
65
  mode that makes a plan dangerous: **you write the spec, so you cannot see its gaps.** A phase built
68
66
  on guessed field names or an imagined API is confidently wrong, passes every completeness check,
69
67
  and only fails at the exit gate — or worse, doesn't.
@@ -164,9 +162,11 @@ of that role and write its Lane line as follows:
164
162
  - `sonnet`: `claude — /model sonnet`
165
163
  - `claude`: `claude — this session`
166
164
  - `codex`: codex — `codex exec --ephemeral --sandbox workspace-write "HEADLESS RUN RULES. Read <plan path> and its Constraints. Implement Phase N only in the current checkout. Do not switch or create branches, commit, push, or edit files outside this phase. Run its exit gate and report the literal result."`
167
- - `agy`: agy — `agy --mode accept-edits --dangerously-skip-permissions --add-dir . --print-timeout 20m --output-format text -p "HEADLESS RUN RULES. Read <plan path> and its Constraints. Implement Phase N only in the current checkout. Do not switch or create branches, commit, push, or edit files outside this phase. Run its exit gate and report the literal result."`
165
+ - `agy`: agy — `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spend.py" run --caller lane-pN -- agy --mode accept-edits --dangerously-skip-permissions --add-dir . --print-timeout 20m --output-format json -p "HEADLESS RUN RULES. Read <plan path> and its Constraints. Implement Phase N only in the current checkout. Do not switch or create branches, commit, push, or edit files outside this phase. Run its exit gate and report the literal result."`
168
166
 
169
- Replace `<plan path>` and `N` with this plan's path and phase number. If the routing command fails
167
+ Replace `<plan path>` and `N` (also in `lane-pN`) with this plan's path and phase number. The agy line
168
+ always starts with `caddis_spend.py run`: it books the call against the global EUR spend cap, and
169
+ `caddis_gate.py lane-check` refuses a bare `agy` Lane line. If the routing command fails
170
170
  or exits 3, use `claude — this session` and state the reason in that phase.
171
171
 
172
172
  #### A phase may take a no-escalation lane only if its exit gate would fail on a spec error
@@ -186,14 +186,9 @@ internal repo path into stakeholder-facing copy, and set a `live` status flag th
186
186
  framework's own "Soon" badge). `tsc` clean, 632/632 tests green, cross-review CLEAN, exit gate
187
187
  satisfied. A headless run following it literally would have committed both, entirely green.
188
188
 
189
- In an Advisory-Hub plan, treat your lane as **provisional**: the Hub writes each `phase-NN.prompt.md`
190
- before the phase runs, and that is the first time anyone but the spec's author reads it. Let that
191
- read confirm or downgrade the lane. It costs nothing — the prompt is being written anyway.
192
-
193
189
  ### Group phases into MILESTONES — only when the plan is big enough
194
190
  **Add milestones when the plan has ~8+ phases OR spans multiple sessions.** Below that, phases and a
195
- Tracker are enough; a three-phase feature gains nothing from ceremony. (Same sizing instinct as the
196
- Advisory-Hub test, deliberately — one threshold to remember, not two.)
191
+ Tracker are enough; a three-phase feature gains nothing from ceremony.
197
192
 
198
193
  A milestone is **a group of phases that ship together**. It answers "what lands when this is done?",
199
194
  which is the question a long plan otherwise leaves the executor guessing at.
@@ -211,9 +206,10 @@ resuming session can see at a glance which group it is in and what remains befor
211
206
  ### Flag high-risk phases (`risk:` — a marker, not a mechanism)
212
207
  Each phase may carry **`risk: normal|high`** (default `normal` — omit the line unless the phase is
213
208
  `high`), meaning only "this is a phase where a wrong answer is expensive" — security/authz, a
214
- correctness-critical algorithm, an ambiguous spec, or an irreversible change. It is **inert**: it
215
- selects no model, spawns no agents, and implies no fan-out — it exists so the executor can decide **at
216
- runtime** whether an extra cross-check is worth it. Do not emit orchestration, lane fan-out, or
209
+ correctness-critical algorithm, an ambiguous spec, or an irreversible change. It selects no model and
210
+ implies no fan-out. It has one effect: the roadmap/plan runner reviews a finished `risk: high` phase
211
+ twice (`caddis_review.py --plan --phase --runs 2`), gives it one fix session on blocking
212
+ findings, and stops `BLOCKED review` when findings remain. Roadmap mode reviews before it publishes the PR. Do not emit orchestration, lane fan-out, or
217
213
  `Workflow` scripts from this command; the runtime decision rules and the intent→model map live in one
218
214
  place, the `agent-orchestration` skill's *Multi-model fan-out* section.
219
215
 
@@ -275,7 +271,10 @@ yourself (relay + Tracker) before stopping — do not hand back "run `/caddis:ha
275
271
  Three rules: one attempt, one review.
276
272
  1. **Think before you send.** Before a task goes to any coder, write its edge cases and check the facts it depends on (one query or one file read).
277
273
  2. **Run it before review.** The coder runs the same checks as CI (name the exact commands in the task). Then run the change once on real data.
278
- 3. **Review once.** Use whatever reviewer is available. Stop at the first CLEAN. After two blocking reviews, ask the owner.
274
+ 3. **Review by tier.** Run `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" review-tier --range <base>...HEAD` (add `--plan <plan> --phase <N>` inside a plan; no `TIER:` line means tier 2).
275
+ Tier 0: gates only. Tier 1-small: your self-check only. Tier 1: one review by another vendor; stop at
276
+ the first CLEAN. Tier 2: two reviewers of two other vendors, in one round. Fix blocking findings only;
277
+ park the rest. Re-review only the fix diff, and only when the fix changed logic. After 3 rounds, ask the owner.
279
278
 
280
279
  - One phase at a time: read this plan → run the phase on its **Lane** → RED→GREEN→VERIFY→CROSS-REVIEW→
281
280
  COMMIT → update the **Tracker** row. The Tracker is the resume signal for every future session.
@@ -293,6 +292,10 @@ Three rules: one attempt, one review.
293
292
  normally; the halt stops anything being **built on top of it** before a human has looked. Blast
294
293
  radius stays one reviewable, revertable commit. Halting *beforehand* buys nothing: the phase has
295
294
  to be executed either way, and a well-specced high-risk phase is as executable as any other.
295
+ One exception: when the session prompt says the runner reviews `risk: high` phases (the
296
+ runner's `plan-resume-prompt.md` says so), the runner's review gate replaces this halt: the
297
+ session ends `STATUS: CONTINUE`, and the runner reviews the phase twice before anything builds
298
+ on it. A headless marker (`CADDIS_HEADLESS=1`) alone does not lift the halt.
296
299
  4. **A failed or blocked phase** — tests red, exit gate unmet, or the plan turned out wrong. Stop;
297
300
  do not build on it.
298
301
  - **A lane change is NOT a halt.** `/caddis:implement` spawns the assigned lane itself and verifies
@@ -366,66 +369,15 @@ done:
366
369
 
367
370
  If any phase relies on the implementer *reasoning out* a gap, close the gap in the plan now.
368
371
 
369
- ## Step 3b — Does this plan need an Advisory Hub? (ask once, here)
370
-
371
- The Advisory Hub is **opt-in per plan**, gated on a single file: `<plan-stem>-advisory-context.md`
372
- beside the plan. `/caddis:implement`, `/caddis:handoff` and `/caddis:validate-phase` all check for it;
373
- **no file → no behaviour change, ever.** But nothing has ever *asked* whether to create it, so the
374
- pattern only ever gets used by someone who already knows it exists. This step closes that gap.
375
-
376
- **Ask it here** — at the end of planning is the only moment the phase count, risk levels and session
377
- boundaries are all known.
378
-
379
- > **You MUST call `Skill(advisory-hub)` and read *"When it earns its keep"* before deciding.**
380
- > Do not decide from memory, and do not decide from any summary — including one in this file.
381
- > The test is stated in exactly one place on purpose: two copies of a rule drift on the first edit,
382
- > and the copy that used to live here had already drifted. It compressed the REQUIRED leg to the
383
- > phrase *"expensive-to-reverse"* and dropped the enumeration that defines it — which reads as
384
- > *"can I `git revert` this?"*, and under that reading a plan that publishes € figures to business
385
- > stakeholders scores "no stakes". That is the one leg that fires on reporting, analytics and
386
- > dashboard work, i.e. most of what this fleet builds. Load the skill.
387
-
388
- If the test passes, tell the user plainly what it costs and what it buys, and offer to scaffold the
389
- context doc from the `advisory-hub` skill's template. **Do not create it silently** — an opt-in
390
- pattern that switches itself on is no longer opt-in.
391
-
392
- **In headless mode, never offer and never create.** Headless forbids asking anything, so an "offer"
393
- is impossible there. Instead record the result as a line under `## Constraints & decisions` —
394
- *"Advisory Hub: test passed (N phases, <criteria>) — not scaffolded, headless run; create
395
- `<plan-stem>-advisory-context.md` to enable"* — so the decision reaches a human rather than being
396
- silently dropped or silently taken.
397
-
398
- If it does not pass, say nothing **to the user** — a three-phase feature should never hear about
399
- this. But **always record the determination in the plan, pass or fail**: one line under
400
- `## Constraints & decisions`, naming which REQUIRED trigger was or was not hit.
401
-
402
- > `Advisory Hub: not applicable — no REQUIRED trigger (not a migration / security change /
403
- > production data correctness / numbers published to stakeholders).`
404
-
405
- ### If the test FAILS but this repo already runs a Hub for another plan
406
-
407
- Check for an existing `*-advisory-context.md` in `.caddis/plans/` belonging to a **different** plan.
408
- If one exists, add a second line under `## Constraints & decisions`:
409
-
410
- > `Hub conventions: this repo runs Advisory Hub for <other-plan>. This plan does NOT — if it borrows
411
- > the phase-NN.prompt.md / .report.md / CONTINUE GATE conventions, the lightweight rule applies: the
412
- > session that files a report must not write the next prompt without an independent re-check.`
413
-
414
- **Why this line exists.** A repo with one Hub plan has its artefacts sitting there as the most recent
415
- example of "how we structure a multi-session plan here", and the next plan copies them by analogy.
416
- It inherits the file names and none of the safety, because the safety was never in the names.
417
- Measured once already: an implementing session filed its own batch report and then wrote the next
418
- batch's prompt in the same session, with nobody having looked in between. Nothing was wrong that
419
- time — and nothing checked either.
420
-
421
- This is the cheapest possible place to catch it: when the second plan is created, before any
422
- artefact-mimicry has happened. See *"Failing this test correctly does not mean no discipline"* in the
423
- `advisory-hub` skill for the rule itself. Do not restate the rule here — one home, or the copies
424
- drift.
425
-
426
- Silent to the human, auditable in the artifact. "Say nothing" once meant *leave no trace anywhere*,
427
- and a wrong negative was then invisible — no line in the plan, no line in the chat, nothing for
428
- anyone to challenge. A rule whose failures leave no artifact cannot be reviewed.
372
+ A `risk: high` phase gets two independent review runs: run by the roadmap/plan runner automatically (from caddis-next Phase 11), and by hand in an interactive `/caddis:implement` run (`caddis_review.py --plan <plan> --phase <n> --runs 2`, from Phase 10). Only a `blocking` finding fails that review (exit 1); `should-fix` and `nit` findings go on a follow-up list and do not stop the merge. A phase gets 3 completed review rounds (a run that did not complete uses none); the 4th ends with exit 5, "stop, the owner decides". The advisory hub is retired; do not plan a separate validation session.
373
+
374
+ ## Programme triggers
375
+
376
+ Small work that does not meet a trigger skips its block.
377
+
378
+ **Trigger: Always.** Add one open-work row for the plan in `.caddis/open-work.md`. Set its cells with `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_rows.py" set --file <open-work.md> --id <row id> --col Status=todo`, never with a regex edit.
379
+
380
+ **Trigger: The plan records a decision.** Record it with `/caddis:decide`.
429
381
 
430
382
  ## Step 4 — Report
431
383
  Output the plan path (`.caddis/plans/<feature-slug>.md`), the phase list (one line each, with each
@@ -0,0 +1,167 @@
1
+ ---
2
+ name: fleet-close
3
+ description: Close a fleet of sessions — every session writes its handoff and acks, then print one restart sheet for the owner
4
+ ---
5
+
6
+ # /caddis:fleet-close — close every session, collect acks, print the restart sheet
7
+
8
+ Use this when **several** sessions must stop together (a machine restart, a long break, a context
9
+ reset for the whole fleet). For one session, run `/caddis:handoff` instead. This session is the
10
+ **coordinator**: it asks every other session to write its own handoff, collects one ack from each,
11
+ writes its own handoff last, and prints a restart sheet. The owner starts each new session from that
12
+ sheet, and each new session runs `/caddis:fleet-open <role>`.
13
+
14
+ Every fleet rule (names, ack format, order, checks) lives in
15
+ `${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py`; this command only calls it. Run the steps in order.
16
+
17
+ **Safety rules for the whole command** (a wrong close loses another session's relay or tasks):
18
+ - Never write, edit or move another session's relay, tasks file or watcher files. Each session writes
19
+ its own; you only collect acks.
20
+ - Never stop, end or kill another session, and never tell one to exit. The owner closes terminals
21
+ after reading the sheet.
22
+ - Never wait with a foreground `sleep`. Every wait is a background timer (`run_in_background`).
23
+ - A session that does not ack is never guessed: its row says `no ack`, and the owner runs
24
+ `/caddis:handoff` in it by hand.
25
+
26
+ The ack format (one line in a fenced block, then the session's full resume prompt):
27
+
28
+ ```
29
+ FLEET-ACK name=<n> role=<r> machine=<m> folder=<abs> relay=<path> tasks=<path|none> mode=<new|keeps-running|restore-on:<machine>|nothing> owns-watchers=<yes|no> worktrees=<abs;abs|none>
30
+ ```
31
+
32
+ ## Step 1 — list the fleet
33
+
34
+ Run `ListAgents`. Your own name is in its header line (`This session is <name>`): you are the
35
+ coordinator. Candidates:
36
+ - every local interactive or background session, and every Remote Control session that is not
37
+ `offline`: each gets the close message in Step 3;
38
+ - every cloud session: it is listed as `keeps-running` and gets **no** message (it keeps running in
39
+ the cloud). In Step 4 you save its ack yourself:
40
+ `FLEET-ACK name=<n> role=<role-of n> machine=cloud folder=- relay=- tasks=none mode=keeps-running owns-watchers=no worktrees=none`,
41
+ then the prompt line `Cloud session: keeps running; nothing to restore.`;
42
+ - `offline` rows and your own row are not candidates.
43
+
44
+ For each candidate, and for yourself, get the role:
45
+ `python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" role-of <name>`. **Two sessions with the same role**
46
+ would get one start line and one new name, and one of them would be lost. So when roles repeat, keep the
47
+ role for the first name (sorted), and give each other one a distinct role `<role>-b`, `<role>-c`, ...; tell
48
+ that session its role in Step 3 (rule 5).
49
+
50
+ Print the candidate list (name, kind, machine, role) before you send anything. If there are no candidates,
51
+ say so, run `/caddis:handoff` for this session only, and **stop**.
52
+
53
+ ## Step 2 — make the fleet dir
54
+
55
+ The fleet dir is `.caddis/relay/fleet/<MMDD>-<HH>/` in this repo, at the coordinator's local time:
56
+
57
+ ```
58
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" new-name fleet
59
+ ```
60
+
61
+ prints `fleet-<MMDD>-<HH>`; the dir name is the `<MMDD>-<HH>` part. Create it. It is local and
62
+ gitignored (it holds machine paths). Use the same dir for every later step, even if the hour changes.
63
+
64
+ ## Step 3 — send the close message
65
+
66
+ Send each candidate (from Step 1) one `SendMessage`. The first line must be exactly:
67
+
68
+ ```
69
+ FLEET CLOSE from <coordinator>: write your handoff and ack.
70
+ ```
71
+
72
+ Then these close rules, in the message:
73
+ 1. Run `/caddis:handoff` for **your own** relay only. Never touch another session's files. Skip its
74
+ Step 7 (the `Push this note for another machine?` question): the restart sheet carries your prompt,
75
+ and a question nobody answers would stop you before you ack.
76
+ 2. In a shared checkout (its `AGENTS.md` says `Shared checkout: yes`, or `git status` shows changes you
77
+ did not make), skip the steps the handoff checklist skips there.
78
+ 3. If you run watchers: copy each watcher script to `.caddis/relay/<your name>-files/watchers/`, and fill
79
+ the relay's `## Watchers` section (per watcher: script path, exact start command, stop condition,
80
+ the action after the stop).
81
+ 4. Your resume prompt must load your tasks file, greet peers with `<role> is now <your new name>`, and,
82
+ in a shared checkout, say: "read code facts from origin/main; a worktree needs its own fresh
83
+ dependencies".
84
+ 5. Reply to `<coordinator>` with this block (one line, every field filled), then your full resume prompt:
85
+ ```
86
+ FLEET-ACK name=<n> role=<r> machine=<m> folder=<abs> relay=<path> tasks=<path|none> mode=<new|keeps-running|restore-on:<machine>|nothing> owns-watchers=<yes|no> worktrees=<abs;abs|none>
87
+ ```
88
+ Use `name=<your current name>` exactly as `ListAgents` shows it, and `role=<role>` as given in this
89
+ message (a role that repeats in the fleet gets `<role>-b`, ...). `mode=new` if your work continues
90
+ in a new session; `mode=nothing` if it needs no new session (for example a finished read-only review).
91
+ 6. Remote sessions (another machine): also put your open task rows inline after the prompt, as a table
92
+ with exactly this header line (other headers are not read):
93
+ ```
94
+ | Old # | Status | Subject |
95
+ |---|---|---|
96
+ ```
97
+ and say whether your machine restarts (`mode=restore-on:<machine>`) or not (`mode=keeps-running`).
98
+ 7. Do not exit or stop after the ack; the owner closes sessions.
99
+
100
+ ## Step 4 — collect acks (first wait: 10 minutes)
101
+
102
+ Start a background timer, never a foreground wait:
103
+
104
+ ```
105
+ sleep 600
106
+ ```
107
+
108
+ with `run_in_background`. Each ack arrives as a cross-session message. For each one:
109
+ 1. Write the message text (from the `FLEET-ACK` line to the end) to a temp file in your scratchpad.
110
+ 2. Save it:
111
+ ```
112
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" ack add --dir <fleet dir> --text-file <temp file>
113
+ ```
114
+ 3. Exit 0 → acked. An error names the missing or bad field: send that session **one** reply that
115
+ quotes the error and asks for a corrected ack. Do not fix the ack yourself.
116
+ 4. The ack's `name=` must be the name of the candidate that sent it, and its `role=` the role you gave
117
+ it. If not, send **one** reply asking for a corrected ack (a wrong name makes a phantom row and marks
118
+ the real session `no ack`). A second ack from the same session replaces the first (`ack add` saves by
119
+ name).
120
+
121
+ Also save the cloud-session acks from Step 1 here, the same way.
122
+
123
+ ## Step 5 — remind once (second wait: 20 minutes)
124
+
125
+ When the 10-minute timer ends, send each silent candidate **one** reminder:
126
+ `FLEET CLOSE reminder from <coordinator>: your ack is still missing.` Start a 20-minute background
127
+ timer (`sleep 1200`, `run_in_background`) and keep saving acks as in Step 4. When it ends (or every
128
+ candidate has acked), stop waiting. Each session still silent is a `no ack` row (Step 7).
129
+
130
+ **A late ack is never dropped.** Until Step 8 ends, keep saving every ack that arrives, as in Step 4, and
131
+ remove that session from the `--no-ack` list before the next `write`.
132
+
133
+ ## Step 6 — your own handoff and ack
134
+
135
+ Run `/caddis:handoff` for this session (the coordinator's own relay). Then write your own ack (the
136
+ `FLEET-ACK` block with your fields and your resume prompt) to a temp file and save it with
137
+ `ack add`, as in Step 4. The coordinator's ack is never skipped. Then record this session's presence
138
+ (your session id is printed at session start as `[caddis] this session's id: <id>`; never guess one):
139
+
140
+ ```
141
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" whoami --session-id <id> --name <your name> --root .
142
+ ```
143
+
144
+ ## Step 7 — write and check the sheet
145
+
146
+ ```
147
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" write --dir <fleet dir> --coordinator <your name> --no-ack <name> [--no-ack <name> ...]
148
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" check --dir <fleet dir>
149
+ ```
150
+
151
+ Pass `--no-ack <name>` once for each silent session from Step 5, **on every `write`**, and leave it out
152
+ when every session acked (a placeholder would become a fake row) (the no-ack rows are not
153
+ saved between runs). `write` saves `roster.md` and `restart-sheet.md` in the fleet dir.
154
+
155
+ - `check` exit 0 → go to Step 8.
156
+ - `check` exit 1 → send each named session **one** message that quotes its error and asks for a
157
+ corrected ack. Start one 5-minute background timer (`sleep 300`, `run_in_background`) and save the
158
+ corrected acks that arrive. Then run `write` (same `--no-ack` flags) and `check` once more. Errors that
159
+ remain go at the end of `restart-sheet.md` under a heading `## Needs the owner:`, one line each,
160
+ quoted exactly.
161
+ - `write` or `check` exit 3 (no acks, or a file it cannot read) → do not print a sheet. Report the exact
162
+ error, list every ack file in `<fleet dir>/acks/`, and **stop**: the owner decides.
163
+
164
+ ## Step 8 — final reply
165
+
166
+ Reply with the whole text of `restart-sheet.md`, then its absolute path, and nothing else. The
167
+ restart closes this session too, so the sheet must be on screen and on disk.
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: fleet-open
3
+ description: Restore one role from the fleet restart sheet in a new session — name check, relay, tasks, peer greeting, watchers
4
+ ---
5
+
6
+ # /caddis:fleet-open — restore a role from the restart sheet
7
+
8
+ A fleet close (`/caddis:fleet-close`) wrote a restart sheet: one row per role, with the folder to
9
+ start `claude` in, a start line that names the new session, and the role's resume prompt. You are the new session
10
+ for one of those rows. This command restores that role in one go.
11
+
12
+ The argument is the role: `$ARGUMENTS`. If it is empty, list the roles of the newest sheet (Step 1)
13
+ and ask which one — do not guess.
14
+
15
+ Every fleet rule lives in `${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py`; this command only calls it.
16
+ Run each step in order. A step that says "stop" ends the command: print why, and nothing else.
17
+
18
+ ## Step 1 — find the newest restart sheet that holds the role
19
+
20
+ ```
21
+ ls -d .caddis/relay/fleet/*/restart-sheet.md
22
+ ```
23
+
24
+ The folders are named `<MMDD>-<HH>` (the coordinator's local time). Go from the newest folder to the
25
+ oldest and take the first `restart-sheet.md` with a section `### <n>. <role>`. Read the
26
+ `roster.md` beside it too: its row for the role gives the relay, the tasks file, the folder and the
27
+ mode.
28
+
29
+ - No sheet holds the role → say `No restart sheet holds <role>.` and **stop**.
30
+ - The sheet row says `no new session` (mode `keeps-running`, `nothing` or `no ack`) → say so, quote
31
+ the row's section, and **stop**. A `no ack` row needs `/caddis:handoff` run by hand in the old
32
+ session first.
33
+
34
+ ## Step 2 — check this session's name before loading anything
35
+
36
+ Run `ListAgents`. Its header line says `This session is <name>`; that is your name. The sheet row's
37
+ Start line already names the session: `claude --name <expected> "/caddis:fleet-open <role>"`, where
38
+ `<expected>` is `new_name` of the role at the sheet's hour.
39
+
40
+ - `<name>` equals `<expected>` → go on.
41
+ - Otherwise it must at least be a name of this role:
42
+ ```
43
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" role-of <name>
44
+ ```
45
+ prints `<role>` (the name is `<role>-<MMDD>-<HH>`) → go on, and note the name differs from the sheet.
46
+ - Anything else → tell the owner to run `/rename <expected>` and then `/caddis:fleet-open <role>`
47
+ again, and **stop**. A session cannot rename itself, and a role loaded under the wrong name is a
48
+ role its peers never reach.
49
+
50
+ Nothing is read into this session (no relay, no tasks, no watcher) until this step passes.
51
+
52
+ ## Step 3 — read the relay and run its resume prompt
53
+
54
+ Read the role's relay (the roster's Relay column, `.caddis/relay/<old name>.md`), then follow the
55
+ resume prompt in the sheet section — the fenced block under `### <n>. <role>`. It is the same prompt
56
+ the old session wrote; do what it says, in order.
57
+
58
+ Load the open tasks: every row of the tasks file (roster Tasks file column,
59
+ `.caddis/relay/<old name>.tasks.md`, table `| Old # | Status | Subject |`) becomes one `TaskCreate`
60
+ with the Subject as its subject. A row with Status `in_progress` then gets
61
+ `TaskUpdate` to `in_progress`. A remote role's rows are inline on the sheet under
62
+ `Tasks (inline, remote session):` — load those the same way. Tasks file `none` → 0 tasks.
63
+ Count the tasks you created; Step 6 reports it.
64
+
65
+ ## Step 4 — greet the live local peers
66
+
67
+ From the `ListAgents` output of Step 2 (run it again if more than a few minutes passed), take each
68
+ live local session whose role is in the roster (`caddis_fleet.py role-of <their name>`), other than
69
+ your own role. When a role has several names, address the newest:
70
+
71
+ ```
72
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" newest <their role> --names-file <file with one name per line>
73
+ ```
74
+
75
+ Send each one message, exactly: `<role> is now <name>` (your role, your name). Skip offline sessions
76
+ and cloud sessions. Keep the list of names you greeted for Step 6.
77
+
78
+ ## Step 5 — restart the watchers
79
+
80
+ Read the relay's `## Watchers` section. For each entry:
81
+
82
+ 1. Print the entry as written (script path, start command, stop condition, after-action).
83
+ 2. Check the script path exists (handoff copied it to `.caddis/relay/<old name>-files/watchers/`)
84
+ and that the stop condition and the after-action are both in the relay. If either is missing,
85
+ do not start it: report it as `watcher not started: <reason>` in Step 6.
86
+ 3. Start it with its exact start command through Bash with `run_in_background`. Never a foreground
87
+ `sleep` or loop.
88
+
89
+ No `## Watchers` section → 0 watchers.
90
+
91
+ ## Step 6 — record the name and report
92
+
93
+ Record this session's presence (your session id is printed at session start as
94
+ `[caddis] this session's id: <id>`; never guess one):
95
+
96
+ ```
97
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_fleet.py" whoami --session-id <id> --name <name> --root .
98
+ ```
99
+
100
+ Then print one line, and any `watcher not started:` lines under it:
101
+
102
+ ```
103
+ [FLEET-OPEN] <role> restored: <n> tasks, <k> watchers, peers greeted: <names>
104
+ ```
105
+
106
+ ## Rules
107
+
108
+ - One role per session. To restore another role, start another session from the sheet.
109
+ - Never `claude --resume` the old session: the sheet exists so every role starts fresh.
110
+ - Never edit the restart sheet or the roster; they are the record of the close.
@@ -167,7 +167,8 @@ gh alias set review 'pr list --search "review-requested:@me"'
167
167
 
168
168
  ```bash
169
169
  gh issue develop 42 --branch fix/issue-42
170
- git add . && git commit -m "fix: resolve login bug" && git push -u origin HEAD
170
+ git add src/auth/login.py tests/test_login.py # named files only, never `git add .`
171
+ git commit -m "fix: resolve login bug" && git push -u origin HEAD
171
172
  gh pr create --title "fix: resolve login bug" --body "Closes #42"
172
173
  gh pr checks --watch
173
174
  gh pr merge --squash --delete-branch