All browser routes are HTML. Machine routes are JSON. Errors use:
{ "error": { "type": "quota_exhausted", "code": "FLEDGE_QUOTA_EXHAUSTED", "message": "..." } }| Method | Path | Auth | Purpose |
|---|---|---|---|
| GET | / |
public | Landing or redirect to dashboard |
| GET | /auth/github |
public | Start OAuth |
| GET | /auth/github/callback |
public | OAuth callback |
| GET | /auth/github/app/install |
approved | Redirect to the GitHub App installation page |
| GET | /auth/github/app/installed |
approved | Bind an installation to the current user (falls back to a matching unbound installation) |
| GET | /auth/github/app/callback |
approved | Alias for the installed callback |
| GET | /auth/github/reauthorize |
approved | Re-authorize with repo scope for user-attributed App writes |
| GET | /repos/new |
approved | GitHub App installations and repository picker |
| POST | /repos/app |
approved + CSRF | Connect repositories through an installation |
| POST | /api/github/webhook |
GitHub signature | GitHub App webhook ingestion and CI/review follow-up |
| POST | /auth/token |
public, rate-limited | Sign in with a GitHub token when OAuth is not configured |
| POST | /auth/logout |
session + CSRF | Sign out |
| GET | /apply |
session | Disclaimer and information-security signature |
| POST | /apply |
session + CSRF | Submit the signed application once |
| GET | /apply/status |
session | Live queue position and status |
| GET | /api/application |
session | JSON status/queue for the status page |
| GET | /dashboard |
approved + session | Repos, quota, jobs, personal delivery metrics (?window=7 or 30) |
| GET | /console |
approved + session | Workspace overview (repos, jobs, quota) |
| POST | /repos |
approved + CSRF | Add an upstream repository; Fledge checks or creates the user's fork |
| GET | /repos/:id |
owner | Repo detail, including the selected role, delivery board and allowed roles (?workState=... filters the work-item list) |
| GET | /readyz |
public | Database and per-repository instance readiness summary |
| GET | /api/read/metrics |
approved | Read-only metrics: a super admin gets the global window, users get their own personal window (?window=7 or 30) |
| POST | /repos/:id/run |
owner + CSRF | Enqueue a manual iterate job; plan-first repositories enqueue a plan |
| POST | /repos/:id/work |
owner + CSRF | Create a work item |
| POST | /repos/:id/work/:workItemId/state |
owner + CSRF | Move a work item through the triage/assignment/review state machine |
| POST | /repos/:id/work/:workItemId/run |
owner + CSRF | Start a plan or iterate job for a work item |
| POST | /repos/:id/work/:workItemId/scope |
owner + CSRF | Queue a Product scope job for a work item |
| POST | /repos/:id/work/:workItemId/verify |
owner + CSRF | Queue a Test verify job for a work item with a PR |
| POST | /repos/:id/role |
owner + CSRF | Select maintainer or developer for this user-repository connection |
| POST | /repos/:id/plan |
owner + CSRF | Enqueue a plan-only job (no code, branch or PR) |
| POST | /repos/:id/instance |
owner + CSRF | Start the per-repository FlyBot instance |
| POST | /repos/:id/instance/stop |
owner + CSRF | Stop the per-repository FlyBot instance |
| POST | /repos/:id/refresh |
owner + CSRF | Re-check the upstream, fork and permissions |
| POST | /repos/:id/enable |
owner + CSRF | Enable the repository connection |
| POST | /repos/:id/disable |
owner + CSRF | Disable scheduling and cancel active jobs |
| POST | /repos/:id/delete |
owner + CSRF | Delete the Fledge connection after typing the repository name |
| GET | /api/inbox/events |
approved | Server-Sent Events stream of the user's inbox |
| POST | /repos/:id/review |
owner + CSRF | Enqueue a manual review job |
| GET | /repos/:id/jobs/:jobId |
owner | Job detail: evidence, cost, attribution, retry |
| POST | /repos/:id/jobs/:jobId/retry |
owner + CSRF | Retry a failed job, including its checkpoint |
| POST | /repos/:id/jobs/:jobId/approve-plan |
maintainer + CSRF | Approve a completed plan with allowed/forbidden paths |
| POST | /repos/:id/jobs/:jobId/reject-plan |
maintainer + CSRF | Reject a completed plan |
| POST | /repos/:id/jobs/:jobId/execute |
maintainer + CSRF | Execute an approved plan as an iterate job |
| POST | /repos/:id/jobs/:jobId/merge |
maintainer + CSRF | Re-check and squash-merge a Fledge PR |
| POST | /repos/:id/delivery/merge-clean |
maintainer + CSRF | Re-check and merge all clean Fledge PRs, skipping blocked ones |
| POST | /repos/:id/jobs/:jobId/cancel |
owner + CSRF | Cancel a queued or running job |
| POST | /repos/:id/jobs/:jobId/pause |
owner + CSRF | Pause a queued or running job |
| POST | /repos/:id/jobs/:jobId/resume |
owner + CSRF | Resume a paused job from its checkpoint |
| GET | /repos/:id/workspace |
owner | Fledge-branded agent workspace shell |
* |
/repos/:id/workspace/app/* |
owner | Authenticated reverse proxy to the per-repo DSH UI |
| GET | /repos/:id/team |
superadmin | Team console |
| GET | /api/repos/:id/team |
superadmin | Team state JSON (polling fallback) |
| GET | /api/repos/:id/team/events |
superadmin | Server-Sent Events snapshot stream |
| POST | /repos/:id/team/guidance |
superadmin + CSRF | Send guidance to a role |
| POST | /repos/:id/chief/message |
owner + CSRF | Send guidance to the Chief from the simplified UI |
| GET | /api/repos/:id/chief/messages |
owner | Chief conversation snapshot (filtered/redacted) |
| GET | /api/repos/:id/chief/events |
owner | Server-Sent Events for new Chief messages |
| POST | /api/repos/:id/team/answer |
superadmin + CSRF | Answer a team question |
| POST | /api/repos/:id/team/stop |
superadmin + CSRF | Stop the active roles (hard when possible, otherwise a stop request) |
| POST | /repos/:id/settings |
owner + CSRF | Goal, target branch, role, plan-first, path constraints, merge method/protection, stage mode, budgets, model selection, bot models, cadence, enabled, reviewer interval |
| POST | /repos/:id/delete |
owner + CSRF | Delete the Fledge connection after typing the repository name; GitHub is untouched |
| GET | /settings |
approved | Account, model providers and models, API tokens |
| GET | /admin/metrics |
superadmin | Product funnel, delivery efficiency, daily trend, failure breakdown, cost breakdown, actionable alerts, team participation, attribution and stage metrics (?window=7 or 30) |
| POST | /settings/model |
approved + CSRF | Save/clear own model |
| POST | /settings/notifications |
approved + CSRF | Notification email, job/question mail, daily digest, test mail |
| POST | /settings/tokens |
approved + CSRF | Create a flg_ token |
| POST | /settings/tokens/:id/revoke |
owner + CSRF | Revoke a token |
| POST | /notifications/read |
approved + CSRF | Mark notifications read |
| GET | /admin |
admin / super admin | Scoped pending users, quotas, jobs and audit (admins see themselves and normal users only) |
| GET | /admin/metrics |
owner | Product funnel, success rate, job cost, team participation, events |
| POST | /admin/users/:id/approve |
admin + CSRF | Approve |
| POST | /admin/users/:id/reject |
admin + CSRF | Reject |
| POST | /admin/users/:id/quota |
admin / super admin + CSRF | Set quota in CNY; unlimited is super-admin-only |
| POST | /admin/users/:id/role |
owner + CSRF | Promote a normal user to admin or demote an admin |
| POST | /admin/simulation |
owner + CSRF | Toggle the normal-user UI preview |
| GET | /approve/:token |
token | Confirmation page |
| POST | /approve/:token |
token | Apply approve/reject |
A session-authenticated, read-only dashboard contract for an external control
room. window=7 (default) or window=30 selects the time window. A normal user
receives only personal metrics for their own account. A super admin
receives the global product, delivery, daily, team, repoCosts, modelCosts
and alerts sections. The route never mutates state.
Job lifecycle mail is sent from MAIL_FROM (production:
fledge@hugoxk.online) when a job finishes, fails, or a team question is
waiting. The user can set a notification email (blank uses the GitHub email), disable job
mail, disable the daily digest, or send a test mail in Settings → Email
notifications. Approval and quota mail are not affected. A question is mailed
once per sessionId + questionId; the preference is stored on the user.
POST /api/inbound/email accepts a JSON message from a mail worker:
{ "from": "...", "to": "...", "subject": "...", "text": "..." }. It requires
X-Fledge-Email-Secret to match INBOUND_EMAIL_SECRET, extracts the
+token from the recipient, checks the sender against the user's notification
email, and sends the cleaned text to the Lead as guidance. Tokens expire after
7 days; a reply to the daily digest is the only supported input.
GET /repos/:id/workspace renders the Fledge shell and embeds
/repos/:id/workspace/app/. The app path is an authenticated same-origin
reverse proxy to the per-repository DSH instance: Fledge verifies the session and
repository ownership, fetches the DSH cookie server-side, strips upstream
Set-Cookie/CSP/frame headers, rewrites the HTML title/base and injects the
Fledge brand, and proxies WebSocket upgrades. The raw DSH token is never sent to
the browser.
GET /api/repos/:id/team/events is an admin-only SSE stream. It emits a
snapshot event when roles, questions, jobs or quota change, and a heartbeat
comment otherwise. The snapshot includes bots (with tool, step, since,
lastActivityAt), questions (with id, sessionId, question, detail,
options, multiSelect), timeline (active/ended role activity), jobs
(summary, status, issue/PR and attribution) and quota. Clients should fall back to the
5-second JSON poll if the stream drops.
POST /api/repos/:id/team/answer takes JSON:
{ "sessionId": "session-…", "questionId": "q1", "selected": ["Fix the bug"], "custom": "" }The Fledge inbox uses the equivalent form endpoint POST /repos/:id/team/answer
(owner + CSRF) with sessionId, questionId, selected, custom and a safe
returnTo path; it redirects back with a localized notice or error.
POST /repos/:id/team/stop is the admin-only form counterpart for the workspace shell: it
takes target (empty for every working role) and returnTo, applies the same
stop logic as the JSON API, and redirects with an honest hard-stop/request note.
POST /api/repos/:id/team/stop takes { "target": "lead" } or an empty target
to stop every role that is currently thinking/working. The response distinguishes
stopped (hard cancel) from requested (stop message delivered; it takes effect
at the next safe point). Both endpoints require the x-csrf-token header.
A verified check_run/check_suite failure or a pull_request_review with
changes_requested can enqueue a follow-up job when the PR URL matches an
existing Fledge job for a repository with the same installation. The follow-up
reuses the original branch and PR URL, skips a second PR/issue, and is deduped by
repo + PR + head SHA + reason and by X-GitHub-Delivery. A repo with an active
job skips the follow-up; arbitrary PRs with no Fledge job are ignored.
These are called by the FlyBot bridge/agent, not by a browser.
Headers: Authorization: Bearer <callbackSecret>
{
"token": "github_pat_…",
"owner": "octo",
"name": "demo",
"defaultBranch": "main",
"upstream": { "owner": "octo", "name": "demo", "defaultBranch": "main", "htmlUrl": "https://github.com/octo/demo" },
"fork": { "owner": "alice", "name": "demo", "defaultBranch": "main", "htmlUrl": "https://github.com/alice/demo" },
"isFork": true,
"permission": "write",
"repoRole": "maintainer",
"autoMerge": true,
"canReview": true,
"canCreateIssue": true
}owner/name is always the upstream. When the token belongs to the upstream
owner, fork equals upstream and isFork is false. Otherwise the agent must
push to fork and open the PR against upstream. repoRole is the role the
user selected for this repository; autoMerge is true only for an iterate job
when that role is maintainer and the repository auto-merge switch is on. Only
while the job is queued or running.
Headers: Authorization: Bearer <callbackSecret>, Content-Type: application/json
{
"status": "succeeded",
"branch": "fledge/fix-123",
"prUrl": "https://github.com/octo/demo/pull/42",
"issueUrl": "https://github.com/octo/demo/issues/41",
"summary": "Fixed the off-by-one in the CSV splitter; added a regression test.",
"error": "",
"attribution": {
"writtenBy": "Dev-1",
"claimedBy": "Lead",
"implementedBy": "Dev-1",
"testedBy": "Test",
"reviewedBy": "Reviewer"
},
"evidence": {
"scope": "Fix the CSV splitter; do not change the public API",
"acceptance": "A quoted comma stays one field",
"testPlan": "Add a failing parser test, then a passing one",
"testRed": "node --test tests/unit/csv.test.mjs — 1 fail",
"testGreen": "node --test tests/unit/csv.test.mjs — 1 pass",
"tests": "node --test tests/unit/foo.test.mjs — 12 pass",
"checks": "CI green",
"files": 3,
"risk": "low",
"rollback": "revert the commit"
},
"checkpoint": "implemented the parser; next: add the rejection test"
}Review jobs use kind=review and return reviewScore (0–100) instead of a
branch/PR:
{ "status": "succeeded", "summary": "Reviewed 6 PRs; average 78.", "reviewScore": 78 }status may be running, succeeded or failed. A running callback is a
progress heartbeat: it updates summary, checkpoint and optionally branch,
attribution or evidence without finishing the job or extending
JOB_TIMEOUT_MINUTES. checkpoint is shown on the job page and is injected
into the goal when a failed job is retried. A plan job writes the plan to
summary and must not create a branch, issue or PR; the super admin can execute it
later as an iterate job. evidence is stored structurally and shown on the job
detail page; the Fledge automation comment stays compact. With
repos.stage_mode = 'enforced', an iterate callback must also include scope,
acceptance, testRed, testGreen and Dev/Test attribution, and a review
callback must include a Reviewer and reviewScore; otherwise the job fails with
STAGE_EVIDENCE_MISSING and does not auto-merge. shadow records the same check
as an event without blocking. On
success, Fledge adds a collapsible automation block to the PR with the job,
team and the attribution steps that actually happened, so humans can see which
role claimed, implemented, tested and reviewed the change without a fabricated
"pending" row. A finished job revokes its job-scoped model token, and later
callbacks or credential reads return HTTP 409.
OpenAI-compatible; base path /v1.
curl -H "Authorization: Bearer flg_…" http://localhost:8080/v1/modelscurl http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer flg_…" \
-H "Content-Type: application/json" \
-d '{"model":"your-model","messages":[{"role":"user","content":"hi"}],"max_tokens":64}'Response headers include:
x-fledge-quota-remaining-cnyx-fledge-top-up-url
When the platform quota is exhausted:
{
"error": {
"type": "quota_exhausted",
"code": "FLEDGE_QUOTA_EXHAUSTED",
"message": "平台额度已用完,请到 Settings → Model 配置你自己的模型 API 后继续。",
"quota": { "initialCny": 1, "usedCny": 1.0002, "remainingCny": 0 },
"settingsUrl": "https://fledge.example/settings"
}
}Status code: 402.
GET /healthz → { "ok": true, "service": "fledge", "version": "0.2.4" }.
- JSON errors always have
error.typeanderror.code. - Browser form errors redirect back with
?error=; API errors use HTTP status. - All timestamps are ISO-8601 UTC.
- Money in the API is CNY unless the field says
usd.
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /settings/providers |
approved + CSRF | Add a provider; HTTP/private URLs need the per-user permission or the global flag |
| POST | /settings/providers/:id/update |
approved + CSRF | Update a provider; existing models are re-tested before saving |
| POST | /settings/providers/:id/delete |
approved + CSRF | Delete a provider and its models |
| POST | /settings/providers/:id/discover |
approved + CSRF | Read the provider's /v1/models list from Fledge |
| POST | /settings/providers/:id/models/bulk |
approved + CSRF | Add selected discovered models, testing each before saving |
| POST | /settings/providers/:id/models |
approved + CSRF | Run a 1-token test from Fledge and save the model only on success |
| POST | /settings/providers/:id/models/:modelId/delete |
approved + CSRF | Delete a provider model |
| POST | /admin/users/:id/private-models |
superadmin + CSRF | Grant or revoke the private/HTTP model permission for a user |
Issue comments from OWNER, MEMBER or COLLABORATOR accounts can run
/fledge status, /fledge plan, /fledge approve or /fledge fix. Commands are
deduped by comment id and reply on the issue. /fledge approve is maintainer-only.