Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 38 additions & 17 deletions connectors/codex/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,67 @@ as Claude — `POST /mcp` with a member token — and gets the same tool surface
gated by the same capability RBAC. Identity is derived by the pot from the token,
never from anything Codex says about itself.

For the topology-A headless driver (BYOA slice 2), see
[`scripts/codex-worker.py`](../../scripts/codex-worker.py) — `codex exec`
with `--sandbox` + `--json`, land-at-review via `runtime-adapter/v1`.

## Connect

Codex reads MCP servers from its config (`~/.codex/config.toml`, or the JSON form
some builds use). Add a `mupot` server pointing at your pot's `/mcp` endpoint with
your member token.
Codex reads MCP servers from `~/.codex/config.toml`. Add a `mupot` server
pointing at your pot's `/mcp` endpoint. **Streamable-HTTP only** — Codex does
**not** support SSE for remote MCP.

### TOML form (`~/.codex/config.toml`)
### TOML form (`~/.codex/config.toml`) — preferred

See [`config.toml`](./config.toml):

```toml
[mcp_servers.mupot]
type = "sse"
url = "https://YOUR-POT.example.workers.dev/mcp"

[mcp_servers.mupot.headers]
Authorization = "Bearer <MUPOT_MEMBER_TOKEN>"
bearer_token_env_var = "MUPOT_MCP_TOKEN"
# then: export MUPOT_MCP_TOKEN=<MEMBER_TOKEN>
```

### JSON form (Codex builds that share Claude's `.mcp.json` shape)
Do **not** set `type = "sse"`. The token comes from an env var so the raw value
never lands in the config file.

See [`mcp.json`](./mcp.json) — identical structure to the Claude connector's
`.mcp.json`.
### JSON form (some Codex builds that share Claude's `.mcp.json` shape)

See [`mcp.json`](./mcp.json) — use `type: "http"`, never `"sse"`. Prefer the
TOML + `bearer_token_env_var` form above for Codex CLI.

## Fill in

1. Replace `YOUR-POT.example.workers.dev` with **your** pot's host.
2. Replace `<MUPOT_MEMBER_TOKEN>` with the raw member token your pot minted
(`channel: workspace`). See the top-level [connectors README](../README.md) for
how to mint one. **Never commit the filled-in file.**
2. Export `MUPOT_MCP_TOKEN` (or your chosen env var) to the raw member token your
pot minted (`channel: workspace`). See the top-level
[connectors README](../README.md) for how to mint one. **Never commit the
token.**

Verify the tool surface (no token needed for discovery; token needed for calls):

Verify the tool surface (no token needed):
```bash
curl -sS https://YOUR-POT.example.workers.dev/mcp \
-H "Authorization: Bearer $MUPOT_MCP_TOKEN" \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

## Headless driver (topology A)

```bash
curl https://YOUR-POT.example.workers.dev/mcp/tools
# Plan mint + attach without live Codex creds:
MINT_ATTACH=1 DRY_RUN=1 python3 scripts/codex-worker.py

# One-shot poll loop (token at ~/.fleet/agents/codex-member.token):
DRY_RUN=1 python3 scripts/codex-worker.py
python3 scripts/codex-worker.py
```

## Capability

Codex acts within the member token's capabilities — same as Claude. `member` on a
squad unlocks `task_create` / `squad_message`; `lead`+ unlocks `wake_agent`;
`remember` / `recall` / `status` are self-scoped. Anything above the grant returns
`403 forbidden`. Codex cannot escalate.
`403 forbidden`. Codex cannot escalate. The driver lands work at `review` and
never merges, deploys, or self-verdicts.
16 changes: 9 additions & 7 deletions connectors/codex/config.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# Codex ── mupot MCP server (EXAMPLE)
# Merge into ~/.codex/config.toml. Replace the host with your pot, and the token
# with the raw member token your pot minted (channel: workspace). Never commit the
# filled-in file — this placeholder version is the only one that belongs in git.
# Merge into ~/.codex/config.toml. Replace the host with your pot.
# Set the env var named below to the raw member token your pot minted
# (channel: workspace). Never commit the filled-in token — this placeholder
# version is the only one that belongs in git.
#
# Streamable-HTTP ONLY. Do NOT set type="sse" / transport=sse — Codex does not
# support SSE for remote MCP (see docs/connect-mcp-client.md).

[mcp_servers.mupot]
type = "sse"
url = "https://YOUR-POT.example.workers.dev/mcp"

[mcp_servers.mupot.headers]
Authorization = "Bearer <MUPOT_MEMBER_TOKEN>"
bearer_token_env_var = "MUPOT_MCP_TOKEN"
# then: export MUPOT_MCP_TOKEN=<MEMBER_TOKEN> (one line, no quotes/newline)
2 changes: 1 addition & 1 deletion connectors/codex/mcp.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"mcpServers": {
"mupot": {
"type": "sse",
"type": "http",
"url": "https://YOUR-POT.example.workers.dev/mcp",
"headers": {
"Authorization": "Bearer <MUPOT_MEMBER_TOKEN>"
Expand Down
3 changes: 2 additions & 1 deletion docs/runtime-adapter-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ Agent identity and runtime binding are separate concepts.

- `agent_id` names the durable Mupot agent.
- `runtime` names the carrying process type, such as `codex`,
`claude-code`, `hermes`, `hermes-cron`, `systemd-user`, `tmux`, or `python`.
`claude-code`, `cursor`, `hermes`, `hermes-cron`, `systemd-user`, `tmux`,
or `python`.
- `lifecycle` describes the expected host model: `on_demand` or `always_on`.
- `member_id` is derived from the bearer token or registered agent key.
- `tenant` is always `env.TENANT_SLUG`; client-supplied tenant fields are not
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"seed:local:test": "wrangler d1 execute mupot-local-test --local --config wrangler-local-test.toml --file scripts/local-test-seed.sql",
"smoke:local": "node scripts/local-browser-smoke.mjs",
"conformance:runtime:local": "node scripts/local-runtime-conformance.mjs",
"conformance:runtime:drivers": "node scripts/runtime-adapter-driver-conformance.mjs",
"receipt:host": "node fleet-runtime/host-receipt.mjs",
"receipt:runtime": "node fleet-runtime/runtime-receipt.mjs",
"receipt:control": "node fleet-runtime/control-receipt.mjs",
Expand Down
21 changes: 21 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,27 @@ It writes `tmp/local-runtime-conformance/report.json` and prints the same JSON
report to stdout. Failures write `tmp/local-runtime-conformance/failure-*.json`
when the process can create artifacts.

### Topology-A driver conformance (offline)

The cursor + mumcp + codex topology-A drivers must stay on `runtime-adapter/v1`.
This smoke is offline (no live pot) and asserts contract markers + preserved
rails:

```bash
npm run conformance:runtime:drivers
```

Shared client: `scripts/runtime_adapter_v1.py`. Drivers:
`scripts/cursor-worker.py` (runtime=`cursor`), `scripts/mumcp-worker.py`
(runtime=`claude-code`), `scripts/codex-worker.py` (runtime=`codex`,
`codex exec --sandbox --json`, remote MCP via `~/.codex/config.toml`
`url` + `bearer_token_env_var` — no SSE).

```bash
# Codex mint+attach plan (no live Codex creds required):
MINT_ATTACH=1 DRY_RUN=1 python3 scripts/codex-worker.py
```

## CI local evidence

GitHub Actions runs the same local evidence gate with:
Expand Down
Loading