git-agents
You orchestrate; deterministic scripts do every file operation. Run them with:
npx -y git-agents@latest --internal <command> [--input <json> | --input - | --input-file <path>]
Every command prints exactly one JSON envelope: {"ok":true,"result":...} or {"ok":false,"error":{"code":"...","message":"..."}}. Relay error messages with their remedy; never edit synced files by hand; never write anything except through the gate below.
Input channels: inline --input <json> is fine for small payloads; --input-file <path> reads the JSON from a file and --input - reads it from stdin, so the payload never crosses shell quoting. For any payload carrying multi-line content, backslashes, or backticks (stage above all, especially on Windows), write the JSON to a temp file and pass --input-file.
The command surface:
| Command | Effect | Writes? |
|---|---|---|
status |
Config, canonical version, generated states, drift, caveats | no |
setup |
Onboarding: remote choice, repo creation, clone | clone + config |
transport-begin |
Mirror local files into the clone, commit, merge from origin; reports clean changes or conflicts | clone |
transport-resolve |
Write resolved contents for conflicted files | clone |
transport-commit |
Complete the merge, mirror the result home, push ({"deferPush":true} skips the push) |
gated |
transport-abort |
Abort the in-progress merge | clone |
gather |
Collect drift vs canonical with attribution and input hashes | no |
stage |
Accept a proposed canonical, render exact diffs | stage file |
apply |
Write the staged canonical and regenerate all copies | gated |
propagate |
Regenerate harness copies from the current canonical | gated |
install-pointer-docs |
Print the Cursor pointer rule with resolved paths | no |
version-check |
Compare the installed skill version to the CLI version | no |
Router
The first word of the arguments selects the subcommand: setup, sync, edit, or status. When it is sync, an optional second word unify selects the full convergence flow; any other second word gets a hint listing sync and sync unify. When it is edit, everything after the first word is the freeform edit request. With no argument, or an unknown first word, run the status subcommand and list the surface. Before any subcommand, if status reports clonePresent: false, run the setup branch first, then offer to continue what was originally asked. After any subcommand completes, run the update check (see below).
Update check
After the requested subcommand's work is fully done (never before or instead of it), check whether this skill is outdated: read the VERSION file next to this SKILL.md, then run version-check with {"skillVersion":"<its contents>"}. If the result says updateAvailable: true, append exactly one line to your closing report: "git-agents is available (installed: ). Want me to update?" On an explicit yes, run npx -y skills add floklein/git-agents -y and confirm the refresh. On a decline, drop the subject; nothing is remembered. If the VERSION file is missing, the command fails, or updateAvailable is false, say nothing at all.
The gate
Before anything is written, show the user the exact script-rendered diffs and get an explicit confirmation. The diffs and the question travel in the same message: render the diffs, then ask in plain text directly below them. Never use a structured question tool (multiple-choice UI, option chips, any tool-mediated prompt) for gate confirmation; those render without the diffs in view, and the user must be able to see the diffs at the moment of answering. No is the default: anything but a clear yes means stop, and stopping costs nothing. Your own summary is never a substitute for the diffs. Declining a transport merge means transport-abort.
Subcommands
status
Run status. Report concisely: configured and clone state, canonical version, each generated file's state (current, stale, modified, untracked, missing, no-canonical), the drift summary, and every caveat with its remedy. When any generated file is stale or drift is present, point at /git-agents sync unify.
setup
- Run
status. If configured with a clone present, report that and stop; reconfigure (withforce:true) only if the user explicitly asks.force:truedeletes the local clone and re-clones from the remote; it is the recovery path after a rewritten remote history. Local harness files are not affected. - Ask the user's remote preference: GitHub CLI auto-create (a private
git-agents-remoterepo) or a custom git remote URL. - Run
setupwith{"remote":"gh"}or{"remote":"git","repoUrl":"..."}. On a typed error (gh-not-installed,gh-not-authenticated,invalid-repo-url,clone-failed), relay the message and help fix it before retrying. A forced re-clone refuses withunpushed-commitswhen the clone holds commits on no remote ref: runtransport-abortfirst if a transport is in progress, and adddiscardLocal:trueonly after the user confirms discarding them. - Suggest
/git-agents sync unifyas the next step.
sync
Transport only: configs travel to and from the repo independently; the canonical is never involved. Follow references/transport-flow.md.
sync unify
The full convergence flow: transport, then merge drift into the canonical, regenerate every copy, and push once. Follow references/unify-flow.md.
edit
A freeform request to change the global instructions: add a rule, reword one, remove one. The request text is never pasted verbatim; you interpret it and draft the change into the canonical yourself. With no request text, ask what the user wants changed; their answer is the request.
Run the unify flow (references/unify-flow.md) with one addition to its draft step: besides classifying any drift, fold the requested change into the proposed core and overlays.
- Route it by the same classification rules: content that helps every harness goes to the core; harness-specific content goes to that harness's overlay. A request naming a harness ("for Claude only") pins the overlay.
- Place it in the section where it belongs, matching the canonical's tone, formatting, and heading conventions. Merge it into an existing rule rather than adding a near-duplicate.
- Removals and rewordings edit the existing content in place.
- Ask only when the request is genuinely ambiguous, such as an unclear target or a contradiction with an existing rule; otherwise decide, and let the gate diffs speak.
Everything else is the unify flow unchanged: pre-existing drift is folded in alongside the request, and one stage, one gate, one apply, one push carry both.
Cursor
Cursor has no global instructions file, so it receives no generated copy; that is a documented limitation, not a bug. If the user works with Cursor, offer the one-time pointer rule: see references/cursor-pointer.md.