A control plane for the coding agents on your machine.
Cortex is a desktop app that starts Claude Code, Codex and OpenCode as processes it owns, shows whether each agent is ready, busy or crashed, and runs tasks across them where one agent's result feeds the next. Any MCP client you configure can drive the same core.
The Agents screen during a real run. The app and the agents' output are real; the project is a small example service with two planted bugs.
- State comes from Cortex's records. READY, BUSY, STOPPED, CRASHED: the card shows what the component that owns the agent recorded, not text read from a terminal.
- Three runtimes side by side. Claude Code, Codex and OpenCode behind one adapter contract. The red line is Codex's own log on stderr, kept apart from stdout.
- Terminal mode. Claude Code's own interface runs inside the card, in a Windows pseudoconsole (ConPTY) that Cortex owns.
- One objective, three tasks. Claude Code traced a bug; Cortex passed its result to Codex and OpenCode.
- Not built yet, so greyed out. Context, Resources, Events, Tools, Skills, Hooks and Behaviours stay inert until they exist.
01Problem
Three agents, three terminals, and you in the middle.
-
State lives in scrollback.
Is it working, waiting for input or gone? You find out by reading each terminal in turn.
-
Processes outlive the session.
Agent CLIs start shells and tools of their own. When a session ends badly, nothing records which processes belonged to it.
-
You are the message bus.
Chaining work means pasting one agent's answer into the next agent's prompt, by hand.
-
Each CLI works its own way.
Starting it, sending an instruction, knowing a turn has ended and stopping it differ from one agent CLI to the next.
02A real run
One objective, three runtimes.
A short script, acting as an MCP client, submitted the objective “Charge invoice tax exactly once” as three tasks with their dependencies. Cortex did not plan them: it ran each one on the agent it was assigned to, in dependency order, and passed the trace to the two tasks waiting on it.
All three agents worked read-only. In structured mode Cortex denies anything that would need approval, so they read the project and answered; none of them edited a file.
An objective is a list of tasks; a task is one instruction for one agent; an attempt is one try at it.
- Trace the invoice total invoice-trace · Claude Code
- Propose the smallest fix after trace fix-review · Codex
- List the missing tests after trace test-plan · OpenCode
The request that started the run
create_objective {
"title": "Charge invoice tax exactly once",
"tasks": [
{ "key": "trace", "title": "Trace the invoice total",
"assigned_agent_id": "<invoice-trace>" },
{ "key": "fix", "title": "Propose the smallest fix",
"depends_on": ["trace"],
"assigned_agent_id": "<fix-review>" },
{ "key": "tests", "title": "List the missing tests",
"depends_on": ["trace"],
"assigned_agent_id": "<test-plan>" }
]
}
Abridged: each task also carried its instruction as description.
The three results as text
- Trace the invoice total · Claude Code
- Tax is applied twice on POST /invoices, so the response is over-charged. For a 10,000-cent EU-DE order, the stored total is 11,900 and the response returns 14,161. (1) src/invoices/createInvoice.ts:25 applies tax the first time, and the result is persisted. (2) src/routes/invoices.ts:15 applies it again in the HTTP response. (3) src/invoices/tax.ts:19-20, applyTax, is the shared helper, not a tax site on its own. (4) src/invoices/refund.ts:8 reads the stored totalCents, so refunds use the single-taxed value.
- Propose the smallest fix · Codex
- Remove the second tax application: src/routes/invoices.ts:15, change totalCents: applyTax(invoice.totalCents, region) to totalCents: invoice.totalCents.
- List the missing tests · OpenCode
- Double taxation: assert the POST /invoices response totalCents equals the stored total (11,900 for 10,000 EU-DE). Double taxation: assert the response totalCents equals applyTax(subtotalCents, region) on the raw subtotal. Refund rounding: a full refund of subtotalCents returns exactly totalCents. Refund rounding: partial refunds whose ratios sum to 1 return the same cents as one full refund.
(full-size image)
03Runtimes
Three CLIs behind one contract.
Cortex drives the CLIs already installed and signed in on your machine; it does not bundle them. Each adapter translates one CLI: executable, flags, protocol, readiness, end of turn. Starting, stopping, limits and recovery are the same for all three.
| Runtime | Process | Protocol | Created from | Modes | In structured mode |
|---|---|---|---|---|---|
| Claude Code | One per session | stream-json JSON lines over stdio |
New agent dialog or MCP | Structured (default) or terminal | Anything that would need approval is denied. Rules you allowed in Claude Code's own settings still apply. |
| Codex | One per instruction, resuming the same thread | exec --json JSON events on stdout |
MCP | Structured | Runs in a read-only sandbox: it can read and run read-only commands, not write. |
| OpenCode | One per session | ACP Agent Client Protocol over stdio |
MCP | Structured | Edit, shell and web requests are refused. |
Terminal mode gives you Claude Code's own interface in the card. Cortex owns the pseudoconsole and the process tree; the CLI's own permission rules apply, including an auto mode you turned on there, as in Fig. 3. A terminal agent is driven only by you: it takes no tasks, MCP messages or interrupts, and Cortex keeps no transcript of it.
A missing CLI marks its runtime unavailable, with a fix; Cortex still starts. All three declare interrupt and turn completion. The contract is built so another CLI can be added without changing the core; none is scheduled.
04MCP
Any MCP client can drive the same core.
Cortex hosts an MCP server on 127.0.0.1, port 47821 by default. Claude Code, or any MCP client you configure with your token, can list, create, start, message, interrupt and stop agents, submit objectives, cancel tasks and follow every turn. The run above was submitted this way.
Restarting or editing an agent, creating a project, the process list and terminals stay in the window. Events are read by cursor with poll_agent_events, which keeps the latest 256; there are no push notifications yet.
| Caller | Credential | May |
|---|---|---|
| You | User token, stored unencrypted in your Cortex data folder | Every tool |
| An agent Cortex started | A credential for its session, valid while the session lives | Read only |
| A remote client | OAuth 2.1 with PKCE, through a tunnel you set up. You approve it by typing, in the Cortex window, the code its browser shows. Revocable. | Acts as you |
Agents started by Cortex run as your Windows user, so the read-only credential limits what Cortex hands them, not what they could read on disk. Remote access was verified with a test client against a simulated public URL on one machine, not yet through a real tunnel or with ChatGPT.
The 14 tools
Read
- list_projects
- list_runtimes
- list_agents
- get_agent_status
- poll_agent_events
- list_tasks
- get_task_status
Write
- create_agent
- send_message
- create_objective
Control
- start_agent
- stop_agent
- interrupt_agent
- cancel_task
05Architecture
One way in. One owner for each piece of state.
Cortex is one Windows desktop process. The window and the MCP server are two surfaces over the same API: every use case enters there, and agent, session, process and task state each have exactly one component allowed to change them. Cortex has no cloud service, account or telemetry of its own; the agent CLIs talk to their own providers. Because everything lives in that process, agents, tasks and the MCP server stop when you close the window.
-
Surfaces
- Desktop windowReact UI over Tauri IPC
- MCP server127.0.0.1 · 14 tools · token or OAuth
-
API
- Cortex APIChecks the caller and the permission, and tags each call with an ID for tracing
-
State owners
- Agent ManagerAgent state, from CREATED to CRASHED
- Session RegistrySessions, turns, output buffers, process slots
- OrchestratorTasks, attempts, retries, dependencies
-
Runtime adapters
- Claude CodeOne process · stream-json
- CodexProcess per turn ·
exec --json - OpenCodeOne process · ACP
-
Processes
- Process ManagerOne Job Object per process, a Windows handle that can end the whole tree · ConPTY for terminal mode · recorded before it runs
-
Windows
- claude.exe
- codex.exe
- opencode.exe
- and the child processes they create
Across layers
- Event busIn process. Carries state changes to the window, the MCP event feed and the task dispatcher.
- Data folderJSON records written atomically: config, projects, agents, objectives, processes, MCP credentials.
- Recovery at startupEnds verified leftover processes and marks interrupted agents CRASHED, before the Core is READY.
What happens when you press Enter in the console
- The window sends the text over Tauri IPC; the host runs the call off the UI thread.
- The Cortex API admits the call, identifies the caller, checks permission and refuses an agent that is not READY. A BUSY agent belongs to its task.
- The Session Registry records the turn, so a typed message and a task can never share one.
- The Claude Code adapter writes one stream-json line to the CLI's stdin. Only adapters know flags and protocols.
- claude.exe is already inside its own Job Object: it was created suspended, recorded, then resumed.
- Output goes into a bounded per-agent buffer that the window reads by cursor. The end of the turn becomes the event session.turn_completed, which tasks and MCP clients see.
06Decisions
Each decision, and the failure it prevents.
-
D-01
A PID is never an identity.
Every process gets a Cortex ID and exactly one owning session. After a crash, a leftover process is ended only if its PID, OS creation time and executable path all match the record.
Prevents ending an unrelated program that was given a reused PID.
-
D-02
The process tree is owned before it runs.
Processes start suspended, join their own Job Object with kill-on-close, get recorded, and only then resume. Claude Code and OpenCode are asked to stop first; Codex's per-turn process is ended at once. Then the whole tree goes.
Prevents child processes the agent creates escaping cleanup, or outliving Cortex itself.
-
D-03
Intent is written before effect.
If the process record cannot be written, the suspended process is killed. At startup, recovery ends verified leftovers and marks agents that were running as CRASHED, with the cause. No session is silently resumed.
Prevents an untracked process after a crash, and a READY badge on a runtime that died.
-
D-04
One writer per state machine.
Agent, session, process and task state each have one owner. A runtime fact applies only if the session it describes is still current. Events are queued under the owner's lock and published after it is released.
Prevents a late exit overwriting a newer start, deadlocks and reordered events.
-
D-05
Capabilities are declared, never simulated.
Each adapter implements runtime contract version 2 and declares what it supports: interrupt, streaming, turn completion, a terminal, one process per session or per turn. Anything undeclared fails with an explicit error.
Prevents a window or MCP client relying on an operation the CLI cannot perform.
-
D-06
Boundaries are tests.
The test suite fails on a forbidden dependency between layers, and on any CLI name, flag or protocol message outside the adapters.
Prevents runtime-specific branches creeping into the core.
-
D-07
The MCP endpoint is treated as hostile.
The listener binds 127.0.0.1 and always checks Host, against DNS rebinding. Without a tunnel it checks Origin too; with one, every MCP call needs a bearer token, which another site's page cannot send. The bearer is resolved inside the core, and a remote client is approved only by typing, in the Cortex window, the code its browser shows.
Prevents a web page or an unapproved remote client taking control of processes that run code on your machine.
07Status
What works today, and what does not yet.
As of 13 October 2026, v0.1.0. An item is listed as available only after its real path has run end to end on Windows.
Available
- Agents with an ID, a project and a runtime; definitions persist across restarts
- Start, stop and restart, with buttons enabled only by the reported state
- Structured and terminal interaction modes, chosen per agent
- A console to send an instruction and read the output
- Processes screen: PID, parent, command, owner, kind, start time
- A cap on running agents: 6 by default, 1 to 32 in config.json
- Job Object ownership and recovery at startup
- Objectives of 1 to 10 tasks with dependencies; retried once by default; 2 run in parallel by default
- MCP server with 14 tools
- Remote MCP access with OAuth 2.1, verified with a test client against a simulated public URL
Known limits
- Windows only: process ownership uses Job Objects and the terminal uses ConPTY. No installer or public build yet.
- Claude Code, Codex and OpenCode must already be installed and signed in.
- Agents, tasks and the MCP server run only while the Cortex window is open.
- In structured mode agents read and answer; applying edits through Cortex is not available yet.
- The New agent dialog creates Claude Code agents; Codex and OpenCode agents are created over MCP.
- Edit changes only the interaction mode of a stopped agent. Agents cannot be removed from the window.
- Terminal-mode agents take no tasks or MCP messages, and Cortex keeps no transcript of them.
- You list the tasks; Cortex does not plan them. With no supervisor yet, a CLI that hangs keeps its task running until you cancel it.
- A turn's result is cut at 4,096 characters before it reaches a dependent task or an MCP client.
- Tokens are stored unencrypted in your data folder, and agents run as your Windows user.
- No CPU or memory measurement; the Memory column shows a dash.
Planned
Next (V1.5)
- Messages between agents
- Global skills, hooks and behaviours
- Routing: choosing the runtime or agent for a task, with the reason recorded
- A command-line interface
- Documentation and installer
Later (V2)
- Scheduler and resource manager, with CPU and memory
- Supervisor and timeouts
- Git worktree isolation and file ownership
- Loop detection and journal-based recovery
- Permissions and autonomy modes
- Execution timeline
There is no public build yet. When an installer and documentation exist, they will be linked from this page. Until then, follow the project on Instagram, Threads and YouTube.