Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

Replying to a message from another agent

When another agent messages you, a normal chat reply never reaches them — your answer lands in your own transcript and the sender simply waits. This page is how to send the reply back over the local command line instead, covering the retry id, what to do when the target is busy, and how to spot a message that was copied to several sessions at once.

What it is

Another agent messaged you. A normal chat reply will not reach them — you have to send it back over the CLI. This page is how.

You are reading this because a message arrived carrying a short <system-reminder> naming the session that sent it. The full instructions are sent to each session once; after that every arrival carries only the sender's id and a link here, because everything else on this page never changes and re-sending it on every message was pure waste.

Where to find it

There is nothing to click. This page is written for an agent, not for you: it is the path a session follows to answer a message that arrived from another session, and no button in the app does it.

A person who wants to watch this traffic — including the messages that never arrived — does so in the Agent Messages panel.

How it behaves

Why a chat reply does not work

The message was injected into your session by another agent. Your reply goes into your own transcript, which the sender never reads. Nothing errors, nothing warns you — the sender simply waits for an answer that is not coming. Sending it back over the CLI is the only path that reaches them.

Send the reply

TOKEN=$AMC_CLI_TOKEN   # your OWN session's token — the same on every machine
RID=$(node -p "crypto.randomUUID()")   # ONE id per MESSAGE — reuse it on every retry
curl -s -X POST http://127.0.0.1:19519/sessions/<THEIR-SESSION-ID>/peer-message \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-AMC-Source-Session-Id: $AMC_SESSION_ID" \
  -H "X-Client-Request-Id: $RID" \
  -H "Content-Type: application/json" \
  --data '{"text":"your reply here","tldr":"one line: what this is and whether they must act"}'

<THEIR-SESSION-ID> is the session id named in the reminder you received. The port is 19519 unless AMC_CLI_PORT says otherwise.

tldr is required past 1,000 characters of text and capped at 600 — the cap applies to the summary itself, not to your message, and a longer summary is refused with a 400. Write the short one on purpose; the full text still reaches the transcript either way.

The four things that bite people

Present your OWN session's token, on every machine. $AMC_CLI_TOKEN is set by every spawn and this route accepts it wherever you are running — a desktop and a cloud box alike. There is no machine to distinguish and nothing to read off disk. Until recently there was: this route refused a session's own token on a desktop, so the reply command branched and read the machine-wide full-trust key file instead. That refusal is gone, and the branch with it — answering a peer is not a reason to hold full trust, and it is not a reason to read a key file.

Mint the retry id ONCE per message, above the call. Inlining the generator into the header gives every attempt a fresh id, which defeats the whole mechanism.

A timeout or an empty response is UNKNOWN, not failed. The send may well have landed. Re-run the same command with the same $RID and the server replays the original result instead of delivering twice — a ten-minute window. Retrying without the id will eventually duplicate: one measured send loop reported success only on attempt 7 of 7, and at least two of the earlier attempts had landed, so the recipient got the same 4,222-byte message twice.

Do the work first, then reply — and only when you have something to say. A bare acknowledgement costs the sender a turn and tells them nothing.

If the message says it is a COPY, it may not be for you

A message that opens with

⚠️ This exact message was ALSO sent to N other sessions.

is one body the sender put in front of several sessions at once. It is not addressed to you personally, and the sender may well have written it for one of the others — so read it before you act on it. If it answers a point you never made, or discusses a branch or a task that is not yours, say exactly that back to the sender rather than working on it.

This exists because a reviewer session once relayed its author thread to a second session with a shell loop. The copies were written in the second person ("your correction is right"), the second session read them as its own conversation, replied, and spent over an hour on someone else's work.

Do not send one body to several sessions yourself. Write to the session you actually mean. If two agents genuinely need the same information, say it to each in its own words, or use the broadcast route, which exists for it.

If the target is busy

Nothing is lost, and there is nothing to re-send. A message to a target that is mid-turn is held, not refused: POST /sessions/:id/peer-message answers 200 with "queued": true and delivers it the moment the target's turn ends. Roughly 41% of sessions are mid-turn at any moment, so this is the ordinary path rather than an error — send once and leave it:

curl -s -X POST http://127.0.0.1:19519/sessions/<THEIR-SESSION-ID>/peer-message \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-AMC-Source-Session-Id: $AMC_SESSION_ID" \
  -H "X-Client-Request-Id: $RID" \
  -H "Content-Type: application/json" \
  --data '{"text":"your reply here","tldr":"one line: what this is and whether they must act"}'

$TOKEN and $RID are the ones the lines above set — it is the same credential and the same per-message id as any other send on this route.

Two cases wait differently, and both are other fields on this same route rather than other routes:

  • Your message genuinely cannot wait for the turn to end. Re-send with "confirmInterruptTurn": true — that kills the work the target is doing right now, so reach for it only when your message is worth more than what it is working on.
  • Your own send budget is spent. You get 429 instead of a delivery. Re-send with "queueIfLimited": true and the message is parked and delivered as the budget refills; that answers 202, which means ACCEPTED, so do not send it a third time.

Do not try to reach another session with POST /session/:id/queue. That route acts on the session id in its own URL, and a token is scoped to the one session it was minted for — so it queues work on your own session, and it is never a way to reach somebody else's. On a cloud box, whose only credential is scoped, a cross-session queue is refused outright: 403 session not authorized for this action.

That is also why peer-message is the one route to learn: it is the only cross-session door that works for every caller, scoped or full-trust alike.

Never forward another session's open question by reference

If you are about to tell someone (the user, or a third session) that ANOTHER session already has a question waiting — an inbox card, an open ask, a pending decision — that pointer goes stale the moment the owning session withdraws or resolves it, and you are not the one who would know. One overseer was about to point the user at another session's inbox card as "already waiting on you"; that card had been withdrawn twenty minutes earlier, and the user would have hunted for a decision that no longer existed.

Either carry the question in full, with its owner's current state confirmed (re-check it, don't recall it), or cite nothing of theirs at all. A secondhand pointer to someone else's open item is never safe to hand off by reference.

Re-check volatile state immediately before you send it

A fact that can change between when you look at it and when your message actually arrives has to be measured again, right before you send — not carried from earlier in your turn. One coordinator's "only one branch is tagged ready-to-merge" was stale by 2.9 seconds: true when read, false by the time the message went out, because a second branch was tagged in the gap. The same coordinator's next "two branches are still tagged" was stale by 4.5 minutes, and reached twelve recipients after the tag had already been pulled.

Anything answerable with a cheap re-run of the same query — a tag count, a queue depth, any count you are about to assert as current — is cheap enough to re-check in the same breath as sending. There is no excuse to quote a read from earlier in the turn: re-measure immediately before any message that asserts the present state of something volatile.

A stale WARNING about a hazard can cause the hazard

This cuts the opposite way from an ordinary stale reassurance. A stale ALL-CLEAR breeds complacency — a reader does nothing extra, which is usually safe. A stale ALARM can provoke action, and the action it provokes can be exactly what recreates the danger it warned about: a broadcast saying "two branches are still tagged, do not let both land" arrived after one of those two tags had already been pulled, and a reader could reasonably take "two are still tagged" as license to mint a third — which is precisely what would have rebuilt the collision.

So when you correct a stale warning, do not just clear the alarm — restate the prohibition explicitly. "The hazard is gone" is not enough on its own; say "and you still must not do X" in the same breath, so the correction can never be misread as new permission.

A rule that tells you to act on a signal must state what that signal means

The same shape one level down: a rule built on a misread field can cause the exact behaviour it forbids, because an instruction that TRIGGERS an action deserves more scrutiny than one that merely informs — a wrong one does not just fail quietly, it acts.

One broadcast told a dozen sessions that a gate ticket reading executionState: running needed a FRESH updatedAt too before you could trust the job was actually alive. On a session-queue reply-mode ticket that field does not move while the job runs — it marks the last STATE TRANSITION, not a heartbeat — so a perfectly healthy job can sit with a minutes-old timestamp indefinitely. A session following the rule literally would have declared that job dead and re-dispatched it, on every such ticket: the safety rule would have caused the exact duplication it was written to prevent.

The corrected rule: executionState: running is the liveness signal on its own; do not also demand a fresh timestamp. This is one measurement on one ticket, flagged rather than asserted — if a session-queue ticket's updatedAt is ever seen advancing while the job runs, the field behaves differently per reply mode and this rule needs splitting, not blind trust.

Keeping routine traffic out of the user's way

If an exchange is machine traffic the person running Omniscio has no reason to read — a status ping, an acknowledgement, a correction between agents — end your turn with the collapse-exchange marker alone on its own line (the reminder you received names it). The message and your whole reply then render as one quiet line they can expand.

It is display only. Nothing is deleted, nothing leaves search, and it is ignored on a turn the user opened or one where you are asking them something — so it can never fold away anything they need. When your reply carries a real answer, it is also skipped if there is nothing else after it — the session keeps something readable rather than folding to a quiet line. It is also independent of self-archiving: it quiets the transcript, it does not close the session.

Related

  • agent-messages.md — the panel where a person watches this traffic, including the messages that never arrived.
  • agent-message-display.md — how an arriving message is rendered in the receiving session's transcript.

Last verified 2026-10-05