Guides
Message another session or agent
Send a message from one session to another session or to an agent, on the same machine or a different one, and get the answer back. Addressing, the cyborg7_message tool, the cyborg message command, what the row shows, and the limits.
Any session can send a message to another session or to an agent of the workspace. The target can run on the same machine or on a different one, and on a different provider. The message starts a turn in the target, and the target’s answer comes back to the sender as a message from it. Nobody has to copy text between windows.
Typical uses:
- A session that is writing code asks your review session to look at the diff.
- A coordinator session splits a job across three sessions and collects the three answers.
- A session asks an agent of the workspace a question without going through a channel.
- You send a note from a terminal to a session that runs on a server.
Who can message whom
Every message is sent on behalf of a person: the person the sending session is working for. Cyborg decides what is allowed from who that person is, never from what the message says.
| Target | Allowed when | What the target’s turn may do |
|---|---|---|
| One of your own sessions | You are a member of the workspace and can use both machines: the one the sender runs on and the one the target runs on. | A normal turn of that session, with what your access to its machine allows. |
| An agent of the workspace | You are a member of the workspace. Any member can message any agent. An agent that has no machine yet and that you have never talked to is not found. | The message joins your own conversation with that agent. If your access to the agent’s machine lets you run agents there, the turn has its normal tools and the answer comes back to the sender. If it does not, the agent answers in a contained turn with limited tools, and the answer goes to your conversation with it, not back to the sender. |
| A session that belongs to someone else | You can already read that session in the app (for example, as a workspace owner or admin). | If your access to its machine lets you run agents there, a normal turn. If it does not and it is an agent’s session, a contained turn of that agent that answers you in your own conversation with it. If it does not and it is a plain session with no agent, the message is refused. |
What stays private:
- A session you cannot read answers exactly like one that does not exist. The sender learns nothing about it, and its owner sees nothing.
- A contained turn does not run in the other person’s session. It is a fresh turn of the agent, addressed to you. Nothing appears in the other person’s transcript and no approval card is shown to them.
- The record of a message holds who sent it, to whom, its state and a short reason code. It does not hold the text.
- The answer comes back only while you are still a member of the workspace, can still use the sender’s machine and, for someone else’s session, can still read that session.
How to name the target
| You pass | It matches |
|---|---|
| A full session id | That session, yours or someone else’s (the rules above then decide). |
| The first 8 or more characters of a session id | One of your own sessions. |
| A session’s shared name | Your session with that name. If you have none, another person’s session with that name. |
| Your own name for a session (your alias) | One of your own sessions. |
| An agent’s exact name, or its id | That agent. |
A session gets its shared name when its owner names it, in the app or with cyborg agent:alias. That name is unique in the workspace and is shown to everyone who can see the session. A name you give to a session you do not own stays yours alone. If the name is already taken in the workspace, the shared name is left unchanged.
Names are matched without regard to upper and lower case. If a name matches several of your sessions, or one session and one agent, nothing is sent and the candidates are listed so the sender can pick one by id. Your own sessions and agents are always tried before another person’s session with the same shared name.
A session cannot message itself, and an agent cannot message itself.
From an agent or a session: the cyborg7_message tool
Every session that is connected to Cyborg has the tool: an agent’s session and a plain session with no agent alike. It needs no extra permission beyond the one that lets a session post messages. An agent that answers you in a contained turn keeps the tool too, with the narrower rules in From a contained turn.
| Argument | Required | What it is |
|---|---|---|
to | yes | The target, named as in the table above. Up to 200 characters. |
text | yes | The message. Up to 32,000 characters. |
expectReply | no | Leave it out to get the target’s answer back in the sending session. Pass false when no answer is needed. |
requestId | no | A key the sender chooses, up to 128 characters. Sending again with the same key sends nothing and returns the first message. Use it to retry safely. |
The tool returns at once with one line. It does not wait for the target to finish.
Every result for a message that was taken starts with the same head:
<Delivered to | Recorded for | Already sent to> <session | agent> <id> (chain <id>, hop <n>/<limit>, edge <id>).
| Case | The line after the head |
|---|---|
| Delivered, an answer will come | Its answer will arrive in this session as a message from it; do not wait or poll for it. |
Delivered, no answer asked (expectReply: false) | No answer comes back here: what it says stays in that session. |
| Delivered to an agent that answers in a contained turn | No answer comes back here: that agent answers the person you work for in their own conversation with it, with limited tools. |
| Recorded for a target whose machine is offline | Not delivered yet: its machine is offline. It is delivered as soon as it can be, and expires after 24 hours. followed by the sentence that says whether an answer comes back. |
Already sent (the same requestId again) | This is the same request as before: nothing was sent again. |
A target that is busy is not a special result: the tool answers Delivered to, the target takes the message after its running turn, and the row in the app shows the reason while it waits.
A refusal is one line that starts with Error (<code>):, with (edge <id>) at the end when the refusal was recorded. Nothing was sent.
| Code | Meaning | What to do |
|---|---|---|
not_found | No session or agent matches, or the person may not read it. | Check the name with cyborg7_list_my_sessions, or pass the full id. |
ambiguous | The name matches more than one target. The line lists them. | Send again with one id from the list. |
self | The target is the sending session itself. | Message a different one. |
daemon_offline | The target’s machine is offline and cannot hold a message until it is back. | Bring that machine online and send again. |
target_outdated | The target’s machine runs an older Cyborg that cannot take this kind of message. | Update that machine. |
contained_unavailable | The target is someone else’s plain session on a machine the person cannot use. | Ask its owner, or message an agent instead. |
no_actor | There is no person behind the turn, or that person may not use the sender’s machine or is no longer a member. | Send from a turn a person started. |
source | The sending session is not one its machine runs for this workspace. | Send from a live session. |
depth | The chain of messages reached the person’s hand-off limit. | Answer in the current session. The person can continue the chain or raise the limit. |
fanout_capped | The sender already has the most messages out that one step may send. | Continue with the answers as they arrive. Do not send it again in the same turn. |
chain_budget | The whole chain has sent the most messages one chain may send. | Answer in the current session. A new message from a person starts a fresh chain. |
chain_unknown | The chain’s count could not be read, so nothing was sent. | Try again in a moment. |
rate | Too many messages in one minute. | Wait a minute. |
not_available | The machine is connected to a Cyborg service that does not take session messages yet. | Update, then try again. |
relay_unavailable | The Cyborg service did not answer. | Try again in a moment. |
invalid | No target was named. | Pass to. |
Which tool to use
| Tool | Use it to | The answer |
|---|---|---|
cyborg7_message | Message a session or an agent directly, with no channel. | Comes back to the sending session. |
cyborg7_prompt_session | Hand work to another of the person’s own sessions when no answer is needed back. Only agents that were granted it have this tool. | Stays in the target session. |
cyborg7_ask_agent | Ask an agent in a channel thread, where the people in the channel can follow the exchange. | Arrives in that thread and wakes the asking agent once. |
cyborg7_send_message | Post to a channel or send a direct message to a person. It does not message a session or an agent. | None. |
From a terminal: cyborg message
cyborg message <workspace-id> <session> "<text>"
<session> is a session id or a unique prefix of it. cyborg session:list shows the ids.
# Send and return as soon as the message is on its way:
cyborg message <ws-id> f24998d0 "the build is green, you can rebase"
# Wait for that session's turn to end and print its reply:
cyborg message <ws-id> f24998d0 "which tests still fail?" --wait --timeout 300
# The same, as JSON:
cyborg message <ws-id> f24998d0 "which tests still fail?" --wait --json
| Flag | What it does |
|---|---|
--wait | Waits for the target’s turn to end and prints only its reply. |
--timeout <seconds> | With --wait: how long to wait for the reply. The default is 120. |
--daemon <id> | Targets one machine by its id. |
--json | Prints the result as JSON. |
From your terminal the message is sent as you, the same way a prompt you type in the app is. A session that is busy takes it after its running turn. The message shows in the target’s transcript as yours.
The same command works inside an agent’s shell. There it runs the agent’s own cyborg7_message tool, so <session> may also be a shared name, your alias for the session, or an agent’s name, and the command prints the tool’s one line. --wait and --timeout are refused inside an agent, because the answer arrives in the agent’s session as a message. The workspace id must be the agent’s own workspace.
Exit codes: 0 when the message was sent, which includes a message recorded for an offline machine and one that was already sent; 1 for a refusal or any other error, with the reason on standard error.
What you see in the app
The sender’s transcript shows one row per message: Sent to and the target’s name. An agent target carries an Agent chip. A target on another provider shows that provider. Click the row to expand it.
The row has one status:
| Status | Meaning |
|---|---|
| Sending… | The tool call is still running. |
| Sent | The message was taken. It may still be waiting for a busy or offline target, or the target may be working on it. |
| Replied | The answer came back. It is nested under the row as Reply from and the target’s name. |
| Not delivered | The message did not reach the target, or the target’s turn failed or was stopped before it answered. |
The target’s transcript shows a From row with the sender’s name, then its own turn. An agent’s session signs as the agent. A plain session signs with its shared name, or with its provider (for example “Claude session”) when it has none.
When a row is expanded, one muted line says why a message waits or was not delivered.
While the row reads Sent:
| Line | What to do |
|---|---|
| Name is busy. Your message is next. | Nothing. It is delivered when the running turn ends. |
| Machine is offline. Delivers when it is back. | Bring the machine online. The message expires after 24 hours. |
When the row reads Not delivered:
| Line | What to do |
|---|---|
| Machine did not come back in time. | The 24 hours passed. Send it again when the machine is online. |
| Name stayed busy for too long. | The 24 hours passed. Send it again. |
| Machine is offline. | Bring the machine online and send again. |
| Machine needs an update before it can take this. | Update Cyborg on that machine. |
| Name runs on a machine you cannot use, and cannot take it safely. | Ask the session’s owner, or get access to that machine. |
| Name could not take it. | The session could not be started on its machine. Open it in the app and try again. |
| Name could not be started. | The agent’s machine could not open the conversation. Message the agent once yourself. |
| Name could not finish its turn. | Open the target session to see the error. |
| Name ran into its usage limit. | Wait for the provider’s limit to reset, then send again. |
| Name has too many messages waiting. | Wait for the target to work through its queue. |
| No session or agent goes by that name. | Check the name, or pass the full id. A session you may not read reads the same way. |
| That session no longer exists. | The session was removed while the message waited. |
| Name’s turn was stopped before it answered. | Someone stopped the target’s turn. Send the message again. |
| Not sent: messaging was not allowed for this session. | You denied the approval card. The session can ask again in its next turn. |
| Not sent: nobody allowed it in time. | Nobody answered the approval card. The session can ask again in its next turn. |
| That session is archived. | Restore the session first. |
| That session moved to another machine. | Send it again. |
| That is this same session. | Name a different target. |
| You do not have access to that session. | Ask its owner. |
| You no longer have access to that session. | Your access changed while the message waited. Ask its owner. |
| You do not have access to this session’s machine. | Get access to the machine the sender runs on. |
| There is no person to run it for. | Send from a turn a person started. |
| Too many messages in a short time. | Wait a minute. |
| Too many messages were sent at once. This one was not sent. | The step’s limit was reached. The sender can send it in a later step. |
| This chain of agent messages hit its limit. | Start again with a new message of your own. |
| This chain of agent calls hit its limit. | The hand-off limit was reached. Reply to continue, or raise the limit. |
| Its chain of agent messages could not be checked. | Try again in a moment. |
| It could not be delivered. | An internal error. Send it again. |
A reason the app has no words for shows no line. When the name of the target or of its machine is not known, the line says “That session” or “Its machine”.
Replies
The target’s answer is the final text of the turn that the message started. It arrives in the sending session as a message from the target and wakes the sender once.
- A sender that is busy takes the answer after its running turn.
- The answer does not ask for anything, and receiving it does not send a new message back.
- If the target messages the sender itself during its turn, that message counts as the reply and no second one follows.
- With
expectReply: falsenothing comes back, and what the target says stays in its own session. - A turn that the person stopped, that failed, or that hit the provider’s usage limit sends no answer.
- If the sending session was archived meanwhile, the answer is dropped without an error.
Limits
| Limit | Value |
|---|---|
| Messages at once | One session can have 8 messages out at one step of a chain. The ninth is refused (fanout_capped); the first eight stay sent. |
| Messages in one chain | 40 in total, counting every sender and every step. The next one is refused (chain_budget). |
| Depth of a chain | 5 hand-offs by default. You can change it up to 10 in Settings → Account → Agent handoffs. |
| Rate | 20 messages per minute per person, across all of that person’s sessions. A chain that sends faster is refused (rate) before it reaches 40. |
| Waiting for a target | 24 hours. After that the message expires and reads Not delivered. |
| Size | 32,000 characters per message. |
A chain is everything that follows from one turn that a person started: the messages that turn sends, the messages their targets send, and so on. A new message from a person starts a fresh chain. An answer that comes back continues the same chain: a message the sender sends after it is the chain’s next step, and it counts toward the depth and the total.
When an agent’s chain stops at the depth limit, the agent’s conversation with you shows “Handoff paused after n hops. Reply here to continue.”
Permission modes that ask first
cyborg7_message follows the sending session’s permission mode like any other tool that changes something.
- In a mode that does not ask (for example bypass permissions), the message is sent with no card.
- In a Claude mode that asks before running tools, such as the default mode, the session shows one card for all its messages: “Let session send messages?”, with “Nothing is sent until you answer.” The card lists each waiting message by its target and first line (the first five, then “and n more”). Messages the session sends while the card is open join the same card.
- Allow sends every listed message, and the session sends without asking again until it ends.
- Deny refuses every listed message, and any other message the session tries in that turn. The session’s next turn can ask again.
- If nobody answers in time, every listed message is refused the same way.
- On other providers that ask before running tools, messages are not grouped: each call shows the provider’s usual approval card.
A refused message returns one of these lines to the session, and its row reads Not delivered:
Error (approval_denied): the person you work for did not allow messages from this session. Nothing was sent; do not send it again in this turn.
Error (approval_expired): nobody allowed this message in time. Nothing was sent; do not send it again in this turn.
From a contained turn
When you message or mention an agent whose machine you cannot use, the agent answers you in a contained turn with limited tools. That turn can still send messages, with narrower rules:
- It can message agents only. A session as the target reads as not found.
- Whatever it sends is contained too: the receiving agent answers with limited tools, and its answer lands in your own conversation with that agent, not back in the turn that sent it.
- It works only in a turn you asked for directly, in a direct message, a mention or a thread. A contained turn that was itself started by a message cannot send one on.
- The message does not wait: if the receiving agent’s machine is offline, it is refused.
Known limitations
- A scheduled run can message, with limits. It sends as the person who created the schedule and counts as unattended: up to 6 messages a minute per schedule. The run waits up to 3 minutes for the answers it is owed, and never into the schedule’s next run; an answer that arrives after the run ended is not delivered to it. If the schedule’s creator can no longer use the machine the run is on, or an agent wrote the schedule, the run can message agents only, as a contained turn.
- A schedule created by someone who does not own the agent’s machine cannot message yet. Its message is refused with
no_actor. - A queued message cannot be cancelled. It is delivered, or it expires after 24 hours.
cyborg messagehas no status lookup. The edge id is in the tool’s line, and the state is on the row in the app.- If a target’s machine restarts in the middle of the turn, the row can stay on Sent and no reply comes back. Send the message again.
- Claude’s own
SendMessageis a different path. It only reaches a session on the same machine while that session’s process is running, and it has none of the above: no queue for a busy or offline target, no delivery states and no reason lines. Usecyborg7_messageto reach a session reliably.