Skip to content

Commit 09be36e

Browse files
committed
Revert "fix(codex): problem with cwd, change codex mcp and hooks config, bump CLI"
This reverts commit 73dd917.
1 parent 01a9a30 commit 09be36e

20 files changed

Lines changed: 113 additions & 379 deletions

.archcore/.sync-state.json

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3201,51 +3201,6 @@
32013201
"source": "plugin/cli-integration-tests.rule.md",
32023202
"target": "plugin/bundled-cli-launcher.adr.md",
32033203
"type": "related"
3204-
},
3205-
{
3206-
"source": "plugin/codex-host-support.plan.md",
3207-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3208-
"type": "depends_on"
3209-
},
3210-
{
3211-
"source": "plugin/codex-host-support.idea.md",
3212-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3213-
"type": "related"
3214-
},
3215-
{
3216-
"source": "plugin/codex-host-support.prd.md",
3217-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3218-
"type": "depends_on"
3219-
},
3220-
{
3221-
"source": "plugin/codex-local-plugin-testing.guide.md",
3222-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3223-
"type": "related"
3224-
},
3225-
{
3226-
"source": "plugin/plugin-development.guide.md",
3227-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3228-
"type": "related"
3229-
},
3230-
{
3231-
"source": "plugin/component-registry.doc.md",
3232-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3233-
"type": "related"
3234-
},
3235-
{
3236-
"source": "plugin/multi-host-plugin-architecture.adr.md",
3237-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3238-
"type": "related"
3239-
},
3240-
{
3241-
"source": "plugin/bundled-cli-launcher.adr.md",
3242-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3243-
"type": "related"
3244-
},
3245-
{
3246-
"source": "plugin/multi-host-compatibility-layer.spec.md",
3247-
"target": "plugin/codex-plugin-spawn-semantics.adr.md",
3248-
"type": "implements"
32493204
}
32503205
]
32513206
}

.archcore/plugin/bundled-cli-launcher.adr.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ In practice this produced real friction:
1818
- The `claude mcp add ...` step is discoverable only by reading the README — `/plugin install` gives no hint that MCP registration is still required.
1919
- Error messages from `bin/session-start` when MCP was unreachable ("install the CLI and register the MCP server") were ignored or misread as install failures.
2020

21-
The Claude Code plugin runtime now supports `${CLAUDE_PLUGIN_ROOT}` substitution in `.mcp.json` shipped at the plugin root, and treats plugin-provided MCP servers as first-class. Duplicate suppression only kicks in when the `command`/`args` exactly match a user- or project-registered server — and if a user has installed `archcore` globally, the PATH resolution inside the launcher picks it up, so the effective command is identical to the user's global registration and deduping is benign. Codex CLI v0.117.0+ (March 2026) gained plugin-shipped MCP via the Codex manifest's `mcpServers` pointer. Codex uses a different resolution mechanism than Claude Code: rather than env-var substitution in `command`/`args`, it rebases a relative `cwd` field against the plugin install root via `codex-rs/core-plugins/src/loader.rs::normalize_plugin_mcp_server_value`. Codex therefore ships a separate plugin-root MCP config at `.codex.mcp.json` with `command: "./bin/archcore"` and `cwd: "."`. The `cwd: "."` is the resolution mechanism — Codex rebases it to the plugin install root so the relative command resolves correctly regardless of the user's project directory; without `cwd`, Codex spawns from the user's project CWD and the MCP fails with ENOENT. See `plugin/codex-plugin-spawn-semantics.adr.md` for the canonical record on Codex's MCP cwd rebase vs hook `${PLUGIN_ROOT}` substitution.
21+
The Claude Code plugin runtime now supports `${CLAUDE_PLUGIN_ROOT}` substitution in `.mcp.json` shipped at the plugin root, and treats plugin-provided MCP servers as first-class. Duplicate suppression only kicks in when the `command`/`args` exactly match a user- or project-registered server — and if a user has installed `archcore` globally, the PATH resolution inside the launcher picks it up, so the effective command is identical to the user's global registration and deduping is benign. Codex CLI v0.117.0+ (March 2026) gained plugin-shipped MCP via the Codex manifest's `mcpServers` pointer, but its plugin examples use plugin-relative command paths rather than Claude's root-variable substitution. Codex therefore ships a separate plugin-root MCP config at `.codex.mcp.json` that points at the same launcher with `./bin/archcore`.
2222

2323
### Drivers
2424

@@ -56,7 +56,7 @@ The plugin root ships `.mcp.json`:
5656
}
5757
```
5858

59-
Claude Code reads this and registers `archcore` as a plugin-provided MCP server. The command points at the launcher — the launcher resolves to the right binary at invocation time. Resolution mechanism: env-var substitution at the host level (`${CLAUDE_PLUGIN_ROOT}` is replaced with the plugin install path before spawn).
59+
Claude Code reads this and registers `archcore` as a plugin-provided MCP server. The command points at the launcher — the launcher resolves to the right binary at invocation time.
6060

6161
Codex CLI reads `.codex-plugin/plugin.json` and follows its `mcpServers` pointer to `.codex.mcp.json`. The Codex build-plugins docs reserve `.codex-plugin/` for `plugin.json`, so the Codex-specific MCP file lives at the plugin root:
6262

@@ -66,21 +66,20 @@ Codex CLI reads `.codex-plugin/plugin.json` and follows its `mcpServers` pointer
6666
}
6767
```
6868

69-
The pointed-to file uses the same wrapper shape as public Codex plugin examples, with the addition of a `cwd` field that's the resolution mechanism for Codex:
69+
The pointed-to file uses the same wrapper shape as public Codex plugin examples:
7070

7171
```json
7272
{
7373
"mcpServers": {
7474
"archcore": {
7575
"command": "./bin/archcore",
76-
"args": ["mcp"],
77-
"cwd": "."
76+
"args": ["mcp"]
7877
}
7978
}
8079
}
8180
```
8281

83-
Codex resolves the command via its `cwd` rebase mechanism: `normalize_plugin_mcp_server_value` (`codex-rs/core-plugins/src/loader.rs`) rebases the relative `cwd` (`.`) to the plugin install root; `launch_server` (`codex-rs/rmcp-client/src/stdio_server_launcher.rs`) then sets that as `current_dir` for the spawned process, so `./bin/archcore` resolves against the plugin root rather than the user's project CWD. This avoids relying on an undocumented `${CODEX_PLUGIN_ROOT}` environment variable (Codex does not export one to MCP processes, nor does it substitute env-var placeholders in MCP `command`/`args`) while still using the same launcher and cache behavior. Without `cwd: "."`, Codex would spawn the MCP from the user's project CWD and fail with ENOENT — the original symptom that motivated the spawn-semantics investigation. See `plugin/codex-plugin-spawn-semantics.adr.md`.
82+
Codex resolves the plugin-relative command path from the installed plugin root. This avoids relying on an undocumented `${CODEX_PLUGIN_ROOT}` environment variable while still using the same launcher and cache behavior.
8483

8584
### Pinned CLI version
8685

@@ -134,12 +133,12 @@ Add `bin/archcore` but leave MCP registration to the user.
134133
- **Enterprise/offline escape hatches.** `ARCHCORE_BIN` pins an explicit binary. `ARCHCORE_SKIP_DOWNLOAD=1` disables network access at the launcher layer.
135134
- **Survives plugin updates.** The cache lives under `$CLAUDE_PLUGIN_DATA/archcore/cli` (Claude Code's stable data dir) or `$CODEX_PLUGIN_DATA/archcore/cli` (Codex CLI's stable data dir), so plugin re-installs don't re-download.
136135
- **Security.** Downloads are checksum-verified before execution. No `curl | sh`.
137-
- **Codex parity with Claude Code.** Codex CLI uses the same launcher mechanism with a Codex-specific MCP config: `command: "./bin/archcore"` paired with `cwd: "."`, where Codex's `normalize_plugin_mcp_server_value` rebases the relative cwd to the plugin install root. Host-prefixed cache directories keep the binary lifecycle aligned with Claude Code. The resolution mechanism differs from Claude Code (cwd rebase vs env-var substitution), but the user experience is identical: zero-setup install, plugin-shipped MCP, same launcher binary, same cache.
136+
- **Codex parity with Claude Code.** Codex CLI uses the same launcher mechanism with a Codex-specific MCP config and plugin-relative command paths. Host-prefixed cache directories keep the binary lifecycle aligned with Claude Code without relying on undocumented root-variable substitution.
138137

139138
### Negative
140139

141140
- **Plugin now owns part of the CLI lifecycle.** Cache invalidation (stale cached binaries after CLI bugfix releases) requires bumping `bin/CLI_VERSION` in the plugin and shipping a plugin release. Mitigation: cache is version-keyed by filename (`archcore-v${VERSION}`), so a pin bump always downloads fresh.
142141
- **First-run network dependency.** Air-gapped environments that don't pre-install the CLI fail at the first MCP call with a network error. Mitigation: documented `ARCHCORE_BIN` / `ARCHCORE_SKIP_DOWNLOAD=1` workflow in the README.
143-
- **Cursor remains the multi-host outlier.** Claude Code and Codex CLI both support plugin-shipped MCP configs (via different mechanisms — env-var substitution and `cwd` rebase respectively); Cursor does not. Cursor users still register MCP externally (via project `mcp.json` or Cursor MCP settings). The launcher still works for them — it just isn't wired in via a plugin-shipped `.mcp.json`. This is a deliberate host-by-host rollout; the ADR does not claim parity across all hosts.
142+
- **Cursor remains the multi-host outlier.** Claude Code and Codex CLI both support plugin-shipped MCP configs; Cursor does not. Cursor users still register MCP externally (via project `mcp.json` or Cursor MCP settings). The launcher still works for them — it just isn't wired in via a plugin-shipped `.mcp.json`. This is a deliberate host-by-host rollout; the ADR does not claim parity across all hosts.
144143
- **Inverts the Multi-Host Plugin Architecture ADR's "MCP ownership boundary" section.** That section is now historically accurate (rationale at the time) but no longer describes current behavior. See that ADR for the cross-link; this ADR supersedes the "plugin does not ship an MCP server configuration" claim for Claude Code and (by extension) Codex CLI specifically.
145144
- **Supply-chain surface area.** The launcher executes downloaded binaries. Checksum verification is the only gate. Any compromise of the GitHub Releases signing pipeline compromises the plugin's trust model. Acceptable given the CLI was the trust root already; the launcher doesn't introduce a new trust boundary.

.archcore/plugin/codex-host-support.idea.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@ Promote OpenAI Codex CLI from "P2 / Future / TBD" (as listed in the Multi-Host C
1515
Codex CLI v0.117.0+ (March 2026) introduced a plugin system with near 1:1 surface to Claude Code:
1616

1717
- `.codex-plugin/plugin.json` manifest with component pointers (`skills`, `mcpServers`, `apps`, `hooks`)
18-
- 6 hook events (SessionStart, PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, Stop) — same names, same JSON shapes (snake_case), exit-code-2 blocking, `hookSpecificOutput.additionalContext` for context injection; runtime execution is gated by Codex's `plugin_hooks` feature (currently `under development, false`)
18+
- 6 hook events (SessionStart, PreToolUse, PermissionRequest, PostToolUse, UserPromptSubmit, Stop) — same names, same JSON shapes (snake_case), exit-code-2 blocking, `hookSpecificOutput.additionalContext` for context injection; runtime execution is gated by Codex's `codex_hooks` feature and current plugin-local hook discovery behavior
1919
- MCP servers via `[mcp_servers.<name>]` in config or plugin-shipped `.mcp.json`
2020
- Skills as `skills/<name>/SKILL.md` directories with `name`+`description` frontmatter — **already compatible with our SKILL.md files**
2121
- Subagents in TOML format with `sandbox_mode` ("read-only" | "workspace-write"), `developer_instructions`, `mcp_servers`, `[[skills.config]]`
2222
- Marketplace install: `codex plugin marketplace add archcore-ai/plugin` (GitHub shorthand)
2323

24-
Codex's resolution mechanisms differ between MCP and hooks (canonical record: `plugin/codex-plugin-spawn-semantics.adr.md`). For MCP, Codex does NOT substitute env-var placeholders in `command`/`args` — the resolution happens through a `cwd` rebase: `normalize_plugin_mcp_server_value` rebases a relative `cwd` field against the plugin install root. The plugin's `.codex.mcp.json` therefore sets `command: "./bin/archcore"` paired with `cwd: "."`. For hooks, Codex's hooks engine injects `PLUGIN_ROOT` (canonical, host-neutral) plus `CLAUDE_PLUGIN_ROOT` (a backward-compat alias for porting old Claude plugins) and folds `${KEY}` substitution at spawn time — so `${PLUGIN_ROOT}/bin/...` is the right form for `hooks/codex.hooks.json`. Note: `CODEX_PLUGIN_ROOT` does not exist in Codex.
25-
26-
This gives **Codex MCP parity with Claude Code** without requiring a `${CODEX_PLUGIN_ROOT}` env var. Cursor remains the multi-host outlier because it lacks an equivalent path-substitution or cwd-rebase mechanism for plugin-provided MCP.
24+
Unlike Cursor (which lacks `${CLAUDE_PLUGIN_ROOT}`-equivalent path substitution for plugin-provided MCP), Codex supports plugin-relative paths from the manifest, which means **Codex gets MCP parity with Claude Code** without depending on a `${CODEX_PLUGIN_ROOT}` env var. The plugin ships a Codex-specific plugin-root `.codex.mcp.json` whose command is `./bin/archcore`.
2725

2826
## Value
2927

@@ -41,9 +39,9 @@ Reuse the existing per-host adapter pattern. New components only:
4139

4240
1. **Manifest**: `.codex-plugin/plugin.json` — minimal name/version/description plus `interface{}` block for marketplace UI metadata; component pointers `skills: "./skills/"`, `mcpServers: "./.codex.mcp.json"`, `hooks: "./hooks/codex.hooks.json"`.
4341

44-
2. **Hooks**: `hooks/codex.hooks.json` — clone of `hooks/hooks.json` with `${PLUGIN_ROOT}/bin/...` substitution (Codex's canonical, host-neutral env var; not the `${CLAUDE_PLUGIN_ROOT}` compat alias) and `apply_patch` added to the edit matcher. Events PascalCase (same as Claude). Block via exit 2 (already supported by `archcore_hook_block`). PostToolUse `additionalContext` via `hookSpecificOutput` (already emitted by `archcore_hook_info`). Runtime execution requires `codex features enable plugin_hooks` (the `plugin_hooks` flag is `under development, false` by default in Codex 0.130.0).
42+
2. **Hooks**: `hooks/codex.hooks.json` — clone of `hooks/hooks.json` with plugin-relative `./bin/...` commands and `apply_patch` added to the edit matcher. Events PascalCase (same as Claude). Block via exit 2 (already supported by `archcore_hook_block`). PostToolUse `additionalContext` via `hookSpecificOutput` (already emitted by `archcore_hook_info`). Runtime execution requires Codex hooks support and `[features].codex_hooks = true`.
4543

46-
3. **MCP wiring**: ship plugin-root `.codex.mcp.json` with `command: "./bin/archcore"`, `args: ["mcp"]`, and `cwd: "."`. The `cwd: "."` is essential — Codex's `normalize_plugin_mcp_server_value` rebases the relative cwd to the plugin install root so the relative command resolves correctly. Without `cwd`, the spawn happens from the user's project CWD and fails with ENOENT. Do NOT reuse Claude's `.mcp.json`, because it contains `${CLAUDE_PLUGIN_ROOT}` which Codex does not substitute.
44+
3. **MCP wiring**: ship plugin-root `.codex.mcp.json` using the public Codex plugin examples' `{"mcpServers": {...}}` wrapper. Do not reuse Claude's `.mcp.json`, because it contains `${CLAUDE_PLUGIN_ROOT}`.
4745

4846
4. **`bin/lib/normalize-stdin.sh`**: add explicit `codex` host detection branch. Codex sends snake_case `hook_event_name` like Claude, so the existing claude-code branch is a working fallback, but explicit detection (e.g., presence of `turn_id` without `conversation_id`/`hookEventName`) gives cleaner separation and future-proofing.
4947

@@ -57,16 +55,16 @@ Reuse the existing per-host adapter pattern. New components only:
5755

5856
## Risks and Constraints
5957

60-
**Codex plugin-local hooks.** The official docs describe plugin-bundled lifecycle config, but hooks are behind the `plugin_hooks` feature (`under development, false` by default in Codex 0.130.0) and upstream runtime behavior has been in flux. Mitigation: ship the documented hook config and keep end-to-end hook execution as a smoke-test requirement rather than assuming it from static packaging.
58+
**Codex plugin-local hooks.** The official docs describe plugin-bundled lifecycle config, but hooks are behind `[features].codex_hooks = true` and upstream runtime behavior has been in flux. Mitigation: ship the documented hook config and keep end-to-end hook execution as a smoke-test requirement rather than assuming it from static packaging.
6159

6260
**Plugin-bundled subagents not confirmed.** Codex docs describe subagents in `~/.codex/agents/` (user) and `.codex/agents/` (project), but don't explicitly state plugins can ship `agents/*.toml`. If unsupported, auditor degrades to manual install.
6361

6462
**Auditor MCP whitelist coarsening.** Current `archcore-auditor.md` whitelists 8 specific MCP read tools via `tools: [...]`. Codex's `sandbox_mode = "read-only"` blocks file writes but does NOT filter MCP tools. To prevent auditor from calling mutating MCP tools (`create_document`, `update_document`, etc.), need either: (a) `disabled_tools[]` per subagent if Codex supports it, (b) `developer_instructions` enforcement (soft), or (c) a separate read-only MCP server invocation (e.g., `bin/archcore mcp --read-only`).
6563

6664
**Skill namespacing.** Codex skill invocation via `@` — unclear if `@archcore/decide` or flat `@decide`. Flat namespace risks collisions with other plugins' similarly-named skills. Spike should confirm.
6765

68-
**`.mcp.json` schema divergence.** Resolved for current Codex examples: use `{"mcpServers": {...}}` in a Codex-specific plugin-root `.codex.mcp.json` with `cwd: "."` companion. Existing `.mcp.json` remains Claude-only because it relies on `${CLAUDE_PLUGIN_ROOT}`, which Codex does not substitute.
66+
**`.mcp.json` schema divergence.** Resolved for current Codex examples: use `{"mcpServers": {...}}` in a Codex-specific plugin-root `.codex.mcp.json`. Existing `.mcp.json` remains Claude-only because it relies on `${CLAUDE_PLUGIN_ROOT}`.
6967

70-
**Cursor ADR side-effect.** `bundled-cli-launcher.adr.md` notes Cursor cannot use plugin-shipped MCP because of missing path substitution. Codex CAN — via the `cwd` rebase mechanism — so the ADR's "Multi-host divergence risk" Negative consequence shifts: Cursor remains the outlier, Codex joins Claude Code in zero-setup install.
68+
**Cursor ADR side-effect.** `bundled-cli-launcher.adr.md` notes Cursor cannot use plugin-shipped MCP because of missing path substitution. If Codex CAN use it, the ADR's "Multi-host divergence risk" Negative consequence shifts: Cursor remains the outlier, Codex joins Claude Code in zero-setup install.
7169

72-
**Codex versioning.** Plugin system is recent (v0.117.0, March 2026). API may evolve; users on older Codex versions will hit incompatibility. Document minimum Codex version in README and check at session-start where possible. The `plugin_hooks` feature flag in particular is unstable — track its promotion to `stable` upstream.
70+
**Codex versioning.** Plugin system is recent (v0.117.0, March 2026). API may evolve; users on older Codex versions will hit incompatibility. Document minimum Codex version in README and check at session-start where possible.

0 commit comments

Comments
 (0)