Why AxiOwl Separates Local Acceptance From Provider Acceptance

When one AI agent sends a message to another, "sent" is not one event. A local router can accept a request, validate it, resolve the target, and create a receipt before the target provider has actually accepted the message. AxiOwl keeps those facts separate because collapsing them into one success message would hide the part operators most need to understand: where the handoff actually stopped.

AxiOwl is built as a local coordinator for provider sessions. Its CLI and MCP server feed a message pipeline. That pipeline resolves the sender, resolves the target through the local registry, builds the final visible body, dispatches exactly one provider edge, and records evidence. The provider edge is the provider-specific adapter: Codex, VS Code, Cursor, Antigravity, remote relay, and CLI providers each need different delivery mechanics.

Those layers are intentionally not treated as the same proof.

Local Acceptance Means AxiOwl Took Responsibility

Local acceptance starts inside AxiOwl, before provider delivery is proven.

In the message pipeline, AxiOwl first rejects malformed sends: an empty target, an empty body, unresolved strict sender identity, an unknown target after targeted discovery, or a registry row that is known but not sendable. These failures are not provider failures. They mean AxiOwl did not accept the message for delivery.

The CLI reflects that boundary with output shaped like:

Message not accepted: <reason>

Once the request is valid, AxiOwl has a message id, a resolved or intentionally unresolved sender policy, a target registry row, a provider, a provider session id, and a final visible body. At that point, it can log message_accepted_by_axiowl. That means the local coordinator accepted the request and is moving it into delivery.

It does not mean the provider received it.

Provider Acceptance Means The Provider Edge Proved Its Handoff

Provider acceptance is returned by the provider edge, not guessed by the middle of the pipeline.

The source model has a ProviderRequest containing the message id, target record, sender identity, final visible body, strict flag, and provider-specific actuation mode. The matching ProviderResult carries the provider name, state, accepted flag, degraded flag, method used, evidence, and error.

The provider edge contract defines states such as:

accepted_by_provider
failed
degraded
unknown

That result is where AxiOwl records whether a Codex CLI command completed, a VS Code bridge command was accepted, an Antigravity delivery path returned success, a remote relay produced a result, or a provider-specific command failed. The evidence matters as much as the boolean: method names, process output, command ids, result files, IPC paths, timeout behavior, and provider session ids are what make a receipt debuggable.

This is why the CLI has a second outcome shape:

Message accepted by AxiOwl, but provider delivery failed.
Message ID: <id>
Delivery state: <state>
Provider: <provider>
Reason: <reason>

The local system accepted the job. The provider edge did not prove delivery.

The Receipt Should Say Only What Is Proven

AxiOwl's receipt rule is simple: do not call a message successful unless the software can prove the specific success being claimed.

The receipt docs explicitly avoid vague output like "Message sent successfully." The preferred shape is more precise:

Message accepted by AxiOwl.
Message ID: <id>
Delivery state: accepted_by_provider
Provider: <provider>

That phrasing says two things at once. First, AxiOwl accepted the request. Second, the delivery state came back from the provider layer as accepted_by_provider. If the provider state is failed, degraded, or unknown, the receipt should expose that instead of smoothing it over.

This distinction also prevents response confusion. A send receipt does not wait for the receiver to answer. A reply from the receiver is a separate future AxiOwl message that runs through the same pipeline in reverse. In the architecture docs, a response over MCP is the strongest end-to-end proof: the target received the message, acted on it, and replied with provider-owned sender identity. That is stronger than local acceptance and stronger than a provider command merely returning success.

Why Operators Need Both States

The separation is practical, not cosmetic.

If a target name is wrong, the registry cannot resolve it. The useful error is local: the target is not in the registry, and known agents can be listed. If the target is known but marked not sendable, the useful error is also local: AxiOwl should not dispatch to a target it already believes cannot receive messages.

If the target is valid but provider delivery fails, the operator needs a different class of evidence. Was the provider session id empty? Did a CLI command exit nonzero? Did a bridge runtime heartbeat go stale? Did a command file get written but no result file appear? Did a remote relay fail over SSH? Those answers live at the provider edge.

Keeping the states separate lets AxiOwl answer these questions cleanly:

That makes debugging shorter because the operator does not have to infer which layer lied.

It Also Prevents Silent Fallbacks

AxiOwl's trust-boundary docs say remote support must not hide local delivery failures, and provider fallbacks must not make unsupported paths look supported. The provider edge contract allows fallback only inside a provider family and requires degraded results to say what property was lost.

For example, a provider-specific fallback may be acceptable if it stays inside the same provider surface and records the degraded property. But a failed VS Code target should not quietly send to Codex instead. That would turn a provider failure into a misleading apparent success.

The local-versus-provider acceptance split is part of that safety rule. AxiOwl can honestly say, "I accepted this request," while still refusing to claim, "the target provider accepted it," until the provider edge has evidence.

The Implementation Is Built Around The Boundary

The C++ model mirrors the product contract:

This is not just naming. It is an operational model. A local receipt proves local intake. A provider result proves whatever the adapter could actually prove. A later reply proves the full round trip.

A Better Meaning Of Success

For AxiOwl, success is not a single green light. It is a chain of increasingly strong facts.

Local acceptance means the request was valid and AxiOwl took responsibility for dispatch. Provider acceptance means the selected provider edge reported a proven handoff. A reply over MCP means the receiving agent actually responded through AxiOwl with usable identity metadata.

Separating those states makes AxiOwl more honest and more useful. Operators can see whether a problem is in the registry, sender identity, provider adapter, remote relay, bridge runtime, or the target agent's eventual response. That precision is what makes multi-agent routing maintainable when every provider has a different delivery surface.