project-sync — Repo-local cross-CLI fan-out
Thin wrapper around dotbabel project-sync. The binary owns all writes; this
skill maps natural-language requests to the right invocation and surfaces
dry-run output before mutating the repo.
When to invoke
- The user wants to adopt cross-CLI workflows in a repo that already has
.claude/commands/*or.claude/skills/*, but noAGENTS.md/GEMINI.md/.github/prompts//.github/instructions/wiring. - A new command or skill was just added to
.claude/, and the user wants Codex/Gemini/Copilot to see it without leaving the editor. - The user asks for "drift check" or "is this repo synced" — run
dotbabel check-project-syncinstead and surface the diff. - First-time setup: if
.dotbabel.jsonis missing, suggestdotbabel project-initfirst.
Workflow
- Pre-flight. Confirm cwd is a git repo and contains
CLAUDE.md(with or without rule-floor markers) plus at least one of.claude/commands/or.claude/skills/. If.dotbabel.jsonis absent, mention that defaults will apply (nocli_substitutions, full fan-out to codex/gemini/copilot, gating on each CLI'scommand -vcheck). - Dry-run first. Always run
dotbabel project-sync --dry-runbefore mutating. Summarize the planned actions to the user (count of instruction files, count of new symlinks per CLI). Pause for confirmation unless the user already said "do it" or "go ahead" in the same turn. - Apply. Run
dotbabel project-sync(no--dry-run). If the user passed--all, propagate it. - Verify. Run
dotbabel check-project-syncand reportok/missing/stalecounts. Exit non-zero output should be surfaced. The check applies the samegate_on_cli_presencegate as the sync, so a CLI absent fromPATHis reported asskipped <cli>: not on PATHrather than as drift. Propagate--allhere too when the user passed it in step 3, so both commands cover the same CLIs.
Triggers and invocations
| Trigger phrase | Invocation |
|---|---|
| "sync this repo", "project sync", "fan out commands" | dotbabel project-sync --dry-run then apply |
| "wire up gemini for this project" | dotbabel project-sync --all (covers all) |
| "is this repo synced", "drift check the project sync" | dotbabel check-project-sync (read-only) |
| "regenerate AGENTS.md for this project" | dotbabel project-sync (instructions are part of the run) |
| "set up project sync here", "first-time project sync" | dotbabel project-init then project-sync |
Reference: Copilot mapping
The Copilot CLI fan-out targets .github/prompts/*.prompt.md (commands) and
.github/instructions/*.instructions.md (skills) inside the target repo.
See references/copilot-mapping.md for the
full layout and rationale.
Boundaries
- Always operate on the user's current working directory unless they pass an
explicit
--repo <path>. Never silently target a different repo. - Never run
--force. The plan reserves it for collision overrides; defer to the binary's existing collision warnings. - For consumer repos with no
.dotbabel.json, the convention path applies (entireCLAUDE.mdbecomes the rule floor when markers are absent). fan_outaccepts onlycodex,gemini, andcopilot. A typo aborts the run withCONFIG_UNKNOWN_CLI; fix the name rather than dropping the gate.fan_out_layoutisper-cliby default. Undershared, Codex and Gemini both point at one.cli/skills/tree, so describe changes by the canonical path instead of naming each CLI directory twice. Switching an existing repo leaves.codex/skills.bak-<timestamp>behind — say so, so the user can delete it. An unknown value aborts withCONFIG_UNKNOWN_LAYOUT.cli_excludedmaps a CLI to command basenames and skill ids it must not receive. Suggest it when a command describes a Claude-only flow. The sync removes an excluded link it wrote earlier and reportsremoved: <path>; mention that so the user expects the deletion in the diff. Undershared, an exclusion forcodexorgeminiapplies to both and the sync warns when the lists differ. A malformed value aborts withCONFIG_INVALID_EXCLUSION.- This skill is for project-scope sync. For user-scope (
~/.claude/,~/.codex/,~/.gemini/) bootstrap, usedotbabel bootstrapinstead.