Prized docs

Run commands and files.

Run a command on your box and get its exit code back, leave one running and check on it later, and copy files in either direction, from the CLI or from any script that holds a CLI token. Nothing to install on the box.

Run a command

prized exec -- make test

The command runs on the box under sh -c in your home directory; stdout, stderr, and the exit code come straight back, and your local stdin is connected. A suspended box wakes first. Use a box name before the -- to pick a box other than the configured one.

CommandWhat it does
prized exec -- npm testRun in your home on the default box; the exit code is npm test's.
prized exec box-a7f3 --cwd app -- npm testRun on a named box, in ~/app (--cwd takes a path relative to your home, or an absolute one).
prized exec --timeout 10m -- ./build.shKill the command after 10 minutes (TERM, then KILL 5 s later): exit 124, and stderr ends with a prized: command timed out after 600s (SIGTERM) line. No limit by default.
prized exec --env CI=1 --env NODE_ENV=test -- npm testAdd environment variables (repeatable, up to 32).
prized exec --json -- makeCapture instead of stream: one object with exitCode, signal, timedOut, stdout, stderr.
  • Quote as you would for ssh: the words after -- are joined with spaces and handed to sh -c, so prized exec -- 'cd app && npm test' runs both halves on the box.
  • The shell is a plain sh, not your login shell: tools that only your .bashrc puts on PATH need prized exec -- bash -lc 'npm test'.
  • For prized exec, --timeout is the command's time limit, not the network timeout the other commands use the flag for.
  • Exit code: the remote command's, or ssh's 255 when the box was unreachable. With --json the object's ok says whether the command ran and exitCode what it returned, and the process still exits with that code. timedOut is true only when the time limit ended the command (that trailer line is removed from stderr); a command that exits 124 on its own is exitCode: 124, timedOut: false.

Detached processes

prized exec --detach -- ./train.sh
# started p_3f9c0a1b2d4e (pid 41213) in /home/ubuntu

--detach starts the command and returns at once with a process id. The process outlives your terminal and the ssh session; its output goes to log files on the box.

CommandWhat it does
prized exec --detach -- CMDStart CMD detached (--cwd and --env apply) and print its id.
prized exec --status p_3f9c0a1b2d4eRunning or exited, the exit code or signal, start and finish times, and the tail of each log.
prized exec --status p_… --tail 1mHow much of each log to show: bytes, or 4k, 1m (the default is 16k, the cap 1m).
prized exec --kill p_3f9c0a1b2d4eStop it: TERM to its process group, then KILL if it is still there after 5 s.
prized exec --psEvery detached process on the box, running or finished.

--status, --kill and --ps never wake a suspended box (they exit 5 and say so); running a command does.

Everything about a detached process lives in one directory on the box, so ls, tail -f, and your own scripts see the same truth the CLI does:

File in ~/.prized/processes/<id>/Contents
cmdThe command line as given.
cwdThe absolute working directory it ran in.
pidThe process id (also its process group id).
boot_idThe box's boot id at start. After a reboot (a paused box resumes from one) the pid is not trusted: the process reads as lost and is never signalled.
started_atStart time, RFC 3339 UTC.
stdout.log, stderr.logThe output, appended as it happens.
exitWritten when the command ends: the exit code, or 128 + signal.

Log directories are never deleted for you. rm -r ~/.prized/processes/p_… on the box when you are done with one.

Copy files

prized cp ./notes.md :notes.md

prized cp works like scp: exactly one side is on the box, written BOX:PATH, and a bare :PATH means the configured box. Paths on the box are relative to your home there unless absolute. Files are written whole (a temp file, then a rename), so an interrupted copy never leaves a half-written target.

CommandWhat it does
prized cp ./file.txt :Copy a file into your home on the box, keeping its name.
prized cp -r ./site box-a7f3:wwwCopy a directory tree (-r is required for directories).
prized cp box-a7f3:logs/app.log ./Copy a file from the box into the current directory.
prized cp -r :proj/dist ./distCopy a directory tree from the box.

Modes are preserved; symlinks are skipped and counted. A progress line shows on stderr when it is a terminal. For a live view of the whole box in Finder rather than copies, see Mount.

The edge API

Everything above is also an HTTP API, for scripts and agents that hold a CLI token and have no prized installed. The token comes from Dashboard → Workspace → CLI tokens (or prized login --token); the base URL comes from GET /api/v1/me. The bearer must be a CLI token (dcp_…) or a dashboard terminal ticket (dtt_…): monitor tickets and mobile SSH passwords are refused, whatever else they can open.

export PRIZED_TOKEN=dcp_…
EDGE=$(curl -s -H "Authorization: Bearer $PRIZED_TOKEN" https://api.prized.dev/api/v1/me | jq -r .edge.url)

Every route is under $EDGE/v1/box/{box}/, where {box} is the box's name or id, with the token as the bearer. Paths on the box are read the way prized cp reads them: relative paths and ~/… are under your home, absolute paths are taken as is. POST /exec wakes a suspended box; every other route never does (they answer box_not_running).

RouteBody or queryAnswer
POST /exec{command, cwd?, timeoutSeconds? (1 to 600, default 30), env?, detached?}exec.result: exitCode, signal, stdout, stderr, stdoutTruncated, stderrTruncated, timedOut, startedAt, finishedAt, cwd
POST /exec with "detached": truesameexec.started: processId, pid, cwd, startedAt, logPath
GET /execexec.list: processes[] with processId, pid, running, lost, exitCode, signal, startedAt, command
GET /exec/{processId}?tail=tail in bytes (default 16384, max 1048576)exec.status: the list fields plus finishedAt, cwd, stdout, stderr, stdoutTruncated, stderrTruncated
DELETE /exec/{processId}exec.killed: wasRunning, signal (TERM, or KILL when TERM was not enough)
GET /files?path=file.read: path, encoding (utf8 or base64), size, mode, content; files over 1 MiB answer 413 and point at /download
PUT /files{path, content, encoding? (utf8 or base64), mode? ("0644")}file.written: path, size
GET /download?path=The file as application/octet-stream, or a directory as application/x-tar (X-Prized-Content: directory)
PUT /upload?path=&mode=The raw file as the bodyfile.uploaded: path, size

Every JSON answer carries ok: true and a type. timedOut is set only when the box's time limit ended the command (signal then says TERM, or KILL when TERM was not enough); a command that exits 124 by itself is exitCode: 124, timedOut: false. Paths are resolved on the box (symlinks followed) and echoed back as path, so you always see what was actually touched. A synchronous run that outgrows 1 MiB per stream keeps the last 1 MiB and sets the Truncated flag; use a detached run and /download on its log for the whole thing.

# run a command and read its exit code
curl -s -X POST "$EDGE/v1/box/box-a7f3/exec" -H "Authorization: Bearer $PRIZED_TOKEN" -H "Content-Type: application/json" -d '{"command":"npm test","cwd":"app","timeoutSeconds":300}' | jq '{exitCode, timedOut, stdout}'

# start something long, then poll it
curl -s -X POST "$EDGE/v1/box/box-a7f3/exec" -H "Authorization: Bearer $PRIZED_TOKEN" -H "Content-Type: application/json" -d '{"command":"./train.sh","detached":true}'
curl -s "$EDGE/v1/box/box-a7f3/exec/p_3f9c0a1b2d4e?tail=4096" -H "Authorization: Bearer $PRIZED_TOKEN"
curl -s -X DELETE "$EDGE/v1/box/box-a7f3/exec/p_3f9c0a1b2d4e" -H "Authorization: Bearer $PRIZED_TOKEN"

# files
curl -s "$EDGE/v1/box/box-a7f3/files?path=app/package.json" -H "Authorization: Bearer $PRIZED_TOKEN" | jq -r .content
curl -s -X PUT "$EDGE/v1/box/box-a7f3/files" -H "Authorization: Bearer $PRIZED_TOKEN" -H "Content-Type: application/json" -d '{"path":"app/.env.test","content":"CI=1\n","mode":"0600"}'
curl -s -X PUT "$EDGE/v1/box/box-a7f3/upload?path=data/train.bin" -H "Authorization: Bearer $PRIZED_TOKEN" --data-binary @train.bin
curl -s "$EDGE/v1/box/box-a7f3/download?path=app/dist" -H "Authorization: Bearer $PRIZED_TOKEN" -o dist.tar

Errors

A failed request answers {"ok": false, "error": {"code", "message"}} with one of these codes:

HTTPerror.codeMeaning
401unauthorizedNo bearer, a token the control plane rejected, or a credential of another class (a monitor ticket, a mobile SSH password).
404not_foundNo such box on this account, no such process, no such path (or parent directory), or no such route.
405method_not_allowedA known route with the wrong method; Allow lists the right ones.
409box_not_runningAny route but POST /exec on a suspended box; the message names the route and how to wake the box.
400invalid_requestThe body is not the documented shape (bad JSON, empty command, a bad env name or mode).
400invalid_timeouttimeoutSeconds outside 1 to 600.
400invalid_pathA path with a NUL or newline byte, a directory where a file was expected, or no path.
403permission_deniedThe box's account cannot read or write that path.
413payload_too_largeOver the inline (1 MiB) or transfer (1 GiB) cap.
429rate_limitedToo many requests for this token or box; Retry-After says when.
502box_unreachableThe box could not be reached, or did not wake in time.
502exec_failedThe ssh session or the on-box script failed; the message carries the box's own words.
5xxcontrol_plane_unavailableThe control plane could not be reached to check the token.

Limits

WhatLimit
Synchronous run600 s (the CLI has no limit unless --timeout)
Output kept per stream1 MiB (the last 1 MiB; flagged as truncated)
Inline file read or write1 MiB
Upload or download1 GiB
Environment variables per run32
Concurrent requests per token, per box8
Sustained request rate per token20 per second

A detached process has no time limit. A directory download is bounded by the 1 GiB cap: when it is reached, tar is stopped on the box and the connection is cut, so a truncated archive never looks complete.

Something unclear or out of date?

On this page