aster.ax / Docs

ax command reference

These examples use the local ax executable. Replace example paths and IDs with values from the active workspace and runner. Consult --help for other options.

Runner discovery and deployment

ax exec nodes --format json
ax exec nodes --refresh --format json
ax exec info build-node --format json

ax deploy ssh user@build-host --name build-node --plan --format json
ax deploy ssh user@build-host --name build-node --format json

user@build-host is an SSH destination; build-node is the local ax alias. --plan probes without installing. Add --system to both deployment commands when system installation is requested. Cross-platform deployment requires a compatible trusted --bundle <manifest>; do not assume a local Mac executable can run on Linux. Installation-only mode skips execution provisioning/checks.

Deployment returns top-level exec_ready and, after successful verification, runner.connectivity. Errors identify the stage after SSH installation, where applicable. A direct or relay connection can work; SSH success alone cannot establish Aster connectivity. Consult ax deploy ls --format json to reconcile an interrupted attempt. Removal is a separate ax undeploy ssh operation; inspect its help and the user's requested removal scope before using it.

nodes normally reads saved entries and existing broker connection snapshots. --refresh probes targets now. Ordinary listing shows the last info, check or refresh observation with its age when available; cached readiness is historical. Its check status and connection state are distinct. info actively queries a runner and reports target capabilities. A node is the network peer; a target selects an execution backend/account on that peer.

For a Windows OpenSSH endpoint dispatching commands into WSL Bash, add --wsl-dispatcher to deployment and removal. WSL also requires a Windows-side keepalive task; see WSL setup.

Submission with attribution

# Use the actual harness/session; omit unknown metadata.
export AX_HARNESS=codex
export AX_HARNESS_SESSION="$actual_session_id"
export AX_LOCAL_WORKSPACE="$PWD"

# Generate once and retain for this command, including an exact retry.
request_id=$(python3 -c 'import uuid; print(uuid.uuid4())')
ax exec run --node build-node --cwd /srv/project \
  --request-id "$request_id" --format json -- /usr/bin/id -u

AX_LOCAL_WORKSPACE must name an existing absolute local directory. Global --harness, --harness-version, --harness-session and --local-workspace flags override the corresponding environment values. Use the real harness name; codex is only an example.

Deployed runners save target/cwd defaults. Use --target <target-id> to select another reported target. Set --cwd to the actual remote project directory when running project commands. --timeout-ms sets the remote execution deadline; it is not the harness's tool wait timeout. Omit it when no deadline is required.

The submission receipt contains job_id, target_id, request_id, node_id and node_name (null when submitted by ID). Save this receipt. The CLI journals the request before network calls.

Send a script on stdin

ax exec run --node build-node --stdin --follow -- bash -s < script.sh

--stdin captures input to EOF before submission, up to 1 MiB and the target's advertised limit. Exact retries must supply identical bytes. Nonempty redirected input without the flag is rejected; closed empty pipes are accepted. An open pipe with no available input is rejected without waiting; use </dev/null for no input. This is bounded job input, not an interactive terminal or file-transfer channel.

Workspace transfer

ax exec info advertises the runner's workspace-transfer adapter. The first push or pull provisions the policy; the explicit form is:

ax workspace setup --node build-node
ax workspace push --node build-node --source . --to /srv/project --dry-run
ax workspace push --node build-node --source . --to /srv/project
ax workspace pull --node build-node --from /srv/project --to ./results --dry-run
ax workspace pull --node build-node --from /srv/project --to ./results
ax exec run --node build-node --cwd /srv/project --workspace . -- cargo test
ax workspace status --node build-node TRANSFER_ID --format json

The destination must exist and be allowed by the execution grant and local ceiling. Git-root selection defaults to tracked working-tree files. Untracked files need --include; sensitive names remain excluded unless permitted by an exact --allow-sensitive path. --exclude is repeatable. Directory selection is available with --directory. A first push or pull provisions the policy if setup never ran; dry runs still require it.

A pull flips the roles: --from is an absolute path on the runner and --to a local directory that must exist. The runner resolves selection (Git auto-detect at the source root unless --git or --directory), and there is no --delete.

Deletion is off by default. --delete currently selects missing tracked Git paths; --delete-path selects an explicit source-absent relative path. Full arbitrary-directory mirroring is not implemented. The combined run form uses default selection; push separately for custom selection.

A receiver receipt gates launch. Preserve --id on an exact push retry and --request-id on a run retry. A retained completed receipt describes that operation, not the current contents after later edits. Fetched payload counters are separate from verified logical bytes and transport overhead. See the workspace guide.

Recovery and output

ax exec ls --format json
ax exec ls -a --format json
ax exec status "$job_id" --format json
ax exec output "$job_id" \
  --cursor 0 --format json
ax exec watch "$job_id"

ls is scoped to the current caller and local workspace; -a includes its other workspaces. It exposes request_id, job, origin, local_cwd, remote_cwd and cached state. Use --refresh to update job statuses. An entry with no job reference may be an unconfirmed submission, not a rejected one.

Follow-up commands resolve unique jobs from the current caller's journal across local workspaces. Pass --node and/or --target to disambiguate. For jobs absent from the journal, supply both explicitly.

Status returns a job reference, state and exit information. Output returns chunks, next_cursor and eof; each chunk's bytes is base64 in JSON. Continue with the returned cursor. Check terminal status as well as output EOF. watch follows until terminal and retained output is drained; wait is its alias. Use --cursor to resume. Interrupted watching does not cancel execution.

watch --format json and run --follow --format json emit NDJSON events, not a single JSON document. For bounded harness calls, submit first, then query status/output or resume watching. Preserve the job reference across calls.

To cancel a specific job when intended:

ax exec cancel "$job_id" --format json

MCP alternative

ax mcp --allow exec-submit starts the existing stdio execution tools. Cancellation requires --allow exec-cancel. Pass workspace/session origin on each submission when sharing one server across projects; its startup directory is otherwise the default. MCP submit requires an explicit target and remote cwd. Deployment remains a CLI operation.

Local agent registration and pickup

# Run from the agent's workspace inside Claude Code to attach this conversation.
ax agent setup --name assistant --workspace /absolute/path
ax agent list
ax send reviewer "Please check the result" # same machine
ax send other-host/reviewer "Please check the result"
# In the recipient workspace, as directed by the socket notification:
ax messages fetch MESSAGE_ID --format json
ax messages inbox --format json
ax reply MESSAGE_ID "Here is the result"

Setup preserves identity and handles Git exclusion for agent.ax.toml. Inspect its session status: registration alone does not establish attachment. Fetch is local to the registered recipient, returns the retained message and marks pickup as delivered. Repeated fetch is safe; inbox inspection does not mark pickup. Fetch/inbox show the authenticated sender name, key and node, and a reply command. Both JSON outputs use compact {message, receipt} objects; inbox returns an array. Reply preserves the conversation and checks the original sender key even if its name has been reused. No return host alias is needed. Owner-authored messages have no reply mailbox. Reply lookup does not record pickup. Delivery is distinct from completed work. Claude may hold/refuse notifications; ax does not launch another session or repeatedly prompt a busy agent.

To correct an accidental assignment:

ax agent move assistant --workspace /correct/path
# Or remove it when intended; history and keys remain.
ax agent remove assistant

If agent.ax.toml was deleted, repeat setup with the same name and explicit workspace to recover its retained key. Move preserves that identity and inbox, clears the old binding and attaches the current Claude session when available. Repeat an interrupted move/remove with the same arguments to finish cleanup. Remove releases the name and workspace; later setup creates a fresh identity.

Multiple agents can share a workspace in agent.ax.toml. Use --agent NAME on send, reply, messages inbox and messages fetch when needed. Setup accepts --harness and defaults a new name to <directory>-<harness>. --takeover explicitly replaces another reachable session attached to the same mailbox.

Discover and contact a running session

ax agent sessions --format json
ax agent sessions localhost --format json
ax admin send
ax send
ax send --host localhost --session SESSION_UUID --harness claude --message "Hello"
ax send --host buildbox --session SESSION_UUID --harness codex --message "Hello" --agent sender
ax send --host buildbox --harness codex --destination-workspace /srv/project --message "Hello"
ax admin status
ax admin status MESSAGE_ID --format json
ax admin status --all
ax admin cancel MESSAGE_ID

The no-argument forms require a terminal. ax admin send uses the owner identity from any directory; ax send requires a selected workspace agent. Neither switches authority automatically. Owner messages have no agent reply mailbox and create no workspace selection. Owner sends use the same destination flags under ax admin send. The message retains its original author and ID throughout recovery. Discovery JSON includes host IDs/aliases, exact harness/session/workspace targets, mailbox mappings, ambiguous mailbox names and diagnostics. Only hosts with running supported sessions appear in the picker. Human tables fit the terminal width; search still matches full workspace, session and mailbox text. Local home paths may display as ~; remote paths are not abbreviated using the sender's home. Short IDs appear only to distinguish rows that would otherwise look identical. Grouped discovery warnings point to the JSON command for full details, including underlying RPC diagnostics. The explicit session form and picker use the same daemon-owned signed-message path. --workspace selects the sender workspace; the destination workspace comes from discovery. The explicit --destination-workspace form selects a logical recipient without live session discovery and requires host/harness. Do not combine it with --session. The durable address is host/harness/workspace; current session IDs are attachments. Named mailbox destinations bind once at the receiving node; replies use the original agent key.

The sender stores the message before forwarding. Offline destinations retry for three days with exponential connection backoff capped around five minutes and immediate forwarding on peer connection. Host acceptance ends forwarding; the receiving daemon then owns agent notification and pickup. Closing the sending CLI does not stop this work. Only recipient fetch establishes delivered-to-agent.

ax admin status lists outstanding local message records; --all includes terminal records and an ID selects detail. ax admin cancel ID is repeatable. Human/JSON output distinguishes destination acceptance from pickup and cancellation pending from confirmed cancellation. Already picked-up messages cannot be cancelled. Expiry stops new forwarding but does not prove non-delivery after a lost receipt.