@humwick/runner 0.130.5 → 0.130.6

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 (211) hide show
  1. package/agent-bin/humwick +2 -2
  2. package/agent-bin/humwick-browser +4 -0
  3. package/hooks/fff-search-redirect/fff-search-redirect.cjs +1 -1
  4. package/hooks/web-tools-redirect/web-tools-redirect.cjs +2 -2
  5. package/package.json +7 -10
  6. package/plugins/browser/skills/playwright-cli/SKILL.md +8 -6
  7. package/plugins/claude/.claude-plugin/plugin.json +3 -3
  8. package/plugins/claude/claude-statusline-probe.cjs +26 -16
  9. package/plugins/claude/hooks/gate-run-guard.provisioned.mjs +47 -17
  10. package/plugins/claude/hooks/gate-run-guard.sh +3 -3
  11. package/plugins/claude/hooks/gate-run-guard.ts +5 -5
  12. package/plugins/claude/hooks/kill-guard.sh +4 -4
  13. package/plugins/claude/hooks/kill-guard.ts +1 -1
  14. package/plugins/claude/hooks/permission-request.sh +1 -1
  15. package/plugins/claude/hooks/post-compact.sh +1 -1
  16. package/plugins/claude/hooks/post-tool-use.sh +3 -3
  17. package/plugins/claude/hooks/pre-compact.sh +2 -2
  18. package/plugins/claude/hooks/read-only-bash-guard.sh +4 -4
  19. package/plugins/claude/hooks/relay-status.sh +32 -32
  20. package/plugins/claude/hooks/session-end.sh +2 -2
  21. package/plugins/claude/hooks/session-start.sh +3 -3
  22. package/plugins/claude/hooks/shell-trust.ts +1 -1
  23. package/plugins/claude/hooks/stop-failure.sh +2 -2
  24. package/plugins/claude/hooks/stop.sh +6 -6
  25. package/plugins/claude/hooks/subagent-skill-policy.cjs +8 -6
  26. package/plugins/claude/hooks/subagent-stop.sh +3 -3
  27. package/plugins/claude/hooks/user-prompt-submit.sh +1 -1
  28. package/plugins/claude/hooks/wait-loop-guard.ts +3 -3
  29. package/plugins/claude/monitors/monitors.json +2 -2
  30. package/plugins/claude/monitors/relay-monitor.provisioned.mjs +96 -62
  31. package/plugins/claude/monitors/relay-monitor.ts +5 -5
  32. package/plugins/claude/skills/label/SKILL.md +3 -3
  33. package/plugins/claude/skills/message/SKILL.md +5 -5
  34. package/plugins/claude/skills/react/SKILL.md +1 -1
  35. package/plugins/claude/skills/read-message/SKILL.md +4 -4
  36. package/plugins/claude/skills/reply/SKILL.md +5 -5
  37. package/plugins/claude/skills/send-claimable/SKILL.md +5 -5
  38. package/plugins/claude/skills/slice-first/SKILL.md +5 -3
  39. package/plugins/claude/skills/slice-first/references/plan-recipe.md +30 -29
  40. package/plugins/claude/skills/status/SKILL.md +1 -1
  41. package/plugins/claude/skills/tags/SKILL.md +5 -5
  42. package/plugins/claude/skills/task/SKILL.md +10 -10
  43. package/plugins/claude-output-style/.claude-plugin/plugin.json +1 -1
  44. package/plugins/claude-output-style/output-styles/{agent-relay.md → humwick.md} +1 -1
  45. package/plugins/codex/skills/guide/SKILL.md +1 -1
  46. package/plugins/codex/skills/label/SKILL.md +3 -3
  47. package/plugins/codex/skills/message/SKILL.md +5 -5
  48. package/plugins/codex/skills/react/SKILL.md +1 -1
  49. package/plugins/codex/skills/read-message/SKILL.md +4 -4
  50. package/plugins/codex/skills/reply/SKILL.md +5 -5
  51. package/plugins/codex/skills/send-claimable/SKILL.md +5 -5
  52. package/plugins/codex/skills/slice-first/SKILL.md +5 -3
  53. package/plugins/codex/skills/slice-first/references/plan-recipe.md +30 -29
  54. package/plugins/codex/skills/status/SKILL.md +1 -1
  55. package/plugins/codex/skills/tags/SKILL.md +5 -5
  56. package/plugins/codex/skills/task/SKILL.md +11 -10
  57. package/src/adapter.ts +95 -92
  58. package/src/adapters/claude-api.ts +8 -11
  59. package/src/adapters/claude-context-command.ts +1 -1
  60. package/src/adapters/claude-credentials.ts +7 -3
  61. package/src/adapters/claude-delivery-lanes.ts +2 -2
  62. package/src/adapters/claude-delivery.ts +16 -16
  63. package/src/adapters/claude-effort.ts +2 -2
  64. package/src/adapters/claude-exit.ts +2 -2
  65. package/src/adapters/claude-headless-mirror.ts +18 -2
  66. package/src/adapters/claude-headless-refusal.ts +3 -3
  67. package/src/adapters/claude-headless.ts +11 -10
  68. package/src/adapters/claude-launch-exit.ts +1 -1
  69. package/src/adapters/claude-monitor-delivery-plan.ts +36 -16
  70. package/src/adapters/claude-permission.ts +5 -5
  71. package/src/adapters/claude-prompt-gates.ts +9 -9
  72. package/src/adapters/claude-prompt-hook.ts +2 -2
  73. package/src/adapters/claude-session-capture.ts +6 -6
  74. package/src/adapters/claude-session-probe.ts +25 -25
  75. package/src/adapters/claude-shutdown.ts +11 -11
  76. package/src/adapters/claude-status-detectors.ts +31 -31
  77. package/src/adapters/claude-subagents.ts +7 -7
  78. package/src/adapters/claude-submit-confirmation.ts +6 -6
  79. package/src/adapters/claude-tmux.ts +43 -43
  80. package/src/adapters/claude-token-usage-capture.ts +5 -5
  81. package/src/adapters/claude-tool-policy.ts +7 -7
  82. package/src/adapters/claude-transcript.ts +24 -24
  83. package/src/adapters/claude.ts +100 -100
  84. package/src/adapters/codex-agent-message-capture.ts +26 -63
  85. package/src/adapters/codex-app-server.ts +1 -1
  86. package/src/adapters/codex-client.ts +9 -9
  87. package/src/adapters/codex-effective-config.ts +1 -1
  88. package/src/adapters/codex-launch-config.ts +5 -5
  89. package/src/adapters/codex-rollout-context.ts +2 -2
  90. package/src/adapters/codex-skill-discovery.ts +1 -1
  91. package/src/adapters/codex-token-usage-capture.ts +16 -16
  92. package/src/adapters/codex-tool-output.ts +4 -4
  93. package/src/adapters/codex-version.ts +3 -3
  94. package/src/adapters/codex.ts +64 -64
  95. package/src/adapters/opencode-api.ts +1 -1
  96. package/src/adapters/opencode-context.ts +20 -22
  97. package/src/adapters/opencode-model-registry.ts +7 -7
  98. package/src/adapters/opencode-provider.ts +8 -8
  99. package/src/adapters/opencode-provisioning.ts +30 -0
  100. package/src/adapters/opencode-server-retry.ts +1 -1
  101. package/src/adapters/opencode-soft-steer.ts +5 -5
  102. package/src/adapters/opencode-spawn.ts +18 -14
  103. package/src/adapters/opencode-token-usage-capture.ts +12 -12
  104. package/src/adapters/opencode-tool-events.ts +15 -15
  105. package/src/adapters/opencode.ts +232 -232
  106. package/src/adapters/project-shell.ts +11 -11
  107. package/src/adapters/service-access.ts +6 -6
  108. package/src/adapters/tmux-offload.ts +9 -9
  109. package/src/adapters/tool-summary.ts +5 -5
  110. package/src/agent-redact.ts +1 -1
  111. package/src/agent-runner/commands/dispatch.ts +10 -10
  112. package/src/agent-runner/commands/lifecycle.ts +2 -2
  113. package/src/agent-runner/commands/prompt.ts +19 -19
  114. package/src/agent-runner/credentials.ts +5 -5
  115. package/src/agent-runner/inbox.ts +1 -1
  116. package/src/agent-runner/lifecycle-milestones.ts +3 -3
  117. package/src/agent-runner/lifecycle-phase.ts +2 -2
  118. package/src/agent-runner/liveness-exchange.ts +4 -10
  119. package/src/agent-runner/registration.ts +8 -8
  120. package/src/agent-runner/runner-context.ts +9 -14
  121. package/src/agent-runner/session-mirror.ts +12 -12
  122. package/src/agent-runner/task-claims.ts +2 -2
  123. package/src/agent-runner/token-usage-coverage.ts +1 -1
  124. package/src/agent-runner/turn-report.ts +12 -12
  125. package/src/api-budget-accounting.ts +3 -3
  126. package/src/area-memory.ts +6 -6
  127. package/src/artifact-path-materialize.ts +1 -1
  128. package/src/async-guard.ts +5 -5
  129. package/src/attachment-cache.ts +17 -22
  130. package/src/background-script-reconcile.ts +6 -6
  131. package/src/bounded-log.ts +1 -1
  132. package/src/busy-reconciler.ts +22 -22
  133. package/src/claim-tracker.ts +3 -3
  134. package/src/claude-settings.ts +8 -8
  135. package/src/claude-system-prompt.ts +1 -1
  136. package/src/claude-workspace-trust.ts +1 -1
  137. package/src/config.ts +62 -61
  138. package/src/context-boundary.ts +5 -5
  139. package/src/context-command.ts +3 -3
  140. package/src/control-server.ts +32 -32
  141. package/src/delivery-result.ts +2 -2
  142. package/src/effort-command.ts +2 -2
  143. package/src/empty-turn.ts +22 -14
  144. package/src/free-port.ts +1 -1
  145. package/src/gate-run-config.ts +3 -3
  146. package/src/host-asset-plan.ts +24 -17
  147. package/src/host-claude-config-worker.ts +2 -2
  148. package/src/host-sources.ts +2 -2
  149. package/src/index.ts +16 -16
  150. package/src/launch-assembly.ts +94 -96
  151. package/src/liveness.ts +15 -15
  152. package/src/logger.ts +3 -3
  153. package/src/mcp-outbox.ts +3 -3
  154. package/src/mcp-preflight.ts +2 -2
  155. package/src/mcp-source-selection.ts +2 -2
  156. package/src/mcp-tool-deferral.ts +1 -1
  157. package/src/mcp-vault-env.ts +2 -2
  158. package/src/message-body-config/config.ts +4 -4
  159. package/src/mid-turn-delivery.ts +2 -2
  160. package/src/native-memory-lever.ts +8 -8
  161. package/src/outbox.ts +15 -15
  162. package/src/pending-permission-store.ts +1 -1
  163. package/src/profile-home.ts +19 -19
  164. package/src/profile-projection.ts +26 -24
  165. package/src/project-instructions.ts +5 -5
  166. package/src/provider-auth-warning.ts +17 -0
  167. package/src/provider-double.ts +1 -1
  168. package/src/provider-hold.ts +3 -3
  169. package/src/provider-home-marker.ts +1 -1
  170. package/src/provider-home-tombstone.ts +1 -1
  171. package/src/provider-input-queue.ts +2 -2
  172. package/src/provider-integration.ts +15 -13
  173. package/src/provider-setup.ts +15 -3
  174. package/src/providers.ts +1 -1
  175. package/src/provisioning.ts +37 -40
  176. package/src/question-decision.ts +2 -2
  177. package/src/quota.ts +0 -6
  178. package/src/rate-limit.ts +24 -13
  179. package/src/refused-prompt-store.ts +2 -2
  180. package/src/relay-injection-events.ts +2 -2
  181. package/src/relay-instructions.ts +5 -5
  182. package/src/relay-mcp-proxy.long-turn-e2e.ts +13 -13
  183. package/src/relay-mcp-proxy.ts +57 -58
  184. package/src/relay-mcp.ts +55 -69
  185. package/src/reply-obligation-cache.ts +9 -9
  186. package/src/response-capture-report.ts +9 -9
  187. package/src/response-routing.ts +1 -1
  188. package/src/runner-core.ts +209 -222
  189. package/src/runner-exit.ts +1 -1
  190. package/src/runner-helpers.ts +10 -10
  191. package/src/runner-insights.ts +4 -2
  192. package/src/runner-mcp-proxy.ts +3 -3
  193. package/src/runner-spawn-config.ts +3 -3
  194. package/src/runtime-token-file.ts +1 -1
  195. package/src/runtime-token-remint.ts +1 -1
  196. package/src/service-access.ts +2 -2
  197. package/src/session-destroy.ts +1 -1
  198. package/src/session-insights.ts +1 -1
  199. package/src/session-scratch.ts +24 -37
  200. package/src/spawn-input.ts +6 -6
  201. package/src/startup-config-fetch.ts +4 -4
  202. package/src/subreaper.ts +3 -5
  203. package/src/test-run-dedup.ts +13 -13
  204. package/src/transcript-context.ts +2 -2
  205. package/src/transport-errors.ts +1 -1
  206. package/src/turn-opener.ts +1 -1
  207. package/src/turn-reconcile-event.ts +2 -2
  208. package/src/vault-proxy-hop.ts +2 -2
  209. package/src/web-tools.ts +2 -2
  210. package/agent-bin/agent-relay-browser +0 -10
  211. package/src/adapters/provider-quota-harvest.ts +0 -76
@@ -1,4 +1,5 @@
1
1
  import { bundledIntegrationAssets, bundledIntegrationHome, suppressOwnedClaudePlugins, selectClaudePluginDirs } from "./provider-integration";
2
+ import { resolveOpenCodeAssets } from "./adapters/opencode-provisioning";
2
3
  import { relayEnv, writeChildEnv } from "@humwick/sdk/env";
3
4
  import { codexRetiredMcpConfigArgs } from "./adapters/codex-effective-config";
4
5
  import { activeSharedMcpServers } from "@humwick/sdk";
@@ -53,7 +54,7 @@ import {
53
54
  codexProvisionedMcpArgs,
54
55
  codexProvisionedMcpTimeoutArgs,
55
56
  openCodeMcpConfigPayload,
56
- relayMcpCodexConfigArgs, runnerMcpGeneration,
57
+ relayMcpCodexConfigArgs,
57
58
  sharedMcpMetaOnlyServer,
58
59
  writeSharedMcpMetaOnlyConfig,
59
60
  SHARED_MCP_METAONLY_CONFIG_FILENAME,
@@ -73,7 +74,7 @@ import {
73
74
  type NativeMemoryLever,
74
75
  } from "./native-memory-lever";
75
76
 
76
- // #1565 P5.7 — relay's inline `--settings` actually reaches this launch. Same gate
77
+ // P5.7 — relay's inline `--settings` actually reaches this launch. Same gate
77
78
  // `claudeSettingsArgs` applies below, passed to the lever so its applied/suppressed report cannot
78
79
  // claim a settings key the merge then drops.
79
80
  const callerSettingsMergeable = (argLists: string[][], cwd?: string): boolean => {
@@ -81,7 +82,7 @@ const callerSettingsMergeable = (argLists: string[][], cwd?: string): boolean =>
81
82
  return !caller || Boolean(caller.settings);
82
83
  };
83
84
 
84
- // #557 — THE single launch-assembly contract. Given a resolved AgentProfile (+ its
85
+ // THE single launch-assembly contract. Given a resolved AgentProfile (+ its
85
86
  // spawn-time ResolvedProvisioning), `assembleLaunch` produces ONE provider-neutral
86
87
  // description of the launch: the relay-provisioned skills/plugins/MCP, the bundled relay
87
88
  // surface, the instruction-source disposition, and `base:"vanilla"` as the zero-host
@@ -106,7 +107,7 @@ export interface AssembledInstructions {
106
107
  /** Repo CLAUDE.md/AGENTS.md cascade: "allow" left available, "suppressed" by the
107
108
  * vanilla launch mechanism, "reinjected" when the native project scope is dropped (to gate
108
109
  * ambient hooks) but P.instructions re-injects the repo docs through the controlled
109
- * append-system-prompt channel (#2086), "unsupported" requested-but-not-enforced. */
110
+ * append-system-prompt channel, "unsupported" requested-but-not-enforced. */
110
111
  repo: AssembledInstructionDisposition;
111
112
  /** Host/global provider instructions: "allow", "isolated" (dropped by the isolated home), or "unsupported". */
112
113
  global: AssembledInstructionDisposition;
@@ -114,47 +115,46 @@ export interface AssembledInstructions {
114
115
  * context) is configured for this launch. `launchContextPending` distinguishes providers that
115
116
  * can only transport it with their first turn from providers that emit it at process launch. */
116
117
  systemPromptAppend: boolean;
117
- // ── #559 SEAM ──────────────────────────────────────────────────────────────────
118
- // Scoped {profile|user} memory does not exist yet (#559 generalizes Projects' anchor
118
+ // ── SEAM ──────────────────────────────────────────────────────────────────
119
+ // Scoped {profile|user} memory does not exist yet (generalizes Projects' anchor
119
120
  // to project|profile|user). When it lands, the assembled instruction world becomes
120
121
  // "instructions + provisioned assets + scoped knowledge": the relay-side composer
121
122
  // (composeSpawnInstructions) gains a profile/user-scoped preamble beside the existing
122
123
  // project preamble, and THIS field reports which scopes contributed. Until then it is
123
- // always "none" — a thin add for #559, not a refactor.
124
+ // always "none" — a thin add, not a refactor.
124
125
  scopedKnowledge: "none";
125
126
  }
126
127
 
127
128
  export interface AssembledMcp {
128
- generation?: import("@humwick/sdk").ToolGeneration;
129
129
  /** The identity-bearing relay HTTP MCP endpoint is injected. */
130
130
  relayEndpoint: boolean;
131
- /** Only the assembled servers may load (Claude --strict-mcp-config). #662: true for ALL
131
+ /** Only the assembled servers may load (Claude --strict-mcp-config).: true for ALL
132
132
  * managed Claude launches so the project `.mcp.json` enable-modal can't wedge a headless
133
133
  * agent; relay's endpoint + provisioned servers (via --mcp-config) are preserved. Always
134
134
  * false for Codex (no equivalent discovery modal). */
135
135
  strict: boolean;
136
136
  /** Relay-provisioned server names (excludes the relay endpoint itself). */
137
137
  servers: string[];
138
- /** #667 — project `.mcp.json` server names projected from the spawn cwd's committed
138
+ /** project `.mcp.json` server names projected from the spawn cwd's committed
139
139
  * `.mcp.json` (via `--mcp-config`, so they survive strict). Sourced from the project,
140
140
  * not ambient host MCP. Empty unless the profile/spawn opted into `projectMcp`, and a
141
141
  * name already declared by relay-provisioned `servers` wins (not double-listed here). */
142
142
  projectServers: string[];
143
- /** #662/#2075 — host USER-scope MCP server names (`~/.claude.json` `mcpServers`) re-injected
143
+ /** host USER-scope MCP server names (`~/.claude.json` `mcpServers`) re-injected
144
144
  * into `--mcp-config` for an `mcp.mode:"host"` profile, so `--strict-mcp-config` keeps
145
145
  * the ambient host MCP (callmux/qmd/gh) instead of dropping it. Isolated homes receive the
146
146
  * explicit host cell too; non-host modes stay empty. Codex reports its host config.toml
147
147
  * servers through the same field. */
148
148
  hostServers: string[];
149
- /** #672 — when the profile/spawn opted into `sharedMcp`, the agent's NON-IDENTITY MCP
149
+ /** when the profile/spawn opted into `sharedMcp`, the agent's NON-IDENTITY MCP
150
150
  * (tokenlean, github) is routed through one orchestrator-owned shared `callmux` listener via
151
151
  * a per-agent `callmux bridge --cwd "$WORKTREE"` (session-cwd isolation), injected through
152
152
  * the same `--mcp-config` / `-c` channel so it survives strict. `url` is the listener the
153
153
  * bridge connects to. Undefined when projection is OFF (the default). The bridge is opaque
154
154
  * at assembly time — its server SET is owned by the listener config, not enumerated here.
155
- * The identity-bearing relay endpoint is never on the shared listener (#215). #1450 —
155
+ * The identity-bearing relay endpoint is never on the shared listener. —
156
156
  * `relayFronted` marks a metaOnly callmux that ALSO fronts the relay endpoint on-demand as a
157
- * second downstream (via the runner proxy, so identity/#215 hold); the relay stays per-agent. */
157
+ * second downstream (via the runner proxy, so identity hold); the relay stays per-agent. */
158
158
  sharedListener?: { url: string; metaOnly?: boolean; relayFronted?: boolean };
159
159
  }
160
160
 
@@ -168,10 +168,10 @@ export interface AssembledLaunch {
168
168
  vanilla: boolean;
169
169
  /** Isolated provider config home (CLAUDE_CONFIG_DIR / CODEX_HOME), or undefined for host base. */
170
170
  configHome?: string;
171
- /** #1963 N3 — the effective Claude `--setting-sources` this launch emits, or undefined when the
171
+ /** N3 — the effective Claude `--setting-sources` this launch emits, or undefined when the
172
172
  * flag is ABSENT. Absent means the provider default loads EVERY scope: empirically
173
173
  * `user,project,local` on Claude 2.1.x (measured with a controlled probe — the CLI documents the
174
- * valid sources but not the absent-flag default; see #1963 R1.0). An explicit array names the ONLY
174
+ * valid sources but not the absent-flag default; R1.0). An explicit array names the ONLY
175
175
  * scopes that load, so the ambient project (`.claude/settings.json`, repo CLAUDE.md/AGENTS.md) and
176
176
  * local (`.claude/settings.local.json`) scopes are DROPPED. Always undefined for Codex, which has
177
177
  * no `--setting-sources` surface (it suppresses the project doc via `project_doc_max_bytes=0`). */
@@ -185,14 +185,14 @@ export interface AssembledLaunch {
185
185
  statusLine: boolean;
186
186
  /** Relay-provisioned skills materialized for this launch. */
187
187
  skills: AssembledAsset[];
188
- /** Project `.claude/skills` materialized for this Claude launch (#668). */
188
+ /** Project `.claude/skills` materialized for this Claude launch. */
189
189
  projectSkills: AssembledAsset[];
190
190
  /** Host/global Claude skills explicitly inherited without enabling host MCP. */
191
191
  hostSkills: AssembledAsset[];
192
- /** Project `.claude/settings.json` stays on Claude's native project-settings path (#669). */
192
+ /** Project `.claude/settings.json` stays on Claude's native project-settings path. */
193
193
  projectSettings: { applied: boolean; keys: string[]; ignoredKeys: string[]; file?: string };
194
194
  /** Relay-provisioned hooks materialized for this launch. Empty when hooks were resolved
195
- * but could not be delivered — see `hooksSuppressed` (the anti-lie invariant, #1096). */
195
+ * but could not be delivered — see `hooksSuppressed`. */
196
196
  hooks: AssembledAsset[];
197
197
  /** Host hooks explicitly re-injected into an isolated Claude settings.json. */
198
198
  hostHooks: boolean;
@@ -202,19 +202,19 @@ export interface AssembledLaunch {
202
202
  projectHooks: AssembledAsset[];
203
203
  /** Project hooks requested by the source matrix but denied by the server trust gate. */
204
204
  projectHooksSuppressed?: { reason: string };
205
- /** #1096 review — set when this launch RESOLVED provisioned hooks (incl. a baseline safety
205
+ /** review — set when this launch RESOLVED provisioned hooks (incl. a baseline safety
206
206
  * guard) that could NOT be delivered: caller `--settings` was unmergeable (Claude), a
207
207
  * host-base Codex agent has no managed CODEX_HOME, or the installed Codex is too old to
208
208
  * consume hooks.json. Drives a LOUD projection warning so a baseline guard is never
209
209
  * SILENTLY absent while the report says "applied". */
210
210
  hooksSuppressed?: { reason: string; names: string[] };
211
- /** #1565 P5.7 — the provider-NATIVE-memory lever this launch carries. `policy:"default"` means
211
+ /** P5.7 — the provider-NATIVE-memory lever this launch carries. `policy:"default"` means
212
212
  * the profile declared nothing: no env/arg/settings key was emitted and the launch is
213
213
  * byte-identical to a pre-P5.7 one. Any other policy renders EXPLICITLY in both directions.
214
214
  * `suppressed` names a lever that was resolved but could not be delivered on this base — the
215
- * `hooksSuppressed` anti-lie precedent (#1096), so a lever is never silently absent. */
215
+ * `hooksSuppressed` anti-lie precedent, so a lever is never silently absent. */
216
216
  nativeMemory: NativeMemoryLever;
217
- /** #1096 review — Claude only: true when the caller's own `--settings` was folded into the
217
+ /** review — Claude only: true when the caller's own `--settings` was folded into the
218
218
  * relay-emitted `--settings` (relay hooks/statusLine merged in). The adapter
219
219
  * must then STRIP the caller's `--settings` from the provider args so exactly one reaches the
220
220
  * launch. False when relay emitted its own settings standalone or added none. */
@@ -223,11 +223,11 @@ export interface AssembledLaunch {
223
223
  plugins: AssembledAsset[];
224
224
  /** Host/global provider plugin dirs explicitly inherited without enabling host MCP. */
225
225
  hostPluginDirs: string[];
226
- /** #3387 — native host plugins (Claude installed-plugin registry ids) this launch's home carries. */
226
+ /** native host plugins (Claude installed-plugin registry ids) this launch's home carries. */
227
227
  hostPlugins: string[];
228
- /** #3387 — per host asset class: applied, selected-empty, disabled or unsupported. */
228
+ /** per host asset class: applied, selected-empty, disabled or unsupported. */
229
229
  hostSources: HostSourceReport;
230
- /** #3387 — the central provider defaultArgs this launch carries (Settings/defaults class). */
230
+ /** the central provider defaultArgs this launch carries (Settings/defaults class). */
231
231
  hostDefaultArgs: string[];
232
232
  mcp: AssembledMcp;
233
233
  /** Lower-precedence source assets intentionally omitted from the emitted launch. */
@@ -237,12 +237,12 @@ export interface AssembledLaunch {
237
237
  args: string[];
238
238
  /** Provisioning-derived env additions (the isolated config-home var). */
239
239
  env: Record<string, string>;
240
- /** #3025 — whether agent-redact's post-tool hooks reached this launch, and how. */
240
+ /** whether agent-redact's post-tool hooks reached this launch, and how. */
241
241
  redaction: AgentRedactState;
242
242
  }
243
243
 
244
244
  // ── Bundled relay assets (relocated from the adapters so the assembler — not each
245
- // adapter — owns launch-arg construction; #557). Adapters re-export for test parity. ──
245
+ // adapter — owns launch-arg construction). Adapters re-export for test parity. ──
246
246
 
247
247
  const CODEX_BUNDLED_SKILLS_DIR = resolve(import.meta.dir, "../plugins/codex/skills");
248
248
 
@@ -259,7 +259,7 @@ function codexSkillSources(config: RunnerSpawnConfig) {
259
259
  const home = providerHomePathFor("codex", config);
260
260
  const provisioned = home ? resolveCodexProvisionedSkills(home, config) : [];
261
261
  const bundled = !config.agentProfile && profileAllowsRelayFeature(config, "skills") ? bundledIntegrationAssets(config).map(asset => asset.dir) : [];
262
- // #3387 — the managed CODEX_HOME hides the host's own skills; Host Skills on names them as roots,
262
+ // the managed CODEX_HOME hides the host's own skills; Host Skills on names them as roots,
263
263
  // off disables the ambient ones Codex would still discover from HOME.
264
264
  const host = home ? codexHostPlan(config, providerSourceHome("codex")) : undefined;
265
265
  const hostRoots = host?.skillRoots ?? [];
@@ -271,7 +271,7 @@ export function codexSkillRoots(config: RunnerSpawnConfig): string[] {
271
271
  return codexSkillSources(config).roots;
272
272
  }
273
273
 
274
- // #552 vanilla base (Codex): suppress the AGENTS.md project-doc cascade. project_doc_max_bytes
274
+ // vanilla base (Codex): suppress the AGENTS.md project-doc cascade. project_doc_max_bytes
275
275
  // (default 32768) caps bytes Codex reads from AGENTS.md walking root→cwd; 0 stops before adding
276
276
  // any, so no repo (or fresh-CODEX_HOME global) project doc loads. The isolated CODEX_HOME already
277
277
  // drops host config.toml MCP/hooks; this closes the cwd-resident repo instruction channel.
@@ -279,14 +279,14 @@ export function codexProjectDocSuppressionArgs(config: Pick<RunnerSpawnConfig, "
279
279
  return profileIsVanillaBase(config) ? ["-c", "project_doc_max_bytes=0"] : [];
280
280
  }
281
281
 
282
- // #1096 — the settings.json relay WRITES into an isolated managed Claude home so the provisioned
282
+ // the settings.json relay WRITES into an isolated managed Claude home so the provisioned
283
283
  // hooks (baseline guard included) land in the DOCUMENTED hook source Claude honors
284
284
  // ($CLAUDE_CONFIG_DIR/settings.json — loaded under `--setting-sources "user"` and the default),
285
285
  // rather than riding ONLY the inline `--settings` CLI flag. Claude does not document `--settings`
286
286
  // as a hook source, and — unlike a file written straight to disk — that flag's JSON must survive
287
287
  // shell/tmux launcher transit and passes Claude's "silently ignore settings that fail validation"
288
288
  // gate; a written settings.json bypasses both, so the baseline guard can't be silently absent
289
- // (the #1096 inert-at-runtime symptom). Returns null when:
289
+ // Returns null when:
290
290
  // • there is NO isolated managed home (host base reuses the real ~/.claude — relay must not
291
291
  // clobber it; that path keeps the inline --settings delivery), or
292
292
  // • a caller --settings is present (the merge/suppression path owns hook delivery inline; see
@@ -305,7 +305,7 @@ export function claudeManagedHookSettings(config: RunnerSpawnConfig, configHome:
305
305
 
306
306
  // ── Instruction disposition (the vanilla floor's effect on the host instruction cascade) ──
307
307
 
308
- // #1963 N1/N3 — the disposition follows the launch FACT, not the profile's declared policy alone.
308
+ // N1/N3 — the disposition follows the launch FACT, not the profile's declared policy alone.
309
309
  // `projectScopeDropped` is true whenever the project setting-source is not loaded (Claude
310
310
  // `--setting-sources user`, emitted for a vanilla base OR a projectConfigProjection launch; Codex
311
311
  // `project_doc_max_bytes=0` for a vanilla base). When it is dropped, the repo CLAUDE.md/AGENTS.md
@@ -316,7 +316,7 @@ export function claudeManagedHookSettings(config: RunnerSpawnConfig, configHome:
316
316
  // minimal/isolated base OR a base:"host"+projectConfigProjection agent reports `isolated`, not the
317
317
  // old `allow` that lied for the isolated prod reviewer.
318
318
  function repoInstructionDisposition(profile: AgentProfile, projectScopeDropped: boolean, reinjected: boolean): AssembledInstructionDisposition {
319
- // #2086 — the drop is not silent when P.instructions re-injects the repo docs through the
319
+ // the drop is not silent when P.instructions re-injects the repo docs through the
320
320
  // controlled channel: the cascade is honored, just via append-system-prompt instead of the
321
321
  // native project scope. Report that FACT so the anti-lie projection never says "suppressed"
322
322
  // for a launch that actually carries the repo instructions.
@@ -328,7 +328,7 @@ function repoInstructionDisposition(profile: AgentProfile, projectScopeDropped:
328
328
  }
329
329
 
330
330
  function globalInstructionDisposition(profile: AgentProfile, isolatedHome: boolean): AssembledInstructionDisposition {
331
- // #1963 N1 review (P1): key on whether host globals are ACTUALLY linked, not on is-isolated-home.
331
+ // N1 review (P1): key on whether host globals are ACTUALLY linked, not on is-isolated-home.
332
332
  // `linkHostGlobalInstructionFiles` (profile-home.ts) symlinks the host global CLAUDE.md into the
333
333
  // managed home whenever `globalInstructions:"allow"` — even for an isolated base — so "allow" means
334
334
  // globals ARE present and reporting "isolated" there would be a false report. Only an `ignore`
@@ -392,7 +392,6 @@ export function openCodeMcpConfigForLaunch(config: RunnerSpawnConfig): Record<st
392
392
  const { declaredMcp, relayEndpoint } = resolveOpenCodeDeclaredMcp(config);
393
393
  return openCodeMcpConfigPayload({
394
394
  relayUrl: config.relayUrl,
395
- generation: runnerMcpGeneration(config.env),
396
395
  ...(config.relayMcpEndpoint ? { endpoint: config.relayMcpEndpoint } : {}),
397
396
  includeRelay: relayEndpoint,
398
397
  servers: declaredMcp,
@@ -400,16 +399,16 @@ export function openCodeMcpConfigForLaunch(config: RunnerSpawnConfig): Record<st
400
399
  }
401
400
 
402
401
  interface CodexMcpResolution extends McpSourceSelection {
403
- /** #1575 — set when the shared-listener route is served through a per-agent metaOnly callmux
402
+ /** set when the shared-listener route is served through a per-agent metaOnly callmux
404
403
  * (Codex worker) rather than the plain flat bridge. Carries the exact config path/url/cwd so
405
- * materializeCodexAssets writes the SAME file assembleCodex's descriptor points at. #1450 —
404
+ * materializeCodexAssets writes the SAME file assembleCodex's descriptor points at. —
406
405
  * `relay` adds the identity-bearing relay endpoint as a SECOND downstream (via the runner proxy)
407
406
  * when the proxy is active, so the on-demand relay set loads through callmux_call. */
408
407
  metaOnlyCallmux?: { configPath: string; url: string; cwd: string; relay?: MetaOnlyRelayDownstream };
409
408
  }
410
409
 
411
- // #1575 — a Codex worker swaps the flat shared-listener bridge for a per-agent metaOnly callmux so
412
- // the ~40 downstream schemas load on demand. Gated exactly like phase C's relay allowlist (#1570):
410
+ // a Codex worker swaps the flat shared-listener bridge for a per-agent metaOnly callmux so
411
+ // the ~40 downstream schemas load on demand. Gated exactly like phase C's relay allowlist:
413
412
  // an explicitly worker-classified profile AND a provider whose manifest eager-loads every tool
414
413
  // schema (no client-native deferral). Data-driven from the manifest, never a provider-identity
415
414
  // branch — Claude (client-defers) never takes this path, coordinators/reviewers keep the flat
@@ -417,7 +416,7 @@ interface CodexMcpResolution extends McpSourceSelection {
417
416
  // the host ~/.codex); worker profiles are isolated, so this holds.
418
417
  function codexMetaOnlyCallmuxConfigPath(config: RunnerSpawnConfig): string | undefined {
419
418
  if (!isCodexLeanWorkerProfile(config.agentProfile?.name)) return undefined;
420
- // #3024 — callmux_call reaches every listener tool and callmux has no per-downstream denylist, so a
419
+ // callmux_call reaches every listener tool and callmux has no per-downstream denylist, so a
421
420
  // profile with a web tool off keeps the flat bridge, where Codex's disabled_tools hides it.
422
421
  if (disabledSharedWebTools(config).length) return undefined;
423
422
  if (!runnerManagedToolDeferralRoute("codex")) return undefined;
@@ -432,14 +431,14 @@ function resolveCodexDeclaredMcp(config: RunnerSpawnConfig): CodexMcpResolution
432
431
  const selected = resolveMcpSources(config, hostMcpInjected ? hostCodexMcpServers() : {});
433
432
  const { sharedListenerUrl, relayEndpoint } = selected;
434
433
  const metaOnlyConfigPath = sharedListenerUrl ? codexMetaOnlyCallmuxConfigPath(config) : undefined;
435
- // #1450 — front the relay endpoint on-demand through the SAME metaOnly callmux, but ONLY when the
434
+ // front the relay endpoint on-demand through the SAME metaOnly callmux, but ONLY when the
436
435
  // runner proxy is active (config.relayMcpEndpoint = the proxy URL, config.mcpProxySecret = its
437
436
  // secret) AND the profile has the relay endpoint on. Routing through the proxy keeps the live
438
- // token off disk (#215). This gate matches runner-core's proxy on-demand-hiding gate exactly, so
437
+ // token off disk. This gate matches runner-core's proxy on-demand-hiding gate exactly, so
439
438
  // the direct client's on-demand tools are hidden ONLY when this front simultaneously exists.
440
439
  const metaOnlyRelay: MetaOnlyRelayDownstream | undefined =
441
440
  metaOnlyConfigPath && relayEndpoint && config.relayMcpEndpoint && config.mcpProxySecret
442
- ? { endpoint: config.relayMcpEndpoint, authSecret: config.mcpProxySecret, generation: runnerMcpGeneration(config.env) }
441
+ ? { endpoint: config.relayMcpEndpoint, authSecret: config.mcpProxySecret }
443
442
  : undefined;
444
443
  const metaOnlyCallmux = sharedListenerUrl && metaOnlyConfigPath
445
444
  ? { configPath: metaOnlyConfigPath, url: sharedListenerUrl, cwd: config.cwd, ...(metaOnlyRelay ? { relay: metaOnlyRelay } : {}) }
@@ -457,7 +456,7 @@ function resolveCodexDeclaredMcp(config: RunnerSpawnConfig): CodexMcpResolution
457
456
 
458
457
  // ── Per-provider arg assembly ──────────────────────────────────────────────────────
459
458
 
460
- // #2513 — `provider` parameterizes the claude family: claude-b reuses this assembler whole,
459
+ // `provider` parameterizes the claude family: claude-b reuses this assembler whole,
461
460
  // and every home/env derivation (providerHomePathFor, configHomeEnv) keys off the id so its
462
461
  // launch resolves the claude-b manifest's configDir instead of claude's.
463
462
  function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfig, hostDefaultArgs: string[], provider: string = "claude"): AssembledLaunch {
@@ -467,7 +466,7 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
467
466
  const vanilla = profileIsVanillaBase(config);
468
467
  const relayPlugin = profileAllowsRelayFeature(config, "plugins");
469
468
  const relaySkills = profileAllowsRelayFeature(config, "skills");
470
- // #3181 — the status line is how Relay tracks a Claude agent's context, so every profile gets it.
469
+ // the status line is how Relay tracks a Claude agent's context, so every profile gets it.
471
470
  const statusLine = true;
472
471
 
473
472
  const skillSources = configHome ? resolveClaudeSkillSources(configHome, config, provider) : { relay: [], project: [], host: [], shadows: [] };
@@ -484,7 +483,7 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
484
483
  ? { reason: config.agentProfile.projectGates?.hooks?.detail ?? "partial — not acknowledged" }
485
484
  : undefined;
486
485
  const provisionedHookSet = renderProvisionedHookSet([...projectHooks, ...provisionedHooks]);
487
- // #1096 — for an isolated managed home with no caller --settings, the provisioned hooks are
486
+ // for an isolated managed home with no caller --settings, the provisioned hooks are
488
487
  // delivered through the managed settings.json (the documented, transit-safe hook source), so
489
488
  // keep them OUT of the inline --settings to avoid double-registering the same guard. Host-base
490
489
  // and caller-`--settings` launches keep inline delivery (see claudeManagedHookSettings).
@@ -493,21 +492,21 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
493
492
  const redact = resolveAgentRedact();
494
493
  const inlineHookSet = managedHookSettings ? {} : mergeHookSets(mergeHookSets(provisionedHookSet, isAgentRedactInstall(redact) ? redact.claudeHooks : {}), claudeSubagentHooks(config));
495
494
  const redaction = isAgentRedactInstall(redact) ? agentRedactOn(managedHookSettings ? "settings.json PostToolUse hooks" : "inline --settings PostToolUse hooks") : redact;
496
- // #1565 P5.7 — the native-memory lever. Resolved BEFORE the settings args so its keys can ride
495
+ // P5.7 — the native-memory lever. Resolved BEFORE the settings args so its keys can ride
497
496
  // relay's inline `--settings` (the only settings channel a host-base launch has); the env var
498
497
  // below is the one that must always be present, and outranks both settings channels.
499
498
  const nativeMemory = resolveClaudeNativeMemoryLever(config, configHome, hostDefaultArgs, (lists) => callerSettingsMergeable(lists, config.cwd), provider);
500
499
  const settings = claudeSettingsArgs(
501
- { ...projectSettings.settings, ...(relayPlugin ? { enabledPlugins: suppressOwnedClaudePlugins(undefined) } : {}), ...claudeGuardedRelaySettings(config.approvalMode, runnerMcpGeneration(config.env)), ...claudeHostInstructionExcludeSettings(config), ...claudeBypassPermissionSettings(config.approvalMode), ...claudeHarnessTrim(config).settings, ...claudeSubagentSettings(config) },
500
+ { ...projectSettings.settings, ...(relayPlugin ? { enabledPlugins: suppressOwnedClaudePlugins(undefined) } : {}), ...claudeGuardedRelaySettings(config.approvalMode), ...claudeHostInstructionExcludeSettings(config), ...claudeBypassPermissionSettings(config.approvalMode), ...claudeHarnessTrim(config).settings, ...claudeSubagentSettings(config) },
502
501
  inlineHookSet,
503
502
  [...projectHooks, ...provisionedHooks].map((h) => h.name),
504
503
  statusLine,
505
504
  nativeMemory.settings,
506
- { cwd: config.cwd, model: config.model, generation: runnerMcpGeneration(config.env) },
505
+ { cwd: config.cwd, model: config.model },
507
506
  hostDefaultArgs,
508
507
  config.providerArgs,
509
508
  );
510
- // The anti-lie invariant (#1096): only report hooks as materialized when they actually reach
509
+ // The anti-lie invariant: only report hooks as materialized when they actually reach
511
510
  // the launch. If the caller's --settings suppressed them, empty the reported set and surface a
512
511
  // loud suppression reason instead of an "applied" report.
513
512
  const hooksSuppressed = settings.suppressedHookNames.length
@@ -517,21 +516,21 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
517
516
 
518
517
  // Plugin dirs (--plugin-dir loads explicitly, independent of --setting-sources):
519
518
  // relay-bundled plugin → only when relay.plugins (carries the relay monitor +
520
- // turn-lifecycle hooks #556, not reproducible via settings.json).
521
- // relay-provisioned plugins (#556) → materialized into the isolated home.
519
+ // turn-lifecycle hooks, not reproducible via settings.json).
520
+ // relay-provisioned plugins → materialized into the isolated home.
522
521
  // host plugin dirs → ONLY host-base profiles; isolated/vanilla must not pull them back in.
523
522
  const relayPluginDirs = !config.agentProfile && relayPlugin ? bundledIntegrationAssets(config).map(asset => asset.dir) : [];
524
523
  // `force-for-plugin: true` in this tiny plugin takes precedence over a caller or
525
524
  // ambient `outputStyle` setting, so a host-base launch is covered too (there is no
526
525
  // Relay-owned CLAUDE_CONFIG_DIR in which to write a custom style file).
527
526
  const provisionedPluginDirs = provisionedPlugins.map((p) => p.dir);
528
- const hostPluginDirs = selectClaudePluginDirs(hostPlan.pluginDirs, runnerMcpGeneration(config.env), relayPlugin);
527
+ const hostPluginDirs = selectClaudePluginDirs(hostPlan.pluginDirs, relayPlugin);
529
528
  const pluginDirs = [...new Set([resolve(import.meta.dir, "../plugins/claude-output-style"), ...relayPluginDirs, ...provisionedPluginDirs, ...hostPluginDirs])];
530
529
 
531
530
  const { declaredMcp, hostMcp, relayEndpoint, strictMcp, mcpServers, projectServers, hostMcpServers, sharedListenerUrl, sourceShadows: mcpSourceShadows } =
532
531
  resolveClaudeDeclaredMcp(config);
533
532
 
534
- // #1292 — a provisioned/host server's env/headers can carry a literal secret; inline JSON
533
+ // a provisioned/host server's env/headers can carry a literal secret; inline JSON
535
534
  // in --mcp-config lands verbatim in argv (world-readable via ps/proc). Whenever there's a
536
535
  // relay-owned scratch dir to write into (any launch with an agentProfile — see
537
536
  // providerProvisioningHomePathFor, which gives even host-base profiles a relay-owned dir
@@ -539,12 +538,12 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
539
538
  // writes the file this path points at, from the SAME resolveClaudeDeclaredMcp(config) inputs.
540
539
  const mcpConfigFilePath = assetHome ? join(assetHome, "mcp-config.json") : undefined;
541
540
 
542
- // #2067 — derive Claude's native setting-source cascade from the Project cells.
541
+ // derive Claude's native setting-source cascade from the Project cells.
543
542
  // P.mcp and P.skills have their own controlled channels and are intentionally not
544
543
  // triggers. The same list drives the instruction disposition report.
545
544
  const settingSources = projectSettingSources(config);
546
545
  const projectScopeDropped = Boolean(settingSources && !settingSources.includes("project"));
547
- // #2086 — when P.hooks forces the project scope off but P.instructions is on, re-inject the repo
546
+ // when P.hooks forces the project scope off but P.instructions is on, re-inject the repo
548
547
  // CLAUDE.md/AGENTS.md through the controlled append-system-prompt channel so the docs are honored
549
548
  // rather than silently dropped (see composeSystemPromptAppend / resolveProjectInstructions).
550
549
  const promptFile = resolveClaudeSystemPrompt(config, hostDefaultArgs, assetHome);
@@ -562,7 +561,6 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
562
561
  ...pluginDirs.flatMap((dir) => ["--plugin-dir", dir]),
563
562
  ...claudeMcpLaunchArgs({
564
563
  relayUrl: config.relayUrl,
565
- generation: runnerMcpGeneration(config.env),
566
564
  ...(config.relayMcpEndpoint ? { endpoint: config.relayMcpEndpoint } : {}),
567
565
  includeRelay: relayEndpoint,
568
566
  servers: declaredMcp,
@@ -611,14 +609,14 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
611
609
  hostSources: claudeHostReport(hostPlan, { mcp: hostMcpServers.length > 0, hooks: hostHooks || (!configHome && hostPlan.selection.hooks), skills: hostSkills.length > 0, defaultArgs: hostDefaultArgs.length > 0, env: Object.keys(providerConfig.env ?? {}).length > 0 && hostPlan.selection.settings }),
612
610
  hostDefaultArgs,
613
611
  mcp: {
614
- ...(runnerMcpGeneration(config.env) === "humwick" ? { generation: "humwick" as const } : {}),
612
+
615
613
  relayEndpoint, strict: strictMcp, servers: mcpServers, projectServers, hostServers: hostMcpServers,
616
614
  ...(sharedListenerUrl ? { sharedListener: { url: sharedListenerUrl } } : {}),
617
615
  },
618
616
  sourceShadows: [...skillSourceShadows, ...mcpSourceShadows],
619
617
  instructions,
620
618
  args,
621
- env: writeChildEnv({}, { ...configHomeEnv(provider, configHome, config.env), ...nativeMemory.env, ...fffMcpHookEnv(config), ...webToolsEnv(config), ...agentRedactEnv(redaction) }),
619
+ env: writeChildEnv({}, { ...configHomeEnv(provider, configHome, config.env), ...nativeMemory.env, ...fffMcpHookEnv(config), ...webToolsEnv(config), ...agentRedactEnv(redaction) }, []),
622
620
  redaction,
623
621
  };
624
622
  }
@@ -631,7 +629,7 @@ function assembleCodex(config: RunnerSpawnConfig, providerConfig: ProviderConfig
631
629
  const { provisioned: provisionedSkills, bundled: bundledSkillDirs, hostRoots, disabled: disabledSkillDirs, roots: skillDirs } = codexSkillSources(config);
632
630
  const hostPlan = configHome ? codexHostPlan(config, providerSourceHome("codex")) : undefined;
633
631
  const hostSelection = hostSourcesFor(config);
634
- // #1096 review, findings 3 & 4 — Codex delivers hooks via CODEX_HOME/hooks.json, so a launch
632
+ // review, findings 3 & 4 — Codex delivers hooks via CODEX_HOME/hooks.json, so a launch
635
633
  // can only carry them when it has an isolated CODEX_HOME (host-base profiles reuse the real
636
634
  // ~/.codex, which relay must not clobber) AND the installed Codex is new enough to consume the
637
635
  // file. Resolve the profile's hook definitions to decide whether there was anything to deliver;
@@ -643,7 +641,7 @@ function assembleCodex(config: RunnerSpawnConfig, providerConfig: ProviderConfig
643
641
  ? {
644
642
  reason: !configHome
645
643
  ? "Codex host-base profile has no managed CODEX_HOME; relay will not overwrite the host ~/.codex/hooks.json, so the baseline guard cannot be delivered"
646
- : "installed Codex is older than 0.124 and ignores CODEX_HOME/hooks.json (set AGENT_RELAY_CODEX_VERSION to override the probe)",
644
+ : "installed Codex is older than 0.124 and ignores CODEX_HOME/hooks.json (set HUMWICK_CODEX_VERSION to override the probe)",
647
645
  names: resolvedHookDefs.map((h) => h.name),
648
646
  }
649
647
  : undefined;
@@ -653,7 +651,7 @@ function assembleCodex(config: RunnerSpawnConfig, providerConfig: ProviderConfig
653
651
  // unenforceable rather than claiming an artifact the provider ignores.
654
652
  const hostHookSet = configHome && hooksSupported && hostSelection.hooks ? hostCodexHooks() : {};
655
653
  const hostHooks = Object.keys(hostHookSet).length > 0;
656
- // #3025 — redaction rides the `-c` session-flags layer, so host-base launches keep ~/.codex.
654
+ // redaction rides the `-c` session-flags layer, so host-base launches keep ~/.codex.
657
655
  const redact = resolveAgentRedact();
658
656
  const redaction: AgentRedactState = !isAgentRedactInstall(redact) ? redact
659
657
  : !hooksSupported ? { state: "unavailable", reason: "installed Codex is older than 0.124 and ignores hooks" }
@@ -662,14 +660,14 @@ function assembleCodex(config: RunnerSpawnConfig, providerConfig: ProviderConfig
662
660
  // Codex has no `--setting-sources`: only a vanilla base drops the ambient project doc
663
661
  // (`project_doc_max_bytes=0`); an isolated CODEX_HOME drops host/global config.toml. There is
664
662
  // no P.hooks→scope-drop interference here (only a vanilla base suppresses the project doc), so
665
- // Codex never re-injects repo instructions (#2086 is Claude's `--setting-sources` surface).
663
+ // Codex never re-injects repo instructions (is Claude's `--setting-sources` surface).
666
664
  const instructions = assembleInstructions(config, {
667
665
  projectScopeDropped: vanilla,
668
666
  isolatedHome: Boolean(configHome),
669
667
  repoInstructionsReinjected: false,
670
668
  });
671
669
 
672
- // #1292 — a provisioned/project server's env can carry a literal secret; `-c
670
+ // a provisioned/project server's env can carry a literal secret; `-c
673
671
  // mcp_servers.<name>.env.<K>=<V>` lands verbatim in argv (world-readable via ps/proc).
674
672
  // An ISOLATED CODEX_HOME is a relay-owned per-instance dir Codex actually reads as its
675
673
  // config home, so route command/args/url/env through CODEX_HOME/config.toml instead
@@ -681,14 +679,14 @@ function assembleCodex(config: RunnerSpawnConfig, providerConfig: ProviderConfig
681
679
 
682
680
  // The skills/MCP/project-doc block; core launch config (model/approval/listen) stays
683
681
  // in the adapter. -c overrides are order-independent, so the assembled block is contiguous.
684
- // #1565 P5.7 — Codex's native-memory lever rides the same `-c` argv precedent as the
682
+ // P5.7 — Codex's native-memory lever rides the same `-c` argv precedent as the
685
683
  // project-doc suppressor above it (`-c project_doc_max_bytes=0`). Argv outranks config.toml, so
686
684
  // this is the portable/authoritative half; the isolated CODEX_HOME config.toml is the belt.
687
685
  const nativeMemory = resolveNativeMemoryLever({ provider: "codex", config, isolatedHome: Boolean(configHome) });
688
686
 
689
687
  const args = [
690
688
  ...bundledSkillConfigArgs(skillDirs, disabledSkillDirs),
691
- ...(relayEndpoint ? relayMcpCodexConfigArgs(config.relayUrl, config.relayMcpEndpoint, runnerMcpGeneration(config.env)) : []),
689
+ ...(relayEndpoint ? relayMcpCodexConfigArgs(config.relayUrl, config.relayMcpEndpoint) : []),
692
690
  ...mcpArgs,
693
691
  ...codexRetiredMcpConfigArgs(config),
694
692
  ...codexProjectDocSuppressionArgs(config),
@@ -732,14 +730,14 @@ function assembleCodex(config: RunnerSpawnConfig, providerConfig: ProviderConfig
732
730
  : nativeHostReport(),
733
731
  hostDefaultArgs,
734
732
  mcp: {
735
- ...(runnerMcpGeneration(config.env) === "humwick" ? { generation: "humwick" as const } : {}),
733
+
736
734
  relayEndpoint, strict: false, servers: mcpServers, projectServers, hostServers: hostMcpServers,
737
735
  ...(sharedListenerUrl ? { sharedListener: { url: sharedListenerUrl, ...(metaOnlyCallmux ? { metaOnly: true } : {}), ...(metaOnlyCallmux?.relay ? { relayFronted: true } : {}) } } : {}),
738
736
  },
739
737
  sourceShadows: mcpSourceShadows,
740
738
  instructions,
741
739
  args,
742
- env: writeChildEnv({}, { ...configHomeEnv("codex", configHome), ...webToolsEnv(config), ...agentRedactEnv(redaction) }),
740
+ env: writeChildEnv({}, { ...configHomeEnv("codex", configHome), ...webToolsEnv(config), ...agentRedactEnv(redaction) }, []),
743
741
  redaction,
744
742
  };
745
743
  }
@@ -748,6 +746,8 @@ function assembleCodex(config: RunnerSpawnConfig, providerConfig: ProviderConfig
748
746
  // provider-home asset formats. It still needs a complete projection object: RunnerCore assembles
749
747
  // every normal provider before registration and launch-injection reporting.
750
748
  function assembleOpenCode(config: RunnerSpawnConfig, provider: string): AssembledLaunch {
749
+ const assets = resolveOpenCodeAssets(config);
750
+ const hooks = profileProvisioning(config).hooks ?? [];
751
751
  const { relayEndpoint, mcpServers, projectServers, hostMcpServers, sharedListenerUrl, sourceShadows } = resolveOpenCodeDeclaredMcp(config);
752
752
  const instructions = assembleInstructions(config, {
753
753
  projectScopeDropped: false,
@@ -761,18 +761,17 @@ function assembleOpenCode(config: RunnerSpawnConfig, provider: string): Assemble
761
761
  ...(config.agentProfile ? { profile: config.agentProfile } : {}),
762
762
  base: config.agentProfile?.base ?? "host",
763
763
  vanilla: profileIsVanillaBase(config),
764
- // OpenCode has no launch-level instruction field: both independently gated blocks are sent
765
- // only with the first initial/inbox turn. Keep availability distinct from an emitted launch
766
- // artifact so projection never mistakes configured systemPromptAppend for delivery proof.
767
- relayContext: false, relayContextPending: resolveRelayContext({ slug: "relay.context.opencode", config }).available, launchContextPending: Boolean(config.systemPromptAppend?.trim()),
768
- relaySkills: false,
764
+ // Native instructions are system-level context, persistent across turns and session clears.
765
+ relayContext: assets.context.available,
766
+ relaySkills: assets.bundled.length > 0,
769
767
  relayPlugin: false,
770
768
  statusLine: false,
771
- skills: [],
769
+ skills: assets.provisioned.map(({ name, dir }) => ({ name, dir })),
772
770
  hostSkills: [],
773
771
  projectSkills: [],
774
772
  projectSettings: { applied: false, keys: [], ignoredKeys: [] },
775
773
  hooks: [],
774
+ ...(hooks.length ? { hooksSuppressed: { reason: "OpenCode uses native plugins, not Claude/Codex hook command manifests; these hooks were not applied.", names: hooks.map(hook => hook.name) } } : {}),
776
775
  hostHooks: false,
777
776
  hostHooksEnforceable: false,
778
777
  projectHooks: [],
@@ -785,14 +784,14 @@ function assembleOpenCode(config: RunnerSpawnConfig, provider: string): Assemble
785
784
  hostSources: { instructions: "unsupported", mcp: "unsupported", hooks: "unsupported", skills: "unsupported", plugins: "unsupported", settings: "unsupported" },
786
785
  hostDefaultArgs: [],
787
786
  mcp: {
788
- ...(runnerMcpGeneration(config.env) === "humwick" ? { generation: "humwick" as const } : {}),
787
+
789
788
  relayEndpoint, strict: false, servers: mcpServers, projectServers, hostServers: hostMcpServers,
790
789
  ...(sharedListenerUrl ? { sharedListener: { url: sharedListenerUrl } } : {}),
791
790
  },
792
791
  sourceShadows,
793
792
  instructions,
794
793
  args: [],
795
- env: writeChildEnv({}, { ...webToolsEnv(config), ...agentRedactEnv(redaction) }),
794
+ env: writeChildEnv({}, { ...webToolsEnv(config), ...agentRedactEnv(redaction) }, []),
796
795
  redaction,
797
796
  };
798
797
  }
@@ -804,13 +803,13 @@ function configHomeEnv(provider: string, configHome: string | undefined, launchE
804
803
  const envVar = manifest?.home?.configDirEnvVar;
805
804
  if (!envVar) return {};
806
805
  if (configHome) return { [envVar]: configHome };
807
- // #2513 review HIGH-1 — a dedicatedHome provider (claude-b) pins the env var at its OWN
806
+ // review HIGH-1 — a dedicatedHome provider (claude-b) pins the env var at its OWN
808
807
  // effective host home even on host-base/profile-less launches, so the provider binary
809
808
  // never falls back to the primary family home (~/.claude). The primary providers
810
809
  // (claude, codex) keep their historical no-export host-base behavior.
811
810
  const hostHome = providerHostConfigHome(provider);
812
811
  if (hostHome) return { [envVar]: hostHome };
813
- // #772 — a caller passing launchEnv (claude) opts in to pinning the effective dir (launch
812
+ // a caller passing launchEnv (claude) opts in to pinning the effective dir (launch
814
813
  // env, else the runner's) so the session-status probe, which falls back to the runner's
815
814
  // value, reads the dir the provider process uses. Unset everywhere stays unpinned.
816
815
  if (!launchEnv) return {};
@@ -838,7 +837,7 @@ function materializeClaudeAssets(config: RunnerSpawnConfig, provider: string = "
838
837
  if (!configHome) return;
839
838
  const hostPlan = claudeHostPlan(config, providerSourceHome(provider));
840
839
  const skillSources = resolveClaudeSkillSources(configHome, config, provider);
841
- // #3387 — host classes first: drop what an opted-out class left in this reused home, then link
840
+ // host classes first: drop what an opted-out class left in this reused home, then link
842
841
  // the selected ones, before Relay/Project skills claim their names.
843
842
  materializeHostAssets(configHome, hostPlan.links, hostPlan.files, skillSources.host.map((skill) => relative(configHome, skill.dir)));
844
843
  materializeResolvedAssets(skillSources.relay);
@@ -846,33 +845,32 @@ function materializeClaudeAssets(config: RunnerSpawnConfig, provider: string = "
846
845
  materializeResolvedAssets(skillSources.host);
847
846
  materializeResolvedAssets(resolveProvisionedHooks(configHome, config));
848
847
  materializeResolvedAssets(resolveProjectHooks(config));
849
- // #1096 — land the provisioned hooks in the managed home's settings.json (the documented
848
+ // land the provisioned hooks in the managed home's settings.json (the documented
850
849
  // hook source), matching the assembler's decision to keep them out of the inline --settings.
851
- // #1565 P5.7 — the native-memory keys ride the SAME file (the isolated-home belt behind the
852
- // env lever). #3387 — so do the selected host settings and native plugin enablement: this is
850
+ // P5.7 — the native-memory keys ride the SAME file (the isolated-home belt behind the
851
+ // env lever). — so do the selected host settings and native plugin enablement: this is
853
852
  // the one writer of the managed settings.json, so nothing later can wipe plugin enablement.
854
853
  const managedHookSettings = claudeManagedHookSettings(config, configHome, provider);
855
854
  const nativeMemorySettings = claudeManagedNativeMemorySettings(config, configHome, (lists) => callerSettingsMergeable(lists, config.cwd), provider);
856
- // T3182 — the SendFeedback deny rides EVERY managed settings.json this launch writes (the
855
+ // the SendFeedback deny rides EVERY managed settings.json this launch writes (the
857
856
  // file-channel belt behind the CLAUDE_CODE_SEND_FEEDBACK=0 env lever, so a stripped env
858
857
  // still removes the tool): merged into the full payload AND the belt-retry payload so the
859
858
  // retry can never drop it.
860
- const withManagedPermissions = (settings: Record<string, unknown>) => withManagedClaudePermissions(settings, config.approvalMode, runnerMcpGeneration(config.env));
859
+ const withManagedPermissions = (settings: Record<string, unknown>) => withManagedClaudePermissions(settings, config.approvalMode);
861
860
  const baseSettings = { ...hostPlan.settings, ...(managedHookSettings ?? {}) };
862
861
  // The hook and selected-host halves of this file are NOT best-effort (a missing baseline guard
863
- // is a real regression, #1096; a selected host class must never silently vanish, #3387), so
862
+ // is a real regression; a selected host class must never silently vanish), so
864
863
  // only the native-memory contribution is guarded: on a write failure, retry without it.
865
864
  if (applyNativeMemoryBelt("the Claude managed settings.json", () => writeClaudeSettingsJson(configHome, withManagedPermissions({ ...baseSettings, ...nativeMemorySettings }))) && Object.keys(baseSettings).length) {
866
865
  writeClaudeSettingsJson(configHome, withManagedPermissions(baseSettings));
867
866
  }
868
867
  materializeResolvedAssets(resolveClaudeProvisionedPlugins(configHome, config));
869
- // #1292 — write the file assembleClaude's --mcp-config <path> points at, from the SAME
868
+ // write the file assembleClaude's --mcp-config <path> points at, from the SAME
870
869
  // resolveClaudeDeclaredMcp(config) inputs (see the purity/consistency note there). Keeps
871
870
  // provisioned/host-server env/headers secrets out of argv.
872
871
  const { declaredMcp, hostMcp, relayEndpoint, strictMcp } = resolveClaudeDeclaredMcp(config);
873
872
  const mcpServers = claudeMcpConfigPayload({
874
873
  relayUrl: config.relayUrl,
875
- generation: runnerMcpGeneration(config.env),
876
874
  ...(config.relayMcpEndpoint ? { endpoint: config.relayMcpEndpoint } : {}),
877
875
  includeRelay: relayEndpoint,
878
876
  servers: declaredMcp,
@@ -893,7 +891,7 @@ function materializeCodexAssets(config: RunnerSpawnConfig): void {
893
891
  materializeHostAssets(configHome, hostPlan.links, []);
894
892
  writeCodexHostSettings(configHome, hostPlan.settings, tomlInlineValue);
895
893
  materializeResolvedAssets(resolveCodexProvisionedSkills(configHome, config));
896
- // #1096 review, finding 4 — don't write CODEX_HOME/hooks.json for a Codex that would ignore it;
894
+ // review, finding 4 — don't write CODEX_HOME/hooks.json for a Codex that would ignore it;
897
895
  // keep disk == report (the assembler reports these hooks suppressed for such a launch).
898
896
  if (codexHooksSupported(config.providerConfig.command)) {
899
897
  const relayHooks = resolveProvisionedHooks(configHome, config);
@@ -902,20 +900,20 @@ function materializeCodexAssets(config: RunnerSpawnConfig): void {
902
900
  const hostHookSet = hostPlan.selection.hooks ? hostCodexHooks() : {};
903
901
  writeCodexHooksJson(configHome, mergeHookSets(hostHookSet, relayHookSet));
904
902
  }
905
- // #1292 — write the CODEX_HOME/config.toml sections assembleCodex's non-secret -c
903
+ // write the CODEX_HOME/config.toml sections assembleCodex's non-secret -c
906
904
  // timeout-only overrides expect to find command/args/url/env in (see the mcpArgs branch
907
905
  // there). Same resolveCodexDeclaredMcp(config) inputs, so disk == launch.
908
906
  const { declaredMcp, metaOnlyCallmux } = resolveCodexDeclaredMcp(config);
909
907
  writeCodexMcpServersToml(configHome, declaredMcp);
910
- // #1565 P5.7 — the isolated-home belt behind the `-c features.memories=…` argv lever. Same
908
+ // P5.7 — the isolated-home belt behind the `-c features.memories=…` argv lever. Same
911
909
  // resolveNativeMemoryLever inputs assembleCodex used, so disk == launch. No-op for an
912
910
  // undeclared profile (`configToml` is empty, so nothing is written). Guarded: never fails the spawn.
913
911
  applyNativeMemoryBelt("the Codex CODEX_HOME/config.toml [features] table", () => {
914
912
  writeCodexFeaturesToml(configHome, resolveNativeMemoryLever({ provider: "codex", config, isolatedHome: true }).configToml);
915
913
  });
916
- // #1575/#1450 — write the per-agent metaOnly config the shared-listener descriptor points at
914
+ // write the per-agent metaOnly config the shared-listener descriptor points at
917
915
  // (`callmux --config <path>`), from the SAME resolveCodexDeclaredMcp inputs so disk == launch.
918
- // The optional relay downstream (#1450) rides here too, so the on-demand relay front and the
916
+ // The optional relay downstream rides here too, so the on-demand relay front and the
919
917
  // agent's stdio callmux descriptor come from one resolution.
920
918
  if (metaOnlyCallmux) {
921
919
  writeSharedMcpMetaOnlyConfig(metaOnlyCallmux.configPath, metaOnlyCallmux.url, metaOnlyCallmux.cwd, metaOnlyCallmux.relay);
@@ -934,7 +932,7 @@ export function assembleLaunch(provider: SpawnProvider, config: RunnerSpawnConfi
934
932
  const hostDefaultArgs = hostProviderDefaultArgs(config, providerConfig);
935
933
  const serviceEnv = serviceAccessLaunchEnv(config);
936
934
  const assembled = assembler(config, providerConfig, hostDefaultArgs);
937
- return { ...assembled, env: writeChildEnv({}, { ...assembled.env, ...serviceEnv }) };
935
+ return { ...assembled, env: writeChildEnv({}, { ...assembled.env, ...serviceEnv }, []) };
938
936
  }
939
937
 
940
938
  /**
@@ -944,9 +942,9 @@ export function assembleLaunch(provider: SpawnProvider, config: RunnerSpawnConfi
944
942
  * system context also uses a private file for host-base and profile-less launches.
945
943
  */
946
944
  export function materializeLaunchAssembly(provider: SpawnProvider, config: RunnerSpawnConfig, assembled?: AssembledLaunch): void {
947
- // #3830 — every Claude path, including host-base/profile-less, uses a private file.
945
+ // every Claude path, including host-base/profile-less, uses a private file.
948
946
  if (getManifest(provider)?.shim?.kind === "claude-relay") materializeClaudeSystemPrompt((assembled ?? assembleLaunch(provider, config, config.providerConfig)).systemPromptFile);
949
- if (!config.agentProfile && runnerMcpGeneration(config.env) === "humwick") {
947
+ if (!config.agentProfile) {
950
948
  const feature = getManifest(provider)?.provisioning?.bundledSkills ? "skills" : "plugins";
951
949
  if (profileAllowsRelayFeature(config, feature)) {
952
950
  materializeProviderHome(bundledIntegrationHome(config), { provider, profile: "integrations", instanceId: config.instanceId || config.runnerId, agentId: config.agentId });