jobs
GET /jobs
The calling studio's jobs, of every kind, newest first.
R40. Only the token's studio: its install, build, download, update, export and uninstall jobs, and the task jobs it reported. Never another studio's (M4 first review, #2).
Needs the jobs capability.
| Go | List(ctx context.Context, params *JobsListParams) (*JobPage, error) |
|---|---|
| Python | def list(self, *, limit: Optional[Any] = None, cursor: Optional[Any] = None) -> Any |
| JavaScript | list(params = {}) |
| Parameter | In | Type | About |
|---|---|---|---|
| limit | query | integer | |
| cursor | query | string | The `next_cursor` of the previous page, unchanged. |
| Status | Body | Means |
|---|---|---|
| 200 | JobPage | A page of jobs. |
| 400 | Error | The request is malformed. Codes: `bad_request`, `bad_filter`, `bad_cursor`, `invalid_document`. |
| 401 | Error | No studio token, or a revoked or unknown one. Code `unauthenticated`. |
| 403 | Error | The token lacks a capability (`capability_required`, with `details.capability`), the job is not a task the studio may change (`not_a_task`), or the request came from another origin (`bad_origin`). |
POST /jobs
Report a long-running piece of the studio's own work as a task job.
R40, Q24. The daemon runs nothing: the studio updates progress and state with PATCH, appends log lines, and ends the job itself. The job starts `running` unless `state: queued` is given.
Needs the jobs capability.
| Go | Create(ctx context.Context, body TaskCreate) (*Job, error) |
|---|---|
| Python | def create(self, body: Dict[str, Any]) -> Any |
| JavaScript | create(body) |
Request body: TaskCreate (application/json)
| Status | Body | Means |
|---|---|---|
| 201 | Job | The new task job. |
| 400 | Error | The request is malformed. Codes: `bad_request`, `bad_filter`, `bad_cursor`, `invalid_document`. |
| 401 | Error | No studio token, or a revoked or unknown one. Code `unauthenticated`. |
| 403 | Error | The token lacks a capability (`capability_required`, with `details.capability`), the job is not a task the studio may change (`not_a_task`), or the request came from another origin (`bad_origin`). |
GET /jobs/{id}
One of the calling studio's jobs. Another studio's is 404.
Needs the jobs capability.
| Go | Get(ctx context.Context, id string) (*Job, error) |
|---|---|
| Python | def get(self, id: str) -> Any |
| JavaScript | get(id) |
| Parameter | In | Type | About |
|---|---|---|---|
| id | path · required | ULID |
| Status | Body | Means |
|---|---|---|
| 200 | Job | The job. |
| 401 | Error | No studio token, or a revoked or unknown one. Code `unauthenticated`. |
| 403 | Error | The token lacks a capability (`capability_required`, with `details.capability`), the job is not a task the studio may change (`not_a_task`), or the request came from another origin (`bad_origin`). |
| 404 | Error | Absent, deleted, or not the caller's to see. Code `not_found`. |
PATCH /jobs/{id}
Report progress on, or finish, a task job the calling studio created.
Q24, M4 first review #11. A JSON merge patch. State may move `queued → running`, and from either to `succeeded`, `failed` or `cancelled`; a finished job cannot change (409 `job_finished`). `progress_num` must not exceed `progress_den`. `last_error: null` clears it. Only the studio's own `task` jobs: another studio's job is 404, and one of its own lifecycle jobs is 403 `not_a_task`.
Needs the jobs capability.
| Go | Update(ctx context.Context, id string, body map[string]any) (*Job, error) |
|---|---|
| Python | def update(self, id: str, body: Dict[str, Any]) -> Any |
| JavaScript | update(id, body) |
| Parameter | In | Type | About |
|---|---|---|---|
| id | path · required | ULID |
Request body: TaskUpdate (application/merge-patch+json)
| Status | Body | Means |
|---|---|---|
| 200 | Job | The updated job. |
| 400 | Error | The request is malformed. Codes: `bad_request`, `bad_filter`, `bad_cursor`, `invalid_document`. |
| 401 | Error | No studio token, or a revoked or unknown one. Code `unauthenticated`. |
| 403 | Error | The token lacks a capability (`capability_required`, with `details.capability`), the job is not a task the studio may change (`not_a_task`), or the request came from another origin (`bad_origin`). |
| 404 | Error | Absent, deleted, or not the caller's to see. Code `not_found`. |
| 409 | Error | Codes: `etag_mismatch`, `name_taken`, `job_finished`, `already_running`, `not_running`, `port_conflict`, `heavy_conflict` (with `details.heavy`), `not_installed`, `conflict`, `in_use`, `missing`, `confirm_required` and `preview_changed` (with `details.preview`), `not_reclaimable`, and from M7: `approval_required` (with `details.approval`), `id_taken`, `not_fetched`, `already_exists`. |
GET /jobs/{id}/logs
One of the calling studio's job logs as server-sent events, from the start, then live until the job finishes.
Events: `step` when an install step's log begins, `line` per line, and `end` once the job has finished and every line has been sent. A task job has no `step` events. Another studio's job is 404.
Needs the jobs capability.
| Go | Logs(ctx context.Context, id string) (*EventStream, error) |
|---|---|
| Python | def logs(self, id: str) -> Any |
| JavaScript | logs(id) |
| Parameter | In | Type | About |
|---|---|---|---|
| id | path · required | ULID |
Events:
- end → JobLogEnd
- line → JobLogLine
- step → JobLogStep
| Status | Body | Means |
|---|---|---|
| 200 | string | An event stream. |
| 401 | Error | No studio token, or a revoked or unknown one. Code `unauthenticated`. |
| 403 | Error | The token lacks a capability (`capability_required`, with `details.capability`), the job is not a task the studio may change (`not_a_task`), or the request came from another origin (`bad_origin`). |
| 404 | Error | Absent, deleted, or not the caller's to see. Code `not_found`. |
POST /jobs/{id}/logs
Append lines to a running task job's log.
Q24. Written to a log file the daemon owns under the logs root, never into the database. A finished job is 409 `job_finished`; a lifecycle job is 403 `not_a_task`; another studio's job is 404.
Needs the jobs capability.
| Go | AppendLog(ctx context.Context, id string, body LogAppend) error |
|---|---|
| Python | def append_log(self, id: str, body: Dict[str, Any]) -> Any |
| JavaScript | appendLog(id, body) |
| Parameter | In | Type | About |
|---|---|---|---|
| id | path · required | ULID |
Request body: LogAppend (application/json)
| Status | Body | Means |
|---|---|---|
| 204 | Appended. | |
| 400 | Error | The request is malformed. Codes: `bad_request`, `bad_filter`, `bad_cursor`, `invalid_document`. |
| 401 | Error | No studio token, or a revoked or unknown one. Code `unauthenticated`. |
| 403 | Error | The token lacks a capability (`capability_required`, with `details.capability`), the job is not a task the studio may change (`not_a_task`), or the request came from another origin (`bad_origin`). |
| 404 | Error | Absent, deleted, or not the caller's to see. Code `not_found`. |
| 409 | Error | Codes: `etag_mismatch`, `name_taken`, `job_finished`, `already_running`, `not_running`, `port_conflict`, `heavy_conflict` (with `details.heavy`), `not_installed`, `conflict`, `in_use`, `missing`, `confirm_required` and `preview_changed` (with `details.preview`), `not_reclaimable`, and from M7: `approval_required` (with `details.approval`), `id_taken`, `not_fetched`, `already_exists`. |
| 413 | Error | The body is over its limit. Code `too_large`, with `details.limit` in bytes. |
POST /jobs/{id}:cancel
Ask for one of the calling studio's task jobs to be cancelled.
Q24. Records `cancel_requested_at` and emits a `job` event. The job stays `running` until the studio ends it. Cancelling a finished job is 409 `job_finished`. A studio cannot cancel its own install, build, download or uninstall jobs (403 `not_a_task`); only the launcher can (POST /launcher/jobs/{id}:cancel). Another studio's job is 404.
Needs the jobs capability.
| Go | Cancel(ctx context.Context, id string) error |
|---|---|
| Python | def cancel(self, id: str) -> Any |
| JavaScript | cancel(id) |
| Parameter | In | Type | About |
|---|---|---|---|
| id | path · required | ULID |
| Status | Body | Means |
|---|---|---|
| 204 | Cancellation requested. | |
| 401 | Error | No studio token, or a revoked or unknown one. Code `unauthenticated`. |
| 403 | Error | The token lacks a capability (`capability_required`, with `details.capability`), the job is not a task the studio may change (`not_a_task`), or the request came from another origin (`bad_origin`). |
| 404 | Error | Absent, deleted, or not the caller's to see. Code `not_found`. |
| 409 | Error | Codes: `etag_mismatch`, `name_taken`, `job_finished`, `already_running`, `not_running`, `port_conflict`, `heavy_conflict` (with `details.heavy`), `not_installed`, `conflict`, `in_use`, `missing`, `confirm_required` and `preview_changed` (with `details.preview`), `not_reclaimable`, and from M7: `approval_required` (with `details.approval`), `id_taken`, `not_fetched`, `already_exists`. |