Skip to content

Releases: DazzleML/dazzle-claude-config

v0.2.2 - Checkout Inside Another Repo Is Now Refused (guard was bypassed at the CLI layer)

Choose a tag to compare

@djdarcy djdarcy released this 25 Jul 14:22
v0.2.2
1e4ff17

dazzle-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 apply while 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 ~/.claude directory 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, and collect scans every file type for credential shapes. apply enforces 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; apply refuses 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-config

apply 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-config

Installs 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/.

v0.2.1 - First Public Release: Git-Backed Claude Code Config Sync

Choose a tag to compare

@djdarcy djdarcy released this 25 Jul 04:43
v0.2.1
3b3f3e6

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. ccs has 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 slice

apply 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-config

Installs 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/.