AxiOwl Node Registry Explained

AxiOwl needs a practical answer to a simple routing question: when an operator says to reach a remote node, what machine is that, how should AxiOwl connect to it, and is the node still usable? The node registry is the small durable table that answers those questions.

In the current AxiOwl C++ implementation, the node registry is separate from the agent registry. The agent registry records sendable provider sessions and chat targets. The node registry records remote AxiOwl machines that may be used for remote discovery, verification, or relay work. Keeping those two tables separate is what lets AxiOwl say "this Codex thread is on node X" without stuffing SSH connection details into every agent row.

Where the Node Registry Lives

AxiOwl stores runtime state under a platform-specific state root. On Windows, the state root is %LOCALAPPDATA%\AxiOwl. On Linux, AxiOwl uses $XDG_STATE_HOME/axiowl when available, otherwise ~/.axiowl.

The node registry path is:

<state root>/registry/nodes.tsv

The companion agent registry path is:

<state root>/registry/agents.tsv

That distinction matters. agents.tsv is about provider sessions: display name, provider, provider session id, node id, sendability, source, and timestamps. nodes.tsv is about machines: node id, display name, aliases, host, SSH user, SSH key path, enabled state, verification timestamps, and last error.

The current C++ model defines a node row with these fields:

node_id
display_name
aliases
host
ssh_user
ssh_key_path
enabled
last_seen_at
last_verified_at
last_error

AxiOwl writes that table as TSV, with a header row, through the NodeRegistry class. Loading skips the header, ignores empty rows, and only returns enabled nodes when resolving a specific node id through find_node.

What a Node Record Means

A node record is not a chat. It is not a provider session. It is the address book entry for another AxiOwl-capable machine.

The important fields are direct:

That design is deliberately plain. The discovery plan describes the registry as a boring table, and the implementation follows that shape. AxiOwl does not need a sprawling object graph to route to a node. It needs a known id, a host, a user, an optional key, and current status evidence.

How Operators Add and Inspect Nodes

The CLI has node-specific commands. A node can be added with an id, host, SSH user, optional key path, optional display name, and optional alias:

axiowl node add --id backend --host 152.70.122.218 --ssh-user ubuntu --key C:\path\to\key.pem --name backend

There is also an older-compatible registry command path that can add a node:

axiowl registry add-node --id backend --host 152.70.122.218 --user ubuntu --key C:\path\to\key.pem

For daily operation, the node command is the clearer surface. axiowl node list prints registered nodes with host, SSH user, enabled state, and any verification or error fields. axiowl status also reports the node registry path and the count of registered nodes.

The useful verification command is:

axiowl node verify --id backend

The implementation resolves the node id from nodes.tsv, builds an SSH command with BatchMode=yes and a connection timeout, includes the configured key path when present, and runs:

hostname; whoami; pwd; hostname -I

If the command succeeds, AxiOwl updates last_seen_at, sets last_verified_at, clears last_error, and saves the node table. If it fails, AxiOwl records a concise SSH failure message in last_error and saves that too. That means node verification leaves a durable trail instead of failing as an invisible one-off shell command.

How Nodes Relate to Agents

The agent registry includes a node_id column. For local sessions, that is usually local. For a remote target, the agent row points at a named node.

This is the key relationship:

agent row -> node_id -> node registry row -> SSH host/user/key

AxiOwl's architecture documentation describes a registry row as one reachable provider session or agent. Important agent fields include display_name, aliases, provider, provider_session_id, node_id, sendable, source, last_seen_at, last_verified_at, and last_error. The node registry supplies the machine-level details behind the node_id.

This separation prevents a common routing mistake: treating "remote Codex" as a special fake provider when it is really Codex on a different node. The lightweight discovery plan states the cleaner model directly: a remote Codex row can still use provider=codex and a remote node_id; the node id is what says the session lives somewhere else.

Discovery Uses Nodes Explicitly

AxiOwl's discovery rule is intentionally conservative:

Discovery reads provider-owned state.
Enrollment writes the AxiOwl registry.
Sending reads only the AxiOwl registry.

For remote Codex discovery, the planned and partially implemented flow is explicit. Local AxiOwl resolves a node from nodes.tsv, opens SSH to that node, runs remote Codex discovery, reads JSON output, and imports matching discovered rows into the local agent registry with the supplied remote node_id.

The code path for targeted remote discovery does that with:

ssh ... <ssh_user>@<host> "axiowl discover codex --json --target <target>"

It then reads discovered_agent JSON lines from the remote command, filters them to the requested target, and creates local discovery rows that remember the remote node. If the node row is missing host or ssh_user, discovery records an issue instead of guessing. If the SSH command fails, discovery records that remote discovery failed for that node.

One operational detail is important: current discover all intentionally excludes remote discovery. The CLI emits a remote discovery report saying remote discovery is excluded from local all-provider discovery. Remote discovery is not a broad sweep. It requires an explicit node target, which keeps expensive or surprising network behavior out of routine local discovery.

Remote Delivery Also Depends on Nodes

The remote provider path also resolves request.target.node_id through NodeRegistry. If no node exists, the provider returns an error that the remote node is not in the node registry. If the node is missing host or ssh_user, it returns an incomplete-row error.

When the row is valid, the Windows remote delivery implementation builds an SSH command to the registered destination and runs:

axiowl relay-session --stdio

The relay input includes the target, final visible body, strict flag, sender identity, sender node, and when available the direct remote provider and remote provider session id. This is why node registry correctness matters: a bad node row is not just a cosmetic problem. It is the difference between an addressable remote route and a rejected delivery attempt.

That said, the current provider support matrix marks remote as unsupported for local-provider remediation builds, and the remote provider docs say remote should not be used as a fallback to hide local provider failures. The node registry exists in the implementation, but operators should treat remote behavior as an explicit remote-node path, not as a magic backup route for broken local integrations.

Why AxiOwl Keeps It Simple

The design avoids three classes of failure.

First, it avoids hidden discovery. AxiOwl's plans repeatedly state that provider adapters should not guess targets by scanning random files during send. Discovery should be visible, logged, and inspectable. A node registry makes remote reachability explicit before remote discovery or relay work starts.

Second, it avoids blind registry sync. The discovery plan says remote discovery has two jobs: discover remote nodes and discover chats on those nodes. It also says not to blindly sync registries. Local AxiOwl should ask the remote installation for provider facts, then decide what to import and enroll locally.

Third, it gives operators an inspectable failure surface. A missing SSH user, stale key path, disabled node, or failed verification can be recorded on the node row. The failure is visible in node list, status, and the registry file itself.

Practical Operator Value

For an operator, the node registry gives AxiOwl a controlled remote inventory:

For developers, the table keeps routing logic testable. NodeRegistry::find_node has a narrow job. Remote discovery and remote delivery can fail early with specific errors when the node row is absent or incomplete. The agent registry can stay focused on provider session identity and sendability.

Closing

The AxiOwl node registry is intentionally not clever. It is a durable map from node id to connection facts, stored as registry/nodes.tsv, used by explicit node verification, targeted remote discovery, and remote relay paths. That small table gives AxiOwl enough structure to route across machines while preserving the product's core rule: discovery is explicit, enrollment is inspectable, and sending should depend on known registry facts instead of guesses.