Skip to main content
A job is a managed run of a command or script — on a new sandbox (created for the run and, by default, deleted once it ends) or an existing one. Jobs exist for the common case of “run this and tell me what happened,” without you having to hold a sandbox handle open, poll exec yourself, or clean up afterward.
A job is not a replacement for exec or managed sessions — it’s a layer above them that also owns sandbox lifecycle for the run. Use exec or a session when you already have a sandbox and want to run something on it directly; use a job when you want the run tracked as its own resource, optionally on a sandbox created and torn down just for it.

Creating a job

POST /v1/job either blocks for the result or starts durably and returns immediately, controlled by the wait body field (default false).
There’s no bonya job CLI command — jobs are reached through REST or an SDK. MCP: job_create covers both modes — pass wait: true to block for the result or leave it false to get a run_id back immediately. The request body (JobRequest) requires exactly one of existing_sandbox_id/new_sandbox, and exactly one of cmd/script:
string
Run on a sandbox that already exists. Mutually exclusive with new_sandbox.
object
Create a sandbox for this run. { template_id?, version?, name? } — template_id may be omitted to use the deployment’s configured default template, the same as sandbox create.
string[]
Argv to run. Mutually exclusive with script.
object
{ body_b64, interpreter?, args?, filename? } — a script the caller wrote or uploaded, run instead of cmd. The body travels inline and is size-capped.
object
Optional script (same shape as script) executed after the sandbox is ready and before the job’s own command or script. A non-zero exit stops the job before it runs.
object
Extra environment variables for the job.
string
Working directory for the job.
string
default:"delete"
delete or keep — what happens to a sandbox this run created once the run ends, however it ends (including cancellation). Not meaningful for existing_sandbox_id.
boolean
default:"false"
Applies to existing_sandbox_id only. false makes a suspended target a failure rather than an implicit resume, since resuming is a billable action the caller may not have intended.
boolean
default:"false"
false starts the run durably and returns immediately with a run_id (202). true blocks for the result, bounded by the caller’s own request timeout (200).
Create also accepts an Idempotency-Key header — see Idempotency.
There is no endpoint to edit a run in place. To “edit and rerun” one: fetch its stored spec with GET /v1/job/{run_id}, change what you need, and POST it to /v1/job as a new run.

Run lifecycle

A run’s status moves through the states the job’s own command or script produces, ending in a terminal state that carries a result (exit_code, captured output, and similar exec-style fields). Whether you passed wait: true or not, the same result shape appears once the run completes — wait only controls whether the create call itself blocks for it.

Listing and inspecting runs

GET /v1/job is paginated, newest first; optionally filtered to sandbox_id or schedule_id (runs fired by a job schedule). GET /v1/job/{run_id} returns the full run detail: the run summary plus the stored job spec that started it and an activity timeline. This is the endpoint to call before an edit-and-rerun, described above.
There’s no bonya job CLI command. MCP: job_list pages through runs; job_get returns one run’s full detail.

Canceling a run

POST /v1/job/{run_id}/cancel requests cancellation rather than forcibly terminating — the run’s own cleanup (for example, deleting a sandbox it created, per disposition) still executes before the run reaches its terminal state.
There’s no bonya job CLI command. MCP: job_cancel requests cancellation the same way.

Job schedules

A job schedule wraps a job spec with timing, so it runs on its own without a caller invoking create each time.
There’s no bonya job-schedule CLI command. MCP: job_schedule_create covers this.
string[]
Cron expressions to fire on. Exactly one of cron_expressions/interval_s/run_at_unix_nanos is required.
integer
Fire every N seconds.
integer
One-shot: a single future calendar time. Refused if it names a time in the past — a one-shot schedule is this field set, not a separate mechanism.
string
IANA zone (e.g. US/Pacific) that cron_expressions is evaluated against. Empty is UTC.
integer
Random delay added to each fire, in seconds.
string
default:"skip"
What a fire does when the previous run from the same schedule is still going: skip (drop the new fire), buffer_one, or allow_all.
boolean
default:"false"
Create the schedule already paused.
object
required
The job spec to run on each fire — same shape and same-field requirements as job create, above.
PATCH /v1/job-schedule/{schedule_id} replaces the whole schedule — timing and job spec together — so re-send every field you want to keep, not just the one you’re changing. GET /v1/job-schedule/{schedule_id} returns the schedule’s timing, stored job spec, pause state, next run time, and its recent run ids: the last 10 fires (oldest first, including manual triggers), each a valid GET /v1/job/{run_id} id — enough to follow a schedule straight to its recent runs without a separate list call. POST /v1/job-schedule/{schedule_id}/pause sets the paused state without deleting the schedule. POST /v1/job-schedule/{schedule_id}/trigger fires one run immediately, ignoring the schedule’s own timing — useful for testing a schedule without waiting for it. DELETE /v1/job-schedule/{schedule_id} permanently removes it, without canceling any run currently in flight.
There’s no bonya job-schedule CLI command. MCP: job_schedule_list and job_schedule_trigger cover the calls above (plus job_schedule_get, _update, _pause, and _delete for the rest of the surface).

Sandboxes

Templates

Exec

Idempotency