Runtime

Containers

Create, inspect, start, stop, resume, rename, and troubleshoot Quilt containers.

Containers are the main runtime unit in Quilt.

If Quilt were a city, containers would be the individual buildings where the actual work happens. Almost everything else either prepares them, inspects them, or manages how they evolve over time.

Primary Routes

GET    /api/containers
GET    /api/containers?state=<state>
GET    /api/containers/<container_id>
GET    /api/containers/by-name/<name>
GET    /api/containers/<container_id>/ready
GET    /api/containers/<container_id>/metrics
GET    /api/containers/<container_id>/logs?limit=<n>
POST   /api/containers
POST   /api/containers/batch
POST   /api/containers/<container_id>/start
POST   /api/containers/<container_id>/rename
POST   /api/containers/<container_id>/kill
POST   /api/containers/<container_id>/stop
POST   /api/containers/<container_id>/resume
POST   /api/containers/<container_id>/snapshot
POST   /api/containers/<container_id>/fork
DELETE /api/containers/<container_id>

A Clean Mental Model

  • POST /api/containers creates and starts a container in one atomic request.
  • GET /api/containers/<id> tells you what runtime state it is in now.
  • GET /api/containers/<id>/ready tells you whether it is actually ready for specific kinds of work.

That distinction matters a lot.

Create a Container

{
  "name": "demo",
  "image": "prod",
  "oci": false,
  "volumes": ["data-volume:/workspace"],
  "working_directory": "/app",
  "memory_limit_mb": 1024,
  "cpu_limit_percent": 50,
  "strict": true,
  "labels": {
    "team": "qa"
  },
  "environment": {
    "FOO": "bar"
  },
  "command": ["/bin/sh", "-lc", "echo hello"]
}

Important Rules

  • name is required.
  • command must be an argv array, not a single shell string.
  • Use volumes, not mounts, for persistent storage attachment.
  • Volume attachments use <volume-name>:<target-path>.
  • prod-gui is special and does not accept a custom command.

What Quilt Returns

Quilt lifecycle routes are split into two categories.

Direct synchronous routes — these complete before returning:

  • POST /api/containers — returns 201 Created with the full container and readiness payload after create, startup, and readiness evaluation complete
  • POST /api/containers/:id/stop — returns 200 OK after graceful stop, state transition, and usage emission complete
  • POST /api/containers/:id/kill — returns 200 OK after force kill and exited-state bookkeeping complete
  • DELETE /api/containers/:id — returns 200 OK after teardown and state removal complete

For these routes, success means the action is already done — not queued.

Operation-driven routes — these return 202 Accepted with an operation handle:

  • POST /api/containers/:id/start
  • POST /api/containers/:id/resume
  • Batch create, snapshot, fork, and clone flows
{
  "success": true,
  "operation_id": "op_123",
  "status_url": "/api/operations/op_123"
}

For operation-driven routes, the response is a receipt, not proof that the work is already done.

Create Response Shape

POST /api/containers returns the full created container on 201 Created:

{
  "container_id": "ctr_123",
  "tenant_id": "ten_abc",
  "name": "demo",
  "state": "running",
  "pid": 12345,
  "exit_code": null,
  "ip_address": "10.0.0.5",
  "created_at": "2026-04-17T10:00:00Z",
  "started_at": "2026-04-17T10:00:01Z",
  "exited_at": null,
  "working_directory": "/app",
  "memory_limit_mb": 1024,
  "cpu_limit_percent": 50,
  "strict": true,
  "gpu_count": 0,
  "gpu_ids": [],
  "labels": { "team": "qa" },
  "exec_ready": true,
  "network_ready": true,
  "checks": {
    "state_running": true,
    "minit_responsive": true,
    "network_configured": true,
    "managed_image_valid": true,
    "gui_backend_reachable": null
  }
}

gui_ready and gui_backend_reachable are only present for managed GUI containers.

Readiness: The Field People Skip Too Often

Readiness checks tell you what the container can actually do.

Important fields:

  • exec_ready: the container is running, minit is responsive, and the managed image contract is valid.
  • network_ready: network allocation is configured.
  • gui_ready: only present for prod-gui, and adds GUI backend reachability on top of exec_ready and network_ready.

Readiness Example

curl \
  -H "X-Api-Key: $QUILT_API_KEY" \
  https://backend.quilt.sh/api/containers/ctr_123/ready

What exec_ready Does Not Mean

exec_ready is not the same as:

  • your app being healthy
  • your web server already listening
  • the GUI being reachable
  • your custom bootstrap script being finished

It only means the container is ready for Quilt’s exec contract.

Resolve by Name, Operate by ID

You can resolve a container by name:

GET /api/containers/by-name/<name>

But once you know the real container_id, use that instead. IDs are safer and less ambiguous.

Rename, Stop, Kill, Resume

Rename is a direct mutation:

{
  "new_name": "renamed-container"
}

Behavior summary:

  • rename is direct, not operation-driven
  • kill is direct, not operation-driven
  • stop is direct, not operation-driven
  • resume and start are operation-driven

Batch Create

If you want several similar containers at once:

{
  "items": [
    { "name": "web-1" },
    { "name": "web-2", "command": ["/bin/sh", "-lc", "echo ready"] }
  ]
}

A Beginner-Friendly First Workflow

1

Create the container

curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $QUILT_API_KEY" \
  https://backend.quilt.sh/api/containers \
  -d '{
    "name": "demo",
    "image": "prod",
    "command": ["/bin/sh", "-lc", "echo hello && sleep 300"]
  }'

The response is 201 Created with the full container and readiness payload. No operation polling needed.

2

Check readiness in the response

Inspect exec_ready and network_ready in the create response. If exec_ready=true, the container is already ready.

You can also poll GET /api/containers/<container_id>/ready if you need to recheck later.

3

Run commands

Once exec-ready, use the exec API or a terminal session.

GPU Note

GPU requests belong in the create payload using gpu_count and optionally gpu_ids. The platform validates bad GPU shapes before creating an operation.

Possible deterministic failures:

  • 400 for invalid GPU shapes
  • 403 for plan-gated requests
  • 503 CAPACITY_FULL when the host does not have GPU capacity

Common Mistakes

Because container detail returns runtime status, not the original create-time request. Do not expect it to echo fields like image, command, or attached volumes in full.

Not directly. Quilt expects argv. If you need shell parsing, wrap it explicitly:

{
  "command": ["/bin/sh", "-lc", "npm test && npm run lint"]
}

It is a boolean hardening flag that is echoed back on list and detail responses when supplied, which lets you confirm the container was created with stricter behavior.

Next Step

Once you can create and inspect containers, move to Exec to run work inside them.