-
Notifications
You must be signed in to change notification settings - Fork 1
How It Works
This page traces Codexify end-to-end: how a request from ChatGPT reaches a tool on your machine, and everything the server does around each call. If you only read one "under the hood" page, read this one.
flowchart LR
ChatGPT["ChatGPT Web\n6 Astra Pro"]
Tunnel["OpenAI Secure MCP Tunnel"]
Client["Official OpenAI\ntunnel-client-runtime\n(supervised)"]
Server["Codexify\nMCP Bridge\n127.0.0.1:3000"]
Tools["Tool Registry"]
WorkDir[("Active project root")]
State[("~/.codexify\nplan + notes")]
Upstream[("Bridged MCP servers")]
ChatGPT <-->|"connector calls"| Tunnel
Client <-->|"outbound HTTPS"| Tunnel
Client <-->|"loopback HTTP /mcp\n+ per-process bearer"| Server
Server --> Tools
Tools --> WorkDir
Tools --> State
Tools -.->|"if configured"| Upstream
The key property: traffic is outbound-only. Codexify listens on 127.0.0.1. The tunnel client dials out to OpenAI over HTTPS and forwards tunnel traffic back to the authenticated loopback endpoint. No inbound port is opened, and there's no public URL.
When you run codexify --work-dir …, before it accepts any traffic the server:
-
Reads config. Loads
codexify.config.json(or the built-in defaults if missing) and applies CLI-flag overrides. The startup banner reports the effective settings. -
Resolves the mode. Single-project (default), multi-project (
--multi-project), and native-tunnel vs legacy/external — see below. -
Discovers MCP upstreams. Reads
$CODEX_HOME/config.toml(read-only) for[mcp_servers.*], optionally enriches viacodex mcp list/get --json, then applies yourmcpServersoverlays. Each upstream is connected and its tools listed. The banner names every one — including failures. See Bridging MCP Servers. -
Installs/verifies the tunnel runtime (native mode only). Downloads the pinned official client if absent, checks it against an embedded SHA-256, and starts it. The server reports ready only after
/readyzpasses and a control-plane poll succeeds. -
Sweeps stale worktrees (multi-project). Removes old, clean, unreferenced managed worktrees beyond
keepCount. See Worktree Isolation.
When ChatGPT (or any MCP client) opens a session, the server returns an initialize response. Its instructions field is where Codexify layers Codex's operating brief, in Codex's own order, each part outranking the one above it:
-
The agent brief — how to behave (edit carefully,
apply_patchover rewrites, respect the dirty-worktree rules, keep a plan, report concisely). Ported from Codex's own prompt. - The environment — OS, shell, work directory, command policy.
- Saved state — the plan and notes from earlier work, if any. See Context and Memory.
- The skill catalogue — what this project and user know how to do, if any skills are installed. See AGENTS and Skills.
-
AGENTS.md— the project speaking for itself, behind a--- project-doc ---marker.
Because instructions is rebuilt per session, editing AGENTS.md or adding a skill takes effect on the next connection — no restart needed.
Important: no client is obliged to show
instructionsto its model, and ChatGPT Web isn't reliable about it. That's whyget_agent_briefreturns the identical string on demand. Opening a chat with "Call get_agent_brief and follow it for the rest of this chat" is the reliable way to onboard. See Connecting to ChatGPT.
When an identifiable ChatGPT caller requests tools/list, Codexify records the exact running package version that served the schema. The record is keyed by a SHA-256-derived caller identity from openai/subject plus optional openai/organization, then scoped to the native tunnel ID or external HTTP work-directory/port endpoint. It therefore spans conversations for the same ChatGPT caller and connector while separating accounts, organizations, and Codexify endpoints. Anonymous discovery is deliberately not attributed.
Only the version string is stored, under ~/.codexify/connector-schemas/<endpoint-hash>/<caller-hash>, with private directory permissions on Unix and atomic replacement. The in-memory observation remains usable even if persistence fails. This is UI bookkeeping, not authorization.
The setup app calls the private setup_status helper with the version embedded in that conversation's setup card. Codexify can then distinguish:
- the running server, recorded connector schema, and conversation card all current;
- a connector whose last
tools/listversion is older than the server, requiring ChatGPT's Refresh control; and - a connector already refreshed to the server version while the current conversation/card remains older, requiring a new conversation.
Polling setup_status never counts as a schema reload; only tools/list does.
For each tool call, the server:
-
Identifies the owner. For ChatGPT calls carrying
_meta["openai/session"], work is scoped to that hashed conversation identity — so bindings, memory, diff checkpoints, andexec_commandsessions survive the connector swapping transports mid-chat. Clients without that metadata fall back to a per-transport-session scope. -
Resolves the active project root.
--work-dirin single-project mode; the conversation's selected root in multi-project mode. Until a root is bound in multi-project mode, project-scoped tools are unavailable and say why. -
Guards the path. Every filesystem tool resolves paths through a guard that rejects anything outside the active project root — after canonicalization, so
..and symlinks can't escape. -
Enforces policy.
exec_commandruns unrestricted by default. Whenexec.modeis"allowlist", every command position in the shell string must appear in the completeexec.extraAllowedCommandslist; command substitution is rejected. Output is bounded per theoutputblock. -
Initializes diff state (first project-scoped call). Captures the checkout as the agent first sees it, before any write — the immutable
project-openbaseline. See Diff Checkpoints. - Runs the tool, bounds the result, and appends a truncation notice when it hit a cap.
-
Records an audit event if
--auditis set — hashes, timings, sizes, redacted argument shape. See Audit Logging.
Any tool that could return unbounded text stops at a budget and says so on its last line, naming the argument that continues:
(showing lines 1-1000 of 4820 — call again with offset=1000 for the rest)
That last line matters as much as the cap — silent truncation reads as "that was the whole file", which is worse than no cap. read_file has a byte ceiling as well as a line one (a minified bundle is one line, megabytes long). exec_command and grep are bounded too, ported that way from Codex.
ChatGPT's window is smaller than most real tasks, and a new chat starts blank. Codexify keeps what's expensive to rediscover:
-
rememberwrites one keyed note;recallreturns the notes plus the current plan;update_planpersists the plan itself. - State lives in
~/.codexify/projects/<name>-<hash>/memory.json, keyed by the absolute project root — never inside your repo. - In single-project mode, the saved plan and notes are already in front of a new conversation via
instructions. In multi-project mode they arrive fromget_agent_briefafter the project is selected. - In multi-project mode, a setup-card continuation can bind a new ChatGPT conversation to the exact previously recorded checkout, managed worktree, or persistent scratch root through
set_project_root.resumePath. Because the absolute root is unchanged, the same plan/notes and dirty filesystem state remain available. Chat history, resident command sessions, and conversation-keyed diff checkpoints do not transfer.
Full detail in Context and Memory.
| Mode | Binds | Endpoint | Auth | When |
|---|---|---|---|---|
| Native OpenAI tunnel |
127.0.0.1 only |
routed via tunnel | random per-process bearer (loopback hop); /readyz gate |
Recommended. No public URL, no inbound port. |
| Legacy / external | 0.0.0.0:3000 |
/mcp, /health
|
you provide it (proxy, --api-key) |
Local clients, or an explicitly authenticated reverse proxy/tunnel. |
| Multi-project | (either of the above) | same | per-conversation project binding | One server, many repos beneath an access root. |
Native and multi-project compose — you can run --multi-project behind the native tunnel. What multi-project changes is project selection, not the transport. See Multi-Project Mode and Connecting to ChatGPT.
- You run
codexify --work-dir ~/code/myappwith anopenaiTunnelblock configured. - Codexify verifies/starts the tunnel client, connects any bridged MCP servers, and reports ready.
- In ChatGPT (Developer mode), you enable the connector for that tunnel and open a chat: "Call get_agent_brief and follow it for the rest of this chat. Task: fix the failing test in auth.rs."
- ChatGPT calls
get_agent_brief, receives the environment +AGENTS.md+ any saved plan, and starts working the way Codex would. - It calls
grep,read_file,apply_patch,exec_command— all pinned to~/code/myapp, all bounded, all optionally audited. - It calls
show_diffto show you exactly what it touched, andgit_commit/git_pushwhen you approve. - You close the chat. The plan and notes persist. In single-project mode a new chat receives them through the brief; in multi-project mode it first selects a workspace or resumes the exact recorded one, then calls
get_agent_brief/recall.
- Tools Reference — the tools invoked in step 3.
- Security Model — the boundary enforced in step 3.
- Diff Checkpoints — the snapshot from step 5.
- Context and Memory — the persistence from step 5.
Repository · Releases · Report an issue · MIT License
Getting started
Reference
How it works
Multi-project
Extending
Operations