API reference

Workers

Enrol, register, list and deregister workers, and the worker protocol: heartbeats and task leases.

GET/v1/ci/workers

List workers

Workers of the tenant; state (comma-separated) and heartbeat_after narrow the page.

Permission: ci:workers.read

Parameters

NameTypeRequiredDescription
cursorquerystringOptional
heartbeat_afterquerystringOptional
limitquerystringOptional
statequerystringOptional

Response200 OK

dataarray of anyRequired
has_morebooleanRequired
next_cursorstring or null
curl "$CIRESK_API/v1/ci/workers" \
  -H "Authorization: Bearer $CIRESK_KEY"
POST/v1/ci/workers

Register a worker

Register with an enrolment secret.

Command: send Idempotency-Key

Parameters

NameTypeRequiredDescription
Idempotency-KeyheaderstringRequired

Request body

capacityobject or null
the host's capacity vector: what the lease statement fits a task's resources into, per dimension. absent from older workers, which are fitted by slots alone
capacity.cpusintegerRequired
capacity.disk_bytesintegerRequired
capacity.memory_bytesintegerRequired
capacity.tmp_bytesintegerRequired
factory_idstringRequired
instance_idstring or null
labelsobjectRequired
the label set the queue matches on
labels.archstringRequired
labels.custommap of string
labels.disposablebooleanRequired
labels.isolationstringRequired
One of process, vm
labels.memory_bytesintegerRequired
labels.osstringRequired
labels.toolchainsarray of stringsRequired
labels.vcpusintegerRequired
labels.view_isolationstring or null
namespace when a view job's task may run here; the queue leases a task with a view only to a member that says soOne of namespace
labels.workspace_warmbooleanRequired
memory_per_slot_bytesinteger or null
the memory one slot stands for: a task's resources.memory weighs ceil(memory / memory_per_slot_bytes) slots on this worker; absent from older workers, which run every task at weight one under their own cap
namestringRequired
protocol_versioninteger
crate::PROTOCOL_VERSION; the server accepts it and the one before
slotsintegerRequired
versionstringRequired

Response201 Created

configobjectRequired
the constants of, handed to the worker so they change without a release
config.egressobjectRequired
config.egress.allowarray of stringsRequired
config.egress.modestringRequired
One of audit, block
config.egress.strictboolean
decision 10: the tenant's egress_mode is strict, sent with mode: block so a worker that predates it runs the tenant's tasks in block; absent from older control planes, which means not strict
config.heartbeat_secsintegerRequired
config.lease_ttl_secsintegerRequired
config.log_chunk_bytesintegerRequired
config.log_flush_msintegerRequired
config.max_log_bytesintegerRequired
config.poll_wait_secsintegerRequired
config.toolchain_storeobject or null
the cell's toolchain key; absent when the cell has no toolchain store and from older control planes, which means every set installs from upstream
config.toolchain_store.key_idstringRequired
config.toolchain_store.public_keystringRequired
-----BEGIN PUBLIC KEY-----
config_versionintegerRequired
protocol_versioninteger
regionstringRequired
the cell a tenant is pinned to. mirrors ciresk_std_api::Region so the api converts a principal's jurisdiction without a second vocabulary.One of eu, us
store_originstring or null
the https origin of the cell's store bucket, which the worker declares a cell service of its egress client; absent for a store whose origin serves more than this cell's bucket (path-style, a custom endpoint) or presigns nothing, and from an older api
tokenstringRequired
the ciw_ token, 24 h, rotated through heartbeat
token_expires_atstring (date-time)Required
wanted_versionstring or null
the worker version the server wants running; the worker logs it in v1, self-update is m3
worker_idstringRequired
uuidv7 rendered as wrk_<32 hex>
curl -X POST "$CIRESK_API/v1/ci/workers" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Idempotency-Key: e26d245b-2054-43e4-b858-90510efcaec8" \
  -H "Content-Type: application/json" \
  -d '{
    "capacity": {
      "cpus": 1,
      "disk_bytes": 18432000,
      "memory_bytes": 68719476736,
      "tmp_bytes": 18432000
    },
    "factory_id": "static",
    "instance_id": "i-0a7c41d2e9f3b8c6d",
    "labels": {
      "arch": "x86_64",
      "custom": {
        "custom": "acme/platform"
      },
      "disposable": false,
      "isolation": "process",
      "memory_bytes": 68719476736,
      "os": "linux",
      "toolchains": [
        "acme/platform"
      ],
      "vcpus": 16,
      "view_isolation": "namespace",
      "workspace_warm": true
    },
    "memory_per_slot_bytes": 18432000,
    "name": "acme/platform",
    "protocol_version": 1,
    "slots": 1,
    "version": "2026.10.0"
  }'
POST/v1/ci/workers/enrol

Create an enrolment secret

A one-time enrolment secret.

Permission: ci:workers.adminCommand: send Idempotency-Key

Parameters

NameTypeRequiredDescription
Idempotency-KeyheaderstringRequired

Request body

expires_in_secsinteger or null
factory_idstringRequired
max_leasesinteger or null
the most leases that registration may take, at least 1: its last lease drains it and the report that ends that lease revokes its token. 1 for a single-use member; absent is no limit
namestring or null
trustsarray of strings
the tiers the registration this secret makes may lease; empty is every tier the worker's kind allows, as before

Response200 OK

expires_atstring (date-time)Required
secretstringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/enrol" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Idempotency-Key: 92c16cf7-01d1-4e67-a071-e3723ab758fe" \
  -H "Content-Type: application/json" \
  -d '{
    "expires_in_secs": 300,
    "factory_id": "static",
    "max_leases": 1,
    "name": "acme/platform",
    "trusts": [
      "trusted_interactive"
    ]
  }'
POST/v1/ci/workers/idle-target

Set idle target

The pool's idle timer from the factory's window report, pushed to its workers.

Permission: ci:workers.admin

Request body

ceiling_slotsinteger or null
the most slots the pool holds at once (its fixed members plus the burst ceiling, times one member's slots), which the tenant's derived concurrency cap follows; absent from an older factory and while no member of the pool has registered yet
cost_cents_per_hourinteger or null
what the pool's running and booting members cost per hour now, in cents: the api counts it until the next report and answers the month so far, which the factory's budget pacer reads back after a restart; absent from an older factory, which records no spend
factory_idstringRequired
in_windowboolean
false outside the pool's schedule; a pool without a schedule reports true
member_pricesarray of objects
what each running member of the pool costs per hour, which the lease statement ranks its slots by; empty from an older factory and for a pool that prices nothing
member_prices[].cents_per_hourintegerRequired
member_prices[].namestringRequired

Response200 OK

idle_stop_secsintegerRequired
the idle timer the pool's workers now run on
month_spendobject or null
what the pool has cost this calendar month (UTC) by the rates it reported; absent when the report carried no cost, and from an older cell
month_spend.centsintegerRequired
month_spend.sincestring (date-time)Required
the first report of the month: a pool that began reporting after the month began has no count for the time before it
reasonstringRequired
recent_submits, default, quiet, outside_schedule
updatedintegerRequired
workers whose row changed and whose config_version was bumped by this call
curl -X POST "$CIRESK_API/v1/ci/workers/idle-target" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ceiling_slots": 1,
    "cost_cents_per_hour": 1,
    "factory_id": "static",
    "in_window": true,
    "member_prices": [
      {
        "cents_per_hour": 1,
        "name": "acme/platform"
      }
    ]
  }'
GET/v1/ci/workers/{id}

Get a worker

One worker with its workspaces.

Permission: ci:workers.read

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Response200 OK

busyboolean
work beside its leases at its last heartbeat: a dev session held or starting; the factory's idle backstop counts it as busy
capacityobject or null
the capacity vector advertised at registration and what is left of it; absent for a worker that registered without one and is fitted by slots alone
capacity.cpusintegerRequired
capacity.disk_bytesintegerRequired
capacity.memory_bytesintegerRequired
capacity.tmp_bytesintegerRequired
configobject or null
the worker protocol constants and the tenant's egress policy, as handed out at registration
config.egressobjectRequired
config.egress.allowarray of stringsRequired
config.egress.modestringRequired
One of audit, block
config.egress.strictboolean
decision 10: the tenant's egress_mode is strict, sent with mode: block so a worker that predates it runs the tenant's tasks in block; absent from older control planes, which means not strict
config.heartbeat_secsintegerRequired
config.lease_ttl_secsintegerRequired
config.log_chunk_bytesintegerRequired
config.log_flush_msintegerRequired
config.max_log_bytesintegerRequired
config.poll_wait_secsintegerRequired
config.toolchain_storeobject or null
the cell's toolchain key; absent when the cell has no toolchain store and from older control planes, which means every set installs from upstream
config.toolchain_store.key_idstringRequired
config.toolchain_store.public_keystringRequired
-----BEGIN PUBLIC KEY-----
config_versioninteger
bumped whenever config changes; a heartbeat answering a higher number makes the worker re-read this resource
disk_free_bytesinteger or null
factory_idstringRequired
first_registered_atstring (date-time) or null
when the row first registered, the age of the member's disk, which the factory retires past max_member_age_days; absent from an older cell
freeobject or null
what a worker has (its capacity, advertised at registration) or has left (free, in every poll and heartbeat): the same four axes as Resources, every one present. disk_bytes and tmp_bytes are the volumes' free space minus the worker's floors
free.cpusintegerRequired
free.disk_bytesintegerRequired
free.memory_bytesintegerRequired
free.tmp_bytesintegerRequired
idstringRequired
uuidv7 rendered as wrk_<32 hex>
idle_stop_secsinteger or null
how long a factory-started worker idles before it stops itself; None for static workers
instance_idstring or null
labelsobjectRequired
the label set the queue matches on
labels.archstringRequired
labels.custommap of string
labels.disposablebooleanRequired
labels.isolationstringRequired
One of process, vm
labels.memory_bytesintegerRequired
labels.osstringRequired
labels.toolchainsarray of stringsRequired
labels.vcpusintegerRequired
labels.view_isolationstring or null
namespace when a view job's task may run here; the queue leases a task with a view only to a member that says soOne of namespace
labels.workspace_warmbooleanRequired
last_heartbeat_atstring (date-time) or null
leases_totalinteger
the leases every registration of this row took: the factory retires a member past its pool's max_member_leases; absent from an older cell, which means none
memory_per_slot_bytesinteger or null
the memory one slot stands for; absent for a worker that registered without it and runs every task at weight one
namestringRequired
public_cacheobject or null
the worker's shared cache of public registry artefacts, from its last heartbeat
public_cache.bytesintegerRequired
public_cache.hitsintegerRequired
public_cache.missesintegerRequired
regionstringRequired
the cell a tenant is pinned to. mirrors ciresk_std_api::Region so the api converts a principal's jurisdiction without a second vocabulary.One of eu, us
registered_atstring (date-time)Required
slotsintegerRequired
slots_freeintegerRequired
statestringRequired
One of online, draining, offline, deregistered
vcpusintegerRequired
versionstringRequired
the release the worker runs, from its registration and refreshed by every heartbeat
wanted_versionstring or null
the release the server wants this worker on (RegisterResponse::wanted_version); absent while no update names one
workspacesarray of objects
workspaces[].base_digeststring or null
workspaces[].bytesintegerRequired
workspaces[].idstringRequired
uuidv7 rendered as ws_<32 hex>
workspaces[].kindstringRequired
One of warm, ephemeral
workspaces[].last_used_atstring (date-time) or null
workspaces[].pathstringRequired
never leaves the cell beyond the owning tenant's own listing
workspaces[].repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
workspaces[].statestringRequired
One of ready, in_use, dirty, evicting, gone
workspaces[].truststringRequired
tiers, with no order on purpose (amendment 2026-10-27): trusted_ci is protected-branch automation and the cache writer every tier reads, trusted_interactive a person's own work, and neither is "below" the other, so every rule over tiers names the tiers it meansOne of untrusted, trusted_ci, trusted_interactive
workspaces[].worker_idstringRequired
uuidv7 rendered as wrk_<32 hex>
curl "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344" \
  -H "Authorization: Bearer $CIRESK_KEY"
POST/v1/ci/workers/{id}/bundles

Start a bundle

The grant to bundle one warm slot now, or why there is none.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
data_dirstringRequired
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
ruststring or null
slotintegerRequired
tree_rootstring or null
the root digest of a working tree: sha-256 of the root directory manifest

Response201 Created

grantedobject or null
which bundle: the slot of a repository's warm root on one architecture, and its generation
granted.archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
granted.generationintegerRequired
granted.repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
granted.slotintegerRequired
reasonstring or null
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/bundles" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "data_dir": "acme/platform",
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
    "rust": "acme/platform",
    "slot": 1,
    "tree_root": "sha256:f6d6c911b491012f14dea3f3004b6101280793ee31519604aecd29f823cca9db"
  }'
POST/v1/ci/workers/{id}/bundles/chunks

Get bundle chunks

One page of presigned gets of a warm-state bundle's chunks.

Permission: ci:workers.lease

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
generationintegerRequired
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
slotintegerRequired
frominteger

Response200 OK

chunksarray of objectsRequired
chunks[].digeststringRequired
sha-256 digest as sha256:<64 hex>
chunks[].downloadobjectRequired
a presigned get
chunks[].download.expires_atstring (date-time)Required
chunks[].download.urlstringRequired
chunks[].indexintegerRequired
chunks[].sizeintegerRequired
nextinteger or null
the from of the next page; none after the last chunk
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/bundles/chunks" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "generation": 1,
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
    "slot": 1,
    "from": 1
  }'
POST/v1/ci/workers/{id}/bundles/commit

Commit a bundle

Every chunk landed: the granted bundle becomes the slot's current one.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
generationintegerRequired
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
slotintegerRequired
chunksarray of objectsRequired
chunks[].digeststringRequired
sha-256 digest as sha256:<64 hex>
chunks[].sizeintegerRequired
entriesintegerRequired
ranarray of objects
ran[].namestringRequired
ran[].runstringRequired
unpacked_bytesintegerRequired

Response201 Created

bundleobjectRequired
which bundle: the slot of a repository's warm root on one architecture, and its generation
bundle.archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
bundle.generationintegerRequired
bundle.repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
bundle.slotintegerRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/bundles/commit" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "generation": 1,
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
    "slot": 1,
    "chunks": [
      {
        "digest": "sha256:c21fa32a40d82233c44e76e6ae776b4d403ac1a564ca26de95a14c6bb47eaf49",
        "size": 18432000
      }
    ],
    "entries": 1,
    "ran": [
      {
        "name": "acme/platform",
        "run": "acme/platform"
      }
    ],
    "unpacked_bytes": 18432000
  }'
POST/v1/ci/workers/{id}/bundles/parts

Start a chunk upload

A presigned put for one chunk of a warm-state bundle the worker was granted.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
generationintegerRequired
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
slotintegerRequired
digeststringRequired
sha-256 digest as sha256:<64 hex>
indexintegerRequired
sizeintegerRequired

Response200 OK

expires_atstring (date-time)Required
headersmap of string
methodstringRequired
urlstringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/bundles/parts" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "generation": 1,
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
    "slot": 1,
    "digest": "sha256:c21fa32a40d82233c44e76e6ae776b4d403ac1a564ca26de95a14c6bb47eaf49",
    "index": 1,
    "size": 18432000
  }'
POST/v1/ci/workers/{id}/deregister

Deregister a worker

Deregister, optionally draining.

Permission: ci:workers.admin

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

drainboolean
revokeboolean
the worker is no longer trusted: every cache-claim key it held is revoked, so no cache row it signed answers again; without it a deregistered worker's rows keep answering, since they were signed while it was trusted

Response200 OK

statestringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/deregister" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "drain": true,
    "revoke": true
  }'
POST/v1/ci/workers/{id}/heartbeat

Send a heartbeat

Liveness, lease renewal, cancellation, token rotation.

Permission: ci:workers.heartbeat

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

busyboolean
the worker holds work its leases do not show: a dev session held or starting, so the factory does not stop it as idle; absent from older workers
disk_free_bytesintegerRequired
drainingboolean
the worker takes no new lease: its host has a spot rebalance recommendation; the api drains its row, so the factory replaces it and ends it once empty. absent from older workers
freeobject or null
what the worker has left of its capacity; advisory for cpus and memory, the row's own arithmetic decides, and the measured word for disk and tmp
free.cpusintegerRequired
free.disk_bytesintegerRequired
free.memory_bytesintegerRequired
free.tmp_bytesintegerRequired
leasesarray of objectsRequired
leases[].idstringRequired
uuidv7 rendered as lease_<32 hex>
leases[].log_bytesintegerRequired
leases[].phasestringRequired
One of leased, running
leases[].renewals_failedinteger
how many renewals of this lease failed on the api's side (5xx, timeout) since the last one that landed; the api stamps renewal_failed_at so an expiry in that window is the outage's, not the worker's, and keeps the task's attempt. absent from older workers
leases[].task_idstringRequired
uuidv7 rendered as tsk_<32 hex>
public_cacheobject or null
the worker's public registry cache; absent from older workers and when the cache is off
public_cache.bytesintegerRequired
public_cache.hitsintegerRequired
public_cache.missesintegerRequired
refresh_tokenboolean
registrationobject or null
what this process runs with, sent on its first beats until one lands: a worker that resumed from state.json never registers again, so without it the row kept the labels, slots and capacity of the first registration (eu1 1.0.14: 31 cpus after the release raised them to 38). absent from older workers and on every later beat
registration.capacityobject or null
what a worker has (its capacity, advertised at registration) or has left (free, in every poll and heartbeat): the same four axes as Resources, every one present. disk_bytes and tmp_bytes are the volumes' free space minus the worker's floors
registration.capacity.cpusintegerRequired
registration.capacity.disk_bytesintegerRequired
registration.capacity.memory_bytesintegerRequired
registration.capacity.tmp_bytesintegerRequired
registration.labelsobjectRequired
the label set the queue matches on
registration.labels.archstringRequired
registration.labels.custommap of string
registration.labels.disposablebooleanRequired
registration.labels.isolationstringRequired
One of process, vm
registration.labels.memory_bytesintegerRequired
registration.labels.osstringRequired
registration.labels.toolchainsarray of stringsRequired
registration.labels.vcpusintegerRequired
registration.labels.view_isolationstring or null
namespace when a view job's task may run here; the queue leases a task with a view only to a member that says soOne of namespace
registration.labels.workspace_warmbooleanRequired
registration.memory_per_slot_bytesinteger or null
registration.signing_keystring or null
standard base64 of the ed25519 public key this worker process signs its cache claims with: drawn at boot, so a restart rotates it; absent from older workers, whose cache rows the api no longer records
registration.slotsintegerRequired
slots_freeintegerRequired
stoppingboolean
the worker is on its way out (an idle stop, a shutdown signal, a spot interruption notice) and leases nothing more: the api takes an online row offline now, so the factory and the lease statement stop counting its slots before the reaper's 90 s of silence. absent from older workers
versionstring or null
the release the worker runs (ciresk_ci_core::release_string), so a self-updated worker refreshes its row without re-registering; absent from older workers

Response201 Created

config_versionintegerRequired
lease_pipelineboolean
the api frees a lease's slot, cpus and memory at its process_ended beat and answers max_leases and ReportRequest::next; absent from an older api, against which the worker counts an ended lease as held until its report
leasesarray of objectsRequired
leases[].expires_atstring (date-time) or null
leases[].idstringRequired
uuidv7 rendered as lease_<32 hex>
leases[].statestringRequired
active renewed, cancel_requested means stop and report cancelled, expired means kill and report nothingOne of active, cancel_requested, expired
leases[].write_tokenstring or null
re-issued once 80 % of the write token's lifetime has passed
store_originstring or null
see RegisterResponse::store_origin: on every beat, so a worker resumed from state.json learns it from its first beat of the boot
tokenstring or null
a new ciw_ token; the old one stays valid five minutes
token_expires_atstring (date-time) or null
wanted_versionstring or null
see RegisterResponse::wanted_version
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/heartbeat" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "busy": true,
    "disk_free_bytes": 18432000,
    "draining": false,
    "free": {
      "cpus": 1,
      "disk_bytes": 18432000,
      "memory_bytes": 68719476736,
      "tmp_bytes": 18432000
    },
    "leases": [
      {
        "id": "lease_01778d67b48ee630f44b3f03ab6254a8",
        "log_bytes": 18432000,
        "phase": "leased",
        "renewals_failed": 1,
        "task_id": "tsk_011ec0cc99550d0e90bc9fed5781decd"
      }
    ],
    "public_cache": {
      "bytes": 18432000,
      "hits": 2,
      "misses": 1
    },
    "refresh_token": true,
    "registration": {
      "capacity": {
        "cpus": 1,
        "disk_bytes": 18432000,
        "memory_bytes": 68719476736,
        "tmp_bytes": 18432000
      },
      "labels": {
        "arch": "x86_64",
        "custom": {
          "custom": "acme/platform"
        },
        "disposable": false,
        "isolation": "process",
        "memory_bytes": 68719476736,
        "os": "linux",
        "toolchains": [
          "acme/platform"
        ],
        "vcpus": 16,
        "view_isolation": "namespace",
        "workspace_warm": true
      },
      "memory_per_slot_bytes": 18432000,
      "signing_key": "acme/platform",
      "slots": 1
    },
    "slots_free": 1,
    "stopping": true,
    "version": "2026.10.0"
  }'
POST/v1/ci/workers/{id}/images

Start a slot image

The grant to refresh one slot image lineage now, or why there is none.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
gidintegerRequired
lineageintegerRequired
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
ruststring or null
tree_rootstring or null
the root digest of a working tree: sha-256 of the root directory manifest
uidintegerRequired
workspace_pathstringRequired

Response201 Created

grantedobject or null
which image: one lineage (the producing slot's index) of a repository on one architecture, and its generation
granted.archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
granted.generationintegerRequired
granted.lineageintegerRequired
granted.repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
reasonstring or null
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/images" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "gid": 1,
    "lineage": 1,
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
    "rust": "acme/platform",
    "tree_root": "sha256:f6d6c911b491012f14dea3f3004b6101280793ee31519604aecd29f823cca9db",
    "uid": 1,
    "workspace_path": "acme/platform"
  }'
POST/v1/ci/workers/{id}/images/chunks

Get slot image chunks

Presigned gets for slot image chunks of the worker's tenant, by digest.

Permission: ci:workers.lease

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
digestsarray of stringsRequired
raw-byte digests, at most IMAGE_GETS_MAX
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>

Response200 OK

chunksarray of objectsRequired
in the request's order
chunks[].digeststringRequired
sha-256 digest as sha256:<64 hex>
chunks[].downloadobjectRequired
a presigned get
chunks[].download.expires_atstring (date-time)Required
chunks[].download.urlstringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/images/chunks" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "digests": [
      "sha256:c21fa32a40d82233c44e76e6ae776b4d403ac1a564ca26de95a14c6bb47eaf49"
    ],
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b"
  }'
POST/v1/ci/workers/{id}/images/commit

Commit a slot image

Make a granted slot image current once its manifest and chunks are in the store.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
generationintegerRequired
lineageintegerRequired
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
manifestobjectRequired
an object of the store by its sha-256 and size: the manifest, or a stored chunk
manifest.digeststringRequired
sha-256 digest as sha256:<64 hex>
manifest.sizeintegerRequired
ranarray of objects
ran[].namestringRequired
ran[].runstringRequired

Response201 Created

imageobjectRequired
which image: one lineage (the producing slot's index) of a repository on one architecture, and its generation
image.archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
image.generationintegerRequired
image.lineageintegerRequired
image.repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
new_bytesintegerRequired
new_chunksintegerRequired
the chunks this generation stored first, and their stored bytes: what the refresh uploaded
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/images/commit" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "generation": 1,
    "lineage": 1,
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
    "manifest": {
      "digest": "sha256:c21fa32a40d82233c44e76e6ae776b4d403ac1a564ca26de95a14c6bb47eaf49",
      "size": 18432000
    },
    "ran": [
      {
        "name": "acme/platform",
        "run": "acme/platform"
      }
    ]
  }'
POST/v1/ci/workers/{id}/images/parts

Start slot image uploads

Presigned puts for a granted slot image's chunks the tenant lacks, and its manifest.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
generationintegerRequired
lineageintegerRequired
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
chunksarray of objects
at most IMAGE_PARTS_MAX
chunks[].digeststringRequired
sha-256 digest as sha256:<64 hex>
chunks[].storedobjectRequired
an object of the store by its sha-256 and size: the manifest, or a stored chunk
chunks[].stored.digeststringRequired
sha-256 digest as sha256:<64 hex>
chunks[].stored.sizeintegerRequired
manifestobject or null
an object of the store by its sha-256 and size: the manifest, or a stored chunk
manifest.digeststringRequired
sha-256 digest as sha256:<64 hex>
manifest.sizeintegerRequired

Response201 Created

manifestobject or null
a presigned put
manifest.expires_atstring (date-time)Required
manifest.headersmap of string
manifest.methodstringRequired
manifest.urlstringRequired
partsarray of objectsRequired
in the request's order
parts[].digeststringRequired
sha-256 digest as sha256:<64 hex>
parts[].uploadobject or null
a presigned put
parts[].upload.expires_atstring (date-time)Required
parts[].upload.headersmap of string
parts[].upload.methodstringRequired
parts[].upload.urlstringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/images/parts" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "generation": 1,
    "lineage": 1,
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
    "chunks": [
      {
        "digest": "sha256:c21fa32a40d82233c44e76e6ae776b4d403ac1a564ca26de95a14c6bb47eaf49",
        "stored": {
          "digest": "sha256:c21fa32a40d82233c44e76e6ae776b4d403ac1a564ca26de95a14c6bb47eaf49",
          "size": 18432000
        }
      }
    ],
    "manifest": {
      "digest": "sha256:c21fa32a40d82233c44e76e6ae776b4d403ac1a564ca26de95a14c6bb47eaf49",
      "size": 18432000
    }
  }'
POST/v1/ci/workers/{id}/images/trace

Report a slot image trace

Merge a mounted slot image's first-read order into its lineage's trace.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
generationintegerRequired
lineageintegerRequired
repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
chunksarray of integersRequired

Response201 Created

keptintegerRequired
the lineage's trace length after the merge
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/images/trace" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "arch": "x86_64",
    "generation": 1,
    "lineage": 1,
    "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
    "chunks": [
      1
    ]
  }'
POST/v1/ci/workers/{id}/lease

Lease a task

The 30 s long-poll for the tasks that fit.

Permission: ci:workers.lease

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

boot_to_online_msinteger or null
the worker's boot-to-online time, recorded on the lease for the cold start analysis
disk_free_bytesintegerRequired
first_lease_after_bootboolean
no lease since boot (Neon item 4): the lease is first_after_boot unless the member came online after the job
freeobject or null
see HeartbeatRequest::free; a zero in cpus or memory answers 204 at once
free.cpusintegerRequired
free.disk_bytesintegerRequired
free.memory_bytesintegerRequired
free.tmp_bytesintegerRequired
max_leasesinteger or null
how many leases one answer may carry, the worker's free slots; absent from an older worker: one
process_endedarray of strings
the phase beat process_ended: the leases this worker holds whose process exited and whose report has not landed; the api frees their slot, cpus and memory before it leases. absent from an older worker
slots_freeintegerRequired
wait_secsintegerRequired
warmarray of objects
warm[].base_digeststring or null
warm[].repo_idstringRequired
uuidv7 rendered as repo_<32 hex>

Response201 Created

jobobjectRequired
job.actorstringRequired
job.base_digeststringRequired
job.base_refstringRequired
job.diffobject or null
a content-addressed blob the receiver fetches by presigned url
job.diff.digeststringRequired
sha-256 digest as sha256:<64 hex>
job.diff.downloadobjectRequired
a presigned get
job.diff.download.expires_atstring (date-time)Required
job.diff.download.urlstringRequired
job.diff.sizeintegerRequired
job.graphobject or null
the cell holds no graph for this root and the manifest has a task with this strategy: record one after the run, once per job
job.graph.dirstring
where the tool runs, repository-relative, "" for the root
job.graph.rootstringRequired
the root digest of a working tree: sha-256 of the root directory manifest
job.graph.strategystringRequired
One of cargo, pnpm, go, turbo, nx, files, none
job.graphsarray of objects
every graph the cell lacks for this root, one request per strategy the manifest declares (cargo, pnpm, go); graph carries the first of them for a worker from before this field
job.graphs[].dirstring
where the tool runs, repository-relative, "" for the root
job.graphs[].rootstringRequired
the root digest of a working tree: sha-256 of the root directory manifest
job.graphs[].strategystringRequired
One of cargo, pnpm, go, turbo, nx, files, none
job.idstringRequired
uuidv7 rendered as job_<32 hex>
job.kindstringRequired
check, test, build, lint or a manifest task id
job.manifest_digeststringRequired
sha-256 digest as sha256:<64 hex>
job.manifest_pathstring or null
the governing manifest's repository-relative path; absent means <cwd>/.ciresk/ci.yaml
job.org_idstring or null
tenants.org_id of tenant, the organisation dev names its sessions by: the worker records it on the warm root, so a dev session only ever pins or indexes its own org's generations; absent from an older api, and a root without it is never handed to a session
job.repoobjectRequired
job.repo.default_branchstring or null
the registration's default branch (ci.repos.create): a lease whose base_ref names it is what an overlay member's trunk follows; absent from an older api
job.repo.idstringRequired
uuidv7 rendered as repo_<32 hex>
job.repo.slugstringRequired
job.repo.urlstring or null
job.seed_packobject or null
the repository's seed pack, offered only to a job with a tree and no view; absent when the cell has none and from an older api
job.seed_pack.bytesintegerRequired
job.seed_pack.downloadobjectRequired
a presigned get
job.seed_pack.download.expires_atstring (date-time)Required
job.seed_pack.download.urlstringRequired
job.seed_pack.entriesintegerRequired
job.seed_pack.rootstringRequired
the tree the pack was built from; its root manifest is the pack's last entry, so a cas that holds the root was seeded already
job.sessionstring or null
job.targetsarray of stringsRequired
job.tenantstring or null
the owner of the tree's blobs, the partition of the worker's local cas
job.toolchainsmap of stringRequired
job.treeobject or null
the tree to materialise; diff stays until every worker reads tree
job.tree.bytesintegerRequired
job.tree.entriesintegerRequired
job.tree.rootstringRequired
the root digest of a working tree: sha-256 of the root directory manifest
job.truststringRequired
tiers, with no order on purpose (amendment 2026-10-27): trusted_ci is protected-branch automation and the cache writer every tier reads, trusted_interactive a person's own work, and neither is "below" the other, so every rule over tiers names the tiers it meansOne of untrusted, trusted_ci, trusted_interactive
job.viewobject or null
the requester's path view when it hides a prefix: the task runs in a fresh namespace on a tree of the readable paths only; absent for every other job
job.view.digeststringRequired
ViewSpec::digest: the entries only, so every key that carries it also carries the tenant
job.view.entriesarray of objectsRequired
job.view.entries[].prefixstringRequired
job.view.entries[].readbooleanRequired
job.view.entries[].writebooleanRequired
job.view.policy_versionintegerRequired
job.workspaceobjectRequired
job.workspace.keeparray of strings
job.workspace.kindstringRequired
One of warm, ephemeral
job.workspace.prewarmboolean
the manifest's workspace.prewarm: an idle worker may refresh the repo's trunk
job.workspace.sparsearray of strings
leaseobjectRequired
lease.cold_startstring or null
how warm this member was for the queue (Neon item 4); absent from an older control planeOne of warm, started, first_after_boot
lease.expected_msinteger or null
the task's expected run: on a spot notice a lease whose remainder fits is finished, not handed back; absent from an older control plane
lease.expires_atstring (date-time)Required
lease.fencingintegerRequired
equals tasks.attempt; a report with an older fence is 409 lease_not_held
lease.heartbeat_secsintegerRequired
lease.idstringRequired
uuidv7 rendered as lease_<32 hex>
lease.warm_wait_msinteger or null
the task's warm wait: 0 means a warm slot pays nothing, so the task never waits for a restore. absent without both p50s and from an older control plane, which waits as before
lease.weightinteger
how many of the worker's slots this lease holds: ceil(resources.memory / memory_per_slot), at least one; an older control plane sends none, which is one
taskobjectRequired
run arrives with targets_arg already substituted
task.artifactsarray of strings
task.attemptintegerRequired
task.cacheobjectRequired
the namespaces this task reads and the one it may write, with the hmac write token
task.cache.bypassstring or null
why the worker computes the key but skips the lookup: no_cache for the job's --no-cache, results_off for the task's cache: { results: false }; absent means look up
task.cache.enabledbooleanRequired
task.cache.readarray of stringsRequired
task.cache.submit_missedstring or null
the submit key the api looked up when the task became ready and found no recorded success under: the worker reads no early key and asks once after the materialise. absent from an older api and whenever the api did not look up or found a row, which means as before
task.cache.writestring or null
task.cache.write_tokenstring or null
task.cwdstringRequired
task.depends_onarray of objects
task.depends_on[].content_digeststring or null
sha-256 of the outputs tar before compression: what the task's key takes for this dependency, and what the restore checks; absent from an older api and for a dependency recorded before it, where the key takes outputs_digest
task.depends_on[].downloadobject or null
a presigned get
task.depends_on[].download.expires_atstring (date-time)Required
task.depends_on[].download.urlstringRequired
task.depends_on[].namestringRequired
task.depends_on[].outputs_digeststring or null
sha-256 digest as sha256:<64 hex>
task.depends_on[].task_idstringRequired
uuidv7 rendered as tsk_<32 hex>
task.egress_strictboolean
decision 10: the manifest's egress: strict; the worker runs the task strict when this or the tenant's policy says so. absent from older control planes, which means the tenant's mode alone
task.envmap of stringRequired
task.global_inputsarray of strings
the manifest's globals.inputs: in every task's key whether or not the task declares inputs, so a lockfile change never hits a stale verdict; absent from older control planes, which means none
task.idstringRequired
uuidv7 rendered as tsk_<32 hex>
task.id_tokenobject or null
: the task's id token; absent when it asks for none, its job is untrusted, or from older apis
task.id_token.audiencestringRequired
task.id_token.expires_atstring (date-time)Required
task.id_token.tokenstringRequired
the signed jwt the task hands a relying party
task.id_token_refusedstring or null
: why the token the task asks for was refused; the worker fails the task before it runs
task.inputsarray of stringsRequired
task.knobsobject
what the derived tool knobs come from when the api trimmed the grant's memory below the manifest's from this run's history: the untrimmed request, so a trim moves the scope's caps and the fit, never a tool's parallelism or heap. absent when the grant is untrimmed and from older control planes: the knobs follow it
task.knobs.cpusinteger or null
whole cpus, CPUQuota of the scope and the -j every tool is handed
task.knobs.diskinteger or null
space the task writes to its workspace (a build directory); fitted against the data volume
task.knobs.memoryinteger or null
MemoryMax of the scope
task.knobs.tmpinteger or null
scratch space the task needs under TMPDIR; the worker refuses the run when the data volume has less than this free
task.logobject or null
the log token path of; absent from older control planes, which means the worker token
task.log.directboolean
: the worker puts sealed segments into the store itself (ci.logs.segment_url, then ci.logs.segment_commit) and sends no log bytes to the api; absent from an older control plane, which means every chunk through ci.logs.append
task.log.max_bytesintegerRequired
task.log.tokenstringRequired
task.namestringRequired
task.nextestobject or null
: the row is one half of a task that builds once and tests on shards; absent for every other task and from older control planes
task.nextest.rolestringRequired
which half of an archive task a row isOne of archive, shard
task.nextest.taskstringRequired
task.outputsarray of stringsRequired
task.pass_envarray of stringsRequired
task.pass_env_refusedarray of objects
the pass_env names whose secret scope this job is outside of: never in pass_env, and the worker fails the task naming each one instead of running it without them. absent from older control planes, which means none
task.pass_env_refused[].namestringRequired
task.pass_env_refused[].reasonstringRequired
task.prioritiesobject or null
the tests to start first, for a task with a junit report the cell has results of (CIR-722); absent from older control planes and for every other task
task.priorities.firstarray of objects
failed or flaky in a recent run and not passed since, most recent first
task.priorities.first[].namestringRequired
task.priorities.first[].suitestringRequired
task.priorities.slowarray of objects
the slowest seen, slowest first
task.priorities.slow[].namestringRequired
task.priorities.slow[].suitestringRequired
task.reportobjectRequired
task.report.junitstring or null
task.report.timingsboolean
task.resourcesobject
the grant: the manifest's resources with what it left unsaid filled from the task's history or the kind defaults; the scope's caps and the derived tool knobs come from it. absent from older control planes, which means the worker's limits
task.resources.cpusinteger or null
whole cpus, CPUQuota of the scope and the -j every tool is handed
task.resources.diskinteger or null
space the task writes to its workspace (a build directory); fitted against the data volume
task.resources.memoryinteger or null
MemoryMax of the scope
task.resources.tmpinteger or null
scratch space the task needs under TMPDIR; the worker refuses the run when the data volume has less than this free
task.runstringRequired
task.servicesmap of object
: the services the task runs beside it, by name, started before it in its own network namespace; leased only to a member labelled services: podman, absent for every other task and from older control planes
task.shardobject or null
a 1-based shard of a sharded task; rendered as k/N where the wire asks for a string
task.shard.countintegerRequired
task.shard.indexintegerRequired
task.timeout_secsintegerRequired
task.toolchainsmap of string or null
: a matrix cell's toolchains when an axis pins one, replacing the job's toolchains for this task; absent for every other task and from older control planes
task.trace_inputsboolean
: the worker traces the task's file reads and reports them as observed_inputs; absent from older control planes, which means off
leasesarray of objects
the leases after the first, up to LeaseRequest::max_leases; absent from an older api
leases[].jobobjectRequired
leases[].job.actorstringRequired
leases[].job.base_digeststringRequired
leases[].job.base_refstringRequired
leases[].job.diffobject or null
a content-addressed blob the receiver fetches by presigned url
leases[].job.diff.digeststringRequired
sha-256 digest as sha256:<64 hex>
leases[].job.diff.downloadobjectRequired
a presigned get
leases[].job.diff.sizeintegerRequired
leases[].job.graphobject or null
the cell holds no graph for this root and the manifest has a task with this strategy: record one after the run, once per job
leases[].job.graph.dirstring
where the tool runs, repository-relative, "" for the root
leases[].job.graph.rootstringRequired
the root digest of a working tree: sha-256 of the root directory manifest
leases[].job.graph.strategystringRequired
One of cargo, pnpm, go, turbo, nx, files, none
leases[].job.graphsarray of objects
every graph the cell lacks for this root, one request per strategy the manifest declares (cargo, pnpm, go); graph carries the first of them for a worker from before this field
leases[].job.graphs[].dirstring
where the tool runs, repository-relative, "" for the root
leases[].job.graphs[].rootstringRequired
the root digest of a working tree: sha-256 of the root directory manifest
leases[].job.graphs[].strategystringRequired
One of cargo, pnpm, go, turbo, nx, files, none
leases[].job.idstringRequired
uuidv7 rendered as job_<32 hex>
leases[].job.kindstringRequired
check, test, build, lint or a manifest task id
leases[].job.manifest_digeststringRequired
sha-256 digest as sha256:<64 hex>
leases[].job.manifest_pathstring or null
the governing manifest's repository-relative path; absent means <cwd>/.ciresk/ci.yaml
leases[].job.org_idstring or null
tenants.org_id of tenant, the organisation dev names its sessions by: the worker records it on the warm root, so a dev session only ever pins or indexes its own org's generations; absent from an older api, and a root without it is never handed to a session
leases[].job.repoobjectRequired
leases[].job.repo.default_branchstring or null
the registration's default branch (ci.repos.create): a lease whose base_ref names it is what an overlay member's trunk follows; absent from an older api
leases[].job.repo.idstringRequired
uuidv7 rendered as repo_<32 hex>
leases[].job.repo.slugstringRequired
leases[].job.repo.urlstring or null
leases[].job.seed_packobject or null
the repository's seed pack, offered only to a job with a tree and no view; absent when the cell has none and from an older api
leases[].job.seed_pack.bytesintegerRequired
leases[].job.seed_pack.downloadobjectRequired
a presigned get
leases[].job.seed_pack.entriesintegerRequired
leases[].job.seed_pack.rootstringRequired
the tree the pack was built from; its root manifest is the pack's last entry, so a cas that holds the root was seeded already
leases[].job.sessionstring or null
leases[].job.targetsarray of stringsRequired
leases[].job.tenantstring or null
the owner of the tree's blobs, the partition of the worker's local cas
leases[].job.toolchainsmap of stringRequired
leases[].job.treeobject or null
the tree to materialise; diff stays until every worker reads tree
leases[].job.tree.bytesintegerRequired
leases[].job.tree.entriesintegerRequired
leases[].job.tree.rootstringRequired
the root digest of a working tree: sha-256 of the root directory manifest
leases[].job.truststringRequired
tiers, with no order on purpose (amendment 2026-10-27): trusted_ci is protected-branch automation and the cache writer every tier reads, trusted_interactive a person's own work, and neither is "below" the other, so every rule over tiers names the tiers it meansOne of untrusted, trusted_ci, trusted_interactive
leases[].job.viewobject or null
the requester's path view when it hides a prefix: the task runs in a fresh namespace on a tree of the readable paths only; absent for every other job
leases[].job.view.digeststringRequired
ViewSpec::digest: the entries only, so every key that carries it also carries the tenant
leases[].job.view.entriesarray of objectsRequired
leases[].job.view.policy_versionintegerRequired
leases[].job.workspaceobjectRequired
leases[].job.workspace.keeparray of strings
leases[].job.workspace.kindstringRequired
One of warm, ephemeral
leases[].job.workspace.prewarmboolean
the manifest's workspace.prewarm: an idle worker may refresh the repo's trunk
leases[].job.workspace.sparsearray of strings
leases[].leaseobjectRequired
leases[].lease.cold_startstring or null
how warm this member was for the queue (Neon item 4); absent from an older control planeOne of warm, started, first_after_boot
leases[].lease.expected_msinteger or null
the task's expected run: on a spot notice a lease whose remainder fits is finished, not handed back; absent from an older control plane
leases[].lease.expires_atstring (date-time)Required
leases[].lease.fencingintegerRequired
equals tasks.attempt; a report with an older fence is 409 lease_not_held
leases[].lease.heartbeat_secsintegerRequired
leases[].lease.idstringRequired
uuidv7 rendered as lease_<32 hex>
leases[].lease.warm_wait_msinteger or null
the task's warm wait: 0 means a warm slot pays nothing, so the task never waits for a restore. absent without both p50s and from an older control plane, which waits as before
leases[].lease.weightinteger
how many of the worker's slots this lease holds: ceil(resources.memory / memory_per_slot), at least one; an older control plane sends none, which is one
leases[].taskobjectRequired
run arrives with targets_arg already substituted
leases[].task.artifactsarray of strings
leases[].task.attemptintegerRequired
leases[].task.cacheobjectRequired
the namespaces this task reads and the one it may write, with the hmac write token
leases[].task.cache.bypassstring or null
why the worker computes the key but skips the lookup: no_cache for the job's --no-cache, results_off for the task's cache: { results: false }; absent means look up
leases[].task.cache.enabledbooleanRequired
leases[].task.cache.readarray of stringsRequired
leases[].task.cache.submit_missedstring or null
the submit key the api looked up when the task became ready and found no recorded success under: the worker reads no early key and asks once after the materialise. absent from an older api and whenever the api did not look up or found a row, which means as before
leases[].task.cache.writestring or null
leases[].task.cache.write_tokenstring or null
leases[].task.cwdstringRequired
leases[].task.depends_onarray of objects
leases[].task.depends_on[].content_digeststring or null
sha-256 of the outputs tar before compression: what the task's key takes for this dependency, and what the restore checks; absent from an older api and for a dependency recorded before it, where the key takes outputs_digest
leases[].task.depends_on[].downloadobject or null
a presigned get
leases[].task.depends_on[].namestringRequired
leases[].task.depends_on[].outputs_digeststring or null
sha-256 digest as sha256:<64 hex>
leases[].task.depends_on[].task_idstringRequired
uuidv7 rendered as tsk_<32 hex>
leases[].task.egress_strictboolean
decision 10: the manifest's egress: strict; the worker runs the task strict when this or the tenant's policy says so. absent from older control planes, which means the tenant's mode alone
leases[].task.envmap of stringRequired
leases[].task.global_inputsarray of strings
the manifest's globals.inputs: in every task's key whether or not the task declares inputs, so a lockfile change never hits a stale verdict; absent from older control planes, which means none
leases[].task.idstringRequired
uuidv7 rendered as tsk_<32 hex>
leases[].task.id_tokenobject or null
: the task's id token; absent when it asks for none, its job is untrusted, or from older apis
leases[].task.id_token.audiencestringRequired
leases[].task.id_token.expires_atstring (date-time)Required
leases[].task.id_token.tokenstringRequired
the signed jwt the task hands a relying party
leases[].task.id_token_refusedstring or null
: why the token the task asks for was refused; the worker fails the task before it runs
leases[].task.inputsarray of stringsRequired
leases[].task.knobsobject
what the derived tool knobs come from when the api trimmed the grant's memory below the manifest's from this run's history: the untrimmed request, so a trim moves the scope's caps and the fit, never a tool's parallelism or heap. absent when the grant is untrimmed and from older control planes: the knobs follow it
leases[].task.knobs.cpusinteger or null
whole cpus, CPUQuota of the scope and the -j every tool is handed
leases[].task.knobs.diskinteger or null
space the task writes to its workspace (a build directory); fitted against the data volume
leases[].task.knobs.memoryinteger or null
MemoryMax of the scope
leases[].task.knobs.tmpinteger or null
scratch space the task needs under TMPDIR; the worker refuses the run when the data volume has less than this free
leases[].task.logobject or null
the log token path of; absent from older control planes, which means the worker token
leases[].task.log.directboolean
: the worker puts sealed segments into the store itself (ci.logs.segment_url, then ci.logs.segment_commit) and sends no log bytes to the api; absent from an older control plane, which means every chunk through ci.logs.append
leases[].task.log.max_bytesintegerRequired
leases[].task.log.tokenstringRequired
leases[].task.namestringRequired
leases[].task.nextestobject or null
: the row is one half of a task that builds once and tests on shards; absent for every other task and from older control planes
leases[].task.nextest.rolestringRequired
which half of an archive task a row isOne of archive, shard
leases[].task.nextest.taskstringRequired
leases[].task.outputsarray of stringsRequired
leases[].task.pass_envarray of stringsRequired
leases[].task.pass_env_refusedarray of objects
the pass_env names whose secret scope this job is outside of: never in pass_env, and the worker fails the task naming each one instead of running it without them. absent from older control planes, which means none
leases[].task.pass_env_refused[].namestringRequired
leases[].task.pass_env_refused[].reasonstringRequired
leases[].task.prioritiesobject or null
the tests to start first, for a task with a junit report the cell has results of (CIR-722); absent from older control planes and for every other task
leases[].task.priorities.firstarray of objects
failed or flaky in a recent run and not passed since, most recent first
leases[].task.priorities.slowarray of objects
the slowest seen, slowest first
leases[].task.reportobjectRequired
leases[].task.report.junitstring or null
leases[].task.report.timingsboolean
leases[].task.resourcesobject
the grant: the manifest's resources with what it left unsaid filled from the task's history or the kind defaults; the scope's caps and the derived tool knobs come from it. absent from older control planes, which means the worker's limits
leases[].task.resources.cpusinteger or null
whole cpus, CPUQuota of the scope and the -j every tool is handed
leases[].task.resources.diskinteger or null
space the task writes to its workspace (a build directory); fitted against the data volume
leases[].task.resources.memoryinteger or null
MemoryMax of the scope
leases[].task.resources.tmpinteger or null
scratch space the task needs under TMPDIR; the worker refuses the run when the data volume has less than this free
leases[].task.runstringRequired
leases[].task.servicesmap of object
: the services the task runs beside it, by name, started before it in its own network namespace; leased only to a member labelled services: podman, absent for every other task and from older control planes
leases[].task.shardobject or null
a 1-based shard of a sharded task; rendered as k/N where the wire asks for a string
leases[].task.shard.countintegerRequired
leases[].task.shard.indexintegerRequired
leases[].task.timeout_secsintegerRequired
leases[].task.toolchainsmap of string or null
: a matrix cell's toolchains when an axis pins one, replacing the job's toolchains for this task; absent for every other task and from older control planes
leases[].task.trace_inputsboolean
: the worker traces the task's file reads and reports them as observed_inputs; absent from older control planes, which means off
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/lease" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "boot_to_online_ms": 83000,
    "disk_free_bytes": 18432000,
    "first_lease_after_boot": true,
    "free": {
      "cpus": 1,
      "disk_bytes": 18432000,
      "memory_bytes": 68719476736,
      "tmp_bytes": 18432000
    },
    "max_leases": 1,
    "process_ended": [
      "lease_01d50b6f005647a6f46cd8e6ccc4a47a"
    ],
    "slots_free": 1,
    "wait_secs": 300,
    "warm": [
      {
        "base_digest": "feef45d804737fdf7a297e27e443d914551629de",
        "repo_id": "repo_0129354d7b6b4146ad16c315d960365b"
      }
    ]
  }'
POST/v1/ci/workers/{id}/registry

Store a registry artefact

A presigned put of one registry artefact the worker fetched and checked, into its tenant's store.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

objectstringRequired
sha256stringRequired
of the bytes, which the put's checksum binds at the store
sizeintegerRequired
at most [REGISTRY_OBJECT_MAX_BYTES]

Response201 Created

putobjectRequired
a presigned put
put.expires_atstring (date-time)Required
put.headersmap of string
put.methodstringRequired
put.urlstringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/registry" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "object": "acme/platform",
    "sha256": "sha256:116014cb5ab2f2af478466c8960a4918f44bc9fafe69acac36742f2bde2a0fc5",
    "size": 18432000
  }'
POST/v1/ci/workers/{id}/registry/lookup

Read registry artefacts

Presigned gets of registry artefacts in the worker's tenant registry store, named by digest.

Permission: ci:workers.lease

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

objectsarray of stringsRequired
objects as [registry_object_valid] reads them, at most [REGISTRY_LOOKUP_MAX]

Response200 OK

getsarray of objectsRequired
gets[].downloadobjectRequired
a presigned get
gets[].download.expires_atstring (date-time)Required
gets[].download.urlstringRequired
gets[].objectstringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/registry/lookup" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "objects": [
      "acme/platform"
    ]
  }'
POST/v1/ci/workers/{id}/toolchains

Publish a toolchain pack

The grant and a put per chunk to store a pack a trusted task installed, or why not.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

data_dirstringRequired
the absolute MISE_DATA_DIR the installs bake into their paths
mise_versionstringRequired
the first line of mise --version
platformstringRequired
<os>-<arch>-<os-release ID>-<VERSION_ID>, linux-aarch64-ubuntu-24.04
chunksarray of objectsRequired
chunks[].digeststringRequired
sha-256 digest as sha256:<64 hex>
chunks[].sizeintegerRequired
contentstringRequired
sha-256 digest as sha256:<64 hex>
entriesintegerRequired
install_userboolean
the install ran as the install user, whose tree no task can write (a root worker's unit); a worker that installs as its own uid, the uid its tasks run as, sends false or nothing and is refused runner
requestedstringRequired
resolvedstringRequired
task_idstringRequired
the lease's task whose install this was: its tier decides whether the store takes it
toolstringRequired
unpacked_bytesintegerRequired

Response201 Created

grantstring or null
putsarray of objects
puts[].expires_atstring (date-time)Required
puts[].headersmap of string
puts[].methodstringRequired
puts[].urlstringRequired
reasonstring or null
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/toolchains" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data_dir": "acme/platform",
    "mise_version": "2026.10.0",
    "platform": "linux-aarch64-ubuntu-24.04",
    "chunks": [
      {
        "digest": "sha256:c21fa32a40d82233c44e76e6ae776b4d403ac1a564ca26de95a14c6bb47eaf49",
        "size": 18432000
      }
    ],
    "content": "sha256:2dac0aeb3eb528642a9b980efb4608061784f3ad33dc2495133b849f8afec981",
    "entries": 1,
    "install_user": true,
    "requested": "acme/platform",
    "resolved": "acme/platform",
    "task_id": "tsk_011ec0cc99550d0e90bc9fed5781decd",
    "tool": "acme/platform",
    "unpacked_bytes": 18432000
  }'
POST/v1/ci/workers/{id}/toolchains/commit

Commit a toolchain pack

Every chunk landed: the cell signs the granted toolchain pack and makes it the current one.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

grantstringRequired

Response201 Created

key_idstringRequired
signaturestringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/toolchains/commit" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "grant": "acme/platform"
  }'
POST/v1/ci/workers/{id}/toolchains/lookup

Read toolchain packs

The cell store's signed toolchain packs for the worker's platform, each with presigned chunk gets.

Permission: ci:workers.lease

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

data_dirstringRequired
the absolute MISE_DATA_DIR the installs bake into their paths
mise_versionstringRequired
the first line of mise --version
platformstringRequired
<os>-<arch>-<os-release ID>-<VERSION_ID>, linux-aarch64-ubuntu-24.04
wantsarray of objectsRequired
wants[].requestedstringRequired
wants[].toolstringRequired

Response200 OK

packsarray of objects
one per want the store holds; a want without one installs from upstream
packs[].chunksarray of objectsRequired
packs[].chunks[].digeststringRequired
sha-256 digest as sha256:<64 hex>
packs[].chunks[].downloadobjectRequired
a presigned get
packs[].chunks[].download.expires_atstring (date-time)Required
packs[].chunks[].download.urlstringRequired
packs[].chunks[].sizeintegerRequired
packs[].contentstringRequired
sha-256 of the uncompressed tar stream
packs[].entriesintegerRequired
packs[].key_idstringRequired
the cell key's id (ciresk_ci_provenance::PublicKey::key_id) and the base64 ed25519 signature
packs[].produced_atstring (date-time)Required
packs[].requestedstringRequired
packs[].resolvedstringRequired
packs[].signaturestringRequired
packs[].toolstringRequired
packs[].unpacked_bytesintegerRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/toolchains/lookup" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "data_dir": "acme/platform",
    "mise_version": "2026.10.0",
    "platform": "linux-aarch64-ubuntu-24.04",
    "wants": [
      {
        "requested": "acme/platform",
        "tool": "acme/platform"
      }
    ]
  }'
POST/v1/ci/workers/{id}/undrain

Undrain a worker

Lease again after a drain.

Permission: ci:workers.admin

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Response200 OK

statestringRequired
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/undrain" \
  -H "Authorization: Bearer $CIRESK_KEY"
POST/v1/ci/workers/{id}/warm

Get the warm plan

The pool's hot repositories with their seed packs and current warm-state bundles.

Permission: ci:workers.lease

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Response200 OK

reposarray of objects
hottest first
repos[].bundlesarray of objects
repos[].bundles[].archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
repos[].bundles[].generationintegerRequired
repos[].bundles[].repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
repos[].bundles[].slotintegerRequired
repos[].bundles[].bytesintegerRequired
compressed, the sum of the chunks
repos[].bundles[].chunksintegerRequired
repos[].bundles[].data_dirstringRequired
the producer's data dir: the slot is restored only at the same absolute path
repos[].bundles[].entriesintegerRequired
the tar entries the stream holds; a restore that meets another number refuses the bundle
repos[].bundles[].produced_atstring (date-time)Required
repos[].bundles[].ranarray of objects
repos[].bundles[].ran[].namestringRequired
repos[].bundles[].ran[].runstringRequired
repos[].bundles[].ruststring or null
the rust release that built target/ (1.91.0), from its .rustc_info.json; a member without that release installed rebuilds anyway and skips the bundle
repos[].bundles[].tree_rootstring or null
the tree the slot's tree.idx holds
repos[].bundles[].unpacked_bytesintegerRequired
the tar stream's length, what the restore writes about
repos[].demandinteger
the repository's trusted tasks the caller could lease now or soon, and those it holds: a member restores at once at most this many of its slots, the rest only once it has run 10 minutes and only if it ran the repository or it is wanted then. 0 from a server that does not say, which restores a wanted repository whole
repos[].imagesarray of objects
the repository's current slot images, lineage 0 first; a member with slot_images on mounts these and restores a bundle only into a slot no image fits
repos[].images[].archstringRequired
std::env::consts::ARCH of the producer (aarch64, x86_64)
repos[].images[].generationintegerRequired
repos[].images[].lineageintegerRequired
repos[].images[].repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
repos[].images[].chunksintegerRequired
non-zero chunks, and their raw and stored sums
repos[].images[].gidintegerRequired
repos[].images[].image_bytesintegerRequired
the image's size, holes included
repos[].images[].manifestobjectRequired
an object of the store by its sha-256 and size: the manifest, or a stored chunk
repos[].images[].manifest.digeststringRequired
sha-256 digest as sha256:<64 hex>
repos[].images[].manifest.sizeintegerRequired
repos[].images[].manifest_downloadobjectRequired
a presigned get
repos[].images[].manifest_download.expires_atstring (date-time)Required
repos[].images[].manifest_download.urlstringRequired
repos[].images[].produced_atstring (date-time)Required
repos[].images[].ranarray of objects
repos[].images[].ran[].namestringRequired
repos[].images[].ran[].runstringRequired
repos[].images[].raw_bytesintegerRequired
repos[].images[].ruststring or null
the rust release that built target/; a member without it installed skips the image
repos[].images[].stored_bytesintegerRequired
repos[].images[].tracearray of integers
chunk indices in the order earlier first tasks read them, fetched before any other
repos[].images[].tree_rootstring or null
the root digest of a working tree: sha-256 of the root directory manifest
repos[].images[].uidintegerRequired
the task user and group that own the image's files
repos[].images[].workspace_pathstringRequired
the path the producer's tasks saw the slot at: a member mounts the image only into a slot whose tasks see the same path (the slot's own path today, the fixed <warm root>/ws under CIR-532)
repos[].repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
repos[].seed_packobject or null
one tar of a recent default-branch tree of the lease's repository, its blobs and directory manifests named by digest, so a worker whose cas lacks the tree seeds it with a few ranged gets before it fetches the difference blob by blob. an accelerator: every entry is re-hashed on arrival, and a pack that is absent, too large or broken changes nothing but the number of gets
repos[].seed_pack.bytesintegerRequired
repos[].seed_pack.downloadobjectRequired
a presigned get
repos[].seed_pack.download.expires_atstring (date-time)Required
repos[].seed_pack.download.urlstringRequired
repos[].seed_pack.entriesintegerRequired
repos[].seed_pack.rootstringRequired
the tree the pack was built from; its root manifest is the pack's last entry, so a cas that holds the root was seeded already
repos[].task_secondsintegerRequired
trusted_interactive task-seconds over the last 24 hours on the workers of this pool
repos[].tenantstringRequired
the cas partition the seed pack goes into (the worker's own tenant)
repos[].wantedboolean
demand is above 0. a server that does not say is taken as wanting every repository, as before
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/warm" \
  -H "Authorization: Bearer $CIRESK_KEY"
POST/v1/ci/workers/{id}/workspaces

Report a worker's workspaces

Workspaces and mirror commits a worker holds.

Permission: ci:workers.report

Parameters

NameTypeRequiredDescription
idpathstringRequiredThe worker's ID.

Request body

commitsarray of objects
commits[].repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
commits[].shasarray of stringsRequired
workspacesarray of objects
workspaces[].base_digeststring or null
workspaces[].bytesintegerRequired
workspaces[].kindstringRequired
One of warm, ephemeral
workspaces[].pathstringRequired
workspaces[].repo_idstringRequired
uuidv7 rendered as repo_<32 hex>
workspaces[].staleboolean
bytes is what the worker recorded at its last walk, not a measurement of now: a worker posts its recorded sizes at boot and walks in the background, so the first lease never waits for a cold-cache stat of every file; the api keeps a row's fresh bytes over a stale report
workspaces[].statestringRequired
One of ready, in_use, dirty, evicting, gone

Response201 Created

evictarray of strings
curl -X POST "$CIRESK_API/v1/ci/workers/wrk_01d0a4beab0d9d6aef88ffcdc85fd344/workspaces" \
  -H "Authorization: Bearer $CIRESK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "commits": [
      {
        "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
        "shas": [
          "feef45d804737fdf7a297e27e443d914551629de"
        ]
      }
    ],
    "workspaces": [
      {
        "base_digest": "feef45d804737fdf7a297e27e443d914551629de",
        "bytes": 18432000,
        "kind": "warm",
        "path": ".ciresk/ci.yaml",
        "repo_id": "repo_0129354d7b6b4146ad16c315d960365b",
        "stale": false,
        "state": "ready"
      }
    ]
  }'