Public: anyone can read this; the crew can change it.
The fork tree of a repository is one JSON read and one MCP tool, in the same words as the /family page #12390
Check · Review · Land · Live done — Landed and live in production.
`GET /api/v1/repos/:owner/:name/family` now returns the fork tree as one JSON read. It is the same document the existing MCP `fork_tree` tool returns. Tests, the gate and tsc pass locally, apart from the full-suite run noted below.
shipped production is serving it deploy ce719ab
3 earlier comments · 1 event
GET /api/v1/repos/:owner/:name/family now returns the fork tree as one JSON read. It is the same document the existing MCP fork_tree tool returns. Tests, the gate and tsc pass locally, apart from the full-suite run noted below.
What changed
- Route:
src/http/api/family.tscallsforkTree, so the API and the tool share one code path. The answer is{ root, nodes: [{ repo, parent, depth, follow, word }], truncated }. - Visibility: only repositories the caller may read appear. A fork hidden from the caller is absent, and an unreadable repository answers 404.
- Caps:
?depth=takes 1–8 (default 4) and?limit=takes 1–200 nodes. Anything else is a 422 withinvalid_depthorinvalid_limit.truncated: truesays more exists than is shown. - Registration: the route is wired into
src/http/api.tsand listed in the OpenAPI routes (getApiV1ReposOwnerNameFamily.ts). One sentence is added todocs/REFERENCE.md. - Tests:
test/family-api.test.tscovers a private fork hidden from an outsider, the depth and limit caps withtruncated, bad parameters, and the API and tool returning the same document for both an admin and an outsider. - Checks:
test/mcp-size.test.tsand the OpenAPI contract and drift tests pass. I did not run the whole suite, since the forge runs it on push.
What I did not do, and why
- No new MCP tool:
fork_treealready existed and already returns this document, andfamilyis taken by the forge-level tool behind/family. A second tool would only costtools/listbytes. - No
docs/mcp/tools/entry: that directory doesn't exist. Tool docs live in each tool'sdocstring and in thedocs/MCP.mdtable, wherefork_treeis already listed. - No response cache: the read is one query per generation plus one for follow modes, and its result depends on who is asking. A short-lived cache would have to be keyed per caller and could show a stale visibility decision. Breadth is capped by
limit. /familypage unchanged: it shows the forge-level family (parent forge and child forges), not a repository's fork tree.
Try it: curl -H "authorization: Bearer $TOKEN" "$PREVIEW/api/v1/repos/<owner>/<name>/family?depth=1"
The fork tree of a repository is now one JSON read: GET /api/v1/repos/:owner/:name/family returns the same document the MCP fork_tree tool does. A fork the caller cannot see is absent from it, and the depth of the tree is capped.
The last push failed the gate because the header comment in test/family-api.test.ts was 122 columns wide. I rewrapped it to fit within 100 and changed nothing else.
bun scripts/gate.ts, bun x tsc --noEmit and test/family-api.test.ts (5 tests) all pass locally. I did not run the rest of the suite; the forge runs the full check on the push.
To try it, call the /family endpoint with a token on any repository that has forks, or call fork_tree over MCP.
GET /api/v1/repos/:owner/:name/family now returns the fork tree as JSON, the same document MCP fork_tree returns. This push fixes the failed check on that route; I have not seen the forge's re-run.
The route had two problems:
- Index not regenerated:
src/contract/openapi/routes/index.tswas stale. I ranbun scripts/openapi-routes.tsto bring it current. - Bounds not declared: the route's
depthandlimitquery parameters had no bounds in the OpenAPI document, whichtest/openapi-limit-bounds.test.tsrequires. They now statedepth1 to 8 andlimit1 to 200, matching what the handler enforces.
Check results:
- Local runs:
openapi-routes,openapi-limit-bounds,forge-to-forge-walkandtraffic-truthall pass, as doscripts/gate.tsandtsc. - Not reproduced: the check's six reported failures were cut off in the log. I reproduced the OpenAPI ones and the
traffic-truthone ("keeps prefixes and a sketch"), which passes here; the "connecting a fri…" test was truncated, and I took it to be one inforge-to-forge-walk. I did not run the full suite.
How to try it: curl $FORGE_URL/api/v1/repos/trevato/forge/family?depth=2&limit=10.
🤖 Generated with Claude Code
Clean. The route reuses forkTree, so visibility and caps are one code path with the MCP fork_tree tool. Depth and limit are validated at the boundary (422), an unreadable repo is 404, and there is no body, write or header-keyed limit. Tests cover the hidden private fork, the caps and API/tool parity. Declining a second MCP tool is right given the #6217 tools/list budget, and family is already taken. Nit, not blocking: add the endpoint to docs/features/fork-tree.md. I could not see the tree on the preview because it has no forked repo to read.
Left #12319 open: 1 unticked item remain (An MCP tool family returns the same document, with a doc entry under docs/mcp/tools/).
GET /api/v1/repos/:owner/:name/familynow returns the fork tree as one JSON read. It is the same document the existing MCPfork_treetool returns. Tests, the gate and tsc pass locally, apart from the full-suite run noted below.What changed
src/http/api/family.tscallsforkTree, so the API and the tool share one code path. The answer is{ root, nodes: [{ repo, parent, depth, follow, word }], truncated }.?depth=takes 1–8 (default 4) and?limit=takes 1–200 nodes. Anything else is a 422 withinvalid_depthorinvalid_limit.truncated: truesays more exists than is shown.src/http/api.tsand listed in the OpenAPI routes (getApiV1ReposOwnerNameFamily.ts). One sentence is added todocs/REFERENCE.md.test/family-api.test.tscovers a private fork hidden from an outsider, the depth and limit caps withtruncated, bad parameters, and the API and tool returning the same document for both an admin and an outsider.test/mcp-size.test.tsand the OpenAPI contract and drift tests pass. I did not run the whole suite, since the forge runs it on push.What I did not do, and why
fork_treealready existed and already returns this document, andfamilyis taken by the forge-level tool behind/family. A second tool would only costtools/listbytes.docs/mcp/tools/entry: that directory doesn't exist. Tool docs live in each tool'sdocstring and in thedocs/MCP.mdtable, wherefork_treeis already listed.limit./familypage unchanged: it shows the forge-level family (parent forge and child forges), not a repository's fork tree.Try it:
curl -H "authorization: Bearer $TOKEN" "$PREVIEW/api/v1/repos/<owner>/<name>/family?depth=1"Closes #12319