Skip to content

fix: reclaim marker-stripped managed hook entries during merge - #13

Draft
devbydaniel wants to merge 1 commit into
mainfrom
fix/hook-merge-dedup
Draft

devbydaniel wants to merge 1 commit into
mainfrom
fix/hook-merge-dedup

Conversation

@devbydaniel

Copy link
Copy Markdown
Owner

Problem

af apply deduplicates managed hook entries in ~/.claude/settings.json by the _agentfiles marker field. But Claude Code re-serializes settings.json whenever a setting changes or a permission is accepted, and it drops unknown fields — including the marker. The next apply then treats the stripped entries as user-owned and appends fresh marked copies.

Observed on Daniel's machine: 12 copies of the 3 SessionStart hooks and 4 copies of the Stop hook, each running per session. Settings backups show the progression (1 → 4 → 6 → 12 SessionStart entries from April to August), with stripped and freshly-marked copies of the same hooks side by side.

Fix

The merge strip-phase now also reclaims unmarked entries whose commands all point into an agentfiles hook deploy dir (.local/share/agentfiles/hooks/ or .agentfiles-hooks/) — those are ours by ownership of the scripts, marker or not. The deploy-base constants move to the hooks package so apply and merge share one definition.

Known limitation: file-form hooks with commands outside the deploy dirs still rely on the marker alone; their stripped survivors are not reclaimed.

Tests

  • TestMergeIntoSettings_ReclaimsStrippedMarkers — regression test simulating the stripped-marker file with duplicates next to a genuine user hook
  • TestIsStrippedManagedEntry — table test for the ownership check (nested/flat/repo-level/mixed/no-command shapes)

🤖 Generated with Claude Code

https://claude.ai/code/session_019NuDDqSg1XzYebxp5JKqmo

MergeIntoSettings deduplicates by the _agentfiles marker field, but other
writers of settings.json — notably Claude Code, which re-serializes hook
entries whenever the user changes a setting or accepts a permission — drop
unknown fields. Each subsequent apply then treated the stripped entries as
user-owned and appended fresh marked copies, duplicating every managed hook
once per strip/apply cycle (observed: 12 copies of 3 SessionStart hooks).

The merge now also reclaims unmarked entries whose commands all point into
an agentfiles hook deploy dir — those are ours by ownership of the scripts,
marker or not. The deploy-base constants move to the hooks package so apply
and merge share one definition.

File-form hooks with commands outside the deploy dirs still rely on the
marker alone; their stripped survivors are not reclaimed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019NuDDqSg1XzYebxp5JKqmo
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