
How to Route Work From One Agent to Another
Routing work between AI agents is only useful if the handoff lands in the right session and the sender can understand what happened. AxiOwl treats that as a transport problem, not a prompt-writing trick. A named sender sends a text body to a named target, AxiOwl resolves both names, builds one final visible message, delivers through one provider edge, and records a receipt.
That design matters because different agent surfaces behave differently. A Codex session, a VS Code native chat, a Copilot-backed VS Code session, an Antigravity agent, and a Cursor agent do not expose the same delivery mechanics. AxiOwl puts that provider-specific work behind routing and delivery edges so the operator can use a consistent command shape.
The Basic Route
The common user-facing command is:
axiowl send --to "Target chat name" --body "Message text"
For longer work instructions, stdin is the safer form:
@'
Review this module and report the highest-risk behavior changes.
Include file paths and the exact test command you used.
'@ | axiowl send --to "Target chat name" --stdin
In the current Windows desktop implementation, the CLI parses the target, body, optional sender fields, strict mode, run id, and optional delivery method. It then creates a MessagePipeline using the local registry and evidence log. The CLI is not supposed to guess provider internals itself; it hands the request into the AxiOwl pipeline.
What AxiOwl Resolves Before Sending
AxiOwl routing starts with identity. The target name in --to is resolved through the registry. Registry rows represent reachable provider sessions and include the display name, aliases, provider, provider session id, node id, sendability, source, and error fields.
That means a friendly name is not the route by itself. A usable route also needs provider-owned facts, such as the provider value and session id. The architecture docs describe the registry as durable local state, not a convenience cache, because stale display names should not become stronger than real provider session identifiers.
The sender matters too. Provider replies are strongest when they come through the AxiOwl MCP tool because MCP can carry provider/session identity metadata. The developer docs explicitly prefer provider-owned MCP metadata, matching provider session ids, or registry aliases over guessing from a display name. If AxiOwl cannot resolve the sender, the pipeline fails loudly for current explicit sends rather than inventing a return route.
The Routing Pipeline
The product contract describes the fixed route:
CLI or MCP tool
-> message pipeline
-> sender resolution
-> target registry resolution
-> final visible body builder
-> provider edge dispatch
-> provider-specific delivery
-> evidence log and receipt
The current message_pipeline.cpp implementation follows that shape. It rejects empty targets and empty bodies, resolves the sender, performs target lookup, allows one targeted discovery repair when a target is missing or stale, checks whether the target is sendable, records the AxiOwl handoff boundary, builds the final visible body, and hands delivery to the delivery worker.
The "one targeted discovery repair" detail is important. AxiOwl can try to repair missing or stale routing state, but sending is not meant to become a broad scan of random provider files. Discovery finds provider facts. Enrollment decides whether those facts are usable send targets. The registry remains the routing source of truth.
The Message the Receiver Sees
AxiOwl does not just forward the raw body. After it knows the sender and target, it builds the final visible message once. In the current implementation, the final body starts with:
Message from <sender agent>
It then includes the original body and, when sender identity is resolved, appends an exact MCP reply instruction using the axiowl_send_message tool. That reply instruction can include a run id and a receipt-for message id. The point is practical: the receiver gets both the work request and the correct return path in the same visible message.
This also explains why a reply is not treated as part of the original send receipt. If the receiving provider responds, that response starts a new AxiOwl send back to the original sender. A send receipt proves only what AxiOwl can prove at that stage.
Provider Edges Keep Routing Honest
Once a target row resolves, AxiOwl dispatches based on the provider field. The current Windows provider edge table includes delivery paths for provider values such as codex, codex_cli, vscode_native, vscode_copilot_backed, antigravity, antigravity_cli, cursor, cursor_cli, claude_code_cli, copilot_cli, and opencode_cli.
That does not mean every provider surface has the same support level. The provider support matrix separates supported, target, experimental, unsupported, and removed surfaces. Current supported surfaces include Codex agents, Codex CLI, VS Code native agents, Copilot in VS Code through the bridge extension, Cursor agents, and Antigravity agents. Several CLI surfaces have code or plans but still require final metadata or response-backed proof.
The remote provider is a useful example of honest routing boundaries. There is a remote provider plan based on SSH relay sessions and newline-delimited JSON frames, but the current provider support matrix marks remote as unsupported for local-provider remediation builds, and provider_edges.cpp returns an explicit out-of-scope result for remote delivery. AxiOwl should not silently use remote routing as a fallback when a local provider route fails.
Reading the Receipt
AxiOwl receipts are intentionally careful. In the CLI implementation, a successful local handoff can print:
AxiOwl handoff receipt: MCP/CLI request accepted by AxiOwl.
Message ID: <id>
Delivery state: accepted_by_axiowl
Provider: <provider>
Receipt boundary: provider delivery, provider wake-up, and provider reply are not implied.
Delivery log: <path>
If a path reports provider acceptance explicitly, the CLI can show that stronger state. If provider delivery fails, it reports the failure loudly with the provider and reason. This distinction is central to AxiOwl's design. accepted_by_axiowl means the request entered AxiOwl and was handed to delivery. It does not prove the target provider displayed, processed, or replied to the message.
The strongest practical proof is a provider reply through AxiOwl MCP with correct sender identity. That proves AxiOwl accepted the request, the provider received it, the provider had the AxiOwl tool available, and AxiOwl could identify the session that replied.
A Practical Operator Workflow
For day-to-day routing, the safe workflow is:
- List or discover agents so the target is represented by a sendable registry row.
- Send short work with
--bodyand longer work with--stdin. - Include a clear requested action in the body, such as review, test, summarize, or implement.
- Read the receipt boundary instead of assuming a provider reply happened.
- Treat a reply through
axiowl_send_messageas the stronger end-to-end signal.
The registry is where routing discipline shows up. If a target is not in the registry, AxiOwl rejects the message after targeted discovery fails. If a target is known but not sendable, it rejects the message with that reason. If the provider field is unknown, the provider edge returns an unknown-provider failure instead of guessing.
Why This Matters
Routing work from one agent to another is not just "paste this into another chat." It requires names that resolve, provider sessions that are real, sender identity that can support replies, delivery paths that match the target provider, and receipts that do not overclaim.
AxiOwl's approach is deliberately plain: use the registry to find the target, build one visible message, dispatch through exactly one provider edge, and record what happened. That gives operators a repeatable way to move work between agents while preserving the difference between a local handoff, provider acceptance, and a real reply.