v0.2.1 - First Public Release: Git-Backed Claude Code Config Sync
dazzle-claude-config v0.2.1
Git-backed sync for your Claude Code configuration -- skills, commands, agents, hooks, and CLAUDE.md -- across every machine you work on, with credential guards on the way in and backups on every write.
First public release.
ccshas been managing its maintainer's own config across machines since v0.1.0; this is the version that reaches PyPI.
The problem it solves
Your Claude Code setup is earned: skills refined over months, commands that encode how you actually work, a CLAUDE.md tuned by a hundred small corrections -- all sitting in ~/.claude on one machine. Copy that folder to a second box by hand and the two drift apart silently, because nothing tells you which is newer. Copy it wholesale into a git repo to "back it up" and you have published an API key, because ~/.claude also holds .credentials.json, OAuth state, plugin caches, and session databases.
ccs makes your configuration a git repository -- a payload -- and moves files between that repo's checkout and your live config:
pip install dazzle-claude-config
git clone <payload-repo> ~/claude/my-config
ccs status # three-way drift: live vs checkout vs remote
ccs diff # which files, exactly
ccs collect # live config INTO the checkout (credentials refused, never silently)
ccs apply # checkout config INTO the live tree (originals backed up first)Git does what git is good at -- history, review, and resolving the conflict when two machines edit the same skill. ccs contains no merge logic and exposes no branch operations.
What's in v0.2.1
Any repo can be a payload
If a repo carries a ccs-manifest.json, that file declares exactly what syncs where. If it does not, ccs recognizes a repo that simply looks like a ~/.claude directory -- root-level CLAUDE.md, skills/, commands/, agents/ -- and synthesizes the manifest. Anyone who pushed their config folder to GitHub as-is has a working payload already.
Try one without committing to it:
git clone https://github.com/DazzleML/dazzle-claude-code-config ~/claude/dazzle-config
ccs diff --checkout-dir ~/claude/dazzle-config # look first
ccs apply --only dotclaude/skills --checkout-dir ~/claude/dazzle-config # take a sliceapply merges into your live config rather than replacing it, backs up anything it overwrites, and treats CLAUDE.md as seed-if-absent -- your own memory file is never clobbered.
Secrets are structurally fenced, in both directions
A hard deny-list (.credentials.json, .claude.json, settings.local.json, plugin state, databases) overrides the manifest, and collect scans every file type for credential shapes (sk-ant-, GitHub/AWS/Slack tokens, PEM private-key headers). Refusals are always reported, never silent.
New in this release: apply enforces the deny-list too. Previously the guard stack protected only the live-to-checkout direction, so a denied file committed into a payload -- an accidental commit, a bad merge, or a naive raw ~/.claude push -- was copied into the live tree as an ordinary applied: line. It now refuses, names the rule, and exits 1.
Output written for someone who has not read the docs
ccs status reports all three legs of "in sync" and says what the verdict means:
checkout ~/claude/dazzle-claude-code-config
on main, in sync with origin/main
compared 83 files across 11 entries of config
~/.claude
~/claude
protected (1 file kept out of sync on purpose -- matches a deny rule, so ccs will not copy it in either direction)
bin/gpg-loopback.sh
status: clean -- your live config and the checkout match; nothing to collect, nothing to apply
Colorized on a TTY, plain when piped or under --no-color / NO_COLOR.
Nothing is destroyed
Every overwrite is preceded by a timestamped backup under ~/claude/backups/ccs/. Removals are staged there behind --sync-removals, never deleted in place. apply refuses to run while the checkout has unresolved merge conflicts. If your home directory is itself a git repository, ccs structurally refuses to operate on it.
Installation
pip install dazzle-claude-configInstalls ccs (alias: dazzle-claude-config). Set CCS_CHECKOUT_DIR to your payload checkout and the --checkout-dir flag becomes optional. ccs --help carries a getting-started section.
Version History (0.2.x)
| Version | Key Change |
|---|---|
| v0.2.1 | Current -- first PyPI release: deny-aware apply, readable colorized output, CCS_CHECKOUT_DIR, alpha designation |
| v0.2.0 | Layout-agnostic payloads: any bare ~/.claude mirror works without a manifest (tag only) |
| v0.1.0 | Phase 1 MVP: collect / apply / status / diff, guard stack, backups, staged removals (tag only) |
Platform Support
| Platform | Status |
|---|---|
| Windows 10/11 | Tested -- primary development, daily use against a real config |
| Linux | CI-tested -- full matrix, human checklist pending |
| macOS / BSD | Expected -- no platform-specific code; pathlib throughout, git shelled out |
CI runs Windows and Ubuntu across Python 3.10-3.13, plus a syntax check against the declared 3.10 floor.
Requirements
- Python 3.10+ (stdlib only -- git is the sole external dependency)
- Git
Alpha status
Working and in daily use; surfaces are not frozen. The Phase 2 set -- templated settings rendering, declarative plugin installs, and one-command ccs bootstrap onboarding -- is still landing, and command surfaces may change until it does. Please file issues for anything rough, and as with any sync tool, keep an independent copy of anything irreplaceable.
Validation: 74 automated tests across 8 CI legs; two adversarial tester-agent runs and human checklists in tests/checklists/.