Codex qe-court seat stall: action plan
- Status: Proposed living plan
- Published: 2026-08-03
- Last updated: 2026-08-03
- Decision owner:
pacphi/agentic-kit maintainers
- Incident scope: Claude Code → Codex MCP seats used during an agentic-qe qe-court
- Evidence cutoff: 2026-08-03 America/Los_Angeles
This document separates confirmed evidence from hypotheses. It does not itself change an
accepted architecture decision. Implementation that changes managed projections or execution
behavior must update the affected agentic-kit ADRs in the same change.
Table of contents
1. Executive brief
Three Codex-routed prosecutor seats stalled during a qe-court run. The initial correlation with
prompts requesting Cargo under a read-only sandbox was real, but controlled reproduction disproved
Cargo as the direct trigger. The three stalled rollouts never reached Cargo or a shell command;
each stopped while a Codex code-mode turn awaited a nested mcp__ruflo__memory_search call. A
plugin-enabled memory-only reproduction also exceeded a 90-second external deadline. In contrast,
an isolated Codex configuration returned normally, direct Ruflo memory search completed in tens of
milliseconds, and plugin-free Cargo controls failed fast under read-only plus never.
The confirmed fault boundary is therefore an unbounded Codex MCP/code-mode session interacting
with nested MCP machinery, not Cargo writes alone. Existing public reports show related classes of
Codex MCP sessions stalling around approvals, elicitation, or sandbox setup, but none proves the
exact local mechanism (Codex #11816, Codex #18243,
codex-plugin-cc #258).
The recommended response has three layers:
- Contain now: treat raw Claude → Codex MCP seats as inspection-only, forbid nested MCP and
build commands in that profile, and impose an operator-visible deadline.
- Fix agentic-kit: replace the bare managed
codex mcp-server projection with a guarded stdio
bridge that injects policy, rejects incompatible requests, enforces an absolute timeout, and
terminates the child process tree. Add a scoped Codex PreToolUse circuit breaker only after
proving its bridge-only scope; Codex documents hooks as useful guardrails rather than complete
enforcement boundaries (Codex hooks).
- Coordinate upstream: file a sanitized Codex issue for the nested MCP/code-mode stall and two
agentic-qe issues for the incomplete qe-court asset plus missing execution-policy preflight.
Route build-capable seats through supervised ak run or agentic-qe's bounded provider path.
2. Actions at a glance
- Today: publish operator guidance and a known-issue warning; use diff-only prompts for the raw
read-only bridge. See Phase 0.
- Today–next business day: file one Codex issue and two agentic-qe issues using sanitized,
minimal reproductions. See Phase 1.
- Within three business days: implement the agentic-kit guarded bridge, external deadline,
cleanup, status diagnostics, and explicit direct-mode escape hatch. See
Phase 2.
- Within four business days: add court-aware compatibility preflight and send build/test work to
ak run rather than the raw seat bridge. See
Phase 3.
- Before release: pass the full bounded-reproduction matrix,
pnpm run check, Markdown lint,
link checks, and ADR reconciliation. See exit criteria.
- Week 2: review upstream responses and decide whether a scoped
PreToolUse rule is proven safe
enough to enable by default. See open questions.
3. Recommended course of action
3.1 Immediate containment
Keep the bridge available, because peer-host delegation is a core ambidextrous capability. Change
its default contract from “arbitrary autonomous worker” to “bounded inspection seat” until the
nested-call failure is understood.
- Add an explicit developer instruction: no builds, tests, package resolution, edits, or nested MCP
calls under the read-only seat profile; return a clear limitation instead.
- Require build/test requests to select
workspace-write through supervised ak run, with network
policy and timeout stated by the activity route.
- Set a temporary 120-second outer deadline for raw court seats. This is intentionally much shorter
than the 35-minute incident stalls and can be tuned after telemetry exists.
- Preserve a deliberate
direct mode for debugging, but warn that it bypasses agentic-kit
supervision.
3.2 Guarded bridge as the agentic-kit default
Agentic-kit owns the project-scoped Claude → Codex projection, so it is the correct place for the portable workaround. Claude Code supports project-scoped stdio MCP definitions in .mcp.json (Claude Code MCP scopes); agentic-kit should project its own wrapper command there instead of projecting bare codex mcp-server. Because this makes agentic-kit responsible for a new supervised boundary, implementation requires an ADR-0020 amendment or a new ADR before the guarded projection becomes the default.
The wrapper should:
- Spawn the real
codex mcp-server and transparently proxy stdio JSON-RPC.
- Intercept
codex tool requests before forwarding them.
- Inject bridge-specific
developer-instructions and a trace marker.
- Reject read-only prompts that explicitly require mutation or build output, with a structured
remediation message.
- Apply an absolute per-request deadline and terminate the whole child process tree on expiry.
- Emit bounded diagnostics without copying prompt or repository contents by default.
- Expose guarded/direct mode and drift in
ak status and repair it through ak sync.
The wrapper must not claim it can disable user-owned Codex plugins per request. That override was not effective in the observed Codex 0.146.0 child sessions. Plugin state remains externally owned.
3.3 Upstream fixes and coordination
- OpenAI Codex: request a minimal per-turn timeout/cancel contract for
mcp-server, reliable
cancellation of nested code-mode tool promises, and documented propagation of per-call config.
The official Agents SDK example places a timeout on the MCP client, which supports the need for
caller-side bounding but does not solve child cleanup by itself
(Codex MCP server guide).
- agentic-qe: ship qe-court's referee and schema as self-contained installed assets, then add a
seat execution policy that validates sandbox/command compatibility and applies a deadline.
Upstream ADR-124 is still marked Proposed at the cited revision despite implementation artifacts
being present (ADR-124).
- Ruflo/RuvNet Brain: do not assign root cause based on the current evidence. Direct Ruflo memory
search was healthy. Engage these maintainers only if a direct server-level reproduction or a
plugin hook contribution is isolated.
- Anthropic Claude Code: no root-cause issue is recommended now. The handoff to a background
tool call worked. Consider a client-side timeout/lifecycle feature request after the agentic-kit
wrapper proves the desired semantics.
3.4 Completely avert: Claude + OpenRouter court
Use this profile when avoiding the incident path is more important than preserving Codex as a
court participant. It removes every Codex seat and disables agentic-kit's managed Claude ↔ Codex
bridge. Claude remains the driving host; court inference uses only the bounded claude-code and
openrouter providers through agentic-qe's ProviderManager.
1. Load the OpenRouter key from a shell profile or secret manager. Keep
OPENROUTER_API_KEY out of kit.json, .agentic-qe/llm-config.json, and the court config.
2. Apply the part agentic-kit owns with existing commands:
ak host pick \
--host claude \
--primary-host claude \
--aqe-provider claude-code \
--aqe-fallback none
ak sync
--host claude is the complete desired host set. It disables Codex and removes only the two
Codex MCP registrations owned by agentic-kit. --aqe-fallback none records that this court must
not silently substitute one provider for another. If an older agentic-kit-managed
.agentic-qe/llm-config.json still contains fallbackChain, remove that stale block or set its
entries to [] before convening; the current Claude-only no-policy projection does not erase an
old on-disk chain merely because the persisted chain is empty.
3. Set these operational fields in the project-owned
.claude/skills/qe-court/config.json. Preserve its $schema, descriptions, and other metadata:
{
"prosecutors": [
"devils-advocate",
"brutal-honesty",
"sherlock",
"security-scanner",
"mutation"
],
"overturnDepth": 2,
"emitScore": false,
"routing": {
"defense": { "provider": "claude-code", "model": "sonnet" },
"prosecutor.devils-advocate": {
"provider": "openrouter", "model": "deepseek/deepseek-v4-flash"
},
"prosecutor.brutal-honesty": { "provider": "claude-code", "model": "opus" },
"prosecutor.sherlock": { "provider": "openrouter", "model": "z-ai/glm-5.2" },
"prosecutor.security-scanner": {
"provider": "openrouter", "model": "google/gemini-3.5-flash"
},
"prosecutor.mutation": {
"provider": "openrouter", "model": "google/gemini-3.5-flash"
},
"jury": { "provider": "openrouter", "model": "openai/gpt-5.6-terra" },
"deeperReviewer": { "provider": "openrouter", "model": "openai/gpt-5.6-sol" }
},
"options": {
"blindFiling": true,
"writerIsNeverJuror": true,
"minDistinctVendors": 2,
"requireDoeGatedScore": true,
"signCourtRecord": true
}
}
The candidate panel passes agentic-kit's current validateCourtConfig() with no violations.
The OpenRouter slugs were verified at the evidence cutoff:
DeepSeek V4 Flash for inexpensive adversarial breadth,
GLM 5.2 for deductive review,
Gemini 3.5 Flash for fast security/mutation evidence interpretation,
GPT-5.6 Terra for the jury, and
GPT-5.6 Sol only as the expensive overturn ceiling.
Do not use an anthropic/* OpenRouter model in the jury. The current validator maps the provider
name openrouter to one coarse vendor and does not inspect the model slug's underlying model
maker; an Anthropic-via-OpenRouter jury could therefore pass the structural check while violating
the substantive writer-versus-juror independence goal.
4. Keep provider attempts bounded. Agentic-qe's Claude Code provider disables Bash, edits,
web access, and subagents by default and has a 120-second request timeout
(source). Its OpenRouter provider uses bounded HTTP requests; make
the retry policy explicit in .agentic-qe/llm-config.json
(source):
{
"providers": {
"openrouter": {
"enabled": true,
"timeoutMs": 60000,
"maxRetries": 1,
"allowFallback": false
}
}
}
Agentic-kit's router projection preserves these provider-specific sibling fields. A failed or
timed-out jury/deeper seat must produce a skipped-seat note and REMAND; it must never fall back
to Claude and then grade Claude's defense.
5. Run commands outside the court, then review immutable evidence. Run builds, Cargo, tests,
security scanners, and mutation tools once through Agentic-QE or a supervised ak run --timeout
workflow. Give the resulting diff, logs, and reports to court seats as read-only evidence. The
court prompt must prohibit mcp__codex__codex, codex, nested MCP, builds, tests, and package
manager commands inside seats.
6. Verify before every court:
ak host status
aqe llm providers
aqe llm health
claude mcp get codex
The expected state is: Claude enabled and primary; Codex disabled; both claude-code and
openrouter healthy; qe-court panel valid; no project Codex MCP registration. If
claude mcp get codex still finds a project entry, agentic-kit did not own it. Inspect it first;
if it is the exact bridge being retired, remove it explicitly:
claude mcp remove codex --scope project
Current CLI boundary: agentic-kit has no existing command that assigns arbitrary qe-court
roles and models. It intentionally treats the court config as project-owned and validates it
read-only. The commands above establish the host/provider boundary; the JSON establishes the role
map. Do not invent or document a one-command ak court-profile surface unless a later ADR amends
the stable command contract.
4. Projects and responsibilities
| Project or actor |
Role in the path |
Accountable action |
Target |
pacphi/agentic-kit |
Provisions the bidirectional bridge, routes activities, and owns managed projections |
Guard the Claude → Codex bridge; add preflight, deadline, cleanup, status, docs, tests, and ADR updates |
Next patch release |
openai/codex |
Runs codex mcp-server, code-mode turns, sandbox policy, and nested MCP calls |
Diagnose the nested tool wait; add fail-fast cancellation/deadline semantics and clarify config propagation |
Upstream schedule |
proffesor-for-testing/agentic-qe |
Defines qe-court protocol/assets and has a bounded Codex provider path |
Repair asset packaging; add seat capability validation, prompt policy, and timeout; reconcile ADR-124 |
Next compatible release |
ruvnet/ruflo |
Provides nested MCP memory and swarm capabilities |
Assist only if the direct server or approval path reproduces independently |
Conditional |
stuinfla/ruvnet-brain |
Adds guidance/hooks around Codex sessions |
Assist only if a specific hook or injected instruction is shown causal |
Conditional |
| Anthropic Claude Code |
Hosts the project MCP client and background transport |
Optional client deadline/lifecycle improvement; no present root-cause assignment |
Follow-up |
| Court convener/operator |
Chooses seat profile and prompt capabilities |
Use inspection-only raw seats; route builds through supervised execution; capture timeout errors, not unbounded waits |
Immediate |
5. Multi-step action plan
5.1 Phase 0: contain and communicate
| What |
Where |
Owner |
When |
Deliverable |
| Document raw bridge limitations and safe seat prompts |
claude/dual-mode-reference.md, docs/TROUBLESHOOTING.md |
agentic-kit maintainer |
T+0, 2026-08-03–04 |
Inspection-only guidance with ak run handoff |
| Warn on an unguarded Codex projection |
src/commands/status.mjs, src/lib/mcp.mjs |
agentic-kit maintainer |
T+0–1 |
Actionable status finding |
| Adopt a temporary outer deadline in court operations |
Convener procedure and qe-court config notes |
Court convener |
Immediate |
Seat ends with timeout evidence within 120 seconds |
| Preserve and redact evidence |
Local rollout records; no public raw upload |
Incident lead |
Before issue filing |
Sanitized repro bundle |
5.2 Phase 1: file focused upstream issues
| Issue |
Owner |
When |
Required content |
Done when |
| Codex nested MCP/code-mode stall |
Incident lead in openai/codex |
T+0–1 |
Clean vs integrated control, exact 0.146.0 call shape, event boundary, deadline behavior, sanitized logs |
Public issue URL recorded here and linked to related reports |
| qe-court packaged asset is incomplete |
Incident lead in agentic-qe |
T+0–1 |
3.13.3/3.13.6 package-vs-source comparison, missing schema/import evidence, installer path |
Maintainer can reproduce from published artifact |
| qe-court lacks execution compatibility preflight |
Incident lead in agentic-qe |
T+0–1 |
Manual MCP bypass, sandbox/command mismatch, timeout requirement, suggested seat capabilities |
Requirement accepted or disposition documented |
Do not combine these into one cross-project issue. Each maintainer should receive the smallest reproduction inside their ownership boundary. Use the templates in Appendix E.
5.3 Phase 2: implement the guarded bridge
| Step |
Where |
Owner |
When |
QA gate |
| Add managed bridge configuration and validation |
Existing config/schema modules; no secrets |
agentic-kit implementer |
T+1 |
Invalid mode/timeout rejected at boundary |
| Add stdio proxy command around the real Codex server |
New focused module under src/lib/execution/ plus command wiring |
agentic-kit implementer |
T+1–2 |
Transparent initialize/list/call fixture passes |
| Add request preflight and developer instructions |
Proxy policy module |
agentic-kit implementer |
T+2 |
Read-only build request rejected; diff-only request forwarded |
| Add deadline, cancellation, and process-tree cleanup |
Proxy lifecycle module, reusing execution-runner patterns |
agentic-kit implementer |
T+2 |
Forced stall exits on time with no descendant left |
| Project guarded command instead of bare Codex |
src/lib/providers.mjs, .mcp.json ownership path |
agentic-kit implementer |
T+2 |
ak sync converges and preserves unrelated user entries |
| Report guarded/direct/drift state |
src/lib/mcp.mjs, status renderers |
agentic-kit implementer |
T+3 |
Status fixtures cover healthy, legacy, drift, unavailable |
| Spike scoped nested-MCP hook |
Managed Codex hook projection, isolated test home |
agentic-kit security reviewer |
T+3 |
Rule acts only on marked bridge sessions or remains opt-in |
The hook spike is not on the critical path. Official Codex documentation says PreToolUse can deny MCP and other local function calls, including the nested code-mode path, but specialized paths may bypass hooks (Codex hooks). The outer proxy deadline therefore remains the mandatory enforcement layer.
5.4 Phase 3: add court-aware preflight and routing
| What |
Where |
Owner |
When |
QA gate |
| Model seat capabilities: inspect, build, network, nested tools |
src/lib/qeCourt.mjs read-only awareness; upstream qe-court schema |
agentic-kit + agentic-qe maintainers |
T+3 |
Incompatible seat/prompt fails before dispatch |
| Route inspection seats to guarded MCP |
qe-court instructions and activity routing |
agentic-kit maintainer |
T+3 |
Diff-reading seat completes under read-only |
| Route build/test seats to supervised execution |
ak run templates/routes or agentic-qe ProviderManager |
agentic-kit + court convener |
T+3 |
Writable build seat is bounded and reports artifacts/errors |
| Repair self-contained referee installation |
agentic-qe asset build and installer |
agentic-qe maintainer |
Upstream |
Fresh install runs validator without source-tree imports |
| Reconcile design status |
agentic-qe ADR-124; agentic-kit ADRs as applicable |
Respective maintainers |
With implementation |
Status and Updated metadata match shipped behavior |
5.5 Phase 4: prove, release, and monitor
- Run the matrix in Appendix B on macOS with Codex
0.146.0 and the then-current stable Codex version.
- Run focused provider, MCP, status, qe-court, and execution-runner tests.
- Run
pnpm run check, pnpm run lint:md, and internal/external link checks.
- Review the projected
.mcp.json diff and prove unrelated user-managed MCP entries survive.
- Release in the next patch only after all mandatory criteria pass.
- During week 2, review issue responses and revise this plan's status, dates, and links.
6. Options considered
| Option |
Benefit |
Cost or failure mode |
Disposition |
| Wait for Codex upstream; change nothing |
No local code |
Leaves indefinite, silent stalls in an agentic-kit-managed projection |
Rejected |
| Documentation/status + developer instructions only |
Ships immediately and preserves ownership |
User steering can bypass it; no wall-clock enforcement |
Phase 0 containment |
| Prompt-only “do not run Cargo” wording |
Immediate and already correlated with completion |
Does not address the confirmed nested MCP wait; user steering can override it |
Containment only |
| Per-call config to disable plugins/MCP |
Narrow in theory |
Tested overrides did not remove loaded integrations in Codex 0.146.0 child sessions |
Rejected until proven upstream |
Isolated CODEX_HOME for court seats |
Clean control completed normally |
Auth/config portability, update, ownership, and user-expectation risks |
Diagnostic control; possible future profile |
Change all seats to danger-full-access |
Avoids some sandbox failures |
Excess privilege and still no proof it prevents nested MCP stalls |
Rejected |
Use workspace-write for Cargo |
Correct capability for build output |
Solves command compatibility, not the observed nested wait |
Recommended only for supervised build seats |
| Disable Ruflo/RuvNet plugins globally |
Removes integrated variables |
Broad collateral damage; direct Ruflo was healthy; violates external ownership |
Rejected |
Codex PreToolUse hook only |
Can deny supported nested MCP calls |
Documented exceptions; scope and propagation must be proven |
Optional defense-in-depth |
| Guarded stdio proxy only |
Provides preflight, deadline, cleanup, and stable diagnostics |
Cannot observe every internal call; needs robust JSON-RPC proxying |
Mandatory base |
| Guarded proxy + scoped hook + supervised routing |
Bounds the turn, blocks known traps, preserves build capability elsewhere |
More implementation and test work |
Recommended |
Route every seat through ak run/ProviderManager |
Existing timeout supervision |
May not preserve interactive court semantics for all seats |
Recommended for build/test seats |
| Remove the Claude → Codex bridge |
Eliminates this path |
Loses a documented ambidextrous capability |
Rejected |
| Export referee subpath or copy TypeScript |
Reuses canonical source |
Global installs cannot reliably import the subpath; consumers may lack a transpiler |
Rejected as sole packaging fix |
| Handwrite a second installed referee |
Simple artifact |
Duplicates policy and will drift |
Rejected |
Generate installed JavaScript, then expose aqe court validate |
Self-contained short-term artifact and stable long-term API |
Requires release artifact tests and CLI design |
Recommended agentic-qe path |
7. Acceptance and exit criteria
The patch is releasable only when all mandatory criteria pass:
- A
read-only request that demands Cargo/build/test output is rejected before Codex starts, with a
remediation pointing to a supervised writable route.
- A forced nested-memory stall is either blocked by a proven scoped hook or terminated by the outer
deadline. It never remains indefinitely “working.”
- A normal diff/grep-only inspection request completes through the guarded bridge.
- A build-capable request completes or fails within the configured
ak run/provider timeout.
- Timeout termination removes the Codex child and descendants; no orphan session remains.
- Guarded/direct mode and drift are visible in human and JSON status output.
ak sync is convergent and does not mutate user-owned plugin caches, Codex settings, or unrelated
MCP registrations.
- Diagnostics identify phase, elapsed time, policy decision, and child exit state without logging
source, prompt text, credentials, or environment secrets by default.
- Focused tests and the full project check pass on supported Node versions.
- ADR-0016, ADR-0018, and ADR-0020 are reviewed; any behavior-changing decision gets an
Updated
entry and implementation evidence in the same patch.
- Upstream issue links and dispositions are added to this living plan.
8. Risks, dependencies, and open questions
- Exact Codex mechanism remains unresolved. The evidence locates the wait at a nested MCP
promise, but does not yet distinguish Codex orchestration, elicitation, cancellation, or an
interaction with plugin-provided machinery.
- Hook scoping may be insufficient. A global nested-MCP denial would break legitimate Codex
work. The default hook requires a reliable bridge-session marker and isolated-home proof.
- JSON-RPC proxy correctness is security-sensitive. Preserve framing, backpressure, stderr,
cancellation, request IDs, and shutdown semantics; reject malformed input at the boundary.
- Timeout selection is policy, not truth. Start at 120 seconds for raw court seats, expose a
bounded configuration, and use telemetry before increasing it.
- Upstream version drift matters. Re-run controls against current Codex before implementation;
do not assume 0.146.0 behavior is permanent.
- Ownership must remain precise. Agentic-kit may replace the projection it owns, but must not
adopt or rewrite user-owned Codex plugin state.
- Decision required after the hook spike: enable a bridge-scoped deny by default, keep it opt-in,
or omit it and rely on the proxy deadline plus routing.
Appendix A: incident background
A.1 Reported symptom
During phase 2 of a qe-court, three of four Codex-routed prosecutor calls produced no output for
more than 35 minutes and were killed manually. The hung prompts asked for Cargo commands under
sandbox: "read-only" and approval-policy: "never"; diff-reading prompts completed. The path was:
Claude Code → mcp__codex__codex → project .mcp.json → codex mcp-server 0.146.0 → Codex turn
The local Codex configuration also loaded Ruflo and RuvNet Brain integrations. Completed calls
showed the Brain guidance footer, which made plugin interaction a reasonable hypothesis but not
proof of fault.
A.2 Corrected forensic conclusion
Rollout inspection showed that all three stalled seats entered code mode and awaited a nested
mcp__ruflo__memory_search. No shell or Cargo call followed. The original “Cargo cannot write
target/ and Codex retries forever” mechanism is therefore disproved for this incident.
The strongest supported conclusion is:
Codex MCP sessions with the integrated configuration can stall indefinitely while a code-mode
turn awaits a nested MCP call; the exact allocation between Codex core and integration
interaction remains open.
A.3 Why the distinction matters
Changing read-only to workspace-write is correct for an intentional build, but it does not fix
the observed stall. Filing the incident as a Cargo sandbox bug would send upstream maintainers the
wrong reproduction. The action plan therefore bounds every raw seat while separately validating
command/sandbox compatibility.
Appendix B: experiments and fault tree
B.1 Experiment matrix
| Case |
Integration state |
Prompt/action |
Sandbox |
Result |
Interpretation |
| Three incident seats |
Ruflo/Brain loaded |
Prosecutor prompts that later mentioned Cargo |
Read-only/never |
Stalled at nested memory_search; no shell event |
Confirms event boundary, not Cargo causality |
| Memory-only reproduction |
Ruflo/Brain loaded |
Invoke nested Ruflo memory search |
Read-only/never |
Exceeded 90-second outer deadline |
Reproduces class without Cargo |
| Isolated Codex home |
Plugins/MCP absent |
Equivalent analysis prompt |
Read-only/never |
Returned in about 9 seconds |
Integrated state is required for observed reproduction |
| Direct Ruflo calls |
Ruflo server directly |
memory_search |
N/A |
31–61 ms |
Ruflo server is not independently slow |
| Cargo controls |
Plugin-free |
cargo test under read-only |
Read-only/never |
Exit 101 and final response in 11–16 seconds |
Sandbox denial fails fast in the control |
| Diff-only court seats |
Integrated |
Git/grep/reasoning only |
Read-only/never |
Returned in about 5–25 minutes |
Raw path can complete, but remains unbounded |
Times are observed local measurements, not service-level guarantees.
B.2 Revised fault tree
- H1 — Codex MCP/code-mode orchestration: still primary for upstream research. Discriminator:
reproduce nested MCP waiting with the smallest non-Ruflo MCP server and clean plugin setup.
- H2 — agentic-kit provisioning: owns lack of caller-side bounding and guardrails. It does not
own Codex plugin lifecycle. Discriminator: guarded proxy prevents unbounded impact regardless of
child cause.
- H3 — qe-court installation/config: owns missing validation assets and absent seat capability
contract. It did not execute through agentic-qe's provider timeout in this manual court.
- Plugin-specific fault: unproven. Discriminator: enable Ruflo and Brain separately, then compare
code-mode nested calls, hook traces, and approval events.
Appendix C: current architecture and ownership
C.1 Request path
Agentic-kit currently registers Codex in Claude Code as a project-scoped stdio MCP server. Codex then independently reads its home configuration and can register Ruflo as a nested MCP server. Claude Code's project scope is shared through .mcp.json, while user and plugin scopes have their own precedence rules (Claude Code MCP scopes).
C.2 Current agentic-kit seams
src/lib/providers.mjs: ensureCodexMcp() projects bare codex mcp-server and records
agentic-kit ownership of that MCP entry (source).
src/lib/mcp.mjs: detects Claude → Codex and Codex → Ruflo registration state.
src/lib/qeCourt.mjs: validates read-only awareness and an existing qe-court config; it does not
implement or dispatch the court protocol (source).
claude/dual-mode-reference.md: documents the bidirectional bridge and ak run as the canonical
activity pipeline (source).
C.3 ADR constraints
- ADR-0016 requires capability-driven adapters, precise ownership, and convergent
managed projections. The wrapper may replace only the Codex MCP projection agentic-kit owns.
- ADR-0018 makes
ak run canonical for supervised host-worker execution and defines
per-attempt timeout/cancellation behavior.
- ADR-0020 establishes one stable GA surface per capability; the guard should extend
the existing bridge and ak run, not add a competing public execution command.
Appendix D: proposed configuration and behavior
D.1 Managed configuration sketch
The exact schema should follow existing agentic-kit configuration conventions. The intended policy is equivalent to:
{
"codexBridge": {
"mode": "guarded",
"timeoutMs": 120000,
"readOnlyPolicy": "inspect-only",
"nestedMcp": "deny-when-scoped"
}
}
nestedMcp must remain deadline-only or opt-in if bridge-only hook scoping cannot be proven.
D.2 Guard decisions
| Request |
Decision |
Message or route |
| Read-only + explicit build/test/package install |
Reject before child call |
Use ak run with a writable activity route |
| Read-only + edit/write instruction |
Reject before child call |
Select an authorized writable workflow |
| Read-only + diff/grep/read-only inspection |
Forward with inspection developer instructions |
Guarded Codex seat |
| Workspace-write requested through raw court bridge |
Reject or require explicit direct escape hatch |
Prefer ak run supervision |
| Nested MCP attempted in a proven marked bridge session |
Deny via scoped hook |
Return limitation to the model |
| Any forwarded request exceeds deadline |
Cancel, terminate tree, return structured timeout |
Include elapsed phase and remediation |
Preflight is deliberately conservative and must not pretend natural-language classification is a security boundary. The outer deadline and sandbox remain enforcement layers.
D.3 Timeout and cleanup contract
- Deadline is absolute per top-level
codex request, not reset by progress events.
- On expiry: send protocol cancellation if available, close stdin, send graceful termination, then
force-kill the validated descendant process group after a short grace period.
- Return one terminal MCP error with a stable agentic-kit error code.
- Record timestamps, PID identities, exit/signal, and cleanup result; redact prompts and content.
- Never target a broad or unresolved process set. Validate the spawned child/process group first.
Appendix E: issue filing packages
E.1 OpenAI Codex
Title: mcp-server turn can hang indefinitely awaiting nested MCP tool in code mode
Include Codex 0.146.0, macOS/architecture, stdio client, sandbox/approval values, exact final rollout
event, a tiny nested MCP server, clean/integrated controls, and external timeout result. Ask for a
per-turn deadline, cancellation propagation, fail-fast terminal response, and documented per-call
config behavior. Link related but non-identical reports
Codex #11816, Codex #18243, and
codex-plugin-cc #258. Explicitly state that Cargo failed fast in controls.
E.2 agentic-qe packaging
Title: qe-court installed asset is not self-contained: referee/schema omitted or source-bound
Compare the published 3.13.3 and later package revision footprint with the cited source implementations:
the referee, skills installer, and
asset preparation script. Provide a fresh-install reproduction and expected
self-contained validator behavior. Request an artifact test in release CI.
E.3 agentic-qe execution policy
Title: qe-court seats need sandbox capability preflight and bounded provider execution
Explain that the manual MCP path bypassed the bounded Codex provider.
Propose declared seat capabilities, sandbox-aware templates, a pre-dispatch compatibility error,
and a required timeout for every provider/manual adapter. Ask maintainers to reconcile shipped
scope with ADR-124's Proposed status.
Appendix F: evidence handling
The primary incident artifacts are local Codex rollout JSONL files, the emailibrium court record, the installed qe-court footprint, and a local session lesson. They may contain private prompts, paths, repository content, or machine metadata.
- Keep originals local and immutable during issue preparation.
- Publish a minimized reproduction in a disposable Rust repository or synthetic MCP server.
- Replace usernames, absolute paths, session IDs, and unrelated MCP configuration.
- Include only the events needed to establish request parameters, final completed event, elapsed
time, cancellation, and process cleanup.
- Label measurements as observations and causal claims as confirmed, disproved, or open.
Appendix G: public references
All references below were accessed on 2026-08-03. Source-code links are pinned where a revision was used in the investigation.
- OpenAI, Codex hooks documentation. Documents
PreToolUse coverage, deny
responses, and the warning that specialized paths can opt out.
- OpenAI, Use Codex with the Agents SDK. Documents
codex mcp-server as a
long-lived stdio server and shows caller-side session timeout configuration.
- OpenAI Codex, issue #11816. Related indefinite MCP/elicitation wait.
- OpenAI Codex, issue #18243. Related macOS MCP sandbox setup failure.
- OpenAI Codex Claude Code plugin, issue #258. Related nested MCP
elicitation stall under read-only/never.
- Anthropic, Claude Code MCP documentation. Defines project-scoped
.mcp.json
stdio servers and scope precedence.
- OpenAI Codex 0.146.0,
codex_tool_config.rs and
release. Pinned incident-version tool configuration and release context.
- agentic-kit, repository, Codex projection,
qe-court awareness, and dual-host reference.
- agentic-kit, ADR-0016, ADR-0018, and
ADR-0020. Current ownership, execution, and stable-surface constraints.
- agentic-qe, ADR-124, referee,
skills installer, Codex provider, and
asset preparation. The revision comparison showed no
relevant repair at the evidence cutoff.
- Ruflo, repository and MCP tools reference. Public project and
memory-tool reference.
- RuvNet Brain, repository. Public integration project.
- OpenRouter model records for DeepSeek V4 Flash,
GLM 5.2, Gemini 3.5 Flash,
GPT-5.6 Terra, and GPT-5.6 Sol.
Codex qe-court seat stall: action plan
pacphi/agentic-kitmaintainersThis document separates confirmed evidence from hypotheses. It does not itself change an
accepted architecture decision. Implementation that changes managed projections or execution
behavior must update the affected agentic-kit ADRs in the same change.
Table of contents
1. Executive brief
Three Codex-routed prosecutor seats stalled during a qe-court run. The initial correlation with
prompts requesting Cargo under a read-only sandbox was real, but controlled reproduction disproved
Cargo as the direct trigger. The three stalled rollouts never reached Cargo or a shell command;
each stopped while a Codex code-mode turn awaited a nested
mcp__ruflo__memory_searchcall. Aplugin-enabled memory-only reproduction also exceeded a 90-second external deadline. In contrast,
an isolated Codex configuration returned normally, direct Ruflo memory search completed in tens of
milliseconds, and plugin-free Cargo controls failed fast under
read-onlyplusnever.The confirmed fault boundary is therefore an unbounded Codex MCP/code-mode session interacting
with nested MCP machinery, not Cargo writes alone. Existing public reports show related classes of
Codex MCP sessions stalling around approvals, elicitation, or sandbox setup, but none proves the
exact local mechanism (Codex #11816, Codex #18243,
codex-plugin-cc #258).
The recommended response has three layers:
build commands in that profile, and impose an operator-visible deadline.
codex mcp-serverprojection with a guarded stdiobridge that injects policy, rejects incompatible requests, enforces an absolute timeout, and
terminates the child process tree. Add a scoped Codex
PreToolUsecircuit breaker only afterproving its bridge-only scope; Codex documents hooks as useful guardrails rather than complete
enforcement boundaries (Codex hooks).
agentic-qe issues for the incomplete qe-court asset plus missing execution-policy preflight.
Route build-capable seats through supervised
ak runor agentic-qe's bounded provider path.2. Actions at a glance
read-only bridge. See Phase 0.
minimal reproductions. See Phase 1.
cleanup, status diagnostics, and explicit direct-mode escape hatch. See
Phase 2.
ak runrather than the raw seat bridge. SeePhase 3.
pnpm run check, Markdown lint,link checks, and ADR reconciliation. See exit criteria.
PreToolUserule is proven safeenough to enable by default. See open questions.
3. Recommended course of action
3.1 Immediate containment
Keep the bridge available, because peer-host delegation is a core ambidextrous capability. Change
its default contract from “arbitrary autonomous worker” to “bounded inspection seat” until the
nested-call failure is understood.
calls under the read-only seat profile; return a clear limitation instead.
workspace-writethrough supervisedak run, with networkpolicy and timeout stated by the activity route.
than the 35-minute incident stalls and can be tuned after telemetry exists.
directmode for debugging, but warn that it bypasses agentic-kitsupervision.
3.2 Guarded bridge as the agentic-kit default
Agentic-kit owns the project-scoped Claude → Codex projection, so it is the correct place for the portable workaround. Claude Code supports project-scoped stdio MCP definitions in
.mcp.json(Claude Code MCP scopes); agentic-kit should project its own wrapper command there instead of projecting barecodex mcp-server. Because this makes agentic-kit responsible for a new supervised boundary, implementation requires an ADR-0020 amendment or a new ADR before the guarded projection becomes the default.The wrapper should:
codex mcp-serverand transparently proxy stdio JSON-RPC.codextool requests before forwarding them.developer-instructionsand a trace marker.remediation message.
ak statusand repair it throughak sync.The wrapper must not claim it can disable user-owned Codex plugins per request. That override was not effective in the observed Codex 0.146.0 child sessions. Plugin state remains externally owned.
3.3 Upstream fixes and coordination
mcp-server, reliablecancellation of nested code-mode tool promises, and documented propagation of per-call config.
The official Agents SDK example places a timeout on the MCP client, which supports the need for
caller-side bounding but does not solve child cleanup by itself
(Codex MCP server guide).
seat execution policy that validates sandbox/command compatibility and applies a deadline.
Upstream ADR-124 is still marked Proposed at the cited revision despite implementation artifacts
being present (ADR-124).
search was healthy. Engage these maintainers only if a direct server-level reproduction or a
plugin hook contribution is isolated.
tool call worked. Consider a client-side timeout/lifecycle feature request after the agentic-kit
wrapper proves the desired semantics.
3.4 Completely avert: Claude + OpenRouter court
Use this profile when avoiding the incident path is more important than preserving Codex as a
court participant. It removes every Codex seat and disables agentic-kit's managed Claude ↔ Codex
bridge. Claude remains the driving host; court inference uses only the bounded
claude-codeandopenrouterproviders through agentic-qe's ProviderManager.1. Load the OpenRouter key from a shell profile or secret manager. Keep
OPENROUTER_API_KEYout ofkit.json,.agentic-qe/llm-config.json, and the court config.2. Apply the part agentic-kit owns with existing commands:
--host claudeis the complete desired host set. It disables Codex and removes only the twoCodex MCP registrations owned by agentic-kit.
--aqe-fallback nonerecords that this court mustnot silently substitute one provider for another. If an older agentic-kit-managed
.agentic-qe/llm-config.jsonstill containsfallbackChain, remove that stale block or set itsentriesto[]before convening; the current Claude-only no-policy projection does not erase anold on-disk chain merely because the persisted chain is empty.
3. Set these operational fields in the project-owned
.claude/skills/qe-court/config.json. Preserve its$schema, descriptions, and other metadata:{ "prosecutors": [ "devils-advocate", "brutal-honesty", "sherlock", "security-scanner", "mutation" ], "overturnDepth": 2, "emitScore": false, "routing": { "defense": { "provider": "claude-code", "model": "sonnet" }, "prosecutor.devils-advocate": { "provider": "openrouter", "model": "deepseek/deepseek-v4-flash" }, "prosecutor.brutal-honesty": { "provider": "claude-code", "model": "opus" }, "prosecutor.sherlock": { "provider": "openrouter", "model": "z-ai/glm-5.2" }, "prosecutor.security-scanner": { "provider": "openrouter", "model": "google/gemini-3.5-flash" }, "prosecutor.mutation": { "provider": "openrouter", "model": "google/gemini-3.5-flash" }, "jury": { "provider": "openrouter", "model": "openai/gpt-5.6-terra" }, "deeperReviewer": { "provider": "openrouter", "model": "openai/gpt-5.6-sol" } }, "options": { "blindFiling": true, "writerIsNeverJuror": true, "minDistinctVendors": 2, "requireDoeGatedScore": true, "signCourtRecord": true } }The candidate panel passes agentic-kit's current
validateCourtConfig()with no violations.The OpenRouter slugs were verified at the evidence cutoff:
DeepSeek V4 Flash for inexpensive adversarial breadth,
GLM 5.2 for deductive review,
Gemini 3.5 Flash for fast security/mutation evidence interpretation,
GPT-5.6 Terra for the jury, and
GPT-5.6 Sol only as the expensive overturn ceiling.
Do not use an
anthropic/*OpenRouter model in the jury. The current validator maps the providername
openrouterto one coarse vendor and does not inspect the model slug's underlying modelmaker; an Anthropic-via-OpenRouter jury could therefore pass the structural check while violating
the substantive writer-versus-juror independence goal.
4. Keep provider attempts bounded. Agentic-qe's Claude Code provider disables Bash, edits,
web access, and subagents by default and has a 120-second request timeout
(source). Its OpenRouter provider uses bounded HTTP requests; make
the retry policy explicit in
.agentic-qe/llm-config.json(source):
{ "providers": { "openrouter": { "enabled": true, "timeoutMs": 60000, "maxRetries": 1, "allowFallback": false } } }Agentic-kit's router projection preserves these provider-specific sibling fields. A failed or
timed-out jury/deeper seat must produce a skipped-seat note and
REMAND; it must never fall backto Claude and then grade Claude's defense.
5. Run commands outside the court, then review immutable evidence. Run builds, Cargo, tests,
security scanners, and mutation tools once through Agentic-QE or a supervised
ak run --timeoutworkflow. Give the resulting diff, logs, and reports to court seats as read-only evidence. The
court prompt must prohibit
mcp__codex__codex,codex, nested MCP, builds, tests, and packagemanager commands inside seats.
6. Verify before every court:
The expected state is: Claude enabled and primary; Codex disabled; both
claude-codeandopenrouterhealthy; qe-court panel valid; no project Codex MCP registration. Ifclaude mcp get codexstill finds a project entry, agentic-kit did not own it. Inspect it first;if it is the exact bridge being retired, remove it explicitly:
Current CLI boundary: agentic-kit has no existing command that assigns arbitrary qe-court
roles and models. It intentionally treats the court config as project-owned and validates it
read-only. The commands above establish the host/provider boundary; the JSON establishes the role
map. Do not invent or document a one-command
ak court-profilesurface unless a later ADR amendsthe stable command contract.
4. Projects and responsibilities
pacphi/agentic-kitopenai/codexcodex mcp-server, code-mode turns, sandbox policy, and nested MCP callsproffesor-for-testing/agentic-qeruvnet/ruflostuinfla/ruvnet-brain5. Multi-step action plan
5.1 Phase 0: contain and communicate
claude/dual-mode-reference.md,docs/TROUBLESHOOTING.mdak runhandoffsrc/commands/status.mjs,src/lib/mcp.mjs5.2 Phase 1: file focused upstream issues
openai/codexagentic-qeagentic-qeDo not combine these into one cross-project issue. Each maintainer should receive the smallest reproduction inside their ownership boundary. Use the templates in Appendix E.
5.3 Phase 2: implement the guarded bridge
src/lib/execution/plus command wiringsrc/lib/providers.mjs,.mcp.jsonownership pathak syncconverges and preserves unrelated user entriessrc/lib/mcp.mjs, status renderersThe hook spike is not on the critical path. Official Codex documentation says
PreToolUsecan deny MCP and other local function calls, including the nested code-mode path, but specialized paths may bypass hooks (Codex hooks). The outer proxy deadline therefore remains the mandatory enforcement layer.5.4 Phase 3: add court-aware preflight and routing
src/lib/qeCourt.mjsread-only awareness; upstream qe-court schemaak runtemplates/routes or agentic-qe ProviderManagerUpdatedmetadata match shipped behavior5.5 Phase 4: prove, release, and monitor
0.146.0 and the then-current stable Codex version.
pnpm run check,pnpm run lint:md, and internal/external link checks..mcp.jsondiff and prove unrelated user-managed MCP entries survive.6. Options considered
CODEX_HOMEfor court seatsdanger-full-accessworkspace-writefor CargoPreToolUsehook onlyak run/ProviderManageraqe court validate7. Acceptance and exit criteria
The patch is releasable only when all mandatory criteria pass:
read-onlyrequest that demands Cargo/build/test output is rejected before Codex starts, with aremediation pointing to a supervised writable route.
deadline. It never remains indefinitely “working.”
ak run/provider timeout.ak syncis convergent and does not mutate user-owned plugin caches, Codex settings, or unrelatedMCP registrations.
source, prompt text, credentials, or environment secrets by default.
Updatedentry and implementation evidence in the same patch.
8. Risks, dependencies, and open questions
promise, but does not yet distinguish Codex orchestration, elicitation, cancellation, or an
interaction with plugin-provided machinery.
work. The default hook requires a reliable bridge-session marker and isolated-home proof.
cancellation, request IDs, and shutdown semantics; reject malformed input at the boundary.
bounded configuration, and use telemetry before increasing it.
do not assume 0.146.0 behavior is permanent.
adopt or rewrite user-owned Codex plugin state.
or omit it and rely on the proxy deadline plus routing.
Appendix A: incident background
A.1 Reported symptom
During phase 2 of a qe-court, three of four Codex-routed prosecutor calls produced no output for
more than 35 minutes and were killed manually. The hung prompts asked for Cargo commands under
sandbox: "read-only"andapproval-policy: "never"; diff-reading prompts completed. The path was:Claude Code → mcp__codex__codex → project .mcp.json → codex mcp-server 0.146.0 → Codex turnThe local Codex configuration also loaded Ruflo and RuvNet Brain integrations. Completed calls
showed the Brain guidance footer, which made plugin interaction a reasonable hypothesis but not
proof of fault.
A.2 Corrected forensic conclusion
Rollout inspection showed that all three stalled seats entered code mode and awaited a nested
mcp__ruflo__memory_search. No shell or Cargo call followed. The original “Cargo cannot writetarget/and Codex retries forever” mechanism is therefore disproved for this incident.The strongest supported conclusion is:
A.3 Why the distinction matters
Changing
read-onlytoworkspace-writeis correct for an intentional build, but it does not fixthe observed stall. Filing the incident as a Cargo sandbox bug would send upstream maintainers the
wrong reproduction. The action plan therefore bounds every raw seat while separately validating
command/sandbox compatibility.
Appendix B: experiments and fault tree
B.1 Experiment matrix
memory_search; no shell eventmemory_searchcargo testunder read-onlyTimes are observed local measurements, not service-level guarantees.
B.2 Revised fault tree
reproduce nested MCP waiting with the smallest non-Ruflo MCP server and clean plugin setup.
own Codex plugin lifecycle. Discriminator: guarded proxy prevents unbounded impact regardless of
child cause.
contract. It did not execute through agentic-qe's provider timeout in this manual court.
code-mode nested calls, hook traces, and approval events.
Appendix C: current architecture and ownership
C.1 Request path
Agentic-kit currently registers Codex in Claude Code as a project-scoped stdio MCP server. Codex then independently reads its home configuration and can register Ruflo as a nested MCP server. Claude Code's project scope is shared through
.mcp.json, while user and plugin scopes have their own precedence rules (Claude Code MCP scopes).C.2 Current agentic-kit seams
src/lib/providers.mjs:ensureCodexMcp()projects barecodex mcp-serverand recordsagentic-kit ownership of that MCP entry (source).
src/lib/mcp.mjs: detects Claude → Codex and Codex → Ruflo registration state.src/lib/qeCourt.mjs: validates read-only awareness and an existing qe-court config; it does notimplement or dispatch the court protocol (source).
claude/dual-mode-reference.md: documents the bidirectional bridge andak runas the canonicalactivity pipeline (source).
C.3 ADR constraints
managed projections. The wrapper may replace only the Codex MCP projection agentic-kit owns.
ak runcanonical for supervised host-worker execution and definesper-attempt timeout/cancellation behavior.
the existing bridge and
ak run, not add a competing public execution command.Appendix D: proposed configuration and behavior
D.1 Managed configuration sketch
The exact schema should follow existing agentic-kit configuration conventions. The intended policy is equivalent to:
{ "codexBridge": { "mode": "guarded", "timeoutMs": 120000, "readOnlyPolicy": "inspect-only", "nestedMcp": "deny-when-scoped" } }nestedMcpmust remaindeadline-onlyor opt-in if bridge-only hook scoping cannot be proven.D.2 Guard decisions
ak runwith a writable activity routeak runsupervisionPreflight is deliberately conservative and must not pretend natural-language classification is a security boundary. The outer deadline and sandbox remain enforcement layers.
D.3 Timeout and cleanup contract
codexrequest, not reset by progress events.force-kill the validated descendant process group after a short grace period.
Appendix E: issue filing packages
E.1 OpenAI Codex
Title:
mcp-serverturn can hang indefinitely awaiting nested MCP tool in code modeInclude Codex 0.146.0, macOS/architecture, stdio client, sandbox/approval values, exact final rollout
event, a tiny nested MCP server, clean/integrated controls, and external timeout result. Ask for a
per-turn deadline, cancellation propagation, fail-fast terminal response, and documented per-call
config behavior. Link related but non-identical reports
Codex #11816, Codex #18243, and
codex-plugin-cc #258. Explicitly state that Cargo failed fast in controls.
E.2 agentic-qe packaging
Title: qe-court installed asset is not self-contained: referee/schema omitted or source-bound
Compare the published 3.13.3 and later package revision footprint with the cited source implementations:
the referee, skills installer, and
asset preparation script. Provide a fresh-install reproduction and expected
self-contained validator behavior. Request an artifact test in release CI.
E.3 agentic-qe execution policy
Title: qe-court seats need sandbox capability preflight and bounded provider execution
Explain that the manual MCP path bypassed the bounded Codex provider.
Propose declared seat capabilities, sandbox-aware templates, a pre-dispatch compatibility error,
and a required timeout for every provider/manual adapter. Ask maintainers to reconcile shipped
scope with ADR-124's Proposed status.
Appendix F: evidence handling
The primary incident artifacts are local Codex rollout JSONL files, the emailibrium court record, the installed qe-court footprint, and a local session lesson. They may contain private prompts, paths, repository content, or machine metadata.
time, cancellation, and process cleanup.
Appendix G: public references
All references below were accessed on 2026-08-03. Source-code links are pinned where a revision was used in the investigation.
PreToolUsecoverage, denyresponses, and the warning that specialized paths can opt out.
codex mcp-serveras along-lived stdio server and shows caller-side session timeout configuration.
elicitation stall under read-only/never.
.mcp.jsonstdio servers and scope precedence.
codex_tool_config.rsandrelease. Pinned incident-version tool configuration and release context.
qe-court awareness, and dual-host reference.
ADR-0020. Current ownership, execution, and stable-surface constraints.
skills installer, Codex provider, and
asset preparation. The revision comparison showed no
relevant repair at the evidence cutoff.
memory-tool reference.
GLM 5.2, Gemini 3.5 Flash,
GPT-5.6 Terra, and GPT-5.6 Sol.