Skip to content

Messaging & Notifications

Scion provides a robust messaging system that allows for bidirectional communication between humans and running agents. This is particularly useful for long-running tasks where an agent might need clarification, approval, or simply wants to notify you of its progress.

In the Web Dashboard, messages from your agents and other users arrive as chat conversations (see Native Web Chat below). There is no separate inbox:

  • Unread Badge: The Chat entry in the header’s mode selector shows how many of your conversations have unread messages. A conversation counts once, however many unread messages it has. Only unmuted DMs and unmuted threads that you are a member of and have permission to read are counted. The browser tab title shows the same number.
  • Popups: New chat messages raise chat popups and browser notifications (see Push Notifications & Presence).
  • Agent events: The bell’s notification tray carries agent events (such as an agent stalling or asking for input), not chat messages.

The badge number comes from GET /api/v1/chat/unread-count (see the API Reference).

Scion features an interactive, top-level Native Web Chat interface in the Web Dashboard (enabled via the web.native_chat feature flag). Rather than being isolated inside a single tab, chat is promoted to a top-level workspace view (a fourth ShellType in the SPA) that provides a cohesive, real-time collaborative environment for humans and agents.

  • Project-Scoped Spaces & Shared Threads: Chat is organized into distinct spaces scoped to specific Projects. Within a project-scoped space, users and agents participate in shared discussion threads, creating focused hubs of collaboration.
    • Un-mentioned thread replies: In a thread with no default agent, a reply with no mention and no target would reach nobody. When the latest message from someone else in that thread came from an agent, Scion appends a short note to the reply that mentions the most recent other human poster (or the thread creator) and names that agent, so that human receives a mention notification. Otherwise the reply is still delivered to no one.
  • Project Context Preservation (Dashboard ↔ Chat Toggle): When you switch between dashboard and chat modes using the navigation icons in the header, Scion automatically maintains your active project context to avoid losing your work state:
    • Dashboard → Chat: Clicking the Chat icon while on a project-scoped dashboard page (e.g., /projects/:id/... or inside an agent view) takes you straight to that project’s chat space (/chat/space/:id).
    • Chat → Dashboard: Clicking the Dashboard icon while in a project chat space (/chat/space/:id/... or /chat/:slug/...) takes you directly back to that project’s detail page (/projects/:id).
    • DMs / General Chat: If there is no active project context (such as when in Direct Messages or bare /chat), the toggle falls back to the top-level dashboard /.
  • Direct Messaging (DMs): In addition to collaborative project spaces, the chat interface supports robust 1-on-1 Direct Messages (DMs). This includes both human-to-human (H2H) communication between team members and human-to-agent (H2A) chats. DMs are structured as a “global pair”—a single, consolidated thread per participant pair.
    • DM Promotion to Shared Threads: When a 1-on-1 Direct Message with an agent develops context useful for the broader team, you can promote the DM conversation into a Shared Space Thread. This atomic operation safely re-keys the messages and streams the transition live to all clients via SSE without a page reload. Use the promotion button located in the DM header.
  • Members Sidebar, Presence & Typing: A right-hand members sidebar lists all participants in the active project space or DM. This includes real-time online presence indicators (active, away, offline) and live typing indicators to show when a team member or agent is actively composing a message. The thread’s default agent is listed first in the AGENTS section of the sidebar, under a Thread default sub-heading. When a thread has a default agent, the thread header shows terminal and graph buttons for that agent, the same as a DM with an agent. Members can be sorted (Alphabetical or Recent Activity). A blue dot marks members with unread messages; to find unread DMs, use the rail’s Unread filter.
  • The Thread Rail & Mobile Swipe Navigation: A left-hand navigation sidebar lists all active chat spaces, threads, and DMs. On mobile viewports, the rail supports native swipe gestures for fluid, app-like drawer navigation.
  • Chat/Log Toggle: Located on the main scion-chat-thread panel, this toggle lets you switch between a clean, dialogue-focused Chat view and a live Execution Log stream for that agent.
  • Zero-Reload Navigation: Move between threads, project spaces, and configuration pages instantly with deep-linking support and no full-page reloads, ensuring no interruption to your active chat context or log streams.
  • Markdown & Rich Rendering: Chat messages support fully-featured real-time Markdown rendering inside chat bubbles (including syntax-highlighted code fences, tables, and nested lists) for highly readable development chats.
  • GitHub References: owner/repo#N references in a message automatically link to the corresponding GitHub issue or pull request.
  • Clickable File Paths: File paths starting with /workspace/... or /scion-volumes/... render as interactive links. Clicking them immediately opens an on-demand file viewer dialog, fetching the current file content directly from the existing workspace and shared-directory APIs without leaving the chat context.
  • Clickable gs:// Links: A gs://bucket/object reference posted by an agent likewise opens the same on-demand viewer, fetching the object through the sending agent’s own assigned GCP identity. See gs:// links in chat for what links, which identity is used, size limits, and error behavior.
  • iOS & Platform Tailoring: The layout incorporates specific styling adjustments for iOS devices, delivering polished rendering and input behavior under Safari and other mobile browsers. Inputs use a 16px font so iOS does not zoom in on focus, and buttons and rail entries have 44px touch targets.
  • Touch Menus & Bottom Action Sheets: On touch screens, a long-press (about half a second) on a message, thread, space or member opens the same menu that right-click opens on desktop; iOS never sends a right-click for a long-press. At 768px wide or narrower, every chat menu opens as a bottom action sheet instead of a popup.
  • Install as an App: The web UI ships an app logo, PWA icons and a web app manifest, so it can be added to a phone’s home screen with its own icon.
  • Config Toggle: Top-level native chat can be turned on or off globally by administrators using a single configuration key (web.native_chat feature flag) or via the Admin interface.
  • Project spaces are visible to the whole project. Every thread in a project space, and every message and attachment in it, can be read by everyone who has access to that project. There are no private threads, and access cannot be limited to individual threads.
  • Conversations stay in their project. A conversation keeps the project it was created in. Conversation lists and lookups return only conversations you can read, and replies, attachments, read markers and thread references stay inside their own conversation. Live DM events go only to the DM’s participants, and live agent messages follow the same visibility rule as the agent’s message history.
  • Direct messages do not appear in the project space. Messages you exchange with an agent also become part of that agent’s history, which the agent’s owner can see. If you promote an agent DM into a space thread, its messages move into the space, and everyone with access to the project can then read them.
  • Pick the right place:
    • Use a DM to keep an exchange with one person or one agent out of the project space.
    • Use a separate project when a group needs its own access boundary. Chat access follows project access, so only that project’s members can read its space.

The native web chat includes a complete suite of collaboration and developer productivity tools (Phases 0–5):

Right-clicking a message (on desktop) or tapping it (on touch devices without hover) opens a contextual context menu providing several per-message actions. On touch devices, taps on links, buttons, mentions, and reply previews keep their normal behavior:

  • Reply / Quote: Quote a previous message with full backend support for reply-threading, maintaining clear context in fast-moving development discussions. Choosing Reply moves focus to the composer so you can start typing immediately.
  • Edit / Delete: Edit or delete your own messages.
  • Copy Permalink: Generate a direct link to any message in the thread.
  • Open terminal / Open in graph: On a message from an agent, open that agent’s terminal or jump to it in the lineage graph. These act on the message’s author, not the thread’s default agent. Open terminal appears only when you can attach to that agent.
  • Thread Pinning: Pin critical threads to the top of the thread rail for easy access.
  • Mark Unread: Right-click a thread in the thread rail, or a member in the members sidebar (for an existing DM with messages), and choose Mark unread to restore its unread marker. The change syncs to your other open tabs.
  • Conversation Muting: Mute busy threads or spaces to suppress notifications while keeping the discussion active.
  • Thread Drag-and-Drop Reorder: Reorder threads within the rail by dragging and dropping them (native HTML5 drag API). Organize related threads into named collapsible groups that you can expand or collapse to manage long thread lists. Group membership, ordering and each group’s collapsed or expanded state are persisted server-side via your user preferences.
  • Rail Sort: The thread rail’s Sort menu offers Recent activity, Alphabetical, and Custom. Recent activity and Alphabetical order both the spaces and the threads within each space, and choosing either discards any custom thread order. Custom applies to space order. Dragging a space switches the rail to Custom, and dragging a thread saves a custom thread order for that space only.
  • Unread Filter: Switch the rail to Unread to show only spaces with unread messages or mentions, and, inside those spaces, only unread threads. Muted threads never count as unread. The conversation you have open stays visible, together with its space, even after you have read it.
  • Space Emoji Icons: Assign optional emoji icons to spaces, stored in project annotations, for quick visual identification in the thread rail.
  • Layout Density: Choose between Dense and Comfortable layout modes via the density toggle. Dense mode reduces whitespace for maximum information density; Comfortable mode provides more breathing room for extended reading.
  • Quick Command Palette: On the chat page, press Cmd/Ctrl-K to open a grouped, fuzzy-matched palette for jumping to any thread or DM, or opening a recent file, without leaving your keyboard. Results are grouped into Agents, Threads, People and Documents; threads also match their space’s name, and Documents lists the files (attachments and detected file paths) that have most recently appeared in your chats. Each agent row also shows the agent’s project slug, so same-named agents in different projects can be told apart, and you can search by project slug or name. A space in your query also matches a hyphen or underscore, so code review finds code-review and code_review. Choosing an agent opens your DM with it, including peers you have not messaged before; choosing a document opens it in a preview dialog over the current conversation, which is left as it was (files that cannot be shown offer a Download button instead). Use Tab / Shift+Tab to jump between groups, the arrow keys to move within the results, Enter to open and Esc to close. A button in the chat header also opens the same palette by tap or click, which is especially useful on touch screens, where the keyboard shortcut isn’t available.
  • Jump-to-Message from Search: Clicking a search result automatically scrolls to the target message, even when it falls outside the currently loaded message buffer. The target message receives a highlight-flash animation, and a “Jump to latest” button appears to return to the live message stream.
  • Unread Divider with Watermark: An unread indicator bar automatically segments new messages since your last visit, including a watermark to ensure you never miss a transition. A thread with unread messages opens scrolled to the New messages divider rather than to the bottom.
  • Day Separators: Messages, including inter-agent messages, are split by day with the same date separator used throughout the thread.
  • Rich Agent Output Rendering: Dispatched agents can render complex interactive payloads directly inside the chat, including structural diffs, test suite results, and interactive JSON/YAML tree-structures.
  • Collapsed Agent-to-Agent Messages: To keep threads readable, background agent-to-agent messages (visible under the Full density filter) are collapsed into a compact, click-to-expand pill. When expanded, these messages are displayed with 2-line truncation. If a message is truncated, an expand icon (‘arrows-angle-expand’) appears next to it, allowing you to open a full-screen Markdown-rendered dialog overlay.
  • Conversation Export: Export any collaborative thread via the export dropdown in the chat header:
    • Download as Markdown for archiving or sharing agent reasoning.
    • Print / Save as PDF for offline review.
    • Copy to Clipboard (HTML + plain text) for quick pasting into other tools. All exported content is HTML-escaped for safe rendering.
  • Send-to-Agent Context & Slash Commands: Fast-track your workflow with slash commands and easily forward snippets or whole discussions directly to your agents as contextual guidance. The built-in commands are /status (list the project’s agents and their state), /spawn <template> [name] (create an agent), /stop <agent> (stop a running agent; it is not deleted), /default <agent|clear>, /clear and /help. In a DM with an agent, /status, /spawn and /stop act on that agent’s project.

  • Real-Time Browser Notifications: Stay informed of @mentions and incoming DMs with native browser push notifications.
  • Smart Suppression: Notifications are mute-aware and automatically suppressed for active conversations (threads you are currently looking at) to prevent alert fatigue.
  • Chat Chime: A short two-tone chime plays when a chat message arrives from someone else. Your own messages never chime. The chime plays at most once every 2 seconds and does not depend on browser notification permission. Turn it off globally with Chat chime sound in your profile’s notification settings. To turn it off for one project, choose Chime on/off from the thread rail’s options menu. Both preferences are stored in the browser. If the browser’s autoplay policy blocks audio, no sound plays.
  • Unread Badges: The tab title shows the same unread conversation count as the Chat mode badge.
  • Per-Thread Draft Persistence: Drafts are saved locally per-thread, so if you switch threads or close the tab, your unsent message remains waiting when you return.

The web composer features a security-hardened, developer-friendly file upload system:

  • Executable Deny-List Strategy: To maximize flexibility for developers, attachment uploads use a security-first deny-list rather than a restrictive mime-type allow-list. It blocks executable binaries/scripts but permits 34+ developer file types (including configuration files, source code, and data structures).
  • Artifact References: With the hub.artifacts experiment on, the paperclip also offers Attach artifact…, which picks published artifacts to reference in the message. Artifact chips and scion://artifact/ links in messages open a preview in place; see Artifacts.
  • Paste-to-Upload: Paste images or file content directly from your clipboard into the composer for instant attachment.
  • Markdown Attachment Rendering: Markdown files uploaded as attachments render directly within the chat bubble, featuring a source/preview toggle and a one-click clipboard copy.
  • Partial Success Reporting: When uploading multiple files simultaneously, the system supports partial success—successful uploads are staged instantly while failed individual files report explicit inline errors.

  • Token-Bucket Rate Limiting: Per-sender token-bucket rate limits prevent message flooding, ensuring platform stability and protecting backend model endpoints.
  • Touch-Friendly Composer: On touch devices without hover, Enter inserts a newline instead of sending, because there is no Shift+Enter. Use the Send button to send.
  • 16K Input Character Limit: A robust 16,000-character limit is enforced in the composer, protecting token context limits.
  • SSE Direct Append & Real-Time Attachments: Chat messages stream via Server-Sent Events (SSE) using direct-append logic, providing lag-free typing rendering. Additionally, attachment previews render immediately on incoming SSE messages, ensuring the user interface instantly displays attachment references without waiting for subsequent user-triggered renders.
  • Idempotency Keys: Client-side idempotency keys eliminate duplicate messages during transient connection drops or retry states.
  • Honest Delivery Status: A message to an agent that is not running is marked Agent unreachable instead of Accepted. Accepted means the agent’s runtime took the message and buffered it, not that the agent has read it; Seen appears once the agent has read it. A thread message that mentions no agent is saved to the thread but marked Not delivered to any agent; mention an agent to deliver the message to it. If the Runtime Broker fails to deliver a message to the agent’s terminal, it makes up to 3 attempts in total, but never retries once part of the text has already reached the terminal (so the agent does not see it twice), and a user sender sees the failure live in the chat. Messages to an agent that has been deleted fail right away instead of waiting in the queue. Failed messages are purged after 7 days.
  • Wake and Send: If you send to a suspended agent and you are allowed to start it (the agent.lifecycle permission), the chat asks whether to wake it instead of marking the message Agent unreachable. Choose Wake and send: the Hub resumes the agent, waits up to 30 seconds for it to be ready, and delivers your message as its first input. The bubble shows Waking agent… in the meantime. A retry after a dropped connection does not send the message twice. Without the permission, or when the agent is stopped, in error or deleted, you see the ordinary Agent unreachable status.
  • Cursor-Based Scrollback Pagination: Solved previous scroll-jump issues and cursor-mismatches. Scrollback pagination and scroll-to-bottom locks operate smoothly as history loads.

When writing instructions, you can easily pull other agents into the thread:

  • Autocomplete Popup: Typing @ in the chat input opens a dropdown list of active agents in the project. The list supports fuzzy-matching as you type, and full keyboard navigation (arrow keys to select, Enter to insert).
  • Code-Fence Guard: The mention autocomplete is smart — it automatically disables itself when typing inside Markdown code fences (e.g., ``` blocks) so code snippets don’t trigger unwanted dropdowns.
  • Mention Leak Protection: Direct mentions are safely partitioned, resolving a previous bug where mentions would leak into the default agent tab.
  • Recipient-Form Mentions: A mention written in recipient syntax, such as @agent:hub-ops, is rewritten to @hub-ops in the message body before the Hub stores it, so the mention reaches the named agent. The Hub does this for web, chat and CLI sends alike (scion message applies the same rewrite before sending). Code spans, fenced code blocks and quoted (>) lines are left as written, and an address such as ops@agent:foo is not a mention.
  • Fan-Out Restrictions: For platform stability, a single message is fanned out to a maximum of 10 recipients per @-mention broadcast.
  • Bidirectional Mention Translation: Mentions are automatically translated between the formats used by agents and the web chat. In the chat UI, mentions display as @firstname-lastname; when delivered to agents, they are translated to @email format, and vice versa. This ensures both humans and agents see the most natural identifier for their context.
  • Composer Default-Agent Disambiguation: When sending messages in collaborative project spaces with multiple active agents, typing a message without an explicit target or @-mention triggers a smart disambiguation interface. This guides the user to select which agent the message should target (or fall back to the project’s configured default agent), keeping routing unambiguous and conversations clear.

If you use external messaging systems alongside the Web Dashboard, Scion ensures that conversations remain coherent across all channels:

  • Broker Inbound Persistence: Inbound messages received from external message brokers (such as Discord or Teams) are persisted in the Hub’s main database, making them instantly visible in the Web Chat.
  • Reply Affinity: Scion tracks user, project, and agent reply affinity so that replies are routed back to the initiating channel.
  • TouchThread & Broadcast Propagation: Messages and read states propagate smoothly across surfaces via TouchThread and Broadcasted events, ensuring that reading or replying to a thread on Discord or Teams instantly syncs the unread badges in your Web Dashboard.

You can also interact with the messaging system directly from the CLI using the scion messages command (aliases: msgs, inbox).

Terminal window
# View unread messages
scion messages
# View all messages for a specific agent
scion messages --agent <agent-name>
# Mark a message as read
scion messages read <message-id>

Use scion message to send messages. The preferred addressing form uses @:

Terminal window
# Send to an agent (preferred form)
scion message @tech-lead "Please review the auth module."
# Send a global DM to a user by email
scion message @preston@example.com "Build is green, ready for review."
# Legacy forms (still work but @-form is preferred)
scion message agent:tech-lead "Please review the auth module."
# Attach a file
scion message @tech-lead "See the test results." --attach ./results.json
# Point at a published artifact (see Artifacts); the recipient is told how to fetch it
scion message @tech-lead "Design ready for review." --artifact scion://artifact/5f1c2d3e-6b1a-4c55-9f3e-0d6e7a1b2c3d
# Read message body from a file (useful for long messages or scripted workflows)
scion message @tech-lead --body-file ./review-notes.md
# Read the message body from stdin (`-`, or equivalently `--body-file -`)
git log --oneline -5 | scion message @tech-lead -
scion message @tech-lead --body-file - < ./review-notes.md

For --body-file and stdin, trailing CR/LF characters are trimmed; everything else is sent exactly as read.

A successful send to an agent prints Message accepted for agent '<name>'. “Accepted” means the Hub handed the message to the agent’s runtime, which buffered it. It does not mean the agent has read it. A send to an agent that is reincarnating prints a separate notice that the message was saved for catch-up.

Messages to an agent that is still starting. Until its harness accepts input, an agent’s activity is initializing (shown as “starting”). Messages sent in that window, from the CLI, web chat or a DM, are accepted and held by the agent’s runtime. They are pasted once the harness reports it is ready, or after at most 90 seconds, so early messages are not lost. An --interrupt sent in that window is delivered as an ordinary message. To wait for readiness before you send, start the agent with scion start --wait-ready.

See scion message for what each status means.

The scion message CLI delivers the body argument verbatim — it performs no escape expansion, no markdown rendering, and no character substitution. Whatever bytes you pass are exactly what the recipient sees.

To include newlines, use real newlines inside shell quoted strings or heredocs. Do not use JSON-encoded bodies or literal backslash-n (\n) sequences — those will appear as literal characters in the delivered message.

Correct — real newlines in a quoted string (plain text only, no backticks or $):

Terminal window
scion message --non-interactive @reviewer "PR #42 is ready for review.
Branch: fix/auth-bug
CI: all green"

Correct — heredoc for longer messages:

Terminal window
scion message --non-interactive @reviewer "$(cat <<'EOF'
PR #42 is ready for review.
Branch: fix/auth-bug
CI: all green
EOF
)"

Wrong — JSON-encoded body with literal \n:

Terminal window
# BAD: literal \n chars appear in the delivered message
scion message --non-interactive @reviewer "PR #42 is ready for review.\n\nBranch: fix/auth-bug\nCI: all green"
  • scion broadcast: Send a message to all agents in the current project, or use --all for a global broadcast. The --broadcast and --all flags on scion message have been removed; use this command instead.
  • scion keys: Send literal terminal input to an agent’s tmux session (e.g., scion keys editor "Enter", as a separate call from scion keys editor "Escape"), with no envelope and no automatic Enter. Useful for unblocking interactive prompts. Works for container-backed agents; not supported for managed-runtime agents (see Managed Agents). When run by an agent, it can only target agents in the agent’s own project — cross-project targets are refused, by the CLI and the Hub alike; a human operator using --project can target other projects, with the same authority as scion attach on the target. It is authorized like terminal attach rather than messaging — message mode does not gate it — and requires, for an agent caller, a live attach relationship on the target in addition to shared project membership (see CLI Reference). There is no key-sequence syntax: issue one scion keys call per key press. This replaces the removed --raw flag on scion message, which now fails with guidance naming scion keys.

The scion conversation command (alias conv) provides a surface-agnostic interface for managing conversations — the containers for message threads that span across the web chat, external channels, and CLI.

Conversations are referenced using one of three forms:

  • conv:<uuid> — by conversation ID.
  • @<agent-name> — resolves the direct conversation with the named agent.
  • #<thread-name> — resolves a named group conversation.
Terminal window
# List your conversations
scion conversation list
# View messages in a specific conversation
scion conversation messages @tech-lead
# Create a new group conversation
scion conversation create "sprint-planning"
# Set a default agent for a conversation
scion conversation set-default "#sprint-planning" agent-id
# Catch up on recent messages (last 2 hours)
scion conversation catch-up @tech-lead --since 2h
# Retrieve a single message by ID
scion conversation get-message conv:a1b2c3d4-... msg-uuid-here
# List participants in a conversation
scion conversation participants "#sprint-planning"
# Join or leave a conversation
scion conversation join "#sprint-planning" user user-id
scion conversation leave "#sprint-planning"

A direct conversation registers both participants, so DMs you send or receive appear in scion conversation list.

An agent post into a group conversation or thread (by conv:<id> or thread ID) that @mentions no agent is delivered to the conversation’s default agent, as a human post is (if the sender may message it, and never to the sender itself). When the post reaches no agent, the response sets no_agent_woken and scion message prints a one-line notice.

For full flag details, see the CLI Reference.

Scion supports Discord through two separate integration pathways:

  • Bidirectional Discord Bot: Interact with agents directly from Discord channels using slash commands under /scion (e.g., /scion setup to link channels, /scion default to set routing targets, /scion agents to check state). Agent replies are pushed back into the Discord channel with their own name and RoboHash-generated avatar.
  • Outbound Webhook Notifications: A simpler, outbound-only mechanism where agents push status updates, alerts, and ask_user requests to a designated Discord channel. Messages are color-coded by severity, and urgent notifications can trigger @user or @role mentions.

For a full setup guide and configuration options, see External Channels.

Scion also supports bidirectional messaging over Telegram: message your agents from a Telegram group and receive their replies in the chat. For a step-by-step Workstation setup, see Setting Up Telegram; for how it fits alongside other channels, see External Channels.

When an agent uses the ask_user tool (or similar mechanism depending on the harness), Scion automatically performs two actions:

  1. State Update: The agent’s state changes to WAITING_FOR_INPUT.
  2. Explicit Message: A persistent message from the agent, clearly stating what it needs, reaches you in Chat (and Discord, if configured), and the agent event appears in the notification tray.

Messages are delivered in real-time to the Web Dashboard via Server-Sent Events (SSE). The Messages Tab on the individual agent detail page provides a real-time stream of all communication with that specific agent.

When an agent finishes a turn, its Stop hook mirrors the agent’s reply to the user who created it, so it reaches you as a message from that agent. Only agents created directly by a user are mirrored; sub-agents (agents created by other agents) are not. Each user notification is stored exactly once.

Messages record the sender’s and recipient’s projects. Human callers see these as senderProjectId and recipientProjectId on conversation messages; agent callers see them only on direct messages where both parties are named in the conversation.

Messages are not silently dropped in these cases:

  • Non-running recipients. A message is rejected if the recipient agent is not running (suspended, stopped, in error, or still starting). For direct messages, human or agent, the send fails immediately with a 409 error. Pass --wake to resume a suspended agent and then deliver. Waking requires the same lifecycle permission as starting the agent (agent.lifecycle), for user and agent senders alike; without it the send fails with 403 and the agent is not resumed. Broadcast, group, and message-broker deliveries are rejected per recipient. A sending agent gets a DELIVERY_FAILED system notice (“Message delivery to <agent> failed: …”) for each rejected recipient.
  • Reincarnating recipients. While an agent is being migrated with scion reincarnate, messages to it are saved to its conversation history instead of being dispatched or dropped. DMs, group messages and @mentions return 202 with status deferred, and a sending agent gets a DELIVERY_DEFERRED system notice rather than a failure. The new generation is told to read what it missed with scion conversation catch-up. Scheduled messages that fire during a reincarnation fail loudly instead of being deferred.
  • Late broker failures. A Runtime Broker may accept a message into its short delivery buffer and then fail to deliver it, for example because the container has gone away. The broker reports this to the Hub. The Hub marks the message failed rather than leaving it dispatched, and notifies the sending agent.
  • Group messages to non-running members. Group messages do not wake agents. A member that is not running is not dispatched to; its copy of the message is stored as failed with a reason (suspended members get a group-specific one), and the sender gets a per-member failure result.
  • Runtime Broker timeouts and cancelled requests. The failure is still recorded: the message is marked failed and the sending agent still gets its DELIVERY_FAILED notice even if the original request was cancelled or the Runtime Broker timed out. Failure reasons from the Runtime Broker are sanitized before they are stored or shown in a notice.
  • Agent messages to humans. If the Hub’s delivery queue for a project is saturated, the agent’s send fails with 503 (unavailable); retry later. A retry may duplicate the message on an external chat channel such as Discord.

Every agent is protected by a Message Mode that controls which users and other agents can send messages to it. An agent’s message mode can be managed in several ways:

  • Web Dashboard: Use the mode controls on the agent detail page.
  • CLI: Use scion set-message-mode <agent-name> <mode>, or set the initial mode at creation time with scion start --message-mode <mode>.
  • Agent self-service: Full-role agents can call set_message_mode programmatically to adjust their own or their children’s message modes.

The available modes are:

  • Project Mode (Default): Any user with the agent:message permission in the project can message the agent. Any peer agent in the project (that is not restricted by lineage mode) can also message it. The most permissive mode. Note that the default project-member role does not include agent:message — messaging requires an owner, admin, or ancestry relationship with the agent (i.e., the agent’s creator or their ancestors). This aligns messaging authorization with the terminal attach permission gate.
  • Hub Mode: Behaves like Project mode within the agent’s own project, and additionally allows the agent to send direct messages across project boundaries when cross-project messaging is enabled. A project-mode agent can receive a cross-project DM but cannot reply across the boundary until granted Hub mode.
  • Branch Mode: Only users in the agent’s ancestry chain (its creator and their ancestors), plus the agent’s direct parent and child agents, can message it. Agent-to-agent messages need both agents in branch mode and one to be the other’s direct parent; siblings, grandparents, and pairs that mix branch with another mode are denied.
  • Lineage Mode: Strictly restricts messaging to users in the agent’s ancestry chain (its creator and their ancestors). No agent-to-agent messaging is permitted.
  • None Mode: Seals the agent from all messaging except system-plane notices. No users and no agents can message a none-mode agent through normal paths.

A new agent’s mode is set once, at creation: the --message-mode flag of scion create or scion start if given, else the template’s message_mode, else the parent agent’s mode when an agent creates it, else project. A default that resolves to hub still needs a hub-mode grant.

To see modes:

  • scion whoami --full shows the calling agent’s own mode (messageMode in --format json).
  • scion conversation get and scion conversation participants show a MSG MODE column for agent participants in the conversation’s project; for a conversation without a project (a DM or legacy group), in the calling agent’s project (messageMode in JSON). It shows - for users, for agents outside that project, and for every agent when a user reads a conversation without a project.
  • When a send is denied, the CLI error names the reason and both modes, for example message_denied: Message delivery denied [reason: ..., sender mode: branch, recipient mode: project] (status: 403).

Highly privileged users can bypass an agent’s message mode restrictions. This is called piercing.

  • Project Owners can pierce Branch and Lineage modes.
  • Super-admins pierce all modes, including None mode. Piercing applies only to user identities — it is never inherited by an owner’s agents.

The Web Dashboard displays reachability indicators (e.g., whether you can message a specific agent) based on the computed messageability, which takes into account the agent’s mode, your ancestry relationship to it, and any piercing privileges.


Agents can send direct messages across project boundaries when all three independent controls permit it. Cross-project messaging is off by default; all three must be enabled for a message to be delivered.

Control Setting Default Who can change it
Hub availability cross_project_messaging_enabled (Hub messaging settings) false Hub administrator
Agent outbound reach Agent message mode set to hub project Agent owner or project admin
Receiving project inbound policy crossProjectInbound on the destination project none Project owner or Hub administrator

Each project controls which cross-project messages it accepts via its crossProjectInbound setting:

Policy Meaning
none Accept no agent messages from other projects (default).
members Accept an external agent only when its originating human is an active member of the receiving project.
any Accept an eligible agent from any project on the Hub.
  1. Hub administrator enables the feature globally:

    Terminal window
    scion hub messaging set --cross-project-enabled=true --revision <N>
  2. Project owner sets an inbound policy on the receiving project:

    Terminal window
    scion project messaging set --project <project> --policy members --revision <N>
  3. Grant hub mode to the sending agent:

    Terminal window
    scion set-message-mode <agent-name> hub
  4. Send a cross-project message:

    Terminal window
    scion message --project <target-project> @<agent-name> "message"

When a cross-project message is rejected, the system returns a specific denial code explaining the reason:

Code Meaning
cross_project_disabled Cross-project messaging is disabled by the Hub administrator.
cross_project_sender_mode The sender must be in Hub mode to send cross-project messages.
cross_project_target_mode The recipient must be in Project or Hub mode to receive cross-project messages.
cross_project_inbound_none The recipient’s project does not accept messages from external agents.
cross_project_origin_not_member The sender’s originating user is not a member of the recipient’s project.
cross_project_untrusted_origin The sender’s identity origin could not be verified.
cross_project_surface_unsupported Cross-project messaging is not supported for this conversation type (e.g., group conversations).

For developers authoring agents and custom orchestrators, Scion’s messaging system follows a set of strict protocol rules and architectural patterns.

Scion maintains different limits depending on the recipient type:

  • User-Directed Messages (Agent-to-Human): Limited to 2,000 Unicode characters (runes). Each CJK character or emoji counts as a single character. Exceeding this limit causes scion message to fail with exit code 1 and print: validation_error: message exceeds 2000 character limit
    • Tip: If you have a long message or log to send to a user, split it into multiple messages under 1,800 characters, or write the full content to a shared scratchpad file and send the filepath.
  • Agent-to-Agent Messages: No enforced length cap in code. You can send larger payloads safely between agents.
  • Large-DM offload (opt-in): A Hub administrator can set offload_threshold_runes in the Hub messaging settings (PUT /api/v1/admin/messaging). When an agent-recipient DM body is longer than the threshold, the agent’s terminal receives a short stub instead: the body size, a preview, and one command to fetch the full body (for example, scion conversation get-message conv:<conversation-id> <message-id> --body). The stored message, the Web Dashboard, and other observers always keep the full body. Plain messages are never offloaded. The default threshold is 0 (disabled); leave it there until your agent images include a scion CLI with that fetch command.

Scion does not forward an agent’s end-of-turn text to anyone. A user, an agent or an A2A caller sees only what the agent sends on purpose with scion message. Instruct agents that answer people or other agents to reply with scion message.

When an agent receives an inbound message in Hub mode, it arrives as a JSON object wrapped in standard delimiters:

You are receiving a message from the orchestration system:
---BEGIN SCION MESSAGE---
{
"timestamp": "2026-10-08T21:00:41Z",
"message_id": "5d0c8a2e-7f41-4b8e-9c1a-2f6e0b3d9a17",
"conversation": {
"id": "af3cd254-0489-408f-a876-a749ec6e7f98",
"kind": "direct",
"surface": "native"
},
"from": "agent:tech-lead",
"type": "message",
"msg": "Write a unit test for the auth package."
}
---END SCION MESSAGE---

The timestamp is when the message was created, and message_id is the ID of the message the Hub stored for this delivery, so an agent can name the exact message it received, for example to tell the sender which message it is answering. When the envelope names a conversation, the agent can also fetch the message with scion conversation get-message conv:<conversation.id> <message_id>; when conversation is omitted (for example on a broadcast), there is no conversation to pass and the message cannot be fetched that way. message_id is omitted when the Hub stored no message for the delivery: scheduled messages, status notifications, artifact review notices, and plain (--plain) deliveries, which carry only the text. In a reply, reply_to still names the message being replied to; message_id names the reply itself.

Always check the type field before acting or replying:

Type Meaning Action Required
message A message for you: a direct message, a group message, or a message routed to you in a chat thread. An @mention fanned out from another agent’s scion message also arrives as message, and so does a notification that an agent you subscribe to is waiting for input (see below). When the message went to several agents, to may list them. Read and act on it.
reply A reply to a message you previously sent. Routes to the original sender agent, not the thread default. reply_to is the ID of the message being replied to, and reply_context holds its first 32 characters. Read and act on it like a message.
mention You were @mentioned in a chat message whose primary recipient is someone else. to lists every agent the message engaged, including you. Treat as FYI unless explicitly directed otherwise.
event A notice generated by Scion rather than written to you. The event object says what happened: event.type is one of agent.state-changed (an agent you subscribe to changed state; event.subject names the agent and event.status the state, for example COMPLETED or STALLED), schedule.fired (a scheduled message; msg is the scheduled text), delivery.failed (a message you sent was not delivered; event.status is DELIVERY_FAILED, or DELIVERY_DEFERRED when it was saved for an agent that is reincarnating), port.exposed, or artifact.review. Act on a schedule.fired message’s text; treat the others as FYI or follow the instructions in the notice.

When an agent signals WAITING_FOR_INPUT (by calling sciontool status ask_user), a notification is dispatched to all subscribed agents (including its creator). It arrives as a message from the waiting agent, with text such as <agent> is WAITING_FOR_INPUT: <question>.

  • Parent Agent Role: If you are the parent agent that created the waiting agent, you may be the intended respondent. Use scion message @<name> to reply with the answer.
  • Peer Agent Rule: Unrelated peer agents should NOT reply to waiting-for-input notifications. Answering a peer’s input prompt wastes context tokens, causes false loop signals, and violates project-scoped boundaries. To request a peer’s input, always send it an explicit message instead.

When the platform halts an agent (for example its Kubernetes pod was preempted or evicted, or it was killed for running out of memory), Scion sends one HALTED notification for that halt, with text such as:

worker-1 was halted by the platform (preempted). Workspace kept. Resume: scion start worker-1.

The workspace part says what scion start does with the workspace: Workspace kept, Workspace re-cloned (a workspace on the pod’s own storage), or Workspace may be re-cloned (where it lives is not known).

Who receives it:

  • The agent’s creator, when they have no subscription to the agent or its project: the user who created the agent, or the agent that created it (while that agent still exists in the same project). A creator who has a subscription gets HALTED only if that subscription selects it.
  • Subscribers with the HALTED trigger. HALTED is one of the default triggers of the subscription recorded when an agent is created with notify on, and one of the Web Dashboard’s default and selectable triggers. The default triggers of scion notifications subscribe do not include it; add it with --triggers.
  • Subscribers with only the ERROR trigger, when the halt replaced what would have been an error (for example a preempted pod whose workspace did not survive). They receive it with status ERROR, as they would have without the halt.

Each subscriber, including the creator, receives one notification per halt.

If a notification cannot be delivered to a subscriber agent (for example because its Runtime Broker is not connected), it is not marked as sent. The Hub tries again on a sweep about every 5 minutes, and again when the Runtime Broker reconnects, for up to 24 hours after the notification was created. Each notification records its number of delivery attempts (dispatchAttempts) and an outcome (dispatchOutcome): delivered, or failed once the 24 hours have passed or the subscription, subscriber or watched agent is gone. The outcome is empty while delivery is still pending. A subscriber agent that has no Runtime Broker is not attempted, so its notification stays pending and does not reach the 24-hour limit.

4. Subscription Management and Agent Self-Service

Section titled “4. Subscription Management and Agent Self-Service”
  • Automatic Subscription: The --notify flag on scion start is deprecated. When you start a sub-agent, Scion automatically registers your subscription via creation ancestry.
  • Explicit Messaging Subscription: Use the --notify flag on scion message only when you need to subscribe to notifications from a peer agent that you did not create.
  • Agent Self-Service Subscriptions: Running agents in Hosted mode are empowered to programmatically manage their own notification subscriptions. Previously restricted to administrative users (returning a 403 Forbidden for agents), agents with appropriate API credentials can now perform the following operations:
    • CRUD Operations: Live agents can list, create, update, and delete their own subscriptions via the Hub API or client utilities.
    • Identity Qualification: To prevent cross-project security leaks, every subscription request is qualified by the agent’s specific (project, slug) coordinates.
    • Granular Scopes: Authorization gates require the agent token to hold the project:read scope for reading subscriptions and the project:agent:notify scope for writing (creating, updating, or deleting) subscriptions.
    • Ownership Constraints: Acknowledging notifications or modifying/deleting existing subscriptions strictly requires ownership validation, meaning an agent can only modify or acknowledge subscriptions that target or belong to itself.

5. Security Controls for Direct Messages & Broadcasts

Section titled “5. Security Controls for Direct Messages & Broadcasts”

Scion employs strict, ingress-level security controls and invariants for Direct Messages (DMs) and Broadcasts to prevent spoofing, cross-project injection, and message divergence:

  • Server-Side Sender Identity & Derivation: Sender identity is forced server-side based on the authenticated request context, completely ignoring any sender claims in the payload. Furthermore, DM conversation keys are derived dynamically from the authenticated caller rather than trusting the payload, closing spoofed-sender conversation-selection vectors.
  • Canonical DM Key Enforcement: Thread IDs (used as DM keys) undergo strict canonicality enforcement. Non-canonical kinds and UUIDs are rejected immediately at derivation without silent normalization, ensuring precise routing.
  • Participant Guard Consolidation: A unified participant guard (CheckDMParticipantKey) protects all DM ingresses (adding/ensuring participants or merging conversations). This strict invariant guarantees that participant records cannot diverge from their canonical thread keys.
  • Broadcast Authorization: Project membership is strictly required and enforced for all broadcast calls.
  • Publish Gating & Stamping: Message publishing to real-time streams (SSE) is securely gated on successful database persistence (dual-write conversation stamping). This ensures that a message is never broadcasted to clients without being safely committed to history.

Instead, pair sciontool status blocked with a scheduled self-callback using scion schedule create:

Terminal window
# Correct way to wait 5 minutes for a build to finish:
scion schedule create --in 5m --message "Check build status" --agent "$(scion whoami --non-interactive --format json | jq -r .name)"
sciontool status blocked "Waiting for build job 103"

The scheduled message delivers the wake-up poke; status blocked tells the platform that your silence is intentional, keeping you from being suspended.

7. @mention Parsing & Conversation Addressing

Section titled “7. @mention Parsing & Conversation Addressing”

@<agent-name> is now the preferred addressing form for sending messages to agents via the CLI (e.g., scion message @tech-lead "..."). This form addresses the agent’s conversation directly.

When a human or an agent sends a message, Scion automatically scans for recipient targeting to fan-out notifications:

Any name starting with @ in the message body (e.g., @dev-lead) is automatically parsed. If the name matches an active agent within the same project, Scion generates a secondary message of type mention and delivers it to that agent.

To send to multiple recipients at once, use the group[...] addressing form:

Terminal window
scion message "group[tech-lead, dev-agent, qa-agent]" "Let's review the deployment strategy"

A group send reports each recipient’s outcome and exits 3 when only some recipients received the message; see Group sends and exit codes.

  1. Deduplication: If an agent is both @mentioned inside the body of a message and explicitly addressed as a recipient, Scion automatically deduplicates the list so they only receive a single mention message.
  2. Project Scope Restriction: Mentions are restricted to the parent project boundary. Body-mentions can only be resolved and delivered to agents that belong to the same project. Unresolved names will result in a warning printed to stderr, but will not fail delivery of the primary message.
  3. Fan-Out Restrictions: A single message is fanned out to a maximum of 10 recipients per @-mention broadcast.
  4. Agent-Authored Mentions: When an agent’s message @mentions another agent, the Hub delivers the mention server-side, authorized like a direct message and charged to the sender’s send budget. Mentions between the same pair of agents are also capped (10 deliveries per 10 minutes) to stop mention loops. A mention that is denied or rate-limited is skipped without failing the primary message.