
AxiOwl Message Routing Explained
AxiOwl message routing is the part of AxiOwl that turns a human target name, such as a known Codex thread or VS Code chat, into a provider-specific delivery attempt. It is not just a text forwarder. The current AxiOwl C++ implementation keeps a local registry of sessions, resolves sender identity, checks whether the target is sendable, builds a visible message body with reply instructions, and then hands delivery to the correct provider edge.
That distinction matters because AxiOwl is designed for real operator workflows, not toy chat relay. A message should go to the named session the sender intended, and a reply should be able to find its way back to the original sender without asking the receiving agent to invent a route.
The Short Version
In the current Windows desktop implementation, the core routing flow is:
CLI or MCP tool call
-> axiowl.exe
-> command handler
-> MessagePipeline
-> sender and target resolution
-> targeted discovery repair when needed
-> provider edge dispatch
-> delivery worker
-> provider-specific write or handoff
-> evidence and delivery logs
The public shape is simple. A user or agent can send with the CLI:
axiowl send --to "<agent>" --body "<message>"
Provider-hosted agents normally use the MCP tool instead:
axiowl_send_message
The MCP server description in the implementation is explicit about the receipt boundary: success is an AxiOwl handoff receipt only. It does not automatically prove that the provider displayed the message, acted on it, or replied. AxiOwl separates "accepted by AxiOwl" from provider delivery proof and from the strongest proof, which is an actual response coming back through AxiOwl MCP with correct sender identity.
Routing Starts With Identity
AxiOwl has to know two things before it can route a message:
- Who is sending.
- Which registered target should receive the message.
For CLI sends, the pipeline can use explicit sender information when available. For MCP sends, the source code is stricter: the host MCP session ID is treated as the stable sender identity key. The server instructions tell provider agents to use axiowl_send_message and not construct raw command lines or provide --from manually.
This is not cosmetic. Reply routing depends on a real provider session identity. If AxiOwl only had a display name guessed from the prompt, the receiving agent might be given a reply path that points to the wrong session or a stale session. The architecture docs call this out directly: MCP sender identity must come from provider metadata or a provider patch that supplies metadata programmatically. Environment-only identity is not considered enough for final provider CLI support.
The Registry Is The Routing Table
AxiOwl's registry is the durable local routing table. A registry row represents a reachable provider session or agent. Important fields include:
display_name, the human-readable target name.aliases, alternate names that can resolve to the same row.provider, such ascodex,vscode_native,vscode_copilot_backed,cursor,antigravity, or a CLI provider surface.provider_session_id, the provider-owned session identifier.node_id, which distinguishes local and node-scoped records.sendable, which controls whether AxiOwl currently believes the row can receive messages.source,last_seen_at,last_verified_at, andlast_error, which explain where the row came from and whether it is healthy.
When MessagePipeline::send receives a request, it validates that the target and body are not empty, resolves the sender, and then asks the registry for the target. If the target is missing or needs repair, the pipeline runs one targeted discovery attempt. That is deliberately limited. Discovery can repair stale inventory, but it is not treated as delivery proof.
If the target is still missing after discovery, AxiOwl rejects the send with a specific error. If the target exists but is marked not sendable, AxiOwl also rejects the send and includes the target's last error when available.
The Receipt Boundary
One of the most important implementation details is where AxiOwl says "accepted."
The pipeline marks a message as accepted_by_axiowl only after the target has resolved to a canonical registry row and the row is sendable. The evidence log records that this receipt is an AxiOwl-only receipt at the boundary after target resolution and before provider delivery completes.
That design prevents a common operations mistake: treating a local router receipt as proof that a provider session actually saw the message. AxiOwl's architecture separates three levels:
accepted_by_axiowl: the request was valid, sender and target resolution succeeded, and delivery handoff started.- Provider acceptance: the provider edge reported that its target accepted or received the write.
- Response over MCP: the target provider acted on the message and replied through AxiOwl with provider-owned sender identity.
For real diagnostics, that third level is the strongest signal.
Final Visible Body And Reply Instructions
Before AxiOwl hands the message to a provider edge, it builds the final visible body. The source in final_visible_body_builder.cpp shows the practical intent: the target sees the original message plus a reply instruction block that points back to the sender with an axiowl_send_message MCP call.
When the sender is resolved, the final visible body starts with a "Message from …" line, includes the original body, and appends a reply instruction containing the sender name, run ID when present, and receipt message ID when present. This makes replies operationally simple for receiving agents: they do not need to guess where the answer belongs.
The same code also records body policy details, including whether activation state caused a license warning to be appended. That policy is logged during delivery handoff, so the operator can inspect what kind of message body was actually sent.
Provider Edges
Provider dispatch happens through provider_edges.cpp. The provider field from the registry row is normalized and mapped to a provider-specific implementation.
Current provider edge names in the dispatch table include:
codexcodex_clivscode_nativevscode_copilot_backedantigravityantigravity_clicursorcursor_cliclaude_code_clicopilot_cliopencode_cli
The provider support matrix is more conservative than the dispatch list. It marks several surfaces as supported, including Codex agents, Codex CLI, VS Code native agents, VS Code Copilot-backed chat, Cursor agents, and Antigravity agents. It marks some CLI surfaces as targets rather than fully supported because current support requires provider-owned metadata and response-backed proof. That is an important difference: having code paths is not the same thing as meeting the support bar.
Delivery Worker Handoff
AxiOwl uses a delivery worker layer for provider delivery. The message pipeline writes a provider request and starts a delivery worker in the background. The worker parses the request, logs stages, calls deliver_to_provider, prints a structured result, and records whether the provider write succeeded, failed, or was accepted only in an unverified way.
This is why a send can return quickly while provider delivery continues. It also gives AxiOwl a cleaner evidence trail. The delivery logs include stages such as request acceptance, target resolution, route resolution, delivery worker handoff, provider write start, provider write success, provider handoff started unverified, or provider write failure.
For operators, those stages are the difference between "AxiOwl could not find the target," "AxiOwl handed the request to the provider edge," and "the provider edge reported a result."
Remote Routing Is Explicit, Not A Fallback
The source tree includes relay-session --stdio handling and remote_relay.cpp, which can receive JSON deliver frames and pass them through direct provider delivery or the normal message pipeline. The Windows desktop README also documents remote node setup commands such as registering a node and registering a remote agent.
At the same time, the current provider support matrix and remote provider page mark remote as unsupported for local-provider remediation builds. The code in provider_edges.cpp returns an out-of-scope result for remote delivery in that build context.
That means remote routing should be understood as an explicit node contract area, not a silent fallback. AxiOwl should not hide a failed local provider send by quietly routing somewhere else. If remote delivery is enabled in a future or selected configuration, it needs its own target record, node identity, relay contract, and validation path.
What This Gives Operators
AxiOwl's routing model gives operators and developers a few practical advantages:
- Named targets are resolved through a registry instead of ad hoc prompt text.
- Sender identity is treated as a routing requirement, not a decoration.
- Discovery can repair missing target rows once, but it does not pretend to prove delivery.
- Provider-specific behavior is isolated behind provider edges.
- Receipts, delivery results, and MCP replies mean different things and can be debugged separately.
- Logs can show whether a failure happened at validation, target resolution, route selection, worker handoff, provider write, or reply.
That separation is especially useful when multiple AI coding tools are open at the same time. A Codex thread, a VS Code native chat, a Copilot-backed VS Code session, a Cursor agent, and an Antigravity session do not share one native message API. AxiOwl's job is to normalize the operator-facing route while preserving the provider-specific delivery path underneath.
The Practical Mental Model
The easiest way to understand AxiOwl routing is to think of it as a local message coordinator with a strict registry and provider adapters.
The sender says, "send this body to that named agent." AxiOwl asks, "do I know who you are, do I know that target, is it sendable, and which provider owns it?" Only after those checks does it build the final visible body and hand the request to the provider edge.
That is the core of AxiOwl message routing: simple commands on the surface, explicit identity and registry rules underneath, and evidence boundaries that make delivery behavior inspectable when something goes wrong.