# graftfork

> graftfork (Graft, at graftfork.com) keeps a changed copy of an open-source project (a fork, or a project with patched dependencies) on each upstream release. It moves the changes onto the release, runs the project's own tests in a sandbox, and keeps the moved branch only if every change lands and the tests pass. Otherwise the copy stays where it was and Graft says why. It also rebuilds a program blind from its duramen record (a written spec with examples and, often, an oracle): builders that never see the existing code write it in TypeScript, Python, Rust or Go, and Graft keeps a rebuild only when every case of the record passes.

Agents can also start at graftfork.ai, the agent front door: https://graftfork.ai/mcp is the same MCP server and https://graftfork.ai/api/v1 the same API, with the same tokens.

Without any token, an agent can try a public fork (see "Try without an account"). The MCP server and the HTTP API need a token, sent as `Authorization: Bearer <token>`. There are three ways to get one: a personal API token (graft_...) a person makes at https://graftfork.com/app#settings and gives to the agent; a token from OAuth, which a person allows on a consent page (see "Connecting with OAuth" below); a token an agent with a wallet buys for itself, with no person (see "Agent accounts" below).

Tokens have scopes: read: see your copies, syncs, reports, waiting conflicts and usage; sync: connect or disconnect a repository, start a sync, check, dependency upgrade or upstream build, connect, set or rebuild a spec or ask for a new spec report, start, edit, check, rebuild or discard a change order, revert a move, set a copy's desired state, add or remove a webhook, and track an upstream pull request or ask for Graft's reviewer (rebuilds and paid reports spend agent work); resolve: hand in a resolved file or answer a question (Graft still runs your tests before anything moves). Rate limit: 120 requests a minute per token, 30 of them changes.

Nothing an agent sends can move a copy. A resolution is stored, Graft syncs again with it, and the copy moves only if every change lands and the tests pass. By default Graft writes nothing to a repository: it keeps the moved branch, graft/<release>, for the owner to take.

## What costs money

- Free, with no account: trying a public fork (POST https://graftfork.com/api/try), reading this file, https://graftfork.com/pricing.json, the OpenAPI description and https://graftfork.com/api/status.
- Within the plan's monthly counts, at no extra cost: connecting copies, syncs, change checks, reading results and taking moves; a spec's free grade (GET /api/v1/regen/{id}/report) and its signed records.
- Agent work, which spends money: Graft's agent resolving a conflict, fixing a dependency upgrade that breaks the tests, a rebuild from a spec, a paid spec report and the hosted drafter. Premium includes $6 of it a month (up to $1.25 a sync, no overage); the free plan gets its first conflict resolved free once. Give each run a ceiling with max_usd: if it could cost more, the answer is price_quote and nothing is spent.
- A person's own Anthropic API key, if they save one, is billed by Anthropic, not graftfork.
- Agent accounts: 12 USD in USDC for 30 days of Premium, and top-ups at 10 USD (see "Agent accounts").

## Try without an account

- `POST https://graftfork.com/api/try` with `Content-Type: application/json` and `{"repo": "owner/name", "upstream": "owner/name (optional)", "base": "release tag (optional)"}`. No token. It runs one real sync of a public GitHub fork onto upstream's newest release in a short-lived sandbox: it never pushes and runs no agent.
- The 201 answer has `id`, `statusUrl` (also the Location header), `resultUrl` and `pollSeconds`. Poll `GET https://graftfork.com/api/try/{id}` until `status` is done, failed or error. `https://graftfork.com/t/{id}` is the result page to share.
- Limits: 10 tries a day per network address (people on one network share them), one running at a time, 10 minutes each. A result for the same fork, base and release is reused for 24 hours (`cached: true`). Results are kept for 30 days.

## MCP server

- Endpoint: https://graftfork.com/mcp (Streamable HTTP, stateless; protocol revisions 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26). Server name: graftfork.
- [Server Card](https://graftfork.com/mcp/server-card): how to connect, before connecting. Registry name: com.graftfork/graftfork.
- Add it to Claude Code: `claude mcp add --transport http graftfork https://graftfork.com/mcp` (Claude Code opens a browser for OAuth), or with a token: `claude mcp add --transport http graftfork https://graftfork.com/mcp --header "Authorization: Bearer <token>"`
- Every tool with its input schema: https://graftfork.com/llms-full.txt

Tools (a token sees the ones its scopes allow):

- `track_change` (sync): Register a GitHub repository whose changes to an open-source project Graft keeps on each upstream release.
- `list_copies` (read): Every copy, one line each, with its last sync and what waits.
- `status` (read): One copy, desired beside observed.
- `sync_now` (sync): Sync one copy onto its newest allowed release; it moves only if every change lands and the tests pass.
- `set_copy` (sync): Write a copy's desired state; only the fields you give change.
- `take_move` (read): A one-hour link to a moved branch (git bundle) and the commands that fetch it into the user's clone as graft/<release>.
- `revert_move` (sync): Undo the move a copy is on now, back to the release before it.
- `send_upstream` (read): One carried change and its reason, as pull request text.
- `build_upstream` (sync): Build graft/upstream/<change>: only this change on the copy's release, tested.
- `upstream_status` (read): One upstream build: status, test verdict, pull request text, one-hour bundle and patch links, and the tracked pull request's state.
- `track_upstream_pr` (sync): Record the pull request the user opened upstream for a built change.
- `explain_stop` (read): Why a copy's last sync didn't move it, and the next action: tools to resolve with, a question for the user, or something only the user can do.
- `list_pending_conflicts` (read): Conflicting files to resolve and questions only the user decides.
- `get_conflict` (read): One conflicting file: base, ours, theirs, and the change's recorded reason; or a question's options.
- `submit_resolution` (resolve): Hand in the WHOLE resolved file for one conflict, or delete: true.
- `answer_question` (resolve): Answer a sync's question with the option (1-based) the user picked; show them the question first.
- `check_change` (sync): Run the project's tests on a change and its base in Graft's sandbox: pass, fail (new failures by name) or could_not_run.
- `check_status` (read): One change check: outcome, why, new failures, the base's own failures, and test output tails.
- `upgrade_dependency` (sync): Upgrade one npm or Python dependency on graft/upgrade/<name>-<version>, delivered only if no test newly fails.
- `get_upgrade` (read): One dependency upgrade: status, version, tests before and after, the agent's fix, and where it went.
- `regen_connect` (sync): Connect a repository whose program is kept in a duramen record, so Graft can rebuild it blind (lang lists the languages open now).
- `regen_run` (sync): Rebuild a spec blind from its record, kept on graft/regen/<id> only if every case passes.
- `regen_set` (sync): Write a spec's desired state; only the fields you give change.
- `regen_disconnect` (sync): Disconnect a spec, as /app's Disconnect does: its queued rebuilds are cancelled and its kept rebuilds deleted; its rebuilds' signed records stay.
- `regen_status` (read): Specs and rebuilds.
- `regen_record` (read): A finished rebuild's signed record.
- `regen_rejudge` (sync): Judge a finished rebuild's stored builds again with today's runner, to confirm a verdict.
- `regen_report` (read): A spec's free grade (strong, usable or thin), its reasons, and what a blind rebuild can be judged on.
- `regen_report_refresh` (sync): Grade a spec's record again, no model.
- `regen_draft_check` (sync): For a record edited on a pushed branch of the user's repository.
- `regen_draft_rebuild` (sync): For a record edited on a pushed branch.
- `regen_draft_status` (read): Drafts from pushed branches.
- `regen_order_create` (sync): For an edit held in Graft (a change order).
- `regen_order_write` (sync): Replace change-order files, each a WHOLE new text (text null restores, delete true deletes).
- `regen_order_check` (sync): For an edit held in Graft (a change order).
- `regen_order_rebuild` (sync): For an edit held in Graft (a change order).
- `regen_order_status` (read): Change orders held in Graft.
- `regen_order_discard` (sync): End a change order the user doesn't want: its edits go, its history stays.
- `usage` (read): The plan, syncs and copies against limits, and agentWork: agent work left, spent, and the caps.
- `webhook_add` (sync): Register a public https URL Graft posts JSON to when work ends or needs someone, instead of polling.
- `webhook_list` (read): The user's webhooks with their last deliveries; with id, one webhook's last 50 (event, status, attempts, what the URL answered).
- `webhook_remove` (sync): Remove a webhook and its delivery log.
- `webhook_test` (sync): Post a signed ping now and say what the URL answered.
- `list_fork_alerts` (read): Team and Enterprise: what fork watch found new: advisory (a fix the fork lacks), behind (a new release), carry (changes that stopped carrying).
- `path_policy` (read): Paths a move you make may not change without a person, for a copy (id) or organization (org).
- `org_settings` (read): An organization's defaults for new copies and specs, its review checklist, its channels' quiet hours, and your own muted email events.
- `org_settings_set` (admin): Owners: set the organization's defaults, review checklist or quiet hours.
- `org_notify_set` (sync): The events you don't want by email from the organization's email channels (an empty list for all of them).
- `org_channels` (read): An organization's team channels: destination, events, team, on or off, and recent deliveries.
- `org_channel_add` (admin): Owners: a new team channel.
- `org_channel_set` (admin): Owners: change a channel's name, events, team (null for every team), recipients (email channels) or pause it.
- `org_channel_remove` (admin): Owners: remove a channel, its webhook and what waits to be sent to it.
- `org_channel_test` (admin): Owners: a test post (or one email to each recipient) now, whatever the channel's events and quiet hours.
- `org_audit_verify` (read): Sign and check the organization's audit log (signature, entry hashes, ledger copies): ok and any problems.
- `org_review_queue` (read): An organization's moves waiting for review, riskiest first, with what to read and skip.
- `buy_agent_work` (pay): Buy one top-up of Graft's agent work for this account, paid in USDC over x402 (version 2, scheme exact) from your own wallet: $10 adds $7, usable this month and next, on Premium.

## Claude connector directory

- graftfork is in Claude's connector directory: https://claude.ai/directory/graftfork. In Claude (web, desktop or mobile): Customize, Connectors, find graftfork, Connect, then allow it on graftfork's consent page. Act (sync) is off by default.

## Claude Code plugin

- `claude plugin marketplace add craigm26/graft-claude-code`, then `claude plugin install graftfork@graftfork` (in Claude Code: `/plugin marketplace add craigm26/graft-claude-code` and `/plugin install graftfork@graftfork`). Restart, run `/mcp`, choose `plugin:graftfork:graftfork` and sign in.
- Had the plugin under its old name, `graft` (1.5 or earlier)? Claude Code keeps the name the marketplace had when it was added, `graft-claude-code`, so `graftfork@graftfork` isn't found there: install `graftfork@graft-claude-code`, uninstall `graft@graft-claude-code`, and sign in again from `/mcp`. The old entry stays in the marketplace at 1.5.0, so it keeps loading until you switch.
- Beyond `claude mcp add`, it adds a skill that writes the reason for each change to a dependency, fork or vendored package into the commit in the form Graft reads, and three commands: `/graftfork:graft-status`, `/graftfork:graft-take` and `/graftfork:graft-upstream`.

## Connecting with OAuth

An MCP client that supports the MCP authorization spec connects without a pasted token: a 401 from https://graftfork.com/mcp names the Protected Resource Metadata (https://graftfork.com/.well-known/oauth-protected-resource), which names the authorization server (https://graftfork.com/.well-known/oauth-authorization-server). Register at https://graftfork.com/oauth/register (public clients only: no secret; redirect URIs are https or http on localhost, 127.0.0.1 or [::1]), then use the authorization code with PKCE (S256 only). The person signs in, allows the client, and sets its limits on the consent page. Access tokens last an hour; the refresh token is swapped for a new one on each use, and one used twice revokes the grant. A token is bound to https://graftfork.com/mcp, https://graftfork.com/api/v1, or both (the resource parameter, RFC 8707). Revoke at https://graftfork.com/oauth/revoke, or the person does it in /app Settings.

## HTTP API

- [OpenAPI 3.1 description](https://graftfork.com/api/v1/openapi.json): the same work as the MCP tools, at https://graftfork.com/api/v1, and Try at https://graftfork.com/api/try
- [API catalog](https://graftfork.com/.well-known/api-catalog) (RFC 9727) and the index at https://graftfork.com/api/v1
- [API docs](https://graftfork.com/docs/api)

## Command line

- `npm install -g graftfork` (Node 22.18 or newer) installs the command `graft`, a thin client for the HTTP API. It reads the token from GRAFT_TOKEN. From version 0.4.2 it is also installed as `graftfork` and reads GRAFTFORK_TOKEN too. Copies: `graft copies`, `graft sync`, `graft why`, `graft pull`. Rebuilds from a duramen record: `graft regen connect`, `graft regen report`, `graft regen run`, `graft regen status`. `graft verify-record <file or link>` checks a signed record with no token. Change orders, drafts, revert and desired state: `graft regen order`, `graft regen draft`, `graft revert`, `graft set`. Webhooks and re-judging are in /app, the API and the MCP server, not the command line.
- With npx, name the package: `npx graftfork verify-record <file>`. The npm package `graft` and the PyPI package `graft` belong to other people; don't run them for graftfork.

## End-to-end flows

1. Try a fork, no account: POST https://graftfork.com/api/try {"repo": "owner/name"}, poll statusUrl, read result.status (moved, stayed or current) and the result page.
2. Keep a fork current (token with read and sync): `track_change` or POST /api/v1/copies {"repo": "owner/name"} connects the copy (Graft's GitHub app must be on the repository; over the API you can give a git address instead); `sync_now` or POST /api/v1/copies/{id}/sync starts a sync; watch it with `status` or GET /api/v1/runs/{id}; if it stayed, `explain_stop` or GET /api/v1/copies/{id}/explain says why and what to do.
3. Resolve what stopped a sync (token with resolve): `list_pending_conflicts` or GET /api/v1/conflicts, `get_conflict`, then `submit_resolution` (a resolved file) or `answer_question` (a choice). Graft syncs again and the tests decide.
4. Take the move: `take_move` or GET /api/v1/copies/{id}/take gives a one-hour link and the commands that fetch graft/<release> into a clone; `graft pull` does it for you. A GitHub pull request is an opt-in per copy.
5. Rebuild from a spec: `regen_connect` or POST /api/v1/regen, read the free grade with `regen_report` or GET /api/v1/regen/{id}/report, rebuild with `regen_run` or POST /api/v1/regen/{id}/run (spends agent work; max_usd caps it), poll `regen_status` or GET /api/v1/regen/runs/{id}, then fetch the signed record (`regen_record` or GET /api/v1/regen/runs/{id}/record) and check it with `npx graftfork verify-record`.
6. Hear when runs end instead of polling: `webhook_add` or POST https://graftfork.com/api/v1/webhooks.
7. No person at all: make an agent account with POST https://graftfork.com/api/v1/agents (x402, below), then flows 2 to 6 with its token.

## Plans and prices

- [Machine-readable plans and prices](https://graftfork.com/pricing.json)
- Free: $0. 10 syncs a month, 5 copies, 20 change checks a month, the first conflict resolved free once (up to $1.25 of agent work, while Graft's agents are on and this month's trial budget lasts). Sign up at https://graftfork.com/#invite.
- Premium: $12 a month. 40 syncs a month, 50 change checks a month and $6 of Graft's agent work included, up to $1.25 of it a sync; no overage. Top-up: $10 adds $7.
- Team: $15 per fork a month, 1 to 20 forks, $6 of agent work per fork (up to $1.25 a sync; until the first invoice is paid, $6 for the whole organization), first 30 days free. Started by email.
- Enterprise: by contract. Graft's reviewer on every carry is $990 per fork per release.

## Agent accounts

An agent with a wallet can make its own Graft account, with no person, inbox or card. It pays 12 USD in USDC for 30 days of Premium and gets the account and a token (read, sync, resolve, pay) in the same answer.

1. `POST https://graftfork.com/api/v1/agents` with `{"name": "...", "contact": "optional email of a responsible person"}`. Graft answers 402 with x402 (version 2) payment requirements in the body and in the PAYMENT-REQUIRED header: scheme exact, network eip155:8453, asset 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, amount 12000000.
2. Sign an EIP-3009 transferWithAuthorization for exactly that and send the same request again with the base64 PaymentPayload in the PAYMENT-SIGNATURE header. Graft settles it through an x402 facilitator.
3. The 201 answer has the account, the token (shown once) and when the paid time ends. Use the token with the MCP server or the HTTP API.
4. Renew with `POST https://graftfork.com/api/v1/agents/renew` and the token, the same way. Past the paid time the account falls back to Free.
5. Buy more agent work with `POST https://graftfork.com/api/v1/topups` (or the MCP tool `buy_agent_work`), the same way: 10 USD in USDC (amount 10000000) adds 7 USD, usable this month and next. The same payment sent again returns the same credit. A person's token can do this too if they gave it the pay scope.

The token works for 90 days; each renewal or top-up paid with it moves that out to 90 days again. Its monthly cap is the account's agent work for the month. Set a lower ceiling per run with max_usd on sync_now, upgrade_dependency and regen_run, and register a webhook (webhook_add, or POST https://graftfork.com/api/v1/webhooks) to hear when runs end instead of polling.

The account works only through the API and the MCP server: no web sign-in, no email. Questions about a payment go by email to support@graftfork.com. Details: https://graftfork.com/docs/agents#accounts

## Forms an agent can post

Each takes `application/x-www-form-urlencoded` or a JSON object (`application/json`) and answers a JSON caller in JSON. Any other body type is a 415 that names the fields.

- `POST https://graftfork.com/api/waitlist`: sign up for a free account; graftfork emails the address a sign-in link (the account is a person's: it signs in from that inbox). Fields: email (required); optional: project, notes, t (the signed start token from GET /api/waitlist/start; without it a sign-up is looked at by a person first).
- `POST https://graftfork.com/api/report`: ask for the free fork report: Graft carries the fork onto upstream's newest release, builds and tests it, and a person emails the result, usually within a few business days. Fields: email, fork and upstream (all required; fork and upstream as GitHub URLs or owner/name); optional: target, notes. A person replies by email.
- `POST https://graftfork.com/api/feedback`: feedback on a carry or on graftfork. Fields: message or rating (1 to 5), at least one; optional: email, carry.

## Docs

- [Agents and Claude Code](https://graftfork.com/docs/agents)
- [Getting started](https://graftfork.com/docs)
- [How it works](https://graftfork.com/how-it-works)
- [Rebuilds from a spec](https://graftfork.com/regen): a program rebuilt blind from its duramen record, kept only when every case passes; [a real change, replayed](https://graftfork.com/regen/replay); [the guide](https://graftfork.com/docs/regen)
- [Security](https://graftfork.com/security)
- [Signed run records: the public keys](https://graftfork.com/.well-known/graft-record-key)
- [Status](https://graftfork.com/api/status) (JSON)

## Support

Email support@graftfork.com. Support is by email only.

## MCP tools, in full

Each tool as tools/list describes it to a token with every scope. Call them at https://graftfork.com/mcp.

### track_change

Track a repository with Graft. Scope: sync.

Register a GitHub repository whose changes to an open-source project Graft keeps on each upstream release. Needs Graft's GitHub app. With only repo, Graft detects the rest. Next: status.

```json
{"type":"object","properties":{"repo":{"type":"string","description":"owner/name"},"branch":{"type":"string","description":"Leave out for the default; with it, give upstream and base"},"upstream":{"type":"string","description":"owner/name on GitHub, or an https git URL"},"base":{"type":"string","description":"The release tag your branch sits on"},"tags":{"type":"string","description":"Release tags, as a git glob such as v*"},"follow":{"type":"string","enum":["all","minor","major"],"description":"Default all"},"pre_releases":{"type":"boolean","description":"With repo only: follow pre-releases too"},"backend":{"type":"string","enum":["managed-agents","delegated","none","anthropic-byok"],"description":"Who resolves conflicts (default: Graft's agent on Premium, you on Free)"}},"required":["repo"],"additionalProperties":false}
```

### list_copies

List tracked copies. Scope: read. Read-only.

Every copy, one line each, with its last sync and what waits. For one copy in full use status; for a spec use regen_status.

```json
{"type":"object","properties":{},"additionalProperties":false}
```

### status

Copy status. Scope: read. Read-only.

One copy, desired beside observed. For all copies use list_copies; for a spec use regen_status. Without id, every copy in short.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From list_copies; leave out for all"}},"additionalProperties":false}
```

### sync_now

Sync now. Scope: sync.

Sync one copy onto its newest allowed release; it moves only if every change lands and the tests pass. One sync, plus agent work on a conflict up to max_usd (over it: price_quote). needs_force: ask the user. Next: status.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From list_copies"},"force":{"type":"boolean","description":"After needs_force; ask the user first"},"max_usd":{"type":"number","minimum":0,"description":"Dollars"}},"required":["id"],"additionalProperties":false}
```

### set_copy

Set a copy's desired state. Scope: sync.

Write a copy's desired state; only the fields you give change. Free; queues nothing. Answers desired beside observed, as status does.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From list_copies"},"follow":{"type":"string","enum":["all","minor","major"]},"pre_releases":{"type":"boolean"},"schedule":{"type":"string","enum":["release","weekly","manual"]},"paused":{"type":"boolean"},"delivery":{"type":"string","enum":["graft","github"]},"max_usd":{"type":["number","null"],"minimum":0,"maximum":1000,"description":"Dollars a sync; null: the per-sync cap"}},"required":["id"],"additionalProperties":false}
```

### take_move

Take a delivered move. Scope: read. Read-only.

A one-hour link to a moved branch (git bundle) and the commands that fetch it into the user's clone as graft/<release>. Run them in that clone.

```json
{"type":"object","properties":{"id":{"type":"string","description":"A copy's id (its current move) or a run's id"}},"required":["id"],"additionalProperties":false}
```

### revert_move

Revert a move. Scope: sync. Destructive.

Undo the move a copy is on now, back to the release before it. Ask the user first. It is a move with review. If the user took the move, they revert their branch themselves. Next: status.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The run's id, from status"},"note":{"type":"string","description":"Why, for the reviewers and the record"}},"required":["id"],"additionalProperties":false}
```

### send_upstream

Send a change upstream. Scope: read. Read-only.

One carried change and its reason, as pull request text. The user opens the pull request from their own account. Next: build_upstream.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From list_copies"},"change":{"type":"string","description":"Its subject, part of it, or its number"}},"required":["id","change"]}
```

### build_upstream

Build a change for upstream. Scope: sync.

Build graft/upstream/<change>: only this change on the copy's release, tested. Never pushed. Next: upstream_status, then track_upstream_pr.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From list_copies"},"change":{"type":"string","description":"Its subject, part of it, or its number"}},"required":["id","change"],"additionalProperties":false}
```

### upstream_status

An upstream build. Scope: read. Read-only.

One upstream build: status, test verdict, pull request text, one-hour bundle and patch links, and the tracked pull request's state.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The build's id, from build_upstream"}},"required":["id"],"additionalProperties":false}
```

### track_upstream_pr

Track an upstream pull request. Scope: sync.

Record the pull request the user opened upstream for a built change. Graft checks it daily; once merged, the change counts as upstreamed.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The build's id, from build_upstream"},"url":{"type":"string","description":"https://github.com/<owner>/<name>/pull/<n>"}},"required":["id","url"],"additionalProperties":false}
```

### explain_stop

Why a sync stayed. Scope: read. Read-only.

Why a copy's last sync didn't move it, and the next action: tools to resolve with, a question for the user, or something only the user can do.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From list_copies"}},"required":["id"],"additionalProperties":false}
```

### list_pending_conflicts

List waiting conflicts. Scope: read. Read-only.

Conflicting files to resolve and questions only the user decides. Leave an item whose claim is set until claim.until. Next: get_conflict.

```json
{"type":"object","properties":{},"additionalProperties":false}
```

### get_conflict

Get a conflict. Scope: read. Read-only.

One conflicting file: base, ours, theirs, and the change's recorded reason; or a question's options. Next: submit_resolution.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From list_pending_conflicts"}},"required":["id"],"additionalProperties":false}
```

### submit_resolution

Submit a resolved file. Scope: resolve.

Hand in the WHOLE resolved file for one conflict, or delete: true. Once every file is in, Graft syncs again and moves the copy only if the tests pass.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The conflict's id"},"content":{"type":"string","description":"The whole file"},"delete":{"type":"boolean","description":"The file should not exist"}},"required":["id"],"additionalProperties":false}
```

### answer_question

Answer a question. Scope: resolve.

Answer a sync's question with the option (1-based) the user picked; show them the question first. Graft syncs again, checked by the tests.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The question's id"},"option":{"type":"integer","minimum":1,"description":"The option the user picked, 1-based"}},"required":["id","option"],"additionalProperties":false}
```

### check_change

Check a change. Scope: sync.

Run the project's tests on a change and its base in Graft's sandbox: pass, fail (new failures by name) or could_not_run. One of the month's change checks; nothing pushed. Next: check_status.

```json
{"type":"object","properties":{"repo":{"type":"string","description":"owner/name, Graft's app installed"},"clone_url":{"type":"string","description":"Or an https git address"},"token":{"type":"string","description":"With clone_url: a read token"},"username":{"type":"string","description":"Default git"},"base":{"type":"string","description":"Compared with (default with pr: its base)"},"head":{"type":"string","description":"The change (default with pr: its head)"},"pr":{"type":"integer","minimum":1,"description":"A pull request's number on GitHub"}},"additionalProperties":false}
```

### check_status

A change check's result. Scope: read. Read-only.

One change check: outcome, why, new failures, the base's own failures, and test output tails. Without id, recent checks.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From check_change; leave out for recent ones"}},"additionalProperties":false}
```

### upgrade_dependency

Upgrade a dependency. Scope: sync.

Upgrade one npm or Python dependency on graft/upgrade/<name>-<version>, delivered only if no test newly fails. One sync; a fix by Graft's agent spends up to max_usd. With a token limited to some copies, give copy_id. Next: get_upgrade.

```json
{"type":"object","properties":{"copy_id":{"type":"string","description":"From list_copies, or give repo"},"repo":{"type":"string","description":"The copy's repository, owner/name"},"branch":{"type":"string","description":"With repo, if connected more than once"},"clone_url":{"type":"string","description":"Or the copy's https clone address"},"dependency":{"type":"string","description":"The package's npm or PyPI name"},"version":{"type":"string","description":"Leave out for the newest"},"max_usd":{"type":"number","minimum":0,"description":"Dollars for a fix"}},"required":["dependency"],"additionalProperties":false}
```

### get_upgrade

An upgrade's result. Scope: read. Read-only.

One dependency upgrade: status, version, tests before and after, the agent's fix, and where it went. Without id, every upgrade. Next: take_move with its run id.

```json
{"type":"object","properties":{"id":{"type":"string","description":"From upgrade_dependency; leave out for all"},"before":{"type":"string","description":"Without id: next_before from the last page"}},"additionalProperties":false}
```

### regen_connect

Connect a spec for rebuilds. Scope: sync.

Connect a repository whose program is kept in a duramen record, so Graft can rebuild it blind (lang lists the languages open now). Premium, Team and Enterprise only; connecting costs nothing. Next: regen_report.

```json
{"type":"object","properties":{"repo":{"type":"string","description":"owner/name on GitHub"},"clone_url":{"type":"string","description":"Or an https git address"},"token":{"type":"string","description":"With clone_url: a read token"},"username":{"type":"string","description":"Default git"},"branch":{"type":"string"},"record":{"type":"string","description":"From the repository's root"},"impl":{"type":"string","description":"The implementation's folder"},"lang":{"type":"string","enum":["ts","py","rs","go"],"description":"ts (TypeScript on Node.js), py (Python), rs (Rust) or go (Go); Rust and Go use the standard library only"},"builds":{"type":"integer","minimum":1,"maximum":3,"description":"Blind builds per rebuild (default 1)"},"on_push":{"type":"boolean","description":"Rebuild when a push changes the record"},"on_model":{"type":"boolean","description":"Rebuild on each new model"},"delivery":{"type":"string","enum":["graft","github"],"description":"github adds a pull request (GitHub app only)"},"org":{"type":"string","description":"An organization you're in, for its defaults and channels"}},"required":["branch","record","impl","lang"],"additionalProperties":false}
```

### regen_run

Rebuild a spec now. Scope: sync.

Rebuild a spec blind from its record, kept on graft/regen/<id> only if every case passes. Spends agent work: $2, or max_usd up to $10 (over it: price_quote; ask the user). 4 to 12 minutes. Next: regen_status with run.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"force":{"type":"boolean","description":"Rebuild even if nothing changed since a passing rebuild"},"max_usd":{"type":"number","minimum":0,"description":"Dollars; default $2"}},"required":["id"],"additionalProperties":false}
```

### regen_set

Set a spec's desired state. Scope: sync.

Write a spec's desired state; only the fields you give change. max_usd only lowers Graft's $2 cap. Free; queues nothing. Answers desired beside observed.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"paused":{"type":"boolean"},"delivery":{"type":"string","enum":["graft","github"]},"max_usd":{"type":["number","null"],"minimum":0.5,"maximum":1000},"on_push":{"type":"boolean"},"on_model":{"type":"boolean"},"builds":{"type":"integer","minimum":1,"maximum":3}},"required":["id"],"additionalProperties":false}
```

### regen_disconnect

Disconnect a spec. Scope: sync. Destructive.

Disconnect a spec, as /app's Disconnect does: its queued rebuilds are cancelled and its kept rebuilds deleted; its rebuilds' signed records stay. Ask the user first.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"}},"required":["id"],"additionalProperties":false}
```

### regen_status

Specs and rebuilds. Scope: read. Read-only.

Specs and rebuilds. For a copy use status; for drafts or change orders, regen_draft_status or regen_order_status. id: one spec; run: one rebuild, with a fields legend. Poll at most every 30 seconds.

```json
{"type":"object","properties":{"id":{"type":"string","description":"A spec's id"},"run":{"type":"string","description":"A rebuild's id"}},"additionalProperties":false}
```

### regen_record

A rebuild's signed record. Scope: read. Read-only.

A finished rebuild's signed record. Save it as JSON and check it with npx graftfork verify-record <file>. Free. {signing: true}: ask again in 30 seconds.

```json
{"type":"object","properties":{"run":{"type":"string","description":"The rebuild's id"}},"required":["run"],"additionalProperties":false}
```

### regen_rejudge

Judge a rebuild's builds again. Scope: sync.

Judge a finished rebuild's stored builds again with today's runner, to confirm a verdict. No agent work; the original stays. Next: regen_status with the new run.

```json
{"type":"object","properties":{"run":{"type":"string","description":"The rebuild's id"},"same_seed":{"type":"boolean","description":"Use the rebuild's own holdout seed (default: a fresh one)"},"duramen_ref":{"type":"string","description":"The duramen to judge with; only the rebuild's own is taken for now"}},"required":["run"],"additionalProperties":false}
```

### regen_report

A spec's report. Scope: read. Read-only.

A spec's free grade (strong, usable or thin), its reasons, and what a blind rebuild can be judged on. Next: regen_run, or regen_report_refresh.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"}},"required":["id"],"additionalProperties":false}
```

### regen_report_refresh

Grade a spec's record again. Scope: sync.

Grade a spec's record again, no model. Free for 20 a day (UTC); then $0.10, only within max_usd. About a minute. Next: regen_report.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"max_usd":{"type":"number","minimum":0,"description":"Dollars; default 0, free only"}},"required":["id"],"additionalProperties":false}
```

### regen_draft_check

Check a branch's record. Scope: sync.

For a record edited on a pushed branch of the user's repository. For an edit held in Graft with no branch, use regen_order_check. First edit the record on a new branch in the user's repository and push it; this grades it free. Next: regen_draft_status.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"branch":{"type":"string","description":"The branch with the edited record, not the spec's own"},"max_usd":{"type":"number","minimum":0,"description":"Dollars past the free reports; default 0"}},"required":["id","branch"],"additionalProperties":false}
```

### regen_draft_rebuild

Rebuild a branch's record. Scope: sync.

For a record edited on a pushed branch. For an edit held in Graft, use regen_order_rebuild. Compared with the last kept build; priced like regen_run. Never writes a branch: the user may merge the branch themselves. Next: regen_draft_status.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"branch":{"type":"string","description":"The branch with the edited record"},"max_usd":{"type":"number","minimum":0,"description":"Dollars; default $2"}},"required":["id","branch"],"additionalProperties":false}
```

### regen_draft_status

A spec's drafts. Scope: read. Read-only.

Drafts from pushed branches. For change orders use regen_order_status. Each check and rebuild, newest first; unexplained (answers changed where both oracles agree) should be 0. With run, one in full.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"run":{"type":"string","description":"One draft's id, for its full detail"},"before":{"type":"string","description":"next_before from the last page"}},"required":["id"],"additionalProperties":false}
```

### regen_order_create

Start a change order. Scope: sync.

For an edit held in Graft (a change order). For a pushed branch, use regen_draft_check. Starts an order with a one-line title and optional whole files. Free. Next: regen_order_write, regen_order_check.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"title":{"type":"string","maxLength":120,"description":"One line, for example Green starts at 78 F"},"files":{"type":"array","maxItems":40,"items":{"type":"object","properties":{"path":{"type":"string"},"text":{"type":["string","null"]},"delete":{"type":"boolean"}},"required":["path"],"additionalProperties":false},"description":"Whole texts, in the record's folder"}},"required":["id","title"],"additionalProperties":false}
```

### regen_order_write

Write a change order's files. Scope: sync.

Replace change-order files, each a WHOLE new text (text null restores, delete true deletes). expect: the overlaySha you edited, null at first. Read files first with regen_order_status. Free. Next: regen_order_check.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"order":{"type":"string","description":"The change order's id"},"expect":{"type":["string","null"],"description":"The overlaySha you edited, or null"},"files":{"type":"array","maxItems":40,"items":{"type":"object","properties":{"path":{"type":"string"},"text":{"type":["string","null"]},"delete":{"type":"boolean"}},"required":["path"],"additionalProperties":false}},"title":{"type":"string","maxLength":120}},"required":["id","order","expect","files"],"additionalProperties":false}
```

### regen_order_check

Check a change order. Scope: sync.

For an edit held in Graft (a change order). For an edit on a pushed branch, use regen_draft_check. Grades the edited record and its version bump. Free within the day's free reports. Next: regen_order_status with order.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"order":{"type":"string","description":"The change order's id"},"max_usd":{"type":"number","minimum":0,"description":"Dollars past the free reports; default 0"}},"required":["id","order"],"additionalProperties":false}
```

### regen_order_rebuild

Rebuild from a change order. Scope: sync.

For an edit held in Graft (a change order). For a pushed branch, use regen_draft_rebuild. Priced like regen_run. Refused until a clean check, a big enough version bump and, if the oracle or a file the judge reads changed, a person's approval in /app. You can't approve it: give the user the link.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"order":{"type":"string","description":"The change order's id"},"max_usd":{"type":"number","minimum":0,"description":"Dollars; default $2"}},"required":["id","order"],"additionalProperties":false}
```

### regen_order_status

A spec's change orders. Scope: read. Read-only.

Change orders held in Graft. For drafts on pushed branches use regen_draft_status. With order: files, approval, check, runs and take (patch true: a git patch).

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"order":{"type":"string","description":"One change order's id, for its detail"},"patch":{"type":"boolean","description":"With order: the record change as a git patch"},"files":{"type":"boolean","description":"The record folder's files"},"path":{"type":"string","description":"One file's whole text"}},"required":["id"],"additionalProperties":false}
```

### regen_order_discard

Discard a change order. Scope: sync. Destructive.

End a change order the user doesn't want: its edits go, its history stays. Refused while a check or rebuild of it runs, or once it is taken.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The spec's id"},"order":{"type":"string","description":"The change order's id"},"why":{"type":"string","maxLength":300}},"required":["id","order"],"additionalProperties":false}
```

### usage

Plan and usage. Scope: read. Read-only.

The plan, syncs and copies against limits, and agentWork: agent work left, spent, and the caps. Read it before work that takes max_usd. Resets on the 1st (UTC).

```json
{"type":"object","properties":{},"additionalProperties":false}
```

### webhook_add

Add a webhook. Scope: sync.

Register a public https URL Graft posts JSON to when work ends or needs someone, instead of polling. Posts are signed in Graft-Signature; the answer holds the secret once, and verify says how to check it. Next: webhook_test.

```json
{"type":"object","properties":{"url":{"type":"string","description":"https URL, port 443, public address"},"events":{"type":"array","items":{"type":"string","enum":["run.finished","run.needs_person","regen.finished","budget.capped","budget.nearing","audit.entry","review.overdue"]}},"org":{"type":"string","description":"Owned organization, for audit.entry"}},"required":["url"],"additionalProperties":false}
```

### webhook_list

Webhooks and deliveries. Scope: read. Read-only.

The user's webhooks with their last deliveries; with id, one webhook's last 50 (event, status, attempts, what the URL answered).

```json
{"type":"object","properties":{"id":{"type":"string","description":"A webhook's id"},"before":{"type":"string","description":"With id: deliveriesNextBefore from the last page"}},"additionalProperties":false}
```

### webhook_remove

Remove a webhook. Scope: sync. Destructive.

Remove a webhook and its delivery log. Graft stops posting to it at once.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The webhook's id, from webhook_list"}},"required":["id"],"additionalProperties":false}
```

### webhook_test

Test a webhook. Scope: sync.

Post a signed ping now and say what the URL answered. A ping that gets through turns a webhook Graft turned off back on.

```json
{"type":"object","properties":{"id":{"type":"string","description":"The webhook's id, from webhook_list"}},"required":["id"],"additionalProperties":false}
```

### list_fork_alerts

List fork watch alerts. Scope: read. Read-only.

Team and Enterprise: what fork watch found new: advisory (a fix the fork lacks), behind (a new release), carry (changes that stopped carrying). Read-only.

```json
{"type":"object","properties":{"id":{"type":"string","description":"An organization's id; leave out for all"},"limit":{"type":"integer","minimum":1,"maximum":200,"description":"Per organization (default 100)"}},"additionalProperties":false}
```

### path_policy

Protected paths. Scope: read. Read-only.

Paths a move you make may not change without a person, for a copy (id) or organization (org). A resolution touching one is held for review.

```json
{"type":"object","properties":{"id":{"type":"string","description":"A copy's id, from list_copies"},"org":{"type":"string","description":"An organization's id, instead of a copy"}},"additionalProperties":false}
```

### org_settings

An organization's settings. Scope: read. Read-only.

An organization's defaults for new copies and specs, its review checklist, its channels' quiet hours, and your own muted email events. Any member reads them.

```json
{"type":"object","properties":{"org":{"type":"string","description":"The organization's id"}},"required":["org"],"additionalProperties":false}
```

### org_settings_set

Change an organization's settings. Scope: admin.

Owners: set the organization's defaults, review checklist or quiet hours. Each one sent replaces what was there (null clears it); the rest stay. Each change is written in the organization's audit log. Needs a token with the admin scope, which only an organization's owner can make.

```json
{"type":"object","properties":{"org":{"type":"string"},"defaults":{"type":["object","null"],"properties":{"delivery":{"enum":["graft","github"]},"builds":{"enum":[1,2,3]},"max_usd":{"type":"number","minimum":0,"maximum":1000},"follow":{"enum":["all","minor","major"]}},"additionalProperties":false},"checklist":{"type":["string","null"],"maxLength":2000},"quiet":{"type":["object","null"],"properties":{"start":{"type":"string","description":"HH:MM, 24 hours"},"end":{"type":"string"},"tz":{"type":"string","description":"An IANA time zone, such as Europe/Berlin"},"through":{"type":"array","items":{"enum":["run.finished","run.needs_person","budget.nearing","budget.capped","audit.entry","regen.finished","review.overdue"]},"description":"Events that go out during quiet hours anyway; left out, budget.capped"}},"required":["start","end"],"additionalProperties":false}},"required":["org"],"additionalProperties":false}
```

### org_notify_set

Mute organization email. Scope: sync.

The events you don't want by email from the organization's email channels (an empty list for all of them). Your own choice; it changes nothing for anyone else.

```json
{"type":"object","properties":{"org":{"type":"string"},"muted":{"type":"array","items":{"enum":["run.finished","run.needs_person","budget.nearing","budget.capped","audit.entry","regen.finished","review.overdue"]}}},"required":["org","muted"],"additionalProperties":false}
```

### org_channels

An organization's team channels. Scope: read. Read-only.

An organization's team channels: destination, events, team, on or off, and recent deliveries. Owners and reviewers.

```json
{"type":"object","properties":{"org":{"type":"string"}},"required":["org"],"additionalProperties":false}
```

### org_channel_add

Add a team channel. Scope: admin.

Owners: a new team channel. kind webhook (Graft's signed JSON; its secret is in the answer, once), slack or teams with url; or email with recipients (members). events defaults to all but audit.entry; team limits it to one team. The organization owns it. Free. Next: org_channel_test.

```json
{"type":"object","properties":{"org":{"type":"string"},"name":{"type":"string","maxLength":60},"kind":{"enum":["webhook","slack","teams","email"]},"url":{"type":"string"},"recipients":{"type":"array","items":{"type":"string"}},"events":{"type":"array","items":{"enum":["run.finished","run.needs_person","budget.nearing","budget.capped","audit.entry","regen.finished","review.overdue"]}},"team":{"type":"string"}},"required":["org","name","kind"],"additionalProperties":false}
```

### org_channel_set

Change a team channel. Scope: admin.

Owners: change a channel's name, events, team (null for every team), recipients (email channels) or pause it. Its address can't change: add a new channel instead.

```json
{"type":"object","properties":{"org":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"events":{"type":"array","items":{"enum":["run.finished","run.needs_person","budget.nearing","budget.capped","audit.entry","regen.finished","review.overdue"]}},"team":{"type":["string","null"]},"recipients":{"type":"array","items":{"type":"string"}},"paused":{"type":"boolean"}},"required":["org","id"],"additionalProperties":false}
```

### org_channel_remove

Remove a team channel. Scope: admin. Destructive.

Owners: remove a channel, its webhook and what waits to be sent to it.

```json
{"type":"object","properties":{"org":{"type":"string"},"id":{"type":"string"}},"required":["org","id"],"additionalProperties":false}
```

### org_channel_test

Send a test to a team channel. Scope: admin.

Owners: a test post (or one email to each recipient) now, whatever the channel's events and quiet hours. One that gets through turns a webhook that went off after failures back on.

```json
{"type":"object","properties":{"org":{"type":"string"},"id":{"type":"string"}},"required":["org","id"],"additionalProperties":false}
```

### org_audit_verify

Check an organization's audit log. Scope: read.

Sign and check the organization's audit log (signature, entry hashes, ledger copies): ok and any problems. Owners and reviewers. To check without trusting Graft, run graft verify-record on its export.

```json
{"type":"object","properties":{"org":{"type":"string"}},"required":["org"],"additionalProperties":false}
```

### org_review_queue

Review queue. Scope: read. Read-only.

An organization's moves waiting for review, riskiest first, with what to read and skip. Says what changed, not what is correct; approving stays a person's, in /app.

```json
{"type":"object","properties":{"org":{"type":"string","description":"The organization's id"}},"required":["org"],"additionalProperties":false}
```

### buy_agent_work

Buy more agent work. Scope: pay.

Buy one top-up of Graft's agent work for this account, paid in USDC over x402 (version 2, scheme exact) from your own wallet: $10 adds $7, usable this month and next, on Premium. Call it without payment_signature to get the payment requirements (network, asset, amount, payTo). Sign an EIP-3009 transferWithAuthorization for exactly that amount to that address, put the x402 PaymentPayload {x402Version: 2, accepted: <the requirement, unchanged>, payload: <the signed authorization>} in base64, and call again with it as payment_signature. Graft verifies and settles it through a facilitator and answers with the credit. Calling again with the same payment_signature returns the same credit and pays nothing. Off Premium it answers not_premium before any payment. Spend only what the user or your own budget allows; usage shows the agent work left.

```json
{"type":"object","properties":{"payment_signature":{"type":"string","description":"The base64 x402 PaymentPayload. Leave out to get the requirements"}},"additionalProperties":false}
```

## HTTP operations

Every operation in https://graftfork.com/api/v1/openapi.json, with the scope it needs. The description has the request and answer schemas.

- `POST /api/try`: Try a public fork, no account (no token)
- `GET /api/try/{id}`: A try's progress and result (no token)
- `GET /api/v1/token`: The token's owner and scopes
- `GET /api/v1/copies`: List your copies (scope: read)
- `POST /api/v1/copies`: Connect a repository (scope: sync)
- `GET /api/v1/copies/{id}`: One copy, its latest syncs, and its desired and observed state (scope: read)
- `PUT /api/v1/copies/{id}`: Set a copy's desired state (scope: sync)
- `POST /api/v1/copies/{id}/sync`: Sync now (scope: sync)
- `POST /api/v1/copies/{id}/disconnect`: Disconnect a copy (scope: sync)
- `GET /api/v1/copies/{id}/runs`: A copy's syncs (scope: read)
- `GET /api/v1/copies/{id}/upstream`: A change, ready to send upstream (scope: read)
- `POST /api/v1/copies/{id}/upstream`: Build a change for upstream (scope: sync)
- `GET /api/v1/upstreams/{id}`: An upstream build (scope: read)
- `POST /api/v1/upstreams/{id}/pr`: Track the upstream pull request (scope: sync)
- `POST /api/v1/upstreams/{id}/review`: Ask for Graft's reviewer (scope: sync)
- `GET /api/v1/copies/{id}/explain`: Why the last sync stayed (scope: read)
- `GET /api/v1/runs/{id}`: A sync's report (scope: read)
- `GET /api/v1/runs/{id}/take`: How to take a move Graft delivered (scope: read)
- `POST /api/v1/runs/{id}/revert`: Revert a move (scope: sync)
- `GET /api/v1/runs/{id}/record`: A run's signed record (scope: read)
- `GET /api/v1/copies/{id}/take`: How to take the move a copy is on now (scope: read)
- `GET /api/v1/conflicts`: What's waiting (scope: read)
- `GET /api/v1/conflicts/{id}`: One conflict or question (scope: read)
- `POST /api/v1/conflicts/{id}/resolution`: Hand in a resolved file (scope: resolve)
- `POST /api/v1/conflicts/{id}/answer`: Answer a question (scope: resolve)
- `GET /api/v1/orgs/{id}/audit`: An organization's audit log, signed (scope: read)
- `GET /api/v1/orgs/{id}/audit/stream`: An organization's audit log as a stream, for a SIEM (scope: read)
- `GET /api/v1/orgs/{id}/agent-record`: An organization's agent change record (scope: read)
- `GET /api/v1/checks`: Your recent change checks (scope: read)
- `POST /api/v1/checks`: Check a change against the project's own tests (scope: sync)
- `GET /api/v1/checks/{id}`: A change check's result (scope: read)
- `GET /api/v1/usage`: Plan and this month's use (scope: read)
- `POST /api/v1/agents`: An agent makes its own account and pays for it (no token)
- `POST /api/v1/agents/renew`: Pay for more time on an agent account
- `POST /api/v1/topups`: Buy more agent work, paid in USDC
- `GET /api/v1/orgs/{id}/policy`: An organization's path policy (scope: read)
- `PUT /api/v1/orgs/{id}/policy`: Add to an organization's path policy (scope: sync)
- `GET /api/v1/copies/{id}/policy`: A copy's path policy (scope: read)
- `PUT /api/v1/copies/{id}/policy`: Add to a copy's path policy (scope: sync)
- `GET /api/v1/orgs/{id}/alerts`: An organization's fork watch alerts (scope: read)
- `GET /api/v1/orgs/{id}/agents`: An organization's agents (scope: admin)
- `POST /api/v1/orgs/{id}/agents`: Make an agent for the organization (scope: admin)
- `DELETE /api/v1/orgs/{id}/agents/{agent}`: Retire an agent (scope: admin)
- `POST /api/v1/orgs/{id}/agents/{agent}/rotate`: A new token for an agent (scope: admin)
- `POST /api/v1/orgs/{id}/agents/disable`: Turn all of the organization's agents off (scope: admin)
- `POST /api/v1/orgs/{id}/agents/enable`: Turn the organization's agents back on (scope: admin)
- `GET /api/v1/orgs/{id}/budgets`: An organization's monthly caps (scope: read)
- `PUT /api/v1/orgs/{id}/budgets`: Set or clear an organization's caps (scope: admin)
- `GET /api/v1/orgs/{id}/enterprise-auth`: An organization's enterprise-managed authorization (scope: admin)
- `PUT /api/v1/orgs/{id}/enterprise-auth`: Set an organization's enterprise-managed authorization (refused with a token) (scope: admin)
- `DELETE /api/v1/orgs/{id}/enterprise-auth`: Turn off an organization's enterprise-managed authorization (refused with a token) (scope: admin)
- `POST /api/v1/orgs/{id}/members/team`: Set a member's team (scope: admin)
- `GET /api/v1/orgs/{id}/console`: An organization's console overview (scope: read)
- `GET /api/v1/orgs/{id}/settings`: An organization's settings (scope: read)
- `PUT /api/v1/orgs/{id}/settings`: Change an organization's settings (scope: admin)
- `PUT /api/v1/orgs/{id}/notify`: Your email from an organization's channels (scope: sync)
- `GET /api/v1/orgs/{id}/audit/entries`: An organization's audit log, filtered (scope: read)
- `POST /api/v1/orgs/{id}/audit/verify`: Check an organization's audit log (scope: read)
- `GET /api/v1/orgs/{id}/team-stats`: How the team works (scope: read)
- `GET /api/v1/orgs/{id}/reviewers`: Who reviews what (scope: read)
- `GET /api/v1/orgs/{id}/review`: Moves waiting for review, with what to read (scope: read)
- `GET /api/v1/orgs/{id}/channels`: An organization's team channels (scope: read)
- `POST /api/v1/orgs/{id}/channels`: Add a team channel (scope: admin)
- `PUT /api/v1/orgs/{id}/channels/{channel}`: Change a team channel (scope: admin)
- `DELETE /api/v1/orgs/{id}/channels/{channel}`: Remove a team channel (scope: admin)
- `POST /api/v1/orgs/{id}/channels/{channel}/test`: Send a test to a team channel (scope: admin)
- `GET /api/v1/orgs/{id}/usage`: An organization's spend by team, agent and member (scope: read)
- `GET /api/v1/upgrades`: Your dependency upgrades (scope: read)
- `POST /api/v1/upgrades`: Upgrade a dependency, checked by the tests (scope: sync)
- `GET /api/v1/upgrades/{id}`: One upgrade and its report (scope: read)
- `GET /api/v1/upgrades/{id}/take`: How to take a delivered upgrade (scope: read)
- `GET /api/v1/regen`: Your specs (scope: read)
- `POST /api/v1/regen`: Connect a spec (scope: sync)
- `GET /api/v1/regen/{id}`: One spec, its rebuilds, and its desired and observed state (scope: read)
- `PUT /api/v1/regen/{id}`: Set a spec's desired state (scope: sync)
- `DELETE /api/v1/regen/{id}`: Disconnect a spec (scope: sync)
- `GET /api/v1/webhooks`: Your webhooks (scope: read)
- `POST /api/v1/webhooks`: Add a webhook (scope: sync)
- `GET /api/v1/webhooks/{id}`: A webhook and its deliveries (scope: read)
- `DELETE /api/v1/webhooks/{id}`: Remove a webhook (scope: sync)
- `POST /api/v1/webhooks/{id}/test`: Post a test event now (scope: sync)
- `POST /api/v1/regen/{id}/run`: Rebuild now (scope: sync)
- `GET /api/v1/regen/runs/{id}`: A rebuild (scope: read)
- `GET /api/v1/regen/runs/{id}/record`: A rebuild's signed record (scope: read)
- `POST /api/v1/regen/runs/{id}/rejudge`: Judge a rebuild's builds again (scope: sync)
- `GET /api/v1/regen/{id}/drafts`: A spec's drafts (scope: read)
- `POST /api/v1/regen/{id}/drafts`: Rebuild from the record on a branch (scope: sync)
- `POST /api/v1/regen/{id}/drafts/check`: Grade the record on a branch (scope: sync)
- `GET /api/v1/regen/{id}/orders`: A spec's change orders (scope: read)
- `POST /api/v1/regen/{id}/orders`: Start a change order (scope: sync)
- `POST /api/v1/regen/{id}/orders/draft`: Draft a change order from one line (scope: sync)
- `GET /api/v1/regen/{id}/order-files`: The record's folder (scope: read)
- `GET /api/v1/regen/{id}/orders/{order}`: A change order (scope: read)
- `PUT /api/v1/regen/{id}/orders/{order}/files`: Edit a change order's files (scope: sync)
- `GET /api/v1/regen/{id}/orders/{order}/diff`: A change order's diff (scope: read)
- `POST /api/v1/regen/{id}/orders/{order}/check`: Check a change order (scope: sync)
- `POST /api/v1/regen/{id}/orders/{order}/approve-oracle`: Approve an oracle change (a person only) (scope: sync)
- `POST /api/v1/regen/{id}/orders/{order}/rebuild`: Rebuild from a change order (scope: sync)
- `GET /api/v1/regen/{id}/orders/{order}/take`: Take a change order's rebuild (scope: read)
- `POST /api/v1/regen/{id}/orders/{order}/discard`: Discard a change order (scope: sync)
- `GET /api/v1/regen/{id}/orders/{order}/patch`: A change order's record change as a patch (scope: read)
- `GET /api/v1/regen/{id}/report`: A spec's report (scope: read)
- `POST /api/v1/regen/{id}/report`: Grade the record again (scope: sync)
