Why AxiOwl Uses SSH for Remote Routing

Remote routing in AxiOwl is not built around a public network service. The current Windows desktop line treats the Windows build as the local coordinator and registry owner, then reaches Linux remote nodes through SSH. On the Linux side, AxiOwl exposes a small command surface: axiowl relay-session --stdio, plus Codex-focused discovery and delivery support.

That choice is deliberate. AxiOwl's job is to send one text message from one named agent to one named agent through a selected provider edge, then record what happened. SSH gives that remote edge a narrow, inspectable, operator-friendly path without asking every remote machine to expose a new always-on AxiOwl port.

The Registry Already Has the SSH Shape

AxiOwl's architecture keeps the registry intentionally plain. For remote nodes, the fields are the practical ones an operator would expect:

node_id
display_name
host
ssh_user
ssh_key_path
enabled

For agents, the registry maps a human-readable agent name to a provider, provider session id, and node. That means a remote target is not magic. It is a normal target with provider=remote, a node_id, and a provider session value that points to the remote agent name or the remote provider/session pair.

The CLI reflects that model:

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"

That is one reason SSH fits AxiOwl well. The remote routing facts are explicit in the node registry. There is no hidden service discovery layer pretending to know where a node lives, which user should connect, or which key should be used.

Delivery Uses a Relay Session, Not an Open Port

In the Windows remote provider, AxiOwl builds a temporary JSONL input file and invokes SSH in batch mode:

ssh -o BatchMode=yes -o ConnectTimeout=10 <user>@<host> "axiowl relay-session --stdio"

If a key path is configured on the node, the command adds -i <ssh-key-path>. The relay input includes a hello frame and a deliver frame with the protocol version, request id, target, final visible body, strict flag, and sender information. The remote command reads those frames from stdin and writes JSONL results back on stdout.

The remote side is equally small. run_relay_session_stdio() writes a hello frame, reads each JSON line from stdin, handles deliver frames, and emits either an error frame or a deliver_result frame. The relay can also emit upstream_message frames, which the Windows side feeds back through the local AxiOwl pipeline when needed.

This keeps the transport boundary simple:

local AxiOwl
  -> SSH
    -> axiowl relay-session --stdio
      -> remote provider delivery
        -> JSONL receipt

There is no remote HTTP listener to configure, no extra public firewall rule, and no long-lived AxiOwl daemon port required for this path.

SSH Also Handles Remote Discovery

AxiOwl uses SSH for more than message delivery. The remote discovery provider runs a targeted command on the node:

axiowl discover codex --json --target <target>

The Windows side wraps that command in SSH with BatchMode=yes and a short connection timeout. It parses returned discovered_agent JSON lines, then records remote rows locally as provider=remote. When the remote node reports a real provider and provider session id, AxiOwl stores them in a compact form such as:

codex:<provider-session-id>

That matters because discovery remains evidence-based. A remote row is not considered useful merely because a name appeared in a config file. The discovery code checks the remote output, matches the requested target name, records the remote provider and session id as evidence, and marks the row sendable only when the returned data supports it.

Installation Uses the Same Operator Boundary

The Windows installer line also uses SSH and SCP for remote Linux setup. The installer helper reads remote node candidates from packaged remote-nodes.json, a local override path, and existing node registry rows. It then verifies the remote payload, creates a tar archive, copies it to the node with scp, and runs the remote Linux installer over SSH.

The Linux installer script installs the axiowl binary to /usr/local/bin/axiowl, installs the bundled Codex plugin payload under the remote user's AxiOwl state root, registers a Codex plugin marketplace, installs axiowl-codex@axiowl, and probes the MCP server to confirm it exposes axiowl_send_message.

That means remote routing is not only a runtime decision. The deployment workflow is built around the same operational assumption: if an operator can SSH to the node, AxiOwl can enroll, deploy, verify, discover, and route through that node without inventing a separate remote management protocol.

The Remote Edge Is Intentionally Narrow

The current Linux remote app supports Codex CLI delivery only. The Windows README says the Linux remote app does not support VS Code, Antigravity, desktop IPC, GUI, tray behavior, or remote relay chaining. The provider code enforces that boundary: on non-Windows builds, remote chaining returns a failure stating that Linux remote AxiOwl intentionally supports Codex CLI delivery only.

That limitation is useful to call out because it is part of the design discipline. AxiOwl is not claiming that every local provider surface can automatically be projected across SSH. It uses SSH to reach a remote AxiOwl command, then lets the remote side use the provider edge it actually supports.

For operators, that is a better failure mode than a silent fallback. If a remote node is missing a host, missing an SSH user, missing a configured key, missing a registered node row, or returns a failed relay result, AxiOwl records a concrete error and includes process output or remote detail in the evidence.

Why This Is Practical

SSH gives AxiOwl a few practical advantages:

It also matches AxiOwl's larger architecture rule: the middle should be boring, and provider-specific behavior should live at the edge. For remote routing, SSH is the edge transport. The AxiOwl message pipeline still resolves the target, builds the final visible body once, chooses the provider edge, records evidence, and returns a receipt.

The Result

AxiOwl uses SSH for remote routing because the remote problem is not just "send bytes to another machine." It is node enrollment, deployment, discovery, delivery, and evidence collection across machines that operators already access through SSH.

The current implementation keeps that path narrow and inspectable. Windows owns the registry and launches an SSH-backed relay session. Linux receives JSONL frames on stdin, delivers through its supported Codex path, and returns structured results. That gives AxiOwl remote routing without a new public service surface, while preserving the core promise: one named sender, one named target, one selected provider edge, and an honest receipt.