Prompt an agent remotely
Prompt Claude Code, Codex, OpenCode or pi on your box from your machine or any script, on the model and backend you pick, follow the run as it happens, and interrupt it; the run lives on the box, so nothing depends on your laptop staying open.
On this page13
Prompt the agent
prized prompt --provider claude "fix the failing tests in app/ and run them again"This starts a headless Claude Code run on the box (claude -p, in your home directory), streams its events to your terminal, and exits when the agent is done. The first prompt installs three small helper scripts on the box; the first OpenCode or pi prompt also installs that agent (OpenCode and pi).
| Command | What it does |
|---|---|
prized prompt --provider claude "…" | Run Claude Code on the default box and follow it. --provider codex, opencode or pi runs that agent. |
prized prompt box-a7f3 --provider codex --cwd app "…" | Run on a named box, in ~/app (--cwd is relative to your home, or absolute). |
prized prompt --provider claude --model opus --effort high "…" | Pick the model and the reasoning effort (low, medium, high). |
prized prompt --provider codex --model deepseek/deepseek-flash "…" | Run on another backend: amazon-bedrock/…, openrouter/… or deepseek/… (Models and backends). |
prized prompt models | The known --model values per agent and backend, with the efforts each takes (--provider narrows it). |
prized prompt --provider claude --continue "…" | Continue the provider's newest session on the box instead of starting fresh. |
prized prompt --provider claude --conversation cv_… "…" | Continue that conversation with the provider you name. See Conversations. |
prized prompt --provider claude --auto "…" | Let the agent edit and run commands without approvals. See Approvals. |
prized prompt --provider claude --detach "…" | Start the run and print its id; follow it later with prized events. |
prized prompt --provider claude --queue "…" | Run after the conversation's turn in progress instead of refusing. |
cat brief.md | prized prompt --provider claude - | Read the prompt from stdin. |
prized prompt conversations | Every conversation on the box, most recently active first, with its prompt count and whether a turn is running. |
prized prompt ls | Every run on the box, newest first (at most 50), with its state and conversation; --conversation cv_… keeps to one. |
prized events --follow | Follow every run in progress until none is left (or show the newest run); --conversation cv_… keeps to one conversation, --run pr_… follows one run, --after N starts after event N. |
prized interrupt | Stop every run in progress (TERM to each one's process group, KILL after 5 s); --conversation cv_… stops one conversation's, --run pr_… one run. |
- Output: the agent's text, each tool call and result as one dim line, and a last line with the verdict and event count;
-vadds the provider's system events. - Exit code: 0 when the run ends cleanly; 1 when the provider's last verdict is an error (one it retried past does not count), it exits non-zero, or the run was interrupted; 130 on Ctrl-C, which also interrupts the run on the box (
prized events --followleaves the run alone on Ctrl-C). - The prompt travels as a file, never on a command line, so it stays out of the box's process list and shell history.
- Several runs at once:
prized events --follownames each run as it starts and, while more than one is in progress, starts each line with its conversation id; its exit code is the worst of the runs it followed. - Waking:
prized promptwakes a suspended box;prized events,prized prompt ls,prized prompt conversationsandprized interruptdo not.
Sign in first
The agent runs as you, with a credential already on the box. Without one, prized prompt refuses with provider_not_signed_in and names what to set. It looks in a login shell for:
| Agent | Credential |
|---|---|
| Claude Code | ~/ (hand yours over with prized agents handoff claude), CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, or CLAUDE_CODE_USE_BEDROCK |
| Codex | ~/.codex/auth.json (prized agents handoff codex), OPENAI_API_KEY or CODEX_API_KEY |
| OpenCode | Nothing required: with no key it offers only its free models; opencode auth login on the box or a provider key opens the rest |
| pi | ~/.pi/agent/auth.json (pi, then /login on the box) or any provider key, such as ANTHROPIC_API_KEY or OPENROUTER_API_KEY |
| Any agent on a backend | That backend's key (Keys for other agents and backends) |
Models and backends
--model takes the agent's own model ids and aliases. Written as <backend>/<model id>, it runs the agent on that backend with the key you set on the box as a Secret or env var:
| Prefix | Backend | Claude Code | Codex | Example |
|---|---|---|---|---|
amazon-bedrock/ | Amazon Bedrock in your AWS account | Bedrock inference profile ids and ARNs | Bedrock's openai.* models | amazon-bedrock/ |
openrouter/ | OpenRouter | Any OpenRouter id | Ids that serve the Responses API | openrouter/ |
deepseek/ | DeepSeek | deepseek-flash, deepseek-v4-pro | Same | deepseek/deepseek-flash |
OpenCode and pi already name models as provider/model, so the same strings work for them unchanged, along with every other provider they support (opencode models and pi --list-models on the box list them). The prefix applies per run and never edits the agent's config files; a model with no prefix runs on whatever the agent is set up for.
prized prompt models lists known ids per agent and backend. Bedrock grants model access per AWS account and region: a model your account has not enabled fails with Bedrock's error.
--effort maps onto each agent's own control: claude --effort, Codex's model_reasoning_effort, opencode run --variant (a model without that variant ignores it), pi --thinking (clamped to what the model supports). DeepSeek models take low and high.
Approvals
By default the agent can edit files but not act freely, since a headless run cannot ask you; --auto lifts that, which "run the tests and fix them" needs. Each agent draws the line its own way:
| Agent | Default | --auto |
|---|---|---|
| Claude Code | claude --permission-mode acceptEdits: edits allowed, commands denied | claude --dangerously-skip-permissions |
| Codex | Its workspace-write sandbox: edits and commands inside the working directory, no network | codex --dangerously-bypass-approvals-and-sandbox |
| OpenCode | Shell commands set to ask, which a headless run answers with a rejection; edits and its other tools as configured | opencode run --auto: every permission not explicitly denied is approved |
| pi | pi has no approvals, so its bash tool is left out: read, edit, write, grep, find, ls | The same tools plus bash |
MCP tools stay available to OpenCode and pi in both modes.
Continuity
--continue resumes the newest session of the same provider on the box, so "now also update the docs" works; --conversation resumes a given one. Each agent resumes in its own way: claude --resume <id>, codex exec resume <id>, opencode run --session <id>, pi --session-id <id>. Claude Code and pi keep sessions per working directory, so continue from the same --cwd. prized prompt ls --json shows each run's sessionId and resumedFrom. With no earlier session on the box, --continue refuses (exit 5, no_session_to_continue on the API) rather than starting fresh.
Conversations
Every prompt is a turn of a conversation: one provider session, with the agent's memory of the turns before it. A conversation's id looks like cv_0123456789ab; prized prompt prints it as the run starts, --json and the API answer it as conversationId, and prized prompt conversations lists them.
| Flag | The turn's conversation |
|---|---|
None, or --new | A new one, which runs beside the others. |
--continue | The provider's newest conversation on the box (Continuity). |
--conversation cv_… | That one; explicitly name its provider with --provider. |
- Choose the provider locally:
--provideris required on every prompt, including--conversation. If omitted, the CLI exits 2 before reading stdin or contacting the box. Conversation files on the box are mutable, so they cannot authorize which agent receives your next prompt. This does not protect prompts or credentials from a compromised box. - One provider per conversation: a prompt for a conversation with another
--providerrefuses (exit 5,provider_mismatch). All four agents hold conversations the same way, and the first turn of OpenCode or pi installs it if needed. - Model per turn: each turn takes its own
--modeland--effort, a backend included; the conversation lists its newest turn's model. - Pauses: conversations are files on the box, so they survive a pause and ride snapshots and forks; continue one by id afterwards.
Parallel runs and the queue
A box runs several conversations at once, up to its limit: one run in progress per 2 GB of the box's memory, at most 16 (Limits). A new run beyond it answers prompt_limit_reached (exit 6). To change the limit, write a number from 1 to 64 to ~/ on the box; each run is a full agent process, so raise it only on a box with memory to spare.
A conversation takes one turn at a time. A prompt for a conversation with a turn in progress answers prompt_in_progress (exit 6); with --queue it waits and runs when that turn ends, continuing its session. --queue with no other flag joins the provider's newest turn in progress, so a --queue "then lint" right after a prompt still follows it; with nothing in progress it starts a new conversation.
Two commands on the box do the same, so a setup script or the agent itself can drive it:
queuePrompt "then run the linter and fix what it finds"
stopAgent| Command | What it does |
|---|---|
queuePrompt "…" | Queue a prompt (from its arguments, or stdin): inside a run, behind that run's conversation; elsewhere behind the newest run in progress; with nothing running, after the next run to finish. PRIZED_CONVERSATION=cv_… queuePrompt "…" picks the conversation. |
stopAgent | Stop every run in progress; stopAgent cv_… stops one conversation's. |
Both are in ~/.prized/bin, on the PATH of login shells after the first prompt. A run sees its own conversation and run id as PRIZED_CONVERSATION and PRIZED_RUN.
- A queued prompt keeps its request: a
--queueprompt keeps its own model, effort, working directory and--auto; aqueuePromptone inherits them from the run it follows. - An interrupted run leaves its conversation's queue for that conversation's next turn.
Where a run lives on the box
Each run is a directory on the box, so it survives a pause, rides a snapshot, and reads with ls and tail -f:
File in ~/.prized/prompts/<run id>/ | Contents |
|---|---|
prompt.txt, meta.json | The prompt as given; provider, model, reasoning effort, and whether --auto was on. |
cmd, next | The provider command line for this run, and the one a continuation uses. |
cwd, pid, started_at, exit | The working directory, the process group id, the start time, the exit code when done. |
events.jsonl, stderr.log | The provider's raw event stream (claude --output-format stream-json, codex exec --json, opencode run --format json, pi --mode json) and its stderr. |
session, resume, parent | The provider's session id once seen; for a continued run, the session it resumed; for a queued one, the run it followed. |
conversation | The conversation the run is a turn of. |
interrupted | Present when prized interrupt or stopAgent stopped the run. |
~/ holds a conversation's queued prompts, one directory each; ~/.prized/prompts/queue/ holds the ones queued with nothing running.
JSON and JSON Lines
--json on prized prompt prints the started run as one object and does not follow. --jsonl follows and prints one normalized event per line; with prized events --jsonl, it is the only command that prints more than one JSON document. A follow of several runs (prized events --follow without --run) adds runId and conversationId to each event.
{"seq": 7, "type": "tool_use", "text": "Let me run the suite.", "tool": {"name": "Bash", "input": {"command": "npm test"}}, "raw": {…}}| Field | Meaning |
|---|---|
seq | The event's line number in events.jsonl, from 1; paging and --after use it (a page holds up to 200 events or 1 MiB). |
at | The provider's timestamp, when the line carries one. |
type | system, assistant, tool_use, tool_result, result, error, or raw for a line the mapping does not know. |
text | The readable content: the agent's text, a command, a tool's output, the final answer, an error (capped at 8 KiB). |
tool | For tool events, {name, input}; Codex's are command_execution, file_change, mcp_tool_call (server/tool), web_search. |
raw | The provider's line as written. |
The agents differ in what they report, and the mapping keeps one line per event:
- OpenCode reports a tool call once, when it finishes, so each is one
tool_resultcarrying the tool, its input and its output. The last step's finish is theresult; an error event iserror. - pi streams token deltas as
systemevents with no text; each finished message is oneassistantevent, tool calls aretool_usethentool_result, and the run's final answer is theresult. A failed model call is anerrorevent, and pi may retry past it; a run whose last model call failed exits 1, so its status isfailedinprized prompt lsand the API too.
A run object (prized prompt --json, prized prompt ls --json, prized events --json) has id, provider, model, reasoningEffort, auto, status (running, done, failed, interrupted), exitCode, pid, cwd, startedAt, finishedAt, sessionId, resumedFrom, parent, eventCount, prompt.
Runs also carry conversationId. A conversation object (prized prompt conversations --json, under conversations beside running and limit) has id, provider, model (its newest turn's), prompts (turns so far), queued, running, lastRunId, lastStatus, sessionId, lastPrompt (the first 160 bytes), createdAt, updatedAt.
The edge API
The same surface is HTTP for scripts that hold an API key, under $EDGE/v1/box/{box}/ with the key as the bearer, found as for running commands:
| Route | What it does |
|---|---|
POST /prompts | Starts or queues a run; new, conversationId and continue pick its conversation. The only route that wakes a suspended box. |
GET /prompts | Lists runs; conversation=cv_… keeps to one. |
GET /prompts/conversations | Lists conversations. |
GET /prompts/{runId}/events | Pages the events, or streams them as Server-Sent Events (follow=1, or Accept: text/event-stream); a stream holds one of the token's concurrent request slots until the run ends. |
GET /prompts/events | Streams every run in progress as Server-Sent Events until none is left; conversation=cv_… keeps to one. |
POST / | Stops a run. |
POST /prompts/interrupt | Stops every run in progress; conversation=cv_… stops one conversation's. |
Bodies and answers are on API reference: Prompts and events.
Errors
A failed request answers {"ok": false, "error": {"code", "message"}}. Beyond the shared edge codes, these routes add invalid_provider, prompt_required, invalid_request, prompt_in_progress, provider_not_signed_in, provider_not_installed and no_session_to_continue (API reference: Errors). provider_not_installed also answers an OpenCode or pi install that failed, with the reason (no network, or a checksum that no longer matches the pin). From the CLI, a run in progress exits 6 (CONFLICT) and the rest exit 5 (CHECK_FAILED) with a hint.
Conversations add prompt_limit_reached (the box is at its limit; exit 6 from the CLI) and provider_mismatch (conversationId names a conversation of another provider; exit 5), and prompt_in_progress names the conversation whose turn is in progress.
Limits
Every cap for prompts, runs, and events is on Limits.
Compared with prized agents run
prized agents run starts the agent interactively in a tmux session you attach to and approve things in; prized prompt is the headless form, with a verdict at the end and an API for scripts. Both use the box's sign-in, and both install OpenCode and pi on first use.