AxiOwl Failure Stages Explained

A failed AxiOwl message is not one vague event. It is a failure at a specific boundary: the request may be malformed, the sender may be unresolved, the target may be missing from the registry, the delivery worker may fail to start, the provider edge may reject the message, or the provider may accept a handoff without enough proof that the recipient actually saw it.

That distinction is central to AxiOwl's current design. The Windows desktop runtime is a local coordinator. It exposes CLI and MCP entry points, keeps a durable local registry, discovers provider sessions, builds the final visible message body, dispatches through provider-specific edges, and records evidence. Because each stage has a different meaning, AxiOwl tries not to collapse them into a single "sent" or "failed" label.

Why Failure Stages Matter

AxiOwl's source-of-truth support guide starts with a simple warning: do not treat an earlier event as proof of a later event. An MSI install succeeding does not prove that messages can be delivered. An accepted_by_axiowl receipt does not prove that a provider accepted the message. Provider acceptance does not prove that the target replied through MCP. A response over MCP is stronger evidence because the target provider received the message, acted on it, and returned through AxiOwl with provider-owned sender identity.

This is not just documentation language. The C++ implementation enforces the boundary. MessagePipeline::send returns an AxiOwl handoff receipt after validating the request, resolving sender and target, choosing a route, building the final visible body, and starting background delivery. The core test suite checks that this receipt reports accepted_by_axiowl, does not claim provider acceptance, logs delivery_receipt as axiowl_only, and records the receipt boundary as after_target_resolution_before_delivery_worker_or_provider.

In practical terms, AxiOwl is designed so an operator can ask: which stage failed?

Stage 1: Request Acceptance

The first stage is simply whether the request entered the pipeline in a usable shape. AxiOwl records a delivery-stage event named accepted when an MCP or CLI request enters MessagePipeline. That stage means AxiOwl saw a request; it does not mean the message is valid or deliverable.

The pipeline immediately rejects empty essentials. If the target name is blank, the receipt error is target is required. If the body is empty, the receipt error is message body is empty. These are early failures, before registry lookup and before provider delivery.

For a developer or operator, this stage is the place to check command construction. The CLI and MCP caller need to supply a target and a body. If either is missing, no provider was involved.

Stage 2: Sender Identity

AxiOwl must know who is sending. The architecture docs call this the sender identity rule: replies must route to a real provider session, not a guessed display name or stale path. For MCP calls, sender identity should come from provider metadata or a provider patch that supplies metadata programmatically.

The message pipeline resolves sender identity from the registry or from explicit sender information. It can run targeted discovery repair for some unresolved sender cases. If the sender still cannot be resolved, AxiOwl rejects the send. In current code, the normal error is shaped as send requires explicit --from sender identity: ...; for a final-visible relay body, the error is send requires resolved sender identity for final-visible relay body: ....

This failure is different from a provider failure. Nothing was delivered to the target. AxiOwl stopped because it could not attach a trustworthy return path.

Stage 3: Target Resolution

After the sender is known, AxiOwl resolves the target through the durable registry. A registry row represents a reachable provider session or agent and includes fields such as display_name, aliases, provider, provider_session_id, node_id, sendable, source, last_seen_at, last_verified_at, and last_error.

If the target is not found, or if the target row needs discovery repair, the pipeline performs one targeted discovery pass. That is an important design choice. Discovery can repair stale or missing registry state, but it is not allowed to become a silent guessing engine. If the target still cannot be resolved after that pass, the receipt explains that the target is not in the registry after targeted discovery. If discovery found only weak evidence, AxiOwl can report that target evidence was found but no sendable exact target row was discovered.

This is the stage to inspect %LOCALAPPDATA%\AxiOwl\registry, discovery logs, provider session IDs, aliases, sendable, and last_error. A provider may be installed and working, but AxiOwl still cannot send if it does not have a trustworthy row for the requested target.

Stage 4: Route And Sendability

Once a target row is found, AxiOwl records target_resolved and then checks whether the row is sendable. A known target can still be rejected with target is known but not sendable. If the row has a last_error, the error text is appended so the operator sees why the row is blocked.

This is where provider support status and registry truth meet. The provider support matrix distinguishes supported, target, experimental, unsupported, and removed surfaces. A provider is not supported merely because AxiOwl can write a config file or start a process. The support bar includes discovery, install behavior, named-session sending, provider receipt, MCP reply, and correct provider-owned sender identity.

The current provider dispatch table includes provider edges such as codex, codex_cli, vscode_native, vscode_copilot_backed, antigravity, cursor, CLI provider targets, and opencode_cli. Unknown provider values fail with an explicit unknown-provider result. The remote provider path is explicitly reported as out of scope for local-provider remediation builds, not used as a hidden fallback.

Stage 5: AxiOwl Receipt Boundary

If sender and target resolution succeed and the target is sendable, AxiOwl accepts the message locally. The receipt state becomes accepted_by_axiowl. The detail is axiowl_receipt_only.

This is a success at the AxiOwl handoff boundary, not at the provider boundary. The architecture docs say the same thing: an AxiOwl send receipt is not provider delivery proof. The current implementation logs that the receipt boundary is after target resolution and before the delivery worker or provider.

This is one of the most useful details when debugging. If the user has a message ID and the state is accepted_by_axiowl, the pipeline accepted the request. The next question is whether the delivery worker handoff started and what the provider edge later reported.

Stage 6: Delivery Worker Handoff

AxiOwl uses a delivery worker for background provider delivery. The message pipeline writes a provider request with the message ID, run ID, target, sender, final visible body, requested delivery method, and strict flag, then starts the worker detached.

If the handoff starts successfully, the message pipeline logs delivery_handoff_started and a delivery-stage record named delivery_worker_handoff_started. If it cannot start the worker process, the state becomes delivery_worker_handoff_failed, with evidence pointing at the request file and error output.

The delivery worker has its own validation boundary. It reads the request JSON file, verifies that the type is delivery_worker_request, reconstructs the provider request, and emits delivery_worker_request_parse_failed if the file is missing, malformed, or not a delivery-worker request. In validate-only mode, it can report delivery_worker_validation_accepted without dispatching a provider.

This stage separates "AxiOwl accepted the request" from "AxiOwl successfully started the background provider write."

Stage 7: Provider Write

When the worker dispatches, it records provider_write_started and calls deliver_to_provider. The provider edge returns a ProviderResult containing provider, state, accepted, degraded, method_used, evidence, error, and optional provider session fields.

If the provider edge accepts the message with strong enough proof, the worker records provider_write_succeeded. If it fails, the stage becomes provider_write_failed. If the edge can only prove that a handoff started, AxiOwl marks the result as unverified or degraded rather than pretending it has final delivery proof.

The VS Code native provider is a concrete example. It writes a bridge command file, triggers the AxiOwl VS Code bridge URI, and can wait for a bridge result file. If it cannot find an active bridge, the error is explicit: no active AxiOwl VS Code native bridge for operation. If the bridge command is started without waiting for a result, the result can be accepted but degraded with provider_handoff_started_unverified and evidence that provider delivery is unverified and an MCP receipt is required for proof.

Stage 8: Reply Proof

The strongest practical proof is not the initial send receipt. It is an MCP reply from the recipient path, carrying provider/session metadata that lets AxiOwl identify the sender without guessing.

The final visible body builder supports this by appending reply instructions when sender identity is resolved. It includes the sender name, the original message body, and an MCP tool call back to AxiOwl with the run ID and receiptForMessageId. If sender identity is unresolved, it adds a warning and does not attach a send-back command to an unknown sender.

That is why debugging a failed workflow should not stop at "was there a receipt?" The full chain is request accepted, sender resolved, target resolved, route selected, AxiOwl receipt returned, delivery worker started, provider write completed or failed, and reply received if the workflow requires one.

What To Collect When Something Fails

For a real failure, collect the AxiOwl logs, registry, and runtime files under:

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

For install and provider integration problems, also collect the MSI verbose log, VS Code or Cursor bridge output channels, provider CLI stdout and stderr, and relevant provider session files when safe. The support docs recommend checking selected installer features, actual provider installation, stale extension folders, stale provider config, provider session IDs, aliases, sendable, last_seen_at, last_verified_at, and last_error.

The message ID is the best search handle for one send attempt. The run ID is the best handle for a larger workflow that may include sends, replies, validation, and provider smoke-test records.

The Operator Value

Failure staging keeps AxiOwl honest. It prevents a successful install from being mistaken for working delivery. It prevents accepted_by_axiowl from being mistaken for provider acceptance. It prevents provider handoff from being mistaken for a reply. It also gives support and developers a concrete debugging map: find the first failed stage, then inspect the files and provider state that belong to that stage.

That is the point of AxiOwl's receipts, delivery-stage logs, registry fields, and provider evidence. They make a cross-provider message path debuggable without hiding uncertainty behind a generic "sent" label.