Runs
Ingest, fetch, and review runs. All routes require client credentials and are scoped to the authenticated repository. See Authentication.
POST /api/v1/runs
Ingest a run report (the JSON the CLI writes with dungbeetle ci --json).
Request body
{
"report": { "...": "the CLI's JSON report" },
"branch": "main",
"commit": "a1b2c3d"
}branch and commit are optional. The repository is authoritative from the credentials, so any report.project field is advisory.
Responses
201 Created—{ "run": { "id", "status", "url", ... } }, whereurlis the canonicalGET /api/v1/runs/:idlink.400 Bad Request— body isn't valid JSON, or fails report validation ({ "error": "…" }).402 Payment Required— the write is blocked by a hard plan limit or a past-due account (managed billing mode).413 Payload Too Large— body exceeds the configured limit.
curl -u "$CID:$CSEC" -X POST http://localhost:4317/api/v1/runs \
-H 'content-type: application/json' \
-d '{"report": '"$(cat .dungbeetle/ci-report.json)"', "branch":"main","commit":"'"$GIT_SHA"'"}'GET /api/v1/runs/:id
Fetch a stored run and its full report. Returns 404 if the run doesn't exist or belongs to another repository.
200 OK
{ "run": { "id", "status", "url", "reviewState", ... }, "report": { "...": "..." } }reviewState is the current approved / rejected / pending decision.
Screenshots are not embedded in the report. On ingest the server offloads each result's before/after/diff PNGs to blob storage and replaces them with content-addressed ids under result.screenshotRefs ({ baseline?, candidate?, diff? }, each a sha-256). Fetch the bytes from the screenshot endpoints. (Older runs ingested before this change may still carry inline base64 under result.screenshot.)
POST /api/v1/runs/:id/review
Record an approve/reject/pending decision on a run — the same review the web UI records, for CI and the MCP server (no cookie/CSRF path). The reviewer of record is the repository's owning user.
Request body
{ "state": "approved", "note": "intended change", "promote": true }state(required) —approved,rejected, orpending.note(optional) — appended to the append-only audit trail.promote(optional) — whentrueandstateisapproved, the run's candidate snapshots become new hosted baseline versions (deduped by digest).
Responses
200 OK—{ "review": { "state", "reviewer", "note", ... }, "promoted": [ { "target", "version", "deduped" }, ... ] }.400 Bad Request— invalid JSON orstate.404 Not Found— the run doesn't exist or belongs to another repository.