API reference¶
The API runs the same pipelines as the CLI over HTTP, so a UI or other tooling can drive them. Each POST starts a pipeline as a background task and returns the task's ID at once. You then poll the task for its log and, when it finishes, its result.
Running the server¶
The API is an optional extra:
uv sync --extra api # or: pip install 'developer[api]'
developer serve # 127.0.0.1:6768; --host and --port to change
To serve beyond this machine, set DEVELOPER_API_TOKEN first. Every endpoint except the health check then needs it as a bearer token:
Without a token the server accepts any request, so developer serve refuses to start without one on anything but a loopback address. --allow-insecure overrides the refusal:
That is reasonable when something else controls who can reach the port: a container whose port is published only on the host's loopback, a firewall or VPN, or a reverse proxy that handles login. Otherwise anyone who can reach the port can run agents that push to your repos. A token that is set is still enforced, with or without the flag.
Example¶
auth="Authorization: Bearer $DEVELOPER_API_TOKEN"
curl -X POST localhost:6768/review -H "$auth" \
-H 'Content-Type: application/json' -d '{"repo": "myrepo", "pr": 42}'
# {"task_id": "a1b2c3d4e5f6", "status": "pending"}
curl localhost:6768/tasks/a1b2c3d4e5f6 -H "$auth"
{
"task_id": "a1b2c3d4e5f6",
"status": "completed",
"log": ["Reviewing PR #42", "Fetching PR #42 from gregology/myrepo...", "Review pipeline complete"],
"result": {
"pipeline": "review",
"dry_run": false,
"pr": 42,
"comment_url": "https://github.com/gregology/myrepo/pull/42#issuecomment-123",
"metrics": [{"stage": "analyze", "model": "claude-opus-5-5", "turn_count": 12, "cost_usd": 0.41}]
},
"error": null
}
(The log and metrics above are shortened.)
Endpoints¶
| Method and path | Body | Does |
|---|---|---|
GET / |
Health check, no token needed: {"status": "ok"} |
|
GET /repos |
Lists the repos in developer.yaml: [{"name", "owner", "repo"}] |
|
POST /repos |
{"owner", "repo"} |
Starts add: investigates the repo and writes its config. Returns 202 |
POST /resolve |
{"repo", "issue", "dry_run"} |
Starts resolve on an issue |
POST /review |
{"repo", "pr", "dry_run"} |
Starts review on a PR |
POST /address |
{"repo", "pr", "dry_run"} |
Starts address on a PR |
POST /audit/{type} |
{"repo", "dry_run", "limit"} |
Starts an audit. type is docs, refactor or tests |
POST /validate |
{"repo"} or {"validate_all": true} |
Starts validate on one repo or all of them |
GET /tasks |
Lists every task, newest first | |
GET /tasks/{task_id} |
Shows one task |
repois a key indeveloper.yaml("myrepo") or"owner/repo".dry_rundefaults tofalse. Like the CLI's--dry-run, the pipeline does the work but publishes nothing.limitcaps an audit's findings and defaults to 3.- Developer reads
developer.yamlon every request, so you can edit it without restarting the server.
Every POST that starts a task returns {"task_id": "...", "status": "pending"}.
Tasks¶
| Field | Description |
|---|---|
task_id |
The task's ID |
status |
pending, running, completed or failed |
log |
What Developer logged while the task ran, one line per entry |
result |
The pipeline's result once the task completes, otherwise null |
error |
Why the task failed, otherwise null |
Only one active task may work on each target: an issue, a PR (review and address count as the same target), a kind of audit, or a repo being added or validated. A second request for that target gets a 409 until the first task finishes.
Tasks run in background threads and live in the server's memory. Restarting the server forgets them, and past 1000 tasks the oldest finished ones are dropped. Each run also leaves a record in runs/, the same as a CLI run (see Architecture).
Results¶
Every result has a pipeline field. The remaining fields depend on the pipeline:
pipeline |
Fields |
|---|---|
resolve |
dry_run, issue, decision, pr_url, comment_url, metrics |
review |
dry_run, pr, comment_url, metrics |
address |
dry_run, pr, comment_url, metrics |
audit |
dry_run, audit, findings, issue_urls, metrics |
validate |
results (repo name to true/false), all_passed |
add_repo |
repo (its key in developer.yaml), config_saved |
decisionis the triage decision:ask,propose,action_proposed,action_direct,declineordecision.pr_urlandcomment_urllink to the PR or comment the run published. They arenullwhen it published none, as on a dry run. A resolve run publishes either a PR or a comment.findingsholds the audit's findings. Each one has atitle,bodyandlabels, and docs findings also have averdictandconfidence.issue_urlsholds the issues filed for them, and is empty on a dry run.metricshas one entry per stage, holding itsstage,model,duration_seconds,turn_count,tool_call_count, token counts,cost_usd,model_usageandrate_limits. These are the same numbers as in the metrics block on what Developer posts.
Errors¶
Errors return {"detail": ...}.
| Status | When |
|---|---|
400 |
Unknown audit type, or /validate without repo or validate_all |
401 |
Missing or wrong bearer token, when the server has one |
404 |
Unknown repo or task |
409 |
The repo is already configured (POST /repos), or another task is working on the same target |
422 |
The body is missing a field or has one of the wrong type |
Interactive docs¶
While the server is running, FastAPI serves documentation generated from the request and response models at /docs (Swagger UI) and /redoc.