Skip to content

feat: add config/local/ overlay for persistent custom configurations#101

Open
bookandlover wants to merge 1 commit intobfly123:mainfrom
bookandlover:feat/custom-config-persistence
Open

feat: add config/local/ overlay for persistent custom configurations#101
bookandlover wants to merge 1 commit intobfly123:mainfrom
bookandlover:feat/custom-config-persistence

Conversation

@bookandlover
Copy link

Problem

ccb update downloads the latest release and replaces the entire install directory, including config templates (config/claude-md-ccb.md,
config/agents-md-ccb.md, config/clinerules-ccb.md). Users who customize role assignments or review rules lose their changes on every update.

Solution

Introduce a config/local/ directory that acts as a persistent overlay layer:

  1. Preservation: copy_project() saves and restores config/local/ during directory replacement
  2. Template resolution: New resolve_config_template() helper checks for local override before falling back to upstream default
  3. CLI management: New ccb config subcommand (init/edit/show/reset)
  4. Documentation: docs/custom-config.md

Usage

ccb config init # Copy templates to config/local/
ccb config edit claude-md-ccb.md # Edit role assignments
ccb reinstall # Apply changes
ccb config show # Check active overrides
ccb config reset # Revert to upstream

Files changed

┌───────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ File │ Change │
├───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ install.sh │ Preserve/restore config/local/; add resolve_config_template(); update 3 config install functions │
├───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ccb │ Add cmd_config() with init/edit/show/reset │
├───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ config/local/.gitkeep │ Placeholder directory │
├───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ docs/custom-config.md │ Usage documentation │
├───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ .gitignore │ Ignore user files, track .gitkeep │
└───────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────┘

Design decisions

  • Full-file override keeps implementation simple and predictable
  • config/local/ inside install dir aligns with existing project layout
  • Backward compatible: No changes when config/local/ is empty

Test plan

  • ccb config init creates local overrides from upstream templates
  • ccb config show correctly identifies active overrides
  • ccb reinstall uses local overrides when present
  • ccb update preserves config/local/ directory
  • ccb config reset removes overrides and reverts to defaults
  • No behavioral change when config/local/ is empty

Problem: `ccb update` downloads the latest release and overwrites all config
templates (role table, review framework, collaboration rules). Users who
customize these settings lose their changes on every update.

Solution: Introduce a `config/local/` directory that acts as a persistent
overlay layer. Files placed here take priority over upstream defaults and
survive updates.

Changes:
- install.sh: copy_project() saves and restores config/local/ during updates
- install.sh: add resolve_config_template() helper; config install functions
  check for local override before falling back to upstream default
- ccb: add `ccb config` subcommand (init/edit/show/reset) for managing
  local overrides
- docs/custom-config.md: usage documentation and examples
- .gitignore: ignore user override files but track .gitkeep

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bookandlover
Copy link
Author

CI Failure Analysis

The CI failure is not caused by this PR. The single failing test test_per_session_worker_pool_reuses_same_key also fails on the upstream
main branch (verified locally).

Root cause: _NoopThread in the test fixture passes a list as _started, but Python 3.13's threading.Thread.is_alive() expects _started to be
a threading.Event with an is_set() method.

lib/worker_pool.py:66: in get_or_create
if worker is not None and not worker.is_alive():
threading.py:1143: in is_alive
return self._started.is_set() and not self._handle.is_done()
E AttributeError: 'list' object has no attribute 'is_set'

Local verification:

  • main branch: 2 passed, 1 failed (same test)
  • This PR branch: 107 passed, 1 failed (same test)

This is a pre-existing issue unrelated to the config/local overlay changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant