CLI reference
Generated from sox help in the shipped binary. Do not hand-edit: regenerate with
scripts/check-docs.py --write.
Usage: sox <command> [options]
Commands:
push config Inspect or configure local push gateway
up [host] [path] [options] Ensure a host and attach or create a shell
down <host> Disconnect; leave shells running
doctor [target] Run a read-only session diagnostics pipeline
ls [host] [--deadline-ms N] Shell inventory by durable handle, from the daemons
attach [host/]<handle> Attach to a shell by durable handle
send [host/]<backing> [--enter|--key] Send acknowledged text or keys to a shell
history [host/]<target> --tail N Read bounded shell scrollback
new [host] [--no-attach] Create a persistent shell
kill [host/]<handle> Kill a shell by durable handle
kill --all <host> [--yes] Kill a live snapshot after assent
which <pid> Name the shell a process is running inside
label [host/]<backing> [k=v ...] Set or print a backing's durable labels
watch [host/]<backing> --until S Block until a backing reaches a state
wait [host/]<backing> [--timeout S] Block until a detached task exits; propagate its code
completions Print shell handle candidates
host ls|rm <host> List or remove the hosts this client connects to
daemon --ensure|--stop Start or stop this home's sox daemon
attention [--state S] [--clear] Submit surface attention (agent plugins)
pair [host] [options] Enroll a phone (host arg = drive it over SSH)
app <command> --home <path> Control one explicitly addressed Sox.app
version Print version
help [command|topic] Print help
Topics:
getting-started Install, first session, updates, and what persists
command-center The attention roster: states, tiers, and sort order
agents Wire Claude Code, Codex, Grok, or pi into the Command Center
sessions Where shells live, restore, and recovery
ssh-agent Which SSH agent a shell signs with, and how to check
Run 'sox help <command>' for command-specific usage,
or 'sox help <topic>' for the prose above.
Exit codes:
0 ok
1 generic
10 arch_detection_failed
11 no_binary_for_arch
12 remote_deploy_no_space
13 remote_deploy_permission_denied
14 remote_deploy_failed
15 deploy_timeout
16 local_binary_missing
17 remote_hash_check_failed
20 ssh_connect_failed
21 rpc_tunnel_failed
22 rpc_daemon_unreachable
25 daemon_version_mismatch
26 remote_home_unreadable
27 daemon_startup_failed daemon died at startup, or declined to start
(see daemon-stderr.log)
42 backing gone: positive proof (refused, retired lineage, or the
session daemon reported the shell ended non-zero or was killed)
(`sox attach`)
43 backing absent or end unconfirmed: no positive death proof
(`sox attach`)
44 shell kept running: materialization needs retry (`sox attach`)
45 send refused: target blocked on an open question (`sox send`)
46 send refused: agent attention state unknown (`sox send`)
sox push
Usage: sox push config [--gateway <url>|off] [--token-stdin]
[--terminal-notifications on|off]
Inspect the local home's push setting and the gateways its phones registered.
Each phone names its own gateway, so a host needs no setting. --gateway
overrides every phone's gateway (tests, self-hosting); off disables push.
The token is transitional: it wakes only phones running an older Sox app.
It is read only from stdin and stored in the macOS login Keychain.
Linux hosts require SOX_PUSH_GATEWAY_TOKEN in the daemon environment.
The daemon reads a changed setting on its next start; Sox.app need not relaunch.
--terminal-notifications off stops OSC 9/777 in this home's shells from
waking the phone, at once and without a restart; agent wakes continue.
sox up
Usage: sox up [host] [path] [options] [--exec -- <argv>]
Ensure a host, add it to config, and attach or create a shell.
With no host, use config default_host, else localhost (local, no SSH).
A path creates a shell at that directory. In a detected Sox.app shell,
the default OSC handoff opens native terminals. --no-attach opts out.
Known limitation: from CLI-minted or remote shells inside Sox.app,
up nests a terminal attach instead. -CC is retired; there is no explicit
handoff workaround. Tracked at https://github.com/0xsend/sox/issues/833.
For remote hosts: establishes SSH connection, deploys the remote
sox binary, and attaches a terminal.
Options:
--forward-agent Enable SSH agent forwarding
--no-forward-agent Disable SSH agent forwarding
--no-attach Ensure the host without creating or attaching a shell
--exec -- <argv> Create and attach a shell running exact argv.
Must be last. For unattended tasks, use
sox new [host] --no-attach --exec -- <argv>.
--progress Force text progress stream on stderr
--no-progress Suppress text progress stream
--log-json Route structured phase logs as NDJSON
--log-file <path> Write NDJSON phase logs to a file
--verbose Print resolved transport config
--env NAME=VALUE Set NAME in the minted shell. A shell's
environment is a declared value, not the
caller's map (REQ-LSX-109), so anything
beyond the login baseline and sox's own
SOX_*/ZMX_* variables is opt-in. Repeatable.
--inherit NAME Carry NAME across from this process.
Repeatable.
-h, --help Show this help
Everything after -- is argv, passed through unmodified: no shell
quoting and no wrapping. To keep the shell alive after the command
exits, pass a wrapper as the argv (see `sox help agents`).
Examples:
sox up ae-dev
sox up ae-dev --exec -- claude --resume
Exit codes:
0 ok
1 generic
10 arch_detection_failed
11 no_binary_for_arch
12 remote_deploy_no_space
13 remote_deploy_permission_denied
14 remote_deploy_failed
15 deploy_timeout
16 local_binary_missing
17 remote_hash_check_failed
20 ssh_connect_failed
21 rpc_tunnel_failed
22 rpc_daemon_unreachable
25 daemon_version_mismatch
26 remote_home_unreadable
27 daemon_startup_failed daemon died at startup, or declined to start
(see daemon-stderr.log)
42 backing gone: positive proof (refused, retired lineage, or the
session daemon reported the shell ended non-zero or was killed)
(`sox attach`)
43 backing absent or end unconfirmed: no positive death proof
(`sox attach`)
44 shell kept running: materialization needs retry (`sox attach`)
45 send refused: target blocked on an open question (`sox send`)
46 send refused: agent attention state unknown (`sox send`)
sox down
Usage: sox down <host>
Disconnect this client's SSH ControlMaster and RPC tunnel from the host.
Remove only the transport runtime hint. No daemon RPC or config edit is
made; every shell remains alive, even if the daemon is unreachable.
Arguments:
host Configured host name or SSH destination (required)
Options:
-h, --help Show this help
To destroy shells explicitly, use sox kill <handle>, or
sox kill --all <host> --yes --home <resolved-home>.
Exit codes:
0 ok
1 generic
10 arch_detection_failed
11 no_binary_for_arch
12 remote_deploy_no_space
13 remote_deploy_permission_denied
14 remote_deploy_failed
15 deploy_timeout
16 local_binary_missing
17 remote_hash_check_failed
20 ssh_connect_failed
21 rpc_tunnel_failed
22 rpc_daemon_unreachable
25 daemon_version_mismatch
26 remote_home_unreadable
27 daemon_startup_failed daemon died at startup, or declined to start
(see daemon-stderr.log)
42 backing gone: positive proof (refused, retired lineage, or the
session daemon reported the shell ended non-zero or was killed)
(`sox attach`)
43 backing absent or end unconfirmed: no positive death proof
(`sox attach`)
44 shell kept running: materialization needs retry (`sox attach`)
45 send refused: target blocked on an open question (`sox send`)
46 send refused: agent attention state unknown (`sox send`)
sox doctor
Usage: sox doctor [target] [options]
Run a read-only diagnostic pipeline for a Sox target.
With no target, diagnoses the local machine at the current directory
(same default as `sox up`). Local targets skip SSH and dial the unix
RPC socket; remote targets still take host:project_root.
Remote steps, in order and under the names `--json` reports:
ssh_master, rpc_tunnel, push_config, watch,
login_session, shells (advertised slots vs
sockets vs attention vs tombstones vs close-intents, plus each shell's
SSH agent: its state, who set it, and what it points at), project_root.
Local targets run push_config first and report SSH as skipped.
The login_session step reports the audit session of the control-plane
daemon that answered, plus that user's GUI-domain availability. It is
that process's session and no listed shell's -- no shell descends from
the control plane -- and each shell carries its own on its row. Graphic
access is necessary for the login keychain and not sufficient, so the
keychain is reported unprobed rather than inferred.
A shell's agent state is one of dangling, unreachable, empty, keyed, or
unknown; its owner is per_handle_export, legacy_global_export, or
inherited. A dangling, unreachable, or empty agent warns and names the
owner; it never fails the step.
Options:
--json Emit a JSON array instead of human-readable output
--shell <id> Restrict the shells join to one handle or backing id.
A host/ qualifier must name the target's host
--bundle [<path>] Write one redacted .tar.gz (default sox-doctor-bundle.tar.gz)
--log-file <path> Include this NDJSON phase log in the bundle when present
-h, --help Show this help
Examples:
sox doctor
sox doctor .
sox doctor localhost
sox doctor --shell s1.g12
sox doctor ae-dev:~/workspace
sox doctor ae-dev:~/workspace --json
sox doctor ae-dev:~/workspace --bundle
sox doctor ae-dev:~/workspace --shell s1.g12
sox ls
Usage: sox ls [host] [--deadline-ms N] [--prefix P] [--backing-ids] [--json]
Shell inventory by durable handle: the handles this control plane
knows how to address, including cold shells.
Every row is one daemon's own answer, taken now. There is no
cached mode: a daemon owns its host's shells, so a client that
answered from a file would be guessing on its behalf.
The extent follows the home, not the command name. A home holding
session rows asks each of those hosts' daemons; a home holding
none asks its own.
Output columns:
handle status cmd cwd [attention=S] [native=ID] [labels]
handle backing-id status cmd cwd [attention=S] [native=ID] [labels]
A handle is lineage-blind: `s1.g1477` and its successor `s1.g1502`
both display as `s1`. That is what `attach` and `kill` take, so it
stays column one. A piped caller also gets the generation, because
`sox send` refuses a handle that names none.
A shell on another host prints as <host>/<handle>, the spelling
every verb sends to that host; this machine's shells print bare.
`status` is a daemon-reported probe verdict. The set it can hold
depends on which extent answered. A shell that exited is not
listed; `sox wait` reports its exit code.
`attention` and `native` come from the daemon's attention snapshot.
`native` is absent when the plugin has not supplied a session id.
This home's own shells:
live the probe reached the shell
cold interrupted; its committed restart has not spawned yet
no-reply:<Error> connection accepted, no decodable reply came back
no-reply the same, with no error name to give
A fleet host's daemon, about its own shells:
live that daemon's probe reached the shell
cold that daemon's probe was refused; history kept
unknown that daemon probed and reached no verdict
`no-reply`, `unknown` and `cold` are not proof of death. A
materialized backing remains listed when its socket is refused;
unowned sockets are never inventory rows. `sox attach <handle>`
starts a `cold` shell whose restart is already committed.
A host whose daemon does not answer prints one `unreachable`
line naming why, and no rows -- a host line, not a status token.
Naming that host explicitly exits non-zero; a fleet-wide
`sox ls` exits zero and renders the hosts that did answer.
Arguments:
host Filter to one exact slug or exact host
--prefix P Keep rows whose backing id starts with P
--json NDJSON: typed shell and unreachable host rows,
then one summary with complete and filtered counts.
A shell row's target is the spelling verbs take.
last_exit_code and ended_at_ms are always null.
An incomplete fleet can exit zero; check complete.
--deadline-ms N How long to wait per host, 1000..60000 ms
(default: 10000)
--backing-ids Print one backing id per line and nothing else.
Fails non-zero, emitting nothing, if any
selected host did not answer: the bare-id
protocol has no way to say a list is partial.
--json does not relax this.
-h, --help Show this help
Examples:
sox ls
sox ls ae-dev
sox ls --deadline-ms 2000
sox ls --backing-ids --prefix sox-
sox attach
Usage: sox attach [<host>/]<handle>
sox attach <handle> [--no-create] [--expect-backing <id>] [-- cmd...]
Attach to a shell by durable handle.
A live shell reconnects. A reserved successor starts its committed shell.
A cold shell restarts in place: a fresh login shell under the same
handle, in the directory the shell was last in, below the history it
left. A retired lineage is refused with exit 42; run `sox ls` to find
a current shell or `sox new` to start one. Exited shells are refused.
When the session daemon reports that the attached shell ended, attach
exits 0 if the shell's status was 0 and 42 otherwise. If the daemon
closes without a report, attach exits 0 when the backing still answers
and 43 when it does not. A create argv's own status is not relayed;
use `sox wait`.
A bare handle is this machine's shell, resolved by this machine's
daemon; no other host is asked. <host>/<handle> runs the attach on
that host over SSH, where its daemon resolves it. `sox ls` prints
every shell on another host that way.
Low-level, for generated invocations. Each one addresses this
home's daemon directly and skips roster resolution:
--no-create Attach only; never mint a backing
--expect-backing <id>
Assert the backing behind the handle, and the
only way to name a raw backing id
--release-token <t>
Reservation token, carried for the caller
--fallback-cwd <dir>
Where a cold shell restarts when its daemon
holds no directory for it: ~, ~/... or an
absolute path on this host
--local-only Refuse a handle on another host. A qualified
attach sends it to the host's daemon
-- cmd... argv for a backing this attach creates for a
caller that already reserved its slot.
Attach never mints a slot handle, so an
unknown one is refused with or without this
-- `sox new --exec` is the verb that creates.
The separator is required: without it `bash`
is indistinguishable from a mistyped flag.
Examples:
sox attach s37
sox attach ae-dev/s0
sox attach s0 -- bash -lc 'npm test'
sox send
Usage: sox send [<host>/]<backing-id> [--enter] [--] [text...]
sox send [<host>/]<backing-id> [--enter] < input
sox send [<host>/]<backing-id> --key <token> [--key <token> ...]
Send byte-exact, acknowledged input to an already-live shell.
Arguments are joined with one ASCII space. With no text arguments,
stdin is read exactly, including NUL and newline bytes. --enter
submits it with one carriage return. A terminal stdin with no
text requires --enter and sends only that carriage return.
The target names its generation -- `s1.g1477`, or `host/s1.g1477`
-- and `sox ls` prints it beside the handle. A bare handle is
refused: a handle is lineage-blind, so `s1` means whichever shell
holds that slot right now, and a send is a blind write. The
refusal names what the handle backs at that moment.
A bare target is this machine's shell. `host/` sends to that host's
shell over SSH; no other host is asked.
A send refuses, having delivered nothing, when the target's agent
has a question or permission picker open (attention state
`blocked`): typed input would answer it. It also refuses when the
target's terminal runs claude, codex or grok, or cannot be sampled,
and its attention state is missing, unreadable, or logged as not
delivered. A plain shell with no attention state receives the send
as before. --answer delivers anyway and appends what the guard saw
to the receipt: `(answer: attention blocked; foreground harness)`.
Use it only for an answer the owner gave. A question opened
between the check and the write, or one the agent never reported,
is not caught.
A payload larger than one PTY read arrives as several reads, so a
shell running a TUI is handed the whole thing as one bracketed
paste when that TUI asked for pastes to be framed, with the
--enter carriage return outside the frame. A shell that did not
ask receives the bytes exactly as given. A payload that already
contains the paste-end sequence is refused rather than framed:
it would end its own paste and the rest would arrive as
keystrokes.
A delivered send reports the backing it wrote to on stderr,
together with the command that shell's terminal is running and
the directory it is in right now -- `sent 412 B to s1.g1477
(claude in /work/repo)`. A shell sitting at a prompt reports its
own shell, which is how "nothing is running here" is said
positively. --expect-fg asserts that command up front and
refuses, having sent nothing, when the target is running
something else or when the command could not be read.
A delivered send does not mean the agent read the text as a message;
confirm it in the target's transcript.
Options:
--key TOKEN Send a named key without paste framing (repeatable).
up/down/left/right/enter/escape/tab/backspace,
home/end/pageup/pagedown, ctrl-a through ctrl-z.
Cannot combine with text, stdin, or --enter.
--enter Submit the payload with one carriage
return, sent after it
--expect-backing <id> The same assertion in the generated
backend form
--local-only Refuse a target on another host; a
qualified send sends it to that host
--expect-fg <name> Deliver only if the target's terminal
is running this command, named as
`sox ls` prints it
--answer Deliver even into an open question or
an unknown attention state
-- Treat every following token as text
-h, --help Show this help
The complete payload is limited to 256 KiB. Queue refusal is
reported without partially delivering the payload.
Exit status:
0 delivered
45 refused: the target is blocked on an open question; relay it
to the owner instead of retrying
46 refused: an agent target's attention state is unknown; run
/sox:doctor in that shell
sox history
Usage: sox history [<host>/]<target> --tail N [--max-bytes B]
Read the newest N rows of a shell's primary-screen scrollback.
The active screen is excluded; soft-wrapped rows stay separate.
Rows print oldest to newest with trailing blanks trimmed and LF.
Controls, backslashes and invalid UTF-8 use zmx's \\xNN escaping.
Nothing is printed until the complete reply has been validated.
--tail N Required plain decimal, 1..200; no row default
--max-bytes B Plain decimal, 1024..65536; default 65536
Older whole rows are dropped to fit B, including escaping and LF.
A newest row that cannot fit B fails with empty stdout.
Empty scrollback succeeds with empty stdout. No --follow.
This read never attaches, creates, resizes or sends shell input.
The socket exchange has one 3-second deadline; an old or silent
daemon reports ReadUnavailable. There is no legacy history fallback.
A bare target is local; host/target runs on the named SSH host.
Use a handle (s3) or an exact generation (s3.g7).
Generated invocations may use --local-only and --expect-backing ID.
Examples:
sox history s3 --tail 50
sox history ae-dev/s3.g7 --tail 200 --max-bytes 4096
sox new
Usage: sox new [host] [--no-attach] [--exec -- <argv>]
Create a persistent shell on the selected host and attach to it.
Always creates. To return to a shell that already exists, use
`sox attach <handle>` with a handle from `sox ls`.
Arguments:
host Host to ensure and create on; config default_host,
else localhost when omitted. No slug lookup.
Options:
--no-attach Run without interactive attach; stdout is exactly
<host>/<backing-id> remotely, bare backing id locally.
sox wait on that target returns the task's exit code.
--exec -- <argv> Run <argv> as the shell's child instead of a
login shell. Must be last; everything after --
is argv, passed through unmodified. To keep the
shell alive after it exits, pass a wrapper as
the argv (see `sox help agents`).
--env NAME=VALUE Set NAME in the minted shell. A shell's
environment is a declared value, not the
caller's map (REQ-LSX-109), so anything beyond
the login baseline and sox's own SOX_*/ZMX_*
variables is opt-in. Repeatable.
--inherit NAME Carry NAME across from this process. Repeatable.
-h, --help Show this help
Examples:
sox new
sox new ae-dev
sox new ae-dev --exec -- claude --resume
sox kill
Usage: sox kill <target>
sox kill --all <host> [--yes] [--home <path>]
Kill a shell by durable handle.
A bare target is this machine's shell, destroyed by this machine's
daemon; no other host is asked. `sox kill <host>/<name>` kills that
host's shell over SSH.
Arguments:
target A shell, in any of the four spellings `sox ls` prints
and `sox send` accepts:
s2 the handle column
s2.g48 the backing-id column; also
asserts that generation
alpha/s2 the shell on host alpha
alpha/s2.g48 both
host A configured host, as `sox host ls` names it
Kill-all obtains exact backing ids from a live daemon snapshot, prints
the resolved home and ids, and requires --yes or interactive assent.
An unreachable daemon refuses; no cached roster or slug selects shells.
Options:
--all Kill the printed snapshot on the required host
--yes Assent to that kill-all plan
--home <path> Assert kill-all's resolved home; never selects a home
--expect-backing <id>
Assert the backing behind the handle. Same assertion
as the `s2.g48` target above. Naming a different
generation than the target is refused.
--local-only
Refuse a shell on another host. A qualified kill
sends it to that host's daemon.
--prove-gone
Assert the shell's process is already gone. Use it
when the process was killed outside sox: the row
survives, `sox ls` still shows it live, and a plain
kill refuses because the daemon cannot tell that
absence from a daemon rebinding its socket. Refuses
if the socket answers.
-h, --help Show this help
Examples:
sox kill s37
sox kill ae-dev/s2.g48
sox kill --all ae-dev --yes
sox kill s3 --prove-gone
sox kill
Usage: sox kill <target>
sox kill --all <host> [--yes] [--home <path>]
Kill a shell by durable handle.
A bare target is this machine's shell, destroyed by this machine's
daemon; no other host is asked. `sox kill <host>/<name>` kills that
host's shell over SSH.
Arguments:
target A shell, in any of the four spellings `sox ls` prints
and `sox send` accepts:
s2 the handle column
s2.g48 the backing-id column; also
asserts that generation
alpha/s2 the shell on host alpha
alpha/s2.g48 both
host A configured host, as `sox host ls` names it
Kill-all obtains exact backing ids from a live daemon snapshot, prints
the resolved home and ids, and requires --yes or interactive assent.
An unreachable daemon refuses; no cached roster or slug selects shells.
Options:
--all Kill the printed snapshot on the required host
--yes Assent to that kill-all plan
--home <path> Assert kill-all's resolved home; never selects a home
--expect-backing <id>
Assert the backing behind the handle. Same assertion
as the `s2.g48` target above. Naming a different
generation than the target is refused.
--local-only
Refuse a shell on another host. A qualified kill
sends it to that host's daemon.
--prove-gone
Assert the shell's process is already gone. Use it
when the process was killed outside sox: the row
survives, `sox ls` still shows it live, and a plain
kill refuses because the daemon cannot tell that
absence from a daemon rebinding its socket. Refuses
if the socket answers.
-h, --help Show this help
Examples:
sox kill s37
sox kill ae-dev/s2.g48
sox kill --all ae-dev --yes
sox kill s3 --prove-gone
sox which
Usage: sox which <pid>
Name the shell a process is running inside.
Prints that shell's backing id -- the spelling `sox send` and
`sox kill` take -- and nothing else, so it composes:
sox send "$(sox which $AGENT_PID)" --enter -- "..."
The pid may be the shell's own or any descendant of it: the walk
climbs parents until it reaches a shell this home is running, and
answers with the nearest one. A pid that belongs to no shell here
is refused rather than answered with a guess.
The shells and their pids are this home's daemon's answer. When
the daemon does not answer, the verb fails and names why.
This machine's shells only. A pid is a number on one host, so
naming a remote one here would answer about whichever local
process happens to hold it; run `sox which` on that host instead.
Options:
-h, --help Show this help
sox label
Usage: sox label [<host>/]<backing-id> [k=v ...]
Set or print the durable labels on one backing.
A label is an assignment the operator makes about a shell, so two
shells opened in one worktree can be told apart by something that
outlives the mint directory: `sox ls` shows them beside the row, and
`sox send --expect-label k=v` refuses a target that does not match.
sox label s3.g441 lane=theme-slot launcher=yolosol native=<uuid>
sox label s3.g441 # print what it carries
sox label ae-dev/s3.g441 lane=theme-slot # a shell on host ae-dev
Keys are one line each; labels are stored with the backing, not the
login session, so they survive a daemon restart and a redeploy. A new
generation (`s3.g442`) starts with none -- labels belong to the
backing, not the handle slot.
The backing id is required, never a bare handle: a handle is
lineage-blind, so `s3` could name either generation.
A bare backing is this machine's; a host-qualified one asks only
that host's daemon, over SSH.
Options:
-h, --help Show this help
sox watch
Usage: sox watch [<host>/]<backing-id> --until done|blocked|gone|exited [--timeout S]
Block until one backing reaches the named state, then print the
transition as one JSON line and exit 0.
sox watch s3.g441 --until done --timeout 30
sox watch ae-dev/s3.g441 --until blocked --timeout 30
{"backing_id":"s3.g441","state":"done","at_ms":1789535077969}
States:
done the attention broker observed the workload finish
blocked the workload is waiting on a person
gone the backing is no longer in this home's socket namespace
exited the owning daemon journaled the backing's death
The wait is bounded: absent --timeout it is 60 s. On timeout the last
observed state prints as one JSON line and the exit status is 3, so a
caller can tell "still working" from "never started". A watch whose
stdout lost its reader exits 141 and prints nothing. The wait reads
the attention broker's own state, never `sox ls` text.
A bare backing is this machine's; a host qualifier watches that
host's backing over SSH. The broker's store is the one agents
report to: SOX_ATTENTION_HOME when set, else SOX_HOME. When
SOX_HOME has no running daemon or no such backing, the daemon of
SOX_ATTENTION_HOME answers for it instead.
Polling backs off from 250 ms to 2 s. Every tick, for any state, asks
the owning daemon once whether the backing still exists: at most
--timeout/2 + 4 probes, plus up to two at start when
SOX_ATTENTION_HOME names another home. done and blocked also read the
broker's store each tick.
Options:
--until S Required. done, blocked, gone or exited
--timeout S Seconds to wait (default 60)
-h, --help Show this help
sox wait
Usage: sox wait [<host>/]<backing-id> [--timeout S]
Block until the backing's task exits, then exit with its code.
id=$(sox new ae-dev --no-attach --exec -- bash -lc 'false')
sox wait "$id" # ae-dev/sN.gM; exits 1 when the task exited 1
`sox wait` reads the death the owning daemon journals, never `sox ls`
text, so it still answers after the task exited and its row is
gone. `<host>/` names the daemon to ask, over SSH; a bare id is this
machine's. A remote `sox new --no-attach --exec` prints its id with
that host already in front.
The wait is bounded: absent --timeout it is 600 s, and a timeout
exits 3.
Exit codes:
0-255 the task's own exit code; a signal death, including
`sox kill`, is 128+signo
3 the timeout expired before the task exited
42 the backing is gone and no exit was recorded
141 stdout lost its reader (an interrupted remote wait); nothing
is printed
A backing minted without `--exec` runs a login shell and has no task to
complete; the wait refuses it by name rather than blocking.
A `sox wait` older than its daemon reads the retired exit receipt,
not the journal: started after the task exited, it exits 42 or 1
instead of the task's code. Upgrade the CLI to match the daemon.
Options:
--timeout S Seconds to wait (default 600)
-h, --help Show this help
sox completions
Usage: sox completions [--deadline-ms N]
Print shell handle completion candidates, one line each:
<handle><tab><cmd> <cwd>
A shell on another host is offered as <host>/<handle>.
Candidates come from the daemons that own the shells. A host that
does not answer inside the deadline contributes no candidates and
no error: a shell prompt completing a word has nowhere to put one.
Options:
--deadline-ms N How long to wait per host, 1000..60000 ms
(default: 10000)
-h, --help Show this help
sox host
Usage: sox host ls
sox host rm <host>
The hosts this client connects to, kept in {SOX_HOME}/config.json.
`sox up <host>` adds a host the first time it connects; `sox ls` asks
every host listed here.
Subcommands:
ls List the configured hosts
rm <host> Remove a host from the list. It disconnects nothing and
kills no shell; the host returns on its next `sox up`.
Examples:
sox host ls
sox host rm ae-dev
sox daemon
Usage: sox daemon --ensure [--budget-ms=N]
sox daemon --stop
Start or stop the sox daemon for the resolved SOX_HOME. Each home
has its own daemon; `sox doctor` reports on that control plane.
Options:
--ensure Start the daemon if it is not already running
--stop Stop this home's daemon
--check-home Read this home's session state and exit 0 if this
binary can read it, non-zero with the refusal if it
cannot. Writes nothing, starts nothing.
--budget-ms=N Milliseconds to wait for readiness, 100-600000.
A value outside that range exits 2 naming it,
rather than silently using the default.
--home <path> Assert the home being acted on. A value that is not
the home this process resolved refuses before
anything is started, stopped, or read.
--foreign-home This call came from another machine's backend
deploy. It still migrates a plain deploy-target
home, but refuses one a Sox on that machine owns
(a `home-owner` marker), naming both schema
versions instead of locking that machine out of
its own state (REQ-LSX-110).
-h, --help Show this help
sox attention
Usage: sox attention [--state S] [--reason T] [--native-session ID] [--progress JSON] [--clear]
sox attention --doctor [--json]
Submit surface attention to the local broker. Agent plugins call
this from hooks; see `sox help agents` for the install procedure.
Submitting never blocks an agent. A submit that lands exits 0; a
rejected one exits 2 (usage: bad option or input, broker never
dialed) or 1 (delivery was not acknowledged; the update may have
applied) with the reason on stderr. The agent hooks discard both;
--doctor diagnoses the wiring. The doctor reads only; it submits
nothing.
Options:
--state <s> Attention state to report
--reason <t> Human-readable reason, truncated to 256 chars
--native-session <id> Optional harness session id (up to 256 bytes)
--progress <json> Token and cost figures from a statusline
--clear Clear this surface's attention
--doctor Diagnose bin/home/socket/key resolution
--json Machine-readable doctor output
-h, --help Show this help
sox pair
Usage: sox pair [options]
Enroll a phone onto the host you run this on. It takes no host
argument: the payload names the machine the phone will dial, so it
is minted there. Install Sox's `sox` command on the host's PATH
before running `sox pair` there. A backend deployed by Sox.app
alone does not install that command on PATH.
This machine mints the payload, prints a QR plus a pasteable line,
and serves the consume port until a phone authorizes its public key
or the token expires.
Options:
--name <n> Display name in the payload
--hostname <h> Hostname the phone should dial
--port <n> SSH port the phone should dial
--user <u> SSH user the phone should use
--sox-home <path> The home the phone should address. The ceremony
prints it either way; when SOX_HOME resolves to
one that is not this login's default (~/.sox) --
a direnv-pinned checkout is the standing case --
pairing is refused unless this flag names it.
--ttl <seconds> Token lifetime (default: 120)
--listen-port <n> Consume port to bind (default: kernel-chosen)
--advertise-port <n> Port to publish when NAT remaps the listener
--sshd <path> sshd whose host key to name (default: the one
serving the dialed endpoint, among all installed)
--host-key-pub <path> Add one trusted local public host-key file.
It adds an anchor; it does not select the pin.
--expect-fingerprint <SHA256:...>
Assert a complete canonical local fingerprint;
skips endpoint resolution and probing.
--json Read-only identity inspection (schema version 1).
Prints candidates and reruns; creates no token.
-h, --help Show this help
Pins always come from trusted local public files. The default probes the
advertised SSH endpoint. If resolution or every connection fails, one
unambiguous local key set permits automatic selection, labelled
"not probed from this machine". Ambiguity or an observed mismatch refuses.
Assert the highest-preference supported host key the serving sshd offers
to the phone: ECDSA P-256 > P-384 > P-521 > RSA. The phone negotiates this
order independently; asserting RSA on a server offering ECDSA will fail.
The phone verifies the pin in its SSH handshake before enrollment.
Examples:
sox pair
sox pair --hostname 127.0.0.1 --port 23117 --user root
sox pair --ttl 300
sox app
Usage: sox app list --home HOME [--host HOST] [--json]
sox app inspect --home HOME --app UUID [--host HOST] [--contents] [--json]
sox app split --home HOME --app UUID --pane UUID --direction D [--timeout-ms N] [--no-wait] [--json]
sox app detach --home HOME --app UUID --pane UUID [--timeout-ms N] [--no-wait] [--json]
sox app plan split|detach --home HOME --app UUID --pane UUID [--direction D] [--json]
sox app apply UUID --home HOME --app UUID [--timeout-ms N] [--no-wait] [--json]
sox app operation UUID --home HOME --app UUID [--json]
sox app wait UUID --home HOME --app UUID [--timeout-ms N] [--json]
sox app cancel UUID --home HOME --app UUID [--json]
sox app watch --home HOME --app UUID --since CURSOR [--timeout-ms N] [--json]
sox app capture --home HOME --app UUID --window UUID --output PATH [--json]
sox app accessibility --home HOME --app UUID --window UUID [--json]
sox app disconnect --home HOME --app UUID [--json]
Inspect and control one explicitly addressed Sox.app. HOME is always an
absolute desktop-endpoint home, never an inferred workload source. Add
--host HOST to any command to reach that endpoint over the existing SSH
transport. Split directions are right, left, up, and down.
Sox.app must launch with SOX_APP_CONTROL=local or be connected from its
application menu. Ordinary split/detach flush a receipt before apply; keep
its operation UUID if the connection is lost, then inspect/wait that UUID
instead of repeating the action. --no-wait reports acceptance only.
Exit: 0 success/accepted; 2 invalid; 3 timeout; 4 conflict; 5 unavailable;
6 failed; 7 cancelled; 8 version; 9 capacity/size; 10 too late;
11 OS observation unavailable.