Skip to content
GhostbranchdocsGitHub

How agents use Ghostbranch

What a coding agent reads before it starts, the loop it runs, and how the ledger tells its commands from yours.

A coding agent drives the same command-line tool you do. It reads a guide that the binary prints, runs every command with --json, and follows the list of next steps in each result. This page shows that from your side: what the agent reads, what it runs, and how you can tell its work from yours afterwards.

ghostbranch guide prints a guide written for coding agents, in Markdown. It’s built into the binary, so it always describes the version you have installed. When you upgrade, the guide changes with it. An agent should read all of it at the start of a task, before it runs anything else.

It covers, roughly in this order:

  • The loop: sync, start a feature, commit and push to the shadow repo, gate, and plan the publish.
  • The details of each step: choosing a history mode, long CI and jobs, setting up a repo, closing features, stacks, updating an open pull request, and keeping up with public main.
  • The rules: how to read results, when to stop, what to do about a leak, and a list of things an agent must never do.
  • Reference: every exit code and error code, with whether it needs a person.
  • Sections for people: the push guard, grants in Claude Code, internal sections, tokens and their permissions, and strict isolation.

The pages in this section explain the same rules for people, with the reasons behind them. If this site and the guide ever disagree, trust the guide: it’s your installed version’s own text.

An agent doesn’t know to read the guide unless something tells it to. ghostbranch guide --install writes a small skill that does. It says to run ghostbranch guide first and follow it, and repeats the most important rules in a few lines: pass --json, act on the exit code and next, stop when a person is needed, never push feature work to the public repo with git, never run agents allow or waivers add, and set GHOSTBRANCH_ACTOR.

  • Claude Code: ghostbranch guide --install claude writes .claude/skills/ghostbranch/SKILL.md in your home folder. If you set CLAUDE_CONFIG_DIR, it writes skills/ghostbranch/SKILL.md in that folder instead.
  • Codex: ghostbranch guide --install codex writes .agents/skills/ghostbranch/SKILL.md in your home folder.

The skill always goes in your user folder, never in your repo. A skill file committed to your repo would go public with your next promote, and would tell everyone that you keep a shadow repo.

--plan shows what it would do. Run on a machine that already had the skill, it changes nothing:

guide --install claude --plan --json (data)
{
"target": "claude",
"path": "/home/you/.claude/skills/ghostbranch/SKILL.md",
"action": "unchanged",
"preview": { "fingerprint": {}, "ops": [] }
}

That run was on a machine where the skill was already up to date, and the path is shown as it would be on Linux. On a first install the action is installed, and after an upgrade that changed the skill it’s updated. If a file at that path wasn’t written by Ghostbranch, --install refuses with BAD_FLAG and leaves it alone. --uninstall claude or --uninstall codex removes the skill.

These are the commands an agent runs for one feature, with what it does in between:

Terminal
ghostbranch sync --repo you/project --json
ghostbranch feature start add-search --repo you/project --json
runs each command in data.checkout, then commits
git push shadow add-search
ghostbranch gate add-search --repo you/project --json
ghostbranch promote add-search --title "Add search" --repo you/project --plan --json
then follows next: runs it, or stops and hands it to you
  1. Sync first. A feature starts from shadow main, so the agent brings it up to date before it starts or resumes one.

  2. Start the feature, and switch to its branch. The result says exactly how, as a list of commands to run in order. It doesn’t leave the agent to guess the remote’s name:

    feature start --json (part)
    {
    "data": {
    "checkout": [
    ["git", "fetch", "shadow"],
    ["git", "switch", "add-search"]
    ],
    "checkout_hint": "git fetch shadow && git switch add-search"
    },
    "next": [
    {
    "command": ["ghostbranch", "gate", "add-search", "--repo", "you/project"],
    "why": "check out with `git fetch shadow && git switch add-search`, commit on add-search, push it with `git push shadow add-search` (the shadow repo, never origin), then gate it",
    "needs_human": false,
    "needs_input": []
    }
    ]
    }

    This is part of the result: the rest of data and the envelope around it are left out.

  3. Commit and push to the shadow repo, never to origin (except an archived feature’s pull request: see After publishing). If you’ve installed the push guard, it refuses a feature push to the public repo whatever the agent intended.

  4. Gate. For a long CI run, the agent can detach and come back with wait, as in Long CI.

  5. Plan the publish with promote --plan. The agent writes the pull request’s title itself, from the change, and shows it to you.

  6. Follow next. If the next step needs a person, the agent stops and gives you the exact command. If you’ve allowed agents to publish to this repo, it may run the publish itself.

Every result has the same shape, and JSON output and next explains how an agent reads it. What only a person can do lists what it hands back to you.

Set GHOSTBRANCH_ACTOR in the agent’s environment, so the ledger records that an agent ran each command:

Terminal window
export GHOSTBRANCH_ACTOR=agent:claude-code
  • Its form is agent:<name>, human:<name> or app. Any other value stops the command before it runs, with BAD_FLAG naming GHOSTBRANCH_ACTOR.
  • If it’s unset, Ghostbranch records the GitHub account of the token it’s using, as human:<login>. So an agent that runs on your login without the variable shows up in the ledger as you. If the login can’t be read either, the ledger says human:unknown and the command warns ACTOR_UNKNOWN.
  • It’s a label only. It never grants or blocks anything: approval and grants don’t read it. It does make a run look like an agent’s, so Ghostbranch can warn AGENT_ON_PERSON_LOGIN when that run uses your own stored login. That warning also fires when Claude Code’s marker variable is set, or when no one is at a console, unless GHOSTBRANCH_ACTOR names a person.

The agent’s guide asks it to set the variable on every command. You can also set it once for the whole agent. In Claude Code, put it under env in a settings file:

.claude/settings.local.json
{ "env": { "GHOSTBRANCH_ACTOR": "agent:claude-code" } }

Keep that file out of your commits, as In Claude Code explains.

ghostbranch log then shows who did what. Here an agent synced, started a feature and waited on a job it hadn’t started yet, after a person had renewed a grant:

Terminal
ghostbranch log
2026-10-13T04:22:16Z agent:claude-code wait add-search exit 2 feature "add-search" has no gate job to wait on: it was never gated, or its last gate stopped before CI; gate it
2026-10-13T04:21:49Z agent:claude-code feature start add-search exit 0 stacked on search-index
2026-10-13T04:21:40Z agent:claude-code sync - exit 0 main up_to_date
2026-10-13T04:17:42Z human:you grant_replaced - exit 0 agents may publish to you/project
older entries left out

The four newest lines of a real log, with names changed. The ledger keeps failures too, such as the exit 2 above.

ACTOR_UNKNOWNwarningGHOSTBRANCH_ACTOR is unset and the GitHub login wasn't read; the ledger records human:unknown.
What to do

Set GHOSTBRANCH_ACTOR, for example agent:claude-code.

AGENT_ON_PERSON_LOGINwarningThis run looks like an agent or a script, and it is using a person's stored login, which can publish.
What to do

Give the agent its own shadow-only token in GHOSTBRANCH_TOKEN (see ghostbranch guide § Tokens). The person's login still needs the console code to publish.

BAD_FLAGexit 2A flag, argument or option value is invalid.
What to do

Fix the value named in error.field.