Provisioning
Endpoints that drive the Devcontainers pipeline: discover available features and runtimes, trigger or rebuild a crew’s cached image, and inspect the local cache. Implementation lives ininternal/api/crew_provisioning_jobs.go and internal/api/crew_provisioning_cache.go; the underlying provisioner is in internal/devcontainer/.
All routes require authentication and are workspace-scoped where they touch crew rows.
Endpoints
Environment revisions
read action. Request:
crewId path parameter; no body or pagination parameters. Response: JSON
object containing revisions and the fixed limit: 100, newest records first.
Statuses: 200 OK; 401 Unauthorized at authentication middleware;
403 Forbidden without the read role; 404 Not Found for a missing, deleted or
other-workspace crew; 500 Internal Server Error on storage/evidence errors.
Each revision contains id, definition_hash, build_hash, image_id,
created_at and nullable toolchain inventory/qualification evidence. Raw
configuration values and credentials are omitted. Empty history returns an
empty array. Records describe builds, not running containers; this endpoint
neither checks whether image bytes still exist nor performs retention or rollback.
Catalogs
Discover the features and runtimes a crew can pin in itsdevcontainer_config.
Feature catalog
search query parameter; no body. Response: JSON object with a features array. Statuses: 200 OK on success; the catalog remains available through the documented fallback when the dynamic fetch fails.
Lists devcontainer features Crewship can install. The dynamic fetcher pulls from upstream registries (ghcr.io/devcontainers/features/*, ghcr.io/devcontainers-extra/features/*, ghcr.io/crewship-ai/features/*); when that fails, the handler falls back to internal/devcontainer.FallbackCatalog so the UI is never empty.
?search= filters by name, description, or category (server-side substring).
Response: 200 OK
Unknown publishers (anything outside the three allowlisted prefixes) are rejected at provisioning time even if they appear in a custom catalog — see
internal/devcontainer/features.go.
Runtime catalog
search query parameter; no body. Response: JSON object with a runtimes array. Statuses: 200 OK on success; the catalog uses the documented fallback when the dynamic fetch fails.
Lists the mise-managed runtimes (Node, Python, Go, Terraform, kubectl, …) the workspace can pin in devcontainer_config.mise. Falls back to FallbackRuntimeCatalog when the dynamic fetcher fails.
Not a base-image catalog. The base-image list is CLI-only — crewship features base-images reads baseImagesCatalog directly from cmd/crewship/cmd_features.go; there is no HTTP endpoint for it today.
Response: 200 OK
Crew provisioning lifecycle
Inspect, trigger, rebuild, and recycle a crew’s cached image and runtime container.Provision status
crewId must belong to that workspace. Request: crewId path parameter; no body. Response: JSON provision-status object described below. Statuses: 200 OK; 404 Not Found when the crew is not in the workspace; 503 Service Unavailable when provisioning is not configured.
Response: 200 OK. Always-present fields come from the crews row; the step / total / message / steps / log_tail / started_at / completed_at / error fields appear when an in-memory job is currently running or recently finished for this crew. error, log_tail and completed_at also surface without a live job when the crew’s most recent build outcome was a failure — they are read back from the journal, so they survive the in-memory job’s TTL and a server restart.
status is one of:
Trigger provision
create role action. Request: crewId path parameter; no body. Response: JSON { "status": "started", "message": "…" }. Statuses: 202 Accepted; 400, 403, 404, 409, 429, 500, or 503 for the conditions listed below.
Requires the create role action (OWNER, ADMIN, MANAGER). Returns 202 immediately and runs the pipeline in a background goroutine; poll the status endpoint for progress.
Response: 202 Accepted
type, title, status, detail, instance) as application/json. Authentication, workspace and role guards use { "error": "…" }; rebuild also uses that envelope for unexpected enqueue failures.
Rebuild
create role action. Request: crewId path parameter; no body. Response: the same JSON shape as the trigger endpoint. Statuses: 202 Accepted; 400, 401, 403, 404, 409, 429, 500, or 503 when the corresponding provisioning or middleware condition applies.
Triggers a fresh build that bypasses the provisioned-image cache and the installation-layer caches, so floating tool selectors can resolve newer versions. The previously selected image stays in place until the new build publishes: a failed or superseded rebuild leaves the previous image and its requirements selected, and the crew remains startable throughout. Use when upstream features publish breaking updates under the same tag.
Response: 202 Accepted — same shape as Trigger.
Restart agents
update role action. Request: crewId path parameter; no body. Response: JSON { "restarted": <count> }. Statuses: 200 OK; 400, 403, 404, 500, or 503 for the conditions listed below.
Force-removes the crew’s runtime container so the next agent exec recreates it from the current cached_image — without rebuilding the image. Used when an env-var change should take effect without the cost of a new image. Idempotent: when no container is running it still returns 200 OK with { "restarted": 0 }.
Requires the update role action (OWNER, ADMIN, MANAGER).
Response: 200 OK with { "restarted": <count> } — the count is the number of non-deleted agents in the crew (they share one container, so all are recreated together).
Image freshness
A crew container is created once and reused until something recreates it. On a long-lived crew that can be weeks, during which the image tag it was built from keeps moving — so the container quietly becomes a snapshot of an older release. These two endpoints report that and fix it. See Keeping crew images current for the full story, including the daily check and the notification it raises.Image status
VIEWER — noticing that a crew is behind is a read. Request: crewId path parameter; no body. Response: JSON object with crew_id, image, container_id, running, running_digest, resolved_digest, behind and reason. Statuses: 200 OK; 400 on an empty crew ID, 404 when the crew is not in the workspace, 500 on a daemon failure, 503 when no container provider can report image digests.
Compares the registry manifest digest the crew’s running container was created from against what its tag resolves to on the registry right now. It never pulls and never restarts anything.
Refresh image
update role action (OWNER, ADMIN, MANAGER). Request: crewId path parameter; no body. Response: JSON object with crew_id, image, previous_digest, new_digest and container_removed. Statuses: 200 OK; 400, 403, 404, 500, or 503 for the conditions listed below.
Pulls the crew’s configured image, then force-removes its runtime container so the next agent exec recreates it from the fresh copy. The pull happens first: if it fails, the crew is left exactly as it was rather than without a container and without an image.
Idempotent — a crew that is already current transfers nothing, and one with no container has nothing to drop (container_removed: false).
Not the same as Restart agents. restart-agents drops the container without pulling, which picks up a devcontainer image you have already rebuilt locally. refresh-image pulls first, which is what picks up a base image that has moved on in the registry.
Cache image registry
Inspect and prune the locally builtcrewship-cache:* images. This registry is per-host, not per-workspace — see Tenancy.
List cached images
images array. Statuses: 200 OK; 500 on Docker image-list failure; 503 when Docker is not configured.
Response: 200 OK
Requires the
read role action (any workspace member). Returns 503 ({ "error": "cache management not available (Docker client not configured)" }) when no Docker client is wired, and 500 on a Docker ImageList failure.
Images orphaned from any crew (i.e. referenced_by is empty) are eligible for the GC sweeper. See CREWSHIP_CACHE_GC_AUTODELETE.
Delete cached image
delete role action (ADMIN or OWNER). Request: tag path parameter and optional force=true query parameter; no body. Response: JSON deletion result with tag and status. Statuses: 200 OK; 400 for an invalid tag, 403 for insufficient role, 409 when a referenced image is not forced, 500 for Docker removal failure, or 503 when Docker is not configured.
Removes a cached image. By default refuses to delete an image still referenced by a live crew (returns 409 Conflict). Pass ?force=true to delete anyway.
Requires the delete role action (OWNER, ADMIN only — a MANAGER is rejected with 403).
Response: 200 OK
409 Conflict body lists the referencing crew slugs under referenced_by. The reference check is host-global — it counts crews in any workspace, so an image another tenant still uses cannot be force-free-deleted by accident:
Tenancy
crewIdon the provision-status / trigger / rebuild / restart-agents routes is validated against the session workspace via thecrews.workspace_idSELECT; a crew in another workspace returns404.- The cache image registry is per-host, not per-workspace — operators sharing a Docker daemon will see each other’s tags, and the cache routes do not workspace-scope the
{tag}path param.GET /cache/imagesscopes only thereferenced_byannotation to the caller’s workspace;DELETE /cache/images/{tag}deliberately checks references across all workspaces so a tag another tenant depends on cannot be deleted without?force=true. There is no cross-tenant404on a{tag}— the tag namespace is shared by design.
Related
- Devcontainers guide — full provisioning pipeline.
crewship features,crewship runtimes— CLI wrappers.- Configuration — Devcontainer Cache GC —
CREWSHIP_CACHE_GC_AUTODELETE.