session-orchestrator 5.3.0 → 5.4.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 (206) hide show
  1. package/.agents/skills/claude-md-drift-check/SKILL.md +1 -1
  2. package/.agents/skills/navigator/SKILL.md +22 -0
  3. package/.agents/skills/navigator/agents/openai.yaml +5 -0
  4. package/.agents/skills/test-audit/SKILL.md +21 -0
  5. package/.agents/skills/test-audit/agents/openai.yaml +5 -0
  6. package/.claude-plugin/marketplace.json +1 -1
  7. package/.claude-plugin/plugin.json +1 -1
  8. package/.codex-plugin/plugin.json +1 -1
  9. package/.codex-plugin/skills/claude-md-drift-check/SKILL.md +1 -1
  10. package/.codex-plugin/skills/navigator/SKILL.md +22 -0
  11. package/.codex-plugin/skills/navigator/agents/openai.yaml +5 -0
  12. package/.codex-plugin/skills/test-audit/SKILL.md +21 -0
  13. package/.codex-plugin/skills/test-audit/agents/openai.yaml +5 -0
  14. package/.cursor/commands/navigator.md +15 -0
  15. package/.cursor/commands/test-audit.md +14 -0
  16. package/.cursor/rules/060-evolve.mdc +27 -12
  17. package/.cursor/skills/claude-md-drift-check/SKILL.md +1 -1
  18. package/.cursor/skills/navigator/SKILL.md +13 -0
  19. package/.cursor/skills/test-audit/SKILL.md +12 -0
  20. package/.cursor-plugin/plugin.json +1 -1
  21. package/.orchestrator/policy/blocked-commands.json +1 -1
  22. package/AGENTS.md +9 -31
  23. package/CHANGELOG.md +70 -0
  24. package/README.md +14 -10
  25. package/docs/agent-authoring.md +2 -2
  26. package/docs/baseline.md +10 -1
  27. package/docs/ci-setup.md +57 -4
  28. package/docs/components.md +12 -12
  29. package/docs/events-schema.md +11 -8
  30. package/docs/persona-panel.md +5 -4
  31. package/docs/rule-authoring.md +27 -12
  32. package/docs/scope-collision-guard.md +26 -4
  33. package/docs/session-config-reference.md +55 -6
  34. package/docs/session-config-template.md +11 -2
  35. package/hooks/_lib/hook-import-set.json +27 -23
  36. package/hooks/hooks-codex.json +1 -1
  37. package/hooks/hooks-cursor.json +5 -0
  38. package/hooks/hooks-pi.json +5 -0
  39. package/hooks/hooks.json +6 -1
  40. package/hooks/on-session-start.mjs +53 -0
  41. package/hooks/on-stop.mjs +3 -1
  42. package/hooks/post-tool-batch-wave-signal.mjs +3 -1
  43. package/hooks/pre-bash-memory-propose-audit.mjs +52 -3
  44. package/hooks/pre-bash-sessions-ledger-guard.mjs +28 -2
  45. package/hooks/pre-edit-sessions-ledger-guard.mjs +162 -0
  46. package/hooks/pre-task-scope-disjoint.mjs +559 -72
  47. package/hooks/subagent-telemetry.mjs +96 -19
  48. package/package.json +3 -3
  49. package/pi/prompts/navigator.md +12 -0
  50. package/pi/prompts/test-audit.md +12 -0
  51. package/rules/README.md +6 -1
  52. package/rules/_index.md +3 -3
  53. package/rules/always-on/bash-harness-pitfalls.md +7 -1
  54. package/rules/opt-in-domain/prompt-caching.md +5 -1
  55. package/rules/opt-in-stack/backend-data.md +9 -1
  56. package/rules/opt-in-stack/backend.md +7 -1
  57. package/rules/opt-in-stack/frontend.md +6 -1
  58. package/rules/opt-in-stack/security-web.md +7 -1
  59. package/rules/opt-in-stack/swift.md +5 -1
  60. package/scripts/apply-session-learnings.mjs +492 -0
  61. package/scripts/archive-closed-prds.mjs +2 -1
  62. package/scripts/autopilot.mjs +49 -53
  63. package/scripts/backfill-abandoned-sessions.mjs +1 -1
  64. package/scripts/baseline-archetypes.mjs +1 -1
  65. package/scripts/check-package-manager.mjs +62 -5
  66. package/scripts/cursor-install.mjs +1 -4
  67. package/scripts/emit-session.mjs +296 -2
  68. package/scripts/export-hw-learnings.mjs +22 -3
  69. package/scripts/fleet-checkin.mjs +147 -0
  70. package/scripts/lib/agent-frontmatter.mjs +3 -3
  71. package/scripts/lib/auto-dream.mjs +7 -6
  72. package/scripts/lib/autopilot/flags.mjs +6 -1
  73. package/scripts/lib/autopilot/loop.mjs +10 -6
  74. package/scripts/lib/baseline-archetypes.mjs +41 -22
  75. package/scripts/lib/config/host-paths.mjs +79 -0
  76. package/scripts/lib/config/persona-gate-wave.mjs +3 -3
  77. package/scripts/lib/config/reaper.mjs +7 -6
  78. package/scripts/lib/config-schema.mjs +13 -0
  79. package/scripts/lib/config.mjs +71 -10
  80. package/scripts/lib/events.mjs +21 -2
  81. package/scripts/lib/fleet-protocol.mjs +270 -0
  82. package/scripts/lib/gates/gate-baseline.mjs +13 -3
  83. package/scripts/lib/gates/gate-full.mjs +7 -2
  84. package/scripts/lib/gates/gate-helpers.mjs +93 -2
  85. package/scripts/lib/gates/gate-incremental.mjs +23 -22
  86. package/scripts/lib/gates/gate-per-file.mjs +16 -7
  87. package/scripts/lib/instruction-budget-guard.mjs +69 -11
  88. package/scripts/lib/learnings/expiry-sweep.mjs +34 -3
  89. package/scripts/lib/learnings/io.mjs +154 -26
  90. package/scripts/lib/learnings/schema.mjs +163 -15
  91. package/scripts/lib/learnings/sizing-subject.mjs +2 -2
  92. package/scripts/lib/memory-proposals/schema.mjs +11 -5
  93. package/scripts/lib/named-baseline-resolver.mjs +53 -28
  94. package/scripts/lib/named-vault-resolver.mjs +104 -5
  95. package/scripts/lib/orphan-reaper/defaults.mjs +41 -0
  96. package/scripts/lib/orphan-reaper/ps-snapshot.mjs +181 -0
  97. package/scripts/lib/orphan-reaper/reaper-audit.mjs +291 -0
  98. package/scripts/lib/orphan-reaper/reaper-decide.mjs +395 -0
  99. package/scripts/lib/orphan-reaper/scan-throttle.mjs +92 -0
  100. package/scripts/lib/orphan-reaper/scan.mjs +506 -0
  101. package/scripts/lib/orphan-reaper.mjs +43 -1315
  102. package/scripts/lib/owner-yaml.mjs +104 -6
  103. package/scripts/lib/persona-panel/catalog-loader.mjs +1 -1
  104. package/scripts/lib/process-group.mjs +62 -11
  105. package/scripts/lib/project-hygiene.mjs +21 -1
  106. package/scripts/lib/quality-gate.mjs +45 -5
  107. package/scripts/lib/resource-probe.mjs +1 -1
  108. package/scripts/lib/rule-loader.mjs +100 -62
  109. package/scripts/lib/rules-sync.mjs +27 -12
  110. package/scripts/lib/scope-baseline.mjs +3 -4
  111. package/scripts/lib/session-record-repair.mjs +183 -26
  112. package/scripts/lib/session-registry.mjs +27 -2
  113. package/scripts/lib/session-schema/constants.mjs +30 -4
  114. package/scripts/lib/session-schema/validator.mjs +28 -1
  115. package/scripts/lib/session-token-rollup.mjs +245 -52
  116. package/scripts/lib/sessions-canonical.mjs +100 -9
  117. package/scripts/lib/sh-quote.mjs +29 -0
  118. package/scripts/lib/subagents-schema.mjs +30 -3
  119. package/scripts/lib/telemetry/pricing.mjs +118 -71
  120. package/scripts/lib/tests-src-ratio.mjs +140 -23
  121. package/scripts/lib/tmux-layout/layouts.mjs +1 -11
  122. package/scripts/lib/tmux-layout/tmux-shell.mjs +2 -11
  123. package/scripts/lib/ux-grill/reconcile.mjs +1 -1
  124. package/scripts/lib/validate/check-agents.mjs +1 -1
  125. package/scripts/lib/validate/check-hooks-symmetry.mjs +5 -0
  126. package/scripts/lib/validate/check-learnings-shell-writes.mjs +214 -0
  127. package/scripts/lib/validate/check-test-value-bans.mjs +87 -14
  128. package/scripts/lib/validate/check-unicode-safety.mjs +1 -0
  129. package/scripts/lib/validate/check-unwired-features.mjs +1 -1
  130. package/scripts/lib/validate-vendored-rules.mjs +206 -81
  131. package/scripts/lib/vault-mirror/telemetry.mjs +8 -1
  132. package/scripts/lib/vault-status/board-writer.mjs +48 -11
  133. package/scripts/lib/vault-status/narrative-mirror.mjs +40 -9
  134. package/scripts/lib/wave-executor/dispatch-common.mjs +10 -18
  135. package/scripts/lib/wave-executor/foreign-dispatch.mjs +1 -1
  136. package/scripts/lib/wave-executor/remote-dispatch.mjs +1 -1
  137. package/scripts/lib/wave-resource-gate.mjs +34 -8
  138. package/scripts/memory-propose.mjs +18 -5
  139. package/scripts/release-session-lock.mjs +2 -1
  140. package/scripts/release.mjs +10 -3
  141. package/scripts/repair-invalid-sessions.mjs +37 -4
  142. package/scripts/run-migrate-v2-cross-repo.mjs +158 -30
  143. package/scripts/run-quality-gate.mjs +323 -302
  144. package/scripts/site-numbers.mjs +163 -5
  145. package/scripts/sweep-expired-learnings.mjs +56 -5
  146. package/scripts/sweep-expired-rules.mjs +2 -1
  147. package/scripts/validate-plugin.mjs +7 -0
  148. package/scripts/vault-integration-watcher.mjs +2 -1
  149. package/scripts/vault-mirror.mjs +72 -46
  150. package/scripts/wave-scope-binding.mjs +2 -1
  151. package/skills/_shared/config-reading.md +3 -3
  152. package/skills/_shared/fleet-protocol.md +131 -0
  153. package/skills/_shared/state-ownership.md +5 -0
  154. package/skills/autopilot/SKILL.md +25 -11
  155. package/skills/bootstrap/SKILL.md +1 -1
  156. package/skills/bootstrap/_shared-template.md +1 -1
  157. package/skills/bootstrap/fast-template.md +1 -1
  158. package/skills/bootstrap/private-contract.md +2 -1
  159. package/skills/bootstrap/public-fallback.md +6 -3
  160. package/skills/bootstrap/references/bootstrap-retroactive-flow.md +2 -1
  161. package/skills/claude-md-drift-check/SKILL.md +10 -10
  162. package/skills/claude-md-drift-check/checker.mjs +26 -18
  163. package/skills/evolve/SKILL.md +2 -2
  164. package/skills/evolve/references/evolve-analyze-mode.md +10 -6
  165. package/skills/memory-cleanup/SKILL.md +1 -1
  166. package/skills/navigator/SKILL.md +193 -0
  167. package/skills/navigator/references/account-check.sh +87 -0
  168. package/skills/navigator/references/fleet-decisions.mjs +231 -0
  169. package/skills/navigator/references/slot-check.sh +114 -0
  170. package/skills/persona-panel/SKILL.md +2 -2
  171. package/skills/persona-panel/persona-format.md +2 -2
  172. package/skills/persona-panel/presets/designer-lens.md +1 -1
  173. package/skills/persona-panel/presets/engineer-lens.md +1 -1
  174. package/skills/persona-panel/presets/pm-lens.md +1 -1
  175. package/skills/plan/mode-retro.md +19 -4
  176. package/skills/quality-gates/SKILL.md +6 -4
  177. package/skills/remote-offload/SKILL.md +4 -2
  178. package/skills/session-end/learning-patterns.md +22 -12
  179. package/skills/session-end/metrics-collection.md +5 -6
  180. package/skills/session-end/references/phase-3-documentation-updates.md +2 -2
  181. package/skills/session-end/references/phase-4a-worktree-cleanup.md +2 -0
  182. package/skills/session-end/references/session-summary-template.md +1 -1
  183. package/skills/session-end/session-metrics-write.md +22 -60
  184. package/skills/session-plan/SKILL.md +0 -3
  185. package/skills/session-start/SKILL.md +6 -0
  186. package/skills/session-start/references/operations-contract.md +4 -0
  187. package/skills/session-start/references/phase-1-7-vault-status-board.md +1 -1
  188. package/skills/session-start/references/phase-4-ssot-environment-check.md +2 -2
  189. package/skills/test-audit/SKILL.md +152 -0
  190. package/skills/test-audit/references/campaign.md +111 -0
  191. package/skills/test-audit/references/mutate.sh +50 -0
  192. package/skills/wave-executor/SKILL.md +1 -1
  193. package/skills/wave-executor/references/wave-executor-state-init.md +3 -0
  194. package/skills/wave-executor/references/wave-loop-dispatch.md +3 -1
  195. package/skills/wave-executor/references/wave-loop-review.md +3 -5
  196. package/templates/personas/README.md +5 -5
  197. package/templates/personas/accounting-compliance.v1.md +1 -1
  198. package/templates/personas/accounting-tax-advisor.v1.md +1 -1
  199. package/templates/personas/buyer-p1-cto.v1.md +1 -1
  200. package/templates/personas/buyer-p2-kanzlei.v1.md +1 -1
  201. package/templates/personas/buyer-p3-build.v1.md +1 -1
  202. package/templates/personas/buyer-p4-tech-veto.v1.md +1 -1
  203. package/templates/personas/buyer-p5-solo.v1.md +1 -1
  204. package/templates/personas/buyer-p6-ld.v1.md +1 -1
  205. package/templates/personas/klima-ai-expert.v1.md +1 -1
  206. package/templates/personas/klima-physicist.v1.md +1 -1
@@ -133,7 +133,16 @@ function jsonlPath() {
133
133
  * Defense-in-depth byte ceiling for transcript reads (#624). The transcript path
134
134
  * is harness-trusted, so this is not an exploitable vector — but the repo follows
135
135
  * a bounded-read discipline: a pathologically large transcript is skipped (yields
136
- * the empty/zero-usage result) rather than read whole into memory.
136
+ * the null-usage result) rather than read whole into memory.
137
+ *
138
+ * CEILING: a skipped transcript yields a stop record with found=true but null
139
+ * tokens and model; the session rollup counts it as an unpriced cost candidate
140
+ * (#1474) instead of reading it. Frequency per issue #1474 (2026-09-29): 2 of
141
+ * 10,482 subagent transcripts exceeded this size. REVISIT when oversized
142
+ * transcripts exceed ~0.1% of found stop records — count them from transcript
143
+ * sizes, because the ledger writes the same token-less record for an oversized,
144
+ * a usage-free and an unreadable transcript — then read large transcripts
145
+ * streamed instead of skipping them.
137
146
  */
138
147
  const MAX_TRANSCRIPT_BYTES = 50 * 1024 * 1024; // ~50 MB
139
148
 
@@ -423,13 +432,23 @@ function readStdinJson() {
423
432
  * Four buckets, not two (#1244 / schema_version 2): `input_tokens`,
424
433
  * `cache_read_input_tokens`, `cache_creation_input_tokens` and `output_tokens`
425
434
  * are accumulated SEPARATELY per deduped turn, because they are billed at three
426
- * different rates. `model` is captured from `message.model` of the last kept
427
- * block that carries one (null when absent) — it is what makes a cost estimate
428
- * possible at all downstream.
435
+ * different rates. `model` is what makes a cost estimate possible at all
436
+ * downstream, so it names only a model that actually carried tokens (#1470): a
437
+ * kept turn is token-bearing when its four clamped buckets sum to > 0. Exactly
438
+ * one distinct `message.model` across the token-bearing turns → that model;
439
+ * zero-token turns of another model (a trailing `<synthetic>` turn) are ignored.
440
+ * Two or more, or a token-bearing turn that names no model → null, an honest
441
+ * unknown, with the token sums unchanged. No token-bearing turn at all → the
442
+ * last kept block that carries one (null when absent). Two or more models with
443
+ * every token-bearing turn named → `modelsUsage` carries the four buckets per
444
+ * model, so the session rollup can price each part; otherwise it is null.
429
445
  *
430
446
  * @param {string|undefined|null} transcriptPath — absolute path from stdin
431
447
  * @returns {{ tokenInputUncached: number|null, tokenCacheRead: number|null,
432
- * tokenCacheCreation: number|null, tokenOutput: number|null, model: string|null }}
448
+ * tokenCacheCreation: number|null, tokenOutput: number|null, model: string|null,
449
+ * modelsUsage: Array<{ model: string, token_input_uncached: number,
450
+ * token_cache_read: number, token_cache_creation: number,
451
+ * token_output: number }>|null }}
433
452
  */
434
453
  function extractTranscriptUsage(transcriptPath) {
435
454
  const nullResult = {
@@ -438,6 +457,7 @@ function extractTranscriptUsage(transcriptPath) {
438
457
  tokenCacheCreation: null,
439
458
  tokenOutput: null,
440
459
  model: null,
460
+ modelsUsage: null,
441
461
  };
442
462
  try {
443
463
  if (typeof transcriptPath !== 'string' || !transcriptPath.trim()) return nullResult;
@@ -523,22 +543,73 @@ function extractTranscriptUsage(transcriptPath) {
523
543
  let tokenCacheRead = 0;
524
544
  let tokenCacheCreation = 0;
525
545
  let tokenOutput = 0;
546
+ /** Last non-null model over ALL kept turns — the zero-token fallback. */
526
547
  let model = null;
548
+ /** Per-model bucket sums of the token-bearing kept turns (#1470). */
549
+ const billedModels = new Map();
550
+ /** A token-bearing turn that names no model: its price is unknowable. */
551
+ let unattributed = false;
552
+ // Per-turn clamp (#624): a turn's value counts ONLY when it is a non-negative
553
+ // integer. A poisoned value (negative, NaN, float like 10.5) contributes 0 so
554
+ // the good turns survive. An absent side contributes 0, not null.
555
+ const clamp = (value) => (Number.isInteger(value) && value >= 0 ? value : 0);
527
556
  for (const { usage, model: turnModel } of kept) {
528
- // Per-turn clamp (#624): add a turn's value ONLY when it is a non-negative
529
- // integer. A poisoned value (negative, NaN, float like 10.5) is skipped so
530
- // the good turns survive. An absent side contributes 0, not null.
531
- const inTok = usage.input_tokens;
532
- const cacheRead = usage.cache_read_input_tokens;
533
- const cacheCreation = usage.cache_creation_input_tokens;
534
- const outTok = usage.output_tokens;
535
- if (Number.isInteger(inTok) && inTok >= 0) tokenInputUncached += inTok;
536
- if (Number.isInteger(cacheRead) && cacheRead >= 0) tokenCacheRead += cacheRead;
537
- if (Number.isInteger(cacheCreation) && cacheCreation >= 0) tokenCacheCreation += cacheCreation;
538
- if (Number.isInteger(outTok) && outTok >= 0) tokenOutput += outTok;
539
- if (turnModel !== null) model = turnModel;
557
+ const inTok = clamp(usage.input_tokens);
558
+ const cacheRead = clamp(usage.cache_read_input_tokens);
559
+ const cacheCreation = clamp(usage.cache_creation_input_tokens);
560
+ const outTok = clamp(usage.output_tokens);
561
+ tokenInputUncached += inTok;
562
+ tokenCacheRead += cacheRead;
563
+ tokenCacheCreation += cacheCreation;
564
+ tokenOutput += outTok;
565
+ const billed = inTok + cacheRead + cacheCreation + outTok > 0;
566
+ if (turnModel === null) {
567
+ if (billed) unattributed = true;
568
+ continue;
569
+ }
570
+ model = turnModel;
571
+ if (!billed) continue;
572
+ let part = billedModels.get(turnModel);
573
+ if (part === undefined) {
574
+ part = {
575
+ model: turnModel,
576
+ token_input_uncached: 0,
577
+ token_cache_read: 0,
578
+ token_cache_creation: 0,
579
+ token_output: 0,
580
+ };
581
+ billedModels.set(turnModel, part);
582
+ }
583
+ part.token_input_uncached += inTok;
584
+ part.token_cache_read += cacheRead;
585
+ part.token_cache_creation += cacheCreation;
586
+ part.token_output += outTok;
540
587
  }
541
588
 
589
+ // Model attribution (#1470): only a token-bearing turn is an observation of
590
+ // its model; one distinct model → that model, two or more → null, none →
591
+ // the fallback above. A token-bearing turn that names no model also gives
592
+ // null: its tokens must not be priced at whichever other model was named.
593
+ // A mixed-model record carries its per-model sums as `modelsUsage`, which
594
+ // the session rollup prices part by part (#1470). Measured 2026-09-29 over
595
+ // 10,745 subagent transcripts under `~/.claude/projects`: 17 (0.16%)
596
+ // contained more than one model on token-bearing turns (0 of 917 in this
597
+ // repo), while 273 contained more than one model id only through zero-token
598
+ // `<synthetic>` turns, which this rule ignores. A model-less token-bearing
599
+ // turn gets no breakdown: its tokens belong to no part, so the record stays
600
+ // unpriced. The ledger now tells a mixed-model null (`models_usage`
601
+ // present) from a missing model (absent). The fallback also names the LAST
602
+ // model of a transcript whose turns all carry 0 tokens — measured 2026-09-29,
603
+ // 31 of 10,479 records, all `<synthetic>`; the session rollup prices a record
604
+ // whose four buckets are all 0 at $0 regardless of its model (#1474), so that
605
+ // name is harmless.
606
+ let modelsUsage = null;
607
+ if (unattributed) model = null;
608
+ else if (billedModels.size > 1) {
609
+ model = null;
610
+ modelsUsage = [...billedModels.values()];
611
+ } else if (billedModels.size === 1) [model] = billedModels.keys();
612
+
542
613
  // The aggregates are guaranteed non-negative integers by per-turn clamping
543
614
  // above (Σ of non-negative integers), so emit them directly.
544
615
  return {
@@ -547,6 +618,7 @@ function extractTranscriptUsage(transcriptPath) {
547
618
  tokenCacheCreation,
548
619
  tokenOutput,
549
620
  model,
621
+ modelsUsage,
550
622
  };
551
623
  } catch {
552
624
  return nullResult;
@@ -752,7 +824,7 @@ async function main() {
752
824
  // NO fallback to input.transcript_path: that path is the parent session
753
825
  // transcript, and reading it is the #949 defect (every stop inherited the
754
826
  // parent's running totals). A phantom stop gets null — the honest value.
755
- const { tokenInputUncached, tokenCacheRead, tokenCacheCreation, tokenOutput, model } =
827
+ const { tokenInputUncached, tokenCacheRead, tokenCacheCreation, tokenOutput, model, modelsUsage } =
756
828
  subagentTranscriptFound
757
829
  ? extractTranscriptUsage(subagentTranscriptPath)
758
830
  : {
@@ -761,6 +833,7 @@ async function main() {
761
833
  tokenCacheCreation: null,
762
834
  tokenOutput: null,
763
835
  model: null,
836
+ modelsUsage: null,
764
837
  };
765
838
 
766
839
  // schema_version 2 (#1244): `token_input` is now BILLABLE PROMPT VOLUME —
@@ -776,11 +849,15 @@ async function main() {
776
849
  }
777
850
  if (tokenOutput !== null) record.token_output = tokenOutput;
778
851
 
779
- // Model id (#1244) — null when the transcript exposes none. Cost is NOT
852
+ // Model id (#1244) — null when the transcript exposes none, or when its
853
+ // token-bearing turns are not attributable to one model (#1470). Cost is NOT
780
854
  // computed here: pricing lives in scripts/lib/telemetry/pricing.mjs and is
781
855
  // applied by the session rollup, so this hot-path hook keeps its import
782
856
  // graph unchanged.
783
857
  record.model = model;
858
+ // Per-model breakdown (#1470) — written only for a mixed-model record, so
859
+ // the rollup can price it part by part; absent on every other record.
860
+ if (modelsUsage !== null) record.models_usage = modelsUsage;
784
861
 
785
862
  // Cost is best-effort / forward-compat (#624): the native transcript does
786
863
  // NOT expose total_cost_usd today, so this is null in practice. No rate
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "session-orchestrator",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "A repeatable Plan, Go, Close workflow for AI coding sessions: /session reads your repo and agrees the scope, /go runs the work in waves with a quality gate between each, /close verifies and commits. Runs on Claude Code, Codex CLI, Cursor and Pi.",
5
5
  "type": "module",
6
6
  "homepage": "https://session-orchestrator.com",
@@ -94,8 +94,8 @@
94
94
  },
95
95
  "overrides": {
96
96
  "vite": "^8.0.16",
97
- "fast-uri": "^3.1.5",
98
- "brace-expansion": "^5.0.9"
97
+ "fast-uri": "^3.1.8",
98
+ "brace-expansion": "^5.0.12"
99
99
  },
100
100
  "license": "MIT",
101
101
  "repository": {
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: "Fleet coordinator persona for sessions running side by side on one host: it measures resources, pipelines and merge readiness itself, writes conditions (\"Auflagen\") as files, starts headless runs behind slot and busy gates, and grants no approvals. Operator-only, invoke as /session-orchestrator:navigator ticker|status|start|fenster|handover."
3
+ argument-hint: "[ticker|status|start|fenster|handover]"
4
+ ---
5
+
6
+ # /navigator
7
+
8
+ Use the Session Orchestrator skill definition at `skills/navigator/SKILL.md`.
9
+
10
+ Arguments: $@
11
+
12
+ Read that skill file and follow it exactly. When it references `$ARGUMENTS`, substitute the arguments above. Keep all Session Orchestrator platform fallbacks intact.
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: "Use when writing, reviewing, or pruning tests. Three modes, one value bar: a four-question gate before any new test is written, a focused audit of one scope, and a campaign over a whole repo or subsystem that removes the least useful tests under a coverage guard. Every delete, merge, or repair carries written evidence and a caught mutation. Triggered by \"audit the tests\", \"prune the test suite\", \"remove low-value tests\", \"test diet\", \"is this test worth adding\", /test-audit."
3
+ argument-hint: "[gate|audit|campaign] [scope] [--goal \\\"<goal>\\\"]"
4
+ ---
5
+
6
+ # /test-audit
7
+
8
+ Use the Session Orchestrator skill definition at `skills/test-audit/SKILL.md`.
9
+
10
+ Arguments: $@
11
+
12
+ Read that skill file and follow it exactly. When it references `$ARGUMENTS`, substitute the arguments above. Keep all Session Orchestrator platform fallbacks intact.
package/rules/README.md CHANGED
@@ -11,7 +11,12 @@ It is **not** the always-on rule set of *this* repository — those live in
11
11
 
12
12
  Every rule file here carries a
13
13
  `<!-- source: session-orchestrator plugin (canonical: rules/<path>) -->` header.
14
- On sync, plugin-sourced files are overwritten in the consumer while its
14
+ In a rule with frontmatter it stands on the first line directly after the
15
+ closing `---` — the frontmatter itself must open on line 1, because Claude Code
16
+ reads a rule's frontmatter only there. A rule without frontmatter carries the
17
+ header on line 1. A path-scoped rule declares its file patterns twice, as
18
+ `globs:` and `paths:` with identical lists: `paths:` is the only key Claude Code
19
+ reads, `globs:` is what `rule-loader.mjs` reads first (#1449). On sync, plugin-sourced files are overwritten in the consumer while its
15
20
  locally-authored rules are preserved (copy-on-write). The canonical manifest of
16
21
  what vendors where is [`_index.md`](./_index.md).
17
22
 
package/rules/_index.md CHANGED
@@ -40,7 +40,7 @@ baseline project type (`nextjs-saas`, `express-service`, `docker-service`,
40
40
  - `always-on/build-value.md` — BV-001..004: the seven-rung build ladder, the four protections never simplified away
41
41
  - `always-on/cross-session-messaging.md` — CSM-001..005: messaging is transport, not shared state; no permission laundering
42
42
  - `always-on/loop-and-monitor.md` — LM-001..008: routing between `/goal`, Workflows, Channels, Monitor, `/loop`, and Routines
43
- - `always-on/bash-harness-pitfalls.md` — six false-green shell-harness failure classes (path-scoped via its own `globs:`/`paths:` frontmatter)
43
+ - `always-on/bash-harness-pitfalls.md` — six false-green shell-harness failure classes (path-scoped via `globs:` + `paths:` frontmatter carrying identical lists — `paths:` is what Claude Code reads, `globs:` what `rule-loader.mjs` reads first; #1449)
44
44
 
45
45
  ## opt-in-stack (vendored on match)
46
46
 
@@ -52,8 +52,8 @@ baseline project type (`nextjs-saas`, `express-service`, `docker-service`,
52
52
 
53
53
  ## opt-in-domain (vendored on match)
54
54
 
55
- - `opt-in-domain/prompt-caching.md` — Anthropic prompt caching (breakpoint placement, TTL selection, pre-warming, verification) [archetypes: nextjs-saas, express-service, docker-service, monorepo-oss, cli-tool]
55
+ - `opt-in-domain/prompt-caching.md` — Anthropic prompt caching (breakpoint placement, TTL selection, pre-warming, verification) [archetypes: nextjs-saas, express-service, docker-service, monorepo-oss]
56
56
 
57
57
  ## Sync mechanism
58
58
 
59
- Consumer repos receive these files via `/bootstrap --sync-rules`. Re-running the command syncs every manifest category that has entries: universal entries always vendor, and archetype-tagged entries vendor only when the consumer repo's resolved archetype matches. Plugin-sourced files are overwritten while local rules are preserved (copy-on-write via the `<!-- source: session-orchestrator plugin ... -->` header on plugin files). Category entries must not share a basename, because all synced files flatten into `.claude/rules/`.
59
+ Consumer repos receive these files via `/bootstrap --sync-rules`. Re-running the command syncs every manifest category that has entries: universal entries always vendor, and archetype-tagged entries vendor only when the consumer repo's resolved archetype matches. Plugin-sourced files are overwritten while local rules are preserved (copy-on-write via the `<!-- source: session-orchestrator plugin ... -->` header on plugin files). That header stands on the first line directly after the closing `---` of a rule's frontmatter, because Claude Code reads frontmatter only when it opens on line 1; only a rule without frontmatter carries it on line 1 (#1449). A consumer copy written in the older format (header on line 1, frontmatter after it) still counts as plugin-owned and is rewritten into the current format on the next sync. Category entries must not share a basename, because all synced files flatten into `.claude/rules/`.
@@ -1,4 +1,3 @@
1
- <!-- source: session-orchestrator plugin (canonical: rules/always-on/bash-harness-pitfalls.md) -->
2
1
  ---
3
2
  globs:
4
3
  - "**/*.sh"
@@ -6,8 +5,15 @@ globs:
6
5
  - scripts/**
7
6
  - tests/**
8
7
  - .husky/**
8
+ paths:
9
+ - "**/*.sh"
10
+ - "**/*.bash"
11
+ - scripts/**
12
+ - tests/**
13
+ - .husky/**
9
14
  tier: wave-only
10
15
  ---
16
+ <!-- source: session-orchestrator plugin (canonical: rules/always-on/bash-harness-pitfalls.md) -->
11
17
  # Bash / Shell-Harness Pitfalls (Path-scoped)
12
18
 
13
19
  Six recurring bash-harness failure classes, each surfaced by a live run rather
@@ -1,11 +1,15 @@
1
- <!-- source: session-orchestrator plugin (canonical: rules/opt-in-domain/prompt-caching.md) -->
2
1
  ---
3
2
  globs:
4
3
  - "**/lib/ai/**"
5
4
  - "**/lib/llm/**"
6
5
  - "**/providers/**"
6
+ paths:
7
+ - "**/lib/ai/**"
8
+ - "**/lib/llm/**"
9
+ - "**/providers/**"
7
10
  tier: wave-only
8
11
  ---
12
+ <!-- source: session-orchestrator plugin (canonical: rules/opt-in-domain/prompt-caching.md) -->
9
13
  # Prompt Caching Rules (Path-scoped — repos using `@anthropic-ai/sdk` or `@ai-sdk/anthropic`)
10
14
 
11
15
  > Path-scoped — applies anywhere a project imports `@anthropic-ai/sdk` or uses the `@ai-sdk/anthropic` provider. Out of scope: `session-orchestrator` itself (no SDK use; `backend.md` § "AI Provider Abstraction" already forbids direct SDK imports in business logic, and the orchestrator runs inside Claude Code's harness which manages caching at the platform layer).
@@ -1,4 +1,3 @@
1
- <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/backend-data.md) -->
2
1
  ---
3
2
  globs:
4
3
  - src/lib/db/**
@@ -8,8 +7,17 @@ globs:
8
7
  - migrations/**
9
8
  - src/lib/redis/**
10
9
  - src/lib/queue/**
10
+ paths:
11
+ - src/lib/db/**
12
+ - src/lib/cache/**
13
+ - src/services/db/**
14
+ - supabase/**
15
+ - migrations/**
16
+ - src/lib/redis/**
17
+ - src/lib/queue/**
11
18
  tier: wave-only
12
19
  ---
20
+ <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/backend-data.md) -->
13
21
  # Backend Data Rules (Path-scoped)
14
22
 
15
23
  ## Database (Supabase)
@@ -1,4 +1,3 @@
1
- <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/backend.md) -->
2
1
  ---
3
2
  globs:
4
3
  - src/app/**
@@ -6,8 +5,15 @@ globs:
6
5
  - src/lib/api/**
7
6
  - src/routes/**
8
7
  - src/app/api/**
8
+ paths:
9
+ - src/app/**
10
+ - src/services/**
11
+ - src/lib/api/**
12
+ - src/routes/**
13
+ - src/app/api/**
9
14
  tier: wave-only
10
15
  ---
16
+ <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/backend.md) -->
11
17
  # Backend Rules (Path-scoped)
12
18
 
13
19
  ## Server Actions (Next.js)
@@ -1,12 +1,17 @@
1
- <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/frontend.md) -->
2
1
  ---
3
2
  globs:
4
3
  - src/**/*.tsx
5
4
  - src/**/*.css
6
5
  - src/**/*.module.css
7
6
  - "**/components/**/*.{ts,tsx}"
7
+ paths:
8
+ - src/**/*.tsx
9
+ - src/**/*.css
10
+ - src/**/*.module.css
11
+ - "**/components/**/*.{ts,tsx}"
8
12
  tier: wave-only
9
13
  ---
14
+ <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/frontend.md) -->
10
15
  # Frontend Rules (Path-scoped)
11
16
 
12
17
  ## React & Next.js
@@ -1,4 +1,3 @@
1
- <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/security-web.md) -->
2
1
  ---
3
2
  globs:
4
3
  - src/middleware*.ts
@@ -6,8 +5,15 @@ globs:
6
5
  - next.config.*
7
6
  - src/lib/csp*
8
7
  - src/lib/cors*
8
+ paths:
9
+ - src/middleware*.ts
10
+ - src/app/**
11
+ - next.config.*
12
+ - src/lib/csp*
13
+ - src/lib/cors*
9
14
  tier: wave-only
10
15
  ---
16
+ <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/security-web.md) -->
11
17
 
12
18
  # Security — Web & API (Path-scoped)
13
19
 
@@ -1,11 +1,15 @@
1
- <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/swift.md) -->
2
1
  ---
3
2
  globs:
4
3
  - "**/*.swift"
5
4
  - "**/Package.swift"
6
5
  - "**/*.xcodeproj/**"
6
+ paths:
7
+ - "**/*.swift"
8
+ - "**/Package.swift"
9
+ - "**/*.xcodeproj/**"
7
10
  tier: wave-only
8
11
  ---
12
+ <!-- source: session-orchestrator plugin (canonical: rules/opt-in-stack/swift.md) -->
9
13
  # Swift Rules (Path-scoped)
10
14
 
11
15
  ## Language & Style