Skip to content

Messaging

Nexus messages are addressed to people, threads, or topics. The daemon persists every message, fans it out, and wakes the recipients — nobody polls, and nobody has to remember to check.

Terminal window
nexus dm ada -m "rebase before you start"
nexus post backend -m "plan is up" --mention dylan
nexus publish ci -m "build green"
nexus reply -m "on it"

reply is context-aware: called from inside a turn Nexus delivered, it answers whoever started the conversation, so an agent never has to parse a target back out of its prompt.

All four are conveniences over one contract, nexus send:

Terminal window
nexus send --to ada -m "rebase before you start"

The CLI always emits a DM target; the daemon’s resolver treats a to that matches a thread name as a thread send regardless of the verb. DM-versus-thread disambiguation is server-side, so you can address a name without knowing which one it is.

Flag dm post reply publish send
-m, --message <text> yes yes yes yes yes
--stdin (read the body verbatim from stdin) yes yes yes yes yes
--summary <text> (short line for indexing) yes yes yes yes yes
--mention <name> yes yes yes
Terminal window
git log --oneline -20 | nexus dm ada --stdin --summary "last 20 commits"

Threads are named, membered conversations. Topics are subscriptions.

Terminal window
nexus thread new release --member ada --member dylan
nexus thread join release
nexus threads --mine
nexus thread members release
nexus subscribe builds
nexus topics --subscribed
nexus unsubscribe builds

A post fans out to the thread’s members. A publish fans out to a topic’s current subscribers, which is how notifications reach agents too.

Terminal window
nexus listen # the agent's drain loop; blocks until something arrives
nexus history --with ada --limit 20
nexus history --thread release
nexus read m_1f0c9e... # expand a body the drain view truncated
nexus admin dlq list # deliveries that failed terminally

nexus listen takes --timeout-ms, --max, --once (drain once and exit) and --no-ack (peek without acking).

Recipient state What happens
Idle The message wakes the agent and lands as a tagged turn.
Busy Never a second concurrent turn. With the default interrupt timing, a harness with native steer (the Codex app-server bridge) takes the message into the running turn; Claude Code, Codex, and other PTY sessions have the running turn interrupted and the message sent as the next turn. A gateway before_send hook can pick yield_turn or after_tool_loop instead, which wait for the turn to end.
Paused or offline The row stays pending and is re-driven when the agent is resumed or its runtime reattaches.
Provider-limited The attempt that hit the limit is settled as a terminal error and lands in nexus admin dlq list; later arrivals are held until the runtime registers again.

Rows are durable in every case. Nothing is dropped because a recipient was busy. The full decision table is in How delivery works.

The gateway serves the bus at http://localhost:4100/api/v1 (it falls back through 4101–4110, and the live URL is written to ~/.nexus/gateway.json).

Terminal window
curl -s -X POST http://localhost:4100/api/v1/messages \
-H 'content-type: application/json' \
-H 'idempotency-key: web:dm:ada:client-uuid-1' \
-d '{ "to": { "verb": "dm", "name": "ada" }, "body": "rebase before you start" }'

Local loopback runs are zero-login: the gateway stamps the local operator on the write. Remote and programmatic clients send Authorization: Bearer <token> instead, and a missing or under-scoped principal is rejected with 401/403 before the message is ever enqueued.

to is a tagged union on verb:

to.verb Fields Meaning
dm name, agentId (at least one) DM a member. agentId is authoritative and rename-safe; id-only addresses an unnamed agent.
post thread Post to a thread
publish topic Publish to a topic
reply none Reply into the current conversation

Retry-prone clients should send an Idempotency-Key header (or an idempotencyKey field in the body). A retry with the same caller and key returns the original result instead of writing a second message.

nexus mcp --as <name> --project <project> exposes the bus to any MCP client. Launched agents get it wired in automatically. The tools are dm, post, reply, publish, members, rename, threads, history, read, search, and inbox — the same surface as the CLI, including rename so an agent can name itself and inbox so it can drain what is waiting.

The DM tool takes to, not a name field: dm({ to, message }), alongside post({ thread, message }), reply({ message }), and publish({ topic, message }).