All workflow, command, reference, template, and tool-output files that surfaced /gsd:<cmd> as a user-typed slash command have been updated to use /gsd-<cmd>, matching the Claude Code skill directory name. Closes #2697 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
5.9 KiB
sync-skills — Cross-Runtime GSD Skill Sync
Command: /gsd-sync-skills
Sync managed gsd-* skill directories from one canonical runtime's skills root to one or more destination runtime skills roots. Keeps multi-runtime installs aligned after a gsd-update on one runtime.
Arguments
| Flag | Required | Default | Description |
|---|---|---|---|
--from <runtime> |
Yes | (none) | Source runtime — the canonical runtime to copy from |
--to <runtime|all> |
Yes | (none) | Destination runtime or all supported runtimes |
--dry-run |
No | on by default | Preview changes without writing anything |
--apply |
No | off | Execute the diff (overrides dry-run) |
If neither --dry-run nor --apply is specified, dry-run is the default.
Supported runtime names: claude, codex, copilot, cursor, windsurf, opencode, gemini, kilo, augment, trae, qwen, codebuddy, cline, antigravity
Step 1: Parse Arguments
FROM_RUNTIME=""
TO_RUNTIMES=()
IS_APPLY=false
# Parse --from
if [[ "$@" == *"--from"* ]]; then
FROM_RUNTIME=$(echo "$@" | grep -oP '(?<=--from )\S+')
fi
# Parse --to
if [[ "$@" == *"--to all"* ]]; then
TO_RUNTIMES=(claude codex copilot cursor windsurf opencode gemini kilo augment trae qwen codebuddy cline antigravity)
elif [[ "$@" == *"--to"* ]]; then
TO_RUNTIMES=( $(echo "$@" | grep -oP '(?<=--to )\S+') )
fi
# Parse --apply
if [[ "$@" == *"--apply"* ]]; then
IS_APPLY=true
fi
Validation:
- If
--fromis missing or unrecognized: print error and exit - If
--tois missing or unrecognized: print error and exit - If
--from==--to(single destination): print[no-op: source and destination are the same runtime]and exit
Step 2: Resolve Skills Roots
Use install.js --skills-root to resolve paths — this reuses the single authoritative path table rather than duplicating it:
INSTALL_JS="$(dirname "$0")/../get-shit-done/bin/install.js"
# If running from a global install, resolve relative to the GSD package
INSTALL_JS_GLOBAL="$HOME/.claude/get-shit-done/bin/install.js"
[[ ! -f "$INSTALL_JS" ]] && INSTALL_JS="$INSTALL_JS_GLOBAL"
SRC_SKILLS_ROOT=$(node "$INSTALL_JS" --skills-root "$FROM_RUNTIME")
for DEST_RUNTIME in "${TO_RUNTIMES[@]}"; do
DEST_SKILLS_ROOTS["$DEST_RUNTIME"]=$(node "$INSTALL_JS" --skills-root "$DEST_RUNTIME")
done
Guard: If the source skills root does not exist, print:
error: source skills root not found: <path>
Is GSD installed globally for the '<runtime>' runtime?
Run: node ~/.claude/get-shit-done/bin/install.js --global --<runtime>
Then exit.
Guard: If --to contains the same runtime as --from, skip that destination silently.
Step 3: Compute Diff Per Destination
For each destination runtime:
# List gsd-* subdirectories in source
SRC_SKILLS=$(ls -1 "$SRC_SKILLS_ROOT" 2>/dev/null | grep '^gsd-')
# List gsd-* subdirectories in destination (may not exist yet)
DST_SKILLS=$(ls -1 "$DEST_ROOT" 2>/dev/null | grep '^gsd-')
# Diff:
# CREATE — in SRC but not in DST
# UPDATE — in both; content differs (compare recursively via checksums)
# REMOVE — in DST but not in SRC (stale GSD skill no longer in source)
# SKIP — in both; content identical (already up to date)
Non-GSD preservation: Only gsd-* entries are ever created, updated, or removed. Entries in the destination that do not start with gsd- are never touched.
Step 4: Print Diff Report
Always print the report, regardless of --apply or --dry-run:
sync source: <runtime> (<src_skills_root>)
sync targets: <dest1>, <dest2>
== <dest1> (<dest1_skills_root>) ==
CREATE: gsd-help
UPDATE: gsd-update
REMOVE: gsd-old-command
SKIP: gsd-plan-phase (up to date)
(N changes)
== <dest2> (<dest2_skills_root>) ==
CREATE: gsd-help
(N changes)
dry-run only. use --apply to execute. ← omit this line if --apply
If a destination root does not exist and --apply is true, print CREATE DIR: <path> before its entries.
If all destinations are already up to date:
All destinations are up to date. No changes needed.
Step 5: Execute (only when --apply)
If --dry-run (or no flag): skip this step entirely and exit after printing the report.
For each destination with changes:
mkdir -p "$DEST_ROOT"
for SKILL in $CREATE_LIST $UPDATE_LIST; do
rm -rf "$DEST_ROOT/$SKILL"
cp -r "$SRC_SKILLS_ROOT/$SKILL" "$DEST_ROOT/$SKILL"
done
for SKILL in $REMOVE_LIST; do
rm -rf "$DEST_ROOT/$SKILL"
done
Idempotency: Running --apply a second time with no intervening changes must report zero changes (all entries are SKIP).
Atomicity: Each skill directory is replaced as a unit (remove then copy). Partial updates of individual files within a skill are not performed — the whole directory is replaced.
After executing all destinations:
Sync complete: <N> skills synced to <M> runtime(s).
Safety Rules
- Only
gsd-*directories are created, updated, or removed. Any directory not starting withgsd-in a destination root is untouched. - Dry-run is the default.
--applymust be passed explicitly to write anything. - Source root must exist. Never create the source root; it must have been created by a prior
gsd-updateor installer run. - No cross-runtime content transformation. Sync copies files verbatim. It does not apply runtime-specific content transformations (those happen at install time). If a runtime requires transformed content (e.g. Augment's format differs), the developer should run the installer for that runtime instead of using sync.
Limitations
- Sync copies files verbatim and does not apply runtime-specific content transformations. Use the GSD installer directly for runtimes that require format conversion.
- Cross-project skills (
.agents/skills/) are out of scope — this command only touches global runtime skills roots. - Bidirectional sync is not supported. Choose one canonical source with
--from.