How to Troubleshoot AxiOwl Message Delivery

Troubleshooting AxiOwl message delivery starts with one discipline: separate the stages. An install can succeed while discovery is stale. A registry row can exist while the target is not sendable. A command can return accepted_by_axiowl while provider delivery, provider wake-up, and a recipient reply are still unproven.

That distinction is intentional in the current AxiOwl implementation. AxiOwl is a local coordinator and message router. It accepts a request, resolves the sender and target, builds the final visible body, selects one provider edge, hands work to the delivery worker, records evidence, and prints an honest receipt. The fastest way to debug a failed send is to follow that exact pipeline instead of guessing from the final symptom.

Start With the Receipt Boundary

The public send command is:

axiowl send --to "<agent>" --body "<message>" --from "<sender>"

For multiline text, JSON, code, lists, quotes, or anything that shell quoting could damage, use stdin:

@'
<full message>
'@ | axiowl send --to "<agent>" --from "<sender>" --stdin

The CLI prints a handoff receipt, not a magical end-to-end truth claim. In the implementation, run_send calls the message pipeline and then branches on the receipt. If AxiOwl accepted the request but provider delivery has not been explicitly reported by that path, the output says:

AxiOwl handoff receipt: MCP/CLI request accepted by AxiOwl.
Receipt boundary: provider delivery, provider wake-up, and provider reply are not implied.

That line is a troubleshooting tool. It tells you where to look next. The local coordinator accepted the request and selected a route, but you still need delivery logs, provider evidence, or a response-backed test to prove the provider actually handled it.

If the output says:

Message not accepted: <reason>

the failure happened before AxiOwl accepted the message into the pipeline. Start with the target, body, sender identity, and registry. If it says the request was accepted but provider delivery failed loudly, start with the delivery worker and provider edge evidence.

Confirm the State Root and Logs

Run:

axiowl status

The current Windows coordinator reports the version, state root, registry path, node registry path, evidence log, delivery log, create lifecycle log, installed executable metadata, activation state, local service endpoint, runtime role, registered agent count, and registered node count.

The important paths are:

%LOCALAPPDATA%\AxiOwl\registry\agents.tsv
%LOCALAPPDATA%\AxiOwl\registry\nodes.tsv
%LOCALAPPDATA%\AxiOwl\logs\events.jsonl
%LOCALAPPDATA%\AxiOwl\logs\delivery.jsonl
%LOCALAPPDATA%\AxiOwl\runtime

On Linux-style state roots, AxiOwl uses $XDG_STATE_HOME/axiowl when set, otherwise ~/.axiowl. The subpaths are the same idea: registry files under registry, logs under logs, runtime files under runtime.

Do not troubleshoot from memory. The status output tells you which installed executable and which state directory the current CLI is actually using. That matters when an older build, stale installer artifact, or different user profile is involved.

Check Whether the Target Is Sendable

List the registered sendable agents:

axiowl list agents

The command prints enabled and sendable rows in this shape:

Some Agent | provider=codex | node=local

If no agents are registered, the command reports that and prints the registry path. That means AxiOwl may be installed correctly, but it has no usable target row. If the intended target is missing from this list, run provider discovery before testing delivery:

axiowl discover all

Or scope discovery to the provider you care about:

axiowl discover codex
axiowl discover vscode-native
axiowl discover vscode-copilot
axiowl discover antigravity
axiowl discover cursor

The send pipeline also performs one targeted discovery attempt when a target is missing or needs repair. That is useful, but it is not a substitute for inspecting the registry. A target can be known but not sendable, stale, associated with the wrong node, or holding a last error from a provider-specific discovery path.

The registry stores more than a display name. The implementation persists agent id, display name, aliases, provider, provider session id, node id, enabled state, sendable state, source, first seen time, last seen time, last verified time, and last error. When delivery fails at target resolution, inspect those fields in agents.tsv or refresh discovery and compare what changed.

Verify the Sender, Not Just the Target

AxiOwl builds a final visible message body that includes sender identity and reply instructions. For normal sends, the pipeline requires a resolved sender. If the sender is missing or only looks like an unresolved provider session id, the send can be rejected before provider dispatch.

That is why a good manual send includes --from:

axiowl send --to "Target Agent" --from "Sender Agent" --body "Can you confirm this path?"

The registry resolution rules are careful. A sender can resolve by registered display name, alias, or provider session id. But if the matched display name is itself just a session identifier, AxiOwl treats that as a problem because the recipient would see an unhelpful or unsafe sender label.

Common sender-side failures include:

If you see one of those, run discovery for the sender's provider, check whether the sender appears in axiowl list agents, and confirm that the row has a real display name rather than a raw UUID-like session id.

Read delivery.jsonl by Message ID

Every send gets a message id. Use that id as the spine of the investigation.

The message pipeline writes delivery-stage records to:

%LOCALAPPDATA%\AxiOwl\logs\delivery.jsonl

The stages are designed to show where the send stopped. The pipeline records when the request entered AxiOwl, when target resolution succeeds or fails, when a route is selected, and whether delivery-worker handoff started or failed. The delivery worker adds its own stages for provider dispatch, provider write success, unverified handoff, or provider write failure.

A healthy accepted handoff can include stages like:

accepted
target_resolved
route_resolved
delivery_worker_handoff_started
provider_write_started
provider_write_succeeded

A failed send may stop earlier:

accepted
target_resolved: error

or:

route_resolved: error

or:

provider_write_failed

That stage tells you which layer owns the next question. A target_resolved error is usually registry or discovery. A route_resolved error may be a known target that is not sendable. A delivery_worker_handoff_failed points at request-file creation, executable resolution, or worker startup. A provider_write_failed points at the provider adapter or selected provider surface.

Read events.jsonl for Evidence

The broader event log is:

%LOCALAPPDATA%\AxiOwl\logs\events.jsonl

The implementation appends JSONL records with event_type, created_at, and event-specific fields. During delivery troubleshooting, useful event types include:

The event log carries details that the command output intentionally does not overstate: provider, target, provider session id, node id, requested delivery method, body policy, activation status, worker evidence, and exact error text.

When you have a message id, search both logs for it. The delivery log gives the sequence. The evidence log gives the context.

Understand Delivery Worker Handoff

AxiOwl does not write directly to every provider from the top-level CLI call. The current implementation builds a ProviderRequest, writes it to a temporary JSON request file, and starts an internal delivery worker:

axiowl delivery-worker --request <request-json-file>

The worker parses the request, validates fields, dispatches to the provider edge, prints a JSON result, appends evidence, writes delivery-stage records, and removes the request file after provider dispatch.

That split is useful because it makes failures clearer. If the handoff fails, the provider may never have been called. If handoff starts but the provider result is failed, the provider edge ran and returned a failure. If the provider result is accepted but marked degraded or unverified, AxiOwl is telling you that the provider path did something useful but did not prove the full intended property.

For direct worker diagnosis, the CLI exposes:

axiowl delivery-worker --request <request-json-file> --validate-only

Most operators will not need to run that by hand, but the command surface matters: delivery is an inspectable stage, not an invisible side effect.

Match the Provider Edge

Provider routing is explicit. The provider edge dispatcher currently recognizes provider values such as:

codex
codex_cli
vscode_native
vscode_copilot_backed
antigravity
antigravity_cli
cursor
cursor_cli
claude_code_cli
copilot_cli
opencode_cli
remote

If the registry row contains an unknown provider, the provider edge returns a failure with evidence that the registry target provider did not match any AxiOwl provider edge. If the provider is remote in the local-provider remediation build, delivery is explicitly out of scope rather than silently disguised as local delivery.

That loud failure behavior is part of AxiOwl's design. The architecture docs ban silent fallbacks and provider-family guessing. If AxiOwl cannot prove a route, it should say so. If a fallback path is ever used, it has to be visible and marked degraded.

Distinguish Install, MCP, Send, and Reply

The support docs define a simple forensic rule: do not treat an earlier event as proof of a later event.

These are separate facts:

MSI install succeeded
accepted_by_axiowl
provider accepted
MCP reply received

An MSI install means selected installer actions completed. It does not prove a provider can receive messages. accepted_by_axiowl means the local coordinator accepted and handed off the request. It does not prove the provider woke up. A provider-accepted result means the provider edge reported acceptance. It does not mean the recipient replied. A reply is a new independent message.

This is why a response-backed smoke test has more value than a send receipt alone. The CLI includes:

axiowl provider smoke-test --all-local --wait-seconds 120 --report

The current smoke provider list includes local provider surfaces such as Codex, VS Code native, VS Code Copilot-backed, Antigravity, Cursor, Claude Code CLI, Copilot CLI, and OpenCode CLI variants. The smoke test sends a contract phrase and waits for an exact reply where provider/session evidence can be checked. That is closer to end-to-end proof than a handoff receipt.

Check Local Inventory

For a quick provider inventory pass, run:

axiowl doctor inventory

The implementation reports the registry path and delivery log path, then checks each local smoke provider for rows and local sendable rows. It marks a provider as failed when there is no local sendable target. Remote rows are counted separately as excluded from the local inventory check.

This command is useful when "send failed" might really mean "there is no sendable local target for this provider." It is also useful after install or discovery changes because it gives a compact row-count view before you run more expensive provider tests.

Diagnose Provider-Specific Symptoms

Once the registry, sender, and delivery worker are ruled out, move to provider-specific checks.

For missing MCP tools, confirm the provider session was restarted after install, the MCP config exists in the provider's expected location, the configured axiowl.exe path exists, the provider can start axiowl mcp-server, and the MCP server receives provider metadata.

For bad discovery, inspect registry rows, provider session ids, display names, aliases, sendable state, source, timestamps, and last_error. Common patterns include stale old paths, provider workspace folders that no longer exist, reused old session names, changed provider session formats, or discovery skipped because the provider was not selected during install.

For Cursor delivery, the support docs call out the failure text:

Cursor Glass submit patch is not installed or not visible to the bridge.

That means the bridge ran, but the patched command required for the intended submit path was unavailable.

For VS Code delivery, check whether the selected feature was installed, old bridge extension folders were removed, the bridge extension is under the current AxiOwl id, the MCP server definition is visible, the native session id maps to the intended target, and bridge ownership selected the right window.

If a provider reports an old working directory or stale folder in a new chat, do not immediately assume AxiOwl delivery failed. The support docs explicitly call this out: it can be provider state reuse, stale MCP config, stale registry data, inherited provider defaults, or old provider session metadata.

Use Run IDs for Reproducible Incidents

For repeated tests, pass a run id:

axiowl send --to "Target Agent" --from "Sender Agent" --run-id "delivery-test-2026-07-08-001" --body "Please confirm receipt."

The pipeline records the run id in delivery-stage and evidence records. That makes it easier to group multiple attempts, compare target discovery behavior, and distinguish your current test from background traffic.

If you are writing a formal incident note, collect:

%LOCALAPPDATA%\AxiOwl\logs
%LOCALAPPDATA%\AxiOwl\registry
%LOCALAPPDATA%\AxiOwl\runtime

Also collect the MSI verbose log when install behavior is in question, provider bridge output channels when VS Code or Cursor is involved, provider CLI stdout/stderr for CLI providers, and provider session files when safe to share.

A Practical Troubleshooting Ladder

Use this order when a message does not arrive:

  1. Run axiowl status and confirm the state root, executable metadata, registry path, and log paths.
  2. Run axiowl list agents and confirm the target is enabled, sendable, on the expected node, and using the expected provider.
  3. Include --from on manual sends and confirm the sender resolves to a useful display name.
  4. Run provider discovery if the target is missing or stale.
  5. Send a small test with --run-id and save the message id.
  6. Search delivery.jsonl by message id and identify the last stage.
  7. Search events.jsonl by message id and read the exact evidence and error text.
  8. If handoff succeeded, inspect the delivery-worker result and provider edge evidence.
  9. If the provider accepted but no reply arrives, run a response-backed smoke test instead of relying on the handoff receipt.
  10. If the symptom points to VS Code, Cursor, Antigravity, Codex, or a CLI provider, switch to that provider's install, MCP, bridge, or patch checks.

The point is not to memorize every provider failure. The point is to keep the layers separate. AxiOwl's delivery model is intentionally small: one sender, one target, one body, one provider edge, one receipt. Troubleshooting works best when it follows the same shape.

Closing

AxiOwl message delivery is easiest to debug when receipts are treated as boundaries, not assumptions. accepted_by_axiowl tells you the coordinator accepted and handed off the request. The registry tells you what AxiOwl believes is addressable. delivery.jsonl tells you where the pipeline stopped. events.jsonl tells you why. Provider smoke tests tell you whether the full path can produce a real response.

That is the operational value of AxiOwl's design: when delivery fails, the system is supposed to leave a trail that names the failing stage instead of hiding it behind a silent fallback.