Skip to content

Keep your own Claude Code hooks

Status: Shipped

Your repo may already commit a .claude/settings.json with hooks, such as a formatter after every edit or a guard before shell commands. This guide shows how to keep them working in CodeSense worktrees, alongside CodeSense’s own hook and any hooks your team adds.

CodeSense’s own hook never touches your settings

To drive the status dot on a terminal tab (in Beta), CodeSense adds a hook that runs .claude/hooks/codesense-notify.sh. It writes that hook into .claude/settings.local.json in the worktree, never into .claude/settings.json:

  • Claude Code runs hooks from both files, so yours and CodeSense’s both fire.
  • Existing keys and hooks in settings.local.json are kept, and the file is excluded from git.
  • If your settings.local.json is tracked by git, is a symlink, or isn’t valid JSON, CodeSense leaves it alone.
  • If your committed settings.json already runs codesense-notify for an event, CodeSense doesn’t add it again.

If your team context has no .claude/settings.json, that’s all there is to it: your repo’s settings are untouched.

When your team ships a settings.json too

Say Ledgerline’s billing team wants every agent to run a check when it stops, so it adds billing/content/.claude/settings.json:

{
"hooks": {
"Stop": [
{ "hooks": [{ "type": "command", "command": "npm run lint --silent" }] }
]
}
}

Meanwhile ledgerline/api commits its own .claude/settings.json:

{
"permissions": { "allow": ["Bash(npm test:*)"] },
"hooks": {
"PostToolUse": [
{ "matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "npx prettier --write ." }] }
]
}
}

By default, a team file replaces the repo’s file of the same name in each worktree. To combine them instead, mark the team’s file as a merge file:

  1. In the file tree for the billing team, right-click .claude/settings.json.
  2. Choose Mark as merge file. The file gets a badge: “Merges with the source file instead of overwriting it”.
  3. Open the file and switch the viewer from Authored to Merged preview, then pick api to see exactly what the worktree will get.

For the example above, the merged file keeps the repo’s permissions and PostToolUse hook and adds the team’s Stop hook.

How the merge decides

  • Objects merge key by key, all the way down.
  • A key only the team file has is added.
  • Where both files set the same key, the repo’s value is kept.
  • Lists aren’t combined. If both files have hooks for the same event (both define PostToolUse, say), the repo’s list for that event is kept and the team’s is dropped.

So the safe pattern is: put team hooks under events your repos don’t use, and let each repo’s own settings win where they overlap. Check the Merged preview for each repo when in doubt.

How we know this is accurate 11 sources

Checked against the app at 1b3d5a69d73473db077dfb44f4390b42cded6bd4.

Feature inventory

  • WW-3
  • A-14
  • D-11

Code

  • src-tauri/src/commands/content_engine.rs
  • src-tauri/src/install/merge_marks.rs
  • src-tauri/src/install/story_linker.rs
  • src-tauri/src/shared/json_io.rs
  • src-tauri/src/shared/config_format.rs
  • src/features/dashboard/lib/use-merge-marks.ts
  • src/features/dashboard/components/status-nav/nav-context-menu.tsx
  • src/features/viewer/components/merge-marked-viewer.tsx