feat(#478): suggest MCP reindex after a workspace clone is pulled/updated#483
Conversation
…ated Companion to #475 (post-clone reindex hook). Closes the post-UPDATE index-staleness gap: when a workspace/<name>/ clone's code drifts because the agent pulled new commits, nothing reindexes that project, so search_code returns stale/not_indexed results and the agent silently falls back to grep. - New advisory hook suggest-mcp-reindex-after-pull.sh fires on a git HEAD-move (pull / merge / checkout / reset) inside a workspace clone and emits a stderr banner naming the project-scoped reindex call. Exit 0 always — non-blocking, mirrors the clone sibling + check-upstream-drift. - Trigger granularity is the coarse HEAD-move, NOT per-file Edit/Write (per-edit prompts would be far too noisy; a single edited file barely moves the index). AgDR-0058 records this + the debounce tradeoff. - Debounce: silent on "Already up to date." when the output is visible; fires otherwise (over-firing a cheap advisory beats under-firing). - Project detection: cwd-first (.cwd / .tool_input.cwd — the common case, pull run from inside the clone), with -C / cd-prefix / bare-path fallbacks. Skips failed commands and non-workspace pulls. - Scoped to the changed project only — never a portfolio-wide reindex. - Wired as a PostToolUse Bash hook (Bash(git *)); test covers cwd / path / merge / checkout / reset fire + silent on non-workspace / failed / up-to-date / non-git / Edit/Write. Hook count 37 -> 38 across CLAUDE.md and site/* (site-counts test green). Closes #478 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review: PR #483
Commit: a7b061219737fa26b5dd55e0e075998641839b8f
Summary
Adds a PostToolUse advisory hook (suggest-mcp-reindex-after-pull.sh, #478) that nudges the agent to reindex a single managed project after a git HEAD-move (pull/merge/checkout/reset) inside its workspace/<name>/ clone. Companion to #475's post-clone hook. Ships the hook, a 19-case test, settings wiring, AgDR-0058, and consistent hook-count bumps (CLAUDE.md 25->26 curated narrative; site/* 37->38 gated).
Checklist Results
- Architecture & Design: Pass
- Code Quality: Pass
- Testing: Pass
- Security: Pass -- no secrets, no injection surface; reads JSON payload via jq, emits stderr only
- Performance: Pass -- fast no-op on the dominant git push/commit/non-workspace path
- PR Description & Glossary: Pass -- narrative summary + 7-term glossary + AgDR marker
- Summary Bullet Narrative: Pass -- every bullet states what + why
- Technical Decisions (AgDR):Pass -- AgDR-0058 present, all 5 template sections, marker linked
- Adopter Handbooks: N/A -- no language handbook triggers (shell + md + html diff)
Verification performed (on PR HEAD a7b0612)
- test_suggest_mcp_reindex_after_pull.sh -> PASS: 19, FAIL: 0
- test_suggest_mcp_reindex_after_clone.sh (sibling, no-regression) -> PASS: 11, FAIL: 0
- test_site_counts.sh -> green (find-derived hooks=38, asserted across all site/*)
- shellcheck -S warning on hook AND test -> clean (no warnings/errors)
- jq empty .claude/settings.json -> valid JSON
- Exit-0-always confirmed: every exit in the hook is
exit 0(6 early no-ops + final); noset -e, so a grep miss cannot abort with non-zero. Executable bit 100755. - Trigger correctness (adversarial):
git fetch && git checkout main-> fires (caught at && boundary by checkout token)echo git pull-> silent (no command-boundary match on pull after echo)git push/git commit-> silent- bare
git fetch, "Already up to date.", exit_code!=0, Edit/Write -> silent - project parse scoped to the changed project (workspace/), cwd-first with -C / cd / bare-token fallbacks
- Settings wiring mirrors the clone hook: same pin-dir-then-walk-up ops-root resolver,
[ -d .claude/hooks ] || exit 0guard, exec into the hook.if: "Bash(git *)"is correctly broader than the clone hook'sgit clone *since pull/merge/checkout/reset are allgit *; the internal regex narrows to HEAD-moves.
Count convention note (not a defect)
CLAUDE.md's curated narrative says "26 shell scripts" while site/* say "38". Confirmed this is the documented dual-count convention, not a drift bug: the gating test_site_counts.sh derives actual_hooks=38 via find .claude/hooks -maxdepth 1 -name '*.sh' ! -name '_lib*' and scans ONLY site/* files -- CLAUDE.md is intentionally outside its scan set. Both numbers were bumped consistently on their own scales (25->26, 37->38). Gating check is green.
Issues Found
None blocking.
Suggestions
- nit:
git checkout -- <file>(a working-tree file restore that does NOT move HEAD) over-fires the banner, since the regex matchescheckout\bregardless of branch-vs-path argument. Benign -- the working tree genuinely changed and a project-scoped reindex is still reasonable -- and consistent with AgDR-0058's explicit "over-firing a cheap advisory beats under-firing" tradeoff. No change required; flagging for awareness only.
Verdict
APPROVED
Reviewed by Rex (Code Reviewer Agent)
Reviewed commit: a7b0612
…ated (#483) Companion to #475 (post-clone reindex hook). Closes the post-UPDATE index-staleness gap: when a workspace/<name>/ clone's code drifts because the agent pulled new commits, nothing reindexes that project, so search_code returns stale/not_indexed results and the agent silently falls back to grep. - New advisory hook suggest-mcp-reindex-after-pull.sh fires on a git HEAD-move (pull / merge / checkout / reset) inside a workspace clone and emits a stderr banner naming the project-scoped reindex call. Exit 0 always — non-blocking, mirrors the clone sibling + check-upstream-drift. - Trigger granularity is the coarse HEAD-move, NOT per-file Edit/Write (per-edit prompts would be far too noisy; a single edited file barely moves the index). AgDR-0058 records this + the debounce tradeoff. - Debounce: silent on "Already up to date." when the output is visible; fires otherwise (over-firing a cheap advisory beats under-firing). - Project detection: cwd-first (.cwd / .tool_input.cwd — the common case, pull run from inside the clone), with -C / cd-prefix / bare-path fallbacks. Skips failed commands and non-workspace pulls. - Scoped to the changed project only — never a portfolio-wide reindex. - Wired as a PostToolUse Bash hook (Bash(git *)); test covers cwd / path / merge / checkout / reset fire + silent on non-workspace / failed / up-to-date / non-git / Edit/Write. Hook count 37 -> 38 across CLAUDE.md and site/* (site-counts test green). Closes #478 Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
suggest-mcp-reindex-after-pull.sh— closes the post-update index-staleness gap (companion to [Task] MCP-first rule doesn't reach sub-agents — they grep instead of search_code #475's post-clone hook). When aworkspace/<name>/managed-project clone's code drifts because the agent pulled new commits, nothing reindexes that project, sosearch_codereturns stale /not_indexedexcerpts and the agent silently falls back to grep. The hook fires on a git HEAD-move inside a workspace clone and reminds the agent to reindex that project, removing the "I forgot the index went stale" failure mode.git pull | merge | checkout | resetat a command boundary. Per-edit reindex prompts were explicitly rejected as far too noisy (one banner per save) and the staleness a single edited file flags is negligible; a pull can rewrite the whole tree in one step, which is exactly when the index goes meaningfully stale. A baregit fetchis not matched (it doesn't move HEAD); agit fetch && git mergecompound is caught via themergetoken. Rationale recorded in AgDR-0058.git pullis normally run from inside the clone (cwd =workspace/<name>), so the hook reads.cwd/.tool_input.cwdfrom the PostToolUse payload first, then falls back to an explicit-C <path>, acd <path> &&prefix, or any bareworkspace/<name>token. cwd-based detection depends on the harness populating cwd in the payload; the fallbacks cover the rest. The suggestion is scoped to the changed project only — never a portfolio-wide reindex. Skips failed commands (exit_code != 0) and non-workspace pulls.check-upstream-drift.sh; graceful when the MCP server is unavailable. Wired as a PostToolUse Bash hook withif: "Bash(git *)"; the hook's internal command-boundary match keeps it a fast no-op ongit push/commit/add/cloneand on non-workspace pulls. Hook count 37 → 38 updated acrossCLAUDE.mdandsite/*(site-counts test green).Testing
bash .claude/hooks/tests/test_suggest_mcp_reindex_after_pull.sh→ PASS: 19, FAIL: 0 — covers cwd-based /-C/cd-prefix / merge / checkout / reset fire, and silent on non-workspace pull / failed command / "Already up to date." / baregit fetch/ non-git command / Edit / Write.bash .claude/hooks/tests/test_suggest_mcp_reindex_after_clone.sh→ PASS: 11, FAIL: 0 (no regression in the sibling hook).bash .claude/hooks/tests/test_site_counts.sh→ green (hooks: 38 across all scannedsite/*files).shellcheck -S warning .claude/hooks/suggest-mcp-reindex-after-pull.sh→ clean.markdownlint-cli2ondocs/agdr/AgDR-0058-*.mdandCLAUDE.md→ only MD060 (ignored per repo convention).Closes #478
Glossary
tool_response.exit_codeand emits an advisory banner to stderr.check-upstream-drift.shand the clone-reindex sibling.HEADpoints at —pull,merge,checkout <branch>,reset --hard. The moment a workspace clone's tree can change wholesale, hence the moment its search index can go stale.mcp__apexyard-search__reindex(scope="project", project="<name>")— rebuilds the apexyard-search index for one project sosearch_code/search_docsreturn fresh results instead of stale ornot_indexedones.workspace/<name>/<name>is the registered project name.