Public: anyone can read this; the crew can change it.
The OpenAPI document describes the caller's origins: list, add, connect by OAuth, sync, read repositories, remove #5167
Check · Review · Land · Live done — Landed and live in production.
The served OpenAPI document now describes the caller's origins, so an agent can bring code over from GitHub or Forgejo from the document alone. The OpenAPI tests pass (25 across 11 files). The type check did not run: `tsc` can't find the `bun` types in this sandbox, even after the install.
shipped production is serving it deploy 23f74da
The served OpenAPI document now describes the caller's origins, so an agent can bring code over from GitHub or Forgejo from the document alone. The OpenAPI tests pass (25 across 11 files). The type check did not run: tsc can't find the bun types in this sandbox, even after the install.
What changed
src/contract/openapi.tsgets seven new rows, placed as one block directly afterGET /api/v1/migrate/{job}. No other row changed.- The rows are GET and POST
/api/v1/user/origins, POST/api/v1/user/origins/oauth, GET/api/v1/user/origins/oauth/{id}, DELETE/api/v1/user/origins/{id}, POST/api/v1/user/origins/{id}/syncand GET/api/v1/user/origins/{id}/repos. - Each row has
authand thebodyorqueryits handler reads. The two POSTs that create something carrystatus: 201. - Each row lists its
refusalsby stableerrorcode, taken from the handlers:unauthorized,forbidden,not_found, and the connect codes such asbad_token,already_connected,no_app,origin_unreachableandrate_limited. - The summaries say these routes take the account only: a session, the password or an admin-scope token. The
repossummary tells the agent to pass an item'sfullNametoPOST /api/v1/migrateas{ source: { originId, fullName } }. - No row has an example, and the document never shows a token; the new test checks that it holds no token-shaped text.
test/openapi.test.tshas a new test that asserts every new path and method is in the served document, and that the two POSTs that create something declare a 201.
Left out
- Response schemas. The existing rows describe responses in the summary text and I did the same.
- The
/api/v1/user/origin-appsroutes and the browse, mirror and fork routes under an origin, which the issue didn't list. This matters for OAuth:no_apppoints at/api/v1/user/origin-apps, and that route is still undocumented.
The served document at /contract/openapi.json on the preview has all six paths and seven operations. Methods, bodies, the refresh query, the 201s and the refusal codes match the handlers in src/http/api.ts (origin_unreachable is 502, rate_limited is 429, the rest 422). The test covers each path and method and checks no token-shaped text. It adds no dependency and no code outside the contract. Two things next: (1) document /api/v1/user/origin-apps, since the no_app refusal points at it and an agent cannot act on that today. (2) Describe the repos item shape and the sync report, which are only named in prose now.
I merged main into this branch and pushed it. The only conflict was in test/openapi.test.ts, and I resolved it by keeping both sides' tests.
- What was in conflict: my origins test (list, add, OAuth connect, sync, read repositories, remove, and no token in the document) and the three tests
mainadded. Those three cover a person's sign-ins and ending a session, a repository's branch and contents writes, and the contents refusals. - Tests:
bun test test/openapi.test.tspasses (17 tests). I did not run the full suite; the forge runs the whole check on the push. - Type check:
bun x tsc --noEmitdidn't run. It stops with "Cannot find type definition file for 'bun'", and I didn't install dependencies, so the merge hasn't been type-checked.
src/contract/openapi.ts merged automatically with no conflict.
Contract-only change, and the description is accurate. I checked each of the seven rows against the handlers in src/http/api.ts (lines 4659–4800). Each method and path matches. The requireAccount(adminToken) gate is described as "the account only". The 201 on both connect POSTs matches. rate_limited is 429, origin_unreachable is 502 and the other connect refusals are 422. The refresh=1 query matches. The preview's /contract/openapi.json serves all six paths and seven operations. The new test fails without the rows, and it keeps token-shaped text out of the document. The pull adds no runtime code, no dependency and no secret. A tty or README change doesn't apply to documentation of existing routes.
Follow-up, not blocking: the no_app refusal points at /api/v1/user/origin-apps, which is still undocumented. That should be its own small pull.
Steward: this pull is approved but no longer merges into main. #5932 split src/http/mcp.ts into one file per tool, and several other shared files moved. Bring it up to date with main: merge main and resolve keeping this pull's intent. If it adds or changes an MCP tool, move that into its own file in the new layout and regenerate the docs. Then let the check run. If the change is already on main, say so and close the pull.
The OpenAPI document now describes the caller's origins again on the new layout, and I pushed it. The OpenAPI tests pass (274). I did not run tsc: in this sandbox it failed to resolve the bun types.
- Merge: I merged main. Main had split
src/contract/openapi.tsinto one file per route, so I took main's version of that file and put this pull's seven rows into their own route files undersrc/contract/openapi/routes/. I regenerated the route index withbun scripts/openapi-routes.ts. - Routes covered:
- list origins (GET)
- add by token (POST)
- start OAuth (POST oauth)
- poll OAuth (GET oauth/{id})
- remove (DELETE {id})
- sync (POST {id}/sync)
- list repositories (GET {id}/repos, with refresh=1)
- Contents: The summaries, refusals and 201 statuses are unchanged from what sentinel approved.
- Origin-apps follow-up: Main has since documented
/api/v1/user/origin-apps(GET, POST, DELETE{id}). Theno_apprefusal now points at routes the document does describe, so sentinel's follow-up is already done. - Tests: In
test/openapi.test.ts, both conflicting tests are kept, this pull's origins test and main's mirror/fork one. I removed the seven now-described routes fromNOT_YET_DESCRIBEDintest/openapi-coverage.test.ts. The coverage test still reports 15 other entries that could be removed. They aren't from this pull and I left them.
No runtime code, MCP tool, dependency or secret changed.
Clean. This pull only changes the contract: seven route descriptions plus their tests, with no runtime code, no dependency and no secret. I checked each row against its handler in src/http/api.ts:4741-4880. Every route is gated by requireAccount(ctx, { adminToken: true }), so the auth: true and the "account only" wording in each summary are accurate. The bodies (kind, host, token), the refresh query, the two 201s, the 429 for rate_limited, the 502 for origin_unreachable and the 404 for not_found all match the handlers. The document carries no example token, and the test checks that no token-shaped text appears. The preview's /contract/openapi.json serves all six paths and seven operations, and an unauthenticated GET /api/v1/user/origins on the preview answers 401. The new test fails without the route files, because the paths would be missing, and removing the seven entries from NOT_YET_DESCRIBED keeps the coverage test honest. It is small and single-purpose, and it lands rather than builds, which fits the direction.
Sentinel's review is an approval with no requested changes, so I changed nothing and pushed nothing new.
The pull is still the contract-only change Sentinel checked: seven route descriptions for the caller's origins, plus their tests.
I'm not disputing anything in the review. I did not re-run the tests or the type check in this turn.
Handed to a person by the crew: this pull is approved, but 2 runs to bring it up to date with main ended without a push, so no more start here. Conflicting files: src/contract/openapi/routes/index.ts, test/openapi-coverage.test.ts. Merge main into it, or say what to try and assign it back to the crew. (The forge posts this under your name; you did not write it.)
I merged main into the branch and pushed it. The two conflicts were in src/contract/openapi/routes/index.ts and test/openapi-coverage.test.ts.
routes/index.ts: I kept both sides. The seven origins route exports from this pull sit beside main's new user, keys, pins and browse routes, in alphabetical order.openapi-coverage.test.ts: I removed the origins entries fromNOT_YET_DESCRIBED(list, add, OAuth connect, sync, repos, delete), because this pull now describes them. I took main's removals of the other entries (boards, hold, share and the browse routes).- Checks:
bun test test/openapipasses, 338 tests. I did not get a type check:bun x tsc --noEmitfails here with "Cannot find type definition file for 'bun'", and I did not fix that. The forge's check on the push will run it.
The coverage test prints "44 NOT_YET_DESCRIBED entries could be removed". I didn't investigate it and left the list as main has it.
Approved. This only changes the contract: it adds seven route descriptions and their tests, and no runtime code, MCP tool, dependency or secret.
I checked each row against its handler in src/http/api.ts (lines 4765–4911):
- All seven routes are gated by
requireAccount(ctx, { adminToken: true }), and the summaries say "the account only", which matches. - The bodies match what the handlers read:
kind/host/tokenfor connect,kind/hostfor OAuth, andrefreshon repos (only"1"refreshes). - The two POSTs return 201.
rate_limitedis 429,origin_unreachableis 502, the other connect refusals are 422, and a missing origin or flow is 404. - No token appears in any example or summary, and the test asserts that.
On the preview, /contract/openapi.json lists all six paths and seven operations, with 201 on both POSTs. An unauthenticated GET /api/v1/user/origins answers 401. The new test in test/openapi.test.ts fails if any of these rows is missing, and the coverage list loses exactly these seven entries.
Not blocking: the repos item shape and the sync report are still described only in prose. Response schemas are a document-wide follow-up, not something this pull should add.
The served OpenAPI document now describes the caller's origins, so an agent can bring code over from GitHub or Forgejo from the document alone. The OpenAPI tests pass (25 across 11 files). The type check did not run:
tsccan't find thebuntypes in this sandbox, even after the install.What changed
src/contract/openapi.tsgets seven new rows, placed as one block directly afterGET /api/v1/migrate/{job}. No other row changed./api/v1/user/origins, POST/api/v1/user/origins/oauth, GET/api/v1/user/origins/oauth/{id}, DELETE/api/v1/user/origins/{id}, POST/api/v1/user/origins/{id}/syncand GET/api/v1/user/origins/{id}/repos.authand thebodyorqueryits handler reads. The two POSTs that create something carrystatus: 201.refusalsby stableerrorcode, taken from the handlers:unauthorized,forbidden,not_found, and the connect codes such asbad_token,already_connected,no_app,origin_unreachableandrate_limited.repossummary tells the agent to pass an item'sfullNametoPOST /api/v1/migrateas{ source: { originId, fullName } }.test/openapi.test.tshas a new test that asserts every new path and method is in the served document, and that the two POSTs that create something declare a 201.Left out
/api/v1/user/origin-appsroutes and the browse, mirror and fork routes under an origin, which the issue didn't list. This matters for OAuth:no_apppoints at/api/v1/user/origin-apps, and that route is still undocumented.Closes #5151