
How AxiOwl Handles Remote Nodes Safely
Remote automation is useful only when it is explicit. A remote node can extend an operator's reach from a local Windows coordinator to a Linux machine, but that same reach becomes risky if it turns into an invisible fallback, a stale host entry, or a background deployment path that runs without proof. AxiOwl's current implementation treats remote nodes as a separate, guarded surface rather than as a hidden rescue path for local provider problems.
That distinction matters. In the AxiOwl source of truth, the remote provider surface is marked unsupported for local-provider remediation builds. The provider documentation says remote delivery should not hide local provider failures, and the installer matrix says remote features may exist but should be unchecked by default. In practice, this means AxiOwl can contain remote-node machinery while still keeping it outside the default local send and repair flow.
Remote Is A Node Registry, Not A Guess
AxiOwl stores remote node information in a dedicated node registry, separate from the agent registry. The node registry is written as nodes.tsv under the local AxiOwl registry directory. A node row records fields such as:
node_iddisplay_name- aliases
- host
- SSH user
- SSH key path
- enabled state
- last seen time
- last verified time
- last error
That shape is important because AxiOwl does not need to infer a remote machine from a chat title or from an old path. The remote provider code looks up the target node by node_id, then refuses to continue if the node is missing, disabled, or incomplete. If the node row has no host or SSH user, delivery fails with an explicit error instead of trying a best-effort command.
The CLI exposes the same idea directly. axiowl node add requires an id, host, and SSH user. axiowl node verify --id <node> runs a real SSH probe and records either last_verified_at or last_error. axiowl node list reports registered nodes and their verification/error state. Remote access is therefore modeled as state that can be inspected, verified, and repaired.
Verification Uses Noninteractive SSH
The remote verification code uses SSH with BatchMode=yes and a connection timeout. That is a safety choice as much as a convenience choice. Batch mode prevents a remote operation from hanging on an interactive password prompt, and the timeout prevents a dead host from blocking the installer or CLI indefinitely.
The verification command is intentionally simple:
hostname; whoami; pwd; hostname -I
That proves the SSH key and route can reach the expected Linux account without changing remote application state. During installer enrollment, AxiOwl tests configured keys, an AXIOWL_REMOTE_SSH_KEY environment key if present, and then the default SSH identity. It logs the candidate as either a configured key or default SSH behavior rather than printing key material.
Only after SSH verification succeeds does enrollment save the node and run axiowl node verify again through the installed local executable. If no remote nodes can be verified, enrollment fails. That is a better failure mode than leaving a half-trusted node in the registry and hoping later delivery can sort it out.
Remote Install Is Explicit And Payload-Checked
The Windows installer has remote feature names for enrollment, deployment, and discovery, but the matrix and tests keep them selected only when the remote feature is explicitly selected. The provider contract tests also check that unchecked remote features remain in the unchecked feature list. The robustness guard tests verify that remote custom actions are tied to their selected MSI features.
When remote deployment does run, it verifies the Linux payload before copying anything. The installer helper checks for required payload pieces:
bin/axiowl- the Codex plugin manifest
- the Codex plugin MCP config
- the remote Linux installer script
It then creates a temporary tar archive, cleans a temporary staging path on the remote host, copies the archive with SCP, expands it remotely, runs install-axiowl-remote-linux.sh, and removes the temporary files. The remote shell paths are quoted through a helper that rejects apostrophes rather than trying to compose unsafe shell strings.
The Linux-side installer has its own checks. It requires the payload directory to exist, requires expected files to be present, installs /usr/local/bin/axiowl, checks that axiowl --version reports the expected version, installs the Codex plugin payload under the user's local AxiOwl Codex area, registers the Codex plugin marketplace, and probes the MCP server for axiowl_send_message. It also uses an assert_under_path helper before operating on plugin and marketplace destinations so a computed path cannot escape the intended install root.
Relay Is Structured JSONL Over SSH
Remote delivery is not a raw "run this arbitrary shell command" path. On Windows, the remote provider writes a temporary JSONL input file containing a hello frame and a deliver frame. It then runs:
axiowl relay-session --stdio
over SSH on the remote node. The remote relay reads JSON frames from standard input and writes JSON frames to standard output. The deliver frame carries the target, final visible body, strict-mode flag, sender identity fields, and, when available, a direct provider address.
The relay validates the incoming frame. If the target or body is missing, it returns a JSON error frame. If the remote target can be addressed directly, the relay builds a provider request and sends it through the remote delivery worker. Otherwise it uses the normal message pipeline on the remote node. In both cases it returns a deliver_result frame with the request id, state, provider, message id, error, and detail.
This matters operationally because a local sender receives a structured result. AxiOwl can distinguish a failed SSH relay, a remote provider rejection, a missing target, and a successful provider acceptance. It does not have to scrape an unstructured terminal transcript and guess what happened.
Remote Discovery Is Not A Default Repair Path
AxiOwl has implementation for targeted remote Codex discovery. It can SSH to a verified node and run a remote discovery command for a named target, then merge returned discovered_agent rows only when the remote result matches the requested target name and provides a sendable provider session id.
But the current local-provider remediation flow deliberately excludes remote discovery. The CLI returns an excluded remote report for axiowl discover remote, and axiowl discover all prints local provider discovery while adding a remote exclusion notice. Local smoke-test reports also state that remote is excluded out of scope.
That is the safety boundary in plain terms: remote discovery may be a designed surface, but it is not allowed to paper over a broken local provider. If VS Code, Cursor, Codex, or another local provider needs repair, AxiOwl should diagnose that provider directly instead of silently sending work to a different machine.
Sender And Target Identity Still Matter Remotely
AxiOwl's broader architecture is built around durable registry rows, provider-owned session ids, and MCP metadata. Remote handling follows the same pattern. A remote target stores the remote node id and a provider session address; remote direct delivery accepts only known provider names such as Codex, VS Code native, VS Code Copilot-backed, and Antigravity after parsing the remote target address. If the provider address is malformed, AxiOwl falls back to normal remote target resolution rather than inventing a destination.
The relay also forwards resolved sender fields. That lets a remote delivery preserve the final visible body and sender context instead of making the remote side guess who initiated the message. For replies that travel back upstream, the remote provider code turns upstream_message frames into local MessagePipeline sends and records evidence about the local message id, target, state, acceptance, and error.
What Operators Get From These Boundaries
The practical value is predictability. Operators can inspect registered nodes, verify SSH access before deployment, see when a node was last verified, and read explicit errors when a remote row is incomplete. Installer behavior is tied to selected features, not broad side effects. Remote deployment checks payload contents before touching a Linux node. Remote delivery returns structured results instead of relying on a vague successful SSH exit.
The current source also avoids overstating the feature. Remote support is not presented as a default supported provider surface for local repair. The docs and tests make that explicit. That honesty is part of the safety model: a capability can exist in the codebase while still being gated until the contract, validation, and support bar are high enough.
Closing
AxiOwl handles remote nodes safely by making them explicit. Nodes live in a separate registry. SSH access is verified before use. Installer actions are feature-scoped and unchecked by default. Remote deployment validates its payload. Relay traffic is structured JSONL over axiowl relay-session --stdio. And, most importantly, remote is not used as a silent fallback when a local provider path fails.
That is the right posture for agent operations across machines: make the remote path visible, make every step inspectable, and fail loudly when the proof is not there.