@caddis/cli 0.2.5 → 0.3.0

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 (54) hide show
  1. package/bundles/antigravity-plugin/agents/claude-md-curator.md +1 -1
  2. package/bundles/antigravity-plugin/caddis_statusline.py +803 -0
  3. package/bundles/antigravity-plugin/claude-md/folder-agents.md.tmpl +21 -0
  4. package/bundles/antigravity-plugin/guard_agy.py +23 -4
  5. package/bundles/antigravity-plugin/plugin.json +1 -1
  6. package/bundles/antigravity-plugin/scripts/caddis_gate.py +524 -0
  7. package/bundles/antigravity-plugin/scripts/caddis_inventory.py +369 -0
  8. package/bundles/antigravity-plugin/scripts/caddis_migrate_dir.py +270 -0
  9. package/bundles/antigravity-plugin/scripts/caddis_spawn.py +300 -0
  10. package/bundles/antigravity-plugin/scripts/caddis_statusline.py +803 -0
  11. package/bundles/antigravity-plugin/scripts/caddis_tidy.py +366 -0
  12. package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +924 -0
  13. package/bundles/antigravity-plugin/scripts/claude-deepseek.ps1 +4 -0
  14. package/bundles/antigravity-plugin/scripts/claude-deepseek.sh +3 -0
  15. package/bundles/antigravity-plugin/scripts/claude-glm.ps1 +4 -0
  16. package/bundles/antigravity-plugin/scripts/claude-glm.sh +3 -0
  17. package/bundles/antigravity-plugin/scripts/claude-oss.ps1 +64 -0
  18. package/bundles/antigravity-plugin/scripts/claude-oss.sh +60 -0
  19. package/bundles/antigravity-plugin/scripts/claudster_config.py +126 -0
  20. package/bundles/antigravity-plugin/scripts/claudster_doctor.py +356 -0
  21. package/bundles/antigravity-plugin/scripts/claudster_init.py +400 -0
  22. package/bundles/antigravity-plugin/scripts/claudster_migrate_rules.py +300 -0
  23. package/bundles/antigravity-plugin/scripts/dream_capture.py +249 -0
  24. package/bundles/antigravity-plugin/scripts/dream_memory.py +438 -0
  25. package/bundles/antigravity-plugin/scripts/enforcement_inventory.py +261 -0
  26. package/bundles/antigravity-plugin/scripts/hook_log.py +156 -0
  27. package/bundles/antigravity-plugin/scripts/oss_ask.py +98 -0
  28. package/bundles/antigravity-plugin/scripts/oss_model.py +166 -0
  29. package/bundles/antigravity-plugin/scripts/oss_review.py +718 -0
  30. package/bundles/antigravity-plugin/scripts/setup_project_ai.py +1429 -0
  31. package/bundles/antigravity-plugin/scripts/usage_review.py +1323 -0
  32. package/bundles/antigravity-plugin/session_end_agy.py +21 -2
  33. package/bundles/antigravity-plugin/skills/_registry.md +2 -0
  34. package/bundles/antigravity-plugin/skills/advisory-hub/reference/succession.md +22 -0
  35. package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +1 -1
  36. package/bundles/antigravity-plugin/skills/ship/SKILL.md +1 -1
  37. package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +1 -1
  38. package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +1 -1
  39. package/bundles/antigravity-plugin/skills/spawn-hub/SKILL.md +33 -0
  40. package/bundles/antigravity-plugin/skills/spawn-session/SKILL.md +213 -0
  41. package/bundles/antigravity-plugin/skills/statusline/SKILL.md +105 -0
  42. package/bundles/antigravity-plugin/skills/use-model/SKILL.md +15 -3
  43. package/bundles/antigravity-plugin/warm_start_agy.py +21 -2
  44. package/bundles/antigravity-plugin-extras/plugin.json +1 -1
  45. package/bundles/antigravity-plugin-extras/skills/architecture-design/SKILL.md +1 -1
  46. package/bundles/antigravity-plugin-extras/skills/caching-patterns/SKILL.md +1 -1
  47. package/bundles/antigravity-plugin-extras/skills/webapp-development/SKILL.md +1 -1
  48. package/bundles/manifest.json +3 -3
  49. package/dist/claude-deepseek.js +544 -0
  50. package/dist/claude-glm.js +544 -0
  51. package/dist/claude-oss.js +544 -0
  52. package/dist/cli.js +375 -46
  53. package/package.json +5 -2
  54. package/bundles/antigravity-plugin/statusline-command-agy.sh +0 -91
@@ -22,6 +22,25 @@ def _artifact_root(root: str) -> str:
22
22
  return os.path.join(str(root), ".caddis")
23
23
 
24
24
 
25
+
26
+ def _hook_note(feature, exc, root=None):
27
+ """Record a swallowed failure in the caddis hook ledger. Never raises, never prints.
28
+
29
+ agy hooks ship FLAT at the plugin root while hook_log.py ships under scripts/, and in
30
+ the source repo this file sits in claude-harness/agy/ with hook_log.py one level up in
31
+ claude-harness/scripts/. Try both layouts.
32
+ """
33
+ try:
34
+ _here = os.path.dirname(os.path.abspath(__file__))
35
+ for _cand in (os.path.join(_here, "scripts"),
36
+ os.path.join(os.path.dirname(_here), "scripts")):
37
+ if os.path.isdir(_cand) and _cand not in sys.path:
38
+ sys.path.insert(0, _cand)
39
+ import hook_log as _hl # noqa: E402
40
+ _hl.record(os.path.basename(__file__).replace(".py", ""), feature, exc, root)
41
+ except Exception:
42
+ pass
43
+
25
44
  def main() -> None:
26
45
  try:
27
46
  data = json.load(sys.stdin)
@@ -43,8 +62,8 @@ def main() -> None:
43
62
  }
44
63
  with open(os.path.join(art, "usage-log.jsonl"), "a", encoding="utf-8") as fh:
45
64
  fh.write(json.dumps(record) + "\n")
46
- except Exception:
47
- pass # never fail the turn
65
+ except Exception as _exc:
66
+ _hook_note("agy usage-log write", _exc) # never fail the turn
48
67
  # No stdout: agy interprets a Stop hook's stdout as a decision object.
49
68
 
50
69
 
@@ -85,6 +85,8 @@
85
85
  | Ship Merge | `ship-merge/` | Merge an already-green, already-reviewed PR behind an explicit deploy-confirm, monitor the deploy, validate prod, then clean up the branch — only on green. |
86
86
  | Ship Pr | `ship-pr/` | Open a reviewed PR for the current feature branch — rebase-safe push, PR create/update, monitor CI, STOP at green. Never merges, never deploys (that's /ship-merge). |
87
87
  | Spawn Hub | `spawn-hub/` | 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 |
88
+ | Spawn Session | `spawn-session/` | Hand the WORK to a fresh session — generate the handover from the repo, then validate the successor by re-deriving its answers |
89
+ | Statusline | `statusline/` | Install the caddis status line into Claude Code and agy — one renderer, once per machine |
88
90
  | Tdd | `tdd/` | Run a strict red-green-refactor TDD cycle for a unit of behavior |
89
91
  | Ui Brief | `ui-brief/` | Design-first UI brief — lock the aesthetic before writing any code |
90
92
  | Usage Review | `usage-review/` | Review local caddis usage over a window, surface prioritised recommendations, and apply config changes in one step |
@@ -92,5 +92,27 @@ the funnel's `offered` count, and why is it NOT `SUM(OfferedInd)`?"* — the nai
92
92
  the correct one 4,783, because the raw flags do not nest. A Hub that only skimmed **fails visibly
93
93
  instead of silently**, which is the entire point.
94
94
 
95
+ ### Four rules that make the self-check mean something
96
+
97
+ Shared with `/caddis:spawn-session`, which transfers the WORK where this transfers the ROLE. Both
98
+ run on `scripts/caddis_spawn.py`, so a fix lands in both.
99
+
100
+ 1. **DERIVE the questions from what CHANGED. Do not choose them.** An agent picking its own exam
101
+ picks what it remembers, which is the thing under test. Spread them: oldest settled decisions
102
+ catch a successor that read only the recent sections; the newest changes catch one that read only
103
+ the summary.
104
+ 2. **A SUPERSEDED fact is the highest-signal question there is**, because the obvious answer is the
105
+ stale one. The measured discriminator was *"which model serves chat?"* — the answer had changed
106
+ **twice**, and naming only the most recent replacement proved the history had not been read.
107
+ 3. **Every question must be answerable from a committed file**, verified with
108
+ `caddis_spawn.py verify-question`, not assumed. A question whose answer is not written down tests
109
+ memory — the thing this mechanism replaces.
110
+ 4. **Store NO answer key. Re-derive at validation time.** A stored key freezes the outgoing agent's
111
+ belief: if it was wrong, the key is wrong and the check certifies the error. Re-deriving validates
112
+ the DOCUMENT as well as the reader — and validating only the reader is precisely what failed, when
113
+ a Hub passed a thirteen-question check on a handover containing four factual errors.
114
+
115
+ **Six questions maximum.** Past six the successor writes an essay and the outgoing agent skims it.
116
+
95
117
  ---
96
118
 
@@ -295,6 +295,6 @@ async def create_record(record: RecordCreate, service: ...):
295
295
  | Resource | Path |
296
296
  |----------|------|
297
297
  | FastAPI instructions | `instructions/fastapi.instructions.md` |
298
- | SQL expert skill | `skills/coding/sql/SKILL.md` |
298
+ | SQL expert skill | the `sql` skill |
299
299
  | Python instructions | `instructions/python.instructions.md` |
300
300
  | Security instructions | `instructions/security.instructions.md` |
@@ -103,5 +103,5 @@ Release tag: <tag> → <sha> | n/a
103
103
 
104
104
  ## Skill reference
105
105
  Full procedures for the Gitea lane (CI monitoring, prod validation, queue triage, failure remediation)
106
- are in `skills/devops/deploy-local/SKILL.md`. For the GitHub lane, the `gh-cli` skill covers `gh run`
106
+ are in the `deploy-local` skill (ships in the optional `caddis-extras` plugin — enable it with `claude plugin enable caddis-extras`). For the GitHub lane, the `gh-cli` skill covers `gh run`
107
107
  usage. Load whichever matches the detected lane when a step needs more detail.
@@ -99,5 +99,5 @@ Cleanup: remote branch ✗ deleted / local ✗ deleted / backup ref droppe
99
99
  - Local-only lane: no PR, no merge — refuse and point at `/ship`.
100
100
 
101
101
  ## Skill reference
102
- Gitea deploy monitoring, prod validation, failure triage: `skills/devops/deploy-local/SKILL.md`.
102
+ Gitea deploy monitoring, prod validation, failure triage: the `deploy-local` skill (ships in the optional `caddis-extras` plugin — enable it with `claude plugin enable caddis-extras`).
103
103
  GitHub `gh pr merge` / `gh run` usage: the `gh-cli` skill.
@@ -98,5 +98,5 @@ human-confirmed door.
98
98
  - Local-only lane: refuse + point at `/ship`. On the default branch: stop + point at `/ship`.
99
99
 
100
100
  ## Skill reference
101
- Gitea API monitoring + failure triage: `skills/devops/deploy-local/SKILL.md`. GitHub `gh pr` / `gh run`
101
+ Gitea API monitoring + failure triage: the `deploy-local` skill (ships in the optional `caddis-extras` plugin — enable it with `claude plugin enable caddis-extras`). GitHub `gh pr` / `gh run`
102
102
  usage: the `gh-cli` skill. Load whichever matches the detected lane.
@@ -151,8 +151,12 @@ audit trail this pattern has.
151
151
  generator:**
152
152
 
153
153
  ```
154
+ python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_spawn.py" preflight
154
155
  python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_inventory.py" --with-tests
155
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.
156
160
  (falls back to `scripts/caddis_inventory.py` in a source checkout; skip the step if absent — it
157
161
  degrades open like every other machine step here.)
158
162
 
@@ -191,6 +195,28 @@ Then write the judgement half yourself. It must contain:
191
195
  > pass while understanding nothing. Rotate it, and prefer a fact the *most recent* milestone
192
196
  > established, since that is what the incoming Hub is least likely to have absorbed.
193
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
+
194
220
  Good traps share a shape: a figure that looks obvious, a correct value that differs, and a reason
195
221
  rooted in the data rather than in the code. On the reference project, one generation asked why the
196
222
  funnel's `offered` is not `SUM(OfferedInd)` (naive 3,814, correct 4,783 — the raw flags do not
@@ -250,8 +276,15 @@ exists to shed.
250
276
  ```
251
277
  python "${CLAUDE_PLUGIN_ROOT}/scripts/caddis_gate.py" handover-check \
252
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
253
281
  ```
254
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
+
255
288
  It fails when the prompt names a file that does not exist. **Validate the DOCUMENT, not just the
256
289
  reader.** The context self-check in Step 4 proves the incoming Hub read carefully; it proves nothing
257
290
  about whether what it read was true. One incoming Hub passed a thirteen-question check on a handover
@@ -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,105 @@
1
+ ---
2
+ name: statusline
3
+ description: Install the caddis status line into Claude Code and agy — one renderer, once per machine
4
+ ---
5
+
6
+ # /statusline — set up the status bar
7
+
8
+ Wire the caddis status line into every coding agent on this machine. One Python renderer serves
9
+ both hosts. It installs at **user scope**, so every project gets the line and no project holds a
10
+ copy that can drift.
11
+
12
+ ## What the user gets
13
+
14
+ Claude Code:
15
+
16
+ ```
17
+ ⌂ claudster-source | saajunaid/caddis ⎇ main +2 ●1 ?3 ↑1 | ◆ Opus 5 (1M context) v2.1.239 |
18
+ ◉ 412k/1M [███░░░░░] 41% | ⚡ 386k cached | effort:high | style:Plain | thinking |
19
+ 5h:12% 7d:40% | 💻 57% (37 GB) | ⏺ relay | ◷ 07:58
20
+ ```
21
+
22
+ agy (Antigravity):
23
+
24
+ ```
25
+ ▛▜ agy | ● idle | 🧠 Gemini 3.6 Flash (High) (high) | 📁 claudster-source | ⎇ main ?3 |
26
+ ◉ 48.5k/1M [░░░░░░░░] 5% | ⚡ 40k cached | q 62% | 💻 57% (37 GB) | ⏺ relay | ◷ 08:01
27
+ ```
28
+
29
+ Both lines come from `caddis_statusline.py`. It has two profiles, because the two hosts send
30
+ different field names — agy's payload is a sibling of Claude Code's, not a copy.
31
+
32
+ ## Run it
33
+
34
+ Find the renderer in this install and run it. Try these paths in order and use the first that exists:
35
+
36
+ - `${CLAUDE_PLUGIN_ROOT}/scripts/caddis_statusline.py`
37
+ - `claude-harness/scripts/caddis_statusline.py` (working inside the caddis source repo)
38
+
39
+ Then:
40
+
41
+ ```bash
42
+ python <path>/caddis_statusline.py --install # both hosts
43
+ python <path>/caddis_statusline.py --install --host claude
44
+ python <path>/caddis_statusline.py --install --host agy
45
+ python <path>/caddis_statusline.py --install --dry-run # print, write nothing
46
+ ```
47
+
48
+ `--install` does four things:
49
+
50
+ 1. Copies the renderer to `~/.caddis/statusline.py` — a **stable** path. Pointing the host
51
+ settings at the plugin cache would break on every caddis upgrade, because the version number
52
+ is in that path.
53
+ 2. Creates `~/.caddis/statusline.json` with the default toggles. It never overwrites an existing one.
54
+ 3. Backs up each host's `settings.json` to `settings.json.bak-caddis-statusline`.
55
+ 4. Sets `statusLine` in `~/.claude/settings.json` and `~/.gemini/antigravity-cli/settings.json`,
56
+ preserving every other key. A host that is not installed is skipped, not failed.
57
+
58
+ Report the tool's own output to the user. Then tell them the line appears on the **next** session —
59
+ neither host re-reads `settings.json` mid-session.
60
+
61
+ ## Verify
62
+
63
+ ```bash
64
+ python ~/.caddis/statusline.py --check # what is wired where
65
+ python ~/.caddis/statusline.py --sample --profile claude # preview, no host needed
66
+ python ~/.caddis/statusline.py --sample --profile agy
67
+ ```
68
+
69
+ `--check` exits non-zero when a host's `statusLine` is missing or points somewhere else.
70
+
71
+ ## Change the look
72
+
73
+ Edit `~/.caddis/statusline.json`. Every key is optional; a missing file means defaults.
74
+
75
+ | key | default | what it controls |
76
+ |---|---|---|
77
+ | `color` | `true` | ANSI colour |
78
+ | `icons` | `true` | Unicode segment icons. These are plain Unicode, **not** Nerd Font glyphs |
79
+ | `progress_bar` | `true` | the `[███░░░░░]` context bar |
80
+ | `bar_width` | `8` | bar cells |
81
+ | `token_counts` | `true` | `◉ 412k/1M` |
82
+ | `cached_tokens` | `true` | `⚡ 386k cached` — bold and bright by design, never width-gated |
83
+ | `ram` | `true` | `💻 57% (37 GB)` |
84
+ | `ram_min_width` | `0` | hide RAM below this terminal width; `0` always shows it |
85
+ | `clock` | `true` | `◷ 07:58` |
86
+ | `relay` | `true` | `⏺ relay` when a parked resume pointer exists |
87
+ | `rate_limits` | `true` | `5h:12% 7d:40%` (Claude Code only) |
88
+ | `session_id` | `false` | `#a1b2c3d4` |
89
+ | `git` | `true` | branch, staged/unstaged/untracked counts, ahead/behind |
90
+ | `separator` | `"\|"` | segment separator |
91
+
92
+ Config changes take effect on the next render. No reinstall needed.
93
+
94
+ ## Notes for you, not the user
95
+
96
+ - Do **not** hand-edit either `settings.json` to wire this. `--install` reads, merges and writes
97
+ back, so it cannot drop an unrelated key. Hand edits have dropped `trustedWorkspaces` before.
98
+ - The renderer never crashes the host. A bad payload, a missing field, or an unreadable config
99
+ degrades to fewer segments; a hard failure degrades to the directory name.
100
+ - RAM on Windows uses `ctypes` `GlobalMemoryStatusEx`, an in-process call. Do not replace it with
101
+ `Get-CimInstance Win32_OperatingSystem` — that cost about 300 ms on **every** render in the
102
+ PowerShell line this replaced.
103
+ - If the user asks why their old `~/.claude/statusline-custom.sh` or
104
+ `~/.gemini/statusline/statusline.ps1` no longer runs: nothing points at them any more. They are
105
+ superseded, not deleted. Both are safe to remove once the user is happy with the new line.
@@ -55,9 +55,21 @@ A wholly new provider: add a row to `PROVIDERS` in `oss_model.py` (base_url, mod
55
55
  pass an unknown provider name with `OSS_BASE_URL`+`OSS_MODEL` set — no table edit required.
56
56
 
57
57
  ## First-time install
58
- Put `claude-harness/scripts/` (or your plugin's `scripts/` dir) on `PATH`, or add a shell profile
59
- function. `/setup-project-ai` documents the one-liner for your platform (PowerShell profile function /
60
- bash alias) — it does not silently edit your shell profile.
58
+
59
+ ```
60
+ npm i -g @caddis/cli # puts claude-oss / claude-glm / claude-deepseek on PATH
61
+ caddis keys # prompts for each provider key, validates it, writes ~/.caddis/keys.env
62
+ claude-glm --print-config # zero-token check: endpoint, model, key all resolved
63
+ ```
64
+
65
+ npm does the PATH work on Windows, macOS and Linux. No profile edit, no script copying, no
66
+ Python needed on the lane path — the resolver is ported into the CLI, because the npm tarball
67
+ ships only `dist` and `bundles`.
68
+
69
+ `npx` runs the default `caddis` binary only; the lane binaries need the global install above.
70
+
71
+ **Plugin-only installs** (no npm CLI) keep the original route: put the plugin's `scripts/`
72
+ directory on `PATH`, or add a shell profile function. caddis never silently edits your profile.
61
73
 
62
74
  ## Exit codes
63
75
  `claude-oss`/`claude-glm` propagate the wrapped `claude` process's exit code, except a resolver failure
@@ -131,14 +131,33 @@ def truncate_relay(text: str) -> str:
131
131
  return text
132
132
 
133
133
 
134
+
135
+ def _hook_note(feature, exc, root=None):
136
+ """Record a swallowed failure in the caddis hook ledger. Never raises, never prints.
137
+
138
+ agy hooks ship FLAT at the plugin root while hook_log.py ships under scripts/, and in
139
+ the source repo this file sits in claude-harness/agy/ with hook_log.py one level up in
140
+ claude-harness/scripts/. Try both layouts.
141
+ """
142
+ try:
143
+ _here = os.path.dirname(os.path.abspath(__file__))
144
+ for _cand in (os.path.join(_here, "scripts"),
145
+ os.path.join(os.path.dirname(_here), "scripts")):
146
+ if os.path.isdir(_cand) and _cand not in sys.path:
147
+ sys.path.insert(0, _cand)
148
+ import hook_log as _hl # noqa: E402
149
+ _hl.record(os.path.basename(__file__).replace(".py", ""), feature, exc, root)
150
+ except Exception:
151
+ pass
152
+
134
153
  def main() -> None:
135
154
  try:
136
155
  _reconfig = getattr(sys.stdout, "reconfigure", None)
137
156
  if _reconfig:
138
157
  try:
139
158
  _reconfig(encoding="utf-8")
140
- except Exception:
141
- pass
159
+ except Exception as _exc:
160
+ _hook_note("agy stdout utf-8 reconfigure", _exc)
142
161
  try:
143
162
  data = json.load(sys.stdin)
144
163
  except Exception:
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "caddis-extras",
3
- "version": "1.3.24",
3
+ "version": "1.3.25",
4
4
  "description": "caddis-extras — the long-tail skills for the Antigravity (agy) caddis plugin; install alongside caddis for the full set."
5
5
  }
@@ -241,4 +241,4 @@ def fetch_records(status: str = None, page: int = 1):
241
241
  | Architect agent | `agents/architect.agent.md` |
242
242
  | FastAPI dev skill | `skills/coding/fastapi-dev/SKILL.md` |
243
243
  | Streamlit dev skill | `skills/frontend/streamlit-dev/SKILL.md` |
244
- | SQL expert skill | `skills/coding/sql/SKILL.md` |
244
+ | SQL expert skill | the `sql` skill |
@@ -382,4 +382,4 @@ This pattern is complementary to chunk retry (Step 6 + Gotcha 6) — the 3-layer
382
382
  |----------|------|
383
383
  | Streamlit dev skill | `skills/frontend/streamlit-dev/SKILL.md` |
384
384
  | Streamlit instructions | `instructions/streamlit.instructions.md` |
385
- | SQL expert skill | `skills/coding/sql/SKILL.md` |
385
+ | SQL expert skill | the `sql` skill |
@@ -283,6 +283,6 @@ st.plotly_chart(create_trend_chart(filter_type), use_container_width=True)
283
283
  |----------|------|
284
284
  | Streamlit dev skill | `skills/frontend/streamlit-dev/SKILL.md` |
285
285
  | FastAPI dev skill | `skills/coding/fastapi-dev/SKILL.md` |
286
- | SQL expert skill | `skills/coding/sql/SKILL.md` |
286
+ | SQL expert skill | the `sql` skill |
287
287
  | Caching patterns | `skills/coding/caching-patterns/SKILL.md` |
288
288
  | UX design skill | `skills/frontend/ux-design/SKILL.md` |
@@ -1,7 +1,7 @@
1
1
  {
2
- "poolVersion": "1.3.74",
2
+ "poolVersion": "1.3.77",
3
3
  "bundles": {
4
- "antigravity-plugin": "1.3.74",
5
- "antigravity-plugin-extras": "1.3.24"
4
+ "antigravity-plugin": "1.3.77",
5
+ "antigravity-plugin-extras": "1.3.25"
6
6
  }
7
7
  }