
Sync Repos
- 53 installs
- 93 repo stars
- Updated May 14, 2026
- thatrebeccarae/claude-marketing
Helps with ai & agent building tasks.
About
sync-repos is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- sync-repos
- AI & Agent Building
- AI-coding skill
Sync Repos by the numbers
- 53 all-time installs (skills.sh)
- +3 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #6,979 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thatrebeccarae/claude-marketing --skill sync-reposAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 53 |
|---|---|
| repo stars | ★ 93 |
| Last updated | May 14, 2026 |
| Repository | thatrebeccarae/claude-marketing ↗ |
What it does
Helps with ai & agent building tasks.
Files
Sync Repos
Manage public/private repository pairs. Verify parity between a dev (private) repo and its public counterpart, detect drift, run sync scripts, validate results, and ensure no PII or secrets leak to the public side.
Install
claude install-skill https://github.com/thatrebeccarae/claude-skills/tree/main/sync-reposWhen to Use
- Before pushing a public repo — verify the sync is clean and current
- After major dev work — check whether the public repo has drifted behind
- On a periodic cadence — weekly or before releases, catch unsynced changes early
- When setting up a new public/private repo pair for the first time
Usage
/sync-repos check [dev-path] [public-path]— Compare repos and report drift/sync-repos sync [dev-path] [public-path]— Run sync script and validate/sync-repos setup [dev-path] [public-path]— Create initial sync-public.sh and config
If paths are omitted, prompt the user for them. Look for .syncignore or scripts/sync-public.conf in the dev repo to auto-detect the pair.
Procedure
Check Mode
1. Validate paths. Confirm both paths exist and contain .git/ directories. Abort with a clear message if either is not a git repo.
2. Detect sync script. Look for scripts/sync-public.sh, scripts/sync-public.conf, or .syncignore in the dev repo. Report whether a sync mechanism exists.
3. Compare file lists. Generate sorted file lists for both repos (excluding .git/, node_modules/, dist/). Categorize differences:
- Expected exclusions — files matching known exclusion patterns (see Common Exclusion Patterns below) or listed in
.syncignore/sync-public.conf - Unexpected drift — files present in dev but missing from public that are NOT in any exclusion list
- Diverged files — files present in both repos but with different content (compare via
sha256sumorgit hash-object) - Public-only files — files in public but not in dev (legitimate: README, CONTRIBUTING, LICENSE, .github/)
4. Check last sync timestamp. If scripts/sync-public.sh exists, check its last execution time via the most recent commit in the public repo that matches a sync pattern. Compare against the latest commit in the dev repo.
5. Report. Present a summary table:
- Sync script: found / not found
- Files only in dev (expected): count
- Files only in dev (unexpected): count + list
- Diverged files: count + list
- Public-only files: count + list
- Estimated drift: number of dev commits since last sync
- Recommendation: "in sync", "minor drift", or "sync needed"
Sync Mode
1. Run check first. Execute the full check procedure above. If no drift is detected, report "already in sync" and stop.
2. Locate sync script. Look for scripts/sync-public.sh in the dev repo. If not found, ask the user whether to run setup mode to create one.
3. Preview the sync. Show what the sync script will do — files to copy, exclusions, text replacements. Require user confirmation before proceeding.
4. Execute the sync script. Run from the dev repo root:
bash scripts/sync-public.shCapture stdout and stderr. If the script exits non-zero, report the error and stop.
5. Post-sync validation. After the script completes:
- Run the check procedure again to confirm parity
- Scan the public repo diff for PII and secrets (see REFERENCE.md for scan patterns)
- Flag any findings and block until resolved
6. Report results. Summarize:
- Files synced: count
- Exclusions applied: count
- PII/secrets scan: clean or findings
- Next step: "Review changes in public repo, then
/safe-pushwhen ready"
Setup Mode
1. Scan the dev repo. Identify files and directories that should NOT sync to public:
- Environment files:
.env,.env.*(except.env.example) - Planning/internal:
.planning/,.claude/,CLAUDE_CONTEXT.md,briefs/ - Data/build artifacts:
data/,dist/,node_modules/,.git/ - Sync infrastructure:
scripts/sync-public.sh,scripts/sync-public.conf - Sensitive config:
*.pem,*.key,*.plist,config/soul.md - Project-specific patterns detected via
.gitignoreanalysis
2. Generate sync-public.conf. Create a config file with:
SOURCE_DIRandTARGET_DIRvariablesPACKAGE_NAMEfor the public repoEXCLUDE_PATHSarray with all identified exclusionsPRESERVE_PATHSarray for public-only files (README, LICENSE, .github/)
3. Generate sync-public.sh. Create the sync script using the rsync-based template from REFERENCE.md. Include:
- Config file sourcing
- Path validation
- Target cleanup (preserve
.git/andPRESERVE_PATHS) - rsync with
--delete-excludedand exclusion list - Personal data leak check
- File count summary
4. User review. Display the generated config and script. Wait for explicit approval before writing.
5. Write files. Save scripts/sync-public.sh (chmod +x) and scripts/sync-public.conf to the dev repo.
Common Exclusion Patterns
These patterns are excluded from sync by default. Append project-specific patterns as needed.
| Pattern | Reason |
|---|---|
.git/ | Git history stays separate |
.env, .env.* | Secrets and environment config |
.planning/ | Internal planning docs |
.claude/ | Claude Code project config |
CLAUDE_CONTEXT.md | Internal agent context |
data/ | Local data / databases |
dist/, node_modules/ | Build artifacts |
*.pem, *.key | Private key material |
*.plist | macOS service config |
scripts/sync-public.* | Sync infrastructure itself |
briefs/ | Internal content briefs |
config/soul.md | Personal agent config |
Key Principles
- Never auto-push. Sync writes files locally. Pushing to remote is always a separate, user-confirmed step via
/safe-push. - Always validate after sync. Every sync run ends with a PII/secrets scan on the public repo. No exceptions.
- Exclusion list is append-only. Never remove exclusion patterns without explicit user approval. It is safer to exclude too much than too little.
- Preserve public-only files. The public repo may have its own README, LICENSE, CONTRIBUTING, .github/ workflows. Sync must never overwrite these.
- Conf is separate from script. Keep
sync-public.confseparate so exclusion lists are easy to review and update without touching script logic.
Sync Repos Examples
Example 1: Check Drift Between Dev and Public Repos
User Request: "Check if my-app-dev and my-app are in sync"
Invocation: /sync-repos check ~/projects/my-app-dev ~/projects/my-app
Steps Taken: 1. Validate both paths are git repos 2. Locate scripts/sync-public.sh and scripts/sync-public.conf in dev repo 3. Parse exclusion list from sync-public.conf 4. Generate file manifests for both repos, filtering exclusions 5. Compare file hashes for files present in both
Sample Output:
Sync Repos — Check Report
==========================
Dev repo: ~/projects/my-app-dev (142 files)
Public repo: ~/projects/my-app (98 files)
Sync script: scripts/sync-public.sh (found)
Files only in dev (expected exclusions): 38
.env, .planning/*, config/soul.md, data/*, briefs/*, ...
Files only in dev (UNEXPECTED): 3
src/config/new-feature.ts
src/plugins/experimental.ts
tests/integration/new-feature.test.ts
Diverged files: 1
src/agent/prompt.ts (dev: a3f8c2b, public: 91e4d0a)
Public-only files: 4
README.md, LICENSE, CONTRIBUTING.md, .github/workflows/ci.yml
Dev commits since last sync: 7
Recommendation: SYNC NEEDED — 3 unexpected files missing from public, 1 file divergedNext Step: User runs /sync-repos sync to bring public up to date.
Example 2: Full Sync Workflow
User Request: "Sync my-app dev repo to public"
Invocation: /sync-repos sync ~/projects/my-app-dev ~/projects/my-app
Steps Taken: 1. Run check (as in Example 1). Drift detected: 5 files diverged, 2 new files missing. 2. Locate scripts/sync-public.sh in dev repo. 3. Preview sync: "Will rsync 67 files, excluding 22 patterns. Text replacements: none configured." 4. User confirms. 5. Execute bash scripts/sync-public.sh. Script completes with exit code 0. 6. Run post-sync check — all files now match. 7. PII/secrets scan on public repo diff: scan all changed files for email addresses, API keys, private IPs, hostnames.
Sample Output:
Sync Repos — Sync Report
==========================
Sync script: scripts/sync-public.sh
Exit code: 0
Files synced: 69
Exclusions applied: 22 patterns
New files in public: 2
Updated files in public: 5
PII/Secrets Scan: CLEAN
Scanned 7 changed files
No email addresses, API keys, private IPs, or secrets detected
Post-sync check: IN SYNC
All non-excluded files match between dev and public
Next step: Review changes in the public repo, then /safe-push when ready.Example 3: Set Up Sync for a New Repo Pair
User Request: "Set up sync between my-dashboard-dev (dev) and my-dashboard (public)"
Invocation: /sync-repos setup ~/projects/my-dashboard-dev ~/projects/my-dashboard
Steps Taken: 1. Confirm both paths exist and are git repos. 2. Scan dev repo for files that should not sync:
- Found
.env(secrets) - Found
data/directory (SQLite databases) - Found
.claude/directory (project config) - Found
.planning/directory (internal docs) - Found
*.plistfiles (macOS service config) - Parsed
.gitignorefor additional patterns
3. Generate sync-public.conf with detected exclusions. 4. Generate sync-public.sh from template. 5. Present both files for review.
Sample Output:
Sync Repos — Setup
====================
Dev repo: ~/projects/my-dashboard-dev
Public repo: ~/projects/my-dashboard
Detected exclusion patterns:
.env, .env.* (secrets)
data/ (SQLite databases)
.claude/ (project config)
.planning/ (internal docs)
*.plist (macOS service config)
dist/ (build output)
node_modules/ (dependencies)
scripts/sync-public.* (sync infrastructure)
CLAUDE_CONTEXT.md (agent context)
Generated files:
scripts/sync-public.conf (exclusion config)
scripts/sync-public.sh (sync script)
Review the generated files above. Approve to write them to the dev repo.User approves. Files written:
[sync-repos] Wrote scripts/sync-public.conf (18 exclusion patterns)
[sync-repos] Wrote scripts/sync-public.sh (chmod +x)
[sync-repos] Setup complete. Run /sync-repos sync to perform the first sync.Follow-up: User runs /sync-repos sync to perform the initial sync, then /safe-push to push the public repo.
MIT License
Copyright (c) 2026 Rebecca Rae Barton
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Sync Repos Reference
sync-public.sh Template
Rsync-based sync script. Source sync-public.conf for configuration.
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=sync-public.conf
source "${SCRIPT_DIR}/sync-public.conf"
# -- Helpers -----------------------------------------------------------
log() { echo "[sync] $*"; }
warn() { echo "[sync] WARNING: $*" >&2; }
die() { echo "[sync] ERROR: $*" >&2; exit 1; }
# -- Validate ----------------------------------------------------------
[[ -d "${SOURCE_DIR}/.git" ]] || die "SOURCE_DIR is not a git repo: ${SOURCE_DIR}"
[[ -d "${TARGET_DIR}/.git" ]] || die "TARGET_DIR is not a git repo: ${TARGET_DIR}"
log "Source: ${SOURCE_DIR}"
log "Target: ${TARGET_DIR}"
# -- Prepare target ----------------------------------------------------
mkdir -p "${TARGET_DIR}"
# -- Clean stale untracked files ---------------------------------------
if [[ -d "${TARGET_DIR}/.git" ]]; then
log "Cleaning stale untracked files from target..."
(cd "${TARGET_DIR}" && git clean -fd --exclude=node_modules) || warn "git clean failed"
fi
# -- Build rsync exclude list ------------------------------------------
RSYNC_EXCLUDES=()
for p in "${EXCLUDE_PATHS[@]+"${EXCLUDE_PATHS[@]}"}"; do
RSYNC_EXCLUDES+=(--exclude "$p")
done
# -- Copy files --------------------------------------------------------
log "Copying files..."
rsync -a --delete-excluded \
"${RSYNC_EXCLUDES[@]+"${RSYNC_EXCLUDES[@]}"}" \
"${SOURCE_DIR}/" "${TARGET_DIR}/"
# -- Verify: check for personal data leaks -----------------------------
log "Checking for personal data leaks..."
LEAKS=0
# Add project-specific patterns to this array
LEAK_PATTERNS=()
for pattern in "${LEAK_PATTERNS[@]+"${LEAK_PATTERNS[@]}"}"; do
MATCHES=$(grep -rE "$pattern" "${TARGET_DIR}" \
--include='*.ts' --include='*.js' --include='*.json' \
--include='*.md' --include='*.sh' --include='*.yaml' \
--include='*.yml' --include='*.toml' --include='*.py' \
2>/dev/null || true)
if [[ -n "$MATCHES" ]]; then
echo " LEAK: '$pattern' found:"
echo "$MATCHES" | head -5
LEAKS=$((LEAKS + 1))
fi
done
if [[ "$LEAKS" -gt 0 ]]; then
die "$LEAKS personal data pattern(s) found in public repo — aborting"
fi
log "Clean — no personal data leaks detected"
# -- Summary -----------------------------------------------------------
FILE_COUNT=$(find "${TARGET_DIR}" -type f ! -path '*/.git/*' ! -path '*/node_modules/*' | wc -l | tr -d ' ')
log "Done. ${FILE_COUNT} files synced to ${TARGET_DIR}"sync-public.conf Template
# sync-public.conf — Configuration for sync-public.sh
# Source this file; do not execute directly.
SOURCE_DIR="${SOURCE_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
TARGET_DIR="${TARGET_DIR:-$(dirname "$SOURCE_DIR")/PUBLIC_REPO_NAME}"
PACKAGE_NAME="${PACKAGE_NAME:-my-project}"
# Files/directories to EXCLUDE from sync (relative to SOURCE_DIR)
EXCLUDE_PATHS=(
".git/"
".env"
".env.*"
"!.env.example"
".planning/"
".claude/"
"CLAUDE_CONTEXT.md"
"data/"
"dist/"
"node_modules/"
"*.pem"
"*.key"
"*.plist"
"briefs/"
"scripts/sync-public.sh"
"scripts/sync-public.conf"
)
# Directories in TARGET_DIR to preserve (not deleted during clean step)
PRESERVE_PATHS=(
".git"
"node_modules"
"README.md"
"LICENSE"
"CONTRIBUTING.md"
"SECURITY.md"
"CHANGELOG.md"
".github"
)Common Exclusion Patterns by Project Type
Node.js / TypeScript
node_modules/ dist/ .env .env.* *.pem *.key data/
.planning/ .claude/ CLAUDE_CONTEXT.md briefs/
scripts/sync-public.* config/soul.md *.plistPython
__pycache__/ *.pyc .venv/ venv/ .env .env.*
*.pem *.key data/ .planning/ .claude/
CLAUDE_CONTEXT.md scripts/sync-public.*Rust
target/ .env .env.* *.pem *.key data/
.planning/ .claude/ CLAUDE_CONTEXT.md
scripts/sync-public.*General (all projects)
.git/ .DS_Store *.log .syncthing.*.tmpGit-Based Sync Alternative
For projects where rsync is too coarse, use git format-patch / git am to replay commits selectively.
# In the dev repo: export patches since last sync tag
git format-patch last-sync-tag..HEAD --output-directory /tmp/patches/
# In the public repo: apply patches
git am /tmp/patches/*.patch
# Tag the sync point in dev
git tag -a "sync-$(date +%Y%m%d)" -m "Synced to public"Limitations: requires commit-level discipline (no commits that mix public and private content). Best for projects with clean commit hygiene. The rsync approach is more forgiving.
Drift Detection Methods
File hash comparison
# Generate sorted hash manifests for both repos
(cd "$DEV_REPO" && find . -type f ! -path './.git/*' ! -path './node_modules/*' \
-exec sha256sum {} \; | sort) > /tmp/dev-manifest.txt
(cd "$PUBLIC_REPO" && find . -type f ! -path './.git/*' ! -path './node_modules/*' \
-exec sha256sum {} \; | sort) > /tmp/public-manifest.txt
# Compare (filtering expected exclusions)
diff /tmp/dev-manifest.txt /tmp/public-manifest.txtGit log comparison
# Last commit timestamps
DEV_LAST=$(cd "$DEV_REPO" && git log -1 --format='%aI')
PUB_LAST=$(cd "$PUBLIC_REPO" && git log -1 --format='%aI')
# Commits in dev since public's last update
cd "$DEV_REPO" && git log --oneline --since="$PUB_LAST"PII Scan Patterns
Reused from the safe-push skill. Scan all text files in the public repo diff for:
| Category | Pattern Examples |
|---|---|
| Email addresses | [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} |
| Phone numbers | \b\d{3}[-.]?\d{3}[-.]?\d{4}\b |
| API keys/tokens | (sk-[a-zA-Z0-9]{20,}), (xoxb-[a-zA-Z0-9-]+), (ghp_[a-zA-Z0-9]{36}) |
| AWS keys | AKIA[0-9A-Z]{16} |
| Private IPs | `\b(10\.\ |
| Private keys | `-----BEGIN (RSA\ |
| Generic secrets | `(password\ |
Allowlist: if the public repo contains a .pii-allowlist file (one regex per line), matches are excluded from the scan.
.syncignore File Format
Optional file at the dev repo root. Same syntax as .gitignore. Defines additional files to exclude from sync beyond the defaults in sync-public.conf.
# .syncignore — additional exclusions for public sync
# One pattern per line. Supports glob patterns.
# Internal docs
docs/internal/
ROADMAP-INTERNAL.md
# Test fixtures with real data
tests/fixtures/real-data/
# Draft content
*.draft.mdWhen both .syncignore and sync-public.conf exist, merge the exclusion lists (union). .syncignore is additive — it never removes exclusions from sync-public.conf.