On this page
Sync existing profiles and shared-settings.json toward canonical defaults.
#claudewheel.patch_profiles
#claudewheel.patch_profiles
Sync existing profiles and shared-settings.json toward canonical defaults.
Canonical defaults advance in defaults.py (new disallowedTools entries, new hook scripts), but per-profile settings.json files are only written at creation and shared-settings.json only when it is first created. This module backs the claudewheel patch-profiles command, which additively brings every discovered profile and shared-settings.json up to the current canonical hook wiring and disallowedTools list without disturbing anything else.
The sync is purely additive and idempotent: - Canonical hook entries (matched by their "matcher" field) are merged in, de-duplicated by script basename, preserving any user-added hooks. - claudewheel.disallowedTools (top-level for shared-settings) is made a superset of defaults.DISALLOWED_TOOLS; user-added extras are kept. - The inert top-level disallowedTools key that Claude Code ignores is folded into the claudewheel namespace and removed. - Missing built-in hook scripts referenced by the canonical hooks are deployed via the shared deploy-hooks code path.
Permissions, credentials, tokens, and all unrelated keys are never touched.
#_script_basename
def _script_basename(command: str) -> strReturn the trailing script name of a hook command path (or "").
#merge_hooks
def merge_hooks(existing: dict, canonical: dict) -> list[str]Additively merge canonical hooks into existing (mutated in place).
Canonical entries are matched to existing ones by their "matcher" field. Individual hooks are de-duplicated by script basename, so a profile that already wires a script under a different absolute path is left untouched. Returns a list of human-readable descriptions of every hook added.
#_append_missing
def _append_missing(current: list, wanted: list) -> list[str]Append entries of wanted absent from current (mutated). Returns them.
#sync_profile_settings
def sync_profile_settings(settings: dict, canonical: dict) -> list[str]Additively sync one profile's settings dict toward canonical (mutated).
Returns descriptions of every change. Empty list means already in sync.
#sync_shared_settings
def sync_shared_settings(shared: dict, canonical: dict) -> list[str]Additively sync shared-settings.json dict toward canonical (mutated).
Returns descriptions of every change. Empty list means already in sync. In shared-settings.json, disallowedTools canonically lives at the top level (unlike profiles, where it is under the claudewheel namespace).
#_referenced_scripts
def _referenced_scripts(hooks: dict) -> list[str]Collect the ordered, unique script basenames referenced by hooks.
#run_patch_profiles
def run_patch_profiles(dry_run: bool=False) -> intSync every discovered profile and shared-settings.json toward canonical.
Deploys any missing built-in hook scripts, then additively patches shared-settings.json and each profile's settings.json. With dry_run, reports what would change and writes nothing.