agentsocks
Connects GitHub Copilot CLI sessions to the agentsocks network, allowing them to send and receive messages and tasks with other supported coding agents.
Wires Hermes sessions into agentsocks for inter-agent messaging and task routing with other supported agents.
Integrates with OpenAI's Codex CLI for session-to-session messaging and task handoff, and provides an optional public listener for ChatGPT clients.
Optional gateway links your own machines and phone over your Tailscale tailnet, enabling agentsocks communication beyond the local machine.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@agentsockstell api-worker the migration is done and the new column is tenant_id"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
agentsocks lets your Claude Code and Codex sessions message each other, on one machine, the way Claude Code sessions already message each other. Since 0.4 it also reaches OpenCode, Hermes, Cursor, GitHub Copilot CLI, Gemini CLI and OMP (oh-my-pi) sessions (see More agents); those integrations are experimental: each is tested against a simulated version of its CLI and not yet run live against this release.
A Codex session can ask a Claude session a question. The Claude session gets it exactly like a message from another Claude session: between tool calls, or as a new turn if it was idle.
A Claude session can answer, or start the conversation, with its built-in
SendMessage. The Codex session picks it up between tool calls, before it finishes its turn, or wakes up if it was idle.Codex sessions can message each other too.
Nothing is ever typed into a terminal. No tmux send-keys, no pane pastes, no fake user input.
Works with Claude Code and Codex CLI running on the same machine, and with the agents in More agents. Linux and macOS are supported and Termux is best effort. Built and tested on Linux. The test suite also runs on macOS in CI, but agentsocks has not been used with real sessions on a Mac yet (see Limits).
At a glance
Messages and tasks. Sessions message each other and hand over tracked tasks that have an owner, a state and a result (Using it, Tasks).
Attention routing. Each message is routed by what the receiver is doing: at its next tool call, at the end of its turn, or in a digest, so a flood of messages is held back instead of interrupting it each time (Attention routing).
Channels, broadcasts and asks (experimental). Post to a
#topic, broadcast, or ask up to 16 sessions one question and get the answers back together (Channels, Asking several sessions).Workers and drivers (experimental). A worker follows one named driver; everyone else's messages reach it as information only (Workers and drivers).
agentsocks top(experimental). A live terminal view of your sessions and today's routing (Watching it).Beyond this machine (experimental, off by default). An optional gateway links your own machines and your phone over your tailnet, and, only if you add one, a public listener for ChatGPT, Grok and token clients (Beyond this machine).
Related MCP server: interclaude
Install
npm install -g agentsocks
agentsocks install
agentsocks doctorRequires Node.js 22.13 or later, Claude Code 2.1.224 or later, and Codex CLI 0.162 or later (for
codex queue; older Codex still works through tools and hooks). New sessions pick it up. Sessions that
are already running are not touched.
A 30-second demo
Two sessions are running in different terminals: api-worker in Claude Code, and a Codex session in
a web project. You tell Codex: "tell api-worker the migration is done and the new column is tenant_id".
Codex looks up who is running and sends the message with its agentsocks tools. The Claude session
shows it like any other cross-session message:
› Message from @codex-web (codex): Migration is done; the new column is tenant_id. (ctrl+o to expand)Claude answers with its built-in SendMessage. The idle Codex session wakes with a short agentsocks
line, reads the answer with a tool, and replies with another:
› 📨 agentsocks: new message from a Claude Code session. Read it with read_inbox.
• Called agentsocks.read_inbox
• Called agentsocks.send_message
└ Sent to @api-worker [064c2f] (claude), message id 1c8a0f3e-.... Delivered. They see it at their
next tool call, or right away if idle.You can do the same from any shell:
$ agentsocks list
api-worker [064c2f] claude idle /work/api
codex-web [9334a8] codex idle /work/web
$ agentsocks send api-worker "the rebase is safe now"
sent 724739a7-6bac-48cc-b4eb-862ce1708fdb to @api-worker [064c2f] (claude) as @cli-web, routed now
Delivered. They see it at their next tool call, or right away if idle.What agentsocks install does
agentsocks install is idempotent and keeps backups of every file it edits under
~/.local/state/agentsocks/backups/. It:
registers the
agentsocksMCP server with Claude Code at user scope;adds
[mcp_servers.agentsocks]to~/.codex/config.toml;appends five hooks to
~/.codex/hooks.json, after your existing ones, so your hooks keep their positions and their trust;marks those five hooks trusted through Codex's own config API. Use
--no-trust-hooksif you would rather approve them yourself in/hooks.
New sessions pick it up, including Codex sessions started through the shared app-server daemon (it reads the config when each thread starts).
With no flag at all, agentsocks install also wires every other agent it finds on this machine (OpenCode,
Hermes, Cursor, Copilot CLI, Gemini CLI, OMP) and says which it skipped. An agent counts as found when its
config folder exists (~/.hermes or $HERMES_HOME, ~/.copilot or $COPILOT_HOME), or its folder
exists or its program is on PATH (OpenCode's folder or opencode, Cursor's ~/.cursor or cursor-agent,
Gemini's settings.json or tmp under ~/.gemini or $GEMINI_CLI_HOME, or gemini; OMP's ~/.omp or omp). Hermes and
Copilot need the folder because other programs are also called hermes and copilot; start the agent
once, or name it with --hermes or --copilot. A machine with no Codex is skipped for Codex. --opencode, --hermes, --cursor, --copilot and
--gemini and --omp wire just those, even when they are not found yet. Each of them is edited the same careful way
as Codex's files: every entry agentsocks adds can be recognised again (hook commands start with an
AGENTSOCKS_HOOK=1 marker, and the MCP server is the one named agentsocks that runs agentsocks; a server of
that name that does not run agentsocks is left alone), every file it changes is backed up first and written
through a temporary file, a file it cannot parse is left exactly as it was, running install twice changes
nothing the second time, and --dry-run shows what would change. JSON files are rewritten with two-space
indentation, so comments (which the agents do not accept in them anyway) and unusual number formatting are
not kept. The folders can move with OPENCODE_CONFIG_DIR, HERMES_HOME, COPILOT_HOME,
GEMINI_CLI_HOME and, for OMP, PI_CODING_AGENT_DIR, PI_CONFIG_DIR and OMP_PROFILE, read when you install
and when you uninstall. agentsocks install exits 1 when
an agent you named could not be wired, and when a Codex or Claude step failed (the other agents are still
done). agentsocks doctor has one line per agent: wired, partly wired, installed but not wired, or not
installed, and untested live while nobody has run that agent end to end.
A Codex thread the shared app-server loaded before the install keeps its old config until it has had no
attached client and no running turn for 60 seconds, so it has no agentsocks tools or hooks. Restarting the terminal
client does not help while another client (a codex agents dashboard, say) stays attached or the thread is resumed within 60 seconds. agentsocks list shows the recent ones (updated in the last 12 hours, not
archived, started by a person and not spawned as a subagent) as not connected yet. A thread can be there because it started before the install or because its hooks have not run yet. A message to one still wakes it, it reads the message with agentsocks inbox, and the first send registers it. agentsocks doctor lists them and says how to give one full
tools: close every client attached to it (its terminal and any codex agents dashboard), wait 60 seconds
with no turn running, then resume it. In agentsocks list --json every entry carries connected.
A subagent that registered through its own hooks is left out of the list; it still answers to its thread id
or ref, and to its name unless a session that is not a subagent has the same name, which goes to that session.
agentsocks uninstall removes all of it (backups are kept); your message history, audit.log and daemon.log stay in the state directory until you delete it.
Using it
You don't need to do anything special. Ask an agent to tell another session something, or to ask it a question, and it will.
Tools (MCP server agentsocks):
Tool | Claude | Codex and the other agents | What it does |
| ✓ | ✓ | Running Claude and Codex sessions, with names, refs, folders and status |
| ✓ | ✓ | Message a Codex session by name, ref, or reply address, with an urgency of |
| ✓ | ✓ | Hand a session tracked work with acceptance criteria; you hear when it moves |
| ✓ | ✓ | Report progress on a task (accepted, in progress, done, failed) or cancel one you created |
| ✓ | ✓ | Tasks assigned to you or created by you |
| ✓ | ✓ | How a message you sent or received was routed, and whether it was sent, shown or answered |
| ✓ | ✓ | What a session is doing next to what is asked of it, with drift flags |
| ✓ | ✓ | v0.4: join or leave a |
| ✓ | ✓ | v0.4: one message to every live session, at |
| ✓ | ✓ | v0.4: rate a message you received useful-now, could-wait or noise (see Learning from ratings) |
| ✓ | ✓ | v0.4: ask up to 16 sessions one question and get the answers together; answer one you were asked (see Asking several sessions) |
| ✓ | Read messages from other sessions | |
| ✓ | Wait for the next message (for headless workers) | |
| ✓ | Choose the name other sessions see | |
| ✓ | Name the local session that drives this one, or |
Claude keeps using its built-in SendMessage and ListAgents for Claude peers, and can reply to a
Codex sender with SendMessage to the from= address on its message. send_message on the Claude
host does not send to a Claude session. agentsocks cannot attest a Claude sender's permission mode, so
the receiver would show its user a held-message approval prompt; the built-in SendMessage carries the
mode, so the tool returns that advice instead. The same goes for agentsocks send run inside a Claude
session. Codex senders and plain shells are unchanged, and send_task still tracks the task (see Tasks). Text a peer wrote (names, task
fields, notes) comes back in tool output inside a framed block marked as written by another session.
CLI:
agentsocks list # who is running, plus recent Codex threads that are not connected
agentsocks send api-worker "rebase is safe now"
agentsocks send --urgency fyi api-worker "lint is green"
agentsocks send '#deploys' "v2 is tagged" # post to a channel (v0.4)
agentsocks channels # channels with subscribers, and who is in each (v0.4)
agentsocks tasks # your active tasks (run inside a session); --all includes finished ones
agentsocks status <msg-id> # how a message was routed and what became of it
agentsocks status api-worker # what a session is doing and what is asked of it (your own name works too)
agentsocks stats # routing metrics per destination
agentsocks driver <peer|none> # name this session's driver (workers and drivers, v0.4)
agentsocks top # live view of sessions and today's routing counts (v0.4)
agentsocks classifier # smart routing: what is in effect, and how to change it
agentsocks eval-router # score the router on the labelled set
agentsocks eval-router --own # score it on your own rated messages (v0.4)
agentsocks labels export # your ratings as JSONL, for fine-tuning a local model (v0.4)
agentsocks whoami # how this process is identified
agentsocks doctor # check the install
agentsocks gateway status # v0.4: the gateway, remote peers and tokens (see Beyond this machine)
agentsocks link <host> # v0.4: another machine's sessions as name@host
agentsocks peer add grok --api xai --key-file ~/xai.env --may-message api-worker # v0.4: a model behind an API as a peerMore agents (v0.4)
OpenCode, Hermes, Cursor, GitHub Copilot CLI, Gemini CLI and OMP sessions are peers too, in the same inbox, with the same tools, routing, tasks and delivery states as Codex. A session of one of them shows up in agentsocks list and list_peers named after its folder (opencode-api, cursor-web, omp-api), with its agent as the kind, and a message to it is announced and read exactly as for Codex: the text reaches the model only as the result of read_inbox or wait_for_message, in the same marked frame.
None of these integrations has been run live against this release. Each was built from the agent's own documentation and tested against fixtures made from it and against a fake of the agent. Nobody has run them against the real programs yet, agentsocks doctor says untested live next to each, and the first live run may find that an agent behaves differently from its documentation. Treat them as experimental.
Agent | How it connects | How it hears about a message | Idle wake |
OpenCode | A generated plugin, | A one-line notice added to the next tool result; a one-line prompt when idle | Yes, through OpenCode's own client in the plugin |
Hermes | An MCP server and five shell hooks in | A notice at the start of the next turn; one more turn at the end of an edit turn | Only if you run Hermes's API server and give agentsocks its key ( |
Cursor (CLI and IDE) |
| A notice after the next tool call; a follow-up message when the turn ends with messages unread | No |
GitHub Copilot CLI |
| A notice after the next tool call; one more turn when the model tries to finish | No |
Gemini CLI |
| A notice after the next tool call; one more turn when the model finishes | No |
OMP (oh-my-pi), full | A generated extension, | A note after the next tool result; a hidden note before a turn; one more turn when the model finishes; a custom message when idle | Yes, through OMP's own |
The agents that cannot be woken are pull-only: they hear nothing while idle, and a message waits until the session next calls a tool, finishes a turn, or is asked to read its inbox. The notices and nudges are counts and a sender kind, never message text, and a nudge at the end of a turn is limited to three in a row.
Hermes, Cursor, Copilot CLI and Gemini CLI do not say which session made an MCP call, so their pre-tool hook stamps the session into the arguments of agentsocks tools, signed with a key only your user can read, and the MCP server accepts a session only from a valid stamp (SECURITY.md has the detail and its limits). Whether each agent really applies that rewrite to MCP tools is not documented, and it is the first thing a live run has to show. Gemini CLI also asks you to confirm each agentsocks tool on first use unless you allow the server; agentsocks never sets trust.
agentsocks install with no flags wires every one of them it finds. --opencode, --hermes, --cursor, --copilot, --gemini and --omp wire one, and agentsocks uninstall removes every entry it added (your own hooks and servers are left in place, each file is backed up first, and a file that does not parse is never touched).
Aider is not supported. It has no MCP client and no hooks, so there is nothing for agentsocks to attach to.
OMP (oh-my-pi)
OMP is the one of these that gets the whole treatment, like OpenCode: tools, a note in the middle of a turn, a nudge at the end of one, and a wake when idle. It is also untested live. The extension targets OMP 18.10.3 (doctor says so, and calls another major partly wired). An earlier 0.4 build passed scripts/live/omp.sh against omp 18.10.3; this release has not been run live. scripts/live/omp.sh is the run that would show it.
How it connects.
agentsocks install --ompwrites one file,extensions/agentsocks.ts, in OMP's agent folder (~/.omp/agent, or$PI_CODING_AGENT_DIR;$PI_CONFIG_DIRrenames~/.omp;OMP_PROFILEorPI_PROFILEselects~/.omp/profiles/<name>/agent, and thenPI_CODING_AGENT_DIRdoes not apply, as in OMP). Its first line marks it as ours, it is mode 600, and OMP loads it the next time it starts.uninstalldeletes only a file with that marker, from the agent folder and from every profile folder.Tools.
agentsocks_list_peers,agentsocks_send_message,agentsocks_read_inbox,agentsocks_wait_for_message, the task, channel, ask and rating tools: one for every tool the Codex route has, always loaded, with thereadapproval tier for the read-only ones andwritefor the rest (OMP's default mode,yolo, allows both). The prefix is there because OMP has its ownask. The session a tool acts for is the one OMP says it is running, read from OMP when the tool is called, so a model cannot name another.What the model is told. After a tool result, when a message waits, OMP adds one line to the next request as context:
📨 agentsocks: new message from a Claude Code session. Read it with agentsocks_read_inbox before your next step.A hidden note of the same kind goes in before a turn if one waits when you submit a prompt. When the model finishes with a message unread, one more turn is asked for with the finish-time line, at most three times in a row. The lines are counts and a sender kind, never message text.Idle wake. The extension long-polls the broker, and a message for an idle session starts a turn with the line
📨 agentsocks: new message from a Claude Code session. Read it with agentsocks_read_inbox.as a custom message of typeagentsocks-notice. The extension never types as the user. While the model is working the line goes in as an aside at the next step instead.Subagents. Only a top-level session is a peer. Subagents (
task,/tanclones), an advisor and anything else OMP does not call the main agent get no tools, no notices and no wake.Things to know. Every line agentsocks hands OMP (a wake, a notice while the model is busy, the finish-time nudge) is an aside: an idle session starts a turn to read its mail, but in plan mode, or after you stop a turn with Esc, OMP folds the line into its context without starting a turn, so it waits until you type again. OMP's extension API changes between minors:
agentsocks doctorprints the OMP version next to the one tested (18.10.3) and calls a different majorpartly wired. If OMP is set to read Claude Code's or Codex's config (enabledProviderslistsclaudeorcodex, orCLAUDE_CONFIG_DIRis set), the agentsocks servers registered there would start inside OMP with no session to attribute their calls to;installanddoctorwarn, anddisabledProvidersis the fix. The extension runs inside OMP with OMP's privileges and spawnsagentsockswith a trimmed environment.
Codex threads in Claude Code's own ListAgents (experimental, Linux, off by default). agentsocks install --claude-listagents makes the broker write one record per live Codex thread into Claude Code's session registry (~/.claude/sessions), the way claude-uds-bridge does, so Claude's built-in ListAgents shows them and SendMessage reaches them. A small holder process per thread supplies the live pid the registry needs. The broker removes the records when a thread ends or the broker stops, deletes only records it wrote (its ledger names them), and never touches the records of real sessions. It stays off unless you ask, and it has not been run against a live Claude Code. agentsocks uninstall turns it off and removes what it wrote.
Attention routing (v0.2)
A message does not always have to interrupt. agentsocks decides, per message, from what the receiver is doing and how many messages it has already had:
Route | Meaning | Claude receiver | Codex receiver |
| At the receiver's next tool call, or at once if it is idle | priority | announced at the next tool call; wakes an idle session |
| When the receiver's current turn ends | priority | not announced mid-turn; blocks |
| Batch it | held, then one combined message (split if it is large) when the session is idle or after 15 minutes | held, released when the session is idle, reads its inbox or after 15 minutes; never wakes anyone |
| Same text already delivered in the last 10 minutes | recorded, not delivered | recorded, not delivered |
The default is now, because a native Claude message already lands at the next tool call; the
protection against floods is the receiver's budget. Rules run first, in this order: a duplicate of
something already delivered is merged; a sender past 10 messages in 10 minutes is batched (urgent
messages and answers to a message the receiver sent are exempt); fyi is batched; an idle receiver
gets it now; an answer to a now or pause message the receiver sent in the last 30 minutes gets it
now, outside the budget; urgent gets it now unless the receiver was already interrupted six times in
10 minutes. Everything else is delivered now unless the receiver was interrupted three times in the last
10 minutes, in which case it is paused, or smart routing says otherwise. A receiver whose
state is unknown is not treated as idle. Repeating a message that is still held or paused, or was
sent in a digest that the receiver has not yet been shown or read, promotes it (urgent beats a digest)
instead of being merged away. Claude's priority now (which aborts the running
turn) is never used.
Every decision is recorded with its rule or backend, confidence and a one-sentence reason; read it
with agentsocks status <msg-id>. A frame that reaches a Codex inbox from outside agentsocks (Claude's
own SendMessage, say) is routed the same way, but it has no outbox row: if it is merged, only the
audit log records that. What the sender is told is one sentence, for example "Delivered. They
see it at their next tool call, or right away if idle."
Typing guard. Before waking an idle Codex session agentsocks checks whether any Codex terminal
read input in the last 38 seconds (Linux only: on macOS it never holds, and agentsocks doctor says so. A terminal's
access time moves in steps of about 8 seconds). It holds and re-checks every 5 seconds; after 10 minutes it
delivers only into an 18-second quiet gap. A failed wake backs off from 30 seconds to 10 minutes and
does not use up the hourly limit of six; urgent messages and answers are exempt from that limit but have
their own of 20 an hour per thread, so two sessions answering each other cannot wake one forever.
Smart routing
The rules decide most messages. For the ones they do not (a normal message to a busy session), agentsocks
asks a classifier whether the message needs the receiver to stop now, can wait until its current step
ends, or can be batched. The classifier is TypeSafe Jev, a small hosted model, and it is off until you
turn it on with agentsocks classifier jev. Until then the rules alone route every message and nothing
is sent anywhere. A TYPESAFE_API_KEY in your environment does not turn it on; agentsocks install and
agentsocks doctor tell you when one is there.
Turn it on. Get a key at https://console.typesafe.ai/keys, then give agentsocks the key in one of two ways:
agentsocks classifier jev --key-file ~/typesafe.env
printf '%s' "$TYPESAFE_API_KEY" | agentsocks classifier jev --key -The first points agentsocks at a KEY=VALUE file that has a TYPESAFE_API_KEY line and reads the key from
it. The second reads the key from stdin, stores it in ~/.config/agentsocks/env (mode 600) and never prints
it. Neither puts the key on a command line, where it can end up in your shell history and in ps. Typing
--key - and pasting at the prompt is not a reliable form: a terminal needs Ctrl-D twice when the paste has no
trailing newline. Giving the key as --key <key> also works.
Once Jev is on, the broker looks for TYPESAFE_API_KEY in the config's apiKeyFile first, then in that env
file, then in its own environment, so a key you stored on purpose wins over one a shell happened to export
and takes effect in a running broker. An install that already names an apiKeyFile in its config, or has a
key stored in the env file, keeps working unchanged. The env file is there because Codex starts MCP servers with a small
environment and the broker is started by whichever client runs first. agentsocks classifier and
agentsocks doctor say which source holds the key in use, and say so when your shell has a key but the
running broker reports its classifier off.
If config.json or the env file is a symlink, the commands write through it to the file it points to.
agentsocks uninstall leaves the env file in place and prints the command that removes it.
Change it. agentsocks classifier shows what is in effect (backend, url, whether a key was found,
whether it is remote). The commands write config.json atomically, keep its other keys, and the daemon
picks the change up on its own.
agentsocks classifier jev [--key - | --key-file <path>] # hosted TypeSafe Jev (off until you turn it on)
agentsocks classifier local <url> [--backend systemone|gliner2] [--allow-remote] # your own hardware
agentsocks classifier off # rules onlyAn agent that is asked to change it can run these in a shell. No MCP tool changes the classifier, so a message from a peer cannot talk an agent into pointing it at another host.
What leaves your machine. Only for a message the rules do not decide, and only to the configured
classifier. Exactly two things are sent: the message text (secrets redacted, at most 2,000 characters),
and the receiver context. For a Codex receiver that is its kind, its last tool and its latest prompt. For
a Claude receiver it is its kind and its latest typed prompt, or the session's name and working directory
when no prompt is found. A prompt has secrets redacted and is cut to 200 characters, and it is never
written to disk or logs. Tasks never go to the classifier: an assignment and its notices are decided by
the rules alone. The assignment is urgent for risk high and normal otherwise; a notice is normal when the
task is done, failed or cancelled and fyi for any other change, whatever the risk. A failure, a timeout or
low confidence leaves the default route, and the confidence is the probability the classifier gave the route
it chose.
SECURITY.md has the full list.
On your own hardware. For data sovereignty, a bigger box, or a model you fine-tune on your own traffic, run Laya (it speaks the same API as Jev) or GLiNER2 yourself and point agentsocks at it:
agentsocks classifier local http://127.0.0.1:8765 --backend gliner2A classifier on this machine sends nothing off it. Any other host must be https and needs
--allow-remote, which records that message text is allowed to go there; without the flag the command
refuses and says why. To run the GLiNER2 backend (fastino/GLiNER2.5-Decide):
pip install gliner2 torch # in a virtualenv
python3 contrib/gliner2_server.py 8765It listens on 127.0.0.1 only and loads the model once at start-up.
agentsocks eval-router --backend config scores the classifier in effect on
contrib/router-eval.json against the no-classifier baseline (everything delivered now). Run it
on your own data before you trust a local model.
Measured
On the 40-case set contrib/router-eval.json (receiver busy):
Backend | Accuracy |
| p50 latency |
TypeSafe Jev, hosted ( | 92.5 to 95% over two runs | 0.89 / 1.00 | about 235 ms |
Laya base checkpoint, local CPU, 4 threads | 55% | 0.67 / 0.71 | 965 ms |
Fastino GLiNER2.5-Decide, local CPU, 4 threads | 50% | 1.00 / 0.71 | about 4 s on a loaded 16-vCPU host |
Rules alone (everything delivered now) | 42.5% | 0.43 / 1.00 | 0 ms |
Jev's own choice is right on 39 of the 40 cases. The default confidence threshold of 0.5 sends the borderline answers (where no route holds half of the probability) to the default route, which is why the end-to-end figure is a little lower. The threshold was chosen after looking at this same set, so treat the Jev figure as a measurement on that set and not as a held-out result.
Hand-written config. ~/.config/agentsocks/config.json (or the file named by AGENTSOCKS_CONFIG).
With no file, or a file without a classifier key, no classifier is used (rules only), unless a key is
already stored in the env file. {"classifier": {"backend": "none"}} turns it off, and a config that cannot be read turns it off too.
{ "classifier": { "backend": "gliner2", "url": "http://127.0.0.1:8765", "threshold": 0.5, "timeoutMs": 1500 } }Field | |
|
|
| The service. A host other than |
|
|
| Name of the environment variable holding the key (default |
| Passed to |
| Minimum confidence, default 0.5 |
| Hard limit per message, default 1500, at most 5000 |
If the config names a key (apiKeyEnv or apiKeyFile) that cannot be found, the classifier stays off
and agentsocks classifier says key MYKEY not set: classifier off. agentsocks install and
agentsocks doctor print one line saying whether smart routing is on.
Tasks
send_task creates a durable task (T- and six hex characters) and sends the assignee one message
with the details, the acceptance criteria and how to update it. Risk high is sent as urgent. The
assignee moves it with update_task (accepted, in progress, done or failed, with a result and
evidence); only the assignee moves a task forward and only the creator cancels. The creator is told
about every change, and update_task says whether that notice was sent, batched or could not be sent.
Between two Claude sessions agentsocks tracks the task but posts nothing, for the same reason as above:
send_task creates it and returns a block to send to the assignee with the built-in SendMessage, and
update_task says the other side was not notified automatically and gives one line to send. The expiry
of such a task is not posted either. Tasks between Codex and Claude, and between two Codex sessions, are
posted and notified as before.
Tasks expire after 24 hours unless the creator sets another time; the assignee can still report a late
done or failed on an expired task. Tasks are matched by session as well as by address, so a Claude
session that restarts keeps its tasks and gets their notices. When a task finishes, progress notices
still waiting in a digest are dropped. A session lists only the tasks it created or was assigned
(agentsocks tasks needs to run inside a session). A task's "on behalf of" field is a claim by the
sender; it never counts as approval.
Workers and drivers (v0.4, experimental)
A worker session (OMP, Codex, any broker-managed inbox) has at most one driver: the orchestrator whose
instructions it follows. It names the driver itself, with the set_driver tool (agentsocks_set_driver
in OMP) or agentsocks driver <peer|none> from inside a Codex shell (a worker driven by Claude binds itself with its own session's tool; the Claude host has no set_driver); only the session itself can use them, though any same-user process can write the broker op directly, so this is coordination, not a boundary.
Everyone else's messages still arrive, but as digests (a reply to the worker's own message arrives as a pause) labelled information-only, never as competing orders,
and the sender is told the worker may not act on them. A send_task from anyone but the driver is refused.
The worker's reports to a driver that instructed it floor at pause, at most 12 an hour per pair, the 13th routing normally; a duplicate of something already delivered merges instead (never a second interruption). An instruction is a task the driver assigned it or a direct message or delivered native frame from it (replies count; channel posts and broadcasts never do), recorded as a timestamp when delivered and honored for 24 hours. read_inbox groups messages under the driver and
everyone else; list, peer_status and top show the driver when one is set, and notices say when it is
offline. The binding is coordination, not a boundary (see SECURITY). Claude Code receivers are out of scope:
native SendMessage does not pass through the broker.
Channels and broadcast (v0.4, experimental)
A channel is a #topic that sessions subscribe to. subscribe and unsubscribe are tools, and a
channel exists while it has a subscriber. Subscriptions are kept in the database, so they survive a
restart of the broker; one whose session has not been alive for 30 days is dropped.
A message to #deploys (send_message with to set to #deploys, or agentsocks send '#deploys' "...") is fanned out by the broker. Every subscriber except the sender gets its own delivery, routed by
the same rules, budgets and classifier as any other message, so a busy subscriber can have it paused or
batched while an idle one gets it now, and a sender past ten messages in ten minutes to one subscriber
has the rest of its posts to that subscriber batched. The body starts with [#deploys], the result lists
each delivery with its message id for message_status, and a subscriber that cannot be reached is
reported without stopping the others.
broadcast (the same as a post to #all) goes to every live Claude Code and Codex session on this machine except the sender (not to a remote peer, see "Beyond this machine"), as fyi
(batched; the default) or normal. An urgent broadcast is refused. A session holds at most 32
subscriptions and a post goes to at most 64 running sessions; subscribers that are not running are not
tried, are named in the result (up to ten) and stay subscribed. A Claude session cannot send to a
Claude session through agentsocks (it cannot attest its permission mode, see Security), so when one
posts to a channel its Claude subscribers are listed in the result and it reaches them with its built-in
SendMessage; Codex sessions and plain shells reach every subscriber. Tested against fake Claude and
Codex sessions; not yet run in live ones.
Asking several sessions (v0.4, experimental)
ask sends one question to up to 16 sessions (names or refs from list_peers, and #channel names for
a channel's subscribers) and returns when all of them have answered or after timeout_seconds (60 by
default, at most 280). Each session gets its own routed message that carries an ask id and says to reply
with the answer tool. The answers come back together, labelled with who gave them, and the sessions that
did not answer are listed; an answer sent any other way, with send_message, still reaches the asker as an
ordinary message. A session answers once, in at most 4,000 characters, and only while the ask is open.
Asks and answers are kept for 14 days. Like send_message, a Claude session cannot ask Claude sessions
through agentsocks: they are listed in the result, and it reaches them with its built-in SendMessage.
An ask is routed like any message. A busy receiver may see it only when its turn ends (it was interrupted
lately, a classifier judges it can wait, or the sender has been rated down, see below) or in a digest (the
sender is past its budget, or a classifier judges it low priority). The result says how each question was
routed. An ask that is still open when the
broker stops is closed, and a late answer is told to use send_message. A channel's sessions that are not
running are left out of an ask.
pick: "best" also asks the smart-routing model, only if you turned one on (see Smart routing), which
reply answers the question best. The result shows every reply, then the model's choice with the
probability it gave each reply, or the reason there is no pick: no model, one reply, a confidence below the
model's threshold, a failure or a timeout. It is the model's opinion and never replaces the replies. It
sends the question and the replies, secrets redacted and cut to 1,000 and 1,500 characters, to that model,
which for hosted Jev is api.typesafe.ai. Tested against fake models only; the request for hosted Jev
follows the shape of its delivery question and has not been tried against the live API.
Learning from ratings (v0.4, experimental)
A receiver tells agentsocks whether a message was worth the interruption with rate_message:
useful-now, could-wait or noise. A Codex session rates by the id its inbox shows; a Claude session
rates the latest message from a sender by name (as its envelope shows it, with or without "(codex)"), or
just the latest one. agentsocks adds three signals of its
own: a reply within ten minutes is useful-now, a duplicate it merged is noise, and a Codex message
still unread two hours later, although the session kept working, is noise. Everything is stored in the
local database for 180 days. Nothing is trained, and nothing is sent anywhere unless you replay the
text against a classifier that is not on this machine (see --own below).
What it changes: a sender that has at least five rated messages delivered now in the last 30 days, of
which 60% or more were rated could-wait or noise, has its grey-zone messages paused instead of delivered
now. The deliveries of one channel post or ask count as one send. A rating applies to the sender
everywhere, so a sender that is rated down is paused for every receiver until its ratings age out after 30
days or its other messages are rated well. The decision reason says so, for example "4 of 6 of this sender's earlier messages delivered now
were rated could-wait or noise by their receivers", and agentsocks status <msg-id> shows it. Urgent
and fyi messages and every other rule decide as before, and the adjustment never makes a route more urgent.
agentsocks eval-router --own replays the rated messages that kept their text through the classifier in
effect (a busy receiver and urgency normal, like the shipped set) and reports how the routes chosen at the
time compare with the labels. A classifier that is not on this machine, which is hosted Jev, gets that
text and the receivers' tasks only if you add --allow-remote; otherwise the command refuses. agentsocks labels export prints every label as one JSON object per line
(task, message, decision, and what was routed) so you can fine-tune a local model yourself; an agent is
refused, because the output is message text. Only an explicit rating carries text. A rated Codex message
keeps its text from the inbox; a Claude receiver's message only while it is still in the broker's memory
(two hours, secrets redacted, 2,000 characters), so a later rating is stored without it. A Claude
session's prompt is never stored, only its session name and folder.
Watching it: agentsocks top (v0.4, experimental)
agentsocks top is a live terminal view (plain ANSI, no dependencies, redrawn every second; q or Ctrl-C
quits and restores the terminal). It lists each live session with its state, unread messages, digests held,
active tasks, when it last had a message and from whom, and a Codex session's current task (a Claude
session does not report one). Under it are today's counts since local midnight: messages routed,
interrupts avoided (paused, batched and merged), digests flushed, and the median time from sending to
shown. They are counts only: nothing estimates time saved. They cover messages sent through agentsocks and
those Claude's built-in SendMessage sends straight to a Codex session (counted when they arrive, but a
duplicate that was merged leaves only an audit-log line, so it is not counted); a message between two
Claude sessions is not seen. top --once prints one frame without a
terminal (names are framed when it is piped or an agent runs it), and top --json prints one snapshot as
plain data for a dashboard. It never starts a broker. Without a terminal, or run by an agent, it prints one
frame and exits.
Is it getting there?
Delivery is tracked in states that are only reported when observed: sent, held (a receiver's
gate holds it, or it is waiting in a digest), shown (Codex: the session acknowledged reading it;
Claude: our message id appears in the receiver's transcript as a peer origin), replied (the
receiver wrote back to the sender after the message had been shown). A message that was merely queued
is never reported as shown, and a reply never makes a message shown.
agentsocks status <peer> compares what is asked of a session with what it is doing and flags drift:
idle with unread messages older than 5 minutes (a digest counts from when it was released), a task
accepted or in progress with no update for 2 hours, a task still open 30 minutes after it was created (which
also catches a Claude to Claude task its creator never forwarded), a Codex session busy with no hook activity
for 15 minutes. agentsocks stats reports, per destination, route counts, median time to shown and to reply,
interrupt precision (the share of now messages that interrupted a busy receiver and were answered
within 30 minutes) and escalations (a follow-up from the same sender, other than an fyi, while an
earlier one is still held or paused). Transcripts are read only for our own message ids; their content
is never stored or logged. A message to a Claude session whose transcript cannot be found stays sent.
A background Claude session that is running subagents reports itself busy until they finish, so its
digests arrive at the 15-minute limit rather than when it goes idle.
How delivery works
To | Path |
Claude Code | Posted to the session's own cross-session inbox socket ( |
Codex | Stored in that thread's agentsocks inbox. Codex is told a message is waiting by an agentsocks hook or, when the session is idle, by |
OpenCode, Hermes, Cursor, Copilot CLI, Gemini CLI, OMP | The same inbox, in the same way. The notice that a message is waiting comes from that agent's own hook, plugin or extension mechanism, and the text only reaches the model as the result of |
A per-user broker (agentsocks daemon, started on demand) keeps the Codex inboxes in SQLite and
serves one socket per Codex thread in the same format Claude Code uses, which is why Claude's built-in
SendMessage can reply to a Codex session directly. When Claude's own cc-socks directory exists the
inbox is advertised there under a hex name, so Claude also sends its held, denied and dropped receipts
back; the old t/<thread>.sock path stays bound as an alias. agentsocks never creates that directory
and never touches another file in it.
Upgrading: update the package (npm update -g agentsocks), then run agentsocks install: it stops
a running older broker (after checking that the process really is an agentsocks daemon, including a
same-version broker from a different build) so the next command starts the new one. Until then senders
say "The running agentsocks broker is an older version. Run agentsocks install (or stop pid N) and
retry.", or post straight to the inbox and say so; agentsocks doctor reports a version or build
mismatch.
Beyond this machine (v0.4, experimental)
Everything here is off until you turn it on, and each part has an off switch. Nothing listens on a network interface, and nothing is sent anywhere, unless you run the command that starts it. SECURITY.md says what is exposed at each step, lists every route and how it is authenticated, and says what was and was not tested live.
The pieces share one idea. A remote peer is a peer that is not a Claude Code or Codex session on this machine: your phone, a model behind an API, ChatGPT, Grok, another machine's sessions. It shows in list_peers as kind remote, with how it connected (via tailnet, token, oauth or api) and which machine. It uses the same tools as a local agent, has a list of the names it may message, and goes through the same routing, budgets and rate limits. A message from a remote peer can never approve anything, and it carries no permission mode, so a Claude session that bypasses permissions holds it for your approval. Its from-name carries a marker: <name> (remote) for a token, OAuth or API peer, name@host for a linked machine's session, <login> (phone) for the phone app. A new peer name cannot contain @ or brackets and cannot collide with a live local session, so the marker always tells the sender apart; where names still repeat, send by the ref in brackets.
The gateway
agentsocks gateway on # listens on 127.0.0.1 (a per-install random port) and prints the tailscale serve command it needs
agentsocks gateway on --serve # the same, and runs that command after saying what it does
agentsocks gateway status # listeners, peers with their may-message lists, token ids, the source-check verdict, last activity
agentsocks gateway off # stops listeners, links, API peers and in-flight requests; undoes serve/funnel agentsocks set up
agentsocks gateway routes # every route, which listener serves it, how it is authenticatedThe listener binds 127.0.0.1 only. tailscale serve is what puts it on your tailnet over HTTPS, and it adds the identity of the caller. agentsocks accepts a request only when that identity checks out against tailscaled (whois, one wait capped at 300 s by AGENTSOCKS_TAILSCALE_TIMEOUT_MS), the node belongs to you (or to a login you named with gateway allow --user, which a tagged server needs; an admitted login starts with an empty may-message list while your own nodes keep *; peers made by an earlier build keep theirs until narrowed with gateway may) and is not tagged, and the request carries no Funnel marker. The gateway stays on across broker restarts until you run gateway off. gateway off stops the private and public listeners, federation links, API peers and in-flight requests, undoes any serve or funnel agentsocks set up, and prints what it stopped; uninstall runs the same stop, disables and revokes every token, grant and API peer (their families stop minting at once), and archives the gateway state into the backups directory (never deleted). Where the local source cannot be checked (same-user tailscaled, macOS), gateway on refuses unless --allow-unverified-local-source is passed, which means any program on this machine can present itself as a tailnet device. The kill switch answers 503 and closes the listeners. Running agentsocks gateway on from inside an agent session is refused: set it up yourself. That refusal is a guard against accidents, not a security boundary; an agent that shakes off its session can still act, and such a process is already inside the trust boundary.
An MCP client on another of your devices (Claude Code on a laptop, an agent framework) can use https://<this machine>.<your tailnet>.ts.net/mcp over streamable HTTP, with no sign-in beyond the tailnet itself. It gets the same tools as a local Codex session except set_name and set_driver, and the v0.4 tools described under "Channels, asks and ratings from a remote peer" below except broadcast. It appears as a remote peer named after its node (hetzner-lab); everything on one node shares that identity. Not tested against a real MCP client other than the SDK's.
Your phone
Open https://<this machine>.<your tailnet>.ts.net/app/ on a device signed in to your tailnet. It is a small web app with no build step: inbox, reply, send (with the urgency you pick), tasks and the peer list. On a phone, add it to the home screen. Turning notifications on (Web Push, from a tap) sends a push with no content when something is waiting; the app shows what. You appear to your agents as a peer named after your login, for example sam (phone), once the app has connected. Push and the page on a real iPhone or in Safari have not been run yet.
Channels, asks and ratings from a remote peer
The gateway has an explicit list of the tools each kind of remote peer may call, and a tool that is not on it is not there. A peer on your tailnet (your own machines and your phone) has subscribe, unsubscribe, list_channels, ask, answer and rate_message, and can post to a channel with send_message and a #topic. It does not have broadcast, a post to #all is refused, and so is asking #all. A public peer (token, OAuth or API) has only answer of these, so a local session can ask it a question and read its answer, and it cannot subscribe or post.
What a remote peer may do with a channel is cut down to the names on its list (gateway may). It subscribes only itself. It sees in list_channels and in a post's result only the members it may message, and a channel with none of them is not shown. A post or an ask to a channel goes to those members and no one else, and answer is refused when the asker is not on its list. rate_message rates only a message the peer was sent. ask with pick is refused, because it would send the replies to your classifier, and an ask waits at most 120 seconds.
In the other direction, a broadcast from a local session reaches local Claude Code and Codex sessions only, never a remote peer, because it names no one and a remote peer may be a service outside your machine. A remote peer that subscribed to a channel receives posts to it, and agentsocks top lists remote peers as remote. An explicit rating by a remote peer is stored with receiver kind remote and counts for the sender like any other. A session that is renamed off a peer's list is not reached by it, through a channel or directly. Tested against fake sessions and the gateway's own listeners; not run on real machines.
Another machine's sessions
On the machine whose sessions you want to reach (hetzner-lab), allow the other one, and on this machine link to it:
agentsocks gateway on --serve && agentsocks gateway allow my-laptop # on hetzner-lab
agentsocks link hetzner-lab # on my-laptopIts sessions then appear here as name@hetzner-lab and yours there as name@my-laptop. A message to one is forwarded and delivered the normal way on the far side (a Claude session receives it through its own cross-session inbox, a Codex session in its agentsocks inbox), and the sender is named name@host. Linking is opt-in on both ends, the traffic is outbound from the machine that linked, and a linked machine can reach only the other's Claude and Codex sessions. agentsocks link --remove <host> undoes it. Tested with two brokers in temporary directories; not yet on two real machines.
ChatGPT, Grok and other remote clients
agentsocks gateway public --via funnel # a second listener, still on 127.0.0.1 until you expose it
agentsocks gateway token add grok --may-message api-worker codex-web
agentsocks gateway pair chatgpt --may-message api-worker --redirect-host chatgpt.com # optional: only an application that returns to that host may use the codegateway public prints the exact tailscale funnel (or cloudflared) command and runs the funnel one only with --yes. agentsocks gateway may <peer> [<name>...] changes the names a peer may message later; a ref or session id survives a rename, so prefer it over a mutable name. A token is shown once and stored as a salted hash; send it as Authorization: Bearer <token>, or as ?key=<token> where a client cannot set headers. A peer name cannot contain @ or brackets, cannot collide with a live local session, and cannot carry the (remote) or (phone) markers, so no local session name can imitate a remote peer. Names an agent chooses (set_name, register with an explicit name) are refused with a suggested alternative; names agentsocks derives (hook-supplied names, Codex thread titles, folder defaults) fall back to the uniquified <agent>-<folder> default after NFKC normalization. ChatGPT's developer-mode connector uses OAuth: point it at https://<public address>/mcp, and when it sends you to the consent page type the six-digit code that gateway pair chatgpt printed (it works once and expires in ten minutes). A peer on the public listener has list_peers, send_message, read_inbox, wait_for_message and answer, sees only the peers it may message, cannot send urgent, and cannot post to a channel. Its messages reach you as <name> (remote). Both the ChatGPT and the Grok connector are experimental: the flows follow the documented shapes and were tested against fakes, and have not been run against the real services. Whether ChatGPT can write at all depends on its plan.
A model behind an API as a peer
agentsocks peer add grok --api xai --key-file ~/xai.env --may-message api-worker
agentsocks peer add chatgpt --api openai --key-file ~/openai.env --may-message api-workerThe peer is named grok (api) so nobody mistakes it for a session, and its messages reach you as grok (api) (remote). When a message arrives, the broker calls the provider's Responses API with list_peers, send_message, read_inbox and answer as function tools; the first prompt carries no message text, so peer text reaches the model only as the result of read_inbox. The key comes from the file you name (XAI_API_KEY=... or OPENAI_API_KEY=...) each time it is used. An answer takes one to six paid calls (one for each round of tool use), capped at 30 calls an hour, counted across broker restarts (--max-calls-per-hour), and the peer is switched off when the provider rejects the key. Only fake servers were used; no real call has been made.
Security
Security. Every release, 0.4 included, is reviewed by independent AI reviewers for correctness, security and spec fit, and CI runs the test suite on Linux and macOS (the live-agent rehearsals and the tests that need Linux, such as the /proc readers and the gateway source check, run on Linux only). CI scans the full git history for secrets on every push. See SECURITY.md for what stays on your machine and what does not. Argo, Aelethion's code security scanner, is coming soon.
Same user only. Sockets are
0600in0700directories, as with Claude Code's own inbox. Symlinked or foreign-owned targets are refused. Any process of your user can reach the broker, so the per-session views of tasks and messages keep sessions out of each other's way; they do not stop another process of yours that can read the database file.A peer is never your user. Claude Code frames peer messages itself. In Codex, peer text only ever arrives as tool output, never in a hook, a Stop reason or a queued line, because Codex gives hook context developer authority and treats a Stop reason as a user prompt. Peer-written text in agentsocks tool output is framed the same way, and so is what the command line prints (
list,send,tasks,status,stats,inbox, and the thread names indoctor) unless a person runs it at a terminal. It is framed when a Codex thread or a process under a Claude Code session runs it, when its output goes to a pipe or a file, and withAGENTSOCKS_FRAME=1. Only a command with no agent in its ancestry and a terminal for output prints plain text.--jsonoutput is plain data.No approvals by message. A message cannot approve a permission prompt or change settings, in either agent. Each session's own permission mode still applies to anything a peer asks for.
Honest sender mode. A Codex sender reports its real permission mode (
bypassonly when its approval policy isnever), so a Claude session that holds messages from bypassing senders still does. A digest claims the weakest mode among its messages.Limits mirror Claude Code's inbox: 64 KiB per message, 30 messages per sender with a refill of one every two seconds (checked before any routing work), identical text merged, at most 200 unread per Codex thread.
What is kept. The audit log at
~/.local/state/agentsocks/audit.logholds one line per send, receive, wake, route decision and receipt, with a hash of the body rather than the body. The outbox keeps a message's text only while it is held in a digest; messages in a Codex inbox are kept for 14 days. The prompt a Codex session is working on is stored redacted (tokens,Bearervalues,key=,token=,password=andsecret=values in text or JSON,--passwordand--tokenflags, passwords in URLs, and 32-character runs that mix upper case, lower case and digits; paths, UUIDs and git hashes are left alone), cut to 200 characters, and shown to peers at 100. A barekey,token,secretorpasswordfollowed by a plain word is prose and stays (primary key: id); a quoted value, a value with a digit, a symbol such as$or@, a capital inside the word, or a long run is redacted, and names such asapi_keyalways are. A password that is a single-case word under 16 letters is not caught. A Claude session's prompt is read from its transcript only to be sent to the classifier; it is never written to disk or logs (a cache in memory holds the redacted 200 characters) and is not shown.Classifier privacy. Nothing leaves the machine unless you turned on hosted TypeSafe Jev with
agentsocks classifier jevor the config names another host withallowRemote: true. Redirects are never followed, the response is capped at 100 kB, and keys are never logged or printed.Kill switch:
touch ~/.config/agentsocks/off, or setAGENTSOCKS_OFF=1. It stops sends, classifier calls and wakes on every path.
Roadmap
Coming soon:
A Grok bot. Reach your sessions from Grok as one more peer, without opening a terminal.
MCP outside the terminal. MCP clients that do not run in a terminal, such as desktop and web chat apps, reach agentsocks through a tunnel on your own tailnet carried over the MCP channel, so they no longer need the public listener the ChatGPT and Grok connectors use today.
Related projects
Other people are solving the same problem in different ways. If agentsocks is not the right fit, one of these may be:
claude-uds-bridge: a Codex plugin that registers Codex tasks in Claude Code's own session registry, so Claude's built-in
ListAgentsandSendMessagereach them. Closest to agentsocks in approach. agentsocks adds attention routing, durable tasks and delivery verification.hcom: messaging, watching and spawning across many agent CLIs. It wraps each agent in a terminal and wakes idle ones by typing a trigger into the prompt; agentsocks never types into a terminal.
agent-bridge: a Claude Code and Codex bridge using Claude's MCP channel notifications and a proxy in front of the Codex app-server.
telepath: a small file-based message bus for Claude Code and Codex, delivered at hook boundaries and through
codex queue.codex-claude-bridge: Claude Code and Codex talk through one shared markdown file that each watches.
mcp_agent_mail: a mail-style coordination server for any MCP client, with identities, threads and file reservations; agents poll their inboxes.
Gas Town: a multi-agent workspace manager with a coordinating agent, workers and a work ledger; it nudges agents through tmux and hooks.
Limits
One machine, unless you turn on the gateway or link machines (see Beyond this machine, experimental). Remote Control and cloud sessions are not reached.
Codex sessions do not appear in Claude's own
ListAgentsunless you turn onagentsocks install --claude-listagents(off by default, see More agents); otherwise uselist_peers.Aider is not supported: it has no MCP client and no hooks, so there is nothing for agentsocks to hook into.
Plain text only.
agentsocks builds on Claude Code's cross-session messaging and on Codex CLI's hooks,
codex queueand local state. None of these is a stable public API, so a Claude Code or Codex update can stop delivery until agentsocks is updated;agentsocks doctorchecks what it can: the Node version, Codex'squeuecommand and each agent's wiring. Tested with Claude Code 2.1.294 to 2.1.302 and Codex CLI 0.162 to 0.163.Not affiliated with or endorsed by Anthropic or OpenAI.
Built and tested on Linux. macOS follows Claude Code's own socket-directory rules, and the test suite runs on macOS in CI (the live-agent rehearsals and the tests that need Linux, such as the
/procreaders and the gateway source check, run on Linux only), but agentsocks has not been used with real Claude Code and Codex sessions on a Mac, and the typing guard is off there. Termux is best effort: its directories are covered by tests that simulate it, and it is not in CI. Windows named pipes are not supported yet.
The full design, including what was rejected and why, is in docs/SPEC.md.
License
MIT
Available Tools
14 toolsanswerAnswer an askA
Answer a question another session sent you with ask (its message names an ask id). The asker receives your answer together with the others. Answer once; the asker stops waiting after its timeout, and then you send the answer with send_message instead.
| Name | Required | Description | Default |
|---|---|---|---|
| answer | Yes | Your answer, in plain text, at most 4000 characters; for more, answer with a file path | |
| ask_id | Yes | The ask id from the question, such as A-1a2b3c |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and discloses important behavior: the asker receives the answer along with other answers, you should answer once, and the asker stops waiting after its timeout. It does not cover invalid/expired ask-id behavior or delivery timing, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded: purpose and parameter source first, then delivery behavior, then the timeout alternative. Every sentence adds useful information without repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter tool with no annotations or output schema, the description covers what it does, when to use it, when not to use it, and the key timeout behavior. The schema handles parameter details, so the remaining context is complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents ask_id and answer, including format and length. The description adds only the source of ask_id (the ask message), so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: answer a question another session sent via ask, with the ask id provided in that message. It also distinguishes this tool from send_message for the timeout case, so an agent can tell when this tool applies.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to use this when another session sent a question with ask and the message names an ask id. It also gives the when-not case: after the asker's timeout, use send_message instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
askAsk several sessions one questionA
Send one question to several sessions at once, wait for their answers, and get them back together. to lists session names or refs, and "#channel" names to ask a channel's subscribers; at most 16 sessions. Each message names the answer tool and the ask id. The call returns when all have answered or after timeout_seconds, and says who did not answer. With pick "best" the smart-routing model, if your user turned it on, also says which reply answers best and how likely each is; that is its opinion, every reply is still shown, and the question and replies are sent to that model. A Claude session cannot ask Claude sessions this way: they are listed so you can use SendMessage.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Session names or refs from list_peers, and "#channel" names; at most 16 sessions in all | |
| pick | No | Set "best" to also get the smart-routing model's opinion on which reply answers best, with probabilities. It sends the question and the replies to that model. | |
| question | Yes | The question, in plain text. Include everything the others need; they cannot see this conversation. | |
| timeout_seconds | No | How long to wait for the answers, at most 280 seconds |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does substantial work: it discloses blocking/wait semantics, the timeout cap, partial-result behavior ('says who did not answer'), and a privacy-relevant side effect ('the question and replies are sent to that model'). It does not cover permissions, rate limits, or whether the reply is delivered as a message.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the action and stays dense with facts per sentence, but the pick='best' explanation is restated from the schema and the Claude-session caveat arrives as a trailing aside, adding length without new routing value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must explain returns, and it does: answers returned together, non-responders identified, and the optional best-reply opinion with probabilities plus the caveat that every reply is still shown. An agent has enough to invoke and interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema lacks: that '#channel' targets a channel's subscribers and that refs come from list_peers, plus the consequence of pick='best'. The rest largely restates schema text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource with scope: 'Send one question to several sessions at once, wait for their answers, and get them back together.' It also distinguishes itself from siblings by naming the one case it does not cover (Claude-to-Claude) and routing that case to SendMessage.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear conditions for use (one question fanned out to multiple sessions, max 16, blocking with a timeout) and an explicit when-not with an alternative ('A Claude session cannot ask Claude sessions this way... use SendMessage'). It stops short of contrasting against broadcast, which an agent might otherwise consider for a similar fan-out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
broadcastMessage every live sessionA
Send one plain-text message to every live Claude Code and Codex session except yourself, each routed separately by its own state and budgets. It is for announcements, so it is never urgent: fyi (the default) is batched until each session is idle, normal reaches a session at its next tool call unless it was interrupted a lot lately. To reach one session or a group, use send_message or a channel instead.
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | The message text. Plain text; include file paths rather than file contents. | |
| urgency | No | fyi: batched until each session is idle. normal: delivered at each session's next tool call unless it was interrupted a lot lately. | fyi |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses per-session routing by state and budget, that fyi is batched until each session is idle, that normal lands at the next tool call, and the 'interrupted a lot lately' exception. It omits any delivery/error behavior, rate limits, or what happens to sessions that never go idle, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tightly packed sentences, front-loaded with the core action and scope, then the delivery model, then the routing alternative. No filler and nothing repeated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter fan-out tool with no output schema and no annotations, the description covers routing, urgency semantics, and alternatives well. It stops short of describing the result shape or any scale/rate constraints on broadcasting to every live session.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both message and urgency, including the fyi/normal batching semantics. The description largely restates the urgency behavior already in the enum description and adds no new format or constraint details, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Send one plain-text message to every live Claude Code and Codex session except yourself') and explicitly distinguishes itself from siblings send_message and channel. The self-exclusion is a precise scope detail that separates it from a generic send.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the use case ('It is for announcements, so it is never urgent') and names the alternatives with the condition that selects them: 'To reach one session or a group, use send_message or a channel instead.' When-to-use and when-not-to-use are both explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_channelsList channelsBRead-only
List the channels that have subscribers, with who is subscribed, which of them are not running, and which one is you.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already establishes this is a safe read, so the description's value-add is the disclosure of what comes back: subscriber identity, non-running channels, and which channel is the caller. It does not explain pagination, ordering, or what a 'channel' or 'not running' means, which matters since there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler, opening on the verb. The trailing list of return fields makes it slightly run-on and reads more like a result spec than an action statement.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-param read tool with no output schema, the description covers the main return elements but leaves key ambiguities: whether the list is exhaustive or subscriber-filtered, what 'not running' denotes, and the return structure. Adequate but not fully self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so there is no parameter semantics to convey; baseline 4 applies. The description's return-field clause is not a substitute for parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (List) plus resource (channels) with an explicit scope qualifier ('that have subscribers'), which separates it from siblings like list_peers and list_tasks. It never names an alternative sibling, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no statement of when to use this versus list_peers, peer_status, or subscribe/unsubscribe, and no prerequisites or exclusions. The only guidance is the implicit scope 'channels that have subscribers', which the agent must infer from a return-value clause.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_peersList agent sessionsARead-only
List the Claude Code and Codex sessions running on this machine that you can message, with their names, refs, working directories and status.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
readOnlyHint=true already establishes the safe-read profile. Beyond that the description adds a real behavioral filter (only messageable sessions, not every process on the machine) and discloses the returned fields (names, refs, working directories, status), which is valuable given there is no output schema. It omits ordering, staleness, and whether the caller's own session appears.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One sentence, front-loaded with the verb and resource, then scope, then return fields. No filler and nothing buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read-only list tool with no output schema, the description covers purpose, scope, and returned fields, and annotations cover safety. Minor gaps remain around result ordering and whether the listing can be incomplete or stale, but nothing essential to calling it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters and the schema is empty, so per the baseline a 4 applies. The description correctly says nothing about parameters, avoiding noise.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb (list) and resource (Claude Code / Codex sessions on this machine), plus the scoping condition 'that you can message'. This is far clearer than the bare name 'list_peers', though it never names or contrasts with the nearest sibling (list_channels, list_tasks), so it stops short of full differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: 'that you can message' hints these are the peers you may target with send_message/ask, but there is no explicit when-to-use, when-not, or named alternative. An agent can infer the workflow but must do the inferring itself.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_tasksList tasksARead-only
List tasks assigned to you or created by you. Active ones by default.
| Name | Required | Description | Default |
|---|---|---|---|
| show | No | Which tasks: those you were assigned, those you created, or both | all |
| include_finished | No | Also show done, failed, cancelled and expired tasks |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already declares this is a safe read operation. The description adds useful context that the default is active tasks only and that results are scoped to the user's assignments or creations, but it does not describe pagination, maximum results, or return format.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no wasted words. The scope and default filtering behavior are front-loaded and immediately actionable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter read-only list tool with full schema coverage and a readOnlyHint, the description provides enough context to call it correctly. It could be slightly richer about result ordering or limits, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are fully documented in the schema. The description lightly mirrors the show parameter's ownership scope and the include_finished default behavior, but adds no syntax or edge-case details beyond the structured fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: list tasks, scoped to tasks assigned to or created by the user. This distinguishes it from mutating siblings like update_task and send_task, but it does not explicitly contrast with any sibling list tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly indicates the default context (active tasks) and the two ownership scopes. It does not name alternatives or explicitly state when not to use this tool, but the usage context is well implied for a list operation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
message_statusCheck what happened to a messageARead-only
Show how a message you sent was routed (now, after the current step, batched or merged) and whether it was sent, shown to the receiver or answered.
| Name | Required | Description | Default |
|---|---|---|---|
| message_id | Yes | The message id returned by send_message |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds real behavioral value by enumerating the routing outcomes (now, after the current step, batched, merged) and the delivery states (sent, shown, answered) that the tool reports — important given there is no output schema. It does not cover what happens for an unknown message_id or any error behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with the verb first and no wasted preamble. The parenthetical enumerations are dense but earn their space by defining the possible states, though the stacked list makes it slightly harder to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read-only status tool with no output schema, the description supplies the conceptual return values an agent needs to interpret results. Missing only error/edge-case behavior and explicit usage triggers, which are minor for this complexity level.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter and schema coverage is 100%, so the schema already documents message_id fully, including its provenance from send_message. The description adds no format, constraint, or edge-case guidance beyond that, making 3 the correct baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('show') and a specific resource (how a sent message was routed plus its delivery/read state), which clearly separates it from siblings like send_message, list_channels, or peer_status. It stops short of explicitly naming which sibling tool produces the message_id, relying on the schema for that linkage.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Use context is implied by 'a message you sent' and the schema note that message_id comes from send_message, so an agent can infer this is a post-send verification call. However there is no explicit when-to-use statement, no mention of alternatives, and no conditions or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
peer_statusSee what a session is doing and what is asked of itARead-only
Show what another session is working on, what is waiting for it (unread messages, held digests, open tasks), when it last showed or answered a message, and any drift between the two.
| Name | Required | Description | Default |
|---|---|---|---|
| peer | Yes | Session name or ref from list_peers |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, so the safety profile is already covered. The description adds real value beyond that by disclosing the shape of the read: unread messages, held digests, open tasks, last shown/answered timestamps, and a drift comparison. It does not mention permissions, visibility scope (same workspace vs. cross-workspace), or staleness/refresh behavior, which keeps it out of the top band.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that opens with the action and then enumerates the payload categories; there is no filler or redundancy. The parenthetical list is dense but each item carries information, so it stays readable rather than sprawling.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With one fully documented parameter, a readOnly annotation, and no output schema, the description must describe what comes back and largely does so via the enumerated categories. What remains thin is operational context: scope/permissions for viewing another session and whether the status is live or cached.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter with 100% schema description coverage, so the schema already defines it as 'Session name or ref from list_peers'. The description adds no additional semantics for the peer argument (e.g., whether an unknown peer errors or returns empty). Baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (show) plus resource (another session's current state) with a clear enumeration of what is reported: work in progress, pending items, last activity, and drift. It reads as distinct from list_peers, which enumerates sessions rather than reporting one session's state. It stops short of explicitly contrasting with the overlapping sibling message_status, which also concerns message activity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the agent infers 'call this when you need to know about another session'. There is no explicit when-to-use, no when-not-to-use, and no named alternative such as list_peers (for enumeration) or message_status (for message-level detail). The peer parameter's reference to list_peers hints at ordering but is not stated as guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rate_messageRate a message you receivedA
Tell agentsocks whether a message another session sent you was worth the interruption: useful-now (right to reach you now), could-wait (fine, but it could have waited until you finished) or noise (not worth reading). Ratings stay on this machine. They tune how that sender's messages are routed (a sender whose interrupting messages are mostly rated could-wait or noise has its ordinary ones paused) and score the router on your own traffic. Without message_id or from it rates the latest message you received.
| Name | Required | Description | Default |
|---|---|---|---|
| from | No | The sender's name: rates the latest message you received from it | |
| rating | Yes | useful-now, could-wait or noise | |
| message_id | No | The id of the message, from the id attribute where your inbox shows one |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does substantial work: it discloses that ratings stay local to the machine, that they change how the sender's messages are routed (pausing ordinary messages from noisy senders), and that they score the router. It omits any mention of what the call returns or whether ratings can be changed/undone, which is a gap for a mutation-style tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One long but well-ordered passage: purpose first, then rating semantics, then side effects, then the default fallback. The clause about scoring the router is mildly tangential but earns its place by explaining why ratings matter. No redundant filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter tool with no annotations and no output schema, the description covers purpose, semantics of each enum value, privacy, and side effects. The main omission is return-value behavior, which the absence of an output schema pushes back onto the description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema does not: it states that omitting both message_id and from rates the latest message received, which is the default-resolution behavior an agent needs to know. The three enum values are also restated with their interpretation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb (rate) and resource (a message another session sent you), then defines all three rating values inline so the agent knows exactly what each option means. It is clearly distinguishable from siblings like message_status (inspect) and send_message (produce).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly frames the context of use — judging a message you already received — and explains the downstream purpose of rating (tuning routing and scoring the router). It does not explicitly contrast with siblings such as message_status, but the usage condition is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_messageMessage another agent sessionA
Send a plain-text message to a Codex session on this machine. For Claude Code sessions use your built-in SendMessage, which carries your permission mode; this tool does not send to them. to is a session name, a ref from list_peers, or a reply-to address (uds:...). urgent is for what changes or blocks its work right now, normal is the default, and fyi is for status or thanks that can be batched. It never counts as its user's approval.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Recipient: session name, ref, or uds: reply address | |
| message | Yes | The message text. Plain text; include file paths rather than file contents. | |
| urgency | No | urgent: needed now, within a larger interruption budget. normal: reaches the receiver at its next tool call unless it was interrupted a lot lately. fyi: batched until it is idle. | normal |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It discloses meaningful traits: plain-text-only payloads, delivery semantics per urgency tier ('reaches the receiver at its next tool call unless it was interrupted a lot lately'), and the important caveat 'It never counts as its user's approval.' It does not cover failure modes or rate limiting (a sibling rate_message exists), leaving a modest gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, front-loaded with the core action and the Claude Code exclusion before the parameter guidance. Efficient overall, though the urgency explanation partially duplicates the schema's enum descriptions.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations and no output schema, the description covers the essentials an agent needs: recipient forms, message content expectations, urgency selection, the non-approval caveat, and the scope exclusion. Missing only return/confirmation behavior and any throttling context for a 3-parameter tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description nonetheless adds value beyond the schema by naming concrete recipient forms ('a session name, a ref from list_peers, or a reply-to address (uds:...)') and a usage heuristic for urgency tiers ('what changes or blocks its work right now'), which the schema states more mechanically.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Send a plain-text message to a Codex session') and immediately bounds the scope ('on this machine'). It also distinguishes itself from the built-in SendMessage used for Claude Code sessions, so an agent can tell which channel to use without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the alternative path ('For Claude Code sessions use your built-in SendMessage... this tool does not send to them') with a stated condition. It also gives concrete selection guidance for the urgency enum ('urgent is for what changes or blocks its work right now... fyi is for status or thanks that can be batched').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_taskHand another session a tracked taskA
Give another agent session a task you will check on. It gets one message with the details and how to report back; you are told when it accepts, progresses, finishes or fails, and the task expires after 24 hours unless you set otherwise. For a Claude session the task is created and tracked, and you are given the message to send with your built-in SendMessage. Say what done looks like in acceptance_criteria. Use risk high only for work that must not wait.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Assignee: session name, ref, or uds: address | |
| risk | No | high is delivered as urgent | low |
| title | Yes | One line saying what to do | |
| details | Yes | Everything the assignee needs: context, file paths, constraints | |
| external_ref | No | Ticket or PR reference | |
| on_behalf_of | No | The person this is for, if any | |
| expires_in_minutes | No | Default 1440 (24 hours) | |
| acceptance_criteria | No | How you will judge it done, for example which test must pass |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does much of it: it discloses the notification lifecycle (accepts/progresses/finishes/fails), the default 24-hour expiry, and the delivery path for a Claude session. It omits permission/auth requirements and what happens if the assignee never responds, but the lifecycle transparency is well beyond a typical 'create task' blurb.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded with the core action and packs substantial information into three sentences with no filler. The middle sentence is long and carries three clauses (lifecycle, expiry, Claude-session delivery), which makes it denser than ideal but not wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation-style tool with eight parameters, no annotations and no output schema, the description covers return behavior (what you are notified about), expiry defaults, and per-parameter intent well enough to call it confidently. Remaining gaps are edge cases (unaccepted tasks, permission requirements) rather than anything needed for a correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the 3 baseline applies, but the description adds real guidance on two parameters: 'Say what done looks like in acceptance_criteria' clarifies the expected content, and 'Use risk high only for work that must not wait' gives a use policy for the enum that the schema's 'delivered as urgent' does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description pairs a specific verb+resource ('Give another agent session a task') with the defining trait that separates it from send_message/ask: the task is 'tracked' and 'you are told when it accepts, progresses, finishes or fails.' An agent can distinguish this from the fire-and-forget messaging siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains the delivery mechanics ('For a Claude session the task is created and tracked, and you are given the message to send with your built-in SendMessage') and gives one conditional rule ('Use risk high only for work that must not wait'). However, it never explicitly states when to choose send_task over ask or send_message, leaving the sibling selection to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
subscribeSubscribe to a channelA
Join a channel such as "#deploys" so messages other sessions post to it reach you. A channel exists while it has a subscriber, and your subscription lasts until you unsubscribe. Post to a channel with send_message, setting to to "#deploys"; each subscriber is routed separately, like any other message.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Channel name such as "#deploys": up to 48 lower-case letters, digits, dots, dashes or underscores |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and delivers meaningful lifecycle semantics: a channel exists only while it has a subscriber, the subscription persists until unsubscribe, and each subscriber is routed separately. It omits behavior for repeat subscribes (idempotency), validation failures, or max channel limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with the core action front-loaded and the send_message routing hint appended for practical use. The final sentence about per-subscriber routing is slightly tangential but earns its place by clarifying delivery semantics.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with no annotations and no output schema, the description covers lifecycle, interaction with send_message, and termination via unsubscribe. It leaves the return value and duplicate-subscribe behavior unspecified, but nothing critical to invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single `channel` param is fully documented with format constraints in the schema itself. The description only repeats the "#deploys" example, adding no syntax or constraint detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb-plus-resource ("Join a channel such as "#deploys"") with an inline example, and it clearly frames the tool as the inverse of unsubscribe by stating the subscription "lasts until you unsubscribe." An agent can distinguish this from send_message, broadcast, or unsubscribe without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains the mechanism for using the subscription (post with send_message by setting `to` to "#deploys") and when the relationship ends (on unsubscribe), which routes the agent to the right siblings. It stops short of explicit when-not-to-use or failure/duplicate-subscribe conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unsubscribeLeave a channelA
Stop receiving messages posted to a channel. It does nothing if you were not subscribed.
| Name | Required | Description | Default |
|---|---|---|---|
| channel | Yes | Channel name such as "#deploys": up to 48 lower-case letters, digits, dots, dashes or underscores |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It usefully discloses idempotency ('does nothing if you were not subscribed'), but says nothing about permissions, whether the action is reversible via `subscribe`, or what the call returns.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the action and followed by the one non-obvious behavioral caveat. No padding or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with no output schema, the definition covers the operation and its no-op condition. It leaves minor gaps around re-subscription and side effects on channel membership, but nothing essential to calling it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single `channel` parameter is fully documented in the schema, including format constraints. The description adds no additional meaning about the parameter, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb+resource pair — stop receiving messages posted to a channel — that an agent can distinguish from the sibling `subscribe` without opening any schema. The title 'Leave a channel' reinforces the same operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied (call this when you want to stop receiving a channel's messages), but there is no explicit when-to-use framing, no naming of the counterpart `subscribe`, and no guidance on prerequisites such as whether you must have joined first. Adequate but with clear gaps.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_taskUpdate a taskA
Report progress on a task. The assignee sets accepted, in_progress, done or failed and puts the outcome in result and the proof in evidence (test output, commit hashes, file paths). Only the creator can set cancelled. The creator is told about every change.
| Name | Required | Description | Default |
|---|---|---|---|
| result | No | What happened, in a few sentences | |
| status | Yes | The new state. The assignee sets accepted, in_progress, done or failed; only the creator sets cancelled | |
| task_id | Yes | Task id such as T-1a2b3c | |
| evidence | No | Proof: test output, commit hashes, file paths |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the permission model (creator-only cancellation) and a side effect (the creator is notified of every change). It omits transition validation rules and error/idempotency behavior, which is why it is not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the core action, then the enum/role rules, then the notification side effect. No sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-parameter mutation tool with no annotations and no output schema, the description covers purpose, permissions, expected payload content, and side effects. Only failure/transition behavior is left unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all four parameters, including the status enum and its role split. The description's guidance on what belongs in result and evidence largely restates the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Report progress on a task'), which is far more concrete than the bare name update_task. It does not, however, explicitly distinguish itself from plausible siblings such as send_task or answer, so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear role-based conditions: the assignee sets accepted/in_progress/done/failed, and only the creator may set cancelled. This tells the agent who can do what, but it names no alternative tool or when-not-to-use condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
14 tool updates
v0.1.0- First observed
answer - First observed
ask - First observed
broadcast - First observed
list_channels - First observed
list_peers - First observed
list_tasks - First observed
message_status - First observed
peer_status - First observed
rate_message - First observed
send_message - First observed
send_task - First observed
subscribe - First observed
unsubscribe - First observed
update_task
TDQS
Scored across 14 tools
Each tool targets a distinct action-resource pair: peer/channel/task listing, one-to-one messaging, broadcast announcements, multi-recipient questions, task lifecycle management, and routing/status introspection are all clearly separated. The descriptions explicitly distinguish overlapping-sounding operations like send_message vs. broadcast vs. ask and message_status vs. peer_status.
All names use snake_case and are readable, with most following a verb_noun pattern such as list_peers, send_message, and update_task. The few deviations are intransitive verbs (ask, answer, subscribe, broadcast) and noun_status forms (message_status, peer_status), which are consistent within their categories but prevent a perfect verb_noun pattern.
Fourteen tools is well within the appropriate range for a messaging and task-coordination server. Each tool covers a meaningful operation, and there is no obvious filler or redundant surface.
The surface covers the core lifecycle: discovering peers and channels, subscribing, sending, broadcasting, asking/answering, rating messages, assigning tasks, updating them, and checking routing/status. Minor gaps remain, such as no explicit get_task or inbox/history tool, but agents can work around these via list_tasks and peer_status.
Maintenance
Related MCP Connectors
The team layer for AI coding agents: shared contracts, collision alerts, E2EE sessions.
- ParleyOAuthdev.weldra
Coordination hub for AI coding agents: message teammates, ask humans, audit every event.
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
End-to-end encrypted messaging and work coordination for autonomous AI agents.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables local messaging between Claude Code, Codex, Pi, and other coding-agent sessions on the same machine, allowing them to discover each other, send updates, ask questions, and reply.816 npm3AGPL 3.0
- AlicenseNot gradedqualityDmaintenanceEnables peer-to-peer communication between Claude Code sessions, allowing them to send messages, hand off tasks, and coordinate across worktrees without manual intervention.MIT
- AlicenseNot gradedqualityBmaintenanceEnables Claude Code, Codex and opencode sessions on the same machine to message each other live over a local pipe, with threaded replies and offline queuing, and to delegate or spawn one another as background subagents. Messages persist in SQLite and any running server can take over as broker, so peers stay reachable without a daemon.19 npm3MIT
- AlicenseNot gradedqualityAmaintenanceLets independent Claude Code and Codex sessions running in different tools and projects discover each other and exchange questions, coordination messages, and replies that arrive back in the conversation that asked. Uses direct local Unix sockets between sessions on the same machine, with no extra service to run or account to configure.863 npmMIT