graft

Docs / For agents

Agents and Claude Code

An agent can use Graft without you opening the dashboard: register a repository whose changes should survive upstream releases, start a sync, see why one stayed, and fix the conflicts it stopped on. The safety rule doesn't change for agents. Graft moves a copy only when every change lands and the tests pass, and nothing an agent sends can skip that.

Claude Code: the plugin

The plugin connects Claude Code to Graft's MCP server and adds a skill and a command:

  • graft-reasons, a skill: whenever Claude changes a dependency, a fork or a vendored package, it writes why into the commit message in the form Graft reads (below), and offers to track the repository with Graft.
  • /graft:graft-status, a command: how your copies are doing, what's waiting, and what to do next.

Install it in Claude Code:

/plugin marketplace add craigm26/graft-claude-code
/plugin install graft@graft-claude-code

Then make a token under Settings in your dashboard and put it in the environment Claude Code starts from, for example in your shell profile:

export GRAFT_TOKEN=graft_...

Restart Claude Code and check the connection with /mcp; the server shows as plugin:graft:graft. The plugin holds only configuration and instructions; it's public at github.com/craigm26/graft-claude-code.

Prefer the server without the plugin? One command adds it:

claude mcp add --transport http graft https://graftfork.com/mcp --header "Authorization: Bearer ${GRAFT_TOKEN}"

Other MCP clients

The server is at https://graftfork.com/mcp. It speaks Streamable HTTP, statelessly, in both the current protocol revision (2026-07-28, no handshake) and the earlier ones that start with initialize (2025-03-26 to 2025-11-25). It authenticates with a bearer token. A client that takes a JSON config:

{
  "mcpServers": {
    "graft": {
      "type": "http",
      "url": "https://graftfork.com/mcp",
      "headers": { "Authorization": "Bearer ${GRAFT_TOKEN}" }
    }
  }
}

Some clients want the token written in rather than an environment variable; your dashboard's Settings page shows the config with a new token filled in, once.

Tools

ToolWhat it doesScope
track_changeRegisters a repository as a copy. With only repo, Graft detects the upstream, the release your branch is on and the tag pattern, and starts the first sync if a newer release is out. To follow another branch, give branch, upstream and base. Graft's GitHub app has to be installed on the repository first.sync
list_copiesYour copies, each with its last sync in plain words and what's waiting.read
statusOne copy and its latest syncs, with pull request links.read
sync_nowStarts a sync. Counts against your monthly syncs.sync
explain_stopWhy the last sync stayed, which changes were stuck, and the next action: resolve, ask you a question, review a pull request, or something only you can do.read
list_pending_conflictsConflicting files waiting for your agent, and questions waiting for your decision.read
get_conflictOne conflicting file in three versions (before your change, with it, in the new release) and your change's reason; or a question and its options.read
submit_resolutionThe whole resolved file. Once every file in that sync is in, Graft runs the sync again and moves your copy only if the tests pass.resolve
answer_questionAnswers a question with the option you pick. Agents are told to ask you first.resolve
usageYour plan, this month's syncs and agent spend.read

A token sees only the tools its scopes allow. The older sync_status tool still answers, as status.

How tokens work

  • Made and revoked in your dashboard, under Settings. A token can't make another token.
  • Shown once. Graft stores only a SHA-256 hash of it and its last four characters, so we can't show it again; make a new one if you lose it.
  • Scoped. read sees your copies, syncs, reports, waiting conflicts and usage. sync connects repositories and starts syncs. resolve hands in a fixed file or answers a question. Give an agent only what it needs: a status dashboard needs read alone.
  • Logged. Every use, by the HTTP API or the MCP server, is recorded with the token, the action and the result, and your dashboard lists the recent ones. Records are kept for 90 days.
  • Rate limited per token: 120 requests a minute, 30 of them changes.
  • Revoking stops a token at once. The "Connect Claude Code" button under Agents makes a token with every scope and turns its previous one off.

Treat a token like a password: keep it in an environment variable or a secret store, never in a repository. Anyone with a resolve token can hand in a resolution, but they still can't move your copy past your tests.

Recording why: the reason format

Graft carries a change onto a new release from its commit. When a change conflicts, the agent that rewrites it works from the reason you recorded, so a good reason is what makes the next carry right. Graft reads, for each commit on your branch after the release it sits on:

  • The subject line: what changed.
  • The body: why. Plain sentences, in one or more paragraphs before any trailers. Say what problem the change solves, why upstream's behaviour doesn't fit, and what has to stay true for the change to still be right.
  • These trailers, in the last paragraph, when they apply: Origin: (where the change came from, such as upstream, https://... for a backported fix), Bug:, Forwarded: (whether it was sent upstream) and Applied-Upstream:.

Other trailers, such as Signed-off-by or Co-authored-by, are bookkeeping and not read as the reason. A line in the last paragraph that starts with a word and a colon counts as a trailer, so don't start a sentence of the reason that way there. An example:

Pin retry backoff to 30 seconds for our rate-limited API

Our upstream API rejects bursts and bans the client for an hour. Upstream's
exponential backoff reaches 4 minutes, which makes our nightly job miss its
window. Keep the cap at 30 seconds while the API's limit is per minute; drop
this change if upstream adds a configurable cap.

Forwarded: no

One change per commit carries best: Graft keeps, drops or rewrites each commit whole. graft record in the CLI lists your changes and flags any without a reason.

Conflicts on a copy an agent tracks

An agent that connects a copy with track_change (or POST /api/v1/copies) resolves that copy's conflicts itself: when a change conflicts, the sync stops and the conflict waits for it. It finds them with list_pending_conflicts, reads each with get_conflict (the file before your change, with it, and in the new release, plus your commit's reason), and hands back the whole file with submit_resolution. An agent can track a copy and resolve its own conflicts without anyone in the loop.

Copies connected in the dashboard don't wait for anyone: conflicts are resolved automatically there (on Premium, for the free first conflict, or on your own API key), or the copy stays and says so.

What an agent can't do

No tool, route or scope can move a copy, mark a sync moved, open a pull request, change the release a copy sits on, or skip the tests. A resolution is stored, and Graft's runner syncs again with it; the copy moves only if every change lands and the tests pass, exactly as when you answer a question in the dashboard. An agent's rewrite is only accepted when tests exist to check it.

For scripts and agents outside MCP, the same actions are on the HTTP API.