github-router 0.3.292 → 0.3.295

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 (93) hide show
  1. package/dist/{attribution-settings-CpLUCi8R.js → attribution-settings-pkIop1NU.js} +69 -30
  2. package/dist/attribution-settings-pkIop1NU.js.map +1 -0
  3. package/dist/{auth-BwUHopJz.js → auth-CluG5e-l.js} +3 -3
  4. package/dist/{auth-BwUHopJz.js.map → auth-CluG5e-l.js.map} +1 -1
  5. package/dist/browser-ext/manifest.json +1 -1
  6. package/dist/{check-usage-BTda5753.js → check-usage-iOzfnKJe.js} +4 -4
  7. package/dist/{check-usage-BTda5753.js.map → check-usage-iOzfnKJe.js.map} +1 -1
  8. package/dist/{claude-_DYGKCw8.js → claude-DNmxk-Rm.js} +162 -42
  9. package/dist/claude-DNmxk-Rm.js.map +1 -0
  10. package/dist/{codex-rTJ8jW5G.js → codex-Dl4gpHn-.js} +5 -5
  11. package/dist/{codex-rTJ8jW5G.js.map → codex-Dl4gpHn-.js.map} +1 -1
  12. package/dist/{debug-B3UrZTHQ.js → debug-DsEwleGg.js} +2 -2
  13. package/dist/{debug-B3UrZTHQ.js.map → debug-DsEwleGg.js.map} +1 -1
  14. package/dist/engine-XnluJUs6.js +2 -0
  15. package/dist/{gate-discovery-Bjar5dgv.js → gate-discovery-WcduofL4.js} +5 -5
  16. package/dist/{gate-discovery-Bjar5dgv.js.map → gate-discovery-WcduofL4.js.map} +1 -1
  17. package/dist/{get-copilot-usage-CRrf1ZSC.js → get-copilot-usage-B7Z4XVWj.js} +2 -2
  18. package/dist/{get-copilot-usage-CRrf1ZSC.js.map → get-copilot-usage-B7Z4XVWj.js.map} +1 -1
  19. package/dist/hooks.mjs +180 -3
  20. package/dist/hooks.sha256 +1 -1
  21. package/dist/{internal-artifact-open-BsEQRvDi.js → internal-artifact-open-D6tKMg8v.js} +2 -2
  22. package/dist/{internal-artifact-open-BsEQRvDi.js.map → internal-artifact-open-D6tKMg8v.js.map} +1 -1
  23. package/dist/internal-fast-dispatch-guard-CPlCrTlU.js +2 -0
  24. package/dist/internal-fast-dispatch-guard-Xyu17k9X.js +187 -0
  25. package/dist/internal-fast-dispatch-guard-Xyu17k9X.js.map +1 -0
  26. package/dist/{internal-first-mate-guard-CVFFJriA.js → internal-first-mate-guard-C9BV7J4U.js} +3 -3
  27. package/dist/{internal-first-mate-guard-CVFFJriA.js.map → internal-first-mate-guard-C9BV7J4U.js.map} +1 -1
  28. package/dist/{internal-first-mate-guard-DJdX6t48.js → internal-first-mate-guard-WJApyc8j.js} +1 -1
  29. package/dist/{internal-plan-review-8TKDLco6.js → internal-plan-review-t3PuNfuL.js} +3 -3
  30. package/dist/{internal-plan-review-8TKDLco6.js.map → internal-plan-review-t3PuNfuL.js.map} +1 -1
  31. package/dist/{internal-prompt-submit-Da7pxqua.js → internal-prompt-submit-C3KovHQG.js} +4 -4
  32. package/dist/{internal-prompt-submit-Da7pxqua.js.map → internal-prompt-submit-C3KovHQG.js.map} +1 -1
  33. package/dist/{internal-session-bind-BOFytA1f.js → internal-session-bind-d2uoja8I.js} +2 -2
  34. package/dist/{internal-session-bind-BOFytA1f.js.map → internal-session-bind-d2uoja8I.js.map} +1 -1
  35. package/dist/{internal-stop-hook-DrX2xlj0.js → internal-stop-hook-DJFtGCsE.js} +5 -5
  36. package/dist/{internal-stop-hook-DrX2xlj0.js.map → internal-stop-hook-DJFtGCsE.js.map} +1 -1
  37. package/dist/{internal-stop-review-CdouacHL.js → internal-stop-review-YtDUGXpX.js} +2 -2
  38. package/dist/{internal-stop-review-CdouacHL.js.map → internal-stop-review-YtDUGXpX.js.map} +1 -1
  39. package/dist/{internal-worker-guard-Bx-itoP8.js → internal-worker-guard-CdkeS9PN.js} +2 -2
  40. package/dist/{internal-worker-guard-Bx-itoP8.js.map → internal-worker-guard-CdkeS9PN.js.map} +1 -1
  41. package/dist/{internal-workspace-header-8WT0iB5K.js → internal-workspace-header-tuBXJV22.js} +2 -2
  42. package/dist/{internal-workspace-header-8WT0iB5K.js.map → internal-workspace-header-tuBXJV22.js.map} +1 -1
  43. package/dist/{lifecycle-nuOHfwgj.js → lifecycle-Bg6doY3-.js} +2 -2
  44. package/dist/{lifecycle-nuOHfwgj.js.map → lifecycle-Bg6doY3-.js.map} +1 -1
  45. package/dist/lifecycle-CGLt1cJQ.js +2 -0
  46. package/dist/{lifecycle-LeSfa7wH.js → lifecycle-CM9eTzvk.js} +2 -2
  47. package/dist/{lifecycle-LeSfa7wH.js.map → lifecycle-CM9eTzvk.js.map} +1 -1
  48. package/dist/lifecycle-DoUwpVDB.js +2 -0
  49. package/dist/main.js +19 -18
  50. package/dist/main.js.map +1 -1
  51. package/dist/{mcp-workspace-header-q34H_4wL.js → mcp-workspace-header-dERl2YTT.js} +2 -2
  52. package/dist/{mcp-workspace-header-q34H_4wL.js.map → mcp-workspace-header-dERl2YTT.js.map} +1 -1
  53. package/dist/{models-hhJcrZhr.js → models-DZ4hYsR7.js} +3 -3
  54. package/dist/{models-hhJcrZhr.js.map → models-DZ4hYsR7.js.map} +1 -1
  55. package/dist/{orchestration-pzbrKkgD.js → orchestration-BiGCEwbH.js} +2 -2
  56. package/dist/{orchestration-pzbrKkgD.js.map → orchestration-BiGCEwbH.js.map} +1 -1
  57. package/dist/{paths-BH4J7slC.js → paths-Ci485qSJ.js} +4 -4
  58. package/dist/{paths-BH4J7slC.js.map → paths-Ci485qSJ.js.map} +1 -1
  59. package/dist/paths-GD7bgGGy.js +2 -0
  60. package/dist/{peer-mcp-personas-CHbl6MwM.js → peer-mcp-personas-BwNtC8jt.js} +411 -84
  61. package/dist/peer-mcp-personas-BwNtC8jt.js.map +1 -0
  62. package/dist/{plan-review-hook-CfcanA7_.js → plan-review-hook-DuW0pSoM.js} +3 -3
  63. package/dist/{plan-review-hook-CfcanA7_.js.map → plan-review-hook-DuW0pSoM.js.map} +1 -1
  64. package/dist/{prompt-submit-hook-Bqf9ORgb.js → prompt-submit-hook-IMl7ssfr.js} +3 -3
  65. package/dist/{prompt-submit-hook-Bqf9ORgb.js.map → prompt-submit-hook-IMl7ssfr.js.map} +1 -1
  66. package/dist/{provision-BYFd9nPK.js → provision-DeNqzvSM.js} +4 -4
  67. package/dist/{provision-BYFd9nPK.js.map → provision-DeNqzvSM.js.map} +1 -1
  68. package/dist/{self-invocation-DhO1Z8iD.js → self-invocation-DAB_od0C.js} +2 -2
  69. package/dist/{self-invocation-DhO1Z8iD.js.map → self-invocation-DAB_od0C.js.map} +1 -1
  70. package/dist/{serve-BWMxDLnD.js → serve-BS5EmCpM.js} +12 -12
  71. package/dist/{serve-BWMxDLnD.js.map → serve-BS5EmCpM.js.map} +1 -1
  72. package/dist/{server-setup-CqlaZukJ.js → server-setup-DsGJnJ_O.js} +398 -283
  73. package/dist/server-setup-DsGJnJ_O.js.map +1 -0
  74. package/dist/{start-5MgGT4IF.js → start-vJdt2MiM.js} +3 -3
  75. package/dist/{start-5MgGT4IF.js.map → start-vJdt2MiM.js.map} +1 -1
  76. package/dist/{stop-gate-hook-BiBp5aGm.js → stop-gate-hook-DQnh_KfI.js} +3 -3
  77. package/dist/{stop-gate-hook-BiBp5aGm.js.map → stop-gate-hook-DQnh_KfI.js.map} +1 -1
  78. package/dist/{stop-gate-policy-BGd6b5hR.js → stop-gate-policy-DMr3KVmw.js} +2 -2
  79. package/dist/{stop-gate-policy-BGd6b5hR.js.map → stop-gate-policy-DMr3KVmw.js.map} +1 -1
  80. package/dist/{token-8drORhXg.js → token-BtJhjXXu.js} +54 -7
  81. package/dist/token-BtJhjXXu.js.map +1 -0
  82. package/dist/{worker-dispatch-D5fGroNr.js → worker-dispatch-BEHkTbnH.js} +2 -2
  83. package/dist/{worker-dispatch-D5fGroNr.js.map → worker-dispatch-BEHkTbnH.js.map} +1 -1
  84. package/package.json +1 -1
  85. package/dist/attribution-settings-CpLUCi8R.js.map +0 -1
  86. package/dist/claude-_DYGKCw8.js.map +0 -1
  87. package/dist/engine-C9axTIu7.js +0 -2
  88. package/dist/lifecycle-C8fOsQke.js +0 -2
  89. package/dist/lifecycle-D4Yc1aap.js +0 -2
  90. package/dist/paths-DJZoXfAS.js +0 -2
  91. package/dist/peer-mcp-personas-CHbl6MwM.js.map +0 -1
  92. package/dist/server-setup-CqlaZukJ.js.map +0 -1
  93. package/dist/token-8drORhXg.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribution-settings-pkIop1NU.js","names":["ERROR_CODE"],"sources":["../src/lib/codex-mcp-config.ts","../src/lib/mcp-permissions-settings.ts","../src/lib/injected-skills/first-mate-conduct-skill.ts","../src/lib/injected-skills/first-mate-operate-skill.ts","../src/lib/injected-skills/first-mate-setup-skill.ts","../src/lib/injected-skills/first-mate-skill.ts","../src/lib/injected-skills/floor-keeper-skill.ts","../src/lib/injected-skills/orchestrate-skill.ts","../src/lib/injected-skills/research-skill.ts","../src/lib/injected-skills/worker-skill.ts","../src/lib/claude-md-injection.ts","../src/lib/injected-skills/write.ts","../src/lib/injected-skills/index.ts","../src/lib/attribution-settings.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\"\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport consola from \"consola\"\n\nimport { type SelfInvocation } from \"./hook-launcher/self-invocation\"\nimport { buildCodexProviderConfigFlags } from \"./launch\"\nimport { buildWorkspaceHeaderHelperCommand } from \"./mcp-workspace-header\"\nimport { oneMContextDisabled, withOneMSuffix } from \"./one-m-context\"\nimport { PATHS, writeRuntimeFileSecure } from \"./paths\"\nimport {\n buildAgentPrompt,\n personasFor,\n type PersonaSpec,\n GROUP_META,\n MCP_GROUPS,\n type McpGroup,\n} from \"./peer-mcp-personas\"\nimport { type Effort as SubagentEffort } from \"./reasoning-effort\"\nimport {\n FAST_CRITIC_ALIAS_ID,\n LUNA_IMPLEMENTER_ALIAS_ID,\n LUNA_SCOUT_ALIAS_ID,\n} from \"./launch-profile\"\nimport {\n activeDispatchModes,\n dispatcherAgentName,\n dispatcherDescription,\n dispatcherPrompt,\n dispatcherTools,\n} from \"./worker-dispatch\"\n\n/**\n * Resolved `mcpServers` config key per enabled group. Bare preferred key\n * (`peers`/`search`/…) or the `gh-router-<group>` fallback on collision;\n * a group absent from the map is either disabled (gate off at launch) or\n * skipped because BOTH its bare AND prefixed keys collided with a user\n * entry. See `resolveGroupKeysFromMirror`.\n */\nexport type ResolvedGroupKeys = Partial<Record<McpGroup, string>>\n\n/** The `peers` server is always enabled, so its resolved key always exists;\n * this convenience reads it with the bare-key fallback for safety. */\nfunction peersKeyOf(groupKeys: ResolvedGroupKeys): string {\n return groupKeys.peers ?? GROUP_META.peers.preferredKey\n}\n\n/** The resolved `workers` server key (bare `workers`, or the `gh-router-workers`\n * fallback on collision). Used to name the dispatcher tools and the guard\n * matcher. Falls back to the preferred bare key when the group is absent (the\n * caller only builds worker dispatchers when the group is enabled anyway). */\nexport function workersKeyOf(groupKeys: ResolvedGroupKeys): string {\n return groupKeys.workers ?? GROUP_META.workers.preferredKey\n}\n\nexport type CodexMcpBackend = \"http\" | \"cli\"\n\ninterface ResolveBackendOpts {\n requested: boolean\n codexInfo: { ok: boolean; version?: string } | null\n}\n\n/**\n * Decide which MCP backend serves the codex personas.\n *\n * - User passed `--codex-cli` AND codex 0.129+ is on PATH → \"cli\".\n * The peer config registers `codex-cli` as a stdio MCP server\n * spawning `codex mcp-server`; codex personas route there;\n * gemini-critic stays on the HTTP backend (Codex CLI can't run\n * Gemini).\n * - User passed `--codex-cli` but codex is missing or < 0.129 →\n * fallback to \"http\" with a warning. Never break\n * `github-router claude` over a missing optional dep.\n * - User did not pass `--codex-cli` → \"http\", read-only personas only.\n */\nexport function resolveCodexCliBackend(\n opts: ResolveBackendOpts,\n): CodexMcpBackend {\n if (!opts.requested) return \"http\"\n if (!opts.codexInfo || !opts.codexInfo.ok) {\n const detail = opts.codexInfo?.version\n ? `installed version \"${opts.codexInfo.version}\" is too old (need 0.129+)`\n : \"codex CLI not found on PATH\"\n consola.warn(\n `--codex-cli requested but ${detail}; falling back to HTTP-only Codex MCP backend (codex-implementer will not be registered).`,\n )\n return \"http\"\n }\n return \"cli\"\n}\n\ninterface BuildOpts {\n /** Whether the codex-cli stdio server should be added. */\n codexCli: boolean\n /** Whether a supported Gemini review model is in the live catalog. Gates both\n * gemini-critic and gemini-reviewer. */\n geminiAvailable: boolean\n /** Preferred Gemini persona model resolved from the live catalog. */\n geminiModel?: string\n /** Resolved config key per enabled group — one `mcpServers` HTTP entry is\n * emitted per present key, pointing at its scoped `/mcp/<group>` URL. */\n groupKeys: ResolvedGroupKeys\n /** Per-launch nonce for the HTTP /mcp Authorization header. */\n nonce: string\n /** Isolated CODEX_HOME for the stdio child (only used when codexCli). */\n codexHome: string\n /** headersHelper command emitted on each HTTP entry for per-session workspace routing. */\n workspaceHeaderCmd?: string\n /** Base proxy URL (e.g. `http://127.0.0.1:PORT`). Needed by\n * `buildPeerAgentDefinitions` to inline each subagent's scoped HTTP MCP\n * server config into its `.md` frontmatter (claude-code#30280 workaround).\n * `buildPeerMcpConfig` takes it positionally, so it's optional here. */\n serverUrl?: string\n /** Whether the core worker tools are served (`workerToolsEnabled()`). When\n * true, the `worker-explore/implement/review/plan/test` dispatcher subagents\n * are generated. Optional (defaults false) so `buildPeerMcpConfig` callers\n * that don't build agents need not pass it. */\n workerToolsAvailable?: boolean\n /** Whether the browse worker tool is served (`browseAgentEnabled()`). Gates\n * the extra `worker-browse` dispatcher. Optional (defaults false). */\n browseAvailable?: boolean\n /** Model for the native subagents that want the OpenAI frontier coder\n * (`implementer`, `reviewer`) when present in the live catalog. */\n nativeSubagentModel?: string\n /** Model for `reviewer`. Google-first and deliberately NOT `implementer`'s\n * model, so a review is cross-lab against whoever produced the work. */\n reviewerModel?: string\n /** Model for `reviewer-fast` (the cheaper review tier). Absent → the agent is\n * OMITTED rather than inheriting the lead's model. */\n reviewerFastModel?: string\n /** Model for `brainstorm` (a third lab, for options the lead would not\n * generate). Absent → the agent inherits the lead's model. */\n brainstormModel?: string\n /** Model for `scout`. Absent → the agent is OMITTED rather than inheriting the\n * lead's model, because being cheaper than the lead is its whole purpose. */\n scoutModel?: string\n /** Model for `scribe`. Absent → the agent inherits the lead's model. */\n scribeModel?: string\n /** Model for `implementer-fast` (the cheaper implementation tier). Absent →\n * the agent is OMITTED rather than inheriting the lead's model. */\n implementerFastModel?: string\n /** Model for `general-purpose-fast` (the fast, cheapest catch-all). Absent →\n * OMITTED. */\n generalPurposeFastModel?: string\n /** Optional hard roster restriction, by native agent key (`\"implementer\"`,\n * `\"scout\"`, …). When present, ONLY keys in this set may be emitted —\n * each still subject to its usual model gate — regardless of whether an\n * excluded agent's model would otherwise resolve. Absent → unrestricted\n * (today's full catalog-driven roster). Used by profile-restricted\n * launches (e.g. the fast profile) so implementer/reviewer/brainstorm/\n * scribe/general-purpose-fast/coordinator are hard-excluded rather than\n * merely missing a model. */\n nativeRoster?: ReadonlySet<string> | ReadonlyArray<string>\n /** Optional persona allowlist (by `agentName`) forwarded to `personasFor`.\n * Absent → unrestricted (today's full persona set). */\n personaAllowlist?: ReadonlySet<string> | ReadonlyArray<string>\n /** Whether to emit the `peer-review-coordinator` meta-subagent. Default\n * true (today's behavior). A profile with too narrow a persona roster\n * for fan-out coordination to make sense (e.g. the fast profile, which\n * registers only `gemini-critic`) should pass `false`. */\n includeCoordinator?: boolean\n /** Fast-profile role assignments. When present, the explicit fast branch\n * emits the exact `scout`/`implementer`/`reviewer`/`planner`/`critic` roster instead\n * of reusing standard role bodies. Standard callers omit these fields. */\n fastProfile?: boolean\n plannerModel?: string\n /** Fixed `effort:` frontmatter overrides. Absent keeps standard picker-driven\n * behavior. */\n scoutEffort?: SubagentEffort\n implementerEffort?: SubagentEffort\n reviewerEffort?: SubagentEffort\n plannerEffort?: SubagentEffort\n criticEffort?: SubagentEffort\n /** Resolved fast native critic model. */\n criticModel?: string\n /** Compatibility fields for the original fast-profile implementation. */\n implementerFastEffort?: SubagentEffort\n reviewerFastEffort?: SubagentEffort\n}\n\nexport interface HttpMcpEntry {\n type: \"http\"\n url: string\n headers: Record<string, string>\n headersHelper?: string\n}\n\ninterface StdioMcpEntry {\n command: string\n args: Array<string>\n env: Record<string, string>\n}\n\nexport interface PeerMcpConfig {\n mcpServers: Record<string, HttpMcpEntry | StdioMcpEntry>\n}\n\n/**\n * Build one scoped HTTP `mcpServers` entry for a group: `type: http`, the\n * `/mcp/<urlSuffix>` URL, the Bearer-nonce Authorization header, and the\n * per-session workspace `headersHelper` when supplied. Shared by\n * `buildPeerMcpConfig` (the session `.claude.json` entries) AND\n * `buildPeerAgentDefinitions` (the per-subagent inline `mcpServers` frontmatter\n * that sidesteps Claude Code's Agent-tool MCP-inheritance bug, anthropics/\n * claude-code#30280 — a bare name-reference \"shares the parent connection\" and\n * re-triggers it, so subagents MUST inline the full HTTP config to connect\n * independently). One source of truth so the two can't drift.\n */\nfunction httpEntryFor(\n serverUrl: string,\n group: McpGroup,\n nonce: string,\n workspaceHeaderCmd?: string,\n): HttpMcpEntry {\n const entry: HttpMcpEntry = {\n type: \"http\",\n url: `${serverUrl}/mcp/${GROUP_META[group].urlSuffix}`,\n headers: {\n Authorization: `Bearer ${nonce}`,\n },\n }\n const ws = workspaceHeaderCmd?.trim()\n if (ws) entry.headersHelper = ws\n return entry\n}\n\n/**\n * Build the JSON payload for `claude --mcp-config <path>` (and the same\n * entries that get merged into the mirrored `.claude.json`).\n *\n * Emits one HTTP `mcpServers` entry per enabled group present in\n * `opts.groupKeys`, each pointing at its scoped `/mcp/<group>` endpoint\n * under the resolved (bare or prefixed-fallback) config key. When\n * `codexCli` is true, also registers `codex-cli` (stdio) which spawns\n * `codex mcp-server` with the proxy's provider-config flags so codex runs\n * through our Copilot-routed billing path rather than its default\n * api.openai.com.\n */\nexport function buildPeerMcpConfig(\n serverUrl: string,\n opts: BuildOpts,\n): PeerMcpConfig {\n const mcpServers: Record<string, HttpMcpEntry | StdioMcpEntry> = {}\n\n const workspaceHeaderCmd = opts.workspaceHeaderCmd?.trim()\n for (const group of MCP_GROUPS) {\n const key = opts.groupKeys[group]\n if (!key) continue // group disabled at launch, or both keys collided\n mcpServers[key] = httpEntryFor(serverUrl, group, opts.nonce, workspaceHeaderCmd)\n }\n\n if (opts.codexCli) {\n mcpServers[\"codex-cli\"] = {\n command: \"codex\",\n args: [\"mcp-server\", ...buildCodexProviderConfigFlags(serverUrl)],\n env: {\n OPENAI_BASE_URL: `${serverUrl}/v1`,\n OPENAI_API_KEY: \"dummy\",\n CODEX_HOME: opts.codexHome,\n },\n }\n }\n\n return { mcpServers }\n}\n\nexport interface PeerAgentDefinition {\n description: string\n prompt: string\n model?: string\n /** Fixed reasoning-effort frontmatter for this subagent, overriding the\n * Claude Code session's effort picker for this subagent only (documented\n * Claude Code subagent frontmatter behavior). Absent → the subagent\n * follows the session's picker, which is the standard-profile default for\n * every native today. Only the fast profile's `scout`/`implementer-fast`/\n * `reviewer-fast` set this. */\n effort?: SubagentEffort\n tools?: ReadonlyArray<string>\n /** Inline MCP servers scoped to this subagent, emitted into its `.md`\n * frontmatter as the connect-independently `mcpServers` list. Required\n * because Agent-tool-spawned subagents don't reliably inherit the session's\n * HTTP MCP servers (anthropics/claude-code#30280); an inline entry connects\n * when the subagent starts. Keyed by resolved server key → HTTP config. */\n mcpServers?: Record<string, HttpMcpEntry>\n}\n\nexport type PeerAgentDefinitions = Record<string, PeerAgentDefinition>\n\n/**\n * The `peer-review-coordinator` Claude Code subagent — the strongest\n * auto-invocation lever per Phase 2A of the peer-MCP plan. It is NOT a\n * peer-MCP tool; it is a regular Claude Code subagent that runs inside\n * the spawned-claude context, has tool access to the peer MCP tools\n * (codex_critic, codex_reviewer, gemini_critic), and fans out + aggregates.\n *\n * The \"use proactively\" phrase in the description is the documented Claude\n * Code idiom for subagents the parent (Opus) should delegate to without\n * explicit user request — at the natural checkpoints listed below.\n *\n * Empirically the polling-loop reliability for \"use proactively\" is ~60%\n * (claude-code-guide expert estimate); the plan calls for an acceptance\n * test (≥7/10 sessions delegate at the right checkpoints) before declaring\n * \"auto-invoked\". If <7/10 we flip the optional PreToolUse hook on\n * ExitPlanMode to default-on (env-disable-able).\n */\nfunction buildCoordinatorAgent(opts: {\n codexCli: boolean\n geminiAvailable: boolean\n}): { description: string; prompt: string } {\n // opus-critic is always registered (Anthropic models are always present\n // in the Copilot catalog), so no `geminiAvailable`-style guard is\n // required. Order: codex-critic first (strongest reasoning, cross-lab),\n // opus-critic second (largest context window — 1M when available),\n // gemini-critic third (third-lab triangulation, formal reasoning, only\n // when registered), codex-reviewer + gemini-reviewer last (line-level code\n // reviewers; both gemini personas gate on the gemini-3.x-pro catalog).\n const peers: Array<string> = [\"codex-critic\", \"opus-critic\"]\n if (opts.geminiAvailable) peers.push(\"gemini-critic\")\n peers.push(\"codex-reviewer\")\n if (opts.geminiAvailable) peers.push(\"gemini-reviewer\")\n\n const description =\n \"Coordinates cross-lab adversarial review across codex-critic, opus-critic, gemini-critic, codex-reviewer. Use proactively before non-trivial plans and after non-trivial commits. Always pass artifacts verbatim — peers are fresh-context.\"\n\n const personaList = peers.map((p) => `- \\`${p}\\``).join(\"\\n\")\n\n const prompt = [\n \"# Subagent: peer-review-coordinator\",\n \"\",\n \"You orchestrate cross-lab adversarial review for the lead orchestrator (Opus). You have access to these peer-MCP subagents:\",\n \"\",\n personaList,\n \"\",\n \"## When the lead invokes you\",\n \"\",\n \"The lead's brief will include an artifact (plan, design, diff, or code) and a goal (e.g. 'review before exit-plan', 'review the commit I just made', 'cross-check codex-critic's verdict'). Pick the right peers for the artifact type:\",\n \"\",\n \"- **Plan / design / architecture choice** → fan out to `codex-critic` (gpt-5.6-sol, strongest reasoning, cross-lab)\"\n + (opts.geminiAvailable ? \" AND `gemini-critic` (third-lab triangulation, strong on formal reasoning) in parallel\" : \"\")\n + \". codex-reviewer is the wrong tool for plans (it's a code-specialist, not an architecture critic).\",\n \"- **Concrete diff or single file** → fan out to `codex-reviewer` (gpt-5.3-codex, line-level code specialist)\"\n + (opts.geminiAvailable ? \" AND `gemini-reviewer` (gemini-3.1-pro, second-lab line-level review)\" : \"\")\n + (opts.geminiAvailable ? \" AND `gemini-critic` for cross-lab triangulation\" : \"\")\n + \". For very small changes (<20 lines), one `codex-reviewer` call is enough.\",\n \"- **Large artifact** → the only peers that take a large artifact WHOLE are `codex-critic` (gpt-5.6-sol, ≈1M-token input window) and `opus-critic` (Opus-4.7-1M, ≈936K-token input on enterprise catalogs; ≈168K otherwise). Route the full artifact to those for cross-lab coverage. `codex-reviewer` (≈272K) and `gemini-critic` (≈136K) have small windows — see Decomposition below: never summarize or downsize the request to squeeze a large artifact into a small-window peer.\",\n \"- **Formal reasoning, proofs, or invariants** → prefer `gemini-critic`\"\n + (opts.geminiAvailable ? \" (gemini-3.1-pro, strong on math and formally-stated properties)\" : \" (NOT REGISTERED in this session — gemini-3.x not in catalog)\")\n + \".\",\n \"- **Tie-breaker after codex-critic has weighed in** → call `gemini-critic`\"\n + (opts.geminiAvailable ? \"\" : \" (NOT REGISTERED in this session)\")\n + \" or `opus-critic` with the artifact AND codex-critic's verdict for cross-check.\",\n \"- **Fast sanity check** → `opus-critic` (same lab as lead but fresh context — catches confabulation and motivated reasoning).\",\n \"\",\n \"## Decomposition for large artifacts\",\n \"\",\n \"Route by the peer's real PROMPT WINDOW (input tokens): `codex-critic` gpt-5.6-sol ≈1M · `opus-critic` Opus-4.7-1M ≈936K (enterprise catalogs; ≈168K otherwise) · `codex-reviewer` gpt-5.3-codex ≈272K · `gemini-critic` gemini-3.1-pro ≈136K. The proxy REJECTS (with an actionable message) any single call whose brief exceeds the target peer's window — it will NOT silently truncate, because dropping lines from a review artifact is worse than a clear error. So: send the full artifact only to peers whose window fits it (large artifacts → `codex-critic` and/or `opus-critic`). When a peer's window is too small (commonly `gemini-critic` at ≈136K, or `codex-reviewer` at ≈272K), do NOT summarize or downsize the request to include it — either skip that peer, or split the artifact into 2-4 logical batches BY CONCERN (not by raw size — semantic batches give better per-batch reviews) that each fit, and call in parallel. Use the big-window peers for the whole and reserve a small-window peer like gemini for the concerns it can actually hold. The proxy's MCP cap allows up to 8 in-flight calls. Aggregate findings yourself before reporting back. (Separately, on the JSON transport a per-effort `predictedTooLong` byte cap still guards the ~60s tools/call timeout for non-SSE clients; Claude Code uses SSE, which streams with heartbeats and isn't subject to that cap.)\",\n \"\",\n \"## Aggregation contract\",\n \"\",\n \"When fan-out completes, return a SEVERITY-GROUPED, DEDUPLICATED finding list. Format:\",\n \"\",\n \" ## Findings\",\n \" ### HIGH\",\n \" 1. <one-line title> — `<file:line>` — sources: codex-critic, gemini-critic (3-lab confirmed if applicable)\",\n \" - bug: <one sentence>\",\n \" - mitigation: <one sentence>\",\n \" ### MEDIUM\",\n \" ...\",\n \" ### LOW\",\n \" ...\",\n \"\",\n \"Cite which peer raised each finding. If two or more peers raised the SAME finding (cross-lab confirmation), call it out — those are the highest-confidence bugs.\",\n \"\",\n \"## What NOT to do\",\n \"\",\n \"- Do not paraphrase or summarize per-peer verdicts BEFORE aggregating; aggregate from the raw verdicts.\",\n \"- Do not invent severity labels not present in the source verdicts.\",\n \"- Do not call peers serially (waste of wall-clock); always fan out in parallel.\",\n \"- Do not consult yourself — you are the coordinator, not a critic.\",\n \"\",\n \"Self-reminder (read before every reply):\",\n \" Did I fan out in parallel to the right peers for this artifact type?\",\n \" Did I aggregate findings by severity, citing which peer raised each?\",\n \" If two peers agreed, did I flag the cross-lab confirmation?\",\n ].join(\"\\n\")\n\n return { description, prompt }\n}\n\n/**\n * Claude Code's built-in subagents, which the interactive CLI provides natively\n * but the Agent SDK (used by CloudCLI under `serve`) does NOT register — so a\n * serve session shows `Agent type 'Explore' not found`. We re-register them as\n * custom subagents so the model's habitual `Agent(subagent_type:\"…\")` calls\n * resolve. SERVE-ONLY: never inject these for `github-router claude` (the CLI's\n * native, tuned built-ins would be shadowed by a same-name custom agent).\n *\n * No `tools:` restriction — each inherits the session's full toolset; the role\n * is steered by the prompt (matching the built-ins' behavior without the risk of\n * an over-narrow allowlist). `statusline-setup`/`output-style-setup` are omitted\n * (niche, rarely invoked).\n */\nexport const BUILTIN_SUBAGENT_DEFINITIONS: PeerAgentDefinitions = {\n \"general-purpose\": {\n description:\n \"General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. Use when searching for a keyword or file and you are not confident you will find the right match in the first few tries.\",\n prompt:\n \"You are a general-purpose agent. Research the question or carry out the multi-step task you are given, using the full toolset (read, search, edit, run commands as needed). Work autonomously and return a single, complete final answer — your final message is the whole result, so include the findings, file paths, and any code the caller needs.\",\n },\n Explore: {\n description:\n \"Read-only search agent for broad fan-out searches — when answering means sweeping many files or directories and you only need the conclusion, not the file dumps. It locates code; it does not modify it.\",\n prompt:\n \"You are a read-only exploration agent. Investigate the codebase to answer the question by reading and searching (Read/Glob/Grep and semantic code search); do NOT modify any files, run mutating commands, or make commits. Cast a wide net, then return a concise conclusion with the relevant file paths and line references — your final message is the whole answer.\",\n },\n Plan: {\n description:\n \"Software architect agent for designing implementation plans. Use when you need to plan the implementation strategy for a task. Returns a step-by-step plan, identifies critical files, and considers architectural trade-offs.\",\n prompt:\n \"You are a planning agent. Read the codebase (read-only — do not modify files) to design a concrete, ordered implementation plan for the task: the approach, the specific files to change, reuse of existing utilities, risks, and how the result will be verified. Return the plan as your final message.\",\n },\n}\n\n/**\n * The names of every native subagent this module can emit, current AND retired.\n *\n * This is a NAME REGISTRY for the sweep allowlist in `paths.ts` and its drift\n * test, NOT a list of agents that are guaranteed to exist in a given launch.\n * `scout`, `implementer-fast`, `reviewer-fast`, and `general-purpose-fast` are\n * conditionally emitted (see `buildPeerAgentDefinitions`) yet are listed here on purpose: the sweep must\n * recognize their filenames so a file written by a launch that DID resolve a\n * model gets reaped by a later launch that did not. Do not iterate this\n * expecting a definition back from `buildPeerAgentDefinitions` for every entry;\n * iterate `Object.keys(agents)` for that.\n *\n * Exported so the natives get the same drift protection\n * `ALL_DISPATCHER_AGENT_NAMES` gives the `worker-*` dispatchers — without it, a\n * renamed or newly added native silently escapes the sweep and its stale `.md`\n * files load forever as ghost subagents.\n */\nexport const ALL_NATIVE_AGENT_NAMES = [\n \"implementer\",\n \"planner\",\n \"reviewer\",\n \"reviewer-fast\",\n \"brainstorm\",\n \"scout\",\n \"scribe\",\n \"implementer-fast\",\n \"general-purpose-fast\",\n \"critic\",\n] as const\n\n/** Empty-string-safe read of an optional model id. */\nfunction nonEmptyModel(id: string | undefined): string | undefined {\n return id && id.length > 0 ? id : undefined\n}\n\n/**\n * The shared \"prefer the dedicated tools over shell\" steer, appended to every\n * native subagent prompt. `bashUses` names the work that legitimately belongs in\n * Bash for that agent (`builds` for a coder, `repros` for an investigator), the\n * only token that ever differed across the three hand-copied variants this\n * replaces.\n *\n * Deliberately NOT merged with `FILE_TOOL_GUIDANCE` in\n * `anthropic-translate/anthropic-request.ts`: that one is injected at the shim\n * boundary and therefore only reaches shim-routed (non-Claude) models. When a\n * native falls back to the lead's Claude model the shim is bypassed entirely, so\n * this prompt-level copy is the only coverage that survives. Two layers, two\n * different reasons to exist.\n */\nfunction fileToolSteer(bashUses: string): string {\n return (\n \"Use the dedicated Edit/Write/Read tools for file changes and Grep/Glob for search; \"\n + `reserve Bash for running ${bashUses}, tests, and git. `\n + \"Do not shell out (sed/awk/python/here-docs) to read or edit files.\"\n )\n}\n\n/** The read-only half of `fileToolSteer`, for agents that never write. */\nfunction readOnlyToolSteer(): string {\n return (\n \"Use Read to read files and Grep/Glob plus the semantic code search tool to find them; \"\n + \"Bash is for read-only inspection such as git log, git blame, and git show. \"\n + \"Do not modify any file, and do not run mutating commands.\"\n )\n}\n\n/**\n * `tools:` allowlist for the read-only natives (`scout`, `brainstorm`), modelled\n * on Claude Code's own `Explore`/`Plan` built-ins, which run with every tool\n * EXCEPT Agent / Artifact / ExitPlanMode / Edit / Write / NotebookEdit — note\n * that Anthropic's own read-only agent keeps Bash, which is what makes `git log`\n * and `git blame` reachable.\n *\n * Two deliberate deviations, both forced by the frontmatter format:\n *\n * 1. `tools:` is a POSITIVE allowlist with no \"all except\" form, so the\n * complement has to be spelled out. Rather than enumerate every harness tool\n * (which varies by Claude Code version, and would silently drop anything\n * added later), this lists the read / search / shell core that a read-only\n * agent actually uses. Tools added by a future release are NOT inherited by\n * these two agents; that is the price of real enforcement over a prompt that\n * merely asks nicely.\n * 2. The workers and orchestrate MCP groups are excluded on the same reasoning\n * that makes `Explore` drop `Agent`: both spawn further agents, so leaving\n * them in would reintroduce exactly the recursion that exclusion prevents.\n *\n * NOT A SANDBOX. `Bash` is retained because Anthropic's own read-only built-in\n * retains it, and without it an explorer cannot run `git log` / `git blame` /\n * `git show`, which is most of what repository archaeology needs. A shell is a\n * general write primitive, so \"read-only\" here means the agent has no dedicated\n * mutation tool and is instructed not to mutate, NOT that mutation is\n * impossible. Dropping Edit/Write still removes the path a model reaches for by\n * default. If a future change needs a hard guarantee, this allowlist is not\n * where it can be made.\n *\n * `searchKey` is the RESOLVED group key, not the bare literal: a user-side\n * `mcpServers` collision renames the group (`gh-router-search`, …), and a\n * hardcoded `mcp__search__*` would then grant nothing at all.\n */\nfunction readOnlyToolAllowlist(searchKey: string): Array<string> {\n return [\n \"Read\",\n \"Grep\",\n \"Glob\",\n \"Bash\",\n \"WebFetch\",\n \"WebSearch\",\n `mcp__${searchKey}__*`,\n ]\n}\n\nfunction decorateGuaranteedOneM(id: string): string {\n if (oneMContextDisabled() || /\\[1m\\]$/i.test(id)) return id\n return `${id}[1m]`\n}\n\n/** Build the literal `-m fast` native roster. This is intentionally separate\n * from the standard definitions: the names overlap, but their role bodies,\n * fixed model assignments, and efforts are profile contracts. */\nfunction buildFastProfileAgentDefinitions(opts: BuildOpts): PeerAgentDefinitions {\n const scoutModel = nonEmptyModel(opts.scoutModel)\n const implementerModel = nonEmptyModel(opts.nativeSubagentModel)\n const reviewerModel = nonEmptyModel(opts.reviewerModel)\n const plannerModel = nonEmptyModel(opts.plannerModel)\n const criticModel = nonEmptyModel(opts.criticModel)\n if (!scoutModel || !implementerModel || !reviewerModel || !plannerModel || !criticModel) {\n throw new Error(\"fast profile requires resolved scout, implementer, reviewer, planner, and critic models\")\n }\n\n const searchKey = opts.groupKeys.search ?? GROUP_META.search.preferredKey\n const peersKey = peersKeyOf(opts.groupKeys)\n const searchMcp: { mcpServers?: Record<string, HttpMcpEntry> } = opts.serverUrl\n ? { mcpServers: { [searchKey]: httpEntryFor(opts.serverUrl, \"search\", opts.nonce, opts.workspaceHeaderCmd) } }\n : {}\n const peersMcp: { mcpServers?: Record<string, HttpMcpEntry> } = opts.serverUrl && opts.groupKeys.peers\n ? { mcpServers: { [peersKey]: httpEntryFor(opts.serverUrl, \"peers\", opts.nonce, opts.workspaceHeaderCmd) } }\n : {}\n const oracleTool = opts.groupKeys.peers ? `mcp__${peersKey}__oracle` : undefined\n const readSearchTools = [\"Read\", \"Grep\", \"Glob\", \"Bash\"]\n const scoutTools = [...readSearchTools, `mcp__${searchKey}__*`]\n const reviewerTools = [...scoutTools, ...(oracleTool ? [oracleTool] : [])]\n const plannerTools = [\n ...readSearchTools,\n \"WebFetch\",\n \"WebSearch\",\n `mcp__${searchKey}__*`,\n ...(oracleTool ? [oracleTool] : []),\n // Claude Code 2.1.246 exposes the native dispatcher as `Agent`; the\n // historical `Task` spelling remains accepted by the policy hook for\n // older clients but is not emitted as a frontmatter capability.\n \"Agent\",\n ]\n\n const reviewerPrompt =\n \"You are the fast profile's repository-aware reviewer. Verify what is actually true by reading the code and running the relevant build, tests, or end-to-end reproduction. Find root causes rather than symptoms. Do not modify production code. Report severity-ranked findings with `file:line` evidence and a clear go/no-go. You do not have Advisor; independently reach your verdict from repository evidence. Use Oracle only as a last resort for one precise unresolved question after your own investigation. \"\n + fileToolSteer(\"builds and reproductions\")\n + \" Do not spawn further agents.\"\n const criticPrompt =\n \"You are the fast profile's fresh-context cross-lab critic. Assess the supplied plan, design, diff, or decision against its stated constraints. Look for overlooked failure modes, unsupported assumptions, and simpler safer alternatives. Do not modify files, run mutating commands, or spawn agents. Return concise severity-ranked findings with `file:line` evidence where applicable. \"\n + readOnlyToolSteer()\n const out: PeerAgentDefinitions = {\n scout: {\n description: `Read-only exploration subagent running ${scoutModel}. Use for broad repository discovery before the lead drafts a plan; return conclusions with file:line evidence, not file dumps.`,\n prompt:\n \"Investigate the repository read-only. Cast a wide net, then return a concise evidence packet for the lead: conclusions, load-bearing `file:line` citations, commands checked, and explicit gaps. Do not plan, edit, or spawn agents. \"\n + readOnlyToolSteer(),\n tools: scoutTools,\n model: decorateGuaranteedOneM(LUNA_SCOUT_ALIAS_ID),\n effort: opts.scoutEffort ?? \"high\",\n ...searchMcp,\n },\n implementer: {\n description: `Implementation subagent running ${implementerModel}. Use for well-specified mechanical changes after the plan is approved; implement and verify end to end in its own context.`,\n prompt:\n \"Implement the approved, well-specified change surgically. Match surrounding style, minimize unrelated churn, use dedicated file tools, and run the relevant build/tests. For verification, you may invoke only the fast-profile `reviewer` or `critic` native subagent; do not invoke any other role or redesign the plan. Report changes, verification, and unresolved risk. \"\n + fileToolSteer(\"builds\"),\n model: decorateGuaranteedOneM(LUNA_IMPLEMENTER_ALIAS_ID),\n effort: opts.implementerEffort ?? \"max\",\n },\n reviewer: {\n description: `Repository-aware reviewer running ${reviewerModel} at medium effort. Use after implementation or for failures that need reproduction, runtime checks, or repository context.`,\n prompt: reviewerPrompt,\n model: reviewerModel,\n effort: opts.reviewerEffort ?? \"medium\",\n tools: reviewerTools,\n mcpServers: {\n ...(searchMcp.mcpServers ?? {}),\n ...(peersMcp.mcpServers ?? {}),\n },\n },\n critic: {\n description: `Fresh-context cross-lab critic running ${criticModel} at medium effort. Use to challenge a plan, design, diff, or decision against its stated constraints and expose overlooked failure modes.`,\n prompt: criticPrompt,\n model: decorateGuaranteedOneM(FAST_CRITIC_ALIAS_ID),\n effort: opts.criticEffort ?? \"medium\",\n tools: scoutTools,\n ...searchMcp,\n },\n planner: {\n description: `Plan consultant and approver running ${plannerModel}. Invoke only after Luna has done the repository legwork and drafted a plan; pass a handcrafted evidence packet and the complete draft. The lead must not implement until this agent returns APPROVE.`,\n prompt:\n \"You are the fast profile's final plan consultant and approver, not a first-pass planner. The caller must provide the user goal, acceptance criteria, repository/domain constraints, Luna's `file:line` and command/test evidence, the complete draft plan, settled decisions, and one focused review question. Selectively verify disputed citations or narrow evidence gaps with read/search tools, but do not repeat broad discovery, edit files, or execute the plan. Return exactly one leading verdict: `APPROVE`, `REVISE`, or `NEED_MORE_CONTEXT`. APPROVE only when the plan is safe, ordered, complete, and verifiable. REVISE must give concrete corrections. NEED_MORE_CONTEXT must name the exact evidence Luna should collect. You do not have Advisor; independently reach your verdict from the evidence packet and selective verification. Use Oracle only as a last resort for one precise unresolved question after your own review. The Task/Agent capability is restricted by the fast in-session ACL: you may invoke only `reviewer`, `scout`, or `critic`; do not invoke any other role. Bash is for evidence commands only; this is not a shell sandbox. \"\n + readOnlyToolSteer(),\n tools: plannerTools,\n model: decorateGuaranteedOneM(plannerModel),\n effort: opts.plannerEffort ?? \"high\",\n mcpServers: {\n ...(searchMcp.mcpServers ?? {}),\n ...(peersMcp.mcpServers ?? {}),\n },\n },\n }\n const roster = opts.nativeRoster == null\n ? undefined\n : opts.nativeRoster instanceof Set\n ? opts.nativeRoster\n : new Set(opts.nativeRoster)\n if (roster) {\n for (const name of Object.keys(out)) {\n if (!roster.has(name)) delete out[name]\n }\n }\n return out\n}\n\n/**\n * Build the JSON payload for `claude --agents <path>`.\n *\n * Always includes the read-only personas applicable to the mode (gemini\n * is dropped if absent from the catalog); adds `codex-implementer` only\n * when `codexCli` is true. Always appends the `peer-review-coordinator`\n * meta-subagent — the strongest \"use proactively\" auto-invocation lever\n * per Phase 2A of the peer-MCP plan.\n */\nexport function buildPeerAgentDefinitions(\n opts: BuildOpts,\n): PeerAgentDefinitions {\n if (opts.fastProfile) return buildFastProfileAgentDefinitions(opts)\n\n const out: PeerAgentDefinitions = {}\n const personas = opts.fastProfile\n ? []\n : personasFor({\n codexCli: opts.codexCli,\n geminiAvailable: opts.geminiAvailable,\n geminiModel: opts.geminiModel,\n agentAllowlist: opts.personaAllowlist,\n })\n const peersKey = peersKeyOf(opts.groupKeys)\n // Inline the `peers` HTTP server into each peer subagent's frontmatter so it\n // connects directly on spawn — Agent-tool subagents don't reliably inherit\n // the session's HTTP MCP servers (claude-code#30280). Only when `serverUrl`\n // is supplied (the real launch path); omitted in bare unit tests that don't\n // exercise the .md wiring.\n const peersMcp: { mcpServers?: Record<string, HttpMcpEntry> } =\n opts.serverUrl\n ? { mcpServers: { [peersKey]: httpEntryFor(opts.serverUrl, \"peers\", opts.nonce, opts.workspaceHeaderCmd) } }\n : {}\n for (const persona of personas) {\n out[persona.agentName] = {\n description: persona.description,\n prompt: buildAgentPrompt(persona, { codexCli: opts.codexCli, peersKey }),\n ...peersMcp,\n }\n }\n if (opts.includeCoordinator !== false) {\n out[\"peer-review-coordinator\"] = {\n ...buildCoordinatorAgent({\n codexCli: opts.codexCli,\n geminiAvailable: opts.geminiAvailable,\n }),\n ...peersMcp,\n }\n }\n // Optional hard roster restriction (e.g. the fast profile): a native key\n // absent from this set is never emitted, independent of whether its model\n // resolved. Absent `opts.nativeRoster` → unrestricted, matching every\n // existing caller.\n const rosterSet = opts.nativeRoster == null\n ? undefined\n : opts.nativeRoster instanceof Set\n ? opts.nativeRoster\n : new Set(opts.nativeRoster)\n const rosterAllows = (name: string): boolean => !rosterSet || rosterSet.has(name)\n // The native subagents are ALWAYS injected — no catalog gate. Each runs on the\n // model chosen for its job when that model is live; otherwise its `model`\n // frontmatter is OMITTED and it inherits the lead's model, so a thin catalog\n // degrades the model, never the roster.\n //\n // `scout`, `implementer-fast`, and `general-purpose-fast` are the exceptions.\n // Their entire reason to exist is being cheaper than the lead's model, so\n // silently inheriting Opus would burn exactly the cost they were added to\n // avoid — their resolvers return undefined when nothing in their chain\n // resolves and the agent is then omitted outright.\n //\n // `implementer`, `implementer-fast`, `reviewer`, `scribe`, and\n // `general-purpose-fast` inherit the full toolset (no `tools:`). `scout` and\n // `brainstorm` carry the read-only allowlist.\n const nativeModel = nonEmptyModel(opts.nativeSubagentModel)\n const reviewerModel = nonEmptyModel(opts.reviewerModel)\n const reviewerFastModel = nonEmptyModel(opts.reviewerFastModel)\n const brainstormModel = nonEmptyModel(opts.brainstormModel)\n const scoutModel = nonEmptyModel(opts.scoutModel)\n const scribeModel = nonEmptyModel(opts.scribeModel)\n const implementerFastModel = nonEmptyModel(opts.implementerFastModel)\n const generalPurposeFastModel = nonEmptyModel(opts.generalPurposeFastModel)\n // Whether the sibling escalation targets are actually in this roster — used\n // to strip a description's cross-reference to an agent a restricted profile\n // never emits (e.g. the fast profile has no `implementer`/`reviewer` to\n // \"escalate\" to).\n const hasImplementer = rosterAllows(\"implementer\")\n const hasReviewer = rosterAllows(\"reviewer\")\n // `[1m]` decorates the FRONTMATTER value only, never the description text.\n // Claude Code budgets a subagent's context off its model id, and its detector\n // (`/\\[1m\\]/i`) has no vendor gate — so without the suffix an `implementer` on\n // `gpt-5.6-sol` (1,050,000 tokens) runs against a 200K budget. `scout` is now\n // floor-gated to 1M across both of its entries, so every emitted scout id receives\n // the suffix; a model below the floor causes the agent to be dropped instead.\n // Descriptions keep the bare id because that string is prose the lead reads.\n const modelField: { model?: string } =\n nativeModel ? { model: withOneMSuffix(nativeModel) } : {}\n const searchKey = opts.groupKeys.search ?? GROUP_META.search.preferredKey\n // Inline the `search` server for the read-only natives, same claude-code#30280\n // workaround the peers/workers subagents use: without it the allowlisted\n // `mcp__<searchKey>__*` names resolve to nothing on spawn.\n const searchMcp: { mcpServers?: Record<string, HttpMcpEntry> } =\n opts.serverUrl\n ? { mcpServers: { [searchKey]: httpEntryFor(opts.serverUrl, \"search\", opts.nonce, opts.workspaceHeaderCmd) } }\n : {}\n if (rosterAllows(\"implementer\")) {\n out.implementer = {\n description: nativeModel\n ? `Bounded implementation subagent running ${nativeModel} (strong non-Claude coder, maximum reasoning). Use proactively for coding changes that need judgment or have ambiguous scope — edits, features, fixes — to keep the lead's context focused; use implementer-fast instead for well-specified, mechanical changes. Runs in its own context. Model is overridable at spawn.`\n : `Bounded implementation subagent (native tools, runs on the lead's model in its own context). Use proactively for coding changes that need judgment or have ambiguous scope — edits, features, fixes — to keep the lead's context focused; use implementer-fast instead for well-specified, mechanical changes. Model is overridable at spawn.`,\n prompt:\n \"You are a bounded implementation subagent for well-scoped coding tasks. Implement the requested change surgically, matching the surrounding code style and minimizing unrelated churn. \"\n + fileToolSteer(\"builds\")\n + \" Verify with the project's build or tests where applicable. Do the work yourself — do not spawn further subagents. Report exactly what changed and any risks.\",\n ...modelField,\n }\n }\n const reviewerPrompt =\n \"You are a feedback subagent. Your job is to tell the caller what is actually true about the artifact you are given — code, a plan, a document, a failure report — and what is wrong with it. \"\n + \"Verify against the ACTUAL code by reading it; never assume. Do whatever the assessment requires: reproduce a failure end to end as close to how a real user hits it as you can, form hypotheses and test them against the code and runtime, and isolate the true root cause rather than a symptom. \"\n + \"Where the change warrants it, author tests that try to BREAK the implementation (edge cases, error paths, and the acceptance criteria as executable checks), run them, and report which pass and which fail; do NOT modify production code just to make tests pass. \"\n + fileToolSteer(\"builds\")\n + \" Do the work yourself — do not spawn further subagents. Report severity-ranked findings with `file:line` citations, the evidence behind each, and end with a clear go/no-go.\"\n if (rosterAllows(\"reviewer\")) {\n out.reviewer = {\n description: reviewerModel\n ? `Feedback subagent running ${reviewerModel}, a DIFFERENT lab from both the lead and the implementer, so its blind spots are decorrelated from whoever produced the work. Use proactively when something already exists and you want it assessed: a diff, a plan, a document, a failing test. Unlike the stateless peer critics, it reads the repo and can RUN things, so prefer it whenever the assessment needs execution or repo context (reproduce a failure, run the suite, bisect); prefer a peer critic when you already hold the artifact and want a fresh-context opinion on it. It can also REVIEW SCREENSHOTS and other images: just point it at the file and it will look at them. Model is overridable at spawn.`\n : `Feedback subagent (native tools, runs on the lead's model in its own context). Use proactively when something already exists and you want it assessed: a diff, a plan, a document, a failing test. Unlike the stateless peer critics, it reads the repo and can RUN things, so prefer it whenever the assessment needs execution or repo context; prefer a peer critic when you already hold the artifact and want a fresh-context opinion on it. Model is overridable at spawn.`,\n prompt: reviewerPrompt,\n ...(reviewerModel ? { model: withOneMSuffix(reviewerModel) } : {}),\n }\n }\n if (reviewerFastModel && rosterAllows(\"reviewer-fast\")) {\n const isGrok = reviewerFastModel === \"grok-4.6\"\n const windowClause = isGrok\n ? \"500K total context, 372K max prompt\"\n : \"1M context\"\n const speedClause = isGrok ? \"\" : \", typically faster than the pro-tier reviewer\"\n const crossLabClause = !isGrok && hasImplementer\n ? \" and cross-lab from the OpenAI-backed implementer\"\n : \"\"\n const bodyClause = hasReviewer\n ? \"Use for lower-stakes assessments that still need repository access or execution; escalate higher-stakes review to reviewer.\"\n : \"Use for lower-stakes assessments that still need repository access or execution.\"\n out[\"reviewer-fast\"] = {\n description: `Cheaper feedback subagent running ${reviewerFastModel} (${windowClause}${speedClause}${crossLabClause}). ${bodyClause} Full toolset, so it can read the repo and run builds, tests, and reproductions in its own context. Model is overridable at spawn.`,\n prompt: reviewerPrompt,\n model: withOneMSuffix(reviewerFastModel),\n ...(opts.reviewerFastEffort ? { effort: opts.reviewerFastEffort } : {}),\n }\n }\n if (rosterAllows(\"brainstorm\")) {\n out.brainstorm = {\n description: brainstormModel\n ? `Divergent-options subagent running ${brainstormModel} (third lab, for approaches the lead would not generate). Use proactively BEFORE an approach is chosen. Pass the decision, the constraints, what you have already ruled out, and the cost of being wrong; pass your current leading approach too if you have one, and it will try to beat it rather than restate it. Read-only; it proposes, then hands off to implementer. Model is overridable at spawn.`\n : `Divergent-options subagent (runs on the lead's model in its own context). Use proactively BEFORE an approach is chosen. Pass the decision, the constraints, what you have already ruled out, and the cost of being wrong; pass your current leading approach too if you have one, and it will try to beat it rather than restate it. Read-only; it proposes, then hands off to implementer. Model is overridable at spawn.`,\n prompt:\n \"You are a divergent-options subagent: the lead's sounding board while an approach is still open. Your job is to surface the option the lead would not have reached on its own. \"\n // Two modes, chosen by what the caller passes. A single pass cannot be\n // both independent of an incumbent and comparative against one, since the\n // model attends to the whole brief either way; so the modes are staged\n // ACROSS calls, the same shape `stand_in` uses for its blind round 1 then\n // informed round 2.\n + \"If the caller states its current leading approach, your job is to try to beat it, and you close with one verdict: `replace`, `retain`, or `insufficient evidence`. \"\n + \"`replace` requires naming a concrete alternative that dominates it and the evidence that decides between them. `retain` is a real answer and a useful one: say it plainly when the approach survives a genuine attempt to beat it. \"\n // Calibration, matching CRITIC_RUBRIC's existing stance. Reflexive dissent\n // is not skepticism; published work gets >99% disagreement from explicit\n // devil's-advocate framing, which measures compliance, not judgment.\n + \"Manufactured disagreement is as useless as agreement; do neither. If the caller states no leading approach, generate independently and let the lead compare. \"\n + \"Return 3 to 5 approaches that differ in MECHANISM, not in phrasing. For each: how it works, what it costs, what would have to be true for it to be the right answer, and the failure mode that would kill it. \"\n + \"Near-duplicate options are the failure mode to avoid — if only one real approach exists, say so plainly and explain why the alternatives are dead, because one honest option beats four padded ones. \"\n // The one defect that reproduced across observed runs: sound mechanism,\n // unexecutable concrete path. Screening only the winner is also\n // selection-biased, hiding candidates that should have ranked higher.\n + \"Screen EVERY candidate against this repository and this environment before you rank them, then verify the one you are about to recommend can actually run here: read the code path it depends on, the guard that would refuse it, the artifact it assumes exists. \"\n + \"A recommendation that cannot execute is worse than no recommendation. If checking kills your front-runner, rerank and say so. \"\n + \"Ground every option in what the repository actually contains, and prefer reusing what is already there over inventing something new. \"\n + readOnlyToolSteer()\n + \" Do the work yourself — do not spawn further subagents.\",\n tools: readOnlyToolAllowlist(searchKey),\n ...(brainstormModel ? { model: withOneMSuffix(brainstormModel) } : {}),\n ...searchMcp,\n }\n }\n if (scoutModel && rosterAllows(\"scout\")) {\n out.scout = {\n description: `Read-only exploration subagent running ${scoutModel} (fast and cheap, so repository lookups do not run at the lead's model rates). Use proactively to find or understand something in the codebase: it sweeps widely and returns conclusions with file:line references rather than file dumps. Model is overridable at spawn.`,\n prompt:\n \"You are a read-only exploration subagent. Answer the question by investigating the repository: cast a wide net, then narrow. \"\n + \"Return the conclusion, not the raw material — cite `file:line` for anything load-bearing and quote only the lines that matter. If the answer is that something does not exist, say so explicitly and describe where you looked. \"\n + readOnlyToolSteer()\n + \" Do the work yourself — do not spawn further subagents.\",\n tools: readOnlyToolAllowlist(searchKey),\n model: withOneMSuffix(scoutModel),\n ...(opts.scoutEffort ? { effort: opts.scoutEffort } : {}),\n ...searchMcp,\n }\n }\n if (rosterAllows(\"scribe\")) {\n out.scribe = {\n description: scribeModel\n ? `Documentation subagent running ${scribeModel} (the mid tier: documentation is verifiable prose, not frontier reasoning). Use proactively for prose that trails the code: docs, ADRs, CLAUDE.md sections, changelog entries, and README updates that have gone stale. Keeps low-glamour upkeep off the lead's context. Model is overridable at spawn.`\n : `Documentation subagent (runs on the lead's model in its own context). Use proactively for prose that trails the code: docs, ADRs, CLAUDE.md sections, changelog entries, and README updates that have gone stale. Model is overridable at spawn.`,\n prompt:\n \"You are a documentation subagent. Write and maintain the prose that trails the code: docs, ADRs, CLAUDE.md sections, changelog entries, README rows. \"\n + \"Read the code before describing it — every claim you write must be checkable against the repository as it is now, not as a summary said it was. Match the surrounding document's voice, structure, and level of detail. \"\n + \"Prefer updating an existing document over adding a new one, and delete what has become false rather than layering a correction on top of it. \"\n + fileToolSteer(\"builds\")\n + \" Do the work yourself — do not spawn further subagents. Report which documents changed and any claim you could not verify.\",\n ...(scribeModel ? { model: withOneMSuffix(scribeModel) } : {}),\n }\n }\n // `implementer-fast` is the cheaper implementation specialist;\n // `general-purpose-fast` is the catch-all for work no specialist fits.\n //\n // Description discipline: a description may claim only what is true of EVERY\n // member of that agent's chain, because the fallback is invisible to whoever\n // reads the prose. `implementer-fast` therefore branches its model-specific\n // framing: terra may carry the speed/cost claim, luna (the fast profile's\n // single-entry pin) names the profile explicitly, while the gemini-pro\n // fallback is described neutrally and may not claim terra's `max` effort\n // tier. `general-purpose-fast` is single-entry, so it may state luna's\n // measured and catalog properties exactly.\n const genericPromptFor = (role: string): string =>\n `You are a general-purpose subagent handling ${role} the lead has delegated to keep its own context free. `\n + \"Work out what the task actually requires, then do it end to end. Verify against the real repository and the real runtime rather than assuming — read the code, run the command, check the exit code. \"\n + fileToolSteer(\"builds\")\n + \" Do the work yourself — do not spawn further subagents. Report what you did, what you verified, and anything you could not settle.\"\n if (implementerFastModel && rosterAllows(\"implementer-fast\")) {\n const tierDescription = implementerFastModel === \"gpt-5.6-terra\"\n ? \"the cheaper, faster implementation tier\"\n : implementerFastModel === \"gpt-5.6-luna\"\n ? \"the fast, low-cost tier for this launch profile\"\n : \"a non-lead implementation model\"\n const escalateClause = hasImplementer\n ? \"; use implementer instead when the change needs judgment or its scope is ambiguous\"\n : \"\"\n out[\"implementer-fast\"] = {\n description: `Implementation subagent running ${implementerFastModel} (1M context, ${tierDescription}). Use proactively for well-specified, mechanical coding changes${escalateClause}. Full toolset, so it can implement and verify the change end to end in its own context. Model is overridable at spawn.`,\n prompt: genericPromptFor(\"a well-specified, mechanical coding change\"),\n model: withOneMSuffix(implementerFastModel),\n ...(opts.implementerFastEffort ? { effort: opts.implementerFastEffort } : {}),\n }\n }\n if (generalPurposeFastModel && rosterAllows(\"general-purpose-fast\")) {\n out[\"general-purpose-fast\"] = {\n description: `Catch-all subagent running ${generalPurposeFastModel} (1.05M context, the lowest-cost model in the catalog and the fastest measured catch-all candidate, with the full reasoning-effort ladder). Use proactively for work no specialist fits when a fast, economical non-lead model can finish it. Full toolset, so it can complete the work rather than only research it. Runs in its own context. Model is overridable at spawn.`,\n prompt: genericPromptFor(\"work no specialist fits\"),\n model: withOneMSuffix(generalPurposeFastModel),\n }\n }\n // Non-blocking workers surface: one `worker-<mode>` DISPATCHER subagent per\n // active worker tool. Each is pinned by a `tools:` allowlist to the workers\n // server only (`mcp__<workersKey>__*`), so it can run the worker and relay\n // the result but has NO Agent/Read/Bash — it cannot spawn further agents\n // (no recursion) or do extra work; its prompt narrows it to the one mode.\n // The lead runs these in the background and is notified on completion, so a\n // long-running (up to 6h) worker never blocks the main turn. Gated on\n // `workerToolsAvailable`\n // (core modes) and `browseAvailable` (the extra `worker-browse`).\n if (opts.workerToolsAvailable) {\n const workersKey = workersKeyOf(opts.groupKeys)\n // Inline the `workers` HTTP server so the dispatcher connects on spawn\n // (claude-code#30280 — inherited HTTP MCP servers don't reach Agent-tool\n // subagents, which is why the raw worker tool showed \"No such tool\n // available\"). The `tools:` allowlist still restricts it to that one server.\n const workersMcp: { mcpServers?: Record<string, HttpMcpEntry> } =\n opts.serverUrl\n ? { mcpServers: { [workersKey]: httpEntryFor(opts.serverUrl, \"workers\", opts.nonce, opts.workspaceHeaderCmd) } }\n : {}\n for (const mode of activeDispatchModes({ browse: opts.browseAvailable === true })) {\n out[dispatcherAgentName(mode)] = {\n description: dispatcherDescription(mode),\n prompt: dispatcherPrompt(mode, workersKey),\n tools: dispatcherTools(mode, workersKey),\n ...workersMcp,\n }\n }\n }\n return out\n}\n\nexport interface PeerMcpRuntimeFiles {\n mcpConfigPath: string\n agentsPath: string\n /** .md subagent files written into ~/.claude/agents/ (Phase 2.5). The\n * `--agents` JSON path is silently ignored by Claude Code v2.1.138's\n * Task `subagent_type` enum (the JSON's subagents are only reachable\n * via natural-language delegation). The .md files in the canonical\n * agents directory ARE picked up by the enum, making the\n * peer-review-coordinator + persona subagents directly invokable. */\n agentMdPaths: Array<string>\n nonce: string\n personas: Array<PersonaSpec>\n cleanup: () => Promise<void>\n}\n\ninterface WriteOpts {\n codexCli: boolean\n /** Stable invocation baked into persisted headersHelper commands. */\n selfInvocation: SelfInvocation\n geminiAvailable: boolean\n /** Preferred Gemini persona model resolved from the live catalog. */\n geminiModel?: string\n /** Resolved config keys per enabled group (from `resolveGroupKeysFromMirror`).\n * Threaded into both the --mcp-config payload and the persona .md routing\n * strings so every reference points at OUR server even after a collision\n * fallback. */\n groupKeys: ResolvedGroupKeys\n /** Whether the core worker tools are served — generates the `worker-*`\n * dispatcher subagents. */\n workerToolsAvailable?: boolean\n /** Whether the browse worker tool is served — adds the `worker-browse`\n * dispatcher. */\n browseAvailable?: boolean\n /** Model for the native subagents that want the OpenAI frontier coder\n * (`implementer`, `reviewer`) when present in the live catalog. */\n nativeSubagentModel?: string\n /** Model for `reviewer`. Cross-lab from `implementer` by design. */\n reviewerModel?: string\n /** Model for `reviewer-fast`. Absent → the agent is omitted entirely. */\n reviewerFastModel?: string\n /** Model for `brainstorm`. Absent → inherits the lead's model. */\n brainstormModel?: string\n /** Model for `scout`. Absent → the agent is omitted entirely. */\n scoutModel?: string\n /** Model for `scribe`. Absent → inherits the lead's model. */\n scribeModel?: string\n /** Model for `implementer-fast`. Absent → the agent is omitted entirely. */\n implementerFastModel?: string\n /** Model for `general-purpose-fast`. Absent → the agent is omitted entirely. */\n generalPurposeFastModel?: string\n /** Optional hard roster restriction, by native agent key. See the matching\n * field on `BuildOpts`. */\n nativeRoster?: ReadonlySet<string> | ReadonlyArray<string>\n /** Optional persona allowlist, by `agentName`. See the matching field on\n * `BuildOpts`. */\n personaAllowlist?: ReadonlySet<string> | ReadonlyArray<string>\n /** Whether to emit `peer-review-coordinator`. Default true. */\n includeCoordinator?: boolean\n /** Fixed `effort:` frontmatter overrides. See the matching fields on\n * `BuildOpts`. */\n scoutEffort?: SubagentEffort\n implementerFastEffort?: SubagentEffort\n reviewerFastEffort?: SubagentEffort\n fastProfile?: boolean\n plannerModel?: string\n implementerEffort?: SubagentEffort\n reviewerEffort?: SubagentEffort\n plannerEffort?: SubagentEffort\n criticEffort?: SubagentEffort\n /** Resolved fast native critic model. */\n criticModel?: string\n /** Extra subagent definitions to register alongside the peer/worker agents\n * (written as `.md` files so they appear in the Task `subagent_type` enum).\n * Used by `serve` to inject Claude Code's built-in subagents (Explore/Plan/\n * general-purpose) that the Agent SDK does NOT register — see\n * BUILTIN_SUBAGENT_DEFINITIONS. Must NOT be passed for `github-router claude`,\n * where the CLI provides those built-ins natively (same-name would shadow). */\n builtinSubagents?: PeerAgentDefinitions\n /** Override for tests. Defaults to PATHS.CODEX_HOME. */\n codexHome?: string\n /** Override for tests. Defaults to PATHS.CLAUDE_RUNTIME_DIR. */\n runtimeDir?: string\n /** Override for tests. Defaults to a fresh 32-byte hex nonce. */\n nonce?: string\n /** Override for tests. Defaults to ~/.claude/agents (where Claude Code\n * reads subagent .md files at session start). */\n agentsDir?: string\n}\n\n/**\n * Default location Claude Code reads subagent .md files from at session\n * startup. Files placed here populate the Task `subagent_type` enum.\n *\n * We point at the router-owned `PATHS.CLAUDE_CONFIG_DIR/agents/` because\n * `getClaudeCodeEnvVars` sets `CLAUDE_CONFIG_DIR=PATHS.CLAUDE_CONFIG_DIR`\n * (the snapshot-mirror substrate fix that gives spawned teammates an\n * authenticatable on-disk credential). The user's own custom-agent .md\n * files were copied into this same dir by `ensureClaudeConfigMirror`,\n * so writing peer-* files here doesn't conflict — and the boot-time\n * sweep is scoped to peer-* names only via the persona-name allowlist.\n */\nfunction defaultAgentsDir(): string {\n return path.join(PATHS.CLAUDE_CONFIG_DIR, \"agents\")\n}\n\n/**\n * YAML frontmatter string-escape — sufficient for our use case where\n * descriptions can contain colons, quotes, newlines. Wraps the value\n * in double-quotes and escapes:\n * - `\\` and `\"` (canonical YAML)\n * - `\\n`, `\\r`, `\\t` (whitespace controls — `\\r` matters on Windows-edited\n * literals; strict YAML 1.2 parsers reject raw `\\r` in double-quoted\n * scalars)\n * - other C0 control chars (\\x00-\\x08, \\x0B, \\x0C, \\x0E-\\x1F) and\n * DEL (\\x7F) — encoded as `\\xNN` so the YAML stays valid even if\n * a future description sources data from an external file\n *\n * NOT a general-purpose YAML serializer; we control the inputs.\n */\nfunction escapeYamlString(s: string): string {\n return (\n `\"${\n s\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, \"\\\\\\\"\")\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\t/g, \"\\\\t\")\n // The point of this regex IS to match control characters so we\n // can replace them with safe `\\xNN` escapes — the lint rule's\n // concern (accidental control-char in regex) doesn't apply here.\n // eslint-disable-next-line no-control-regex\n .replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, (c) =>\n `\\\\x${c.charCodeAt(0).toString(16).padStart(2, \"0\")}`,\n )\n }\"`\n )\n}\n\n/**\n * Strict allowlist for subagent names — controls both the YAML\n * frontmatter `name:` field AND the filename suffix. Defense-in-depth:\n * even if a future contributor wires in a dynamic agent name from\n * outside, the validator at the top of `writePeerAgentMdFiles` rejects\n * anything that wouldn't be a safe bare YAML scalar AND a safe path\n * component.\n */\nconst VALID_AGENT_NAME = /^[A-Za-z][A-Za-z0-9-]*$/\n\n/**\n * Emit the subagent-frontmatter `mcpServers` block as a YAML sequence of\n * single-key maps (the INLINE form that connects on subagent start — a bare\n * name-reference would re-trigger claude-code#30280). Scalars are\n * JSON.stringify-quoted, which is valid YAML double-quoted syntax (handles the\n * Windows-path/backslash headersHelper command safely).\n *\n * ```yaml\n * mcpServers:\n * - workers:\n * type: http\n * url: \"http://127.0.0.1:PORT/mcp/workers\"\n * headers:\n * Authorization: \"Bearer <nonce>\"\n * headersHelper: \"<cmd>\"\n * ```\n */\nfunction emitMcpServersYaml(mcpServers: Record<string, HttpMcpEntry>): Array<string> {\n const lines: Array<string> = [\"mcpServers:\"]\n for (const [key, entry] of Object.entries(mcpServers)) {\n lines.push(` - ${JSON.stringify(key)}:`)\n lines.push(` type: ${JSON.stringify(entry.type)}`)\n lines.push(` url: ${JSON.stringify(entry.url)}`)\n lines.push(` headers:`)\n for (const [hk, hv] of Object.entries(entry.headers)) {\n lines.push(` ${JSON.stringify(hk)}: ${JSON.stringify(hv)}`)\n }\n if (entry.headersHelper !== undefined) {\n lines.push(` headersHelper: ${JSON.stringify(entry.headersHelper)}`)\n }\n }\n return lines\n}\n\n/** Build a single subagent .md file body (frontmatter + system prompt).\n *\n * `tools` (optional) becomes a `tools:` frontmatter allowlist RESTRICTING the\n * subagent to exactly those tools (omission inherits the parent's full toolset,\n * per Claude Code semantics). Used by the `worker-*` dispatchers to pin each to\n * its single `mcp__<workersKey>__<mode>` tool — which physically prevents them\n * from spawning other agents or doing extra work. `mcpServers` (optional) is\n * emitted as an inline `mcpServers` frontmatter list so the subagent connects\n * directly to its scoped MCP server(s) — a workaround for claude-code#30280\n * (Agent-tool subagents don't reliably inherit the session's HTTP MCP servers).\n * Names are validated by the caller (`writePeerAgentMdFiles`) / are\n * proxy-generated, so no escaping needed beyond the comma-join Claude Code's\n * frontmatter parser expects. */\nexport function buildAgentMd(spec: {\n name: string\n description: string\n prompt: string\n model?: string\n effort?: SubagentEffort\n tools?: ReadonlyArray<string>\n mcpServers?: Record<string, HttpMcpEntry>\n}): string {\n const lines = [\n \"---\",\n `name: ${spec.name}`,\n `description: ${escapeYamlString(spec.description)}`,\n ]\n if (spec.model) {\n lines.push(`model: ${escapeYamlString(spec.model)}`)\n }\n if (spec.effort) {\n lines.push(`effort: ${escapeYamlString(spec.effort)}`)\n }\n if (spec.tools && spec.tools.length > 0) {\n // YAML flow array of quoted strings — matches how Claude Code's loader\n // parses `tools:` (an array), and quoting keeps the `mcp__…__*` wildcard\n // a plain string (the `*` is never mistaken for a YAML alias).\n lines.push(`tools: [${spec.tools.map((t) => JSON.stringify(t)).join(\", \")}]`)\n }\n if (spec.mcpServers && Object.keys(spec.mcpServers).length > 0) {\n lines.push(...emitMcpServersYaml(spec.mcpServers))\n }\n lines.push(\"---\", \"\", spec.prompt, \"\")\n return lines.join(\"\\n\")\n}\n\n/**\n * Write per-launch subagent .md files into the user's `~/.claude/agents/`\n * directory so they appear in Claude Code's Task `subagent_type` enum\n * (which `--agents` JSON files do NOT, per claude-code-guide expert).\n *\n * Filenames follow `peer-<pid>-<rand>-<agentName>.md` so the boot-time\n * sweep (`sweepStalePeerAgentMdFiles` in paths.ts) can drop orphans\n * from crashed prior proxy sessions without touching the user's other\n * `.claude/agents/` files. The `name:` field in the frontmatter is the\n * canonical agent identifier — matching across files would cause Claude\n * Code to (un)deterministically pick one, so concurrent proxies running\n * the same agents need different filenames but resolve to the same\n * agent name (intended — they're the same subagent, just registered\n * twice).\n *\n * Returns the file paths plus a cleanup() that unlinks them.\n */\nexport async function writePeerAgentMdFiles(\n agents: Record<string, PeerAgentDefinition>,\n opts: { agentsDir?: string; fileSuffix: string },\n): Promise<{ paths: Array<string>; cleanup: () => Promise<void> }> {\n // Validate every agent name BEFORE touching the filesystem. Defense-\n // in-depth against a future contributor wiring in a dynamic name from\n // outside (--agent flag, MCP tool registration, etc.). Names appear\n // in BOTH the filename (path-traversal vector if unvalidated) and the\n // YAML frontmatter `name:` field (parser-confusion if it contains\n // YAML indicator chars). The strict regex matches only safe lowercase\n // identifiers — every current persona/coordinator name passes.\n for (const name of Object.keys(agents)) {\n if (!VALID_AGENT_NAME.test(name)) {\n throw new Error(\n `writePeerAgentMdFiles: invalid agent name ${JSON.stringify(name)} — `\n + `must match ${VALID_AGENT_NAME.source}`,\n )\n }\n }\n const dir = opts.agentsDir ?? defaultAgentsDir()\n await fs.mkdir(dir, { recursive: true })\n const paths: Array<string> = []\n try {\n for (const [name, def] of Object.entries(agents)) {\n const filePath = path.join(dir, `peer-${opts.fileSuffix}-${name}.md`)\n // Same idempotency pattern as the JSON tempfiles: unlink first so\n // O_EXCL succeeds even if a same-suffix file somehow survived.\n await fs.unlink(filePath).catch(() => {})\n await writeRuntimeFileSecure(\n filePath,\n buildAgentMd({\n name,\n description: def.description,\n prompt: def.prompt,\n model: def.model,\n effort: def.effort,\n tools: def.tools,\n mcpServers: def.mcpServers,\n }),\n )\n paths.push(filePath)\n }\n } catch (err) {\n // Partial-failure cleanup: if iteration N fails (disk full, EPERM,\n // EEXIST race), the N-1 successfully-written files would otherwise\n // be orphans the caller has no handle to. Unlink the partials before\n // re-throwing so the boot sweep doesn't have to deal with them.\n await Promise.allSettled(paths.map((p) => fs.unlink(p)))\n throw err\n }\n const cleanup = async (): Promise<void> => {\n await Promise.allSettled(paths.map((p) => fs.unlink(p)))\n }\n return { paths, cleanup }\n}\n\nexport type InjectPeerMcpResult =\n | { ok: true; serversAdded: ReadonlyArray<string> }\n | {\n ok: false\n reason: \"user-has-conflicting-entry\"\n conflictingServers: ReadonlyArray<string>\n }\n\ninterface InjectOpts {\n codexCli: boolean\n /** Stable invocation baked into persisted headersHelper commands. */\n selfInvocation: SelfInvocation\n geminiAvailable: boolean\n /** Resolved config keys per enabled group (from `resolveGroupKeysFromMirror`).\n * Collision-free by construction, so the merge below never overwrites a\n * user entry. */\n groupKeys: ResolvedGroupKeys\n /** Per-launch nonce — must match what writePeerMcpRuntimeFiles wrote\n * so the proxy's /mcp Authorization check passes. */\n nonce: string\n /** Override for tests. Defaults to PATHS.CODEX_HOME. */\n codexHome?: string\n /** Override for tests. Defaults to PATHS.CLAUDE_CONFIG_DIR (per-launch). */\n claudeConfigDir?: string\n}\n\n/**\n * Read just the `mcpServers` object from a mirrored `.claude.json` (or `{}`\n * on missing / malformed). Used by `resolveGroupKeysFromMirror` to detect\n * which of our bare group keys would collide with a user-side entry.\n */\nasync function readMcpServersSnapshot(\n target: string,\n): Promise<Record<string, unknown>> {\n try {\n const raw = await fs.readFile(target, \"utf8\")\n const parsed = JSON.parse(raw) as unknown\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n const servers = (parsed as Record<string, unknown>).mcpServers\n if (servers && typeof servers === \"object\" && !Array.isArray(servers)) {\n return servers as Record<string, unknown>\n }\n }\n } catch {\n // Missing / unparsable → treat as no existing servers (a fresh mirror).\n }\n return {}\n}\n\n/**\n * Resolve a config-entry key for each enabled group, defending against\n * collisions with the user's own `mcpServers`. Prefer the bare key\n * (`peers`/`search`/…); on collision walk the numbered fallback sequence\n * `gh-router-<group>`, `gh-router-<group>-2`, `gh-router-<group>-3`, …\n * until a free name is found. This NEVER skips and NEVER returns a name the\n * user already owns: every enabled group is guaranteed a key WE control, so\n * a capability is never silently dropped AND the model is never routed at\n * the user's same-named server (the caller threads these resolved keys into\n * both the `mcpServers` entries AND the persona `.md` routing strings). The\n * `skipped` field is retained for API stability but is always empty now.\n *\n * Reads the mirror snapshot once; the caller passes the result to BOTH\n * `writePeerMcpRuntimeFiles` and `injectPeerMcpIntoMirror`. The mirror is a\n * per-launch dir written ONLY by us (after `ensureClaudeConfigMirror`\n * snapshotted the user's config) and nothing mutates it between this read\n * and `injectPeerMcpIntoMirror`'s write, so the two reads see identical\n * state — no TOCTOU window, and the inject-side defensive conflict check\n * never fires for these resolved keys.\n */\nexport async function resolveGroupKeysFromMirror(\n enabledGroups: ReadonlyArray<McpGroup>,\n claudeConfigDir?: string,\n): Promise<{ keys: ResolvedGroupKeys; skipped: Array<McpGroup> }> {\n const dir = claudeConfigDir ?? PATHS.CLAUDE_CONFIG_DIR\n const existing = await readMcpServersSnapshot(path.join(dir, \".claude.json\"))\n const keys: ResolvedGroupKeys = {}\n for (const group of enabledGroups) {\n const bare = GROUP_META[group].preferredKey\n if (existing[bare] === undefined) {\n keys[group] = bare\n continue\n }\n // Bare key taken — walk the prefixed sequence until a free name.\n let candidate = `gh-router-${group}`\n let n = 1\n while (existing[candidate] !== undefined) {\n n += 1\n candidate = `gh-router-${group}-${n}`\n }\n keys[group] = candidate\n }\n return { keys, skipped: [] }\n}\n\n/**\n * Mutate the mirrored `<CLAUDE_CONFIG_DIR>/.claude.json` to add the\n * `gh-router-peers` entry (and `codex-cli` when enabled) under\n * `mcpServers`. This is the load-bearing fix for subagent MCP visibility.\n *\n * Subagents — Agent-tool subagents, forks, and agent-teams subprocesses\n * — discover MCP servers from persistent scopes (`.claude.json` and\n * project-scope `.mcp.json`), NOT from the parent's `--mcp-config` CLI\n * flag. Writing into the per-launch mirror's `.claude.json` makes the\n * MCP entry visible to subagents transparently: they inherit\n * `CLAUDE_CONFIG_DIR` from the parent's env, so they read the same\n * config file we just mutated.\n *\n * Safety:\n * - Refuses to overwrite a same-named user-side entry (the snapshot\n * copied their `.claude.json` first, so an existing entry would\n * belong to the user). Returns `{ ok: false }` so the caller can\n * fall back to leaving `--mcp-config` in place for the parent.\n * - Preserves all other top-level fields and other `mcpServers`\n * entries.\n * - Atomic write: temp-file with `wx` (`O_CREAT | O_EXCL`) followed by\n * `rename`, mirroring the synthetic-credentials write pattern in\n * `ensureClaudeConfigMirror`. Mode 0o600. The per-launch\n * `CLAUDE_CONFIG_DIR` means there are no cross-launch racers.\n */\nexport async function injectPeerMcpIntoMirror(\n serverUrl: string,\n opts: InjectOpts,\n): Promise<InjectPeerMcpResult> {\n const dir = opts.claudeConfigDir ?? PATHS.CLAUDE_CONFIG_DIR\n const target = path.join(dir, \".claude.json\")\n\n // 1. Read existing snapshot (or {} if missing / malformed). We do NOT\n // fail loudly on parse error — start fresh and let the proxy\n // session run. Logging the warn surfaces the underlying corruption\n // for the user to investigate.\n let existing: Record<string, unknown> = {}\n try {\n const raw = await fs.readFile(target, \"utf8\")\n try {\n const parsed = JSON.parse(raw) as unknown\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n existing = parsed as Record<string, unknown>\n } else {\n consola.warn(\n `injectPeerMcpIntoMirror: ${target} parsed to non-object `\n + `(typeof=${typeof parsed}); discarding contents and starting fresh.`,\n )\n }\n } catch (err) {\n consola.warn(\n `injectPeerMcpIntoMirror: cannot parse ${target} as JSON; `\n + `starting fresh (existing contents will be overwritten):`,\n err,\n )\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n consola.debug(\n `injectPeerMcpIntoMirror: cannot read ${target}:`,\n err,\n )\n }\n // Either ENOENT (first-ever launch, no user .claude.json) or some\n // other read error. Either way, start fresh.\n }\n\n // 2. Normalize `mcpServers` to an object (clobber if user had it set\n // to a non-object value — that's already broken; our overwrite\n // won't make it worse and the warn flags it).\n let mcpServers: Record<string, unknown>\n const rawServers = existing.mcpServers\n if (\n rawServers !== undefined\n && rawServers !== null\n && typeof rawServers === \"object\"\n && !Array.isArray(rawServers)\n ) {\n mcpServers = rawServers as Record<string, unknown>\n } else {\n if (rawServers !== undefined && rawServers !== null) {\n consola.warn(\n `injectPeerMcpIntoMirror: mcpServers field in ${target} is not an `\n + `object (typeof=${typeof rawServers}); replacing with our entry.`,\n )\n }\n mcpServers = {}\n }\n\n // 3. Build our desired entries from the SAME builder used for\n // --mcp-config so the two channels never drift. Keys are pre-resolved\n // (collision-free) by `resolveGroupKeysFromMirror`.\n const peerConfig = buildPeerMcpConfig(serverUrl, {\n codexCli: opts.codexCli,\n geminiAvailable: opts.geminiAvailable,\n groupKeys: opts.groupKeys,\n nonce: opts.nonce,\n codexHome: opts.codexHome ?? PATHS.CODEX_HOME,\n workspaceHeaderCmd: buildWorkspaceHeaderHelperCommand(opts.selfInvocation),\n })\n\n // 4. Defensive: the resolved keys are collision-free by construction, so\n // this should never fire. If it somehow does (a racing mutation of the\n // mirror between resolution and now), refuse to overwrite the user's\n // entry and let the caller fall back to --mcp-config (parent-only).\n const conflicts: Array<string> = []\n for (const name of Object.keys(peerConfig.mcpServers)) {\n if (mcpServers[name] !== undefined) conflicts.push(name)\n }\n if (conflicts.length > 0) {\n consola.warn(\n `injectPeerMcpIntoMirror: your ~/.claude/.claude.json already has `\n + `mcpServers entries named [${conflicts.join(\", \")}]; refusing to `\n + `overwrite. Subagents will not see those tools — only the parent `\n + `session via --mcp-config fallback. To resolve, rename the `\n + `user-side server(s) (e.g. via \\`claude mcp remove\\`) and relaunch.`,\n )\n return {\n ok: false,\n reason: \"user-has-conflicting-entry\",\n conflictingServers: conflicts,\n }\n }\n\n // 5. Merge our entries; preserve everything else.\n for (const [name, entry] of Object.entries(peerConfig.mcpServers)) {\n mcpServers[name] = entry\n }\n existing.mcpServers = mcpServers\n\n // 6. Atomic temp+rename. Same pattern as the synthetic .credentials.json\n // write in ensureClaudeConfigMirror. Per-launch dir means there are\n // no cross-launch racers; EEXIST on the tempfile is essentially\n // impossible (per-pid + 8-hex random). Mode 0o600 to match the\n // upstream Claude Code file perms.\n const desiredJson = JSON.stringify(existing, null, 2) + \"\\n\"\n await fs.mkdir(dir, { recursive: true })\n const tempPath = `${target}.${process.pid}.${randomBytes(4).toString(\"hex\")}.tmp`\n try {\n await fs.writeFile(tempPath, desiredJson, { mode: 0o600, flag: \"wx\" })\n await fs.rename(tempPath, target)\n } catch (err) {\n await fs.unlink(tempPath).catch(() => {})\n throw err\n }\n\n return { ok: true, serversAdded: Object.keys(peerConfig.mcpServers) }\n}\n\n/**\n * Generate a per-launch nonce, write the MCP config + agents JSON\n * tempfiles under `CLAUDE_RUNTIME_DIR` with mode 0o600 and `O_EXCL`,\n * and return a `cleanup()` to unlink them on shutdown.\n *\n * Filenames are `peer-mcp-<pid>-<rand>.json` and `peer-agents-<pid>-<rand>.json`.\n * The PID prefix is what the boot-time sweep (`sweepStaleRuntimeFiles` in\n * paths.ts) keys off to drop orphans from crashed prior sessions; the\n * random suffix prevents two concurrent calls within the same process\n * from clobbering each other's files (e.g., a proxy that internally\n * relaunches its spawned child without restarting itself).\n */\nexport async function writePeerMcpRuntimeFiles(\n serverUrl: string,\n opts: WriteOpts,\n): Promise<PeerMcpRuntimeFiles> {\n const nonce = opts.nonce ?? randomBytes(32).toString(\"hex\")\n const runtimeDir = opts.runtimeDir ?? PATHS.CLAUDE_RUNTIME_DIR\n const codexHome = opts.codexHome ?? PATHS.CODEX_HOME\n // Defensive mkdir — `ensurePaths` already creates this in the normal\n // setupAndServe path, but if we're called from a context that didn't\n // run it (tests, future callers), don't fail with ENOENT.\n await fs.mkdir(runtimeDir, { recursive: true })\n if (process.platform !== \"win32\") {\n await fs.chmod(runtimeDir, 0o700).catch(() => {})\n }\n // 4-byte random suffix gives 2^32 distinct names per PID — collision-free\n // for any realistic count of in-process re-invocations.\n const fileSuffix = `${process.pid}-${randomBytes(4).toString(\"hex\")}`\n const mcpConfigPath = path.join(runtimeDir, `peer-mcp-${fileSuffix}.json`)\n const agentsPath = path.join(runtimeDir, `peer-agents-${fileSuffix}.json`)\n\n const mcpConfig = buildPeerMcpConfig(serverUrl, {\n codexCli: opts.codexCli,\n geminiAvailable: opts.geminiAvailable,\n geminiModel: opts.geminiModel,\n groupKeys: opts.groupKeys,\n nonce,\n codexHome,\n workspaceHeaderCmd: buildWorkspaceHeaderHelperCommand(opts.selfInvocation),\n })\n const agents = buildPeerAgentDefinitions({\n codexCli: opts.codexCli,\n geminiAvailable: opts.geminiAvailable,\n geminiModel: opts.geminiModel,\n groupKeys: opts.groupKeys,\n workerToolsAvailable: opts.workerToolsAvailable,\n browseAvailable: opts.browseAvailable,\n nativeSubagentModel: opts.nativeSubagentModel,\n reviewerModel: opts.reviewerModel,\n reviewerFastModel: opts.reviewerFastModel,\n brainstormModel: opts.brainstormModel,\n scoutModel: opts.scoutModel,\n scribeModel: opts.scribeModel,\n implementerFastModel: opts.implementerFastModel,\n generalPurposeFastModel: opts.generalPurposeFastModel,\n nativeRoster: opts.nativeRoster,\n personaAllowlist: opts.personaAllowlist,\n includeCoordinator: opts.includeCoordinator,\n scoutEffort: opts.scoutEffort,\n implementerFastEffort: opts.implementerFastEffort,\n reviewerFastEffort: opts.reviewerFastEffort,\n fastProfile: opts.fastProfile,\n plannerModel: opts.plannerModel,\n implementerEffort: opts.implementerEffort,\n reviewerEffort: opts.reviewerEffort,\n plannerEffort: opts.plannerEffort,\n criticModel: opts.criticModel,\n criticEffort: opts.criticEffort,\n nonce,\n codexHome,\n serverUrl,\n workspaceHeaderCmd: buildWorkspaceHeaderHelperCommand(opts.selfInvocation),\n })\n\n // If a prior same-PID file survived (boot sweep didn't run, or this\n // function is called twice in one lifecycle), unlink first so wx\n // succeeds. Letting wx fail loudly is correct from a security\n // standpoint, but here we're the same PID — there's no race window\n // a different process could exploit.\n await fs.unlink(mcpConfigPath).catch(() => {})\n await fs.unlink(agentsPath).catch(() => {})\n\n let mdResult: Awaited<ReturnType<typeof writePeerAgentMdFiles>> | undefined\n try {\n await writeRuntimeFileSecure(mcpConfigPath, JSON.stringify(mcpConfig, null, 2))\n await writeRuntimeFileSecure(agentsPath, JSON.stringify(agents, null, 2))\n\n // Phase 2.5: also write the same agents as .md files into\n // ~/.claude/agents/ — this is the registry Claude Code's Task\n // `subagent_type` enum reads from at session start. The `--agents`\n // JSON path above is kept for inspection / future-proofing but the\n // .md files are what makes the subagents actually invokable from\n // Opus's tool surface.\n //\n // `builtinSubagents` (serve only) adds Claude Code's built-in Explore/Plan/\n // general-purpose, which the Agent SDK does NOT register — so the model's\n // habitual `Agent(subagent_type:\"Explore\")` calls resolve instead of 404ing.\n const agentsToWrite = opts.builtinSubagents\n ? { ...agents, ...opts.builtinSubagents }\n : agents\n mdResult = await writePeerAgentMdFiles(agentsToWrite, {\n agentsDir: opts.agentsDir,\n fileSuffix,\n })\n } catch (err) {\n if (mdResult) await mdResult.cleanup().catch(() => {})\n await Promise.allSettled([fs.unlink(mcpConfigPath), fs.unlink(agentsPath)])\n throw err\n }\n\n const completeMdResult = mdResult\n if (!completeMdResult) throw new Error(\"peer MCP agent files were not generated\")\n\n const personas = opts.fastProfile\n ? []\n : personasFor({\n codexCli: opts.codexCli,\n geminiAvailable: opts.geminiAvailable,\n geminiModel: opts.geminiModel,\n agentAllowlist: opts.personaAllowlist,\n })\n\n const cleanup = async (): Promise<void> => {\n await Promise.allSettled([\n fs.unlink(mcpConfigPath),\n fs.unlink(agentsPath),\n completeMdResult.cleanup(),\n ])\n }\n\n return {\n mcpConfigPath,\n agentsPath,\n agentMdPaths: completeMdResult.paths,\n nonce,\n personas,\n cleanup,\n }\n}\n","import fs from \"node:fs/promises\"\n\nimport { STRIPPED_AUTH_ROUTING_ENV_KEYS } from \"./stripped-env-keys\"\n\n/**\n * CLAUDE_CODE_* / auth / routing env keys that must NOT reach the CloudCLI-spawned\n * serve agent through the mirror `settings.json` `env` block. CloudCLI applies\n * that block via the Agent SDK's `settingSources`, so anything a user set in their\n * real `~/.claude/settings.json` (for their own workflow) is mirrored in and\n * mis-shapes the single serve chat agent — the exact mechanism behind the\n * coordinator-mode bug.\n *\n * - {@link STRIPPED_AUTH_ROUTING_ENV_KEYS} (shared with the process-env strip in\n * `launch.ts`): auth/routing/remote keys that would re-route the agent OFF the\n * github-router proxy (`ANTHROPIC_BASE_URL`, `CLAUDE_CODE_USE_BEDROCK/VERTEX/\n * FOUNDRY`, a personal gateway), inject real auth over the synthetic\n * credential (`ANTHROPIC_API_KEY`/`AUTH_TOKEN`/`OAUTH_TOKEN`), pin a\n * non-Copilot `ANTHROPIC_MODEL`, or activate the unimplemented Bridge/remote\n * path. The settings.json `env` block is a SECOND vector for the same keys the\n * process-env strip already blocks.\n * - `CLAUDE_CODE_COORDINATOR_MODE`: strips the single agent to delegation-only\n * (Glob/Read/Bash fail \"not enabled in this context\").\n * - `CLAUDE_CODE_SUBAGENT_MODEL`: a rank-#1 hard override that would retarget\n * the injected implementer/peer-critic subagents off their frontmatter models.\n *\n * `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` is intentionally NOT stripped — purely\n * additive, matching `github-router claude` parity.\n */\nconst SERVE_STRIP_ENV_KEYS = [\n ...STRIPPED_AUTH_ROUTING_ENV_KEYS,\n \"CLAUDE_CODE_COORDINATOR_MODE\",\n \"CLAUDE_CODE_SUBAGENT_MODEL\",\n] as const\n\nasync function readSettingsObject(\n settingsPath: string,\n): Promise<Record<string, unknown> | null> {\n let raw: string\n try {\n raw = await fs.readFile(settingsPath, \"utf8\")\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"ENOENT\") return null\n throw err\n }\n const parsed: unknown = JSON.parse(raw)\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>\n }\n throw new Error(`settings.json at ${settingsPath} is not a JSON object; refusing to overwrite`)\n}\n\nasync function writeSettingsObject(\n settingsPath: string,\n obj: Record<string, unknown>,\n suffix: string,\n): Promise<void> {\n const tmp = `${settingsPath}.${process.pid}.${suffix}.tmp`\n await fs.writeFile(tmp, `${JSON.stringify(obj, null, 2)}\\n`, { mode: 0o600 })\n await fs.rename(tmp, settingsPath)\n}\n\n/**\n * Remove serve-inappropriate CLAUDE_CODE_* keys (see {@link SERVE_STRIP_ENV_KEYS})\n * from the serve mirror `settings.json` `env` block. UNCONDITIONAL — unlike the\n * permission bypass this is NOT gated by `GH_ROUTER_SERVE_NO_AUTO_APPROVE`,\n * because a user who only wants permission prompts still needs a working toolset.\n * Serve mirror only; never the operator's real `~/.claude/settings.json`. Atomic\n * temp+rename, mode 0o600. Returns the keys it removed (empty if none present).\n */\nexport async function sanitizeServeSettingsEnv(\n settingsPath: string,\n): Promise<{ removed: string[] }> {\n const existing = await readSettingsObject(settingsPath)\n if (!existing) return { removed: [] }\n\n const envRaw = existing.env\n if (!envRaw || typeof envRaw !== \"object\" || Array.isArray(envRaw)) {\n return { removed: [] }\n }\n const env = { ...(envRaw as Record<string, unknown>) }\n const removed: string[] = []\n for (const key of SERVE_STRIP_ENV_KEYS) {\n if (key in env) {\n delete env[key]\n removed.push(key)\n }\n }\n if (removed.length === 0) return { removed: [] }\n\n await writeSettingsObject(settingsPath, { ...existing, env }, \"serveenv\")\n return { removed }\n}\n\n/**\n * Native Claude Code tools worth auto-approving alongside our injected MCP\n * servers so PLAN mode is frictionless for research. These are read-only\n * discovery tools that plan mode would otherwise prompt for.\n *\n * Deliberately MINIMAL and safe:\n * - `WebSearch` / `WebFetch` — network reads; exactly the research surface a\n * planner reaches for, and they prompt by default in plan mode.\n * - EXCLUDES `Read`/`Glob`/`Grep` — Claude Code already runs them in plan mode\n * without a rule (its built-in safe list), so a rule would be redundant.\n * - EXCLUDES `Bash` — can mutate (`rm`, redirects); blanket-allow is unsafe.\n * Curated `Bash(<readonly cmd> *)` rules are the user's own call.\n * - EXCLUDES `Task`/`Skill`/`Workflow`/`SendMessage` — spawn/delegate; a\n * subagent launched in plan mode isn't guaranteed to inherit plan's\n * read-only restriction, so auto-approving them is a plan-mode-bypass vector.\n * - EXCLUDES `Edit`/`Write`/`NotebookEdit` etc. — plan mode gates them by\n * design and we must not override that.\n */\nexport const NATIVE_RESEARCH_ALLOW_RULES = [\"WebSearch\", \"WebFetch\"] as const\n\n/**\n * The routine native Claude Code tools serve auto-approves so ordinary agent\n * work stays seamless (no per-call prompt) — the exact surface a coding agent\n * uses turn to turn. Seeded into CloudCLI's `localStorage['claude-settings']`\n * `allowedTools` (feeds the Agent SDK `canUseTool` fast-path + `sdkOptions.allowedTools`).\n *\n * DELIBERATELY EXCLUDES the two interaction tools `AskUserQuestion` and\n * `ExitPlanMode`. CloudCLI hard-codes both into its `TOOLS_REQUIRING_INTERACTION`\n * set (claude-sdk.js) and renders a real question widget / plan Approve-Reject\n * card for them — but ONLY when `canUseTool` runs (non-bypass) AND they are NOT\n * pre-approved. Leaving them off this list is what routes them to the human\n * instead of letting the model auto-answer its own question. This is the same\n * line the interactive Claude CLI draws: routine tools seamless, decisions to\n * the user. Never add either name here.\n *\n * A tool omitted from this list degrades to a one-off Allow/Deny prompt in\n * CloudCLI — safe, not broken — so the list is a superset of the common surface\n * rather than an exact registry match (extra names for tools this Claude build\n * lacks are harmless no-ops).\n */\nexport const SEAMLESS_BUILTIN_TOOLS = [\n \"Task\",\n \"Bash\",\n \"BashOutput\",\n \"KillShell\",\n \"Glob\",\n \"Grep\",\n \"Read\",\n \"Edit\",\n \"Write\",\n \"NotebookEdit\",\n \"WebFetch\",\n \"WebSearch\",\n \"TodoWrite\",\n \"Skill\",\n \"SlashCommand\",\n \"EnterPlanMode\",\n] as const\n\n/**\n * Merge arbitrary allow rules into a mirror `settings.json` `permissions.allow`\n * so the listed tools auto-run WITHOUT a permission prompt in every mode —\n * including plan mode, where a matched allow rule bypasses the prompt for any\n * tool NOT on plan mode's file-edit/shell-write restricted list (MCP tools and\n * read-only natives like WebSearch/WebFetch). See {@link NATIVE_RESEARCH_ALLOW_RULES}\n * for the native additions and the \"Configure permissions\" Claude Code doc for\n * the plan-mode semantics.\n *\n * Rules are literal allow strings (`mcp__peers`, `WebSearch`, …). Existing\n * `allow` entries and `deny`/`ask` are preserved; merge is idempotent (no write\n * when every rule is already present). Mirror only; never the operator's real\n * settings. Atomic temp+rename, mode 0o600.\n */\nexport async function injectAllowRules(\n settingsPath: string,\n rules: readonly string[],\n): Promise<{ added: string[] }> {\n const want = [...new Set(rules.filter(Boolean))]\n if (want.length === 0) return { added: [] }\n\n const existing = (await readSettingsObject(settingsPath)) ?? {}\n const permsRaw = existing.permissions\n const perms: Record<string, unknown> =\n permsRaw && typeof permsRaw === \"object\" && !Array.isArray(permsRaw)\n ? { ...(permsRaw as Record<string, unknown>) }\n : {}\n const allow = Array.isArray(perms.allow) ? [...(perms.allow as unknown[])] : []\n const present = new Set(allow.filter((x): x is string => typeof x === \"string\"))\n const added = want.filter((rule) => !present.has(rule))\n if (added.length === 0) return { added: [] }\n\n perms.allow = [...allow, ...added]\n await writeSettingsObject(settingsPath, { ...existing, permissions: perms }, \"allowrules\")\n return { added }\n}\n\n/**\n * Build the full plan-mode allow-rule set: a bare `mcp__<server>` rule per\n * injected MCP server (whole-server allow) plus the native research tools. The\n * server keys are the RESOLVED mcpServers config keys (collision-aware —\n * `peers` or `gh-router-peers`, `codex-cli`, …) so each rule matches the server\n * name the model actually sees.\n */\nexport function planModeAllowRules(serverKeys: readonly string[]): string[] {\n return [\n ...[...new Set(serverKeys.filter(Boolean))].map((k) => `mcp__${k}`),\n ...NATIVE_RESEARCH_ALLOW_RULES,\n ]\n}\n\n/**\n * Ensure the serve mirror's `settings.json` `permissions.defaultMode` is NOT\n * `bypassPermissions` — the load-bearing half of serve's \"seamless routine +\n * decisions to the user\" model.\n *\n * Under `bypassPermissions` the Agent SDK resolves approval at the permission-mode\n * step and SKIPS the `canUseTool` callback entirely (claude-sdk.js) — the only\n * channel CloudCLI's interactive widgets ride on, so `AskUserQuestion` and\n * `ExitPlanMode` auto-resolve on a model-generated answer and never reach the human.\n * CloudCLI leaves `sdkOptions.permissionMode` unset when the composer is in default\n * mode, so the binary falls back to THIS `defaultMode` — a stale `bypassPermissions`\n * here would silently re-defeat the fix through the settings vector.\n *\n * MINIMAL override: only rewrite when the mode is absent or an explicit\n * `bypassPermissions` (→ `\"default\"`, keeping `canUseTool` live). A user's\n * deliberate NON-bypass posture (`plan` / `acceptEdits` / `default`) is preserved\n * verbatim — all three already keep `canUseTool` live, so there is nothing to fix\n * and no reason to override their choice. `allow`/`deny`/`ask` are always untouched.\n *\n * Only ever rewrites the per-launch serve mirror, never the operator's real\n * `~/.claude/settings.json`. Atomic temp+rename, mode 0o600. A non-object\n * settings.json throws; the caller wraps this in warn-and-continue.\n *\n * Opt out with `GH_ROUTER_SERVE_NO_AUTO_APPROVE=1` (the caller skips this AND the\n * allow-list/localStorage seed) — the mirrored `defaultMode` is then left exactly\n * as snapshotted and CloudCLI prompts on every not-yet-approved tool.\n */\nexport async function configureServeDefaultPermissionMode(\n settingsPath: string,\n): Promise<{ written: boolean }> {\n const existing = (await readSettingsObject(settingsPath)) ?? {}\n const permsRaw = existing.permissions\n const perms: Record<string, unknown> =\n permsRaw && typeof permsRaw === \"object\" && !Array.isArray(permsRaw)\n ? { ...(permsRaw as Record<string, unknown>) }\n : {}\n\n // Preserve any explicit NON-bypass mode the user set — it already keeps\n // canUseTool live, so overriding it would silently discard their posture.\n if (perms.defaultMode !== undefined && perms.defaultMode !== \"bypassPermissions\") {\n return { written: false }\n }\n // Absent or an explicit bypass → pin to \"default\" so canUseTool stays live.\n perms.defaultMode = \"default\"\n await writeSettingsObject(settingsPath, { ...existing, permissions: perms }, \"servemode\")\n return { written: true }\n}\n","import { DEFINITION_OF_GREATNESS } from \"~/lib/first-mate/operating-protocol\"\n\nexport const FIRST_MATE_CONDUCT_SKILL = {\n name: \"gh-first-mate-conduct\",\n md: `---\nname: gh-first-mate-conduct\ndescription: Fleet conductor for first-mate — one durable heartbeat loop drives a FLEET of per-repo CEO meta-subagents to greatness. Arms the deterministic loop, sweeps the whole portfolio once, fans out a fresh CEO subagent per repo that needs judgment, batches their verdicts, couriers human decisions, and re-arms. Use when first-mate should be the default durable driver for one or many repos.\nuser-invocable: true\n---\n\n# gh-first-mate-conduct: the deterministic-loop fleet conductor\n\nYou are the **fleet conductor**. One correctly-armed heartbeat loop, run by you (the main session), drives a fleet of GitHub repos — each by its own per-repo CEO meta-subagent — to greatness. This is the ONLY way one instance drives many repos durably: only the main REPL can arm a durable cron, so you own the heartbeat; the per-repo CEOs own judgment; the durable ledger + strategy store own memory. You hold almost nothing in context.\n\nYou carry the whole brain by REFERENCE, not by memorizing missions: the CEO/CTO/CPO operating protocol (\\`/gh-first-mate-operate\\`), the per-CEO driving loop (\\`/gh-first-mate\\`), and the definition of repo greatness (below). Your context each wake is only the compact board + each CEO's compact return — never diffs, logs, or transcripts.\n\n## The loop each wake (arm it right, then fan out)\n\n1. **One global sweep.** Call \\`mcp__first-mate__advance\\` ONCE with no \\`mission_id\\` — it sweeps the whole portfolio and returns \\`board\\`, \\`needsModel[]\\`, \\`needsHuman[]\\`, \\`nextWakeSeconds\\`. Tier1 auto-answers have ALREADY fired inside the tool for the safe \\`author_fix\\`/\\`answer_agent_question\\`/\\`decompose\\` envelope, so the cheap mechanical loop is handled for free and most wakes surface little. Do NOT disable tier1 — it is what keeps you from spawning a CEO for trivia.\n2. **Partition by mission/repo.** Group the residual \\`needsModel\\` (escalated \\`review_plan\\`/\\`judge_review\\` + anything tier1 declined) and open \\`needsHuman\\` and active board rows by \\`missionId\\`.\n3. **Surgical per-repo CEO fan-out.** For each mission that has an open judgment \\`needsModel\\`, OR a strategic checkpoint due (a phase to advance, a greatness item to verify, a pre-registered kill/pivot threshold reached), spawn a **fresh** CEO meta-subagent — Agent tool, in PARALLEL (multiple Agent calls in one message), capped at a few per wake (fleet fan-out cap; the MCP inflight budget is shared). A mission whose agents are grinding with no \\`needsModel\\` and no checkpoint due needs ZERO CEO spawns this wake. Hand each CEO its brief (below).\n4. **Batch + apply + courier.** Collect each CEO's returned \\`model_answers\\`; call \\`mcp__first-mate__advance\\` ONCE more with all of them (\\`model_answers: [...]\\`) to apply — the CONDUCTOR owns the single drive lease, CEOs never call \\`advance\\` themselves (that would contend the lease). Courier every \\`needsHuman\\` packet to the user (open \\`packetHtmlPath\\` in the artifact panel); never decide merges/abandons yourself.\n5. **Re-arm ONE heartbeat** from the MINIMUM \\`nextWakeSeconds\\` across the portfolio (the tightest cadence wins, so an imminent-work repo tightens the whole fleet).\n\n## The CEO spawn brief (hand this to each fresh per-repo CEO)\n\n> You are the CEO of repo <owner/name> (mission <id>), spawned fresh for one turn with COMPLETE authority over that repo on the GitHub platform. Do NOT arm a heartbeat (you are a subagent — you cannot) and do NOT call \\`mcp__first-mate__advance\\` (the conductor applies your verdicts). Steps: (1) \\`mcp__first-mate__read_strategy({mission_id})\\` + \\`mcp__first-mate__mission_status({mission_id})\\` to re-hydrate strategy + state; (2) follow \\`/gh-first-mate\\` (per-CEO driving) + \\`/gh-first-mate-operate\\` (CEO protocol) + the greatness bar — you DELEGATE all buildable work (code, docs, README/website content, UI, CI, tests) to cloud-agent units and do little yourself; your hands are for orchestration, verification, and decisions, not building; and you VERIFY every user-viewable surface (product UI, README-as-rendered, Pages, docs, release, og-card) by VIEWING the rendered pixels (\\`mcp__browser__*\\` / screenshots), never guessing from code; (3) for each of YOUR \\`needsModel\\` requests, VERIFY the deliverable against external evidence (delegate heavy reads to worker-explore/worker-review to stay context-thin) and produce the typed verdict (decompose with disjoint \\`fileScopes\\`, review_plan, judge_review, author_fix, answer_agent_question); (4) \\`mcp__first-mate__write_strategy({mission_id, currentPhase, activeBet, greatnessChecklist, decisionLog:[one entry], nextStrategicAction})\\` to persist your strategy delta; (5) RETURN a compact \\`{ model_answers:[{requestId,verdict}], needsHuman:[…to courier], strategy_written:true }\\` — no prose, no diffs.\n\nBecause each CEO is FRESH per wake, its strategic continuity comes ONLY from the strategy store — so a rich \\`write_strategy\\` (phase, pre-registered bet + thresholds, greatness checklist with evidence handles, an append-only decision-log entry, what-was-tried) is what stops the next wake's CEO from drifting or re-litigating a dead end.\n\n## Self-driving heartbeat (arm / disarm — you own the ONLY one)\n\nONE durable cron, marker \\`[fm-heartbeat]\\`, is the dead-man's-switch that survives idle, compaction, restart, and /clear. There is exactly ONE first-mate heartbeat regardless of which driver skill armed it; manage it create-fresh-then-reap-the-rest:\n\nArm (nextWakeSeconds is a number):\n1. Cadence bucket from nextWakeSeconds (fixed cron, no time math): \\`<=120 → \"1-59/2 * * * *\"\\`; \\`<=600 → \"2,7,12,17,22,27,32,37,42,47,52,57 * * * *\"\\`; else \\`\"3,13,23,33,43,53 * * * *\"\\`.\n2. CronCreate the new job (durable:true, recurring:true, the chosen cron, prompt \\`\"/gh-first-mate-conduct [fm-heartbeat] wake the fleet, sweep, fan out CEOs, apply verdicts, reschedule.\"\\`) and capture its id.\n3. CronList, then CronDelete every job whose prompt contains \\`[fm-heartbeat]\\` EXCEPT the id you just created — converges to exactly one, reaps duplicates/old-version orphans (including a stray standalone \\`/gh-first-mate\\` heartbeat), resets the 7-day expiry.\n\nDisarm (nextWakeSeconds is null AND no pending needsHuman): CronList and CronDelete every \\`[fm-heartbeat]\\` job; report the fleet is idle and resumes when a mission is next started/advanced.\n\nMCP unavailable / not \\`--agents\\`: do not advance; reap all \\`[fm-heartbeat]\\` jobs and report \"re-run under \\`github-router claude --agents\\`.\" No scheduler tool: report the next wake is in nextWakeSeconds and stop.\n\n## Context discipline & report\n\nThe ledger is durable memory for unit state; the strategy store is durable memory for CEO strategy; your context is neither. Never read a full diff/log/transcript. Report compactly from the board: per mission — id, repos, phase counts, blocked count, the greatness-checklist progress (leading done + which LAGGING signals moved), needsHuman awaiting the user, and the next wake. A repo is only \"great\" when a LAGGING signal has moved, never when leading boxes are merely ticked.\n\n## Definition of greatness (the bar every repo is driven toward)\n\n${DEFINITION_OF_GREATNESS}\n`,\n} as const\n","import { CONDENSED_OPERATING_SEQUENCE, DEFINITION_OF_GREATNESS } from \"~/lib/first-mate/operating-protocol\"\n\nexport const FIRST_MATE_OPERATE_SKILL = {\n name: \"gh-first-mate-operate\",\n md: `---\nname: gh-first-mate-operate\ndescription: Operator-facing CEO/CTO/CPO operating protocol for autonomously driving a product with first-mate — shape each mission from a real struggling moment, make acceptance criteria externally verifiable, sequence discovery through growth, and escalate launch, spend, and pricing to the human. Use when deciding WHAT product work first-mate should drive, not only how to execute it.\nuser-invocable: true\n---\n\n# gh-first-mate-operate: drive a product as CEO + CTO + CPO\n\nYou are the CEO of the product. The GitHub cloud coding agents are your team — they carry the CTO/CPO/engineering execution roles (scaffolded into each repo). Your job is to think like a CEO and get real, verified work out of that team: decide the product direction (the niche, the riskiest assumption, the MVP scope, when to launch, what to measure, what to iterate), turn each decision into a scoped mission, drive the agents to deliver it, and hold the result to evidence.\n\nYou do not write the product code. You orchestrate: shape missions, review plans, answer the team's questions fast so they never idle, verify deliverables, and sequence the whole effort toward an outcome. Seed the team's playbook once with \\`mcp__first-mate__scaffold_repo\\` (it commits \\`docs/playbook/README.md\\` plus the \\`ceo\\`/\\`cto\\`/\\`cpo\\` role agents the cloud agents read); then use THIS protocol to run the company.\n\n## Delegate the work — your hands are for orchestration, not building\n\nYou are the orchestrator; the GitHub cloud coding agents are the workers. The whole point of first-mate is to get work OUT of the team — so DELEGATE, and do little yourself.\n\n- **Everything BUILDABLE is a cloud-agent mission/unit, never hand-written by you:** product code, bug fixes, README/docs/website CONTENT, CI/workflows, tests, the UI. Dispatch it via \\`mcp__first-mate__start_mission\\` / \\`add_units\\` / \\`decompose\\` — do NOT open an editor and write it yourself.\n- **Your OWN hands are only for:** strategy & decisions, decomposition, answering the team (plan review, questions, fix instructions, judge verdicts), VERIFYING deliverables (browse / read / screenshot — **observe, never build**), persisting strategy, and GitHub-**platform** governance via \\`gh\\` (merge, release, branch protection, secrets, labels, issues, triage). That is orchestration, not building.\n- **Resist the \"I'll just quickly fix it myself\" urge — it is the failure mode.** A quick hand-edit feels faster but doesn't scale, produces no reusable team capability, and isn't your job. If you catch yourself about to write code, docs, or UI: STOP and dispatch it as a scoped unit instead. The only exception is a genuine one-line last-mile config the cloud-agent loop cannot reach — and even then, prefer a unit.\n\n## Drive the team (get work out of them)\n\n- **Verify, never trust \"done\".** Every deliverable clears an external checkpoint — a real HTTP 200, green CI, an observed analytics event, a real survey N — or it is not done. Reject self-reported completion and send it back with a concrete gap.\n- **Keep the team unblocked and busy.** A blocked agent produces nothing: answer \\`answer_agent_question\\` promptly, dispatch independent units in parallel, and re-steer a stalled or underdelivering agent instead of waiting. Idle or looping agents are wasted throughput.\n- **Set the bar as acceptance criteria.** The mission's acceptance criteria = the phase's externally verifiable checkpoint. Vague criteria produce vague work; make the bar reproducible.\n- **Own the P&L of attention.** Kill low-value missions, double down on what moves the outcome metric, and escalate only the genuinely human-gated calls (launch to real channels, spend, pricing, merges).\n\n## The one rule that makes autonomy safe\n\nEvery phase advances only on an EXTERNALLY VERIFIABLE checkpoint — a real HTTP 200, a green CI run, an observed analytics event, or a real survey sample size — never a self-reported \"done\". Autonomous agents fail or hallucinate \"done\" a large fraction of the time, so an unverified claim is not progress. Encode the checkpoint as the mission's acceptance criteria and refuse to advance without the evidence.\n\n## Operating loop (OODA inside Build-Measure-Learn)\n\n- Inner loop, each turn: OBSERVE fresh evidence (issues, mentions, downloads, analytics), ORIENT against the current job/segment/assumptions, DECIDE one reversible next action against a pre-set threshold, ACT by delegating a scoped mission to the cloud agents.\n- Outer loop, each phase: build the smallest testable increment, measure externally observable behavior, learn against the pre-registered threshold, then persist or pivot. Do not enter the next phase until its checkpoint is independently reproducible.\n\n## Shaping a mission by phase\n\nWhen you call \\`mcp__first-mate__start_mission\\` (or \\`mcp__first-mate__add_units\\`), set the fields from the CURRENT phase:\n\n- **goal**: the phase objective, grounded in a real struggling moment — not a feature wish.\n- **acceptance_criteria**: the phase's externally verifiable exit checkpoint, stated as evidence a reviewer can reproduce (e.g. \"cold-start quickstart under five minutes, timed from a fresh checkout, recorded in the PR\"; \"Sean Ellis survey with N≥40 responses and ≥40% 'very disappointed'\").\n- **house_rules**: any hard constraint (privacy, license, brand, spend limit).\n- Unlock real parallelism the right way: give each independent unit a DISJOINT \\`fileScopes\\` allowlist so their builds run CONCURRENTLY (the controller proves non-overlap and dispatches in parallel up to the mission's \\`maxConcurrentBuilds\\`), and/or split fully independent workstreams into SEPARATE missions (the build gate is per-mission, so N missions build N units at once). \\`max_in_flight_per_provider\\` is a global provider cap, NOT the build-concurrency lever — disjoint \\`fileScopes\\` and separate missions are. Never race overlapping work on the same files.\n\nLet the controller drive decomposition and steering (see \\`gh-first-mate\\`); this skill decides the PHASE and the checkpoint, not the controller mechanics.\n\n## Phased sequence (shared with the scaffolded playbook)\n\n${CONDENSED_OPERATING_SEQUENCE}\n\n## Definition of greatness (the shipping bar every repo must clear)\n\nDriving a product to greatness is not just shipping features — the repo itself must clear a verifiable shipping-infrastructure bar. Drive each repo toward it and gate each item on real, third-party-checkable evidence (a green check, a \\`gh api\\`, a \\`curl\\`, a \\`cosign verify\\`), never a self-report. This is the SAME bar the scaffolded playbook and the eval use.\n\n${DEFINITION_OF_GREATNESS}\n\n## Iterate to polish — never guess the UI, drive it and view the pixels\n\nUI/UX quality (and every user-viewable surface) is DRIVEN, SEEN, and ITERATED, never designed once and asserted. For ANY unit that touches the product UI, the README, the website, docs, the release page, or the og-card, require the cloud agent to — and verify yourself by — VIEW the rendered result before \"done\":\n1. Build & run the real artifact (the deployed Pages / live URL, or a dev server) — a local happy-path screenshot is not the product.\n2. Drive every state & flow with \\`mcp__browser__*\\` (navigate/act/observe): first-run/empty, real input, forced error, success, edge/overflow — not just the ideal state.\n3. Screenshot the matrix: each state at mobile/tablet/desktop × light+dark, honoring \\`prefers-color-scheme\\` and \\`prefers-reduced-motion\\`. These pixels, not the code, are the evidence.\n4. Critique the pixels against the professional bar (Pillar D of the greatness definition); for each defect name the concrete problem AND the screenshot it is in. Rank by severity.\n5. Fix the top defects (dispatch to the implementer role; prefer token/design-system fixes over one-off patches).\n6. Re-drive & re-capture (repeat 2–5) until the vision rubric is clean and the deterministic gates (visual-regression / axe / contrast / CWV) are green. Update \\`toHaveScreenshot\\` baselines only on an intentional, reviewed change.\n7. Lock it in: commit the visual-regression baselines + axe/Lighthouse/CWV CI so polish can't silently regress.\n\nThe no-guessing rule: never mark a user-viewable surface — including the README as GitHub renders it — \"done\" from code/markdown review alone; back every claim with a screenshot of the actual running/rendered artifact.\n\n## Every iteration must move the end-user experience forward — and regress nothing\n\nThis is the objective the whole loop is tuned to, and the operating expression of the CEO eval (\\`docs/first-mate-ceo-eval-framework.md\\`, the End-User Experience Delta lens): after each iteration (or a bounded set), measure what VERIFIABLY improved for the END USER, and confirm nothing regressed.\n\n- **Drive the pinned user journeys before AND after.** Keep a pinned set of golden journeys per repo (the aha path + key flows) plus user-facing facets — journey completion, time-to-first-value, capability, performance, accessibility, user-facing correctness, the rendered README/Pages/docs/Release, state robustness. Capture them on the inherited state, then again after the iteration, by DRIVING the real artifact — never inferred from code or a 200.\n- **Ship only a net improvement.** An iteration is done only when it shows at least one MATERIAL, verified user-facing improvement (past a pre-set threshold, tied to a real user job) AND zero detected unintended regression under the coverage you actually ran. Report coverage honestly: \"no regression detected in the pinned journeys,\" never an absolute \"zero.\"\n- **A detected regression is stop-the-line.** A journey that worked now failing, a metric crossing its budget the wrong way, a removed/broken capability, a new user-hitting bug, a broken rendered surface, or a slower quickstart CAPS the iteration: fix the regression before the improvement counts. Recovering a regression you caused only retires the debt; it is not new progress.\n- **Intended user-facing changes are approved tradeoffs, not free.** A deliberate deprecation / redesign / pivot is recorded as an approved tradeoff (old baseline preserved, migration path, human approval) — never silently relabeled \"not a regression.\"\n- **Necessary invisible work is legitimate but bounded.** Security hardening, migrations, and refactors that de-risk future UX are enabling-investment, not churn — but bounded: after ~2 consecutive iterations with no user-facing delta (or ~a third of a milestone's budget), the next iteration must show a material user improvement or you flag the strand.\n- **The agent must not own the ruler.** The journey manifest + measurement harness are yours (or human-blessed), not authored by the cloud agent being measured; a change to them is reviewed and logged, like a merge approval.\n\n## Anti-patterns (hard stops)\n\n- **Over-building without distribution:** run a reachability/channel test before extending product scope. \"Build it and they will come\" is not a plan.\n- **Hallucinated progress:** require real evidence (HTTP 200, green CI, observed analytics, real survey N); never convert activity or a narrative into completion.\n- **Viral ≠ product-market fit:** attention, stars, and shares do not replace the Sean Ellis threshold plus a flattening retention curve.\n- **Metrics after the fact:** pre-register kill/pivot/continue thresholds before collecting results.\n\n## Escalate to the human (never decide autonomously)\n\nHard authority limits: launching to real external channels, any spend or paid acquisition, setting or changing pricing, issuing discounts, entering contracts, expanding privileges, and any regulated/legal/privacy commitment require an explicit human boundary or approval. Within those limits, proceed on best judgment and record assumptions rather than pausing. Merge approval and abandonment remain human-gated per \\`gh-first-mate\\`.\n\n## Report\n\nReport the current phase, its checkpoint and whether it is met with reproducible evidence, the active mission(s) and their phase-appropriate acceptance criteria, and the next decision or escalation.\n`,\n} as const\n","export const FIRST_MATE_SETUP_SKILL = {\n name: \"gh-first-mate-scaffold\",\n md: `---\nname: gh-first-mate-scaffold\ndescription: Scaffolds a repo-geared agentic-dev foundation through first-mate: seeds guidance files, role agents, ADRs, changelog, learnings, PR template, test instructions, Copilot setup, and CI through a scaffold branch and PR. Use before the first build wave on an owned repository.\nuser-invocable: true\n---\n\n# gh-first-mate-scaffold\n\nInvoke the ` + \"`scaffold_repo`\" + ` MCP tool (` + \"`mcp__first-mate__scaffold_repo`\" + `) before the first build wave on an owned repository. The goal is not generic TODO stubs; it is a repo-geared foundation that GitHub agents, local agents, reviewers, and CI can read.\n\n## What it seeds\n\n- ` + \"`AGENTS.md`\" + ` / ` + \"`CLAUDE.md`\" + ` / ` + \"`GEMINI.md`\" + ` / ` + \"`.github/copilot-instructions.md`\" + ` — identical guidance with overview, detected stack, commands, hard DoD gate, primary OS, conventions, structure, decisions/memory, handoff, testing, and gotchas.\n- ` + \"`.github/agents/{ceo,cto,cpo,planner,implementer,reviewer,researcher,tester}.md`\" + ` mirrored into ` + \"`.claude/agents/`\" + ` — C-suite operator hats plus execution roles, each with frontmatter, cold-start contract, method, quality bar, output contract, and self-reminder.\n- ` + \"`docs/playbook/README.md`\" + ` — the autonomous DISCOVER → NICHE → POSITION → SCOPE → BUILD → LAUNCH → MEASURE → ITERATE → GROW protocol, externally verifiable phase gates, OODA / Build-Measure-Learn governance, and authority limits.\n- ` + \"`docs/adrs/0000-template.md`\" + ` plus ` + \"`docs/adr/0001-record-architecture-decisions.md`\" + ` — Nygard-style decision record foundation.\n- ` + \"`LEARNINGS.md`\" + `, ` + \"`CHANGELOG.md`\" + `, ` + \"`docs/history/0000-template.md`\" + `, ` + \"`docs/plans/README.md`\" + `, and ` + \"`docs/research/README.md`\" + ` — durable memory, history, plans, and research conventions.\n- ` + \"`.github/pull_request_template.md`\" + ` — summary, type, failure-modes-considered-and-tested, and DoD checklist.\n- ` + \"`.github/instructions/tests.instructions.md`\" + ` — path-scoped test guidance filled from detected framework/dir/glob where possible.\n- ` + \"`.github/workflows/copilot-setup-steps.yml`\" + ` and starter ` + \"`.github/workflows/ci.yml`\" + ` — detected toolchain setup with stable quality-gate job names.\n\nIt does not seed factory-protocol or ` + \"`docs/factory/`\" + ` files. Orchestration remains outside the product repo in first-mate.\n\n## Usage\n\n` + \"```\" + `\nmcp__first-mate__scaffold_repo({ repo: \"owner/repo\" })\nmcp__first-mate__scaffold_repo({ repo: \"owner/repo\", mode: \"enhance\" })\nmcp__first-mate__scaffold_repo({\n repo: \"owner/repo\",\n mode: \"add-missing-only\",\n detection_overrides: { primary_os: \"windows-latest\", test_command: \"npm test\" }\n})\n` + \"```\" + `\n\nModes:\n\n- ` + \"`add-missing-only`\" + ` (default): seed absent files and skip present files.\n- ` + \"`enhance`\" + `: for guidance files, product playbook, ADR index, changelog, and learnings, append only missing ` + \"`##`\" + ` sections; never rewrite existing prose. Other present files are skipped.\n- ` + \"`overwrite-approved`\" + `: replace existing files only when explicitly approved.\n\nAlways inspect the returned per-file report and PR. A no-op result means the repo already has the foundation or has no missing enhanceable sections.\n`,\n} as const\n","export const FIRST_MATE_SKILL = {\n name: \"gh-first-mate\",\n md: `---\nname: gh-first-mate\ndescription: Thin operating protocol for the first-mate GitHub cloud-agent controller: starts missions, wakes the durable loop, answers model and human requests, keeps context compact, and reports from the board/ledger. Use when the user wants first-mate to drive GitHub cloud coding agents across one or more repositories with foundation-first scaffolding and scoped, testable work.\nuser-invocable: true\n---\n\n# gh-first-mate: durable cloud-agent controller loop\n\nUse this skill when the user wants first-mate to drive GitHub cloud coding agents across one or more repositories.\nThe first-mate controller is the durable system of record: missions, units, decisions, handles, and controller state live in its registry and ledger.\nYour job is to run the thin protocol, not to hold the mission in context.\n\n## You are the CEO\n\nYou are the CEO of the product. The GitHub cloud coding agents are your team; your job is to get real, verified work out of them and drive the product to an outcome — not to write the code yourself. Operate like a CEO every turn:\n\n- **Drive results, not activity.** Hold every deliverable to external evidence (a real HTTP 200, green CI, an observed metric, a real survey N). Never accept a self-reported \"done\" — autonomous agents fail or hallucinate completion a large fraction of the time.\n- **Set clear expectations.** Every mission's acceptance criteria IS the bar: a phase's externally verifiable checkpoint, stated so a reviewer can reproduce it.\n- **Keep the team unblocked and busy.** Answer agent questions fast (the controller surfaces \\`answer_agent_question\\`), dispatch independent units in parallel, and re-steer a stalled or weak agent promptly rather than letting it idle.\n- **Own the outcome.** Sequence missions toward the product result (niche → MVP → launch → traction), kill low-value work, and iterate on evidence. Think in bets — hypothesis, metric, threshold — and delegate execution to the cloud-agent team.\n\nFor the full operating protocol — discovery, positioning, MVP scope, launch, measure, iterate, grow — invoke \\`/gh-first-mate-operate\\`.\n\n## Foundation-first mandate\n\nBefore the first build wave on an owned repository, run \\`mcp__first-mate__scaffold_repo\\` and verify the PR landed or is already present. The scaffold must seed a repo-geared foundation that GitHub agents and CI can read: guidance, role agents, ADRs, changelog, learnings, PR template, test instructions, Copilot setup, and CI. Do not seed factory-protocol files into product repos; first-mate is the external orchestrator.\n\nUse \\`mode: \"add-missing-only\"\\` for new repos, \\`mode: \"enhance\"\\` when a repo has existing guidance that should keep its prose while appending missing \\`##\\` sections, and \\`mode: \"overwrite-approved\"\\` only with explicit approval.\n\n## Scoped-work discipline\n\nWell-scoped, testable work items succeed; vague meta-work fails. Discovery/decompose must emit concrete units with acceptance criteria, expected evidence, and dependencies. **Parallelize deliberately.** Independent build units that declare DISJOINT \\`fileScopes\\` build CONCURRENTLY — the controller proves independence (no unmet deps + non-overlapping declared scopes) and dispatches them in parallel up to the mission's \\`maxConcurrentBuilds\\` cap; units with overlapping or undeclared scope serialize their builds (the safe default). For fully independent workstreams you can also run SEPARATE missions — the build gate is per-mission, so N missions build N units at once. Never race overlapping work on the same files.\n\nJudgment and merge policy: merge remains human-gated, evidence-gated, and head/base-bound. Use the best available model tier for plan review, judgment, and merge decisions; never cheap out on plan/judge/merge calls.\n\n## Start a mission\n\nFor a new goal, call mcp__first-mate__start_mission with:\n\n- goal: the user's goal in one sentence.\n- repos: repository strings as owner/name.\n- acceptance_criteria: explicit user-blessed acceptance criteria.\n- priority and house_rules only when the user supplied them or they are necessary constraints.\n\nIf acceptance criteria are missing or ambiguous, ask the user before starting.\nDo not decompose the mission yourself at start time; mission registration is intentionally simple and later controller wakes/model requests drive decomposition and steering. If the user explicitly asks to append scoped work to an existing active mission, use mcp__first-mate__add_units with concrete unit titles.\n\nInvariant (closes the stranding hole): work only ever becomes active inside a turn — start_mission is a tool call, nothing activates a mission server-side. So immediately after start_mission, run one loop turn (advance, then arm the heartbeat) in the SAME turn, before you yield. Never register a mission and stop without arming; otherwise nothing will wake to drive it.\n\n## Controller loop (push-based, self-driving)\n\nThe loop is push-based: each turn you DRAIN all ready work, then ARM the next wake and YIELD the turn. You never sit polling advance in a tight loop — that does not scale and wastes context. A durable heartbeat re-invokes this skill while the session is idle, and one advance call sweeps the WHOLE portfolio (every mission, every repo) at once, so a single heartbeat drives everything.\n\nEach turn:\n\n1. Call mcp__first-mate__advance, batching any answers you already have.\n2. Read the compact response: board, needsModel, needsHuman, applied_count, nextWakeAt, and nextWakeSeconds.\n3. Answer every needsModel item with the typed verdict for its kind, and courier every needsHuman packet. If you produced any model_answers this turn, call advance again to apply them and pick up the resulting state. Stop this inner drain once advance returns no new needsModel you can answer without the user; keep it bounded (at most a few iterations), never a busy loop.\n4. Manage the heartbeat from nextWakeSeconds (see \"Self-driving heartbeat\").\n5. Report compactly from the board, then YIELD. Do not call advance again until the next scheduled wake or a new user message.\n\nWhen submitting answers, batch what you have:\n\n- model_answers: [{ requestId, verdict }]\n- human_decisions: [{ requestId, choice }]\n\nKeep verdicts small and typed to the request kind.\n\n## Model request verdicts\n\nUse the request's kind and payload as the contract:\n\n- decompose: split a unit-less active mission into dispatchable units. Return { units: [{ title, repo?, agent?, dependsOn?, model?, fileScopes? }] }. \\`dependsOn\\` entries are 0-based indices into the same units list. **\\`fileScopes\\` is the parallelism lever** — declare each unit's disjoint file allowlist (paths or \\`dir/**\\` prefixes it may touch) so the controller can prove independence and build those units CONCURRENTLY; units with overlapping or absent scopes serialize their builds. Emit once per unit-less active mission; the controller creates durable unit ids and will not ask again after units exist.\n- review_plan: review the plan against the mission goal, acceptance criteria, and house rules. Return { decision: \"approve\" } when the plan is good enough to implement, or { decision: \"refine\", instruction: \"...\" } with a short actionable refinement.\n- answer_agent_question: answer only from the acceptance criteria and supplied context. Return { answer: \"...\" }. If the answer is not derivable, do not invent policy; escalate by leaving a short answer that says what the human must decide.\n- author_fix: author a concise fix instruction for the cloud agent. Return { instruction: \"...\" } with the failure, expected behavior, and any bounded check to run.\n- judge_review: judge whether review/CI/floor evidence is sufficient. Return { pass: true } only when the acceptance criteria and floor are satisfied; otherwise return { pass: false } with a compact reason when useful.\n\nDelegate heavy reading to workers:\n\n- Use the worker-explore subagent (Agent tool) for focused source or history gathering.\n- Use the worker-review subagent (Agent tool) for compact review of a specific plan, PR summary, or suspicious change.\n- Use the worker-test subagent (Agent tool) when a missing executable check is the blocker.\n\nOperator / --agents mode constraint: delegate product implementation to GitHub cloud agents. Direct \\`mcp__workers__*\\` / \\`mcp__orchestrate__*\\` calls are subagent-only for the main operator; use the worker-* Agent subagents when local worker help is genuinely needed. Local tools (Edit/Write/Bash, \\`gh\\`, \\`git\\`) remain available, but prefer authoring fix instructions for the cloud agent rather than pulling large diffs or CI logs into the lead context.\n\nDo not read a full diff, full CI log, or full transcript in the lead context. Ask workers for narrow facts and compact excerpts. The ledger is durable memory; context is not.\n\n## Human requests\n\nFor each needsHuman item:\n\n1. If packetHtmlPath is present, open that HTML file in the ai-or-die artifact panel for the user.\n2. Tell the user the reason, repo, issue/PR handles, and the available decision choices.\n3. Wait for the user's decision.\n4. Submit the choice back with mcp__first-mate__advance({ human_decisions: [...] }).\n\nIf an artifact-panel tool is unavailable, give the user the local packetHtmlPath and the compact summary from needsHuman.\nNever decide a merge approval or abandonment choice on the user's behalf.\n\n## Self-driving heartbeat (arm / disarm)\n\nThe loop keeps itself alive with ONE durable cron job — a dead-man's-switch that survives idle, compaction, restart, and /clear because it lives on disk, not in your context. The controller hands you nextWakeSeconds so you never do arithmetic: it is a ready-to-use delay in seconds, or null when the whole portfolio is idle. Every heartbeat carries the exact marker token [fm-heartbeat] in its prompt so you can identify it unambiguously (never a fuzzy match against unrelated crons). Manage exactly one heartbeat:\n\nArm — \"create fresh, then reap the rest\" (nextWakeSeconds is a number, i.e. there is active work):\n\n1. Pick the cadence bucket from nextWakeSeconds (fixed cron expressions, no time math), so the heartbeat tracks the controller's own cadence:\n - nextWakeSeconds <= 120 → \"1-59/2 * * * *\" (about every 2 min)\n - nextWakeSeconds <= 600 → \"2,7,12,17,22,27,32,37,42,47,52,57 * * * *\" (about every 5 min)\n - otherwise → \"3,13,23,33,43,53 * * * *\" (about every 10 min)\n2. CronCreate the new heartbeat and capture its id: durable: true, recurring: true, the chosen cron, prompt \"/gh-first-mate [fm-heartbeat] wake the controller loop, answer ready requests, reschedule.\" Creating first (before deleting) guarantees at least one heartbeat always exists.\n3. CronList, then CronDelete every job whose prompt contains [fm-heartbeat] EXCEPT the id you just created. This converges to exactly one, reaps duplicates and old-version orphans, and — because you recreate each wake — resets the 7-day recurring-cron expiry so a long mission never silently stops.\n\nDisarm (nextWakeSeconds is null AND there are no pending needsHuman): nothing is active. CronList and CronDelete every [fm-heartbeat] job. Report that first-mate is idle and resumes when the user next starts or advances a mission (safe because, per the Start-a-mission invariant, only a turn can reactivate work, and that turn re-arms).\n\nResponsiveness (optional): the buckets above already tighten cadence to ~2 min for imminent work. If this session is a /loop you MAY additionally ScheduleWakeup(delaySeconds: nextWakeSeconds, ...) for an exact one-shot; keep at most one outstanding.\n\nGuardrails: never leave more than one [fm-heartbeat] job; never busy-loop advance; if no scheduler tool is available, tell the user the next wake is in nextWakeSeconds seconds and stop.\n\nMCP unavailable: if the first-mate MCP server is not present (this is not a \\`--agents\\` session and \\`mcp__first-mate__advance\\` would return a tool-not-found error), do NOT attempt to advance. CronList then CronDelete every [fm-heartbeat] job (same as Disarm above), and report \"first-mate paused — re-run under \\`github-router claude --agents\\` to resume.\" Stop without further action.\n\n## Board reports\n\nUse mcp__first-mate__board or mcp__first-mate__mission_status for read-only status checks.\nReport compactly:\n\n- mission id and title\n- repositories\n- phase counts\n- blocked count and why, when available\n- per-unit handles for non-terminal units: unitId, issue/PR, phase, provider, validation, model, and blockedReason when present\n- resolved cloud-agent model per unit (surfaced on the board — verify model choice before approving plans)\n- terminal work only as summary counts; use include_all only when the user asks for completed/abandoned history\n- next wake time or the next requested action\n\nNever reconstruct status by rereading raw logs when the controller board already has the handles.\n\n## Context discipline\n\n- The ledger is the durable memory; do not paste large artifacts into the chat.\n- Never read a full diff/log/transcript unless the user explicitly asks and it is essential.\n- Prefer handles: mission id, repo, issue, PR, request id, packet path.\n- Keep every answer to first-mate compact and action-oriented.\n- If controller state and chat memory disagree, trust the controller state and ask for clarification only when it affects acceptance criteria or human approval.\n\n## Return format\n\nWhen reporting progress, return:\n\n- Mission: id and one-line goal.\n- Board: compact phase counts and blocked count.\n- Applied: count or short list of important controller actions.\n- Needs model: request ids and kinds answered or pending.\n- Needs human: decision ids/packet paths and the user's required choice.\n- Next wake: the heartbeat state — armed and next check in nextWakeSeconds seconds, or idle (disarmed).\n`,\n} as const\n","export const FLOOR_KEEPER_SKILL = {\n name: \"gh-floor-keeper\",\n md: `---\nname: gh-floor-keeper\ndescription: Done-checkpoint verification for non-trivial changes: runs the executable gate, sends the diff to OpenAI and Google reviewers, consults the advisor, reconciles findings by severity, authors missing tests through a different lab when bounded and appropriate, and returns an honest go/no-go. Use before declaring non-trivial work complete.\nuser-invocable: true\n---\n\n# gh-floor-keeper: done-checkpoint verification\n\nInvoke this before declaring a non-trivial change done.\nIt is the final floor check: executable gate first, cross-lab review second, advisor third, severity reconciliation last.\nIt does not prove the change is correct; it reports what was checked and what remains residual.\n\n## Operating contract\n\n- Input: the user ask, user-blessed acceptance criteria, current diff, and any research or plan pointers.\n- Output: go/no-go with binding executable results, advisory review findings, and residual risks.\n- Scope: changed behavior and changed files, not a full repo audit unless requested.\n- Reuse /gh-research for claim verification instead of re-deriving complex facts.\n- Keep attempts bounded and ask before expanding into a large new test harness.\n\n## Honest limits\n\n- The executable gate is binding only for what it covers.\n- A green gate does not rule out wrong-spec or missing coverage.\n- Cross-lab review reduces correlated blind spots but is advisory.\n- Advisor output is judgment-only unless converted into tests, source changes, or a gate.\n- Different-lab test authorship is an advisory practice, not enforceable provenance.\n\n## Step 1: gather the done context\n\nCollect:\n\n- Original ask and acceptance criteria.\n- Current working-tree diff.\n- Commands already run and their outputs.\n- Research brief pointer, if one exists.\n- Plan or orchestration summary, if one exists.\n- Known residual risks from earlier phases.\n\nIf acceptance criteria are absent, stop and ask for them or state that wrong-spec risk remains high.\n\n## Step 2: run the executable gate\n\nRun the repo-appropriate executable checks for the changed slice:\n\n- typecheck, tests, lint, build, or focused command named by the repo/user.\n- Prefer the existing gate command when available.\n- Capture exact command, exit code, duration, and relevant output.\n- If the command times out or cannot run, report unknown, not pass.\n\nBinding rule:\n\n- Red gate for covered behavior means no-go until fixed or explicitly waived by the user.\n- Green gate means only that the checks that ran passed.\n- Missing checks or unavailable commands remain residual risk.\n\n## Step 3: identify missing test coverage\n\nAsk whether changed behavior has executable coverage.\n\n- If behavior changed and no relevant test exists, dispatch the worker-test subagent (Agent tool, subagent_type worker-test) to author a focused test through a DIFFERENT lab than the implementer when possible.\n- Cap missing-test attempts; default to a small number of focused tries.\n- Run the new test and then the relevant existing gate.\n- If creating a large new harness, broad fixture system, or slow integration environment is required, ask the user before proceeding.\n- If a model-authored test is the only oracle, label it honestly as helpful but not a complete correctness guarantee.\n\n## Step 4: fan out cross-lab review\n\nSend the same diff, acceptance criteria, and gate results in parallel to:\n\n- mcp__peers__codex_reviewer (OpenAI)\n- mcp__peers__gemini_reviewer (Google)\n\nAsk both reviewers for:\n\n- correctness bugs\n- acceptance-criteria misses\n- regressions\n- security or data-loss risks\n- test gaps\n- maintainability issues that matter for this change\n- severity for each finding: blocker, high, medium, low, nit\n\nDo not treat reviewer agreement as proof. Treat it as advisory signal to investigate or fix.\n\n## Step 5: consult advisor\n\nConsult the advisor with a focused concern:\n\n- whether the diff satisfies the acceptance criteria\n- whether the gate covers the risky behavior\n- whether reviewer findings indicate no-go\n- what residual risk should be surfaced to the user\n\nAdvisor output is advisory unless you convert it into a source-verified claim, executable test, or code change.\n\n## Step 6: verify disputed or load-bearing claims\n\nFor any important claim from a reviewer, advisor, or your own reading:\n\n- If it needs research, invoke /gh-research and use its persisted brief pointer.\n- Prefer reproducing the issue or running a focused test: verified-executable.\n- Otherwise read the actual source and cite it: verified-source.\n- If neither is possible within budget, mark unverified and include it in residual risk.\n\nDo not re-derive complex repo facts from memory when /gh-research is the right tool.\n\n## Step 7: reconcile by severity\n\nBuild a reconciliation table:\n\n- Finding.\n- Source: gate, codex reviewer, gemini reviewer, advisor, research, or self.\n- Severity: blocker, high, medium, low, nit.\n- Evidence tag: verified-executable, verified-source, cross-lab-agreed, or unverified.\n- Decision: fix now, accept residual, ask user, or no action.\n\nDecision rules:\n\n- Any covered executable failure is no-go.\n- Any credible blocker or high correctness/security/data-loss issue is no-go unless disproven or explicitly waived.\n- Medium issues usually require fixing when cheap; otherwise surface as residual.\n- Low and nit findings do not block unless they violate acceptance criteria.\n- Wrong-spec residual is always listed unless the user explicitly blessed the acceptance criteria for this exact done state.\n\n## Step 8: return go/no-go\n\nReturn a compact final checkpoint:\n\n- Verdict: go or no-go.\n- Executable gate: commands, pass/fail/unknown, and why it is binding or not.\n- Missing-test handling: tests authored, skipped, capped, or user approval needed.\n- Cross-lab review summary: OpenAI findings, Google findings, agreements, disagreements.\n- Advisor summary.\n- Reconciliation table with severity and evidence tags.\n- Residual risks, explicitly including wrong-spec if applicable.\n- Required next actions before declaring done.\n\n## Non-goals\n\n- Do not claim the change is correct merely because tests passed.\n- Do not let advisory reviewers override a covered red executable gate.\n- Do not spend unbounded attempts creating tests.\n- Do not bury cap-hit or unknown states in a green-sounding summary.\n`,\n} as const\n","export const ORCHESTRATE_SKILL = {\n name: \"gh-orchestrate\",\n md: `---\nname: gh-orchestrate\ndescription: Right-sized blind-spot-elimination for non-trivial implementation asks: captures user-blessed acceptance criteria, delegates bounded research, decomposes and plans, composes a native Workflow with explicit deterministic/advisory annotations, verifies the workflow, checkpoints residual risks and cost, then runs only when the pipeline actually raises the floor. Use when a non-trivial implementation ask benefits from workflow-level blind-spot reduction.\nuser-invocable: true\n---\n\n# gh-orchestrate: right-sized blind-spot elimination\n\nUse this skill when the user asks for a non-trivial change and the composed workflow can reduce real blind spots.\nThe sole objective is: how does the composed workflow deterministically raise the floor for THIS ask, and what blind spots does it eliminate with which tools?\n\n## Right-size first\n\n- For trivial asks, skip this pipeline and say why.\n- A three-line obvious fix, typo, small config read, or simple explanation should not pay orchestration cost.\n- If the ask has multiple files, unclear behavior, risky migration, uncertain tests, or high user impact, orchestration is likely worth it.\n- The pipeline is a tool, not a ritual.\n\n## Honest limits\n\n- User-blessed acceptance criteria are the only defense against the wrong-spec hole.\n- Executable gates do not catch a model solving the wrong task.\n- Cross-lab review is advisory unless a code rule or executable gate consumes its output.\n- The native Workflow path approximates but does not carry the kernel's hard max(orchestrated, baseline) guarantee.\n- Use mcp__orchestrate__run_workflow instead when the user wants the hard floor from the frozen kernel.\n\n## Phase 0: scope and acceptance criteria\n\n1. Restate the user's goal in one sentence.\n2. Capture explicit USER-BLESSED acceptance criteria before planning.\n3. If acceptance criteria are missing or ambiguous, ask the user or present a short candidate list for confirmation.\n4. State plainly: these criteria are the only guard against wrong-spec; green tests can still be green for the wrong interpretation.\n5. Identify constraints: files, APIs, compatibility, performance, security, release risk, and forbidden changes.\n\n## Phase 1: delegate research\n\n1. Invoke /gh-research for the ask and acceptance criteria.\n2. Wait for its bounded saturated brief.\n3. If the brief is cap-hit-with-residuals, surface that status; do not treat it as complete.\n4. Read the persisted research file by pointer when needed and check freshness metadata.\n5. If HEAD or the working-tree diff hash moved, re-verify stale load-bearing claims.\n\n## Phase 2: blind-spot analysis\n\nCreate a blind-spot table before decomposing:\n\n- Wrong-spec risk: judgment-only, mitigated only by user-blessed acceptance criteria and checkpoint.\n- Root-cause risk: executable-checkable if reproduced or covered by a failing test; otherwise advisory.\n- Integration risk: usually source-verified plus tests where possible.\n- Regression risk: executable-checkable when tests/typecheck/lint cover it.\n- Review risk: advisory cross-lab reviewers reduce correlated blind spots.\n- Concurrency or merge risk: source-verified and sometimes executable-checkable.\n- Missing-test risk: executable-checkable only after a test exists and runs.\n\nTag every blind spot as executable-checkable or judgment-only.\n\n## Phase 3 and 4: decompose and plan (run in parallel)\n\nThese two are INDEPENDENT: mcp__orchestrate__decompose consumes { ask, context: research brief plus blind-spots }, and the worker-plan subagent consumes the ask, acceptance criteria, research pointer, and blind-spot table. Neither needs the other's output. So issue BOTH in a SINGLE parallel batch (same turn) — call mcp__orchestrate__decompose and dispatch the worker-plan subagent together; do not wait for decompose first.\n\n- decompose: mcp__orchestrate__decompose({ ask, context: research brief plus blind-spots }). Treat the output as a proposal, not gospel; reject or revise nodes that do not map to a real blind spot.\n- plan: dispatch the worker-plan subagent (Agent tool, subagent_type worker-plan) with the ask, acceptance criteria, research pointer, and blind-spot table. Ask for files, tests, rollback concerns, and minimal safe increments; keep it bounded and suited to the change size.\n\n## Phase 5: compose a native Workflow\n\nCompose a native Workflow using the Workflow tool where every node has:\n\n- goal\n- input artifacts\n- output artifact\n- gh-router tool to call\n- blind spot it kills\n- deterministic or advisory annotation\n- producer and checker lab where relevant\n\nParallelism (the Workflow tool's core optimization rule):\n\n- DEFAULT to pipeline(): items flow through stages with NO barrier, so the slowest single item, not the slowest stage, sets wall-clock.\n- Use parallel() ONLY at a genuine barrier — a stage that needs ALL prior results at once (dedup/merge across the set, an early-exit on the total, or a cross-item comparison). \"It is cleaner\" or \"I need to map/flatten first\" is NOT a barrier; do that transform inside a pipeline stage.\n- Independent nodes within a phase run concurrently; never serialize work that has no data dependency.\n\nRole to tool mapping:\n\n- research: worker-explore (Agent subagent) and mcp__search__code for focused follow-ups.\n- plan: worker-plan (Agent subagent).\n- implement: worker-implement (Agent subagent), with worktree:true for parallel writers.\n- test: worker-test (Agent subagent), authored by a DIFFERENT LAB than the implementer when possible. This is an advisory practice, not enforced provenance.\n- review: mcp__peers__codex_reviewer plus mcp__peers__gemini_reviewer. Advisory unless findings are converted into executable checks or code changes.\n- baseline and selector: OPT-IN only because it doubles cost. Choose max(orchestrated, baseline) by EXECUTABLE gate result, not model judgment. If no executable oracle exists, say the selector is advisory.\n- verify: cross-lab checker plus mcp__orchestrate__attest_step with producer not equal to checker lab.\n\nNo nesting:\n\n- A Workflow node must not invoke /gh-orchestrate.\n- Workflow-spawned workers are internal sessions.\n- Internal sessions must not get prompt steering or stop-gate blocking.\n- Carry a depth or call budget and stop with a diagnostic if it would recurse.\n\n## Phase 6: verify the workflow\n\n1. Call mcp__orchestrate__verify_workflow.\n2. Fix drift between the ask, acceptance criteria, research, plan, and node graph.\n3. Bound this repair loop to at most 3 verification rounds.\n4. If drift remains after the cap, checkpoint with the drift as residual risk instead of pretending it is solved.\n\n## Phase 7: checkpoint, then run\n\nBefore running, present:\n\n- Goal and user-blessed acceptance criteria.\n- Node to tool map.\n- Per-node blind spot killed.\n- Per-node deterministic or advisory annotation.\n- Residual-risk list, including the wrong-spec residual.\n- Research saturation status and any open residual unknowns.\n- Cost estimate: workers, peer calls, tests, and whether baseline plus selector is enabled.\n- The statement that native Workflow approximates, but does not guarantee, hard max(orchestrated, baseline).\n\nAfter the checkpoint, run the Workflow only if it still appears right-sized for the ask.\nIf the user rejects scope or cost, downshift to the smallest workflow that kills the important blind spots.\n\n## Return format\n\nReturn:\n\n- Whether orchestration was skipped or run, with the right-sizing reason.\n- Acceptance criteria used.\n- Research brief pointer and freshness status.\n- Workflow summary and node annotations.\n- Executable gate results, if any.\n- Advisory review results, if any.\n- Final residual risks and next action.\n`,\n} as const\n","export const RESEARCH_SKILL = {\n name: \"gh-research\",\n md: `---\nname: gh-research\ndescription: Bounded saturation research for non-trivial GitHub Router asks: enumerates unknowns, gathers in parallel through code search, web search, and explore workers, adversarially verifies load-bearing claims, persists a freshness-stamped brief, and returns a compact confidence-tagged root-cause summary. Use when grounded context is needed before planning or changing code.\nuser-invocable: true\n---\n\n# gh-research: bounded saturation engine\n\nUse this skill when an ask needs grounded investigation before planning or editing.\nYour output is a compact confidence-tagged root-cause brief plus a pointer to the durable full brief.\nDo not try to be exhaustive forever; saturation is bounded by explicit caps.\n\n## Operating contract\n\n- Objective: find the most likely root cause, integration constraints, or decision facts for this ask.\n- Prefer primary sources over summaries.\n- Prefer executable proof over all other evidence.\n- Be honest about uncertainty: only verified-executable is deterministic.\n- Delegate heavy gather to workers so the top-level context stays compact.\n- Never silently claim completeness after hitting a cap.\n\n## Evidence tags\n\nUse these exact tags on every finding and claim:\n\n- verified-executable: reproduced the symptom, ran the failing test, or ran a check that directly proves the claim. This is the only deterministic confidence tag.\n- verified-source: read the actual source, config, logs, docs, or primary artifact and cited the relevant locations. This is model-mediated and can still be wrong.\n- cross-lab-agreed: a different-lab reviewer or critic independently agreed with the claim. This reduces correlated blind spots but is advisory.\n- unverified: plausible but not confirmed; treat as residual risk.\n\n## Bounded loop\n\nDefault caps unless the user explicitly gives a smaller or larger budget:\n\n- Maximum rounds: about 3.\n- Maximum parallel explore workers per round: finite and right-sized to the ask.\n- Maximum search and peer-review calls: finite; do not spend unbounded context.\n- Terminate at the first of saturation or a cap.\n- On cap-hit, return with open unknowns flagged as residual. Do not loop forever.\n\n## Procedure\n\n1. Restate the ask and define the research target.\n - Identify whether this is a bug, feature, refactor, incident, or design question.\n - Name the expected downstream consumer: implementer, orchestrator, floor-keeper, or user.\n\n2. Enumerate unknowns as an explicit worklist.\n - Include facts needed to decide the root cause or safe implementation path.\n - Mark each unknown as code, behavior, dependency, history, external, or acceptance-criteria related.\n - Add newly discovered unknowns as they appear.\n\n3. Fan out in parallel.\n - Run independent code, web, history, and explore calls concurrently where possible; only the semantic-to-lexical code-search refinement is ordered. Issue the independent calls in a SINGLE turn (one message, multiple tool calls) so the harness actually runs them in parallel rather than serializing.\n - Use mcp__search__code semantically first to find concepts and likely files.\n - Then use mcp__search__code lexically for exact symbols, filenames, errors, routes, flags, and config keys.\n - Use git blame or history when authorship, regression timing, or intent matters.\n - Use mcp__search__web for upstream APIs, package behavior, protocol docs, or public issues.\n - Launch parallel worker-explore background subagents (via the Agent tool, subagent_type worker-explore) for heavy gathering, each with a narrow question and expected artifact. They run non-blocking and report back on completion.\n - Keep worker results summarized; do not paste every detail into the main context.\n\n4. Form a root-cause hypothesis.\n - For bugs: describe the causal chain from trigger to observed symptom.\n - For features: identify integration points, constraints, and likely implementation seams.\n - For design questions: identify the decision, alternatives, and primary constraints.\n - State what would falsify the hypothesis.\n\n5. Verify load-bearing claims adversarially.\n - First preference: reproduce the bug, run the failing test, or run the direct check. Tag verified-executable.\n - If executable proof is not available, read the actual source or primary artifact and cite the lines. Tag verified-source.\n - Dispatch the worker-review subagent (via the Agent tool) to confirm the source-reading for important claims.\n - Ask a different-lab refuter through mcp__peers__codex_critic or mcp__peers__gemini_critic to try to refute the hypothesis.\n - Give the refuter the symptom, observed facts, and acceptance criteria, but not your proposed root cause. Avoid anchoring them.\n - If the refuter finds a plausible alternative, add it to the worklist and spend at most one bounded round resolving it.\n\n6. Run a completeness pass.\n - Ask: what do we still not know?\n - Ask: what claim, if false, would break the conclusion?\n - Ask: have we checked primary sources for every load-bearing claim?\n - Ask: did a further bounded round surface anything material?\n - If no material unknowns remain and the root cause is at least verified-source, stop for saturation.\n\n7. Persist the full brief.\n - Write a durable markdown file such as .docs/research/<slug>.md.\n - Include freshness metadata: HEAD commit, working-tree diff hash, timestamp, repo path, and command/search date.\n - Include the unknown worklist, searches run, workers consulted, evidence table, refuter result, residuals, and full citations.\n - Downstream phases should read by pointer and check freshness instead of re-injecting the whole brief.\n\n## Return format\n\nReturn a compact brief, not the whole research dump:\n\n- Research file: path to the durable brief.\n- Freshness: HEAD commit, diff hash, timestamp.\n- Termination: saturated or cap-hit; if cap-hit, name the cap.\n- Root-cause hypothesis: 3-8 bullets with confidence tags.\n- Evidence table: claim, tag, primary source or command, reviewer/refuter status.\n- Residual unknowns: explicit list, or none.\n- Downstream guidance: recommended next action and what must be rechecked if the tree changes.\n\n## Non-goals\n\n- Do not present verified-source or cross-lab-agreed as deterministic.\n- Do not hide open unknowns because the answer looks useful.\n- Do not keep searching after the cap.\n- Do not paste the entire persisted brief into later turns unless the user asks.\n`,\n} as const\n","/**\n * The `/gh-worker` skill: the operating model for the NON-BLOCKING workers\n * surface. Materialized into the per-launch mirror whenever `workerToolsEnabled()`\n * (same gate as the other floor-raising skills). Discoverability + playbook; the\n * load-bearing enforcement is the PreToolUse guard + the `worker-*` dispatcher\n * subagents (see src/lib/worker-dispatch.ts).\n */\nexport const WORKER_SKILL = {\n name: \"gh-worker\",\n md: `---\nname: gh-worker\ndescription: Runs github-router workers without blocking the turn: dispatches the matching worker-* background subagent (explore/implement/review/plan/test, up to 6 hours each) for a completion notification instead of a blocking wait. Use when a task would benefit from a background worker for investigation, planning, review, implementation, or test authoring.\nuser-invocable: true\n---\n\n# gh-worker: non-blocking workers\n\nWorker tasks (explore, implement, review, plan, test) can run for up to 6 hours.\nIn this session they are NON-BLOCKING BY DESIGN: you dispatch a\nbackground \\`worker-*\\` subagent, get control back immediately, and receive the\nworker's result as a completion notification when it finishes. Your turn is\nnever blocked waiting on a worker, and the worker's tool output never fills your\ncontext (only its final result comes back).\n\n## How to run a worker\n\nDispatch the matching dispatcher subagent with the Agent tool:\n\n- worker-explore: read-only investigation / codebase gathering, returns a summary.\n- worker-review: reads the code itself to verify a change or claim; findings with severity + file:line.\n- worker-plan: returns an ordered implementation plan from a task + acceptance criteria.\n- worker-implement: read/write/bash coding worker; pass worktree: true for isolated-worktree execution + a returned diff.\n- worker-test: independent test author that writes tests trying to break the implementation and reports pass/fail.\n\nPut the full worker brief in the subagent's prompt (and an absolute workspace\npath, or model/thinking/worktree, only if you need to override the defaults).\nThe dispatcher calls the worker once and relays its result verbatim.\n\n## What to expect\n\n- The dispatch returns immediately; you can keep working or start other workers.\n- When the worker finishes you get a completion notification carrying its result.\n- Up to 8 workers run concurrently (the worker-semaphore cap); further dispatches queue.\n- You do NOT call the raw mcp__...__ worker tools from the main thread: a guard\n denies that and points you at the matching worker-* subagent. That guard is the\n guarantee your turn never blocks; dispatching worker-* directly is the normal path.\n\n## Notes\n\n- Large worker output may be summarized by the dispatcher relay; for a big\n artifact, have the worker write it to a file and return the path.\n- Dispatching the same worker twice runs it twice (no dedup); avoid double-dispatch\n for side-effecting work like worker-implement.\n- Background subagents + completion notifications are the interactive default. In\n headless (claude -p) runs the task surface behaves differently; prefer interactive\n for long worker fan-out.\n`,\n} as const\n","import { randomBytes } from \"node:crypto\"\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport consola from \"consola\"\n\nimport { isUnderClaudeConfigMirror, PATHS } from \"./paths\"\n\n/**\n * Marker fences for each injection block. The literal text of each\n * fence is intentionally specific enough that a content collision with\n * user prose is implausible. Each block's parser only matches its own\n * marker pair, so blocks operate independently.\n *\n * Writer-side guard: the injector refuses to write a snippet that\n * itself contains its own marker literals (that would create\n * ambiguous state on the next launch where the inner literal would\n * parse as a new open or close marker).\n */\nconst PEER_MARKER_OPEN =\n \"<!-- gh-router peer-mcp awareness — auto-injected, regenerated per launch -->\"\nconst PEER_MARKER_CLOSE = \"<!-- /gh-router peer-mcp awareness -->\"\n\nconst STYLE_MARKER_OPEN =\n \"<!-- gh-router style directive — auto-injected, regenerated per launch -->\"\nconst STYLE_MARKER_CLOSE = \"<!-- /gh-router style directive -->\"\n\nconst OPERATING_MARKER_OPEN =\n \"<!-- gh-router operating defaults — auto-injected, regenerated per launch -->\"\nconst OPERATING_MARKER_CLOSE = \"<!-- /gh-router operating defaults -->\"\n\nconst TOOLBELT_MARKER_OPEN =\n \"<!-- gh-router toolbelt awareness — auto-injected, regenerated per launch -->\"\nconst TOOLBELT_MARKER_CLOSE = \"<!-- /gh-router toolbelt awareness -->\"\n\nconst ARTIFACT_MARKER_OPEN =\n \"<!-- gh-router artifact-panel directive — auto-injected when in an ai-or-die tab -->\"\nconst ARTIFACT_MARKER_CLOSE = \"<!-- /gh-router artifact-panel directive -->\"\n\n// Default-on review in the panel: when running inside an ai-or-die tab the\n// artifact_* tools reach a real review panel, so steer the agent to use it.\n// Lever split: this directive is the SOFT steer for the model-judgment cases\n// (show a comparison/table/diagram mid-conversation, which no hook can detect).\n// The one DETERMINISTIC artifact-open is the PostToolUse(ExitPlanMode) hook\n// (buildArtifactOpenHookCommand in claude.ts) that auto-opens a finalized plan.\n// A Stop / UserPromptSubmit hook is deliberately NOT added: it would either\n// mis-fire on ordinary turns or merely duplicate this soft steer.\n//\n// Scope: this block carries ONLY the trigger + the HTML-by-default steer + the\n// tool entry points + a pointer. The full authoring/review-loop playbook (HTML\n// conventions, design-system choice, per-type cheatsheet, the data-aod-*\n// controls, honest limits) lives in the materialized `gh-artifact-review`\n// skill, so it is not restated here every turn (per the injected-surface\n// review: CLAUDE.md holds the steer, the skill holds the procedure).\nfunction ARTIFACT_PANEL_DIRECTIVE(peersKey = \"peers\"): string {\n const toolPrefix = `mcp__${peersKey}__artifact_`\n return \"## Review in the artifact panel (HTML by default)\\n\\n\"\n + `You are running inside an ai-or-die tab, so the \\`${toolPrefix}*\\` tools drive a live human-review panel. `\n + \"Default to opening a self-contained HTML artifact for anything the user should review before you proceed: plans, design proposals, comparisons / trade-offs, decisions that need their input, diagrams, tables, code diffs, and reports. \"\n + \"Plan-mode plans are auto-rendered to HTML and opened for you; skip the panel only for trivial one-line answers. \"\n + `Run the \\`gh-artifact-review\\` skill for the full playbook: HTML + design conventions, the \\`${toolPrefix}open\\` / \\`${toolPrefix}await\\` (pass back the \\`cursor\\`) / \\`${toolPrefix}reply\\` / \\`${toolPrefix}end\\` loop, and the \\`data-aod-*\\` interactive controls.`\n}\n\n// Back-compat aliases used by existing tests. The peer block's\n// markers remain the \"default\" pair surfaced through __testExports.\nconst MARKER_OPEN = PEER_MARKER_OPEN\nconst MARKER_CLOSE = PEER_MARKER_CLOSE\n\n/**\n * Writing / communication style directive injected at the TOP of the\n * mirrored CLAUDE.md so every spawned agent (main, Agent-tool subagent,\n * agent-teams teammate) reads it before the user's own CLAUDE.md body.\n *\n * Self-referentially compliant: the directive itself uses no em\n * dashes and does not mention any Claude / Anthropic attribution.\n */\nconst STYLE_DIRECTIVE =\n \"Write concisely without losing detail. \"\n + \"Use a natural human voice. \"\n + \"Avoid em dashes. \"\n + \"Do not attribute work to Claude, AI, LLM, or Anthropic anywhere \"\n + \"(commits, PRs, issues, code, comments, docs).\"\n\n/**\n * Operating-defaults directive injected at the TOP of the mirrored CLAUDE.md.\n * The main agent's system prompt (`--append-system-prompt`) gets\n * OPERATING_DEFAULTS_DIGEST instead, with this full statement available through\n * CLAUDE.md. Three defaults, each explicitly overridden by the user's own\n * direction and the domain's standards:\n *\n * 1. Orchestrate (strong default): delegate the heavy / parallel /\n * context-heavy work to the right subagent / worker / model, keeping the\n * main context free to reason and collaborate with the user, while still\n * doing trivial / surgical / last-mile work directly (delegating that\n * would only add relay-fidelity loss + latency).\n * 2. Adversarial review: WHEN a peer critic earns its keep and, equally\n * important, when reaching for one is ritual rather than review. Same\n * failure shape the delegation default had: \"consult a critic for\n * non-trivial changes\" is unfalsifiable in advance, so it collapses into\n * either never (four of four unprimed agents) or always (worse than\n * never). The discriminator is whether the conclusion still turns on\n * judgment once the direct evidence is in: a consequential recommendation\n * cannot be run, which is exactly where confabulation hides, while a\n * tracing question a search already proved gains nothing from a second\n * model re-deriving it. The roster, the lens-to-artifact match, the\n * advisor-complements-rather-than-substitutes distinction, and the\n * do-not-anchor-the-critic rule live here; the digest carries only the\n * trigger and the ritual exclusion.\n * 3. Excellence lens: the principles stated plainly and concretely (radical\n * simplicity + real-user focus; whole-system first-principles thinking that\n * anticipates scale; work back from the customer outcome). Named exemplars\n * were dropped per the injected-surface review: a named entity is a dense,\n * high-variance vector that pulls in persona mannerisms at top salience, and\n * the guidance favors specific functional framing over comparison, so\n * specificity carries the vividness instead.\n * 4. Engineering excellence: quality / robustness / maintainability over\n * development cost; reproduce a bug end-to-end (as a real user hits it)\n * before fixing so the fix targets the real cause; a pixel-perfect UI bar;\n * and fix any lint error / test failure / flake on sight, whoever caused it,\n * folded into the current work rather than derailing the user's task (the\n * scope guardrail keeps proactive quality from becoming yak-shaving). The\n * digest carries a one-line form; the full statement lives here so it does\n * not cost the context window every turn.\n *\n * Self-referentially compliant with the style directive: no em dashes, no\n * Claude / Anthropic attribution.\n *\n * Availability-aware: four of the natives (`scout`, `implementer-fast`,\n * `reviewer-fast`, and `general-purpose-fast`) are DROPPED rather than\n * downgraded when no model in\n * their chain resolves, so naming them unconditionally here would tell the lead to delegate\n * to an agent that has no `.md` file and is absent from the Task\n * `subagent_type` enum. Build the directive with\n * `buildOperatingDefaultsDirective` and the same availability booleans used for\n * the `.md` generation and the awareness snippet; the exported const below is\n * the all-available form, kept for callers and tests that do not model a thin\n * catalog.\n */\n\n/** Which of the conditionally-emitted natives this launch actually wrote.\n * `undefined` means available, matching `buildPeerAwarenessSnippet`'s\n * `scoutAvailable` convention, so an existing caller that passes nothing keeps\n * the previous full-roster text. */\nexport interface NativeAgentAvailability {\n scoutAvailable?: boolean\n implementerFastAvailable?: boolean\n reviewerFastAvailable?: boolean\n generalPurposeFastAvailable?: boolean\n /** True when this launch's LEAD is a lighter Claude tier (sonnet, haiku)\n * rather than an Opus. Reorders the delegation clauses so the cheap tiers\n * lead; see `buildNativeReachClauses`. Absent/false keeps the Opus-lead\n * ordering, so existing callers are unaffected.\n *\n * Unlike the advisor's lead-awareness, this is resolved ONCE per launch and\n * baked into the mirrored CLAUDE.md, so it cannot follow a mid-session\n * `/model` switch. Acceptable for prose that biases a choice; it would not\n * be for anything that routes a request. */\n budgetLead?: boolean\n /** `\"fast\"` selects the fast launch profile's roster-restricted prose: a\n * hard restriction (not a catalog-availability signal, unlike every\n * `*Available` flag above). When set, `buildNativeReachClauses` and\n * `buildOperatingDefaultsDirective` return a short, self-contained\n * rendering naming only `scout`/`implementer`/`reviewer`/`planner`/`critic`,\n * Advisor, and Oracle — it must never name the standard-only `*-fast`/\n * `brainstorm`/`scribe`/`general-purpose-fast`, `peer-review-coordinator`,\n * `worker-*`/`orchestrate` tools or skills, or `stand_in`, since none of\n * those are registered in this profile regardless of catalog state.\n * Absent/`\"standard\"` is today's catalog-driven full roster. */\n profile?: \"standard\" | \"fast\"\n /** False when a fast launch disabled or failed its MCP/native runtime wiring.\n * The fallback directive must not advertise agents/tools that do not exist. */\n fastRuntimeAvailable?: boolean\n}\n\n/** Oxford-comma join: \"a\", \"a and b\", \"a, b, and c\". */\nfunction joinClauses(parts: ReadonlyArray<string>): string {\n if (parts.length <= 1) return parts[0] ?? \"\"\n if (parts.length === 2) return `${parts[0]} and ${parts[1]}`\n return `${parts.slice(0, -1).join(\", \")}, and ${parts[parts.length - 1]}`\n}\n\n/** The \"Reach for X when Y\" list, omitting any agent this launch did not emit.\n *\n * On a budget lead the coding AND review clauses swap order so the cheap tier\n * leads and the frontier tier is named as the complexity escalation. Choosing a\n * lighter lead is a decision to spend less while holding quality, and a roster\n * that names the expensive `implementer` / `reviewer` first works against\n * exactly that. This is ORDERING AND WORDING ONLY: no agent's model changes,\n * and both frontier tiers stay named so work beyond the fast tier still has\n * somewhere to go.\n *\n * Review gets the same treatment as implementation because the cost gap is the\n * same shape: `reviewer` runs the pro tier (200/1200 per 1M) against\n * `reviewer-fast`'s flash tier (75/375), and measured 2026-08-13 the flash\n * model was also the FASTER of the two on every axis (tool-call p50 ~1.2s vs\n * ~2.8s, TTFT ~1.9s vs ~3.7s, decode ~326 vs ~165 tok/s). So on a budget lead\n * there is no quality-for-cost trade being hidden by leading with the cheap\n * tier; reserve `reviewer` for the higher-stakes assessment it is there for. */\nfunction buildNativeReachClauses(opts: NativeAgentAvailability): string {\n if (opts.profile === \"fast\") {\n return joinClauses([\n \"`scout` to find or understand something in the repo\",\n \"`implementer` for approved mechanical coding changes\",\n \"`reviewer` for repository-aware verification, reproduction, and root-causing\",\n \"`planner` as the Sol plan consultant and approver after Luna has drafted with evidence\",\n \"`critic` for a fresh-context cross-lab challenge to a plan, design, diff, or decision\",\n ])\n }\n const clauses: Array<string> = []\n const implementerFast = opts.implementerFastAvailable !== false\n const reviewerFast = opts.reviewerFastAvailable !== false\n // The swap requires `implementer-fast` to actually exist this launch — on a\n // catalog where it was dropped, naming it first would point the lead at an\n // agent absent from the Task `subagent_type` enum.\n if (opts.budgetLead === true && implementerFast) {\n clauses.push(\n \"`implementer-fast` first for coding changes, since it is the cheaper and \"\n + \"faster tier and this session is running a lighter lead\",\n \"`implementer` when the change needs judgment, its scope is ambiguous, or \"\n + \"its complexity is beyond what the fast tier can carry\",\n )\n } else {\n clauses.push(\n \"`implementer` for coding changes that need judgment or have ambiguous scope\",\n )\n if (implementerFast) {\n clauses.push(\"`implementer-fast` for well-specified, mechanical coding changes\")\n }\n }\n // Same swap, same precondition, for the review pair.\n if (opts.budgetLead === true && reviewerFast) {\n clauses.push(\n \"`reviewer-fast` first when something exists and you want it assessed, \"\n + \"since it is the cheaper and faster review tier\",\n \"`reviewer` when the assessment is higher-stakes or needs deeper \"\n + \"reproduction and root-causing than the fast tier can carry\",\n )\n } else {\n clauses.push(\n \"`reviewer` when something exists and you want it assessed (including \"\n + \"reproducing and root-causing a failure)\",\n )\n if (reviewerFast) {\n clauses.push(\"`reviewer-fast` for lower-stakes assessments\")\n }\n }\n clauses.push(\n \"`brainstorm` when you do not yet know which approach to take\",\n )\n if (opts.scoutAvailable !== false) {\n clauses.push(\"`scout` to find or understand something in the repo\")\n }\n clauses.push(\"`scribe` for docs and ADRs that trail the code\")\n if (opts.generalPurposeFastAvailable !== false) {\n clauses.push(\n opts.budgetLead === true\n ? \"`general-purpose-fast` for work no specialist fits, in preference to \"\n + \"carrying it inline yourself\"\n : \"`general-purpose-fast` for work no specialist fits\",\n )\n }\n return joinClauses(clauses)\n}\n\n/** Everything after the orchestration paragraph's agent list. Unchanged by\n * availability, so it lives here once rather than in both branches. */\nconst OPERATING_DEFAULTS_TAIL =\n \"context free to reason and collaborate with the user. Launch independent \"\n + \"agents concurrently in a single message rather than serially. Delegation \"\n + \"pays when the work is WIDE \"\n + \"(many files or sources to sweep) or SLOW, and you need only the \"\n + \"conclusion: the main thread is where you think with and respond to the \"\n + \"user, and its context window is a finite shared resource. It does NOT pay \"\n + \"merely because a sub-question is separable. A narrow, deep question whose \"\n + \"whole value is file:line fidelity loses exactly that through a \"\n + \"summarization layer, and a sub-question you could answer in one command is \"\n + \"cheaper done directly than paying a subagent's startup. Do trivial, \"\n + \"surgical, and last-mile work yourself. A named teammate persists after it \"\n + \"reports so you can send it follow-ups, and nothing reaps it for you: its idle \"\n + \"notice means available, not finished. Stop it once you are done with it.\\n\\n\"\n + \"Adversarial review. The peer critics (`codex_critic` and `codex_reviewer`, \"\n + \"`gemini_critic` and `gemini_reviewer`, `opus_critic`, and the \"\n + \"`peer-review-coordinator` that fans out to several of them) are \"\n + \"fresh-context models, so what they add is a blind spot that whoever \"\n + \"produced the work cannot reach by thinking harder about it; prefer a \"\n + \"critic from a different lab than the producer, since blind spots \"\n + \"correlate within a lab. The `advisor` is a complement and not a \"\n + \"substitute: it sees your transcript, so it catches your own drift and \"\n + \"momentum, but it inherits your framing, which is exactly what a \"\n + \"fresh-context critic does not. They earn their keep on consequential design \"\n + \"choices, recommendations, and hard-to-reverse decisions: the cases where \"\n + \"plausible alternatives remain and the conclusion rests on judgment rather \"\n + \"than on something you can verify directly. That is where confabulation \"\n + \"hides, so budget the wait even under delivery pressure. Always consult one \"\n + \"when the change touches auth, user input, database queries, crypto, or \"\n + \"serialization. They do NOT pay for read-only tracing, ordinary repository \"\n + \"lookup, or a conclusion that a focused test, a direct reproduction, or \"\n + \"unambiguous code evidence already settles. Asking a critic to re-derive a \"\n + \"proven fact returns a confident answer either way, which is ritual \"\n + \"skepticism rather than review, and skipping them there is the right call \"\n + \"and not a shortcut. Match the lens to the artifact: a strategic critic for \"\n + \"plans and trade-offs, a code reviewer for a concrete diff, the coordinator \"\n + \"only when the risk warrants several independent lenses. Give whichever you \"\n + \"pick the artifact and the constraints and not your rationale, since \"\n + \"justification anchors the review and dulls it.\\n\\n\"\n + \"Aim high. Default to radical simplicity and a relentless focus on the user's \"\n + \"real experience: design for the person and the job to be done, not the demo. \"\n + \"Reason about the whole system from first principles, anticipating scale and the \"\n + \"long arc rather than patching the surface. Work backwards from the outcome the \"\n + \"user actually needs. Question every assumption and prefer what you can derive, \"\n + \"reproduce, or test.\\n\\n\"\n + \"Engineering excellence. When making technical decisions, give little weight to \"\n + \"development cost; prefer quality, simplicity, robustness, scalability, and \"\n + \"long-term maintainability. Fix a bug by first reproducing it end to end, as \"\n + \"close to how a real user hits it as you can, so you solve the real problem and \"\n + \"not a symptom. When testing a product end to end, be picky about the UI and \"\n + \"obsessed with pixel perfection: if something clearly looks off, even when it is \"\n + \"unrelated to your task, get it fixed along the way. Hold that same bar for the \"\n + \"codebase itself: a lint error, a failing test, or a flaky test is worth fixing \"\n + \"the moment you see it, whoever introduced it. Fold it into your current work \"\n + \"rather than letting it derail the task the user actually asked for.\"\n\n/**\n * Build the operating-defaults directive for one launch, naming only the\n * natives that launch actually emitted.\n *\n * Callers must pass the SAME availability booleans they used for the `.md`\n * generation and `buildPeerAwarenessSnippet`, so the three surfaces cannot\n * disagree about which agents exist.\n */\n/**\n * Fast-profile-only operating-defaults body. Self-contained (does not share\n * text with `OPERATING_DEFAULTS_TAIL`) because that tail names\n * `codex_critic`/`codex_reviewer`/`gemini_reviewer`/`opus_critic`/\n * `peer-review-coordinator` and `worker-*` agents, none of which the fast\n * profile registers — reusing it and trying to string-surgery those names\n * out would be far more fragile than a short, purpose-written paragraph.\n * Keeps the same \"why delegate\" and \"why adversarial review\" reasoning the\n * standard tail carries, scaled to the fast profile's actual roster.\n */\nconst FAST_OPERATING_DEFAULTS_TAIL =\n \"context free to reason and collaborate with the user. Delegate only when work is wide or slow; do trivial and surgical work directly. \"\n + \"Luna investigates and drafts. The lead must give `planner` a handcrafted evidence packet and must not implement until `planner` returns `APPROVE`. \"\n + \"Advisor is an optional, non-binding, lead-only transcript-aware sounding board for consequential unresolved uncertainty, conflicting evidence, or a genuinely stuck path; never use it for routine progress, waiting, directly verifiable facts, planner approval, reviewer verification, or completion ritual. \"\n + \"`oracle` is exact Opus 5 (1M/high), stateless and last resort after the normal paths remain stuck. \"\n + \"Before declaring work done, run the relevant build/tests and ask `reviewer` for repository-aware verification. \"\n + \"Verify claims, report uncertainty, and stop named teammates when finished.\"\n\nexport function buildOperatingDefaultsDirective(\n opts: NativeAgentAvailability = {},\n): string {\n if (opts.profile === \"fast\") {\n if (opts.fastRuntimeAvailable === false) {\n return (\n \"## Operating defaults (apply when the user has not specified otherwise; the \"\n + \"user's explicit direction and the domain's own standards always override)\\n\\n\"\n + \"Fast profile runtime wiring is unavailable, so no injected Task roster, search, or Oracle is available. Work directly, use only tools actually listed in this session, verify with the repository's relevant build/tests before declaring done, report uncertainty, and do not invent unavailable capabilities.\"\n )\n }\n return (\n \"## Operating defaults (apply when the user has not specified otherwise; the \"\n + \"user's explicit direction and the domain's own standards always override)\\n\\n\"\n + \"Orchestrate. Delegate research, implementation, and review to the right \"\n + \"subagent. Reach for \"\n + buildNativeReachClauses(opts)\n + \"; Task subagents run in parallel. That keeps your own \"\n + FAST_OPERATING_DEFAULTS_TAIL\n )\n }\n return (\n \"## Operating defaults (apply when the user has not specified otherwise; the \"\n + \"user's explicit direction and the domain's own standards always override)\\n\\n\"\n + \"Orchestrate. Delegate research, implementation, review, and large reads to the \"\n + \"right subagent, worker, or model. Reach for \"\n + buildNativeReachClauses(opts)\n + \"; worker-* agents for background \"\n + \"non-blocking runs; Task subagents for parallel work; peer critics for review. \"\n + \"That keeps your own \"\n + OPERATING_DEFAULTS_TAIL\n )\n}\n\n/** The all-available form of the directive. Prefer\n * `buildOperatingDefaultsDirective` on any path that knows which natives\n * resolved; this const is the default for callers and tests that do not model\n * a thin catalog. */\nexport const OPERATING_DEFAULTS_DIRECTIVE = buildOperatingDefaultsDirective()\n\n/**\n * Condensed digest of OPERATING_DEFAULTS_DIRECTIVE for the spawned session's\n * system prompt (--append-system-prompt). The FULL directive is prepended to\n * the mirrored CLAUDE.md (read by the main agent and descendants); this digest\n * keeps both behavioral directives at top salience without duplicating the full\n * ~310-token block in the context window every turn. Points to the full copy.\n *\n * The unverifiable-claim rule is here rather than in CLAUDE.md alone because it\n * fires at a moment that suppresses lookups: an agent racing to deliver a\n * recommendation is precisely the one that will not stop to consult its project\n * instructions, which is how the check got crowded out in the first place. It\n * also closes a hole in the rule above it, which only covers claims that direct\n * evidence CAN settle. The roster of critics, the lens-to-artifact match, and\n * the reasoning stay in the directive; the always-resident copy carries only\n * the trigger and the ritual exclusion.\n */\nexport const OPERATING_DEFAULTS_DIGEST =\n \"## Operating defaults (the user's explicit direction and the domain's standards always override)\\n\\n\"\n + \"Delegate when the work is WIDE (many files or sources to sweep) or SLOW and you need only the \"\n + \"conclusion, to protect the main thread's finite context and keep it free for reasoning and \"\n + \"interacting with the user; prefer parallel delegation for independent work. Do NOT delegate \"\n + \"merely because a sub-question is separable: a narrow, deep question whose value is file:line \"\n + \"fidelity loses exactly that through a summarization layer, and one answerable in a single \"\n + \"command is cheaper done directly. Do trivial, surgical, and last-mile work yourself. \"\n + \"Stop a named teammate once you are done with it: it persists for follow-ups, its idle \"\n + \"notice means available rather than finished, and nothing reaps it for you.\\n\\n\"\n + \"Verify, do not assert. Run the code, read the file, check the exit code. A claim in prose is \"\n + \"worth nothing against state you did not check, and a check that cannot fail proves nothing. \"\n + \"Reproduce a bug end to end, the way a real user hits it, before fixing it. Fix a lint error, \"\n + \"failing test, or flake the moment you see it, whoever introduced it, without letting it \"\n + \"derail the task at hand. Prefer quality and long-term maintainability over development cost.\\n\\n\"\n + \"Verification has a blind spot: a consequential recommendation, a design or trade-off call, or \"\n + \"a hard-to-reverse decision that still turns on judgment among plausible alternatives once the \"\n + \"direct evidence is in. That is where confabulation hides, so put it past a peer critic before \"\n + \"you ship it and budget the wait even under delivery pressure. When a test, a run, a \"\n + \"reproduction, or a search would settle the claim, settle it that way instead; a critic asked \"\n + \"to re-derive what you can already prove is ritual, not review.\\n\\n\"\n + \"The agent roster, the tool surface, and the reasoning behind these defaults are in your \"\n + \"CLAUDE.md project instructions. Read them when choosing HOW to work; the rules above apply \"\n + \"without a lookup.\"\n\n/**\n * Skip the helper if the user's `~/.claude/CLAUDE.md` (or, equivalently,\n * the would-be post-write file) has grown past this size.\n * Read-modify-write becomes pathological at very large sizes; CLAUDE.md\n * should never legitimately be a database. The main agent still gets\n * the awareness via `--append-system-prompt`, so skipping here only\n * loses descendant-reach.\n */\nconst MAX_CLAUDE_MD_BYTES = 1 * 1024 * 1024 // 1 MiB\n\n/**\n * Bounded retry budget for the temp → rename step on Windows where\n * `fs.rename` can transiently fail with EBUSY / EPERM / EACCES when\n * CLAUDE.md is open in an editor, scanned by AV, or indexed by the\n * search service. Mirrors the verify-on-rename-fail pattern at\n * `paths.ts:795-818`. POSIX renames almost never fail this way; the\n * cost on Linux/macOS is one extra `lstat` in the unhappy path.\n */\nconst RENAME_RETRY_DELAYS_MS = [50, 200, 500] as const\n\n/**\n * Grep-able error-code prefix. Every warn-and-continue path here\n * starts its message with this token so a Windows user who never sees\n * a fresh marker block in their mirror can `grep CLAUDE_MD_WRITE` in\n * the launcher output and land on the actionable line directly.\n */\nconst ERROR_CODE = \"CLAUDE_MD_WRITE\"\n\ninterface MarkerBlock {\n openLineIndex: number\n closeLineIndex: number\n}\n\n/**\n * Find every well-formed marker block matching the given `markerOpen`\n * + `markerClose` pair. A well-formed block is an exact `markerOpen`\n * line followed somewhere later (any number of intervening lines) by\n * an exact `markerClose` line, with no intervening `markerOpen`.\n * Multiple stale blocks all surface here so the caller can remove\n * all of them.\n *\n * Malformed state (open without close, or close without open) is\n * reported separately via the second return value so the caller can\n * `warn` and leave user prose untouched. We never try to \"fix\"\n * malformed marker state — that risks corrupting user content.\n */\nexport function findMarkerBlocks(\n lines: ReadonlyArray<string>,\n markerOpen: string = PEER_MARKER_OPEN,\n markerClose: string = PEER_MARKER_CLOSE,\n): {\n blocks: Array<MarkerBlock>\n malformed: boolean\n} {\n const blocks: Array<MarkerBlock> = []\n let pendingOpen: number | null = null\n let malformed = false\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n if (line === markerOpen) {\n if (pendingOpen !== null) {\n // Two opens with no close between them — malformed.\n malformed = true\n }\n pendingOpen = i\n } else if (line === markerClose) {\n if (pendingOpen === null) {\n // Close with no preceding open — malformed.\n malformed = true\n } else {\n blocks.push({ openLineIndex: pendingOpen, closeLineIndex: i })\n pendingOpen = null\n }\n }\n }\n if (pendingOpen !== null) {\n // Open with no close — malformed.\n malformed = true\n }\n return { blocks, malformed }\n}\n\n/**\n * Detect line-ending style of `content`. Returns `\"\\r\\n\"` if `\\r\\n`\n * sequences outnumber bare `\\n`; otherwise `\"\\n\"`. Empty content\n * defaults to `\\n` (POSIX-style new file).\n *\n * Preserves CRLF on Windows users' existing CLAUDE.md — flipping their\n * line endings under them would be a regression even though Claude\n * Code itself reads either style.\n */\nfunction detectLineEnding(content: string): \"\\r\\n\" | \"\\n\" {\n if (content.length === 0) return \"\\n\"\n // Count CRLF occurrences. Bare `\\n` count is `\\n total - CRLF count`.\n const crlf = (content.match(/\\r\\n/g) ?? []).length\n const totalLf = (content.match(/\\n/g) ?? []).length\n const bareLf = totalLf - crlf\n return crlf > bareLf ? \"\\r\\n\" : \"\\n\"\n}\n\n/**\n * Strip a leading UTF-8 BOM (`U+FEFF`) if present so the first line's\n * marker comparison is byte-exact. CLAUDE.md authored on Windows in\n * Notepad / VS Code sometimes carries a BOM; without this strip the\n * first marker line would never match (`<BOM><!--...` !== `<!--...`)\n * and successive launches would loop into malformed-state warn paths.\n */\nfunction stripLeadingBom(content: string): string {\n return content.charCodeAt(0) === 0xfeff ? content.slice(1) : content\n}\n\n/**\n * Split `content` into lines without losing the line-ending style.\n * The split is done on `\\n`; trailing `\\r` (from CRLF) is stripped\n * from each line for marker comparison, but the original ending is\n * reconstructed via `detectLineEnding` + `joinLines`.\n */\nfunction splitLines(content: string): Array<string> {\n if (content.length === 0) return []\n const lines = content.split(\"\\n\").map((l) =>\n l.endsWith(\"\\r\") ? l.slice(0, -1) : l,\n )\n // If the file ends in `\\n`, the trailing element is `\"\"` — keep it\n // so we can detect \"trailing newline present\" when rebuilding.\n return lines\n}\n\nfunction joinLines(lines: ReadonlyArray<string>, eol: \"\\r\\n\" | \"\\n\"): string {\n return lines.join(eol)\n}\n\n/**\n * Containment check that defeats symlink/junction tricks (peer-review\n * C3). `isUnderClaudeConfigMirror` is purely lexical via\n * `path.resolve()` — it does NOT dereference symlinks, so an attacker\n * (or an unfortunate `~/.claude` symlinked into Dropbox) could escape\n * the mirror while passing the lexical guard. This helper resolves\n * BOTH paths to their canonical form via `fs.realpath()` first.\n *\n * **Fail-closed semantics (advisor follow-up):**\n *\n * - If the mirror root itself is a symlink (`lstat` reports\n * `isSymbolicLink() === true`), refuse. A symlinked mirror root\n * means writes flow through the link to whatever the user (or an\n * attacker) targeted — the boundary's whole point is to never\n * mutate real `~/.claude/`, so accepting any symlinked root\n * undermines it.\n * - If `realpath` fails on the mirror root OR the target parent,\n * refuse. The mirror dir is provisioned by `ensureClaudeConfigMirror`\n * before this helper runs (documented ordering invariant); a\n * `realpath` failure here signals an unexpected state, and after\n * the root check has already succeeded a missing parent means the\n * root vanished between checks (TOCTOU race).\n */\nexport async function isUnderClaudeConfigMirrorRealpath(\n target: string,\n): Promise<boolean> {\n // Fast lexical reject first: if even the lexical check fails the\n // path is clearly wrong and we never need to touch the filesystem.\n if (!isUnderClaudeConfigMirror(target)) return false\n\n const mirrorRoot = PATHS.CLAUDE_CONFIG_DIR\n\n // Reject a symlinked mirror root. realpath would happily follow it\n // and the resolved target would still appear \"under\" the resolved\n // root — masking the escape.\n try {\n const rootLink = await fs.lstat(mirrorRoot)\n if (rootLink.isSymbolicLink()) {\n consola.warn(\n `${ERROR_CODE}: mirror root is a symlink (${mirrorRoot}); refusing to write through it`,\n )\n return false\n }\n } catch (err) {\n consola.warn(\n `${ERROR_CODE}: cannot lstat mirror root ${mirrorRoot}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n return false\n }\n\n // Canonicalize the mirror root. Failure here is fail-closed — the\n // mirror should exist by the time this helper runs.\n let resolvedRoot: string\n try {\n resolvedRoot = await fs.realpath(mirrorRoot)\n } catch (err) {\n consola.warn(\n `${ERROR_CODE}: realpath failed on mirror root ${mirrorRoot}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n return false\n }\n\n // Canonicalize the target's parent. ENOENT here is fail-closed: the\n // mirror root has already been lstat'd and realpath'd successfully\n // above, so a missing parent at this point means the root vanished\n // between checks — exactly the race-window an attacker would use to\n // swap the mirror with a symlink/junction. Refuse rather than grant\n // access (peer-review codex-critic C1).\n const targetParent = path.dirname(target)\n let resolvedTargetParent: string\n try {\n resolvedTargetParent = await fs.realpath(targetParent)\n } catch (err) {\n consola.warn(\n `${ERROR_CODE}: realpath failed on target parent ${targetParent} after root check (TOCTOU?): ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n return false\n }\n\n if (resolvedTargetParent === resolvedRoot) return true\n return resolvedTargetParent.startsWith(resolvedRoot + path.sep)\n}\n\n/**\n * Try `fs.rename(temp, target)` with bounded retry + verify-on-fail.\n * Mirrors `injectSyntheticClaudeJsonFields` in `paths.ts`. Windows\n * `fs.rename` can transiently fail with EBUSY / EPERM / EACCES when\n * the destination is held by another process (editor, AV, search\n * indexer). Returns `true` on eventual success, `false` after all\n * retries are exhausted (caller will warn-and-continue).\n *\n * On final failure we read the destination back and check whether it\n * already matches `desiredContent` — a concurrent racer may have\n * landed the same bytes (the snippet is deterministic per launch).\n * In that case treat as success.\n *\n * **No `copyFile` fallback** (peer-review codex-critic C2). `fs.copyFile`\n * follows the destination path — if `target` was replaced with a\n * symlink/junction between our earlier `lstat` and now (TOCTOU), or\n * if `target` is a hardlink to the real `~/.claude/CLAUDE.md`,\n * `copyFile` would mutate user files through the link. The boundary\n * we are defending says \"never mutate the real `~/.claude/`\". Rename\n * is safe because replacing a path entry doesn't follow the link; the\n * `copyFile` degradation reintroduces the escape. Fail-closed instead.\n */\nexport async function renameWithRetry(\n tempPath: string,\n target: string,\n desiredContent: string,\n): Promise<boolean> {\n let lastErr: unknown\n for (let attempt = 0; attempt <= RENAME_RETRY_DELAYS_MS.length; attempt++) {\n try {\n await fs.rename(tempPath, target)\n return true\n } catch (err) {\n lastErr = err\n // Don't sleep after the final attempt.\n if (attempt < RENAME_RETRY_DELAYS_MS.length) {\n await new Promise<void>((resolve) =>\n setTimeout(resolve, RENAME_RETRY_DELAYS_MS[attempt]),\n )\n }\n }\n }\n\n // All retries exhausted. Verify-on-fail: did a racer land the same\n // bytes we wanted? (Matches the paths.ts:795-818 pattern.)\n try {\n const observed = await fs.readFile(target, \"utf8\")\n if (observed === desiredContent) {\n await fs.unlink(tempPath).catch(() => {})\n consola.debug(\n `${ERROR_CODE}: rename failed but target already holds expected content (racer-won-race): ${\n lastErr instanceof Error ? lastErr.message : String(lastErr)\n }`,\n )\n return true\n }\n } catch {\n // Fall through to final cleanup + caller-side warn.\n }\n\n // Fail-closed: no copyFile fallback (would follow symlinks/hardlinks\n // and bypass the never-mutate-user-files boundary). Better to lose\n // descendant-reach for this launch than to risk overwriting the\n // user's real CLAUDE.md.\n await fs.unlink(tempPath).catch(() => {})\n consola.warn(\n `${ERROR_CODE}: rename failed for ${target} after ${RENAME_RETRY_DELAYS_MS.length + 1} attempts (no copyFile fallback to avoid symlink/hardlink escape; descendant-reach via CLAUDE.md disabled this launch; main agent still has --append-system-prompt). rename err: ${\n lastErr instanceof Error ? lastErr.message : String(lastErr)\n }`,\n )\n return false\n}\n\n/**\n * Generic marker-block injection into the mirrored CLAUDE.md.\n * Parameterized on the marker pair (so independent blocks coexist\n * without colliding) and position (`\"top\"` = prepend, `\"bottom\"` =\n * append). Encapsulates all the safety invariants; the two exported\n * helpers (`appendPeerAwarenessToMirroredClaudeMd` and\n * `prependStyleDirectiveToMirroredClaudeMd`) are thin wrappers.\n */\ninterface InjectMarkerBlockOpts {\n snippet: string\n markerOpen: string\n markerClose: string\n position: \"top\" | \"bottom\"\n /** Logged in debug messages so the two callers are distinguishable. */\n label: string\n}\n\nasync function injectMarkerBlock(opts: InjectMarkerBlockOpts): Promise<void> {\n const { snippet, markerOpen, markerClose, position, label } = opts\n\n // Invariant 7: writer-side guard. Refuse to inject a snippet that\n // contains either marker literal — otherwise the next launch's\n // parser would see the inner literal as a new open/close and\n // either delete user content (the I5 footgun) or trip the\n // malformed-marker path indefinitely. The snippet body should\n // never legitimately contain these strings; failing fast here\n // catches a builder bug at the source.\n if (snippet.includes(markerOpen) || snippet.includes(markerClose)) {\n consola.warn(\n `${ERROR_CODE}: refusing to inject ${label} snippet that contains marker literal; this would corrupt idempotency on the next launch`,\n )\n return\n }\n\n const target = path.join(PATHS.CLAUDE_CONFIG_DIR, \"CLAUDE.md\")\n\n // Invariant 1: mirror-only safety guard (symlink-resolving).\n if (!(await isUnderClaudeConfigMirrorRealpath(target))) {\n consola.warn(\n `${ERROR_CODE}: refusing to write outside resolved mirror dir (target=${target}, mirror=${PATHS.CLAUDE_CONFIG_DIR}) [${label}]`,\n )\n return\n }\n\n // Invariant 2: refuse to follow symlinks on the leaf. lstat tells\n // us about the link itself; fs.readFile would silently follow.\n let existingContent: string\n let targetExists: boolean\n try {\n const linkStat = await fs.lstat(target)\n if (linkStat.isSymbolicLink()) {\n consola.warn(\n `${ERROR_CODE}: refusing to write through symlinked CLAUDE.md (target=${target}) [${label}]`,\n )\n return\n }\n if (!linkStat.isFile()) {\n // Directory or other non-regular entry sitting where CLAUDE.md\n // should be. Refuse rather than try to fix.\n consola.warn(\n `${ERROR_CODE}: refusing to write non-regular target (target=${target}, mode=${linkStat.mode.toString(8)}) [${label}]`,\n )\n return\n }\n // Early size guard (peer-review codex-critic suggestion #9) — skip\n // before paying the readFile cost. The post-build size guard below\n // catches the runaway-snippet case; this catches the runaway-file\n // case. nlink > 1 also caught here: hardlinked CLAUDE.md to the\n // real user file would otherwise be a path-following escape via\n // fs.writeFile, even with the symlink-refusal above.\n if (linkStat.size > MAX_CLAUDE_MD_BYTES) {\n consola.warn(\n `${ERROR_CODE}: skipping oversized CLAUDE.md (${linkStat.size} bytes > ${MAX_CLAUDE_MD_BYTES}) [${label}]; descendant-reach disabled this launch`,\n )\n return\n }\n if (linkStat.nlink > 1) {\n consola.warn(\n `${ERROR_CODE}: refusing to write to hardlinked CLAUDE.md (nlink=${linkStat.nlink}) [${label}]; would mutate shared inode`,\n )\n return\n }\n targetExists = true\n existingContent = await fs.readFile(target, \"utf8\")\n } catch (err) {\n if (\n typeof err === \"object\"\n && err !== null\n && \"code\" in err\n && (err as { code: string }).code === \"ENOENT\"\n ) {\n // No existing CLAUDE.md — start from empty content.\n existingContent = \"\"\n targetExists = false\n } else {\n consola.warn(\n `${ERROR_CODE}: failed to stat/read target (${target}) [${label}]: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n return\n }\n }\n\n // Invariant 4: detect line-ending style from the existing content\n // AND remember whether the file had a UTF-8 BOM so we can preserve\n // it (peer-review codex-critic I5).\n const hadBom = existingContent.charCodeAt(0) === 0xfeff\n const normalizedContent = stripLeadingBom(existingContent)\n const eol = detectLineEnding(normalizedContent)\n\n // Strip prior well-formed marker blocks of THIS pair only\n // (invariant 5: malformed state is warn-and-leave; we do not edit\n // through user prose). Other marker pairs in the file are untouched\n // so the peer-awareness block and the style block coexist without\n // interfering.\n const lines = splitLines(normalizedContent)\n const { blocks, malformed } = findMarkerBlocks(lines, markerOpen, markerClose)\n if (malformed) {\n consola.warn(\n `${ERROR_CODE}: malformed marker state in ${target} (open without close or vice versa) [${label}]; leaving file untouched`,\n )\n return\n }\n // Remove blocks in reverse order so earlier indices stay valid.\n // Also drop blank-line separators that were inserted around the\n // block on prior writes (loop until non-blank to handle accumulation).\n const cleanedLines = [...lines]\n for (let i = blocks.length - 1; i >= 0; i--) {\n const block = blocks[i]\n cleanedLines.splice(\n block.openLineIndex,\n block.closeLineIndex - block.openLineIndex + 1,\n )\n if (position === \"bottom\") {\n // Drop trailing blank lines BEFORE the (removed) block.\n while (\n block.openLineIndex - 1 >= 0\n && cleanedLines[block.openLineIndex - 1] === \"\"\n && cleanedLines.slice(0, block.openLineIndex - 1).some((l) => l !== \"\")\n ) {\n cleanedLines.splice(block.openLineIndex - 1, 1)\n }\n } else {\n // position === \"top\": drop leading blank lines AFTER the\n // (removed) block — they were the separator we inserted last\n // time between our prepended block and user content.\n while (\n block.openLineIndex < cleanedLines.length\n && cleanedLines[block.openLineIndex] === \"\"\n && cleanedLines.slice(block.openLineIndex + 1).some((l) => l !== \"\")\n ) {\n cleanedLines.splice(block.openLineIndex, 1)\n }\n }\n }\n\n // Trim trailing blank lines so the bottom-append block sits with\n // exactly one separator; for top-prepend, trim leading blanks\n // analogously.\n if (position === \"bottom\") {\n while (\n cleanedLines.length > 0\n && cleanedLines[cleanedLines.length - 1] === \"\"\n ) {\n cleanedLines.pop()\n }\n } else {\n while (cleanedLines.length > 0 && cleanedLines[0] === \"\") {\n cleanedLines.shift()\n }\n }\n\n // Build the final content. Position determines whether our block\n // sits at the top or bottom, with exactly one blank-line separator\n // between user content and our block.\n const snippetLines = snippet.split(\"\\n\").map((l) =>\n l.endsWith(\"\\r\") ? l.slice(0, -1) : l,\n )\n const markerBlockLines = [markerOpen, ...snippetLines, markerClose]\n let finalLines: Array<string>\n if (cleanedLines.length === 0) {\n finalLines = [...markerBlockLines, \"\"]\n } else if (position === \"bottom\") {\n finalLines = [...cleanedLines, \"\", ...markerBlockLines, \"\"]\n } else {\n finalLines = [...markerBlockLines, \"\", ...cleanedLines, \"\"]\n }\n const bodyContent = joinLines(finalLines, eol)\n const finalContent = hadBom ? \"\" + bodyContent : bodyContent\n\n // Invariant 3: size guard, measured on the post-build content so a\n // user fixture sitting just below the cap with a stale block can\n // still be cleaned up (peer-review I6).\n if (Buffer.byteLength(finalContent, \"utf8\") > MAX_CLAUDE_MD_BYTES) {\n consola.warn(\n `${ERROR_CODE}: post-build content exceeds ${MAX_CLAUDE_MD_BYTES} bytes [${label}]; skipping update (descendant-reach disabled this launch)`,\n )\n return\n }\n\n // Invariant 6: atomic temp + rename, with bounded retry + verify-\n // on-fail. No copyFile fallback (would defeat symlink boundary).\n const tempPath = `${target}.${process.pid}.${randomBytes(4).toString(\"hex\")}.tmp`\n try {\n await fs.writeFile(tempPath, finalContent, {\n encoding: \"utf8\",\n flag: \"wx\",\n })\n } catch (err) {\n await fs.unlink(tempPath).catch(() => {})\n consola.warn(\n `${ERROR_CODE}: temp-file write failed for ${tempPath} [${label}]: ${\n err instanceof Error ? err.message : String(err)\n }`,\n )\n return\n }\n const ok = await renameWithRetry(tempPath, target, finalContent)\n if (!ok) return\n\n consola.debug(\n `${ERROR_CODE}: ${\n targetExists ? \"updated\" : \"created\"\n } ${target} [${label}] (${finalContent.length} bytes, eol=${eol === \"\\r\\n\" ? \"CRLF\" : \"LF\"})`,\n )\n}\n\n/**\n * Append the peer-MCP awareness `snippet` to the mirrored\n * `<CLAUDE_CONFIG_DIR>/CLAUDE.md`. Idempotent across launches: prior\n * well-formed peer-marker blocks are removed before appending a fresh\n * one at the bottom. The original user content is preserved\n * byte-for-byte at the top (modulo line-ending normalization to the\n * file's detected style; leading UTF-8 BOM is preserved).\n *\n * Failures `warn` and return — this surface is the descendant-reach\n * enhancement; the main agent still gets the awareness via\n * `--append-system-prompt`. Every warn message starts with\n * `CLAUDE_MD_WRITE` so users can grep launcher output.\n */\nexport async function appendPeerAwarenessToMirroredClaudeMd(\n snippet: string,\n): Promise<void> {\n await injectMarkerBlock({\n snippet,\n markerOpen: PEER_MARKER_OPEN,\n markerClose: PEER_MARKER_CLOSE,\n position: \"bottom\",\n label: \"peer-mcp-awareness\",\n })\n}\n\n/**\n * Prepend a writing / communication style directive to the TOP of the\n * mirrored `<CLAUDE_CONFIG_DIR>/CLAUDE.md` so every spawned agent\n * reads it first. The directive itself is hard-coded to\n * `STYLE_DIRECTIVE` above; the parameter exists for tests / future\n * configurability. Idempotent across launches via the\n * style-marker fence (separate from the peer-awareness fence, so the\n * two blocks coexist without colliding).\n */\nexport async function prependStyleDirectiveToMirroredClaudeMd(\n directive: string = STYLE_DIRECTIVE,\n): Promise<void> {\n await injectMarkerBlock({\n snippet: directive,\n markerOpen: STYLE_MARKER_OPEN,\n markerClose: STYLE_MARKER_CLOSE,\n position: \"top\",\n label: \"style-directive\",\n })\n}\n\n/**\n * Prepend the operating-defaults directive (orchestrator posture + hybrid\n * excellence lens; `OPERATING_DEFAULTS_DIRECTIVE` above) to the TOP of the\n * mirrored CLAUDE.md so the main agent and descendant agents (Agent subagents,\n * agent-teams teammates) inherit the full statement. The main agent also gets\n * OPERATING_DEFAULTS_DIGEST at higher salience via `--append-system-prompt`.\n * Separate marker fence from the style / peer blocks so all coexist;\n * best-effort (warn-and-continue) like its siblings.\n */\nexport async function prependOperatingDefaultsToMirroredClaudeMd(\n directive: string = OPERATING_DEFAULTS_DIRECTIVE,\n): Promise<void> {\n await injectMarkerBlock({\n snippet: directive,\n markerOpen: OPERATING_MARKER_OPEN,\n markerClose: OPERATING_MARKER_CLOSE,\n position: \"top\",\n label: \"operating-defaults\",\n })\n}\n\n/**\n * Append the toolbelt awareness one-liner (which CLI tools are on PATH)\n * to the bottom of the mirrored CLAUDE.md so descendant agents (Agent\n * subagents, agent-teams teammates) and the main agent learn about the\n * provisioned tools via the mirrored CLAUDE.md. This line is not sent via\n * `--append-system-prompt`.\n * Separate marker fence from the peer-awareness / style blocks.\n */\nexport async function appendToolbeltAwarenessToMirroredClaudeMd(\n snippet: string,\n): Promise<void> {\n await injectMarkerBlock({\n snippet,\n markerOpen: TOOLBELT_MARKER_OPEN,\n markerClose: TOOLBELT_MARKER_CLOSE,\n position: \"bottom\",\n label: \"toolbelt-awareness\",\n })\n}\n\n/**\n * Prepend the artifact-panel review directive to the TOP of the mirrored\n * CLAUDE.md so plans/artifacts are reviewed in the ai-or-die panel by default.\n * Gated by the caller on AIORDIE_SESSION_ID (only useful inside a tab). Separate\n * marker fence; best-effort like the style/peer blocks.\n */\nexport async function prependArtifactPanelDirectiveToMirroredClaudeMd(\n peersKey = \"peers\",\n): Promise<void> {\n await injectMarkerBlock({\n snippet: ARTIFACT_PANEL_DIRECTIVE(peersKey),\n markerOpen: ARTIFACT_MARKER_OPEN,\n markerClose: ARTIFACT_MARKER_CLOSE,\n position: \"top\",\n label: \"artifact-panel-directive\",\n })\n}\n\n/**\n * Test-only exports — internal helpers exposed so unit tests can\n * exercise marker handling and line-ending logic without writing\n * files. NOT part of the public API.\n */\nexport const __testExports = {\n MARKER_OPEN,\n MARKER_CLOSE,\n PEER_MARKER_OPEN,\n PEER_MARKER_CLOSE,\n STYLE_MARKER_OPEN,\n STYLE_MARKER_CLOSE,\n STYLE_DIRECTIVE,\n ARTIFACT_MARKER_OPEN,\n ARTIFACT_MARKER_CLOSE,\n ARTIFACT_PANEL_DIRECTIVE,\n MAX_CLAUDE_MD_BYTES,\n ERROR_CODE,\n RENAME_RETRY_DELAYS_MS,\n detectLineEnding,\n stripLeadingBom,\n splitLines,\n joinLines,\n isUnderClaudeConfigMirrorRealpath,\n renameWithRetry,\n}\n","/**\n * Writer for injected skills: materializes a `SKILL.md` into the per-launch\n * `CLAUDE_CONFIG_DIR` mirror so the spawned Claude Code session discovers it as a\n * user-scope skill (`<CLAUDE_CONFIG_DIR>/skills/<name>/SKILL.md`, where the folder\n * name MUST equal the frontmatter `name` — the loader enforces this).\n *\n * Safety mirrors `claude-md-injection.ts`:\n * - mirror-only write guard (symlink-resolving) so we never touch the user's\n * real `~/.claude/skills/`;\n * - ATOMIC temp+rename so a concurrent child process can never read a\n * half-written `SKILL.md` (Claude Code watches the skills dir);\n * - warn-and-continue on every failure — an injected skill is an enhancement,\n * never a launch blocker.\n *\n * No per-skill stale sweep is needed: the whole per-launch mirror dir is GC'd by\n * `removeOwnClaudeConfigMirror` / `sweepStaleClaudeConfigMirrors`.\n */\n\nimport { randomBytes } from \"node:crypto\"\nimport fs from \"node:fs/promises\"\nimport path from \"node:path\"\n\nimport consola from \"consola\"\n\nimport { isUnderClaudeConfigMirrorRealpath, renameWithRetry } from \"../claude-md-injection\"\nimport { PATHS } from \"../paths\"\n\n/** Grep-able prefix on every warn path (mirrors the CLAUDE_MD_WRITE convention). */\nconst ERROR_CODE = \"INJECTED_SKILL_WRITE\"\n\n/**\n * Strict skill-name allowlist. Lowercase kebab so the folder name is a safe path\n * segment AND a valid Claude Code skill `name` (loader asserts folder == name).\n * All our injected skills (`gh-research`, `gh-orchestrate`, `gh-floor-keeper`,\n * `gh-first-mate`) pass.\n */\nconst VALID_SKILL_NAME = /^[a-z][a-z0-9-]*$/\n\nexport interface WriteInjectedSkillResult {\n written: boolean\n /** Absolute path of the written `SKILL.md` on success. */\n path?: string\n}\n\n/**\n * Write `md` to `<CLAUDE_CONFIG_DIR>/skills/<name>/SKILL.md`. `md` must already be\n * a complete `SKILL.md` (YAML frontmatter with `name: <name>` + `description`,\n * then the body). Idempotent across launches (overwrite); the per-launch mirror\n * dir is disposable.\n */\nexport async function writeInjectedSkill(\n name: string,\n md: string,\n): Promise<WriteInjectedSkillResult> {\n if (!VALID_SKILL_NAME.test(name)) {\n consola.warn(`${ERROR_CODE}: invalid skill name \"${name}\" (need lowercase kebab); skipping`)\n return { written: false }\n }\n\n const dir = path.join(PATHS.CLAUDE_CONFIG_DIR, \"skills\", name)\n const target = path.join(dir, \"SKILL.md\")\n\n // The mirror-only guard resolves the target's PARENT via realpath, so the\n // parent must exist first. Creating the dir before the guard is safe: mkdir\n // inside the mirror is the same privilege as the write we are about to do, and\n // the guard still rejects if the resolved parent escapes the mirror root.\n try {\n await fs.mkdir(dir, { recursive: true })\n } catch (err) {\n consola.warn(\n `${ERROR_CODE}: mkdir failed for ${dir}: ${err instanceof Error ? err.message : String(err)}`,\n )\n return { written: false }\n }\n\n if (!(await isUnderClaudeConfigMirrorRealpath(target))) {\n consola.warn(\n `${ERROR_CODE}: refusing to write outside the resolved mirror dir (target=${target}, mirror=${PATHS.CLAUDE_CONFIG_DIR})`,\n )\n return { written: false }\n }\n\n // Atomic temp + rename (wx so we never clobber a racer's temp). No copyFile\n // fallback (would follow a symlink/hardlink and escape the mirror boundary).\n const tempPath = `${target}.${process.pid}.${randomBytes(4).toString(\"hex\")}.tmp`\n try {\n await fs.writeFile(tempPath, md, { encoding: \"utf8\", flag: \"wx\" })\n } catch (err) {\n await fs.unlink(tempPath).catch(() => {})\n consola.warn(\n `${ERROR_CODE}: temp-file write failed for ${tempPath}: ${err instanceof Error ? err.message : String(err)}`,\n )\n return { written: false }\n }\n\n const ok = await renameWithRetry(tempPath, target, md)\n if (!ok) return { written: false }\n\n consola.debug(`${ERROR_CODE}: wrote ${target} (${md.length} bytes)`)\n return { written: true, path: target }\n}\n","/**\n * Injected-skill registry: the floor-raising / controller skills the `claude`\n * launcher materializes into the per-launch `CLAUDE_CONFIG_DIR` mirror so the\n * spawned Claude Code session discovers them (`/gh-research`,\n * `/gh-orchestrate`, `/gh-floor-keeper`, `/gh-first-mate`). See\n * `docs/floor-raising-agent-surface.md`.\n */\n\nimport { FIRST_MATE_CONDUCT_SKILL } from \"./first-mate-conduct-skill\"\nimport { FIRST_MATE_OPERATE_SKILL } from \"./first-mate-operate-skill\"\nimport { FIRST_MATE_SETUP_SKILL } from \"~/lib/injected-skills/first-mate-setup-skill\"\nimport { FIRST_MATE_SKILL } from \"./first-mate-skill\"\nimport { FLOOR_KEEPER_SKILL } from \"./floor-keeper-skill\"\nimport { ORCHESTRATE_SKILL } from \"./orchestrate-skill\"\nimport { RESEARCH_SKILL } from \"./research-skill\"\nimport { WORKER_SKILL } from \"./worker-skill\"\n\nexport { ARTIFACT_REVIEW_SKILL } from \"./artifact-review-skill\"\nexport { FIRST_MATE_CONDUCT_SKILL } from \"./first-mate-conduct-skill\"\nexport { FIRST_MATE_OPERATE_SKILL } from \"./first-mate-operate-skill\"\nexport { FIRST_MATE_SETUP_SKILL } from \"~/lib/injected-skills/first-mate-setup-skill\"\nexport { FIRST_MATE_SKILL } from \"./first-mate-skill\"\nexport { writeInjectedSkill, type WriteInjectedSkillResult } from \"./write\"\n\n/** A skill to materialize: `name` is BOTH the frontmatter `name` and the folder\n * name (the loader enforces folder == name); `md` is the full `SKILL.md`. */\nexport interface InjectedSkill {\n name: string\n md: string\n}\n\n/** All injected skills, in dependency order (research underpins the others). */\nexport const INJECTED_SKILLS: ReadonlyArray<InjectedSkill> = [\n RESEARCH_SKILL,\n ORCHESTRATE_SKILL,\n FLOOR_KEEPER_SKILL,\n WORKER_SKILL,\n FIRST_MATE_SKILL,\n FIRST_MATE_SETUP_SKILL,\n FIRST_MATE_OPERATE_SKILL,\n FIRST_MATE_CONDUCT_SKILL,\n]\n","import fs from \"node:fs/promises\"\n\n/**\n * Deterministic backstop for the injected \"no attribution\" style directive.\n *\n * github-router injects a CLAUDE.md style directive telling the agent not to\n * attribute work to Claude / AI / Anthropic. That directive is ADVISORY (prose\n * the model may or may not follow). Claude Code also exposes a HARNESS-ENFORCED\n * control that suppresses attribution at the source: the `attribution`\n * settings.json key (Claude Code v2.0.62+; string `commit` / `pr` sub-fields),\n * which supersedes the deprecated boolean `includeCoAuthoredBy`. Setting both\n * sub-fields to the empty string removes the \"Generated with Claude Code\"\n * commit footer and the \"Co-Authored-By: Claude\" byline from commits and PRs.\n * Because the harness reads and applies this itself, it holds even when the\n * model ignores the prose directive — a deterministic backstop, not a second\n * suggestion.\n *\n * PRESENCE-GUARDED. If the mirrored settings already carry `attribution` OR\n * `includeCoAuthoredBy`, the user expressed a deliberate preference in their\n * real config (which the one-way mirror snapshotted); we DO NOT override it.\n * Only a user who has expressed no preference receives github-router's\n * no-attribution default. This keeps faith with \"the user's explicit direction\n * always overrides\".\n *\n * The mirror is a per-launch snapshot of the user's real `~/.claude` config, so\n * this write never propagates back to the user's own settings.json. A\n * project-scope `<repo>/.claude/settings.json` still overrides the mirror\n * (global scope) at runtime, so the default remains overridable per-repo.\n *\n * Failure model matches the sibling settings writers: a transient read error\n * or a non-object settings.json throws (never clobber a file we don't\n * understand); the caller wraps this in warn-and-continue so a settings-write\n * hiccup never blocks launch.\n */\nexport async function injectAttributionSuppressionIntoSettingsFile(\n settingsPath: string,\n): Promise<{ written: boolean; reason?: \"user-set\" }> {\n let existing: Record<string, unknown> = {}\n let raw: string | undefined\n try {\n raw = await fs.readFile(settingsPath, \"utf8\")\n } catch (err) {\n // Never clobber on a transient read error; a missing file starts clean.\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err\n raw = undefined\n }\n if (raw !== undefined) {\n // A parse failure means a real file we don't understand: do NOT replace it.\n const parsed: unknown = JSON.parse(raw)\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n existing = parsed as Record<string, unknown>\n } else {\n throw new Error(\n `settings.json at ${settingsPath} is not a JSON object; refusing to overwrite`,\n )\n }\n }\n // Respect an existing explicit attribution preference (current OR deprecated\n // key). A user who set either one deliberately wins.\n if (\"attribution\" in existing || \"includeCoAuthoredBy\" in existing) {\n return { written: false, reason: \"user-set\" }\n }\n const merged = { ...existing, attribution: { commit: \"\", pr: \"\" } }\n const tmp = `${settingsPath}.${process.pid}.attr.tmp`\n await fs.writeFile(tmp, `${JSON.stringify(merged, null, 2)}\\n`, { mode: 0o600 })\n await fs.rename(tmp, settingsPath)\n return { written: true }\n}\n"],"mappings":"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"}