create-claude-cabinet 0.46.0 → 0.47.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 (139) hide show
  1. package/README.md +2 -6
  2. package/lib/cli.js +348 -91
  3. package/lib/copy.js +108 -6
  4. package/lib/db-setup.js +122 -17
  5. package/lib/metadata.js +51 -2
  6. package/lib/settings-merge.js +52 -10
  7. package/lib/watchtower-setup.js +22 -2
  8. package/package.json +1 -1
  9. package/templates/cabinet/advisories-state-schema.md +1 -1
  10. package/templates/cabinet/checklist-stats-schema.md +15 -1
  11. package/templates/cabinet/memory-lifecycle-contract.md +135 -0
  12. package/templates/cabinet/pib-db-access.md +13 -0
  13. package/templates/cabinet/watchtower-contracts.md +414 -0
  14. package/templates/cabinet/worktree-invocation-contract.md +87 -0
  15. package/templates/engagement/OVERVIEW.md +12 -0
  16. package/templates/engagement/__tests__/engagement.test.mjs +177 -2
  17. package/templates/engagement/__tests__/invoice-doc.test.mjs +195 -0
  18. package/templates/engagement/engagement-preview.mjs +100 -0
  19. package/templates/engagement/engagement-schema.md +240 -0
  20. package/templates/engagement/engagement.mjs +391 -11
  21. package/templates/engagement/pib-db-patches/pib-db-mcp-server.mjs +5 -44
  22. package/templates/engagement/pib-db-patches/pib-db.mjs +5 -2
  23. package/templates/hooks/action-completion-gate.sh +9 -3
  24. package/templates/hooks/memory-index-guard.sh +17 -11
  25. package/templates/hooks/watchtower-session-start.sh +24 -2
  26. package/templates/mcp/pib-db.json +1 -4
  27. package/templates/mux/bin/mux +8 -1
  28. package/templates/mux/config/help.txt +1 -0
  29. package/templates/rules/acknowledge-when-corrected.md +33 -0
  30. package/templates/rules/maintainability.md +11 -0
  31. package/templates/rules/memory-capture.md +26 -4
  32. package/templates/rules/plan-before-bulk-or-irreversible-actions.md +48 -0
  33. package/templates/rules/verify-before-asserting.md +79 -0
  34. package/templates/scripts/__tests__/ahead-check-origin.test.mjs +355 -0
  35. package/templates/scripts/__tests__/batch-disposition.test.mjs +98 -0
  36. package/templates/scripts/__tests__/claude-churn-authored.test.mjs +90 -0
  37. package/templates/scripts/__tests__/cross-ring-reader.test.mjs +505 -0
  38. package/templates/scripts/__tests__/dx-captures-briefing.test.mjs +169 -0
  39. package/templates/scripts/__tests__/hook-runner.test.mjs +247 -0
  40. package/templates/scripts/__tests__/narrative-corpus.test.mjs +247 -0
  41. package/templates/scripts/__tests__/phase-shim.test.mjs +112 -0
  42. package/templates/scripts/__tests__/qa-handoff-merge-state.test.mjs +162 -0
  43. package/templates/scripts/__tests__/resolve-cli.test.mjs +314 -0
  44. package/templates/scripts/__tests__/ring-state-ownership.test.mjs +120 -0
  45. package/templates/scripts/__tests__/ring1-content-detector.test.mjs +168 -0
  46. package/templates/scripts/__tests__/ring1-flagged-actions.test.mjs +135 -0
  47. package/templates/scripts/__tests__/ring1-script-drift.test.mjs +126 -0
  48. package/templates/scripts/__tests__/ring2-queue-reader.test.mjs +80 -0
  49. package/templates/scripts/__tests__/ring2-recall-canary.test.mjs +150 -0
  50. package/templates/scripts/__tests__/ring2-roster-review.test.mjs +311 -0
  51. package/templates/scripts/__tests__/ring3-chunk-merge.test.mjs +122 -0
  52. package/templates/scripts/__tests__/ring3-close-lenses.test.mjs +359 -0
  53. package/templates/scripts/__tests__/ring3-dedup.test.mjs +92 -12
  54. package/templates/scripts/__tests__/ring3-memory-titles.test.mjs +187 -0
  55. package/templates/scripts/__tests__/ring3-novelty-rescue.test.mjs +148 -0
  56. package/templates/scripts/__tests__/ring3-recent-slice.test.mjs +101 -0
  57. package/templates/scripts/__tests__/ring4-reconcile.test.mjs +393 -0
  58. package/templates/scripts/__tests__/shared-thread-reader.test.mjs +187 -0
  59. package/templates/scripts/__tests__/suppression-ledger.test.mjs +148 -0
  60. package/templates/scripts/__tests__/verify-backfill.test.mjs +103 -0
  61. package/templates/scripts/__tests__/verify-coverage.test.mjs +80 -0
  62. package/templates/scripts/__tests__/watchtower-snapshot.test.mjs +261 -0
  63. package/templates/scripts/__tests__/watchtower-sync.test.mjs +311 -0
  64. package/templates/scripts/load-triage-history.js +5 -2
  65. package/templates/scripts/pib-db-mcp-server.mjs +5 -44
  66. package/templates/scripts/pib-db-path.mjs +61 -0
  67. package/templates/scripts/pib-db.mjs +5 -2
  68. package/templates/scripts/validate-memory.mjs +214 -16
  69. package/templates/scripts/watchtower-advisories.mjs +7 -3
  70. package/templates/scripts/watchtower-build-context.mjs +192 -8
  71. package/templates/scripts/watchtower-cross-ring-reader.mjs +700 -0
  72. package/templates/scripts/watchtower-hook-runner.mjs +422 -0
  73. package/templates/scripts/watchtower-lib.mjs +273 -4
  74. package/templates/scripts/watchtower-narrative-corpus.mjs +385 -0
  75. package/templates/scripts/watchtower-phase-shim.mjs +171 -0
  76. package/templates/scripts/watchtower-queue.mjs +341 -3
  77. package/templates/scripts/watchtower-ring1.mjs +405 -45
  78. package/templates/scripts/watchtower-ring2.mjs +710 -68
  79. package/templates/scripts/watchtower-ring3-close.mjs +988 -147
  80. package/templates/scripts/watchtower-ring4-runner.sh +85 -0
  81. package/templates/scripts/watchtower-ring4.mjs +753 -0
  82. package/templates/scripts/watchtower-routines.mjs +1 -1
  83. package/templates/scripts/watchtower-snapshot.mjs +452 -0
  84. package/templates/scripts/watchtower-sync.mjs +393 -0
  85. package/templates/skills/briefing/SKILL.md +281 -41
  86. package/templates/skills/cabinet-process-therapist/SKILL.md +28 -0
  87. package/templates/skills/cabinet-security/SKILL.md +11 -0
  88. package/templates/skills/catch-up/SKILL.md +113 -0
  89. package/templates/skills/cc-publish/SKILL.md +53 -16
  90. package/templates/skills/cc-remember/SKILL.md +45 -0
  91. package/templates/skills/close/SKILL.md +107 -0
  92. package/templates/skills/collab-client/SKILL.md +22 -5
  93. package/templates/skills/collab-consultant/SKILL.md +110 -2
  94. package/templates/skills/debrief/SKILL.md +21 -4
  95. package/templates/skills/debrief-classic/SKILL.md +696 -0
  96. package/templates/skills/debrief-classic/calibration.md +44 -0
  97. package/templates/skills/debrief-classic/phases/audit-pattern-capture.md +78 -0
  98. package/templates/skills/debrief-classic/phases/auto-maintenance.md +48 -0
  99. package/templates/skills/debrief-classic/phases/checklist-feedback.md +123 -0
  100. package/templates/skills/debrief-classic/phases/close-work.md +163 -0
  101. package/templates/skills/debrief-classic/phases/health-checks.md +54 -0
  102. package/templates/skills/debrief-classic/phases/inventory.md +40 -0
  103. package/templates/skills/debrief-classic/phases/loose-ends.md +52 -0
  104. package/templates/skills/debrief-classic/phases/methodology-capture.md +223 -0
  105. package/templates/skills/debrief-classic/phases/qa-handoff-sweep.md +78 -0
  106. package/templates/skills/debrief-classic/phases/record-lessons.md +177 -0
  107. package/templates/skills/debrief-classic/phases/report.md +59 -0
  108. package/templates/skills/debrief-classic/phases/update-state.md +48 -0
  109. package/templates/skills/debrief-classic/phases/upstream-feedback.md +185 -0
  110. package/templates/skills/debrief-classic/phases/verify-coverage.md +101 -0
  111. package/templates/skills/execute/SKILL.md +71 -6
  112. package/templates/skills/execute/phases/commit-and-deploy.md +8 -0
  113. package/templates/skills/execute-group/SKILL.md +23 -26
  114. package/templates/skills/generate-plan-groups/SKILL.md +20 -0
  115. package/templates/skills/inbox/SKILL.md +84 -28
  116. package/templates/skills/memory/SKILL.md +22 -6
  117. package/templates/skills/orient/SKILL.md +71 -5
  118. package/templates/skills/orient-classic/SKILL.md +770 -0
  119. package/templates/skills/orient-classic/phases/auto-maintenance.md +52 -0
  120. package/templates/skills/orient-classic/phases/briefing.md +53 -0
  121. package/templates/skills/orient-classic/phases/cabinet.md +46 -0
  122. package/templates/skills/orient-classic/phases/checklist-status.md +54 -0
  123. package/templates/skills/orient-classic/phases/context.md +88 -0
  124. package/templates/skills/orient-classic/phases/data-sync.md +35 -0
  125. package/templates/skills/orient-classic/phases/deferred-check.md +55 -0
  126. package/templates/skills/orient-classic/phases/dx-captures.md +53 -0
  127. package/templates/skills/orient-classic/phases/health-checks.md +50 -0
  128. package/templates/skills/orient-classic/phases/verify-backfill.md +109 -0
  129. package/templates/skills/orient-classic/phases/work-scan.md +69 -0
  130. package/templates/skills/qa-drain/SKILL.md +38 -0
  131. package/templates/skills/qa-handoff/SKILL.md +287 -46
  132. package/templates/skills/setup-accounts/SKILL.md +38 -16
  133. package/templates/skills/threads/SKILL.md +4 -0
  134. package/templates/skills/validate/phases/validators.md +41 -0
  135. package/templates/skills/watchtower/SKILL.md +160 -8
  136. package/templates/verify-runtime/CONVENTIONS.md +9 -0
  137. package/templates/verify-runtime/README.md +37 -0
  138. package/templates/watchtower/config.json.template +8 -2
  139. package/templates/workflows/execute-group-complete.js +10 -1
@@ -5,10 +5,13 @@ description: |
5
5
  project by project — plain-English state, what deserves attention,
6
6
  and the project's pending inbox items batched into proposed
7
7
  dispositions you approve in-conversation. Decisions are chunked by
8
- project, never interleaved. Also handles /recap (factual-only mode).
8
+ project, never interleaved. Also handles /recap (factual-only mode)
9
+ and a per-project decision-lineage drill-down ("why is this project
10
+ the way it is — what still constrains it").
9
11
  Use when: "briefing", "brief me", "/briefing", "what's the landscape",
10
- "recap", "/recap", "what happened", "what did I do yesterday".
11
- argument-hint: "scope e.g., 'today', 'this week', 'maginnis only', 'recap'"
12
+ "recap", "/recap", "what happened", "what did I do yesterday",
13
+ "decision lineage", "why is this the way it is".
14
+ argument-hint: "scope — e.g., 'today', 'this week', 'maginnis only', 'recap', 'lineage'"
12
15
  ---
13
16
 
14
17
  # /briefing — The Daily Surface
@@ -21,10 +24,19 @@ the conversation. The success test: the operator runs this daily
21
24
  because it is pleasant, and the inbox drains through batch decisions
22
25
  here instead of item-by-item `/inbox` walks.
23
26
 
24
- Tone contract for every section below: conversational, concept-first,
25
- no fid/jargon walls. Item ids and `act:` fids appear on request or in
26
- disposition confirmations never as the narrative spine. Lead with
27
- what matters; counts and mechanics trail.
27
+ Tone contract for every section below **non-negotiable, every run**:
28
+ plain English, conversational, concept-first. No insider jargon, no
29
+ fid/jargon walls. Say "the background system files one note when the
30
+ same mistake keeps happening" not "Ring 2 emitPatternPromotion
31
+ dedups by failure class." Name the thing in words the operator would
32
+ use, then add the id only as a trailing reference. Item ids and `act:`
33
+ fids appear on request or in disposition confirmations — never as the
34
+ narrative spine. Lead with what matters; counts and mechanics trail.
35
+ This recurred live (2026-06-14): a briefing slipped into "Ring 2
36
+ meta-critiques / generator leak" and the operator could not act on it
37
+ until it was re-said plainly. If you catch yourself writing a term a
38
+ non-author wouldn't recognize, rewrite the sentence. See also the
39
+ decision/context structure rule under Step 3c.
28
40
 
29
41
  ## The Anti-Accretion Invariant (structural rule)
30
42
 
@@ -57,6 +69,9 @@ rules, not sections:
57
69
  - If `$ARGUMENTS` contains the word "recap", or the skill was invoked
58
70
  as `/recap`: **Factual mode.** Deliver Step 2's summary, write the
59
71
  timestamp (Step 5), and stop. No walk, no dispositions, no cabinet.
72
+ - If `$ARGUMENTS` contains "lineage", "why is", or "decision history":
73
+ **Lineage mode.** Render THIS desk's project decision lineage (see
74
+ "Lineage Mode" below), then stop. No walk, no dispositions, no cabinet.
60
75
  - Otherwise: **Full mode.** Summary, then the project walk with batch
61
76
  dispositions, then the cross-portfolio close.
62
77
 
@@ -81,6 +96,87 @@ The time window scopes the NARRATIVE (sessions, threads, what
81
96
  happened); pending inbox items are always loaded in full — old pending
82
97
  items are exactly what batch dispositions exist to drain.
83
98
 
99
+ ## Lineage Mode: Decision-Lineage Drill-Down (act:a2efc0ce)
100
+
101
+ On-demand, read-only. Answers "why is THIS desk's project the way it is —
102
+ what past decisions still constrain it, and what's safely reversible?"
103
+ This is a **projection** over existing stores (the inbox, threads, memory
104
+ `decision_*.md`, `.claude/methodology/`, pib-db), never a new store, and
105
+ it **writes nothing**. It is current-project-scoped in Stage 1: it reads
106
+ the project the current desk's cwd belongs to (worktree-aware). If the
107
+ operator named a *different* project, say plainly that lineage is
108
+ per-desk for now — run it from that project's desk — then either run it
109
+ for the current project or stop. (Cross-project lineage is deferred.)
110
+
111
+ Distinct from `/threads arc <slug>`, which tells **one work thread's**
112
+ evolution. Lineage tells the **whole project's decision causality**.
113
+
114
+ **L1 — corpus (inbox + threads).** Run the read-only helper (it lives
115
+ beside the queue lib, in the project-root `scripts/` dir):
116
+ ```bash
117
+ node scripts/watchtower-narrative-corpus.mjs --corpus --project-path "$(pwd)"
118
+ ```
119
+ It returns `project_identity`, `inbox_decisions` (knowledge-extraction
120
+ items, captured-to-memory duplicates already dropped, `superseded`
121
+ included), `thread_cursors` (full `cursor_history` timelines),
122
+ `per_store_counts`, and `skipped_unresolved`. If `reason` is
123
+ `project-unresolved`, say the desk isn't a watchtower project and stop.
124
+
125
+ **L2 — memory decisions + recorded edges.** Resolve the project's
126
+ built-in memory dir the way orient does (prefer
127
+ `node -e "console.log(require('./scripts/project-context.cjs').resolveMemoryDir())"`
128
+ when that script exists; else `~/.claude/projects/<dashified-cwd>/memory`),
129
+ then have the SAME helper parse the decision files (the consumer resolves
130
+ the path; the helper owns the edge rule):
131
+ ```bash
132
+ node scripts/watchtower-narrative-corpus.mjs --memory "<memory-dir>"
133
+ ```
134
+ Each entry carries `supersedes` (RECORDED, directional edges) and
135
+ `see_also` (undirected wikilinks — **never** render a see-also as a
136
+ supersession).
137
+
138
+ **L3 — methodology "why" (richest substrate).** If `.claude/methodology/`
139
+ exists in the cwd, read its `README.md` index and the `-internal.md`
140
+ bodies relevant to the load-bearing decisions — these carry the
141
+ Claim→Evidence→Skeptic→Counter reasoning the other stores summarize away.
142
+
143
+ **L4 — pib-db design rationale.** `pib_list_actions` for the current
144
+ project (resolve the `prj:` fid via `pib_list_projects`; if the name is
145
+ ambiguous, ask — never guess). Action notes carry `absorbs act:…` /
146
+ `Supersedes …` prose — these are **inferred** edges (prose, not a
147
+ structural field), mark them so.
148
+
149
+ **L5 — synthesize, ANSWER-FIRST** (plain English, concept-first; the tone
150
+ contract above applies in full):
151
+
152
+ 1. **What still constrains this project right now** — lead with this. The
153
+ decisions/constraints from earlier that later work still depends on;
154
+ for the ones the operator might want to revisit, say whether anything
155
+ still hangs on them (reversible vs load-bearing). This is the answer
156
+ the drill-down exists to give.
157
+ 2. **Supersession chains** — what replaced what, with **provenance**:
158
+ *recorded* (a parsed `**Supersedes:**` block or a pib `absorbs act:`
159
+ marker — citable) vs *inferred* (read from prose) — labeled, never
160
+ conflated. A narrative is a trust surface: do not present an inferred
161
+ link as recorded history, and never render a `[[wikilink]]` as a
162
+ supersede.
163
+ 3. **The causal timeline** — OPTIONAL deep-read, placed **below** the
164
+ answer. Chapter by causal **pivot / phase transition** (the moments
165
+ direction changed — a constraint discovered, an approach superseded),
166
+ not by raw time gaps. Skip this entirely when the corpus is sparse.
167
+
168
+ **Honesty footer.** Report `per_store_counts` and `skipped_unresolved` in
169
+ plain words when either is notable: "history may be incomplete — N inbox
170
+ items couldn't be attributed to a project and may belong here." Never
171
+ present a silently-truncated history as complete.
172
+
173
+ **Sparse / empty.** If the combined decision count (inbox_kept + memory
174
+ decisions) is under ~3, say "not enough decision history to narrate yet
175
+ (N found)" and stop — a story needs enough points to have an arc.
176
+
177
+ Lineage mode renders inline and stops. It writes nothing — no state file,
178
+ no inbox item, no memory write.
179
+
84
180
  ## Step 1: Gather Data
85
181
 
86
182
  No Claude API calls — pure filesystem reads plus the queue lib. State
@@ -116,18 +212,58 @@ and titles. Also collect resolved `qa-handoff` items whose
116
212
  pib-db (`pib_get_action` or `node scripts/pib-db.mjs get <fid>`) and
117
213
  keep only still-open ones — these are the open QA debts for Step 4.
118
214
 
119
- ### 1d. Portfolio state
215
+ ### 1d. Cross-ring portfolio view (state, threads, git attention, resolution history)
120
216
 
121
- Read `state/projects/*.md`Active Plans, Last Session, Standing
122
- Issues per project (scope-filtered if a project filter is active).
217
+ Run the cross-ring reader ONE gather call that replaces the old
218
+ per-store reads (state files + threads) and adds two signals nothing
219
+ here consulted before: the inbox **resolution history** (with
220
+ `resolution_mix` ratios — what the operator's past decisions actually
221
+ engaged vs discarded, per project) and the structured **git-attention
222
+ facts**:
123
223
 
124
- ### 1e. Active threads
224
+ ```bash
225
+ XRING="$(mktemp)"
226
+ node scripts/watchtower-cross-ring-reader.mjs --portfolio > "$XRING"
227
+ # with a project filter active: --project "<name or slug>" instead
228
+ # (config-key name preferred; a unique slug match also resolves)
229
+ ```
125
230
 
126
- Read `state/threads/*.json`; collect `status: "active"` threads. The
231
+ **Consume by Reading the file, never by echoing it through Bash** — a
232
+ live portfolio view runs to a few hundred KB and Bash tool output
233
+ truncates long before that (a truncated JSON parse is the failure this
234
+ instruction exists to prevent). Read the envelope's top (counts +
235
+ honesty fields) for Step 2, then Read each project's view slice as you
236
+ walk that chunk in Step 3; the JSON is pretty-printed, so each
237
+ project's view is one contiguous block.
238
+
239
+ Per project it returns the parsed Ring 1 state sections (Active Plans,
240
+ Last Session, Standing Issues, Tech Stack), git-attention facts, recent
241
+ session summaries, thread cursor timelines (capped to the newest 3
242
+ snapshots with `history_total` — the full evolution is lineage mode's
243
+ job; a legacy lone-`cursor` file arrives as a single-entry history;
244
+ current cursor = the LAST history entry), pending counts by
245
+ category/urgency, and the resolution history (`resolution_mix` carries
246
+ full counts; the event list is capped with `resolution_events_total`).
247
+ Every cap reports its total — "3 of 85" is signal, not truncation. The
248
+ envelope's honesty fields (`unattributed_items`, `orphan_threads`,
249
+ `orphaned_state_files`) are real signal — surface them in plain words
250
+ in Step 4 when notable. Pending COUNTS here are a narration snapshot;
251
+ 1c's live `listPending()` load stays the disposition source of truth.
252
+
253
+ **Fallback (script absent — a consumer that hasn't reinstalled since
254
+ the reader shipped):** read the raw stores directly as 1e describes,
255
+ and proceed without the resolution-history/git-attention signals.
256
+
257
+ ### 1e. Active threads (fallback path only)
258
+
259
+ Normally covered by the 1d view. When the 1d fallback is in effect,
260
+ read `state/threads/*.json`; collect `status: "active"` threads. The
127
261
  current cursor is `cursor_history[last].cursor` (older files may carry
128
262
  a lone `cursor` object — treat it as current). Extract `what`,
129
263
  `where_left_off`, `next_steps`, `last_updated`, session count. Sort by
130
- `last_updated` descending.
264
+ `last_updated` descending. (Also read `state/projects/*.md` — Active
265
+ Plans, Last Session, Standing Issues per project, scope-filtered if a
266
+ project filter is active.)
131
267
 
132
268
  ### 1f. Last briefing timestamp
133
269
 
@@ -155,6 +291,29 @@ observation is Step 4 close material. Include only members who said
155
291
  something; silence is fine and is the common case. In recap mode, skip
156
292
  the panel entirely — it spawns only on full-mode invocation.
157
293
 
294
+ ### 1h. Unprocessed DX captures (mux's global capture list)
295
+
296
+ Read mux's global DX-capture store — `~/.local/share/mux/dx.json` — the
297
+ single cross-project list where `mux dx "..."` and `/dx-feedback` drop
298
+ developer-experience ideas and friction. A pure filesystem read with no
299
+ ordering dependency on the panel spawn. If the file is absent or
300
+ unparseable (mux not installed, or no captures yet), skip silently — it
301
+ is a mux-owned store and its absence is normal, not an error.
302
+
303
+ An item is **active** (unprocessed) only when BOTH `done` is false AND
304
+ `filed` is false. `done` items were cleared; `filed` items already live
305
+ in pib-db (an action or feedback) — resurfacing either is exactly the
306
+ write-only-telemetry bug this duty exists to kill. Collect each active
307
+ item's `text`, `created_at`, `origin`, and its **global active-list
308
+ position** (1-based index among active items — the position
309
+ `manage-dx.py` addresses when draining). Resolve each item's `origin` to
310
+ a walk project where you can: labels like `"claude-cabinet"` or `"flow"`
311
+ map to a project chunk; labels like `"session-observation"` or
312
+ `"unknown"` do not — those are portfolio-level (Step 4). If there are
313
+ zero active items, skip silently. (This was orient's job; post-orient
314
+ nothing reads these unless the briefing does — see
315
+ `lesson_write_only_telemetry_wire_a_reader`.)
316
+
158
317
  ## Step 2: Top Brief
159
318
 
160
319
  Ten lines or fewer — the whole portfolio in one glance, curated. Not a
@@ -183,11 +342,19 @@ gate.").
183
342
 
184
343
  ## Step 3: The Project Walk
185
344
 
186
- One project at a time, in curated order: projects with pending gated
187
- items first, then urgent items, then by thread recency and pending
188
- count; quiet projects last (and a project with nothing to say gets one
189
- line or silence absence of news is news the operator doesn't need).
190
- A project filter scopes the walk to that project.
345
+ One project at a time, in curated order: lead with the chunks the
346
+ operator can actually act on from this session the current desk and
347
+ any project with dispositionable (ungated, this-desk) items then
348
+ projects with pending gated items, then urgent items, then by thread
349
+ recency and pending count; quiet projects last (and a project with
350
+ nothing to say gets one line or silence — absence of news is news the
351
+ operator doesn't need). A project filter scopes the walk to that
352
+ project. **Why actionable-first:** a cross-desk gated item can only be
353
+ "left queued for its own desk" from here — it is read-only from this
354
+ session, so surfacing it (and a wall of another desk's state) before
355
+ the operator's own decisions just front-loads context they must hold.
356
+ Surface it, but later. A gated item is never dropped (floor #1); it is
357
+ only re-ordered.
191
358
 
192
359
  **Decisions are never interleaved.** Each project's chunk completes —
193
360
  narrative, attention items, dispositions executed — before the next
@@ -204,9 +371,11 @@ Each chunk has three movements:
204
371
  ### 3a. State, in plain English
205
372
 
206
373
  Two to four sentences synthesized from the project's threads, Last
207
- Session, and standing issues: where work stands, what changed in
208
- scope, what's hanging. Concept-first "the publish pipeline is built
209
- but has never run against a live tag" not file paths and fids. This
374
+ Session, and standing issues all already in hand from the Step 1d
375
+ cross-ring view (no second read; its parsed sections, session bullets,
376
+ and cursor timelines are the input). Concept-first"the publish
377
+ pipeline is built but has never run against a live tag" — not file
378
+ paths and fids. This
210
379
  is the operator-facing register (`cabinet/skill-output-conventions.md`
211
380
  §9) as the briefing's whole default; keep it that way. Offer nothing
212
381
  here; drill-down happens by the operator asking.
@@ -238,6 +407,13 @@ floor-or-not) — a new duty adds an entry here, never a section:
238
407
  just read the surfacing state.
239
408
  - **Verify signals** · shipped-uncovered warnings · weigh as they arrive.
240
409
  - **State-file flags** · anything in Standing Issues that needs a human.
410
+ - **Unprocessed DX captures** · active items in mux's global `dx.json`
411
+ (1h) whose `origin` resolves to this chunk's project · weigh fresh,
412
+ then decay like any aged item — one line each, with a process/dismiss
413
+ path so the list actually drains (handling below) · not a floor:
414
+ captures are freely drainable and dismissable. Captures whose origin
415
+ resolves to no walk project go to the Step 4 close — never silently
416
+ dropped.
241
417
 
242
418
  Everything else stays in the batch counts below.
243
419
 
@@ -254,7 +430,7 @@ Advisor signals come from two sources, both weighed here:
254
430
  ungated items — legal batch material in 3c.
255
431
  - **Live panel observations** (Step 1g) that named this project.
256
432
 
257
- Two categories get specific handling when selected:
433
+ Three categories get specific handling when selected:
258
434
 
259
435
  - **Gated items (`qa-handoff`):** present what merged and what hangs
260
436
  on it, then offer exactly two paths — run the recipient gate now in
@@ -269,10 +445,48 @@ Two categories get specific handling when selected:
269
445
  `acted-on`. If the moment passed (yesterday's morning briefing),
270
446
  propose it for the stale batch below — routine items are dispatched
271
447
  but not gated, and the engine supersedes stale ones anyway.
448
+ - **DX captures:** write-only until something drains them. Surface each
449
+ active capture as one plain line (the idea · when · where it came
450
+ from) and offer exactly two paths, one decision at a time — **process**
451
+ it (act on it now, or file it to pib-db as an action or feedback, then
452
+ mark it filed) or **dismiss** it as no-longer-relevant. Both paths
453
+ drain the list through mux's own tooling — single source of truth,
454
+ never hand-edit `dx.json`:
455
+
456
+ ```bash
457
+ # dismiss (clear) a capture — n is its position in the active list
458
+ python3 ~/.config/mux/manage-dx.py done <origin> <n>
459
+ # after filing a capture to pib-db, mark it filed (drops it from the panel)
460
+ python3 ~/.config/mux/manage-dx.py mark-filed <origin> <n>
461
+ ```
462
+
463
+ `<n>` is the global active-list position, and positions renumber as
464
+ items leave — when draining several, clear from the **highest position
465
+ down** (or re-read positions between marks) so an earlier removal can't
466
+ shift the index out from under you. `<origin>` is context only; the
467
+ number addresses the global active list regardless of origin.
272
468
 
273
469
  ### 3c. Batch dispositions
274
470
 
275
- Cluster this project's remaining pending items into **at most three
471
+ **First, the sign-off batch the SAVE direction (M4, act:ffae4eec).**
472
+ Before any decay clustering, partition this project's ungated pending
473
+ items with `partitionForBatchSignoff` (the lib owns the predicate). Its
474
+ `signoff` set is the high-confidence pre-drafted knowledge-extraction
475
+ items (non-empty `draft_artifact`, not urgent, not low-confidence) —
476
+ work the rings already did that needs a nod, not a judgment. Offer the
477
+ whole set as ONE sign-off decision ("the background system drafted these
478
+ N memory entries; approving writes them to memory — sign off on all?").
479
+ On approval, write each `draft_artifact` to memory (`/cc-remember` or a
480
+ direct write), THEN one `applyBatch` resolve with
481
+ `resolution_type: 'captured-to-memory'`. This is the throughput valve:
482
+ M1/M2 raise inflow and success = filed × approval-rate (the M5 canary
483
+ tracks it), so a fast sign-off keeps drafts from ageing out
484
+ unadjudicated. Pulled-out items get per-item `/inbox` treatment after
485
+ the walk; everything else falls to the decay flow below — still one
486
+ decision at a time, the sign-off batch presented first.
487
+
488
+ **Then, decay clustering.** Cluster this project's REMAINING pending
489
+ items into **at most three
276
490
  proposed batches** by theme — category × age × thread is the usual
277
491
  axis. For each batch, propose a disposition in plain English with the
278
492
  reasoning visible. Decay lives here: the curator's default proposal
@@ -283,27 +497,40 @@ A batch proposal must name: what's in it (count + a few example
283
497
  titles), the proposed disposition, and the typed reason that will land
284
498
  on every item.
285
499
 
286
- Ask for approval as a **plain-text question, never a same-turn
287
- dialog**. A dialog eclipses everything above it, and batch rationale
288
- does not fit inside option descriptions the operator ends up
289
- approving reasoning they cannot see (recurred live 2026-06-13, twice
290
- in one session, during this skill's own QA). The shape: the chunk's
291
- prose ends with the batch proposals (each one: what's in it, the
292
- disposition, the typed reason) followed by a one-line question
293
- "Apply batch 1, batch 2, both, or neither?" — and the turn STOPS
294
- there. The operator answers in prose. Reserve `AskUserQuestion` for
295
- choices that are self-sufficient inside the dialog; batch
296
- dispositions never are.
500
+ Ask for approval **one decision at a time** never a stack of
501
+ questions under a wall of context, never a same-turn dialog. Two
502
+ failure modes, both observed live: a same-turn dialog eclipses the
503
+ reasoning above it, so the operator approves logic they cannot see
504
+ (recurred 2026-06-13); and a long narrative followed by several
505
+ questions at the end forces the operator to hold every batch's
506
+ rationale in their head at once, which they cannot (recurred
507
+ 2026-06-14). **The decision/context structure rule:** the only thing
508
+ that should require working memory is the single decision in front of
509
+ the operator, with its reason immediately beside it.
510
+
511
+ The shape: present **one batch** — what's in it (count + a few example
512
+ titles), the proposed disposition, the typed reason — then a one-line
513
+ question ("Dismiss these 14 as stale? y / n / show me") and the turn
514
+ STOPS. The operator answers in prose. Apply it, confirm in one line,
515
+ then present the next batch the same way. Pure read-only material —
516
+ portfolio state for desks the operator isn't on, platform notes,
517
+ anything needing no decision — is delivered AFTER all decisions are
518
+ made; it costs nothing to hold, so it never sits above a decision.
519
+ Reserve `AskUserQuestion` only for a self-contained choice whose
520
+ options stand on their own inside the dialog (e.g. a layout pick with
521
+ previews); batch dispositions never qualify.
297
522
 
298
523
  Execute approved batches immediately via the queue lib, then say what
299
524
  happened in one line each and move to the next project:
300
525
 
301
526
  ```bash
302
527
  node --input-type=module -e "
303
- import { applyBatch } from './scripts/watchtower-queue.mjs';
528
+ import { applyBatch, partitionForBatchSignoff, listPending } from './scripts/watchtower-queue.mjs';
529
+ // Sign-off batch (M4): partitionForBatchSignoff(listPending({project})).signoff
530
+ // → resolve 'captured-to-memory' (write each draft_artifact FIRST). Decay='dismiss'.
304
531
  const r = applyBatch([/* ids */], {
305
- disposition: 'dismiss', // or 'resolve'
306
- resolution_type: 'stale', // typed reason — required
532
+ disposition: 'dismiss', // or 'resolve' (the sign-off batch)
533
+ resolution_type: 'stale', // typed reason — required ('captured-to-memory' for sign-off)
307
534
  notes: '<the reason shown to the operator, verbatim>',
308
535
  });
309
536
  console.log(JSON.stringify(r));
@@ -325,10 +552,15 @@ include a part only when it has signal.
325
552
 
326
553
  - **Cross-cutting synthesis** — patterns spanning projects (the same
327
554
  friction filed from two desks, a theme across threads, a decision
328
- made in one project that answers a question open in another). This
329
- is live synthesis by the briefing session; if a precomputed
330
- cross-ring synthesis layer exists, consume it here instead of
331
- re-deriving.
555
+ made in one project that answers a question open in another). The
556
+ substrate is the Step 1d cross-ring portfolio view synthesize from
557
+ its per-project views (git-attention facts across projects,
558
+ `resolution_mix` ratios, thread/session convergence) instead of
559
+ re-deriving from raw stores. Its honesty fields belong here too, in
560
+ plain words when notable: "N inbox items couldn't be attributed to
561
+ any project", "one active thread matches no configured project".
562
+ The synthesis itself stays live — the reader gathers, this session
563
+ thinks.
332
564
  - **Standing debts** — floor #2: while any QA filed-gaps remain open,
333
565
  one roll-up line each ("X still owes the migration test filed by
334
566
  last week's QA — act:fid"). Same treatment for unmerged-worktree
@@ -338,6 +570,11 @@ include a part only when it has signal.
338
570
  historian precedent that answers an open question, a platform delta
339
571
  from the insider, a legibility flag from the user-advocate). One line
340
572
  each, only members who said something — never a roll call.
573
+ - **Unprocessed DX captures, portfolio-level** — active `dx.json`
574
+ captures (1h) whose `origin` resolved to no walk project land here,
575
+ one line each, with the same process/dismiss drain path as the
576
+ per-project handling (3b). Only when some exist; never a standing
577
+ section.
341
578
 
342
579
  Close with one sentence: dispositions applied this run (N resolved, M
343
580
  dismissed, across K projects), what remains pending, and — only if
@@ -367,6 +604,9 @@ After the briefing completes (any mode), atomically write
367
604
  the watchtower module): deliver the read-only briefing from global
368
605
  state and say dispositions need a watchtower-installed project.
369
606
  - Corrupt/unparseable item files: skip with a one-line warning count.
607
+ - No mux DX store (`~/.local/share/mux/dx.json` missing, or mux not
608
+ installed): skip the DX-capture candidate silently — a mux-owned
609
+ store's absence is normal, not an error.
370
610
  - An `applyBatch` throw is a stop-and-show, not a retry loop: name the
371
611
  item that tripped the gate, pull it into per-item handling, re-offer
372
612
  the rest as a new batch.
@@ -125,3 +125,31 @@ universal patterns below. Absent is normal — it is seeded by debrief
125
125
  when recurring findings accumulate.
126
126
 
127
127
  <!-- Universal patterns below this line -->
128
+
129
+ ### Don't redo work that's already done or already specified
130
+
131
+ Recurring inefficiency: discovery is run for things already in hand, and
132
+ complete plans are rebuilt instead of executed.
133
+
134
+ - **Use what you already know directly.** Don't run discovery
135
+ (ToolSearch, phase-file hunts, grep archaeology) for a tool name,
136
+ path, or spec you already have. A targeted lookup or direct attempt
137
+ beats a discovery loop; reserve discovery for the genuinely unknown.
138
+ - **Don't re-encode a complete plan.** If the prompt is already ordered
139
+ and explicit, execute it rather than rebuilding it as tasks that
140
+ mirror it. A task layer earns its cost only when it adds structure the
141
+ prompt lacks: progress-tracking through a long single-session run, or
142
+ a durable record when the work will span sessions. Match the vehicle
143
+ to the lifespan — an in-session task list for progress (it is lost on
144
+ interruption), a `.claude/plans/` doc or pib-db action for anything
145
+ that must outlive the session.
146
+ - **Bound your research.** Stop at minimum-viable understanding, not
147
+ maximal confidence. If you are hunting for something the user believes
148
+ exists, ask where it lives before a long search.
149
+ - **Reconcile on resume.** A continuation prompt is a claim about the
150
+ past; check current state (query the named action FIDs) before acting
151
+ on it.
152
+ - **Spawn with a sync point.** Load context before launching parallel
153
+ sub-agents, and define where you will collect and surface their
154
+ output. No fire-and-forget black boxes — no completion check, no
155
+ output handling.
@@ -108,3 +108,14 @@ universal patterns below. Absent is normal — it is seeded by debrief
108
108
  when recurring findings accumulate.
109
109
 
110
110
  <!-- Universal patterns below this line -->
111
+
112
+ ### Secrets pasted into the conversation need an active response
113
+
114
+ When a secret lands in the chat — a PAT, API key, password, connection
115
+ string the user pastes to unblock something — do not just consume it
116
+ silently. Two reflexes: (1) advise against pasting secrets in plain text
117
+ and point at the safer path (env var, secret store, the OS secure dialog
118
+ the engagement flow uses); (2) when you must echo or reference it,
119
+ redact/truncate it (`ghp_…abcd`) rather than reprinting it in full.
120
+ Silently using a plaintext secret normalizes leaking it into transcripts
121
+ and logs.
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: catch-up
3
+ description: |
4
+ Mid-session awareness refresh. Watchtower injects state once, at session
5
+ start; a long session then drifts from that snapshot as other sessions
6
+ advance threads, the background rings file inbox items and detect new git
7
+ state, and deferred tasks come due. /catch-up shows what CHANGED since this
8
+ session started — a short, plain-English delta, not a re-dump of everything.
9
+ Read-only. Use when: "catch-up", "/catch-up", "what changed", "what's new
10
+ since I started", "what did I miss", "refresh my context", "poll watchtower",
11
+ "re-orient".
12
+ argument-hint: "(none)"
13
+ ---
14
+
15
+ # /catch-up — What Changed Since This Session Started
16
+
17
+ Watchtower runs continuously in the background, but it injects its state into
18
+ a session exactly **once**, at session start. Over a long session that
19
+ snapshot goes stale: other desks advance shared work threads, Ring 2 enriches
20
+ and files inbox items, Ring 1 detects new git state, deferred actions come due.
21
+ This skill closes that gap — it compares the current watchtower state against
22
+ the **baseline captured when this session started** and tells you, in plain
23
+ language, only what's new.
24
+
25
+ This skill is **read-only**. It reads state and renders a delta. It never
26
+ triages, resolves, or writes anything except (when no baseline exists yet) a
27
+ fresh baseline for next time.
28
+
29
+ It is the manual, on-demand half of mid-session awareness. The automatic
30
+ "notify me when something significant changes" version is a deliberate later
31
+ enhancement (see the plan's Option B) — not this skill.
32
+
33
+ ## How the baseline works
34
+
35
+ At session start, the watchtower SessionStart hook captures a structured
36
+ snapshot of watchtower state, keyed by this session's id, at
37
+ `~/.claude-cabinet/watchtower/state/session-snapshots/<session-id>.json`.
38
+ `/catch-up` re-reads current state and diffs it against that baseline. All the
39
+ snapshot/diff/render logic lives in one place —
40
+ `~/.claude-cabinet/watchtower/scripts/watchtower-snapshot.mjs` — which this
41
+ skill just drives; it does not re-implement any of it.
42
+
43
+ ## Step 1 — Locate the runtime and this session's baseline
44
+
45
+ ```bash
46
+ WT="${HOME}/.claude-cabinet/watchtower"
47
+ SNAP="${WT}/scripts/watchtower-snapshot.mjs"
48
+ SID="${CLAUDE_CODE_SESSION_ID:-}"
49
+ BASE="${WT}/state/session-snapshots/${SID}.json"
50
+ ```
51
+
52
+ Resolve three facts:
53
+
54
+ - **Watchtower installed?** If `${SNAP}` does not exist, say plainly that
55
+ watchtower isn't installed (or this project isn't using it), so there's
56
+ nothing to catch up on, and stop.
57
+ - **Session id known?** `CLAUDE_CODE_SESSION_ID` is the session's id (a UUID;
58
+ it matches the session transcript name and the id the SessionStart hook keys
59
+ the baseline under). If it is empty, there is no per-session baseline to diff
60
+ against — say so plainly and stop (do **not** read or write a keyless/shared
61
+ baseline file; a shared "unknown" baseline would show you another session's
62
+ changes as if they were yours).
63
+ - **Baseline present?** Whether `${BASE}` exists decides Step 2's branch.
64
+
65
+ ## Step 2 — Diff, or self-seed if there's no baseline yet
66
+
67
+ **If `${BASE}` exists** — run the diff and relay it:
68
+
69
+ ```bash
70
+ node "${SNAP}" --diff "${BASE}" --project-path "$(pwd)"
71
+ ```
72
+
73
+ The module prints the delta already in plain, concept-first English (deferred
74
+ tasks that came due, new inbox items, threads that advanced or appeared, new or
75
+ cleared git attention) — or a single "Nothing new since this session started"
76
+ line. **Relay that output directly.** Don't reformat it into field dumps or
77
+ re-expand it into the full state; the whole point is the delta. You may add one
78
+ short framing sentence, but the rendered delta is the answer.
79
+
80
+ Phrase anything you add as *project-level* change ("since your session started,
81
+ the project picked up…"), never as something you personally did — in a worktree,
82
+ a concurrent session's work legitimately shows up in this delta.
83
+
84
+ **If `${BASE}` does NOT exist** — this session predates the feature, or the
85
+ SessionStart hook didn't capture a baseline. Self-seed one now so the *next*
86
+ `/catch-up` works, and say so honestly:
87
+
88
+ ```bash
89
+ node "${SNAP}" --emit-snapshot "${BASE}" --project-path "$(pwd)" --session-id "${SID}"
90
+ ```
91
+
92
+ Then tell the user, plainly: there was no start-of-session baseline to compare
93
+ against, so you've captured one as of now — run `/catch-up` again later to see
94
+ what's changed since this point. Do not invent a delta you can't compute.
95
+
96
+ ## Step 3 — Keep it short
97
+
98
+ The value here is the delta, surfaced fast. Lead with the headline ("2 new
99
+ inbox items, one thread advanced, a deferred task came due"), let the rendered
100
+ detail follow, and stop. If a new item or freshly-due task clearly wants
101
+ action, you may name the one next step — but routing and triage belong to
102
+ `/inbox` and `/briefing`; this skill just makes you current.
103
+
104
+ ## Calibration
105
+
106
+ **Without this skill:** the only way to re-orient mid-session is to restart, so
107
+ a session works for an hour against a start-of-session snapshot while threads
108
+ move, items get filed, and deferrals fire — all invisible until the next
109
+ session.
110
+
111
+ **With this skill:** one command answers "what did I miss while I was heads
112
+ down?" against a real baseline — the single upgrade that makes watchtower feel
113
+ alive mid-session rather than boundary-only.