How to Send Messages Between Named Agents

AxiOwl's core job is deliberately small: send one text message from one named agent to one named agent, route it through the correct provider edge, and record what happened. Instead of making a user remember provider-specific session identifiers, the operator addresses a human-readable agent name and lets AxiOwl resolve that name through its local registry.

That design shows up in both the user-facing command surface and the C++ implementation. The CLI accepts a target name with --to, a message body with --body or --stdin, and then hands the request to MessagePipeline. The pipeline resolves the sender, resolves the target, builds the visible message body, selects the provider edge from the registry row, logs receipt boundaries, and starts provider delivery.

The Basic CLI Send

For a short message, the common command form is:

axiowl send --to "Target chat name" --body "Message text"

For anything multiline, quoted, structured, or easy to damage with shell escaping, use stdin:

@'
Please review the current branch and report the first blocking issue.

Return only actionable findings.
'@ | axiowl send --to "Target chat name" --stdin

The current CLI handler reads --to or --target, reads --body, and replaces the body with all stdin content when --stdin is present. It then creates a MessagePipeline with the local registry and evidence log and calls pipeline.send(request).

That matters because AxiOwl is not just printing text into a chat window. A send goes through the registry-backed pipeline.

Why Named Agents Work

AxiOwl's registry stores provider sessions as agent records. The implemented model includes fields such as:

The useful mental model is:

agent name -> provider -> provider session id -> node

The name is for humans. The provider session id is for the provider adapter. When you run axiowl send --to "Target chat name", AxiOwl looks for a matching registry row. The registry resolution code prefers exact provider-session matches first, then name matches, and prefers sendable rows over merely enabled rows.

If you are adding a known target manually, the documented command shape is:

axiowl registry add-agent --name "Test Agent" --provider codex --session "<provider-session-id>"

For a remote-style registry entry, the Windows desktop README shows:

axiowl registry add-node --id "front" --host "<host>" --user "<ssh-user>" --key "<ssh-key-path>"
axiowl registry add-agent --name "Remote Test" --provider remote --node "front" --session "<remote agent name>"
axiowl send --to "Remote Test" --body "hello"

The current provider dispatch code treats the remote delivery edge as out of scope for the local-provider remediation build, so remote registry commands should be understood as part of the evolving remote contract, not as a blanket promise that every remote path is live in every build.

Sender Identity Is Not Optional

A named target is only half the route. AxiOwl also needs to know the sender.

For raw CLI sends, the current pipeline requires an explicit sender identity. The send usage includes:

axiowl send --to <agent> --body <message> [--from <agent>] [--from-node <node>] [--strict]
axiowl send --to <agent> --stdin [--from <agent>] [--from-node <node>] [--strict]

If the sender cannot be resolved, the pipeline rejects the send with a clear error such as send requires explicit --from sender identity. If the sender value looks like a provider session id but does not resolve to a registered sender, AxiOwl can run targeted discovery repair, then tries sender resolution again. If it still cannot resolve the sender, it fails before provider dispatch.

That rule exists for practical routing. AxiOwl appends reply instructions to the visible message body. Those reply instructions need a real return target, not a guessed display name or a stale session id.

MCP Sends Are Preferred From Provider Sessions

When the sender is an AI provider session, the preferred path is the AxiOwl MCP tool rather than a hand-built shell command. The bundled Codex skill says to use axiowl_send_message, and the native MCP server exposes that tool with a concrete receipt boundary: success means the MCP-to-AxiOwl handoff happened, not that the target replied.

The MCP tool takes a simple shape:

{
  "to": "Target chat name",
  "body": "Message text"
}

Inside mcp_server.cpp, axiowl_send_message resolves host metadata, registers the sender when possible, then invokes the same CLI send path with --to, --from, --from-node, and --stdin. That is why MCP is better for provider replies: the host MCP session id becomes the stable sender identity key, and AxiOwl can resolve that to the visible registered sender name.

Provider sessions should not invent their own session ids, manually add --from, or construct low-level relay arguments. The tool receives the host metadata that AxiOwl needs.

What The Recipient Actually Sees

AxiOwl does not pass the raw body straight to every provider. The pipeline builds one final visible body before provider delivery. When the sender is resolved, the body starts with the sender name, includes the original message, and appends an MCP reply instruction addressed back to the sender.

The current final-body builder uses this shape conceptually:

Message from <sender agent>

<original body>

If requested to, respond with this exact MCP tool call:
mcp__axiowl.axiowl_send_message({
  "to": "<sender agent>",
  "body": "<full reply>"
})

If the sender is unresolved, the builder uses a loud warning and does not attach a usable send-back command. That behavior is intentional: AxiOwl should fail or warn loudly rather than creating a false return route.

In unactivated builds, the final body builder also appends the current activation warning text from the implementation. Operators should expect that warning in visible provider messages until activation state reports as activated.

What A Send Receipt Means

The most important operational detail is the receipt boundary.

When the CLI returns success, it prints an AxiOwl handoff receipt. In the common accepted path, the CLI explicitly says that provider delivery, provider wake-up, and provider reply are not implied. The pipeline sets accepted_by_axiowl after the target is resolved and a route is selected, then starts delivery through the delivery worker.

A stronger provider result can appear when a path reports it explicitly, but a send receipt is still not the same as a recipient response.

The implemented receipt concepts include:

The strongest proof is a separate reply through AxiOwl MCP with correct sender identity. A reply is a new message, not hidden data inside the original send receipt.

Provider Edges

After target resolution, provider dispatch is based on the registry row's provider field. The current Windows provider edge table includes delivery functions 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.

Unsupported or unknown providers fail loudly. The dispatch table has an explicit unknown-provider result, and the current remote delivery branch returns an out-of-scope result for this build instead of silently pretending remote delivery worked.

That is the right expectation to carry into operations: named-agent messaging depends on a sendable registry row and a provider edge that can actually deliver to that row.

Practical Workflow

Use this sequence when sending between named agents:

  1. List available targets.
axiowl list agents
  1. Pick the exact registered target name. If a provider has multiple surfaces or rows, use the full display name from the registry rather than a guessed shorthand.

  2. Send short text with --body.

axiowl send --to "Target chat name" --from "Sender agent name" --body "Please check the latest failing step."
  1. Send longer or structured text with --stdin.
@'
Context:
- The installer completed.
- The MCP tool is visible.
- The provider reply has not arrived.

Task:
Check whether this target can receive and reply through AxiOwl MCP.
'@ | axiowl send --to "Target chat name" --from "Sender agent name" --stdin
  1. When sending from inside Codex or another provider session with AxiOwl MCP installed, use axiowl_send_message instead of manually composing a CLI command. That preserves sender identity better.

  2. Treat the send result as a handoff receipt. Look for an actual MCP reply or evidence log entry before claiming end-to-end success.

Why This Is Useful

Named-agent messaging gives operators a stable way to coordinate provider sessions without memorizing provider-specific ids. The local registry owns the mapping, the pipeline owns sender and target resolution, and provider adapters own the messy provider-specific delivery work.

The result is a small, inspectable contract: one sender, one target, one body, one provider edge, and one receipt. When the registry is accurate and the provider edge is supported, the operator can send to a named agent directly. When something is missing, AxiOwl is designed to fail loudly enough that the next repair step is visible.

That is the practical value of AxiOwl's named-agent send path: it turns cross-provider coordination into an addressable operation while keeping the proof boundary honest.