Repository navigation
0.14.0 — the Claude approve-and-execute experience, on Codex - #12
Merged
Merged
Conversation
A new stdio JSON-RPC surface for the pythia MCP approver: mcp_handle answers initialize (echoing the client's protocol version, declaring a tools capability), the initialized notification (silently), and tools/list (one tool, pythia_approve). Unknown methods get a JSON-RPC method-not-found error, never a crash. Hand-rolled with json + stdio, stdlib only. tests/test_mcp.py is new and wired into CI and the bench suite list, so the whole approver is CI-covered from the first commit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mcp_approve_decision is the security-critical logic, kept transport-free: it takes an elicit(message, schema) callable, builds pythia's own card from the journal, and mints the grant (approver=mcp) ONLY when the elicitation returns accept with decision Approve. A Reject, a decline, a cancel, an unknown or applied token, or an elicit that raises — all fail closed, minting nothing. Reuses approval_card and mint_grant, so an MCP-minted grant is identical to a console one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mcp_serve is the stdio loop: newline-delimited JSON-RPC in and out. A tools/call for pythia_approve runs the elicitation round-trip inline — send elicitation/create, read until the matching-id response, ignore anything interleaved — then answers the call with the decision's tool result. One call in flight at a time, which is how Codex drives tools in a turn. cmd_mcp runs it on real stdio; the command is registered no-DB and given its place in the guide so the coherence lint passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The stdlib cannot parse or write TOML on 3.9, so these never parse it. Both merges use a marker-delimited block: merge_codex_mcp_config appends [mcp_servers.pythia] + mcp_elicitations when neither table is present (else refuses, so the developer's TOML is never corrupted); merge_codex_requirements writes a fresh requirements.toml forbidding danger-full-access and never (else refuses on an existing file). The caller prints what to add on a conflict. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cmd_install's project branch now calls report_codex_mcp after the Codex hooks: it registers [mcp_servers.pythia] in .codex/config.toml, enables mcp_elicitations, and writes .codex/requirements.toml forbidding danger-full-access — the pin that keeps elicitations reaching a human. On a table collision or a pre-existing requirements.toml it prints what to add instead of touching the file. --no-hooks skips it; -g does not register the server, as the guide stays per-project. Verified end to end by driving the real subprocess over OS pipes: initialize, tools/list, a pythia_approve call, an elicitation answered Approve, and a minted grant with approver=mcp. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A write-free MCP approver (pythia mcp) gives Codex the inline approve-and-run UX via MCP elicitation: the agent calls pythia_approve, Codex shows the card as a select prompt, and the developer's Approve mints the same grant the console mints. install registers the server and pins the sandbox so elicitations always reach a human. Four manifests bumped, CHANGELOG in the repo voice. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
0.13.0 put the harness on Codex but left approval on a second terminal. This gives Codex the Claude approve-and-execute UX — the agent asks, a select prompt appears, the developer clicks Approve, the write runs — inline, without weakening the gate.
Why an MCP approver
Codex's hooks cannot read a human's answer to a prompt and it has no custom question tool (openai/codex#28833, #23465), so Claude's
AskUserQuestion+ hook mint has no analog. The one mechanism that carries a verified human choice back to pythia is MCP elicitation (Codex ≥ v0.120): a server issues a structured request, Codex renders the select UI, and the answer returns to the server — the agent cannot fabricate it. IDEAS.md already sanctioned a write-free MCP approver (writes never go through MCP).What changed
pythia mcp— a stdio JSON-RPC server, stdlib only, write-free, one toolpythia_approve(token). It builds pythia's own card from the journal, issues anelicitation/createwith a{Approve, Reject}enum, and mints the same grant the console mints (approver="mcp") only on an explicit accept-with-Approve. A Reject, decline, cancel, unknown/applied token, or any transport error fails closed.pythia installregisters[mcp_servers.pythia]+mcp_elicitations = truein.codex/config.tomland writes.codex/requirements.tomlforbiddingdanger-full-access(which auto-approves elicitations) andnever. Both are append-only and refuse to touch a file that already defines those tables — the stdlib cannot safely merge TOML, so a conflict prints what to add instead.--no-hooksskips it;-gdoes not register the server.apply --confirmstill verifies the grant itself. The consolepythia approve <token>stays as the fallback for older Codex and headless runs — nothing regresses.Verification
tests/test_mcp.py, wired into CI and the bench suite list: transport handshake/tools-list, the fail-closed mint logic (a fake elicit for every accept/reject/decline/cancel/error path), the fullmcp_serveloop via a scripted client, and both TOML merges (append, idempotent, preserve, refuse-on-collision).python -m pythia mcpsubprocess was driven over OS pipes end to end: initialize, tools/list, apythia_approvecall, an elicitation answered Approve, a grant mintedapprover="mcp".elicitation/createmethod name matches the installed Codex — the field test. The method name is isolated in one constant (MCP_ELICIT_METHOD) if it needs adjusting.🤖 Generated with Claude Code