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.
The guide is the source
Section titled “The guide is the source”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.
Install the skill
Section titled “Install the skill”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 claudewrites.claude/skills/ghostbranch/SKILL.mdin your home folder. If you setCLAUDE_CONFIG_DIR, it writesskills/ghostbranch/SKILL.mdin that folder instead. - Codex:
ghostbranch guide --install codexwrites.agents/skills/ghostbranch/SKILL.mdin 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:
{ "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.
The loop, as an agent runs it
Section titled “The loop, as an agent runs it”These are the commands an agent runs for one feature, with what it does in between:
-
Sync first. A feature starts from shadow
main, so the agent brings it up to date before it starts or resumes one. -
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
dataand the envelope around it are left out. -
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. -
Gate. For a long CI run, the agent can detach and come back with
wait, as in Long CI. -
Plan the publish with
promote --plan. The agent writes the pull request’s title itself, from the change, and shows it to you. -
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.
Say who is acting
Section titled “Say who is acting”Set GHOSTBRANCH_ACTOR in the agent’s environment, so the ledger records that an agent ran each command:
export GHOSTBRANCH_ACTOR=agent:claude-code- Its form is
agent:<name>,human:<name>orapp. Any other value stops the command before it runs, withBAD_FLAGnamingGHOSTBRANCH_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 sayshuman:unknownand the command warnsACTOR_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_LOGINwhen 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, unlessGHOSTBRANCH_ACTORnames 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:
{ "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:
The four newest lines of a real log, with names changed. The ledger keeps failures too, such as the exit 2 above.
Errors you may see
Section titled “Errors you may see”ACTOR_UNKNOWNwarningGHOSTBRANCH_ACTOR is unset and the GitHub login wasn't read; the ledger records human:unknown.
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.
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.
Fix the value named in error.field.