The AxiOwl Messaging Model

AxiOwl's messaging model is deliberately small: one sender, one target, one body, one selected provider edge, and one honest receipt. That constraint matters because AxiOwl is not just moving text between two identical chat windows. It is coordinating messages across provider sessions, local and remote nodes, MCP tools, CLI commands, registry rows, and provider-specific delivery code.

The model is built to keep that complexity at the edge. The middle of AxiOwl has a fixed job: accept a request, resolve who sent it, resolve where it should go, build the visible body once, dispatch it through the right provider edge, and record evidence. Provider-specific behavior belongs in provider modules, not in the message contract.

One Message Shape

The planning document for the simple AxiOwl architecture states the core principle plainly: AxiOwl sends one text message from one named agent to one named agent through one selected provider edge, then records what happened. The intended message shape is compact: message id, sender, target, body, and creation time.

The current C++ model follows that same direction. MessageRequest carries fields such as target_name, body, run_id, strict, requested_delivery_method, source_context, explicit_sender_agent, explicit_sender_node, and relay-specific fields for already-final-visible bodies. SendReceipt carries the result boundary: message_id, state, target_agent, provider, detail, error, accepted_by_axiowl, and accepted_by_provider.

That split is important. A message request is not a provider-specific object. The body starts as the sender's content. A receipt is not a chat reply. It is a statement about how far AxiOwl carried the request.

The Public Send Surface

The Windows CLI exposes the main send command in two forms:

axiowl send --to <agent> --body <message> [--from <agent>] [--from-node <node>] [--strict] [--run-id <uuid>] [--delivery-method <cursor-method|A|B|C|D|E>]
axiowl send --to <agent> --stdin [--from <agent>] [--from-node <node>] [--strict] [--run-id <uuid>] [--delivery-method <cursor-method|A|B|C|D|E>]

The --stdin path exists for the practical cases that matter in agent work: multiline instructions, code blocks, JSON, lists, and text that should not be damaged by shell quoting. The CLI also exposes registry and node commands, including list agents, registry add-agent, and node add, because AxiOwl cannot route a message without a known target.

For MCP clients, the native MCP server exposes axiowl_send_message. Its tool description is explicit that success is an MCP-to-AxiOwl handoff receipt only. Provider delivery and provider reply are not implied by the tool call response.

Sender Identity Is Not Optional

AxiOwl must know who is sending before it can safely attach reply instructions. The developer docs define the sender identity order: provider-owned MCP metadata first, then explicit provider session id, then explicit sender address or alias, then targeted discovery repair.

The MCP server reflects that design. It reads host and provider context, normalizes provider identities, inspects metadata, and maps provider session details back to registered agents where possible. Its initialization instructions tell clients to use the typed AxiOwl tools and to let AxiOwl resolve the host MCP session ID into a visible sender name. It specifically avoids asking the chat to invent its own session id.

That rule prevents a common failure mode in agent-to-agent routing: sending a helpful-looking reply command to a guessed name that is not a real reachable session. If the sender cannot be resolved, the pipeline rejects ordinary CLI sends that require sender identity, or, for already-final-visible relay bodies, rejects the relay when the body claims a final sender but lacks a resolved identity.

The Registry Is a Routing Table

The registry is durable local state. It maps human-facing names and aliases to provider-owned session identifiers and node identities. The current model includes fields such as display_name, aliases, provider, provider_session_id, node_id, enabled, sendable, source, last_seen_at, last_verified_at, and last_error.

That design keeps responsibilities clear:

The registry is not supposed to invent provider facts. Discovery can add sessions, refresh state, enrich manual rows, and repair one missing target during send. It should not silently turn stale display names into trusted delivery routes.

The Fixed Send Pipeline

The current MessagePipeline::send implementation follows the fixed model:

  1. Create a message id and delivery run id.
  2. Record that the MCP or CLI request entered the pipeline.
  3. Validate that the target and body are present.
  4. Resolve the sender from registry or explicit identity, or from relayed final-visible metadata.
  5. Attempt targeted discovery repair for a missing or stale target.
  6. Reject known-but-not-sendable targets loudly.
  7. Mark the request accepted by AxiOwl after target resolution.
  8. Build the final visible body unless the body was already final-visible.
  9. Create a ProviderRequest.
  10. Hand the provider request to the delivery worker.
  11. Log evidence and delivery stages.

That receipt boundary is one of the most practical parts of the model. The CLI prints an "AxiOwl handoff receipt" when AxiOwl accepts the request. If provider status is not already known, the receipt says so directly: provider delivery, provider wake-up, and provider reply are not implied.

The Final Visible Body

AxiOwl builds the visible provider body once, after sender resolution. In the current builder, a resolved sender produces a body headed with Message from <sender agent>, followed by the original body and an MCP reply instruction block. The reply instruction points back to mcp__axiowl.axiowl_send_message with the resolved sender as the target, and can include run and receipt correlation fields.

This is a routing feature, not decorative text. It gives the receiving agent a concrete way to send content back through AxiOwl while preserving the sender identity chain. It also prevents each provider adapter from inventing its own reply format.

Provider Edges Do Provider Work

Once the pipeline has a target row and final visible body, provider selection becomes mechanical. provider_edges.cpp dispatches by normalized provider id to provider-specific modules, including provider families such as Codex, Codex CLI, VS Code native, VS Code Copilot-backed, Antigravity, Antigravity CLI, Cursor, Cursor CLI, Claude Code CLI, Copilot CLI, OpenCode CLI, and remote handling.

The provider edge receives a ProviderRequest with the message id, run id, target registry row, sender identity, final visible body, delivery method, and strictness. The provider result reports whether that edge accepted, failed, degraded, or produced evidence about the attempt.

This keeps the center of AxiOwl stable even when provider integrations differ sharply. A Codex CLI send can resume a provider thread with stdin. A VS Code bridge may use extension behavior. A remote provider may require relay logic. Those differences should not change the message shape.

Receipts Are Honest By Design

AxiOwl separates three concepts that are often blurred in agent tooling:

The architecture docs call the response over MCP the strongest proof because it demonstrates the return path, not just outbound delivery. A send receipt alone must not be treated as a recipient reply.

Current Implementation Status

The Windows desktop README describes the current implementation status clearly. The CLI skeleton, fixed send pipeline, create-session pipeline, TSV registry, final visible body builder, JSONL evidence log, provider edge interface, and live provider delivery for current local Windows edges are implemented. The always-running local service is not implemented yet; the reserved endpoint is 127.0.0.1:37661.

That means current CLI behavior runs the local pipeline directly, and the delivery worker provides background handoff for provider work. On the Linux side, axiowl-linux exposes CLI provider tools such as codex-cli, opencode-cli, and antigravity-cli commands for detection, MCP install, discovery, create, rename, send, and MCP self-test. The Linux remote app is documented as supporting Codex CLI delivery only, not GUI or relay chaining.

Why This Model Helps Operators

The practical value is predictability. When a message fails, the operator can look at the exact boundary: target missing, sender unresolved, target known but not sendable, delivery worker handoff failed, provider write failed, or provider accepted without an end-to-end reply yet.

The model also makes multi-agent operations safer. AxiOwl does not need every provider to behave the same way. It needs every provider edge to accept the same resolved request and report evidence honestly. That makes it easier to add integrations without turning the central pipeline into a pile of provider-specific exceptions.

For developers, the message model is a guardrail. Registry code owns durable routing facts. Discovery owns session discovery and repair. The message pipeline owns validation and final body construction. Provider modules own provider-specific delivery. The delivery worker owns asynchronous dispatch and provider evidence logging. The MCP server owns typed tool exposure and sender metadata handling.

Closing

The AxiOwl messaging model is intentionally boring in the middle. That is the point. A message should not become a different object just because it crosses from CLI to MCP, from local registry to remote node, or from one provider family to another.

AxiOwl's current implementation turns that principle into concrete behavior: a fixed send pipeline, durable registry rows, resolved sender identity, one final visible body, provider-edge dispatch, delivery evidence, and receipts that say exactly what they prove. That gives operators and agents a shared contract for sending work across provider sessions without pretending that a handoff is the same thing as a reply.