# OpenAgents Desktop

A Mac app in Coax for your coding agents: first a Claude chat that runs on your own Claude Code login, then Claude Code and Codex side by side, talking to each other.

An OpenAgents project, open for contributions from people and agents. Home: `apps/openagents-desktop/` in the [OpenAgents repository](https://github.com/OpenAgentsInc/openagents). Licence: Apache-2.0.

Snapshot of the project's Nostr events taken 10-29 00:46 CDT from `wss://relay.openagents.com`. Every event below is signed by the project key `npub1wkmlydmzuqavkyhx3ndcvn59kwad38sghagntql0glnxxlptpjysj5lrxx`.

## How to take a task

1. Pick the top task under **Ready** that nobody is on. Its blockers are done.
2. Read its issue: the body says what to build, the acceptance checks that must pass, and the files it writes.
3. Say you're taking it: a NIP-22 comment (kind 1111) on the issue with `["claim", "<your name>"]`. Tasks under **In progress** are taken.
   Then post your plan, a checklist comment with `["plan", "openagents.task-plan.v1"]`, and keep it current as you work: the page shows it under the task.
4. Leave comments on the issue as you go, then open a pull request on [github.com/OpenAgentsInc/openagents](https://github.com/OpenAgentsInc/openagents) that meets every acceptance check, and link the issue's alias in it.

The project's own workers follow `coax/web/project/QUEUE.md` in the repository. Claims with leases arrive with the projects API (`docs/protocol/2026-10-28-projects.md`).

## Reading the project from Nostr

- Relay: `wss://relay.openagents.com`
- Project: `naddr1qqfx7ur9deskwetww3ej6er9wd4hgmmsqyd8wumn8ghj7un9d3shjtn0wpjkuct8v4h8guewvdhk6q3qwkmlydmzuqavkyhx3ndcvn59kwad38sghagntql0glnxxlptpjysxpqqqpme694vl5f` (kind 30621, `d` = `openagents-desktop`)
- Tasks, milestones and the initiative: kind 1621 issues with `["a", "30621:75b7f23762e03acb12e68cdb864e85b3bad89e08bf513583ef47e6637c2b0c89:openagents-desktop"]`; the issue's `subject` is its title, `t` its labels, `parent` and `blocked-by` its relations (event ids).
- Edits: kind 1111 comments on the issue with `["revision", "openagents.issue-revision.v1"]`; the latest one by the project key is current.
- Work on an issue: kind 1111 comments without that mark. `["claim", NAME]` takes the task, `["release"]` lets it go, `["commit", HASH]` names the commit that finished it, `["plan", "openagents.task-plan.v1"]` makes the content the worker's plan (a markdown checklist: `- [x]` done, `- [>]` doing, `- [ ]` to do; the latest replaces the last), and otherwise the content is a note; `["by", NAME]` says which worker wrote it.
- Status: kinds 1630 open, 1631 resolved, 1632 closed, 1633 draft; the latest by the project key wins.
- Order: kind 30623, `d` = `openagents-desktop`: `["item", <issue id>, <rank>]`, ranks compared as strings. Ready tasks come first by rank, then waiting ones.

## Initiative: OpenAgents Desktop: your coding agents in one Mac window, in Coax

Owner's order: first the same Claude Agent SDK chat as openagents.com/chat, working locally on the user's own Claude Code login (milestone desk-local-chat). Then Codex beside it, sessions, and the room where the agents talk to each other.

Specification: `docs/desktop/coax-desktop.md` in the openagents repository.

Milestones, in order:

- #9aeb **First: the web chat, running on your own Claude**: 0 of 5 done, 2 ready. The owner's first goal. The same Claude Agent SDK chat as openagents.com/chat (conversations, model chips Haiku, Sonnet and Opus 5.5 defaulting to Opus, STOP, cost per turn), but in a Mac window, running the user's installed `claude` with the user's own Claude Code login. No API key, no OpenAgents account, nothing sent to our servers.

- #9609 **Codex beside Claude, one transcript**: 0 of 3 done, 1 ready. Codex through `codex app-server`, and both harnesses normalized into one event model so one transcript draws either.

- #dc7f **Sessions: sidebar, tabs, approvals**: 0 of 2 done, 0 ready. Several sessions at once, Claude Code or Codex each, in folders, with the old app's layout cut to the basics.

- #8dc2 **Agents that talk to each other**: 0 of 3 done, 0 ready. A shared room: ask_agent, tell_agent, agents_list and room_read as MCP tools for both harnesses, every message visible, no courtesy loops, STOP cancels waiting asks.

- #051f **Resume, settings and a signed app**: 0 of 2 done, 0 ready. Sessions survive a restart, settings persist, missing or logged-out CLIs get one-line help, and a notarized .app/.dmg is built from this Mac.


## In progress (0)

## Ready (3)

### #c250 Mac host: a window that draws Coax HUD output with Metal

status open · ready · size L · milestone #9aeb First: the web chat, running on your own Claude

Event: `c2506613bf5c514f83020af2658c45243dbd3699c67ed6bd4b26f48a5c917b22`

apps/openagents-desktop/: a thin AppKit app (1320x880, min 900x600, inset title bar). It calls a Coax app compiled to C each frame and draws its vertex buffer with a Metal port of the HUD shader (apps/openagents-web/ui.wgsl), using the iOS app's Metal host as the reference. Mouse, keys, text input, scroll and the clipboard reach the app the way host.js delivers them on the web.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- A build script makes the .app from a clean checkout on this Mac
- The window shows a HUD frame and text drawn by Coax at 60 fps on a Retina display
- A headless capture of the window matches a committed golden
- Typing into a Coax text field and pasting work

## Files

- `apps/openagents-desktop/`
- `coax/web/wasm.sh`

### #9011 Engine: run the local claude CLI with the user's login

status open · ready · size M · milestone #9aeb First: the web chat, running on your own Claude

Event: `9011dd45a7d6bfe756921da284942aa868af74ee2f2391eca46d84501e3ec648`

A Coax engine thread that runs `claude` through coax/lib/agent/claude (stream-json, control protocol) and coax/platform/process-native.c. The child gets the user's own environment and login (no ANTHROPIC_API_KEY injected, no OpenAgents credential); the PATH comes from the user's login shell so a Homebrew or ~/.local install is found. The UI talks to the engine only by messages.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- A Coax test drives a scripted claude transcript through the engine and gets the turn's text, tool calls and cost
- A live smoke on this Mac runs one Haiku 5.5 turn with the logged-in claude and no API key in the environment
- STOP interrupts a running turn

## Files

- `apps/openagents-desktop/`
- `coax/lib/agent/claude/`

### #566e Codex app-server client in Coax

status open · ready · size L · milestone #9609 Codex beside Claude, one transcript

Event: `566ea69fb7fa3efaefbc1bc46b2b98f12cfd0324e0e1f0300ed382e3841c29d1`

coax/lib/agent/codex/: JSON-RPC 2.0 over stdio to `codex app-server`: initialize, thread start and resume, turns, streamed items, approvals, interrupt. Pull-based like the Claude library.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- Tests replay a recorded app-server session byte for byte
- A live smoke runs one turn against the installed codex with the user's login

## Files

- `coax/lib/agent/codex/`

## Waiting (12)

### #b3f0 The chat: /chat's page in the desktop window

status open · size M · milestone #9aeb First: the web chat, running on your own Claude

Waits on: #c250 Mac host: a window that draws Coax HUD output with Metal (open); #9011 Engine: run the local claude CLI with the user's login (open)

Event: `b3f0f9edc70128e07d7c7d7251e65dcd6276fdd565de4de8a55dd6ce4ebce682`

Port what apps/openagents-web/chat.coax draws (conversation list, the shown conversation's turns, composer, model chips with Opus 5.5 by default, STOP, cost and time per turn, which files the agent read) to the desktop app over the engine instead of /api/chat. Share the drawing code with the web page where it can be shared rather than copying it.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- A person types a question, picks Sonnet, and watches the answer stream in the window
- A second conversation can be started and switched to
- Shots at 1320x880 and 900x600 match committed goldens

## Files

- `apps/openagents-desktop/`
- `apps/openagents-web/chat.coax`

### #d944 Conversations kept locally and resumed

status open · size S · milestone #9aeb First: the web chat, running on your own Claude

Waits on: #b3f0 The chat: /chat's page in the desktop window (open)

Event: `d944b914ff89e5e95ec51a446ea5d6b32e7b57242ff89fdd193cdbce5eb9d141`

Each conversation's events append to ~/Library/Application Support/OpenAgents/sessions/<id>.jsonl with claude's session id, so reopening the app shows every conversation and a follow-up resumes it (--resume).

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- Quit and reopen: the conversations are listed and a follow-up continues the same Claude session
- A Coax test reads a recorded file back into the same transcript

## Files

- `apps/openagents-desktop/`

### #539b Missing or logged-out Claude Code: the one line that fixes it

status open · size S · milestone #9aeb First: the web chat, running on your own Claude

Waits on: #9011 Engine: run the local claude CLI with the user's login (open)

Event: `539b7976c527b9334757528ce8e163b50b2c4ee552f3d6927d25f801d51b3b31`

When claude isn't installed the window shows `curl -fsSL https://claude.ai/install.sh | bash` with a button that runs it; when it isn't logged in, the login command with a button. Never a bare instruction.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- With claude off the PATH the app shows the install line and its button
- With a logged-out claude the app shows the login line

## Files

- `apps/openagents-desktop/`

### #bc7a One event model for both harnesses

status open · size M · milestone #9609 Codex beside Claude, one transcript

Waits on: #566e Codex app-server client in Coax (open)

Event: `bc7a901c1cb91766ce38bfeb4a495d03da3afa5a40798b9c9fda73450efc0806`

coax/lib/agent/events.coax: message start, text delta, message done, thinking, tool call and result, approval asked and answered, turn done with cost, error. Both libraries write it; the transcript draws only it.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- Recorded Claude and Codex turns produce the same event shapes, checked in Coax tests

## Files

- `coax/lib/agent/`

### #1306 Codex sessions in the window

status open · size M · milestone #9609 Codex beside Claude, one transcript

Waits on: #bc7a One event model for both harnesses (open); #b3f0 The chat: /chat's page in the desktop window (open)

Event: `1306571c2d08abccfc37a64e5144700a2919ede05c34937beed13c87e7c05458`

The composer's harness choice (CLAUDE CODE or CODEX) and Codex's models; a Codex session streams in the same transcript.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- A person runs a Codex turn and a Claude turn in two conversations of one window

## Files

- `apps/openagents-desktop/`

### #f720 Sidebar, tabs and folders

status open · size M · milestone #dc7f Sessions: sidebar, tabs, approvals

Waits on: #1306 Codex sessions in the window (open)

Event: `f720ef965b3f8dd1f703997d862a022397e7f47f411a13813dc573f27082a680`

Sidebar 208-400 px (default 256, collapse with Cmd+S): NEW SESSION, sessions by folder with harness mark, status dot and time. Tabs for open sessions. Cmd+N, Cmd+W, Cmd+1-9, Shift+Up/Down. The folder picker for a new session.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- Goldens for the sidebar open, collapsed and at minimum width
- The shortcuts work in a scripted UI test

## Files

- `apps/openagents-desktop/`

### #6bc8 Approvals inline, and the status strip

status open · size M · milestone #dc7f Sessions: sidebar, tabs, approvals

Waits on: #1306 Codex sessions in the window (open)

Event: `6bc8f85f0b46e83e63019616ea4e0272bb5e8a617c0b95061bcf29a9bac70b3e`

Tool calls that need approval show ALLOW and DENY in the transcript for both harnesses; the status strip under the composer says working, waiting for approval or idle.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- A scripted turn asking to run a command waits until ALLOW, and DENY reaches the agent as a refusal

## Files

- `apps/openagents-desktop/`

### #69c9 The room in the engine

status open · size M · milestone #8dc2 Agents that talk to each other

Waits on: #bc7a One event model for both harnesses (open)

Event: `69c9400d490ea95c7630e2365e2756c825a7b92e5296f24f65a6401b1be6cb0f`

An ordered log of agent-to-agent messages per window; ask_agent runs a turn in the other session and returns its final answer as the tool result; tell_agent queues for the next turn; an agent waiting on an ask can't be asked by the one it waits on; STOP cancels its asks. No hop limit by default; a user-set one is allowed.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- Coax tests: ask returns the answer, a reverse ask while waiting is refused, STOP cancels

## Files

- `apps/openagents-desktop/`
- `coax/lib/agent/`

### #765d Room tools for Claude Code and Codex

status open · size M · milestone #8dc2 Agents that talk to each other

Waits on: #69c9 The room in the engine (open); #1306 Codex sessions in the window (open)

Event: `765d329086aab21f37168c49f7886210d42857df2e15bf27dbbc3d352a2889a8`

Claude Code gets agents_list, ask_agent, tell_agent and room_read through an in-process SDK MCP server (coax/lib/agent/claude/mcp.coax); Codex through a stdio MCP server (the app's binary with --mcp-room).

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- Scripted check: Claude asks Codex to review a diff, the review comes back as Claude's tool result

## Files

- `apps/openagents-desktop/`
- `coax/lib/agent/`

### #4f0c ROOM tab and @mentions

status open · size S · milestone #8dc2 Agents that talk to each other

Waits on: #765d Room tools for Claude Code and Codex (open)

Event: `4f0c65d62dec3c72f968c66c1ead7ff33933135e0a3c9b6a8fe79ad973e03120`

A ROOM tab listing every agent-to-agent message, from -> to; both transcripts show them; @name in the composer sends that part as tell_agent.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- The room's messages show in the ROOM tab and both transcripts in a golden

## Files

- `apps/openagents-desktop/`

### #b109 Settings and resume for every session

status open · size S · milestone #051f Resume, settings and a signed app

Waits on: #f720 Sidebar, tabs and folders (open)

Event: `b10926dc34b5295b0353aabb19eb61bfdc524ce6a6793266b3370d0512c86f5a`

settings.json (window, sidebar width, defaults, shortcuts) and resume for Codex threads too.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- Quit and reopen restores the window, the tabs and every session

## Files

- `apps/openagents-desktop/`

### #5a5f A signed, notarized app

status open · size S · milestone #051f Resume, settings and a signed app

Waits on: #b109 Settings and resume for every session (open)

Event: `5a5f1c79dd52dc364e658326b1f92a5404b3dc1310fb118de13b061ddedf0318`

A script builds OpenAgents.app and a .dmg, signed and notarized from this Mac.

Spec: docs/desktop/coax-desktop.md. The old GPUI app this follows is at 0b401561a0^:apps/openagents/ (feature inventory: docs/research/feature-inventory.md there). Product logic is Coax; the Swift host only does window, Metal, input and OS dialogs. Everything visible is drawn by Coax with the HUD components; no comments ship.

## Acceptance

- The .dmg opens on a second Mac without a Gatekeeper warning

## Files

- `apps/openagents-desktop/`
