At a glance

GET    /api/health
POST   /api/runs            # real repo run in the CloudboxRunner container
POST   /api/computers       # materialize a ComputerSpec workspace
POST   /api/brief
GET    /api/c/:id/list
GET    /api/c/:id/read?path=...
POST   /api/c/:id/write
POST   /api/c/:id/ask
POST   /api/c/:id/submit
GET    /api/c/:id/grade
GET    /api/c/:id/receipts
GET    /api/c/:id/spec

When CLOUDBOX_API_TOKEN is set, authenticated endpoints require Authorization: Bearer $CLOUDBOX_API_TOKEN (or x-cloudbox-token).

Health

curl http://localhost:8799/api/health
# → { "ok": true, "name": "cloudbox" }

Run a real repo

The runner surface. Cloudbox boots the cloudbox-runner Cloudflare Container, clones a public GitHub repo, executes commands, then verify, collects the requested artifact, and returns the trail.

curl -X POST https://cloudbox.coey.dev/api/runs \
  -H "authorization: Bearer $CLOUDBOX_API_TOKEN" \
  -H 'content-type: application/json' \
  -d '{
    "repo": "https://github.com/acoyfellow/cloudbox",
    "commands": ["pnpm install --ignore-scripts"],
    "verify": ["pnpm run build", "pnpm run test"],
    "artifact": "HANDOFF.md"
  }'

Response shape:

type ContainerRunResult = {
  runId: string;
  ok: boolean;
  receipts: ContainerRunReceipt[];      // clone, command, verify, diff steps
  runnerReceipts: RunnerLifecycleEvent[]; // container boot / request / error
  artifact?: { path: string; content: string } | null;
  diff?: string;
  error?: string;
};

Each ContainerRunReceipt carries cmd, code, signal, stdout, stderr, startedAt, finishedAt. Non-zero verify exit codes set ok: false and return HTTP 422.

runnerReceipts are the computer proof layer. They show whether the CloudboxRunner Durable Object started or reused a Container, how many readiness attempts were needed, how long boot took, and when the runner responded. Typical events are runner.container.start, runner.container.ready_attempt, runner.container.ready, runner.response, and runner.container.not_ready.

Recent runs are available when D1 is bound:

GET /api/runs/recent
GET /api/runs/:runId

Materialize a workspace

curl -X POST http://localhost:8799/api/computers \
  -H 'content-type: application/json' \
  -d @spec.json
# → { "id": "cb_abc123…", "baseUrl": "/api/c/cb_abc123…" }

The id is a deterministic content hash of the spec. The same spec returns the same id every time — re-materializing is idempotent.

Brief → spec

curl -X POST http://localhost:8799/api/brief \
  -H 'content-type: application/json' \
  -d '{"brief":"A staff engineer triaging an open PR with failing CI."}'
# → { "spec": { profile, filesystem, collaborators, objectives, rubric } }

The draft spec is a starting point — edit it, then POST it to /api/computers to materialize. v0 is a deterministic stub; the Workers AI-backed structured generator lands in a later phase.

List files

curl http://localhost:8799/api/c/$ID/list
# → { "files": [{ "path": "...", "kind": "...", "state": "..." }, ...] }

Read a file

curl "http://localhost:8799/api/c/$ID/read?path=docs/auth-redesign.md"
# → { "path": "...", "kind": "...", "content": "..." }

Records a read receipt.

Write a file

curl -X POST http://localhost:8799/api/c/$ID/write \
  -H 'content-type: application/json' \
  -d '{"path":"notes/triage.md","content":"# Notes\n…"}'
# → { "path": "...", "written": <bytes> }

Records a write receipt.

Ask a collaborator

curl -X POST http://localhost:8799/api/c/$ID/ask \
  -H 'content-type: application/json' \
  -d '{"who":"arch","message":"Should this use a queue?"}'
# → { "from": "arch", "role": "reviewer", "style": "architectural", "reply": "..." }

Records an ask receipt. The who value is the collaborator’s id from the spec.

Submit a decision

curl -X POST http://localhost:8799/api/c/$ID/submit \
  -H 'content-type: application/json' \
  -d '{"objective":"triage","decision":"request-changes","notes":"..."}'
# → { "objective": "...", "accepted": true }

Records a submit receipt. objective is the objective’s id from the spec.

Grade

curl http://localhost:8799/api/c/$ID/grade
# → {
#     "score": 4,
#     "max": 5,
#     "totalWeight": 6,
#     "passed": ["design-first", "decided"],
#     "failed": ["right-reviewer"],
#     "ungraded": ["explain-ci"],
#     "detail": [...]
#   }

Pure replay of the receipt log against the rubric. Idempotent — call it as many times as you want; the score is a function of the receipts at that moment.

Receipts

curl http://localhost:8799/api/c/$ID/receipts
# → { "receipts": [{ "ts", "kind", "payload" }, ...] }

The full append-only log. Useful for debugging an agent’s behavior.

Spec

curl http://localhost:8799/api/c/$ID/spec
# → the original ComputerSpec