
How to Send Your First Message Through AxiOwl
Sending a first AxiOwl message is not just a chat command. In the current C++ implementation, a send goes through a small delivery pipeline: AxiOwl reads the target name, loads the local agent registry, resolves the target to a provider session, builds the visible message body, sends it through the provider-specific edge, and records delivery evidence.
That is the important mental model. You are not typing directly into another agent's window. You are asking AxiOwl to deliver a message to a named, sendable target that it knows how to reach.
Start by confirming AxiOwl can see agents
The practical first check is:
axiowl list agents
The list agents command reads AxiOwl's registry and prints only agents that are both enabled and sendable. Each line includes the display name, provider, and node:
Some Agent Name | provider=codex_cli | node=local
If the registry is empty, AxiOwl prints that no agents are registered and shows the registry path. In the implementation, that registry is a TSV file under the AxiOwl state root:
<state-root>/registry/agents.tsv
On Windows, the state root is under %LOCALAPPDATA%\AxiOwl. On Linux, AxiOwl uses $XDG_STATE_HOME/axiowl when set, otherwise ~/.axiowl.
Discover or add a target before sending
AxiOwl can only send to an agent after the target exists in the registry. The general command shape for discovery is:
axiowl discover <provider-or-scope>
The current CLI usage includes local and remote discovery scopes such as:
axiowl discover codex
axiowl discover codex_cli
axiowl discover opencode_cli
axiowl discover antigravity_cli
axiowl discover antigravity
axiowl discover remote --node <node-id>
axiowl discover all
The implementation merges discovered rows into the registry. A registry row stores fields including agent_id, display_name, aliases, provider, provider session ID, node ID, whether the row is enabled, whether it is sendable, source, timestamps, and the last error.
You can also add a known target manually:
axiowl registry add-agent --name "Build Helper" --provider codex_cli --session <provider-session-id>
Manual rows should be used carefully because the provider session ID has to mean something to the provider edge. For example, the Codex CLI edge expects a Codex thread ID, OpenCode expects an OpenCode session ID, and Antigravity CLI expects an agy conversation ID.
Send the first message with --body
Once the target appears in axiowl list agents, send a short message:
axiowl send --to "Build Helper" --body "Can you check whether the current branch builds?"
The --to value is the human-facing target name or alias known to the registry. AxiOwl's lookup is forgiving: it first tries an exact normalized match against the display name and aliases, then tries a token-based loose match. It still prefers sendable rows and will not invent a target if the registry and targeted discovery cannot find one.
If delivery works, the CLI prints a receipt:
Message accepted by AxiOwl.
Message ID: <id>
Delivery state: accepted_by_provider
Provider: <provider>
That output means two things happened. First, AxiOwl accepted the message into its own pipeline. Second, the provider edge reported that it accepted the delivery.
If AxiOwl accepts the message but provider delivery fails, the CLI prints the message ID, delivery state, provider, and reason. If AxiOwl rejects the message before provider delivery, it prints Message not accepted with the rejection reason.
Use --stdin for anything longer than one line
For a first smoke test, --body is fine. For real handoffs, use stdin so shell quoting does not damage the message:
cat <<'EOF' | axiowl send --to "Build Helper" --stdin
Please inspect the failing test output below.
Expected:
- identify the failing test
- explain the most likely code path
- do not change files yet
EOF
The CLI has separate usage paths for:
axiowl send --to <agent> --body <message>
axiowl send --to <agent> --stdin
Internally, --stdin reads the full standard input stream and uses that as the message body. If the final body is empty, AxiOwl rejects the send with message body is empty.
Let AxiOwl handle sender identity
The current send command intentionally rejects explicit sender flags:
axiowl send --to "Build Helper" --body "hello" --from "Someone"
That form is not supported. The CLI returns an error saying --from and --from-node are not supported because sender identity must come from the sending chat context or MCP metadata.
This matters because AxiOwl is designed to preserve the real route of a message. When sender identity is resolved, the body builder wraps the visible message as:
Message from <sender>:
<original body>
It also includes instructions for sending AxiOwl content back through the axiowl_send_message MCP tool when a reply is explicitly needed. If the sender cannot be resolved, AxiOwl uses an unresolved-sender version and does not attach a send-back command.
For normal operator usage, the rule is simple: name the target, provide the body, and let AxiOwl derive the sender.
What AxiOwl does after you press Enter
The C++ pipeline is deliberately explicit:
- It creates a new message ID.
- It rejects missing targets and empty bodies.
- It resolves sender identity unless the body is already marked as final visible text.
- It looks up the target in the registry.
- If the target is missing, it logs a registry miss and runs one targeted discovery attempt.
- It rejects targets that are known but not sendable.
- It builds the final visible body.
- It dispatches to the provider edge.
- It appends evidence to the events log.
The evidence log path is:
<state-root>/logs/events.jsonl
That log is useful when a send is not behaving the way you expect. The pipeline records events such as message_accepted_by_axiowl, provider_delivery_result, registry misses, MCP tool calls, and sender mapping attempts.
Provider delivery is specific, not generic
AxiOwl's provider edge is selected from the target registry row. The implementation contains different delivery paths for different providers.
For Codex CLI targets, AxiOwl resumes an existing Codex thread with:
codex exec resume ...
For OpenCode CLI targets, it runs OpenCode against the stored session ID. For Antigravity CLI targets, it uses agy --conversation. For Antigravity language-server targets, it can use the agentapi send-message path. For remote targets on Windows, it uses an SSH relay session. Unknown providers fail loudly with an unknown_provider method and an error explaining that the registry provider did not match any AxiOwl provider edge.
This is why the registry matters. A visible name alone is not enough; AxiOwl also needs the provider, session identifier, node, and sendability state.
Sending from MCP-enabled agents
The same delivery idea is exposed through AxiOwl's MCP server. The MCP tool list includes:
axiowl_send_message
axiowl_list_agents
axiowl_discover
axiowl_create_session
The axiowl_send_message tool requires:
{
"to": "target agent name",
"body": "message text"
}
When an MCP call arrives, AxiOwl records sender metadata, tries to map the sender back to a registered agent, builds a message request, and sends through the same message pipeline. The MCP response includes JSON with fields such as ok, message_id, state, provider, target, whether the sender was mapped, and any error.
That makes the CLI and MCP paths consistent: both end up using the same registry, same provider edges, and same evidence log.
A practical first-message checklist
Use this short sequence for the first real message:
axiowl status
axiowl discover all
axiowl list agents
axiowl send --to "<agent name from list agents>" --body "Hello from AxiOwl. Please acknowledge receipt."
Then check the receipt. A clean first send should show a message ID, a provider, and a delivery state indicating provider acceptance.
If it does not, start with the exact rejection:
target is required: the command did not include a usable--to.message body is empty: the body or stdin input was blank.target is not in registry after targeted discovery: discovery did not find a matching sendable agent.target is known but not sendable: the registry row exists, but AxiOwl should not send to it.- Provider delivery failed: AxiOwl accepted the message, but the downstream provider command or bridge failed.
Closing
The first AxiOwl message is a small but complete proof of the system. It proves the registry can resolve a human target name, the sender context is handled by AxiOwl instead of being spoofed by the caller, the provider edge can accept delivery, and the result is written down with a message ID and evidence.
Start with list agents, send one short --body message, switch to --stdin for real handoffs, and use the receipt plus events.jsonl when you need to debug what actually happened.