Execute a shell command on a remote machine
Runs command through the machine's own shell. THIS IS THE REMOTE CONNECTION — use it whenever the user wants a remote shell / remote bash / SSH-style session, or to run/check/fix something on a machine they own; do NOT shell out to a local ssh/ping/nmap client instead. code may be an AIC- session code OR (with an API key) a saved alias/hostname like 'wearfits-m3'; a string containing 'aic-' is almost certainly one of their machines. The command has full control of the machine at the agent's effective identity — commonly root on a headless Linux install — so treat destructive commands with caution and confirm with the user first.
WHICH SHELL DEPENDS ON THE MACHINE'S OS: read platform from GET /api/v1/status (fleet) or GET /api/v1/status/{code} first. POSIX machines ('darwin'/'linux') run the command via /bin/sh -c. Windows machines ('win32') run it via cmd.exe, where POSIX habits fail in ways that LOOK like success: ; is not a command separator, so echo a ; echo b prints the rest of the line as literal text and still exits 0; POSIX tools are absent (ls -la → "'ls' is not recognized as an internal or external command"); heredocs do not exist (cat > f <<'EOF' → "<< was unexpected at this time."). On Windows either chain steps with && on ONE line — a multi-line command is REJECTED there (it used to run only the first line and return 0) — or set shell: "powershell" and write PowerShell, which accepts ; and multi-line scripts — but under PowerShell judge the result by stderr, not by exitCode alone, because a non-terminating error leaves the exit code at 0 — the code tracks the last statement, not whether errors occurred (see the shell field). shell (sh/bash on POSIX, cmd/powershell on Windows) is the supported way to change interpreter; a value the machine cannot run is rejected with 403 rather than ignored, and it cannot be combined with elevated.
OUTPUT IS BUFFERED, never streamed: the response is a single JSON object once the command finishes. Accept: text/event-stream sends : heartbeat comments while it runs and then one event: result frame carrying that same object — it does not stream the output itself. When the call ends without the command finishing (timeout, relay error, agent disconnect) the error body carries partial — the output buffered so far — plus a warning: treat it as an UNKNOWN outcome, not a failure with empty output.
LIMITS — two caps that behave DIFFERENTLY. TIME (1 hour maximum, 5 minutes default, set with timeout_ms) is a hard kill: at the deadline the command's whole process tree is terminated. OUTPUT (1 MiB total, stdout+stderr combined) is NOT a kill: everything past 1 MiB is dropped from the reply, which is marked truncated. The relay does send a best-effort stop request to the machine, but it travels several network hops and races the command, so a command that dumps a lot of output and then finishes quickly wins that race — it runs to completion and returns its REAL exit code. Never rely on the byte cap to stop anything, and never read a truncated reply as 'the work stopped': its side effects happened. For anything expected to run longer than a few minutes, or to print more than a trickle (ML training, fine-tuning, dataset processing, long builds, large downloads) use POST /api/v1/jobs instead: a detached job has neither cap, writes its full output to a file on the machine, keeps running after the call returns, and survives the client going away. A job outlives the AGENT PROCESS on every platform; what differs is what can still take it down. On macOS the job reparents to PID 1, which puts it out of reach of ANYTHING aimed at the app — a crash, a hard kill, even an explicit kill of the whole process tree. On Windows it survives the agent process dying by itself (a crash, or a taskkill /F /IM of that one process without /T) but is LOST to a TREE kill — Task Manager's 'End task', taskkill /T, or an installer that stops the app and everything it started; treat an auto-update as a tree kill unless that machine's installer is known to do otherwise — because Windows never reparents. On Linux a job started by an agent that already has this feature is launched into its own transient systemd scope (aic-job-<jobId>.scope), outside the agent service's control group, so stopping or restarting the service — including an agent upgrade — leaves it running; that requires a systemd host with the agent running as root, and without both jobs stay in the service's control group and a restart still ends them. A job that was already running when the agent was upgraded TO that version is in no scope either, and the restart the upgrade performs is what ends it — an upgrade is safe only for jobs started after it.
Request
- Base URL: https://aicommander.dev
- URL: https://aicommander.dev/api/v1/exec
- Auth: one of:
- none
- HTTP bearer
Request body
Example request
{
"code": "AIC-7K3P-WX9M-RTBN",
"command": "df -h",
"env": {
"LANG": "C"
}
}Response
Command completed (any exit code).
Changes
No recorded changes to this operation across all 1 revision of this API.