Skip to content

adopt / setup.sh --hook: silent inconsistency when installed hooks are gitignored but referenced from a committed settings.json #77

Description

@psaboia

Defect

adopt's .claude/settings.json merge grant delegates to wiki/agents/claude-code/setup.sh --hook, which does two things:

  1. installs hook FILES under .claude/hooks/ (ensure-wiki.py, session-start.sh);
  2. registers hook COMMANDS referencing those paths in .claude/settings.json.

Whether each half is committed is decided by the HOST's .gitignore — which adopt, by design, only appends to (append-only grant) and never reads. When the host's rules ignore .claude/hooks/ but track settings.json, the registrations get committed while the files stay machine-local, and every other clone gets a settings.json referencing hooks that do not exist. Nothing warns; each grant behaves correctly in isolation and the interaction is validated nowhere.

Observed (crcresearch/paper-atomizer)

Host-authored ignore-then-whitelist stanza:

.claude/*
!.claude/commands/          # …wiki-*.md whitelisted
!.claude/skills/            # …wiki-*.md whitelisted
!.claude/settings.json      #  tracked
                            # ← .claude/hooks/ NOT whitelisted

Committed settings.json registers two SessionStart hooks under .claude/hooks/; the directory is absent from the repo. Consequence per fresh clone: the ensure-wiki.py line fails soft (guarded with command -v python3 … || true), but .claude/hooks/session-start.sh is registered unguarded — Claude Code reports a hook error at every session start and the wiki auto-pull never runs on collaborators' machines.

For contrast, the template's intended default is committed hooks: the shipped .gitignore carries .claude/hooks/ deliberately commented out ("uncomment if your team agrees not to share them"), and instantiated projects (e.g. sci-doc-understanding) track .claude/hooks/ alongside settings.json.

Proposed fix (detection, not modification)

Host .gitignore content stays sacred — no new writes. After setup.sh --hook installs and registers:

git check-ignore -q .claude/hooks/session-start.sh   # hooks ignored on this host?
git ls-files --error-unmatch .claude/settings.json   # settings tracked?

If ignored + tracked: print a warning naming the consequence ("collaborators' clones will reference missing hooks; either whitelist .claude/hooks/ or have each user run setup.sh --hook") and record it via the lw_record_* report — and, when reached through adopt, in .llm-wiki-adopt-log.md.

Optional hardening to discuss: register session-start.sh behind an existence guard the way ensure-wiki.py already is ([ -x .claude/hooks/session-start.sh ] && … || true). Trade-off: silences the dangling-reference error for collaborators, which also removes the signal that setup was never run — the warning above is the primary fix either way.

Acceptance

  • Fixture: a host whose .gitignore ignores .claude/hooks/ (tracked settings.json) → adopt/setup prints the warning and the adopt log records it; a host with the template-default gitignore does not warn. Red-first against current code (today both paths are silent).
  • Real-world reference: the paper-atomizer state above, reported by a user hitting the session-start hook error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions