# Workspace Runs (/docs/api/workspace-runs)



Workspace Runs are CrowNest's archive-based execution surface for agent and repo
workflows. Create a run, upload a gzipped tar archive, start execution,
stream events, then read the Evidence Bundle after the sandbox is gone.

Use Workspace Runs when you want CrowNest to execute a checked-out project,
test suite, build, or agent-produced archive without keeping a sandbox open
manually.

The API key needs `workspace_run:create`, `workspace_run:read`, and
`workspace_run:cancel` for the run lifecycle. Runs that export artifacts also
need `artifact:create` and `file:read`.

<Callout type="info" title="Archive input">
  Upload an existing `.tar.gz` or `.tgz` archive. The public API does not pack a local
  directory for you. For dirty checkout sync, use a client such as Crabbox or build the
  archive before calling CrowNest.
</Callout>

## The Workspace Run object [#the-workspace-run-object]

| Field               | Type    | Description                                                                                                                      |
| ------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `id`                | string  | Workspace Run ID, prefixed `wsr_`.                                                                                               |
| `projectId`         | string  | Project that owns the run.                                                                                                       |
| `status`            | string  | `awaiting_archive`, `archive_uploaded`, `starting`, `extracting`, `running`, `collecting`, `succeeded`, `failed`, or `canceled`. |
| `command`           | string  | Shell command executed after archive extraction.                                                                                 |
| `templateSlug`      | string  | CrowNest template slug, such as `python-node`.                                                                                   |
| `templateVersionId` | string  | Frozen CrowNest template version used for placement.                                                                             |
| `archive`           | object  | Uploaded archive checksum, size, and upload timestamp.                                                                           |
| `artifactIds`       | array   | Artifacts collected from explicit artifact requests.                                                                             |
| `artifactErrors`    | array   | Per-path artifact collection errors.                                                                                             |
| `cleanupStatus`     | string  | `succeeded`, `failed`, `pending`, or `not_requested`.                                                                            |
| `evidenceAvailable` | boolean | True only when the durable Evidence Bundle has been persisted and `GET /evidence` can read it.                                   |
| `exitCode`          | integer | Command exit code after completion.                                                                                              |
| `failureClass`      | string  | `user_input`, `user_command`, `platform`, or `canceled` when failed.                                                             |
| `failureReason`     | string  | Stable failure reason, such as `command_exit`, `timeout`, or `extraction_failed`.                                                |
| `sandboxId`         | string  | Internal CrowNest sandbox ID when available. Provider IDs are never exposed.                                                     |

## Create a run [#create-a-run]

`POST /v1/workspace-runs` — requires `workspace_run:create`. Accepts an
[`Idempotency-Key`](/docs/api/pagination-and-idempotency) header.

| Field               | Type    | Required | Description                                                               |
| ------------------- | ------- | -------- | ------------------------------------------------------------------------- |
| `command`           | string  | Yes      | Shell command to run after archive extraction.                            |
| `projectId`         | string  | No       | Project to create the run in. Defaults to the key's project context.      |
| `template`          | string  | No       | CrowNest template slug. `python-node` is the launch template and default. |
| `templateVersionId` | string  | No       | Specific CrowNest template version.                                       |
| `sandboxId`         | string  | No       | Warm sandbox to reuse. Its template must match the run template.          |
| `keepSandbox`       | boolean | No       | Keep the sandbox after the run instead of cleaning it up.                 |
| `timeoutMs`         | integer | No       | Command timeout in milliseconds.                                          |
| `metadata`          | object  | No       | Small string labels for listing and evidence.                             |
| `sourceMetadata`    | object  | No       | Caller-supplied source labels, such as repo or commit.                    |
| `artifacts`         | array   | No       | Explicit relative paths to collect after the command finishes.            |

Artifact collection also requires `artifact:create` and `file:read`.

```bash title="Terminal"
curl -X POST https://api.crownest.dev/v1/workspace-runs \
  -H "Authorization: Bearer $CROWNEST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: repo-test-01" \
  -d '{
    "template": "python-node",
    "command": "pnpm test",
    "timeoutMs": 120000,
    "artifacts": [{ "path": "coverage/lcov.info", "name": "coverage" }],
    "sourceMetadata": { "repo": "acme/app", "commit": "abc123" }
  }'
```

Returns `201` with `{ "workspaceRun": { ... } }` and status
`awaiting_archive`.

## Upload an archive [#upload-an-archive]

For small archives, upload raw gzipped tar bytes directly:

`PUT /v1/workspace-runs/{workspaceRunId}/archive` — requires
`workspace_run:create`.

```bash title="Terminal"
SHA=$(shasum -a 256 repo.tgz | awk '{print $1}')
SIZE=$(wc -c < repo.tgz | tr -d ' ')

curl -X PUT "https://api.crownest.dev/v1/workspace-runs/wsr_abc123/archive" \
  -H "Authorization: Bearer $CROWNEST_API_KEY" \
  -H "Content-Type: application/gzip" \
  -H "x-crownest-archive-sha256: $SHA" \
  -H "x-crownest-archive-size: $SIZE" \
  --data-binary @repo.tgz
```

Returns `{ "archive": { ... }, "workspaceRun": { ... } }` with status
`archive_uploaded`.

<Callout type="info" title="Archive size">
  Direct uploads are capped at 8 MiB. Use staged archive transfer for repo archives up
  to the returned `transfer.maxSizeBytes`.
</Callout>

## Staged archive transfer [#staged-archive-transfer]

Use staged transfer for normal repo archives. CrowNest returns an upload target
with an explicit `uploadId`, `maxSizeBytes`, headers, and finalize step.

1. Create a transfer:

   ```bash title="Terminal"
   curl -X POST "https://api.crownest.dev/v1/workspace-runs/wsr_abc123/archive-transfer" \
     -H "Authorization: Bearer $CROWNEST_API_KEY" \
     -H "Content-Type: application/json" \
     -d "{ \"sha256\": \"$SHA\", \"sizeBytes\": $SIZE }"
   ```

2. Upload the archive to `transfer.uploadUrl` with `transfer.method` and
   the returned `transfer.headers`. Production transfer URLs may point directly
   at storage; do not attach the CrowNest bearer token to external upload URLs.

3. Finalize:

   ```bash title="Terminal"
   curl -X POST "https://api.crownest.dev/v1/workspace-runs/wsr_abc123/archive/finalize" \
     -H "Authorization: Bearer $CROWNEST_API_KEY" \
     -H "Content-Type: application/json" \
     -d "{ \"uploadId\": \"upl_abc123\", \"sha256\": \"$SHA\", \"sizeBytes\": $SIZE }"
   ```

## Start execution [#start-execution]

`POST /v1/workspace-runs/{workspaceRunId}/start` — requires
`workspace_run:create`. Accepts an `Idempotency-Key` header.

The run must already have an uploaded archive. Start transitions through
`starting`, `extracting`, and `running`, then finishes as `succeeded`,
`failed`, or `canceled`.

```bash title="Terminal"
curl -X POST "https://api.crownest.dev/v1/workspace-runs/wsr_abc123/start" \
  -H "Authorization: Bearer $CROWNEST_API_KEY"
```

## Read and stream events [#read-and-stream-events]

`GET /v1/workspace-runs/{workspaceRunId}/events` — requires
`workspace_run:read`.

Query parameters:

| Parameter  | Type    | Description                        |
| ---------- | ------- | ---------------------------------- |
| `afterSeq` | integer | Return events after this sequence. |
| `limit`    | integer | Maximum events to return.          |
| `stream`   | boolean | Set `true` for server-sent events. |

Stored event reads return `{ "data": [...], "hasMore": false,
"nextSeq": 12 }`. Streaming uses SSE and accepts `afterSeq` or the
standard `Last-Event-ID` header.

Event types are `status`, `archive_progress`, `stdout`, `stderr`,
`artifact_collected`, `artifact_error`, `heartbeat`, `terminal`, and
`error`.

```bash title="Terminal"
curl -N "https://api.crownest.dev/v1/workspace-runs/wsr_abc123/events?stream=true" \
  -H "Authorization: Bearer $CROWNEST_API_KEY"
```

## Status, list, cancel, and evidence [#status-list-cancel-and-evidence]

`GET /v1/workspace-runs/{workspaceRunId}` — requires
`workspace_run:read`.

`GET /v1/workspace-runs` — requires `workspace_run:read`.

`POST /v1/workspace-runs/{workspaceRunId}/cancel` — requires
`workspace_run:cancel`. Cancel is idempotent by state.

`GET /v1/workspace-runs/{workspaceRunId}/evidence` — requires
`workspace_run:read`.

The Evidence Bundle is durable run proof: command, template fields,
archive checksum, timing, exit code, artifact IDs and errors, failure
classification, cleanup status, metadata, and source metadata. It is
available only after the run reaches a terminal state and evidence
persistence succeeds.

## Dashboard inspection [#dashboard-inspection]

The signed-in dashboard includes a Workspace Runs inspection surface at
`/workspace-runs`. Use it after a run is created through the API, CLI, SDK, or
Crabbox to list runs, open a detail page, inspect Evidence Bundle fields, copy
Artifact IDs, and cancel active runs.

## Next steps [#next-steps]

* [TypeScript SDK Workspace Runs](/docs/sdk/workspace-runs) — use the
  typed client and staged upload helper.
* [CLI Workspace Runs](/docs/cli/workspace-runs) — run an existing archive
  from the terminal.
* [Capability matrix](/docs/api/capabilities) — compare supported surfaces.
