v0.2.2 - Checkout Inside Another Repo Is Now Refused (guard was bypassed at the CLI layer)
Latestdazzle-claude-config v0.2.2
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.
A safety guard that existed, was tested, and was quietly bypassed before it ever reached you.
What's fixed in v0.2.2
A checkout inside another git repository is now refused (behavior change)
If your payload checkout was a plain folder living inside some other git repository -- a monorepo, a scratch tree, anything with a .git above it -- ccs proceeded as though it were an ordinary non-git folder. That was never safe: it meant binding to the outer repository, and it silently switched off two guarantees:
- the verification that files collected into your payload actually reach git's index, so a stray ignore rule cannot quietly drop config from the repo
- the refusal to
applywhile the checkout has unresolved merge conflicts
Neither omission was reported. You would see a normal, successful run.
ccs now stops:
ccs: not a git repository root: /path/to/checkout (inside repo /path/to/outer)
-- ccs will not bind to a parent repository; move the checkout outside it, or `git init` it
If this affects you, either move the checkout outside the enclosing repository, or run git init inside it so it becomes its own repository. The error names both.
If it does not, nothing changes: a checkout that is already its own git repository, and a plain folder that is not inside any repository, both behave exactly as before.
The refusal had been written, tested, and documented since v0.1.0 -- the test asserted "must be refused" and passed the whole time, because it exercised the internal guard directly while the command-line layer downgraded the same condition to "this is just a plain folder." A guard is only as good as the layer that surfaces it. Found by a post-release checklist run against the published PyPI artifact; the report ships in tests/checklists/results/.
Plainer language in user-facing docs
The changelog had been describing fixes with internal shorthand -- acceptance-check IDs like A4 and A8 that map to project-private design documents no reader outside the project can open. Those entries now name each guarantee by what it does. The public test checklists, which ship for external testers, gained legend tables defining every code they use, so they stand on their own.
Everything from v0.2.1 still applies
v0.2.1 was the first public release. If you are arriving now, that is the feature set:
- Any repo can be a payload. With a
ccs-manifest.json, that file declares exactly what syncs where. Without one, ccs recognizes a repo that simply looks like a~/.claudedirectory and synthesizes the manifest -- so a config folder pushed to GitHub as-is already works. - Secrets are structurally fenced, in both directions. A hard deny-list (
.credentials.json,.claude.json,settings.local.json, plugin state, databases) overrides the manifest, andcollectscans every file type for credential shapes.applyenforces the deny-list too, so a denied file committed into a payload is refused rather than installed. - Protected files are not drift. A file that can never sync is annotated and the run still reports clean; only credential-shaped content raises an alarm.
- Nothing is destroyed. Every overwrite is preceded by a timestamped backup under
~/claude/backups/ccs/; removals are staged, never deleted in place;applyrefuses over unresolved merge conflicts; and if your home directory is itself a git repository, ccs refuses to operate on it. - Output written for someone who has not read the docs, colorized on a TTY and plain when piped.
Try it against a public collection 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-configapply merges into your live config rather than replacing it, and treats CLAUDE.md as seed-if-absent -- your own memory file is never clobbered.
Installation
pip install --upgrade dazzle-claude-configInstalls ccs (alias: dazzle-claude-config). Set CCS_CHECKOUT_DIR to your payload checkout and --checkout-dir becomes optional. ccs --help carries a getting-started section.
Version History (0.2.x)
| Version | Key Change |
|---|---|
| v0.2.2 | Current -- checkout-inside-another-repo now refused instead of silently bypassing two guards |
| v0.2.1 | First PyPI release: deny-aware apply, readable colorized output, CCS_CHECKOUT_DIR |
| v0.2.0 | Layout-agnostic payloads: any bare ~/.claude mirror works without a manifest (tag only) |
| v0.1.0 | 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; verified end-to-end on a second machine |
| 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: 75 automated tests across 9 CI jobs; two adversarial tester-agent runs plus a post-release checklist run against the published artifact, all reported in tests/checklists/.