session-orchestrator 3.22.0 → 3.24.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 (316) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.cursor/commands/autopilot-multi.md +14 -0
  5. package/.cursor/commands/autopilot.md +14 -0
  6. package/.cursor/commands/bootstrap.md +14 -0
  7. package/.cursor/commands/brainstorm.md +14 -0
  8. package/.cursor/commands/close.md +13 -0
  9. package/.cursor/commands/contract-version-bump.md +14 -0
  10. package/.cursor/commands/debug.md +14 -0
  11. package/.cursor/commands/discovery.md +14 -0
  12. package/.cursor/commands/dispatcher.md +14 -0
  13. package/.cursor/commands/eli5.md +14 -0
  14. package/.cursor/commands/eval.md +14 -0
  15. package/.cursor/commands/evolve.md +14 -0
  16. package/.cursor/commands/go.md +14 -0
  17. package/.cursor/commands/grill.md +14 -0
  18. package/.cursor/commands/harness-audit.md +13 -0
  19. package/.cursor/commands/journey-audit.md +14 -0
  20. package/.cursor/commands/memory-cleanup.md +14 -0
  21. package/.cursor/commands/persona-panel.md +14 -0
  22. package/.cursor/commands/plan.md +14 -0
  23. package/.cursor/commands/portfolio.md +14 -0
  24. package/.cursor/commands/reconcile.md +14 -0
  25. package/.cursor/commands/release.md +14 -0
  26. package/.cursor/commands/repo-audit.md +13 -0
  27. package/.cursor/commands/session.md +14 -0
  28. package/.cursor/commands/spinout.md +14 -0
  29. package/.cursor/commands/sunset-review.md +14 -0
  30. package/.cursor/commands/templates-ack.md +14 -0
  31. package/.cursor/commands/test.md +14 -0
  32. package/.cursor/hooks.json +60 -0
  33. package/.cursor/rules/000-session-orchestrator.mdc +8 -0
  34. package/.cursor/rules/010-session-workflow.mdc +9 -1
  35. package/.cursor/rules/020-quality-gates.mdc +1 -1
  36. package/.cursor/rules/030-wave-execution.mdc +1 -1
  37. package/.cursor/rules/050-plan.mdc +2 -2
  38. package/.cursor/rules/070-gitlab-ops.mdc +73 -57
  39. package/.cursor/rules/080-ecosystem-health.mdc +7 -7
  40. package/.cursor/skills/architecture/SKILL.md +13 -0
  41. package/.cursor/skills/autopilot/SKILL.md +12 -0
  42. package/.cursor/skills/bootstrap/SKILL.md +12 -0
  43. package/.cursor/skills/brainstorm/SKILL.md +13 -0
  44. package/.cursor/skills/claude-md-drift-check/SKILL.md +13 -0
  45. package/.cursor/skills/contract-version-bump/SKILL.md +12 -0
  46. package/.cursor/skills/convergence-monitoring/SKILL.md +12 -0
  47. package/.cursor/skills/daily/SKILL.md +12 -0
  48. package/.cursor/skills/debug/SKILL.md +13 -0
  49. package/.cursor/skills/discovery/SKILL.md +13 -0
  50. package/.cursor/skills/dispatcher/SKILL.md +13 -0
  51. package/.cursor/skills/docs-orchestrator/SKILL.md +13 -0
  52. package/.cursor/skills/domain-model/SKILL.md +13 -0
  53. package/.cursor/skills/ecosystem-health/SKILL.md +13 -0
  54. package/.cursor/skills/eli5/SKILL.md +13 -0
  55. package/.cursor/skills/eval/SKILL.md +12 -0
  56. package/.cursor/skills/evolve/SKILL.md +13 -0
  57. package/.cursor/skills/frontmatter-guard/SKILL.md +13 -0
  58. package/.cursor/skills/gitlab-ops/SKILL.md +13 -0
  59. package/.cursor/skills/gitlab-portfolio/SKILL.md +13 -0
  60. package/.cursor/skills/grill/SKILL.md +13 -0
  61. package/.cursor/skills/hook-development/SKILL.md +13 -0
  62. package/.cursor/skills/journey-audit/SKILL.md +13 -0
  63. package/.cursor/skills/mcp-builder/SKILL.md +13 -0
  64. package/.cursor/skills/memory-cleanup/SKILL.md +12 -0
  65. package/.cursor/skills/mode-selector/SKILL.md +13 -0
  66. package/.cursor/skills/npm-publish/SKILL.md +12 -0
  67. package/.cursor/skills/peekaboo-driver/SKILL.md +13 -0
  68. package/.cursor/skills/persona-panel/SKILL.md +12 -0
  69. package/.cursor/skills/plan/SKILL.md +13 -0
  70. package/.cursor/skills/playwright-driver/SKILL.md +13 -0
  71. package/.cursor/skills/quality-gates/SKILL.md +13 -0
  72. package/.cursor/skills/reconcile/SKILL.md +12 -0
  73. package/.cursor/skills/remote-offload/SKILL.md +13 -0
  74. package/.cursor/skills/repo-audit/SKILL.md +13 -0
  75. package/.cursor/skills/session-end/SKILL.md +13 -0
  76. package/.cursor/skills/session-plan/SKILL.md +13 -0
  77. package/.cursor/skills/session-start/SKILL.md +13 -0
  78. package/.cursor/skills/skill-creator/SKILL.md +13 -0
  79. package/.cursor/skills/spinout/SKILL.md +12 -0
  80. package/.cursor/skills/sunset-review/SKILL.md +13 -0
  81. package/.cursor/skills/test-runner/SKILL.md +13 -0
  82. package/.cursor/skills/tmux-layout/SKILL.md +13 -0
  83. package/.cursor/skills/ubiquitous-language/SKILL.md +13 -0
  84. package/.cursor/skills/using-orchestrator/SKILL.md +13 -0
  85. package/.cursor/skills/vault-mirror/SKILL.md +13 -0
  86. package/.cursor/skills/vault-sync/SKILL.md +13 -0
  87. package/.cursor/skills/wave-executor/SKILL.md +13 -0
  88. package/.cursor/skills/write-executable-plan/SKILL.md +13 -0
  89. package/.mcp.json +4 -1
  90. package/CHANGELOG.md +446 -0
  91. package/README.md +22 -17
  92. package/agents/AGENTS.md +23 -4
  93. package/agents/code-implementer.md +2 -1
  94. package/agents/db-specialist.md +2 -2
  95. package/agents/docs-writer.md +3 -1
  96. package/agents/eval-judge.md +1 -1
  97. package/agents/session-reviewer.md +7 -1
  98. package/agents/test-writer.md +2 -1
  99. package/agents/ui-developer.md +2 -1
  100. package/commands/bootstrap.md +2 -2
  101. package/commands/close.md +3 -1
  102. package/commands/go.md +1 -1
  103. package/commands/journey-audit.md +43 -0
  104. package/docs/USER-GUIDE.md +2 -2
  105. package/docs/ci-setup.md +194 -25
  106. package/docs/codex-setup.md +64 -0
  107. package/docs/components.md +7 -7
  108. package/docs/cursor-setup.md +26 -47
  109. package/docs/events-schema.md +120 -10
  110. package/docs/github-mirror-protection.md +197 -0
  111. package/docs/pi-setup.md +2 -0
  112. package/docs/rule-authoring.md +3 -1
  113. package/docs/scope-collision-guard.md +49 -2
  114. package/docs/session-config-reference.md +89 -9
  115. package/docs/session-config-template.md +38 -7
  116. package/docs/telemetry/telemetry-claims.md +11 -10
  117. package/docs/telemetry.md +52 -1
  118. package/hooks/_lib/atomic-json.mjs +111 -0
  119. package/hooks/_lib/lock-bootstrap.mjs +8 -4
  120. package/hooks/_lib/subagent-paths.mjs +143 -0
  121. package/hooks/_lib/vcs-create-matcher.mjs +397 -38
  122. package/hooks/cwd-change-restore.mjs +9 -29
  123. package/hooks/enforce-scope.mjs +93 -0
  124. package/hooks/hooks-codex.json +1 -1
  125. package/hooks/hooks-cursor.json +201 -20
  126. package/hooks/hooks-pi.json +1 -1
  127. package/hooks/hooks.json +2 -2
  128. package/hooks/on-session-end.mjs +486 -19
  129. package/hooks/on-session-start.mjs +263 -12
  130. package/hooks/on-stop.mjs +392 -24
  131. package/hooks/post-bash-write-verify.mjs +104 -4
  132. package/hooks/post-subagent-discovery-validator.mjs +182 -21
  133. package/hooks/post-tool-batch-wave-signal.mjs +165 -42
  134. package/hooks/post-tool-failure-corrective-context.mjs +9 -32
  135. package/hooks/pre-bash-issue-budget.mjs +117 -4
  136. package/hooks/pre-bash-memory-propose-audit.mjs +13 -7
  137. package/hooks/pre-bash-sessions-ledger-guard.mjs +159 -0
  138. package/hooks/pre-bash-staging-fence.mjs +4 -0
  139. package/hooks/pre-task-scope-disjoint.mjs +368 -35
  140. package/hooks/skill-invocation-telemetry.mjs +21 -10
  141. package/hooks/subagent-telemetry.mjs +11 -26
  142. package/monitors/monitors.json +6 -0
  143. package/package.json +1 -1
  144. package/pi/prompts/journey-audit.md +12 -0
  145. package/rules/_index.md +9 -1
  146. package/rules/always-on/ask-via-tool.md +62 -0
  147. package/rules/always-on/bash-harness-pitfalls.md +168 -0
  148. package/rules/always-on/build-value.md +47 -0
  149. package/rules/always-on/cross-session-messaging.md +59 -0
  150. package/rules/always-on/loop-and-monitor.md +221 -0
  151. package/rules/always-on/parallel-sessions.md +142 -12
  152. package/rules/always-on/receiving-review.md +108 -0
  153. package/rules/always-on/test-value.md +40 -0
  154. package/rules/always-on/verification-before-completion.md +77 -0
  155. package/scripts/archive-closed-prds.mjs +258 -18
  156. package/scripts/autopilot.mjs +31 -12
  157. package/scripts/backfill-abandoned-sessions.mjs +80 -11
  158. package/scripts/backfill-evidence-digest.mjs +376 -0
  159. package/scripts/cursor-install.mjs +89 -48
  160. package/scripts/emit-event.mjs +10 -2
  161. package/scripts/export-hw-learnings.mjs +143 -2
  162. package/scripts/express-path.mjs +299 -0
  163. package/scripts/generate-cursor-adapter.mjs +253 -0
  164. package/scripts/github-protection-audit.mjs +358 -0
  165. package/scripts/lib/auq/parse.mjs +5 -29
  166. package/scripts/lib/auto-dialectic.mjs +68 -0
  167. package/scripts/lib/autopilot/worktree-pipeline.mjs +318 -18
  168. package/scripts/lib/build-live-signals.mjs +49 -27
  169. package/scripts/lib/ci-status-banner.mjs +158 -11
  170. package/scripts/lib/cold-start-detector.mjs +23 -14
  171. package/scripts/lib/command-blocker.mjs +70 -0
  172. package/scripts/lib/config/block-header.mjs +55 -0
  173. package/scripts/lib/config/discovery-validator.mjs +7 -2
  174. package/scripts/lib/config/health-endpoints.mjs +383 -0
  175. package/scripts/lib/config/reconcile.mjs +79 -4
  176. package/scripts/lib/config/remote-hosts.mjs +233 -0
  177. package/scripts/lib/config/section-extractor.mjs +235 -36
  178. package/scripts/lib/config-schema.mjs +9 -1
  179. package/scripts/lib/config.mjs +87 -8
  180. package/scripts/lib/convergence-monitor.mjs +13 -2
  181. package/scripts/lib/cursor-hook-bridge.mjs +443 -0
  182. package/scripts/lib/dispatcher/cli.mjs +2 -2
  183. package/scripts/lib/dispatcher/enumerate.mjs +2 -17
  184. package/scripts/lib/events-schema.mjs +48 -0
  185. package/scripts/lib/events.mjs +238 -5
  186. package/scripts/lib/evolve/autonomy-verdict.mjs +9 -4
  187. package/scripts/lib/evolve/autopilot-effectiveness.mjs +18 -1
  188. package/scripts/lib/express-path.mjs +327 -0
  189. package/scripts/lib/file-lock.mjs +22 -4
  190. package/scripts/lib/gates/gate-full.mjs +81 -8
  191. package/scripts/lib/gates/gate-helpers.mjs +76 -15
  192. package/scripts/lib/git-config-drift.mjs +134 -5
  193. package/scripts/lib/gitlab-portfolio/cli.mjs +3 -15
  194. package/scripts/lib/harness-audit/categories/category1.mjs +17 -6
  195. package/scripts/lib/host-identity.mjs +247 -2
  196. package/scripts/lib/instruction-budget-guard.mjs +31 -1
  197. package/scripts/lib/issue-budget.mjs +229 -30
  198. package/scripts/lib/learnings/io.mjs +55 -10
  199. package/scripts/lib/learnings/schema.mjs +95 -28
  200. package/scripts/lib/lock-reaper.mjs +7 -1
  201. package/scripts/lib/locks/staging-fence-lock.mjs +5 -1
  202. package/scripts/lib/locks/state-md-lock.mjs +8 -1
  203. package/scripts/lib/memory-banner.mjs +25 -10
  204. package/scripts/lib/memory-paths.mjs +15 -6
  205. package/scripts/lib/mode-selector/scoring.mjs +53 -6
  206. package/scripts/lib/peer-discovery.mjs +20 -2
  207. package/scripts/lib/platform.mjs +72 -9
  208. package/scripts/lib/plugin-root.mjs +143 -19
  209. package/scripts/lib/project-hygiene.mjs +43 -3
  210. package/scripts/lib/quality-gate.mjs +271 -13
  211. package/scripts/lib/reconcile/emitter.mjs +87 -19
  212. package/scripts/lib/reconcile/engine.mjs +517 -18
  213. package/scripts/lib/reconcile/idempotency.mjs +102 -1
  214. package/scripts/lib/reconcile/renderer.mjs +148 -3
  215. package/scripts/lib/reconcile/sanitize.mjs +40 -17
  216. package/scripts/lib/reconcile/writer.mjs +415 -84
  217. package/scripts/lib/rule-loader.mjs +37 -2
  218. package/scripts/lib/rules-sync.mjs +51 -8
  219. package/scripts/lib/scope-gate.mjs +126 -0
  220. package/scripts/lib/session-close-backfill.mjs +427 -37
  221. package/scripts/lib/session-discovery.mjs +69 -5
  222. package/scripts/lib/session-end/phase-skip.mjs +38 -5
  223. package/scripts/lib/session-end/worktree-cleanup.mjs +154 -7
  224. package/scripts/lib/session-id.mjs +30 -14
  225. package/scripts/lib/session-identity/own-session.mjs +220 -0
  226. package/scripts/lib/session-lock.mjs +85 -30
  227. package/scripts/lib/session-schema/normalizer.mjs +70 -3
  228. package/scripts/lib/session-schema/validator.mjs +40 -0
  229. package/scripts/lib/session-start-probes.mjs +608 -0
  230. package/scripts/lib/session-transition.mjs +277 -0
  231. package/scripts/lib/sessions-canonical.mjs +446 -0
  232. package/scripts/lib/sessions-staleness-banner.mjs +124 -57
  233. package/scripts/lib/spiral-carryover.mjs +90 -9
  234. package/scripts/lib/state-md/frontmatter-mutators.mjs +41 -8
  235. package/scripts/lib/state-md/mission-status.mjs +350 -52
  236. package/scripts/lib/state-md/yaml-parser.mjs +145 -16
  237. package/scripts/lib/state-md.mjs +12 -2
  238. package/scripts/lib/telemetry/schema.mjs +74 -8
  239. package/scripts/lib/telemetry/sync.mjs +91 -16
  240. package/scripts/lib/tmux-layout/telemetry.mjs +14 -2
  241. package/scripts/lib/validate/check-agents.mjs +66 -0
  242. package/scripts/lib/validate/check-cursor-adapter.mjs +102 -0
  243. package/scripts/lib/validate/check-dead-bridge.mjs +24 -2
  244. package/scripts/lib/validate/check-doc-cli-commands.mjs +25 -65
  245. package/scripts/lib/validate/check-hooks-emit-event-guard.mjs +370 -0
  246. package/scripts/lib/validate/check-hooks-symmetry.mjs +29 -63
  247. package/scripts/lib/validate/check-playwright-mcp-canary.mjs +13 -22
  248. package/scripts/lib/validate/check-plugin-monitors.mjs +10 -4
  249. package/scripts/lib/validate/check-skill-script-paths.mjs +436 -0
  250. package/scripts/lib/validate/check-test-value-bans.mjs +165 -17
  251. package/scripts/lib/validate/check-untracked-test-deps.mjs +10 -0
  252. package/scripts/lib/validate/check-unwired-features.mjs +333 -32
  253. package/scripts/lib/validate/check-validator-registration.mjs +248 -0
  254. package/scripts/lib/validate/check-vcs-repo-flag.mjs +6 -28
  255. package/scripts/lib/validate/markdown-fences.mjs +196 -0
  256. package/scripts/lib/validate/repo-files.mjs +275 -0
  257. package/scripts/lib/validate-vendored-rules.mjs +229 -7
  258. package/scripts/lib/vault-mirror/process.mjs +99 -43
  259. package/scripts/lib/vault-mirror/telemetry.mjs +210 -0
  260. package/scripts/lib/vault-staleness-banner.mjs +76 -6
  261. package/scripts/lib/vault-status/board-lock.mjs +185 -0
  262. package/scripts/lib/vault-status/board-writer.mjs +381 -141
  263. package/scripts/lib/vault-status/narrative-mirror.mjs +190 -27
  264. package/scripts/lib/wave-executor/foreign-dispatch.mjs +832 -0
  265. package/scripts/lib/wave-executor/remote-dispatch.mjs +504 -0
  266. package/scripts/lib/wave-resource-gate.mjs +127 -7
  267. package/scripts/lib/wave-transcript-tail.mjs +889 -0
  268. package/scripts/materialize-wave-scope.mjs +228 -15
  269. package/scripts/mcp-server.sh +11 -2
  270. package/scripts/memory-propose.mjs +132 -8
  271. package/scripts/parse-config.mjs +65 -0
  272. package/scripts/promote-vault-strict.mjs +4 -15
  273. package/scripts/site-numbers.mjs +36 -4
  274. package/scripts/token-audit.sh +9 -2
  275. package/scripts/validate-plugin.mjs +29 -0
  276. package/scripts/validate-wave-scope.mjs +67 -0
  277. package/scripts/vault-consolidate.mjs +3 -11
  278. package/scripts/vault-integration-watcher.mjs +2 -4
  279. package/scripts/vault-mirror.mjs +305 -51
  280. package/skills/_shared/monitor-patterns.md +31 -5
  281. package/skills/_shared/parallel-aware-auq.md +31 -2
  282. package/skills/_shared/parallel-aware-preamble.md +19 -4
  283. package/skills/_shared/platform-tools.md +11 -5
  284. package/skills/_shared/state-ownership.md +29 -2
  285. package/skills/autopilot/SKILL.md +5 -1
  286. package/skills/bootstrap/SKILL.md +3 -3
  287. package/skills/bootstrap/_shared-template.md +18 -10
  288. package/skills/bootstrap/deep-template.md +10 -6
  289. package/skills/bootstrap/fast-template.md +15 -8
  290. package/skills/bootstrap/standard-template.md +10 -6
  291. package/skills/claude-md-drift-check/checker.mjs +39 -11
  292. package/skills/contract-version-bump/SKILL.md +1 -1
  293. package/skills/dispatcher/SKILL.md +1 -1
  294. package/skills/ecosystem-health/SKILL.md +4 -1
  295. package/skills/ecosystem-health/wizard.md +5 -0
  296. package/skills/evolve/SKILL.md +38 -1
  297. package/skills/journey-audit/SKILL.md +270 -0
  298. package/skills/peekaboo-driver/SKILL.md +15 -3
  299. package/skills/persona-panel/SKILL.md +1 -1
  300. package/skills/reconcile/SKILL.md +46 -3
  301. package/skills/remote-offload/SKILL.md +89 -0
  302. package/skills/session-end/SKILL.md +17 -4
  303. package/skills/session-end/metrics-collection.md +7 -4
  304. package/skills/session-end/phase-3-6-tail.md +20 -9
  305. package/skills/session-end/phase-3-7a-recommendations.md +16 -2
  306. package/skills/session-plan/SKILL.md +6 -1
  307. package/skills/session-plan/wave-template.md +1 -0
  308. package/skills/session-start/SKILL.md +54 -17
  309. package/skills/session-start/phase-7-5-mode-selector.md +15 -3
  310. package/skills/session-start/phase-8-5-express-path.md +77 -12
  311. package/skills/vault-sync/validator.mjs +31 -0
  312. package/skills/wave-executor/SKILL.md +5 -3
  313. package/skills/wave-executor/circuit-breaker.md +34 -9
  314. package/skills/wave-executor/wave-loop.md +143 -22
  315. package/templates/_shared/journey-manifest.md +110 -0
  316. package/templates/_shared/rules/parallel-sessions.md +0 -77
@@ -3,7 +3,7 @@ name: code-implementer
3
3
  description: 'Use this agent for feature implementation, API development, refactoring, and general code changes. Handles backend logic, API routes, service layers, and cross-cutting concerns. <example>Context: Wave plan assigns a new API endpoint implementation. user: "Implement CRUD API for invoices" assistant: "I''ll dispatch the code-implementer agent to build the invoice API endpoints." <commentary>Feature implementation with multiple files is the code-implementer''s core strength.</commentary></example> <example>Context: Refactoring task in an implementation wave. user: "Extract shared validation logic into a utility module" assistant: "I''ll use the code-implementer to extract and refactor the validation logic." <commentary>Cross-file refactoring requires systematic reading, extraction, and verification.</commentary></example>'
4
4
  model: inherit
5
5
  color: green
6
- tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
6
+ tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*), SendMessage
7
7
  sandbox-tier: repo-write
8
8
  output-schema: schemas/code-implementer.schema.json
9
9
  ---
@@ -37,6 +37,7 @@ You are a focused implementation agent. You write production code, refactor exis
37
37
  - Do NOT add standalone or narrative documentation (README, CLAUDE.md, guides), and never write docs for code that does not exist yet — those surfaces are owned by docs-writer. Inline code-surface docs ARE yours: comments where logic is non-obvious, plus JSDoc/TSDoc on public functions you author (per `.claude/rules/development.md` § Documentation).
38
38
  - Do NOT introduce new runtime dependencies without explicit instruction. If a new dependency seems necessary, pause and report rather than installing.
39
39
  - Do NOT run ANY git write operation (`git add`, `git commit`, `git stash`, `git mv`, `git rm`, `git push`, `git reset`) — the git index and stash are shared session resources (PSA-007); the coordinator handles ALL VCS operations.
40
+ - **Escalation channel (#1051, opt-in):** If you hit a WAVE-BLOCKING obstacle — one that makes your task unfulfillable, not a question you could answer by reading more code — send exactly ONE `SendMessage` to `main` carrying your agent role (`code-implementer`), your declared file scope, and the obstacle. Then keep working in your scope or end with `Status: blocked`. NEVER wait for a reply (CSM-004); never message a sibling agent (CSM-001 — upward only). Where `SendMessage` is unavailable, report the obstacle in your final report instead (CSM-005). Note the send in Blockers / Notes.
40
41
  - Do NOT touch unrelated files in the same directory just because they share a folder.
41
42
  - Before creating a NEW file, grep for existing files with a similar basename/purpose (`git ls-files | grep -i <basename>`) — if one exists, prefer extending it over creating a "cousin" duplicate (#730.3).
42
43
  - Do NOT use destructive operations (`rm -rf`, `git reset --hard`, `git clean`). Stick to Edit/Write — the git-write ban above (PSA-007) already covers `git reset`/`git clean`'s VCS-specific forms.
@@ -3,7 +3,7 @@ name: db-specialist
3
3
  description: 'Use this agent for database work — schema design, migrations, queries, indexes, and database functions. Handles SQL, ORMs, and database architecture decisions. <example>Context: New feature requires database schema changes. user: "Create the migration for the invoice tables with proper indexes" assistant: "I''ll dispatch the db-specialist agent to design the schema and create the migration." <commentary>Schema design requires understanding normalization, indexing, and the existing data model.</commentary></example> <example>Context: Performance issue with database queries. user: "Optimize the slow invoice listing query" assistant: "I''ll use the db-specialist to analyze and optimize the query with proper indexing." <commentary>Query optimization requires understanding execution plans, indexes, and data access patterns.</commentary></example>'
4
4
  model: inherit
5
5
  color: purple
6
- tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
6
+ tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*), SendMessage
7
7
  sandbox-tier: repo-write
8
8
  output-schema: schemas/db-specialist.schema.json
9
9
  ---
@@ -36,6 +36,7 @@ You are a focused database agent. You design schemas, write migrations, optimize
36
36
  - Do NOT modify application code — only database-related files (`migrations/`, `schema.sql`, `prisma/`, RPC function definitions).
37
37
  - Do NOT run `DROP TABLE`, `TRUNCATE`, or `DELETE` without explicit user instruction.
38
38
  - Do NOT run ANY git write operation (`git add`, `git commit`, `git stash`, `git mv`, `git rm`, `git push`, `git reset`) — the git index and stash are shared session resources (PSA-007); the coordinator handles ALL VCS operations.
39
+ - **Escalation channel (#1051, opt-in):** If you hit a WAVE-BLOCKING obstacle — one that makes your task unfulfillable, not a question you could answer by reading more code — send exactly ONE `SendMessage` to `main` carrying your agent role (`db-specialist`), your declared file scope, and the obstacle. Then keep working in your scope or end with `Status: blocked`. NEVER wait for a reply (CSM-004); never message a sibling agent (CSM-001 — upward only). Where `SendMessage` is unavailable, report the obstacle in your final report instead (CSM-005). Note the send in Blockers / Notes.
39
40
 
40
41
  ## Quality Standards
41
42
 
@@ -92,7 +93,6 @@ Append a fenced ```json block at the end of your response per `agents/schemas/db
92
93
  ```
93
94
 
94
95
  Required: `status`, `task_id`, `files_changed`, `blockers`. Optional: `verdict`. **Emit `verdict` alongside `status` (status→verdict mapping: done→PROCEED, partial→PROCEED_WITH_FOLLOWUPS, blocked→BLOCKED). `status` is deprecated and will be removed in v4.0 (#472).** The coordinator parses the LAST fenced ```json block.
95
- ```
96
96
 
97
97
  ## Edge Cases
98
98
 
@@ -3,7 +3,7 @@ name: docs-writer
3
3
  description: 'Use this agent when documentation needs to be generated or updated as part of a session — user-facing READMEs, dev-focused CLAUDE.md sections, or vault narratives (context.md, decisions.md, people.md). <example>Context: a feature session added a new CLI flag. user: "Update the README with the new --no-vault flag." assistant: "I''ll dispatch the docs-writer agent to scan the diff and update README plus the Dev CLAUDE.md section if warranted." <commentary>Scope touches user-facing docs — docs-writer decides audience split and cites the diff.</commentary></example>'
4
4
  model: inherit
5
5
  color: cyan
6
- tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
6
+ tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*), SendMessage
7
7
  sandbox-tier: repo-write
8
8
  output-schema: schemas/docs-writer.schema.json
9
9
  ---
@@ -52,6 +52,8 @@ General rule: edit only files explicitly listed in the session scope passed at d
52
52
 
53
53
  Do NOT run ANY git write operation (`git add`, `git commit`, `git stash`, `git mv`, `git rm`, `git push`, `git reset`) — the git index and stash are shared session resources (PSA-007); the coordinator handles ALL VCS operations.
54
54
 
55
+ **Escalation channel (#1051, opt-in):** If you hit a WAVE-BLOCKING obstacle — one that makes your task unfulfillable, not a question you could answer by reading more code — send exactly ONE `SendMessage` to `main` carrying your agent role (`docs-writer`), your declared file scope, and the obstacle. Then keep working in your scope or end with `Status: blocked`. NEVER wait for a reply (CSM-004); never message a sibling agent (CSM-001 — upward only). Where `SendMessage` is unavailable, report the obstacle in your final report instead (CSM-005). Note the send in Blockers / Notes.
56
+
55
57
  ## Output Format
56
58
 
57
59
  Report back in this shape:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: eval-judge
3
- description: Use this agent during the /eval Skill Phase 3 (Epic #803, issue #810) to judge — from a session-eval record's dimension evidence, kpis, and session_id — the record's instruction-adherence and report-quality per rubric-v1.md's Judge Dimensions section. Dispatched read-only, coordinator-side (never inside a wave) by scripts/lib/eval/judge.mjs::runEvalJudge with a bounded per-call budget. RETURNS one fenced json block of two advisory judge dimensions (instruction-adherence, report-quality); the coordinator merges them via mergeJudgeDimensions() and appends the record via appendEvalRecord(). Read-only by contract — never writes files. Advisory-only and always uncalibrated — never blended into the deterministic tally or any global score. <example>Context: /eval Phase 3 with eval.judge: haiku. user "Judge whether this session-eval record shows instruction adherence and honest report quality." assistant "Dispatching eval-judge to read the record slice and emit advisory instruction-adherence/report-quality judgments." <commentary>The judge overlays a cheap advisory signal onto the five deterministic dimensions — never a global score, never a gate.</commentary></example>
3
+ description: "Use this agent during the /eval Skill Phase 3 (Epic #803, issue #810) to judge — from a session-eval record's dimension evidence, kpis, and session_id — the record's instruction-adherence and report-quality per rubric-v1.md's Judge Dimensions section. Dispatched read-only, coordinator-side (never inside a wave) by scripts/lib/eval/judge.mjs::runEvalJudge with a bounded per-call budget. RETURNS one fenced json block of two advisory judge dimensions (instruction-adherence, report-quality); the coordinator merges them via mergeJudgeDimensions() and appends the record via appendEvalRecord(). Read-only by contract — never writes files. Advisory-only and always uncalibrated — never blended into the deterministic tally or any global score. <example>Context: /eval Phase 3 with eval.judge: haiku. user \"Judge whether this session-eval record shows instruction adherence and honest report quality.\" assistant \"Dispatching eval-judge to read the record slice and emit advisory instruction-adherence/report-quality judgments.\" <commentary>The judge overlays a cheap advisory signal onto the five deterministic dimensions — never a global score, never a gate.</commentary></example>"
4
4
  model: haiku
5
5
  color: cyan
6
6
  tools: Read, Grep, Glob
@@ -3,7 +3,7 @@ name: session-reviewer
3
3
  description: 'Use this agent between waves or at session end to verify work quality against the session plan. Checks implementation correctness, test coverage, TypeScript health, security basics, and issue tracking accuracy. <example>Context: Impl-Core wave is complete, coordinator needs quality check before Impl-Polish. user: "Impl-Core wave done, review before continuing" assistant: "I''ll dispatch the session-reviewer to verify Impl-Core outputs." <commentary>Inter-wave quality gate ensures issues are caught early, not at session end.</commentary></example> <example>Context: Session end, verifying all work before committing. user: "/close" assistant: "Running session-reviewer to verify all session work before committing." <commentary>Final quality gate before any code is committed.</commentary></example>'
4
4
  model: inherit
5
5
  color: pink
6
- tools: Read, Grep, Glob, Bash
6
+ tools: Read, Grep, Glob, Bash, SendMessage
7
7
  sandbox-tier: read-only
8
8
  output-schema: schemas/session-reviewer.schema.json
9
9
  ---
@@ -164,6 +164,12 @@ The same standard binds your own conduct: a defect in your OWN review process
164
164
 
165
165
  Evidence for both halves (2026-08-14 quality panel, 18 findings / 2 HIGH): each of the three reviewers refuted at least one coordinator claim. The architect's 10-entry CONFIRMED list and the QA strategist's 12-entry REFUTED list produced no findings at all, yet two REFUTED entries closed gaps the coordinator had explicitly suspected — re-work the next wave would otherwise have repeated. The security reviewer reproduced a HIGH that no test and no gate had surfaced (self-review and a green gate are not review), and disclosed a defect in his own probe with its full cleanup. A fix-agent refused a coordinator-specified `needleCount > 0` coupling by showing it would disable the fix in the zero-needle run — i.e. in exactly the leaking run.
166
166
 
167
+ ### Escalation channel (#1051, opt-in)
168
+
169
+ If you hit a WAVE-BLOCKING obstacle — one that makes the review itself unfulfillable (the diff you were pointed at does not exist, the gate cannot run at all), not a defect you could report as a finding — send exactly ONE `SendMessage` to `main` carrying your agent role (`session-reviewer`), your declared review scope, and the obstacle. Then finish whatever review remains possible and report as usual. NEVER wait for a reply (CSM-004); never message a sibling agent (CSM-001 — upward only). Where `SendMessage` is unavailable, report the obstacle in your final report instead (CSM-005). Note the send in your report.
170
+
171
+ A HIGH finding is not an escalation — findings travel in the findings list, and `stop-and-escalate` (RCR-007) is a classification you report, not a message you send. This channel exists only for the obstacle that stops the review from happening.
172
+
167
173
  ## Output Format
168
174
 
169
175
  ```
@@ -3,7 +3,7 @@ name: test-writer
3
3
  description: 'Use this agent to close NAMED test gaps and to consolidate redundant tests. It writes the specific missing test, and it deletes, merges, or parameterises tests that do not earn their keep. <example>Context: Quality wave named one concrete gap — the invoice service never exercises the declined-payment branch. user: "The invoice service has no test for a declined payment" assistant: "I''ll dispatch the test-writer to add that one error-path test and run the falsification check on it." <commentary>A named gap states a bug that would ship undetected; ''improve coverage'' names nothing and is not a dispatchable task.</commentary></example> <example>Context: The auth test file has 14 tests — 6 assert the same validation branch and 3 only pin prose strings. user: "Clean up the auth test file" assistant: "I''ll use the test-writer to merge the 6 duplicates into one parameterised test and delete the 3 prose-pinning tests — net test count falls 14 to 6 while catch-power rises, reported as test_delta.removed plus test_delta.consolidated." <commentary>Consolidation is a success outcome: fewer tests that each catch a distinct bug beat many that catch none, and a scope with no real gap legitimately ends with status no-tests-needed.</commentary></example>'
4
4
  model: inherit
5
5
  color: orange
6
- tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
6
+ tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*), SendMessage
7
7
  sandbox-tier: repo-write
8
8
  output-schema: schemas/test-writer.schema.json
9
9
  ---
@@ -40,6 +40,7 @@ You are a focused testing agent. You write tests — unit, integration, and edge
40
40
  - Do NOT write trivial tests. `expect(typeof add).toBe('function')` does not test behavior.
41
41
  - Do NOT add test utilities unless the same pattern appears 3+ times. Premature abstraction in tests obscures what's being tested.
42
42
  - Do NOT run ANY git write operation (`git add`, `git commit`, `git stash`, `git mv`, `git rm`, `git push`, `git reset`) — the git index and stash are shared session resources (PSA-007); the coordinator handles ALL VCS operations.
43
+ - **Escalation channel (#1051, opt-in):** If you hit a WAVE-BLOCKING obstacle — one that makes your task unfulfillable, not a question you could answer by reading more code — send exactly ONE `SendMessage` to `main` carrying your agent role (`test-writer`), your declared file scope, and the obstacle. Then keep working in your scope or end with `Status: blocked`. NEVER wait for a reply (CSM-004); never message a sibling agent (CSM-001 — upward only). Where `SendMessage` is unavailable, report the obstacle in your final report instead (CSM-005). Note the send in Blockers / Notes.
43
44
  - Do NOT use computed values in assertions. Always use hardcoded literals.
44
45
  - Do NOT skip error paths. Every function with failure modes needs at least one error/edge case test alongside the happy path.
45
46
  - **Falsification check (mandatory)**: Before finishing, verify each test would FAIL if the core logic were removed. If it wouldn't, the test is worthless.
@@ -3,7 +3,7 @@ name: ui-developer
3
3
  description: 'Use this agent for frontend implementation — UI components, pages, styling, accessibility, and responsive design. Handles React/Next.js components, CSS, and design system work. <example>Context: Implementation wave includes UI component work. user: "Build the invoice list page with filters and pagination" assistant: "I''ll dispatch the ui-developer agent to implement the invoice list UI." <commentary>Frontend page implementation with interactive components is the ui-developer''s specialty.</commentary></example> <example>Context: Accessibility improvements needed. user: "Fix WCAG violations in the dashboard components" assistant: "I''ll use the ui-developer to audit and fix the accessibility issues." <commentary>WCAG compliance requires understanding semantic HTML, ARIA attributes, and keyboard navigation.</commentary></example>'
4
4
  model: inherit
5
5
  color: magenta
6
- tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*)
6
+ tools: Read, Edit, Write, Glob, Grep, Bash, Skill(session-orchestrator:*), SendMessage
7
7
  sandbox-tier: repo-write
8
8
  output-schema: schemas/ui-developer.schema.json
9
9
  ---
@@ -36,6 +36,7 @@ You are a focused frontend implementation agent. You build UI components, pages,
36
36
  - Do NOT write backend logic — server actions, API routes, DB queries are out of scope. Use client-only patterns + existing data-fetching layers (React Query, SWR, server components).
37
37
  - Do NOT use `dangerouslySetInnerHTML` without DOMPurify sanitization (XSS risk).
38
38
  - Do NOT run ANY git write operation (`git add`, `git commit`, `git stash`, `git mv`, `git rm`, `git push`, `git reset`) — the git index and stash are shared session resources (PSA-007); the coordinator handles ALL VCS operations.
39
+ - **Escalation channel (#1051, opt-in):** If you hit a WAVE-BLOCKING obstacle — one that makes your task unfulfillable, not a question you could answer by reading more code — send exactly ONE `SendMessage` to `main` carrying your agent role (`ui-developer`), your declared file scope, and the obstacle. Then keep working in your scope or end with `Status: blocked`. NEVER wait for a reply (CSM-004); never message a sibling agent (CSM-001 — upward only). Where `SendMessage` is unavailable, report the obstacle in your final report instead (CSM-005). Note the send in Blockers / Notes.
39
40
 
40
41
  ## Quality Standards
41
42
 
@@ -6,7 +6,7 @@ argument-hint: "[--upgrade <tier>]"
6
6
 
7
7
  # Bootstrap
8
8
 
9
- **TL;DR — for first-time users:** Run `/bootstrap` with no flags. The skill auto-detects the right tier (fast/standard/deep) from your repo, recommends one with a one-line reason, and asks **a single confirmation question**. Bestätigen → fertig. Keine weiteren Schritte.
9
+ **TL;DR — for first-time users:** Run `/bootstrap` with no flags. The skill auto-detects the right tier (fast/standard/deep) from your repo, recommends one with a one-line reason, then walks a **fixed questionnaire** — tier/stack (1–2 prompts), owner persona (5), dispatcher autonomy (1); **7–9 prompts** on a first-run full bootstrap. Bestätigen → fertig. Keine weiteren Schritte.
10
10
 
11
11
  The flags below cover special cases (re-adopting an existing repo, upgrading a tier, syncing rules). If you don't recognize the case in the description, you don't need the flag.
12
12
 
@@ -22,7 +22,7 @@ This is the path 95 % of users want.
22
22
 
23
23
  | Invocation | Behavior |
24
24
  |------------|----------|
25
- | `/bootstrap` | Auto-detect tier (fast / standard / deep) from repo context. Present recommendation via `AskUserQuestion` with options to confirm or override. At most ONE question in the normal case. Then scaffold files + commit. |
25
+ | `/bootstrap` | Auto-detect tier (fast / standard / deep) from repo context. Present recommendation via `AskUserQuestion` with options to confirm or override. Tier/stack: 1–2 questions; first-run full bootstrap adds owner interview (5, `owner-interview.mjs`) + dispatcher-autonomy capture (1). Then scaffold files + commit. |
26
26
 
27
27
  What the user sees:
28
28
 
package/commands/close.md CHANGED
@@ -10,7 +10,9 @@ The user wants to end the current session.
10
10
  **Pre-check before invoking session-end:** Determine `<state-dir>` from the current platform (`.claude/`, `.codex/`, `.cursor/`, or `.pi/`). Check if `<state-dir>/STATE.md` exists and read its `status` field. Three exit conditions:
11
11
 
12
12
  1. **STATE.md does not exist:** Read Session Config to check `persistence`. If `persistence: false`, inform the user: "Session completed (persistence is off — STATE.md was never created). Use `/session` to start a new session." If `persistence: true` (or Session Config unavailable), inform the user: "No active session found. Use `/session` to start a session first." Either way, stop.
13
- 2. **STATE.md exists and `status: completed`:** Inform the user: "Previous session was already finalized by session-end. Start a new session with `/session`, or inspect `<state-dir>/STATE.md` to review the prior close. (Note: if this is unexpected after an Express Path session, `commands/go.md` should have auto-invoked /close check that STATE.md `## Deviations` contains an `Express path:` entry.)" and stop.
13
+ 2. **STATE.md exists and `status: completed`:** `status: completed` alone is NOT proof that session-end's Phase 3.7 writer ever ran (#429) the field can be set by hand, or by any path that stops short of that write. Before treating the prior close as final, read STATE.md frontmatter's `session` field (the semantic session id, e.g. `main-2026-05-27-session-1`; see `skills/_shared/state-ownership.md`) and check whether `.orchestrator/metrics/sessions.jsonl` contains a record whose `session_id` equals it (`grep -c` for the literal id, or parse each line as JSON and compare `session_id`).
14
+ - **A matching record exists:** Inform the user: "Previous session was already finalized by session-end. Start a new session with `/session`, or inspect `<state-dir>/STATE.md` to review the prior close. (Note: if this is unexpected after an Express Path session, `commands/go.md` should have auto-invoked /close — check that STATE.md `## Deviations` contains an `Express path:` entry.)" and stop.
15
+ - **No `session` field is present in STATE.md frontmatter, OR no matching record exists:** Warn the user: "STATE.md completed ohne Ledger-Record — session-end wurde vorher nie ausgeführt (#429)." Do NOT stop — proceed to invoke the session-end skill exactly as in exit condition 3, so the missing record gets written this time. (The SessionEnd hook's `backfillCompletedFromStateMd` — `scripts/lib/session-close-backfill.mjs` — independently self-heals this same gap on a later session's teardown; this Pre-Check branch covers the case where /close is re-run before that hook has had a chance to fire.)
14
16
  3. **STATE.md exists and `status: active` or `status: paused`:** Proceed to invoke the session-end skill.
15
17
 
16
18
  For any other `status` value (e.g., `idle`), warn the user: "Unexpected session status `<value>`. Inspect `<state-dir>/STATE.md` and use `/session` to reset if needed." and stop.
package/commands/go.md CHANGED
@@ -10,7 +10,7 @@ The user has approved the session plan. Begin execution immediately.
10
10
 
11
11
  ## Express Path Detection
12
12
 
13
- Before invoking the wave-executor, check the conversation context for the Express Path activation banner emitted by session-plan or session-start Phase 8.5:
13
+ Before invoking the wave-executor, check the conversation context for the Express Path activation banner printed by `node scripts/express-path.mjs` in session-start Phase 8.5, and carried through session-plan's Short-Circuit (#1146):
14
14
 
15
15
  ```
16
16
  Express path activated — <N> tasks, coordinator-direct, no inter-wave checks.
@@ -0,0 +1,43 @@
1
+ ---
2
+ description: Outside-in product audit as a deep session — 7 read-only roles check what the site promises against what the code does, what a user experiences, what arrives by mail, and what the data says is used. Writes a dossier; needs a per-repo journey-manifest.
3
+ argument-hint: "[manifest-path]"
4
+ ---
5
+
6
+ # Journey Audit
7
+
8
+ Invokes the `journey-audit` skill (`skills/journey-audit/SKILL.md`). Dispatches roles R1–R7 against
9
+ the repo's journey manifest, re-verifies every P0 claim in the coordinator thread, and writes
10
+ `docs/audits/YYYY-MM-DD-user-journey-audit.md`.
11
+
12
+ Complements `/discovery` rather than replacing it: discovery checks code quality inside-out,
13
+ journey-audit checks product truth outside-in.
14
+
15
+ ## Argument Validation
16
+
17
+ The optional argument is a path to the manifest, overriding the default
18
+ `.orchestrator/journey-manifest.md`. Use it for a second manifest (e.g. a staging variant) or when
19
+ the repo keeps it elsewhere.
20
+
21
+ - `/journey-audit` — uses `.orchestrator/journey-manifest.md`
22
+ - `/journey-audit .orchestrator/journey-manifest.staging.md` — uses that file instead
23
+
24
+ If the argument names a file that does not exist, say so and stop — do NOT silently fall back to
25
+ the default path, because auditing the wrong manifest produces findings that look valid and are not.
26
+
27
+ ## Behavior
28
+
29
+ 1. **Gates** — bootstrap gate, then the manifest HARD-GATE: no manifest → refuse and point at
30
+ `templates/_shared/journey-manifest.md`; no filled `## SAFETY` block → run without R5 and say so.
31
+ 2. **Peer-session check** — announce the audit before dispatching (`.claude/rules/parallel-sessions.md`).
32
+ 3. **Wave** — R1–R7 in parallel, all read-only except R5, each fed from the manifest.
33
+ 4. **Coordinator re-verification** — every P0 re-checked with the coordinator's own command before
34
+ it enters the dossier. This step is not optional and not delegable.
35
+ 5. **Dossier + closing AUQ** — fixed section order, then fix-wave packages (multiSelect) and an
36
+ optional issue batch via `skills/gitlab-ops/SKILL.md` label taxonomy.
37
+
38
+ ## Related
39
+
40
+ - `skills/journey-audit/SKILL.md` — the skill, in full
41
+ - `templates/_shared/journey-manifest.md` — the per-repo manifest template (SAFETY block gates R5)
42
+ - `docs/prd/2026-08-28-journey-audit-skill.md` — the PRD, incl. the first-run evidence
43
+ - `commands/discovery.md` — the inside-out counterpart
@@ -36,7 +36,7 @@ Session Orchestrator is a Claude Code and Codex plugin that brings structured, w
36
36
 
37
37
  #### Claude Code
38
38
 
39
- Claude Code installs plugins through slash commands inside a running session. There is no `claude plugin` shell CLI — run these commands in the Claude Code prompt:
39
+ Claude Code also has a `claude plugin` shell CLI (`claude plugin --help` lists subcommands). For end-user installation, use the slash commands inside a running session — run these in the Claude Code prompt:
40
40
 
41
41
  **From GitHub (recommended for end users):**
42
42
 
@@ -992,7 +992,7 @@ Enforcement levels (configured via `enforcement`):
992
992
 
993
993
  ### Prerequisites
994
994
 
995
- Scope and command enforcement hooks require `jq` to be installed. If `jq` is not available, hooks degrade gracefully all operations are allowed with a warning to stderr. Install `jq` for enforcement to be active:
995
+ The enforcement hooks (`hooks/enforce-scope.mjs`, `hooks/enforce-commands.mjs`) do not call `requireJq()` they run without `jq`. `jq` is required by `scripts/validate-plugin.mjs` and by the wave-scope shell snippets in `skills/wave-executor/` (e.g. deriving `blockedCommands` and reading Session Config). Install `jq` when you run those tools or snippets:
996
996
 
997
997
  - **macOS**: `brew install jq`
998
998
  - **Ubuntu/Debian**: `sudo apt-get install jq`
package/docs/ci-setup.md CHANGED
@@ -14,11 +14,106 @@ project-level Job Token allowlists are explicitly configured — an admin action
14
14
  in the foreign project that cannot be scripted from here. The fix is a deploy
15
15
  token or PAT stored as the masked CI variable `SCHEMA_DRIFT_TOKEN`.
16
16
 
17
+ > **Current decision (2026-08-28, #1062): amber is the accepted normal state.**
18
+ > `glab variable list` on this project returns zero CI variables — no
19
+ > `SCHEMA_DRIFT_TOKEN` is set — so every pipeline runs the job to exit 3
20
+ > (`NOT VERIFIED`) and `pipeline-gate` prints the amber line. This is a
21
+ > deliberate operator choice, not a defect: the job is correctly fail-loud
22
+ > (exit taxonomy below), the vendored schema is compared manually at each
23
+ > baseline refresh (#1100), and no token is rotated for a check that runs
24
+ > against a private project of our own. Session-start's CI banner keeps
25
+ > reporting the soft failure on purpose (`allow_failure` jobs are invisible
26
+ > at pipeline level, which is what that banner exists to surface). Revisit
27
+ > trigger: the first time a vendored-schema drift ships unnoticed, or when
28
+ > the baseline gains a public mirror — then set the token (Option A below)
29
+ > and flip `SCHEMA_DRIFT_OPTIONAL` at both sites.
30
+
31
+ ### Activation status (measured 2026-09-02)
32
+
33
+ **Update, same day:** the token below was **revoked** — an unused credential is a
34
+ liability per SEC-005's secrets-lifecycle discipline, and leaving a live,
35
+ never-set-as-a-CI-variable token sitting in `infrastructure/projects-baseline`
36
+ served no purpose once the control run below had already answered the
37
+ question it was minted for. Re-minting it (same `glab api --method POST … --input -`
38
+ recipe as Option A step 1) is now **Step 0** of the re-activation sequence
39
+ below, not an assumed-still-valid token.
40
+
41
+ A Project Access Token was provisioned today, scoped exactly as Option A
42
+ below recommends:
43
+
44
+ - **Name:** `session-orchestrator-ci-schema-drift`
45
+ - **Project:** `infrastructure/projects-baseline` (id 52) — the TARGET repo,
46
+ not this one
47
+ - **Scopes:** `read_repository`
48
+ - **Access level:** Reporter (20)
49
+ - **Expires:** 2027-09-01
50
+
51
+ The masked `SCHEMA_DRIFT_TOKEN` CI variable on this project (id 74) was set
52
+ with that token, then **removed again**. A control run with the token set
53
+ confirmed the clone step authenticates correctly — but the drift check itself
54
+ then failed for a real, already-known reason:
55
+ `skills/vault-sync/validator.mjs`'s `vaultNoteTypeSchema` enum carries
56
+ `peer-card` and `board`, and the canonical `infrastructure/projects-baseline`
57
+ source does not have either yet. This is the documented vendor-ahead state
58
+ (`scripts/sync-vault-schema.mjs` header, "Vendor-ahead state (2026-05-23,
59
+ #503, I5)") and tracked as upstream-sync-debt in issue #531 (#503 itself is
60
+ closed). With the variable set and `SCHEMA_DRIFT_OPTIONAL` still `"true"`,
61
+ this exit-1 `DRIFT` is a **hard** failure — it is not in
62
+ `allow_failure.exit_codes: [3]` — so leaving the variable set today would turn
63
+ the next push red for a fact already tracked in #531, not for a new defect.
64
+ The variable was removed rather than left set; activation stays blocked until
65
+ the canonical enum gains both values.
66
+
67
+ **Re-activation sequence once #531 lands upstream:**
68
+
69
+ 0. **Re-mint the token** — it was revoked (see § Activation status above). Run
70
+ the same `glab api --method POST … --input -` recipe as Option A step 1,
71
+ against the TARGET project (id 52), and copy the response's `token` field
72
+ immediately — it is shown exactly once.
73
+ 1. `read -rs TOKEN` at the prompt (no echo), then pipe it into `glab variable
74
+ set` rather than passing it as a `--value` argument — a value passed on the
75
+ command line is visible to any other process on the host via `ps`, while
76
+ stdin is not:
77
+
78
+ ```bash
79
+ read -rs TOKEN
80
+ printf '%s' "$TOKEN" | glab variable set SCHEMA_DRIFT_TOKEN \
81
+ -R infrastructure/session-orchestrator --masked
82
+ ```
83
+
84
+ **Not** `--protected`: `.gate-rules` (`.gitlab-ci.yml:74`) runs the job
85
+ on every branch and every MR pipeline, and a protected-only variable would
86
+ silently reproduce the exit-5 `UNAVAILABLE` failure on every unprotected
87
+ branch. (`glab variable set --help` documents stdin piping directly —
88
+ `cat file.txt | glab variable set SERVER_TOKEN` — but no `-`/dash value
89
+ for `--value`; the flag only accepts a literal string, so omitting it
90
+ entirely and piping the value is the only way to keep the token off argv.)
91
+ 2. Push an ordinary commit and read the `schema-drift-check` job log for
92
+ `RESULT: IN-SYNC` — and confirm the job DURATION is well over 20 seconds
93
+ (see the pipeline-6815 warning above). A fast "success" is the exit-3
94
+ soft-skip in disguise, not a real run.
95
+ 3. Flip `SCHEMA_DRIFT_OPTIONAL` to `"false"` at **both** sites —
96
+ `schema-drift-check` and `pipeline-gate` — in one commit.
97
+ `tests/ci/schema-drift-check.test.mjs` already asserts the two values are
98
+ equal, so no test edit is needed to enforce the flip.
99
+ 4. Local counter-probe before trusting the pipeline: clone
100
+ `infrastructure/projects-baseline` with the token, make a throwaway copy of
101
+ `packages/zod-schemas/src/vault-frontmatter.ts` with one field
102
+ deliberately edited, then run
103
+ `node scripts/sync-vault-schema.mjs --check --canonical <path-to-edited-copy>`
104
+ — expect exit 1 with a diff naming the edited field. That confirms the
105
+ check diffs real content rather than passing on a broken comparison.
106
+
107
+ Per `.claude/rules/security.md` § SEC-005, this token's lifecycle belongs in
108
+ `.claude/docs/SECRETS-INVENTORY.md` once one exists — that file is not present
109
+ in this repo (measured 2026-09-02: no `.claude/docs/` directory tracked), so
110
+ the inventory is not adopted here and this section remains the sole record.
111
+
17
112
  ### Required CI variable
18
113
 
19
114
  | Variable | Type | Mask | Protect | Value |
20
115
  |---|---|---|---|---|
21
- | `SCHEMA_DRIFT_TOKEN` | Variable | Yes | Optional | deploy token or PAT (see below) |
116
+ | `SCHEMA_DRIFT_TOKEN` | Variable | Yes | No | Project Access Token or PAT see Option A/B below |
22
117
 
23
118
  If `SCHEMA_DRIFT_TOKEN` is **not set**, the job prints a `NOT VERIFIED` notice
24
119
  and exits **3** — which `allow_failure.exit_codes` renders as an amber *warning*,
@@ -62,6 +157,18 @@ a schema diff that does not exist. Only 3 is listed in
62
157
  outcome also prints its own `[schema-drift] RESULT: <STATE>` line, so the job log
63
158
  answers "what happened" without the reader having to know this table.
64
159
 
160
+ **Caveat — a second, narrower exit-3 collision (do not change the YAML for
161
+ it).** `scripts/sync-vault-schema.mjs` has its own exit 3, for a different
162
+ condition: malformed sentinel comments in `validator.mjs` (only one of
163
+ `begin`/`end` present). If `--check` ever hit that branch, it would return
164
+ exit 3 from the tool itself — and `allow_failure.exit_codes: [3]` reads the
165
+ shell's final exit code, not which tool produced it, so a genuine tooling
166
+ defect (broken sentinels) would render as the same amber "no token, declared
167
+ optional" warning that the missing-token guard produces. This is a caveat to
168
+ note, not a blocker: the sentinels are intact today, and the fix — if it is
169
+ ever needed — is giving `sync-vault-schema.mjs`'s malformed-sentinel case a
170
+ distinct exit code, not a change here.
171
+
65
172
  **After completing the token setup below, change `SCHEMA_DRIFT_OPTIONAL` to
66
173
  `"false"` in `.gitlab-ci.yml`** — in **both** places: the `schema-drift-check`
67
174
  job and `pipeline-gate`. One flag, two enforcement points;
@@ -84,35 +191,93 @@ not the accidental side effect of an unset CI variable.
84
191
  > exactly this failure — pipeline 6815 reported SUCCESS in 17 s having checked
85
192
  > nothing (issue #933).
86
193
 
87
- ### Option A — Deploy Token (recommended, least-privilege)
88
-
89
- 1. Open `infrastructure/projects-baseline` on your GitLab instance.
90
- 2. Go to **Settings Repository Deploy tokens**.
91
- 3. Click **Add token**:
92
- - **Name:** `session-orchestrator-ci-schema-drift`
93
- - **Expires at:** set a reminder (e.g. 1 year); rotate before expiry
94
- - **Scopes:** check `read_repository` only
95
- 4. Copy the generated token value (shown once).
96
- 5. Open `session-orchestrator` on GitLab.
97
- 6. Go to **Settings CI/CD Variables Add variable**:
98
- - **Key:** `SCHEMA_DRIFT_TOKEN`
99
- - **Value:** paste the deploy token
100
- - **Type:** Variable
101
- - **Masked:** Yes
102
- - **Protected:** Optional (enable if you only need it on protected branches)
103
- 7. Save.
194
+ ### Option A — Project Access Token (recommended — works with the current clone URL)
195
+
196
+ GitLab resolves a **deploy token** by its own fixed username
197
+ (`gitlab+deploy-token-<n>`, or a custom username if one was set at creation).
198
+ The job's clone step hardcodes the login as `oauth2:${SCHEMA_DRIFT_TOKEN}`
199
+ (`.gitlab-ci.yml` ~:652) `oauth2` is the username GitLab expects for a
200
+ Personal or Project Access Token, not for a deploy token. A deploy token's
201
+ value paired with that hardcoded username fails authentication at clone time
202
+ and surfaces as exit 5 `UNAVAILABLE`, which reads as a network/credential
203
+ problem rather than "wrong username" (see the demoted Deploy Token option
204
+ below). Tokens with **PAT semantics** GitLab accepts any username alongside
205
+ the token value — authenticate correctly with this clone URL: a Personal
206
+ Access Token, or, least-privilege, a **Project Access Token** scoped to the
207
+ TARGET project (`infrastructure/projects-baseline`). A Project Access Token
208
+ is preferred over a personal PAT for the same reason the deploy token used to
209
+ be recommended: it belongs to the project, not a person, and survives staff
210
+ changes.
211
+
212
+ 1. Create the token via API against the TARGET project (id 52) — GitLab has
213
+ no path to create a Project Access Token FOR a project from outside that
214
+ project's own Settings UI, so use `glab api`:
215
+
216
+ ```bash
217
+ glab api --hostname "$GITLAB_HOST" -X POST "projects/52/access_tokens" \
218
+ -H 'Content-Type: application/json' --input - <<'JSON'
219
+ {"name":"session-orchestrator-ci-schema-drift","scopes":["read_repository"],"access_level":20,"expires_at":"2027-09-01"}
220
+ JSON
221
+ ```
222
+
223
+ `--input -` plus the explicit `Content-Type: application/json` header is
224
+ required because the payload has a nested type (`scopes` is a JSON array),
225
+ which `glab api`'s `-f`/`-F` flag form cannot express. `access_level: 20`
226
+ is Reporter — the lowest access level that can read repository content.
227
+ `expires_at` is an operator choice, not a fixed value; the token created
228
+ for this document's own dry run (2026-09-02) was set 1 year out
229
+ (`2027-09-01`) — rotate before expiry.
230
+
231
+ 2. The response's `token` field holds the token value and is **shown exactly
232
+ once** — copy it immediately; GitLab will not display it again.
233
+
234
+ 3. Store it in `session-orchestrator` CI/CD variables as `SCHEMA_DRIFT_TOKEN`.
235
+ Prefer stdin over `--value` — a value passed as a command-line argument is
236
+ visible to other processes on the host (`ps`), while stdin is not:
237
+
238
+ ```bash
239
+ read -rs TOKEN
240
+ printf '%s' "$TOKEN" | glab variable set SCHEMA_DRIFT_TOKEN \
241
+ -R infrastructure/session-orchestrator --masked
242
+ ```
243
+
244
+ **Masked:** Yes. **Not** `--protected` — `.gate-rules` (`.gitlab-ci.yml:74`)
245
+ runs the job on every branch and every MR pipeline, so a protected-only
246
+ variable would silently be absent everywhere the job actually needs it.
104
247
 
105
248
  ### Option B — Personal Access Token (fallback)
106
249
 
107
- Use this if a deploy token is not available for the target project.
250
+ The same PAT-semantics reasoning from Option A applies: a personal PAT
251
+ authenticates under any username, so it works with the hardcoded `oauth2:`
252
+ clone login. Use this only if you cannot create a Project Access Token on
253
+ `infrastructure/projects-baseline` (e.g. you lack Owner/Maintainer there).
108
254
 
109
255
  1. Go to your GitLab profile → **Access Tokens**.
110
256
  2. Create a token with scope `read_repository` and a reasonable expiry.
111
257
  3. Store it in `session-orchestrator` CI/CD variables as `SCHEMA_DRIFT_TOKEN`
112
- (Masked: Yes)same steps 5–7 above.
113
-
114
- Note: a PAT is scoped to the creating user's access; prefer a deploy token so
115
- the CI credential survives staff changes.
258
+ (Masked: Yes, **not** Protected see Option A step 3 above).
259
+
260
+ A personal PAT is tied to the creating user's account and access; prefer the
261
+ Project Access Token in Option A so the CI credential survives staff changes.
262
+
263
+ ### Deploy Token — does not work with the current clone URL
264
+
265
+ This was the previously recommended option; it is demoted here because, as
266
+ the job is written today, it does not authenticate. GitLab deploy tokens
267
+ authenticate under their OWN username (`gitlab+deploy-token-<n>`, or a custom
268
+ username set at creation) — never as `oauth2`. The job's clone step hardcodes
269
+ `oauth2:${SCHEMA_DRIFT_TOKEN}` (`.gitlab-ci.yml` ~:652), so a deploy token's
270
+ value paired with the wrong username fails authentication at clone time. This
271
+ job reports that as exit 5 `UNAVAILABLE` — read as a network/credential-scope
272
+ problem, when the actual cause is the username mismatch.
273
+
274
+ To use a deploy token instead of Option A, `.gitlab-ci.yml`'s clone step would
275
+ need to stop hardcoding `oauth2` — either read the deploy token's own username
276
+ from a second CI variable and interpolate it into the clone URL, or create the
277
+ deploy token with a custom username of `oauth2` if the GitLab instance allows
278
+ choosing one. Neither change is made in this repo; that edit is out of this
279
+ document's scope. Option A avoids needing it at all, by using a token whose
280
+ username requirement (any username) already matches the hardcoded login.
116
281
 
117
282
  ### Verification path
118
283
 
@@ -148,8 +313,12 @@ Documenting it here for completeness:
148
313
  `infrastructure/session-orchestrator`.
149
314
  - Once the allowlist entry is saved, the job can use `CI_JOB_TOKEN` directly
150
315
  and `SCHEMA_DRIFT_TOKEN` is not needed.
151
- - Issue #279 chose the deploy-token path because it requires no admin action
152
- in the foreign project and works immediately after variable creation.
316
+ - Issue #279 chose the token-variable path over this allowlist because it
317
+ requires no admin action in the foreign project and works immediately after
318
+ variable creation. The original choice was a deploy token; as documented in
319
+ Option A above, a deploy token does not actually authenticate with this
320
+ job's hardcoded `oauth2:` clone login, so a Project Access Token (or PAT)
321
+ is the variant that delivers on that original reasoning.
153
322
 
154
323
  ## `pipeline-gate` — the fan-in job
155
324
 
@@ -30,6 +30,42 @@ codex plugin list --available --json
30
30
 
31
31
  It operates only through public Codex plugin commands; hook trust remains untouched.
32
32
 
33
+ ### Short-Form Marketplace Add (Verified 2026-08-28, codex-cli 0.141.0)
34
+
35
+ `codex plugin marketplace add --help` documents a short remote form:
36
+
37
+ ```
38
+ codex plugin marketplace add owner/repo --ref main
39
+ ```
40
+
41
+ Tested against this repo in a scoped throwaway `CODEX_HOME` (2026-08-28, codex-cli 0.141.0):
42
+
43
+ ```
44
+ $ codex plugin marketplace add Kanevry/session-orchestrator --json
45
+ {
46
+ "marketplaceName": "kanevry",
47
+ "installedRoot": ".../.tmp/marketplaces/kanevry",
48
+ "alreadyAdded": false
49
+ }
50
+ $ echo $?
51
+ 0
52
+ ```
53
+
54
+ This succeeds and clones the repo via git — no `--ref`/`owner/repo` string is needed beyond the short form; the resulting marketplace name (`kanevry`) is read from `.claude-plugin/marketplace.json`'s `name` field, not from the `owner/repo` argument.
55
+
56
+ **However**, the subsequent install step fails identically for both this short remote form *and* the long-form local install documented above (`codex plugin marketplace add "$PWD"`, same as `scripts/codex-install.mjs` runs):
57
+
58
+ ```
59
+ $ codex plugin add session-orchestrator@kanevry --json
60
+ Error: plugin `session-orchestrator` was not found in marketplace `kanevry`
61
+ $ echo $?
62
+ 1
63
+ ```
64
+
65
+ `codex plugin list --available --json --marketplace kanevry` returns `{"installed": [], "available": []}` for both forms — the marketplace is configured, but no plugin is discoverable inside it, contradicting item 1 under "Understand the Three States" below. A synthetic marketplace root mirroring this repo's exact layout (`.codex-plugin/plugin.json` directly at root, no `.claude-plugin/marketplace.json`) reproduces the same empty discovery; by contrast, a directory scanned via a `<root>/plugins/<name>/.codex-plugin/plugin.json` layout (the shape `codex plugin marketplace add --help`'s `--sparse plugins/foo` example implies, and the shape this host's own pre-existing `local` marketplace uses via `~/plugins/session-orchestrator`) resolves correctly. This suggests codex's own plugin-discovery convention expects a `plugins/<name>/` marketplace layout that this repo's flat root does not provide, though `.claude-plugin/marketplace.json` (Claude Code's schema) is independently accepted as "a supported manifest" at the `marketplace add` step, without resolving to a discoverable Codex plugin at `list` time.
66
+
67
+ **Caveat that limits this finding:** this host's installed codex-cli is **0.141.0**, older than the "0.144.4 or newer" prerequisite this guide states above. This failure was not re-verified against 0.144.4+, so it may be specific to running below the documented minimum rather than a defect in this repo's layout on a supported version. Until re-verified on 0.144.4+, treat both the short remote form and the long-form local install (`node scripts/codex-install.mjs`) as **unconfirmed end-to-end on this host** — the `marketplace add` step succeeds either way, but `plugin add` does not, on 0.141.0. Do not elevate either form to a README-level recommended command until a `plugin add` success is measured and dated.
68
+
33
69
  ## Understand the Three States
34
70
 
35
71
  Codex reports three distinct states that must not be conflated:
@@ -115,9 +151,12 @@ After installation and hook review, start a fresh task. Session Orchestrator exp
115
151
  | Config file | `CLAUDE.md` | `AGENTS.md` |
116
152
  | Task tracking | TaskCreate/TaskUpdate | Text-based checklists |
117
153
  | Hook root | `$CLAUDE_PLUGIN_ROOT` | native `${PLUGIN_ROOT}` plus `CODEX_PLUGIN_ROOT` compatibility export |
154
+ | MCP server root | `$CLAUDE_PLUGIN_ROOT`, injected into the server process | resolved by `.mcp.json` itself — Codex expands no root variable inside `mcpServers.args` and injects none into the MCP child's environment |
118
155
 
119
156
  Both platforms share session history and learnings through `.orchestrator/metrics/`.
120
157
 
158
+ `CODEX_PLUGIN_ROOT` is **session-orchestrator's own compatibility export, not a variable Codex provides.** The hook wrapper in `hooks/hooks-codex.json` assigns it from Codex's native `${PLUGIN_ROOT}` so that shared code (`scripts/lib/plugin-root.mjs`) can read one name on every harness. Nothing outside a hook command string sets it — in particular an MCP server started by Codex inherits neither `CODEX_PLUGIN_ROOT` nor `PLUGIN_ROOT`. That is why `.mcp.json` resolves the plugin root on its own instead of relying on a harness-provided variable: it tries `CLAUDE_PLUGIN_ROOT`, `CODEX_PLUGIN_ROOT`, `PLUGIN_ROOT`, then `git rev-parse --show-toplevel`, then asks Node to resolve the installed `session-orchestrator` package (which reaches `resolvePluginRoot()` and with it the `CURSOR_RULES_DIR` / `PI_PLUGIN_ROOT` roots too), and as the last tier scans the client plugin caches (`${CODEX_HOME:-$HOME/.codex}` and `$HOME/.claude` under `plugins/cache/*/session-orchestrator/*`, accepted only when the copy's `package.json` names `session-orchestrator`; newest by mtime wins). The tier order is documented once, in `scripts/lib/plugin-root.mjs` § TIER ORDER, and `.mcp.json` mirrors it. Each candidate must actually contain `scripts/mcp-server.sh` before it is used.
159
+
121
160
  ## Platform Limitations
122
161
 
123
162
  Claude Code dispatches role-specialized agents with dedicated definitions. Codex maps implementation work through its configured roles, so task prompts carry specialization that is not represented by a dedicated role. A project can add more specific TOML definitions under `.codex/agents/` when needed.
@@ -140,3 +179,28 @@ codex plugin list --available --json
140
179
  - **Other pre-public plugin/config/cache/hook-state residue is suspected:** this state is unsupported. Do not modify private Codex files. File an issue with `codex --version`, `codex plugin list --available --json`, and `codex plugin marketplace list --json` output so the public recovery path can be diagnosed.
141
180
  - **Agent dispatch fails:** verify Codex multi-agent support and inspect the bundled or project-level role TOMLs.
142
181
  - **Hooks report that Node is unavailable:** expose Node 24+ on the Codex hook PATH or set `SO_NODE_BIN` to the absolute Node executable.
182
+ - **`MCP startup failed: handshaking with MCP server failed: connection closed: initialize response`:** the MCP entrypoint could not locate the plugin, or could not run. Read the server's **stderr** — since GH#64 it names itself. Two diagnostics exist:
183
+ - `session-orchestrator: cannot locate the plugin root` — no plugin-root variable was set, the working directory was outside any git checkout, no cached copy of the plugin was found, and Node could not resolve an installed `session-orchestrator` package. Fix: reinstall the plugin so a cached copy exists (see *Where the plugin actually lives* below), or add `CODEX_PLUGIN_ROOT` (or `CLAUDE_PLUGIN_ROOT`) pointing at the plugin directory to that server's `env` block. Do not expect Codex to supply the variable — see the note under *Key Differences* above.
184
+ - `session-orchestrator: 'jq' not found in PATH` — the plugin was found but `jq` is missing. Fix: install `jq` and restart Codex. (Before GH#64 this case wrote a JSON-RPC error to *stdout* with `id: null`, which is not a valid `initialize` response either, so a missing `jq` and a missing plugin were indistinguishable from the client side.)
185
+ - **The MCP tools answer `Error: not inside a git repository`:** expected, not a failure. The handshake succeeded; `session_config` and `session_metrics` read the *project* you are working in, so they need Codex's working directory to be inside a git repository. Start Codex from the project, or `cd` into it.
186
+ - **"another session holds the lock" right after `resume`/`compact` in Codex:** the session lock appears to be self-collision across a resume/compact boundary rather than a real second session. Cause: before v3.23.0 (unreleased at time of writing), `parseSessionId()`'s UUID matcher was pinned to version nibble `4` (Claude Code's format), so every native session id Codex CLI mints — UUIDv7 — failed to parse; `hooks/on-session-start.mjs` fell through to a freshly generated `randomUUID()` on each `SessionStart`, and the new mint then collided with the lock the previous mint still held (Kanevry#66 / #1091). Fixed in v3.23.0 by widening `UUID_RE` in `scripts/lib/session-id.mjs` to accept any RFC 9562 UUID version 1–8, not only `4`. Check: `node -e "import('./scripts/lib/session-id.mjs').then(m=>console.log(m.parseSessionId('017f22e2-79b0-7cc3-98c4-dc0c0c07398f')))"` must print `format: 'uuid'` and `version: 7` (verified 2026-08-28 @ 30940cb — it does).
187
+
188
+ ### Where the plugin actually lives (measured 2026-08-28, codex-cli 0.141.0)
189
+
190
+ Three facts explain why launching Codex from `$HOME` used to kill the MCP server before `initialize` (GH Kanevry/session-orchestrator#64), and none of them is guessable from the docs:
191
+
192
+ 1. **Codex copies the plugin; it does not run it from your clone.** A marketplace install lands at `<CODEX_HOME>/plugins/cache/<marketplace>/<plugin>/<version>/` — measured here as `~/.codex/plugins/cache/local/session-orchestrator/<version>+codex.<stamp>/`, a full self-contained tree with its own `.mcp.json`, `package.json` and `scripts/mcp-server.sh`. Claude Code uses the same shape under `~/.claude/plugins/cache/`.
193
+ 2. **The MCP child gets no plugin-root variable and no working directory of its own.** Probing a registered MCP server launched from `/tmp` showed `PWD=/private/tmp` (the launch directory, verbatim) and `CLAUDE_PLUGIN_ROOT`, `CODEX_PLUGIN_ROOT`, `PLUGIN_ROOT` and `CODEX_HOME` **all unset**; `codex mcp list` prints `Env: -` and `Cwd: -` for the entry. `HOME` *is* set. So from `$HOME` — not a git repository — every locator the entrypoint had was blind, and `$(git rev-parse --show-toplevel)` collapsed the path to `/scripts/mcp-server.sh`.
194
+ 3. **Codex does not expand `${...}` in the registered command, and the registration is a snapshot.** `codex mcp list` shows the launch string verbatim, `${CLAUDE_PLUGIN_ROOT:-…}` and all — bash expands it, not Codex. It comes from the *cached* `.mcp.json`, taken at install time: a fix committed to this repo reaches an existing install only after a reinstall.
195
+
196
+ The entrypoint therefore scans those cache roots itself, matching on `package.json` `"name": "session-orchestrator"` rather than on the directory name, and preferring the most recently installed copy. A directory that merely *sits* under a `session-orchestrator/` marketplace folder is rejected.
197
+
198
+ **If your install predates this fix, reinstall — the fix cannot reach a cached copy on its own:**
199
+
200
+ ```bash
201
+ codex plugin marketplace add Kanevry/session-orchestrator
202
+ codex mcp list | grep session-orchestrator # the launch string should mention plugins/cache
203
+ ```
204
+
205
+ The 0.144.4 minimum-version caveat above still stands: everything in this section was measured on **0.141.0**, below the documented minimum, and has not been re-verified on 0.144.4+ or on the reporter's 0.149.0-alpha.4.3.
206
+