Skip to content

Coding agents ​

The Cursor, Codex and Claude Code sessions on your computer, seen and steered from any device of your account — the phone on the way home, the browser, another computer — and from the Muse itself.

Nothing is installed into the agents and nothing is proxied through anyone's server. The runtime on the computer reads what the agents leave on disk, starts their own command-line interface for a new message, and streams what comes back. Another device asks over the hub; the hub only carries the frames.

In the apps ​

  • Phone: the drawer's Coding row (or Settings → Coding agents, or the nanomuse://coding link). Pick a computer, an agent, a session; read the transcript; type a message and watch the run — the text as it streams, the tools as they are called — and stop it if it goes wrong.
  • Web and desktop: the Coding screen. This computer's agents at the top, the account's other computers after them.
  • The Muse: ask it — "what did I ask Cursor to do last?", "tell Codex in the api repo to add a test for the parser" — and it uses the coding_agents tool with the same read-only readers and the same runner, on this computer or, with device, on another one.

Only computers whose runtime is on the hub and announces the coding.* actions appear; a phone never does.

What is read ​

AgentSessions on diskStarted with
Cursor~/.cursor/projects/<workspace-slug>/agent-transcripts/<id>/<id>.jsonl; CLI chats also ~/.cursor/chats/<hash>/<id>/meta.json (the cwd)cursor-agent -p --output-format stream-json --stream-partial-output --force [--resume <id>] [--workspace <dir>] "<text>"
Codex~/.codex/sessions/YYYY/MM/DD/rollout-<time>-<id>.jsonlcodex exec [resume <id>] --json --skip-git-repo-check -c sandbox_mode="workspace-write" [-C <dir>] "<text>"
Claude Code~/.claude/projects/<workspace-slug>/<id>.jsonlclaude -p --output-format stream-json --verbose --permission-mode acceptEdits [--resume <id>] "<text>"

Reading is best effort: a line that does not parse is skipped, a missing directory is an agent with no sessions. The ~ is the user's home unless NANOMUSE_CODING_HOME names another directory (a container that mounts the host's CLI homes somewhere else, or a test). A session lists its agent, id, title (the first user message), workspace, timestamps, message count, the last exchange and whether it is resumable. Cursor IDE chats can be read but not resumed from the CLI (resumable: false, source: "ide"): a message to one goes straight out as a fresh CLI chat in the same workspace, with the old chat's title and last exchange quoted, and the run says resumed: false; the apps say so above the composer. The same fallback runs when a chat the store called resumable turns out unknown to the CLI.

running on an agent is the number of its processes alive right now, read from /proc on Linux, ps on macOS and tasklist (plus the command lines of node.exe, for the node-bundled Cursor CLI) on Windows — never pgrep -f, and at most once every two seconds.

The runner stops reading when the agent's terminal event arrives, not at pipe EOF: cursor-agent leaves a worker server running after it answers and would otherwise hold the run open forever. The process is then waited for and killed after a grace period.

Where it runs ​

Every agent runs with the permissions it has on that computer — Codex in workspace-write, Claude Code with acceptEdits, Cursor with --force — and edits files there. Sending a message is therefore treated like running a command on that computer: the request travels only between devices of one account, over the account's own hub session, and the computer can refuse remote control altogether (Remote control off keeps coding.* local).

The agents' own API keys and sign-ins are theirs; nanoMuse never sees them. The transcripts are read from disk and shown to you; they are not sent anywhere but to the device that asked.

The API ​

On the runtime (nanomuse serve), behind the app token:

GET  /api/coding                                  → {agents: [{id, name, installed, cli, version, sessions_root, running}], runs: […]}
GET  /api/coding/sessions?agent=&limit=&device=   → {sessions: [{agent, id, title, workspace, path, created_at, updated_at, messages, status, last_user, last_assistant, source, resumable}]}
GET  /api/coding/sessions/{agent}/{id}?device=    → the session with transcript: [{role, text}]
POST /api/coding/send    {agent, text, session_id?, workspace?, device?, wait?}  → the run
POST /api/coding/stop    {run_id, device?}

A run is {id, agent, session_id, asked_session_id, workspace, text, started_at, ended_at, status, output, resumed, error, tools, device?}; status is running, done, error or stopped. The last 50 finished runs are kept in <data_dir>/coding/runs.json and read back when the runtime starts, so the record survives a restart; a run that was still going then comes back as stopped with a note (the CLI process ended with the runtime). While it runs the bus carries {"kind": "coding", "run": id, …} events every open app follows live: started {session_id, model}, text {text, partial} (Cursor sends deltas, then the whole message; the apps replace the streamed text with the final one), tool {text, phase}, done, error.

Over the hub ​

device names another computer; the same request travels as hub actions (coding.agents, coding.sessions, coding.session, coding.send, coding.stop, coding.runs — see hub.md). coding.send with wait follows the run on the target's bus and forwards each step as an event frame whose body carries the run id, so the caller can coding.stop it; the result frame is the finished run.

The tests are tests/test_coding.py (the readers on fixture transcripts, the stream normaliser, a fake CLI, the API) and the hub path in tests/test_hub.py.

GPL-3.0-or-later. nanoMuse is an independent community project, not affiliated with Meta.