On this page
ConfigManager class for claudewheel.
#claudewheel.config
#claudewheel.config
Config loading, saving, and schema migration system.
#_migration_1_github_optional
def _migration_1_github_optional(config: dict, segments_def: list[dict], theme: dict, options_def: dict) -> NoneMake github segment optional (was incorrectly required).
#_migration_2_profile_paths
def _migration_2_profile_paths(config: dict, segments_def: list[dict], theme: dict, options_def: dict) -> NoneRewrite profile metadata config_dir from ~/.claude-
#_migration_3_classify_pinned
def _migration_3_classify_pinned(config: dict, segments_def: list[dict], theme: dict, options_def: dict) -> NoneClassify existing 'values' into 'pinned' vs discard.
Discovery-backed segments: values with metadata -> pinned (wizard-created), values without metadata -> discard (from discovery, will be re-discovered).
Static segments (no discovery): values in HISTORICAL_DEFAULTS that are still in DEFAULT_OPTIONS -> discard (they come from defaults now). Values in HISTORICAL_DEFAULTS but NOT in current defaults -> pinned (conservative). Values not in any defaults -> pinned (user-added).
#ConfigManager
Manages the four JSON config files (config, segments, options, state) and runs migrations on init.
#_resolve_theme_name
def _resolve_theme_name(theme_name: str) -> strResolve 'auto' theme to 'light' or 'dark' via terminal detection.
Explicit 'light' or 'dark' are returned as-is. 'auto' queries the terminal background color; detection failure falls back to 'dark'.
#_recover_incomplete_renames
def _recover_incomplete_renames() -> NoneFinish any interrupted profile renames (crash recovery).
#_warn_old_profile_dirs
def _warn_old_profile_dirs() -> NonePrint a warning if old-style ~/.claude-
#_ensure_shared_settings
def _ensure_shared_settings(self) -> NoneCreate shared-settings.json from canonical values if it doesn't exist.
#_ensure_dir
def _ensure_dir(self)Create config directories and write default files on first run.
#_migrate
def _migrate(self, theme_file: Path, theme_default: dict) -> NoneAdd missing default keys to existing config files on startup.
Only adds keys that are absent — never overwrites existing user values. Saves each file only when something actually changed, so running twice is a no-op (idempotent).
#_run_versioned_migrations
def _run_versioned_migrations(self, theme_file: Path) -> NoneRun schema-versioned migrations that change existing values.
Complements _migrate() which only adds missing keys. Versioned migrations can mutate values and run exactly once per version bump.
#_deep_merge_missing
def _deep_merge_missing(target: dict, defaults: dict) -> boolRecursively add keys from defaults that are absent in target.
Returns True if any key was added (i.e. the target was mutated).
#add_option
def add_option(self, segment_key: str, value: str) -> NoneAdd a new option value to the pinned list in options.json for the given segment.
#set_option_metadata
def set_option_metadata(self, segment_key: str, value: str, meta: dict) -> NoneSet metadata for a specific option value in options.json.
#save_state
def save_state(self)Save in-memory state to disk.
Merges out-of-band keys (auth_browser) from disk before writing to prevent clobber by stale in-memory state. The auth wizard writes auth_browser directly to disk while the TUI holds its own in-memory state loaded at startup; this merge ensures that value survives.