You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
hook-guard: Read/Glob PreToolUse nudge has no project-membership or graph-freshness gate — fires identically on out-of-project files and stale graphs #1840
Version: reproduced on 0.9.10 through 0.9.13 (current v8 HEAD); _run_hook_guard is unchanged across that range.
Problem:graphify/__main__.py::_run_hook_guard (read branch, ~line 1676 on 0.9.10; moved to graphify/cli.py on v8) fires _READ_NUDGE whenever (a) the tool call's file_path/pattern/path has a trailing extension in _HOOK_SOURCE_EXTS (which includes .md/.rst/.txt/.mdx), (b) the path isn't under graphify-out/, and (c) graphify-out/graph.json exists in the cwd. Two real-world consequences observed in production use (Claude Code, 2026-07 audit sessions):
Reading a file with no relationship to the project the graph indexes — a global plugin-cache SKILL.md, another repo's config — fires the same "MANDATORY: run graphify before reading source files" additionalContext as reading the project's own .py source, because the guard only inspects the path string's extension, never whether the path is plausibly inside the tree graphify-out/graph.json was built from.
A graph that is arbitrarily stale (no cron/CI rebuild; graphify update is run by hand) gates identically to a freshly-rebuilt one — the guard calls only .is_file() on graph.json, never compares its age against the tracked tree.
Both make the nudge fire on a majority of reads in a typical audit/ops/docs-heavy session (measured: ~100% of reads were on non-application-code targets in one such session), training the agent to habitually override "MANDATORY" language — which also blunts the signal on the minority of reads where the nudge is actually correct.
Proposed smallest fix:
Resolve the candidate path and skip the nudge when it isn't under the graph's project root (reuse the existing .graphify_root/GRAPHIFY_REPO_ROOT root-resolution convention already used by _rebuild_code and friends elsewhere in __main__.py/build.py).
Optionally scope .md/.rst/.txt/.mdx out of the hard _HOOK_SOURCE_EXTS gate (or behind a docs/ allowlist), since a knowledge graph built from AST/semantic hashing has limited signal for arbitrary non-project markdown — proposed as opt-in/config-gated rather than a default-behavior change, since the list is documented as "verbatim from the old hook".
Test plan suggestion: a fake project root + graph.json; a Read call on a path outside that root should emit no nudge even though the extension matches; a generated_at stamp older than the corpus's newest file mtime should downgrade the nudge's language.
Version: reproduced on 0.9.10 through 0.9.13 (current
v8HEAD);_run_hook_guardis unchanged across that range.Problem:
graphify/__main__.py::_run_hook_guard(readbranch, ~line 1676 on 0.9.10; moved tographify/cli.pyonv8) fires_READ_NUDGEwhenever (a) the tool call'sfile_path/pattern/pathhas a trailing extension in_HOOK_SOURCE_EXTS(which includes.md/.rst/.txt/.mdx), (b) the path isn't undergraphify-out/, and (c)graphify-out/graph.jsonexists in the cwd. Two real-world consequences observed in production use (Claude Code, 2026-07 audit sessions):SKILL.md, another repo's config — fires the same "MANDATORY: run graphify before reading source files"additionalContextas reading the project's own.pysource, because the guard only inspects the path string's extension, never whether the path is plausibly inside the treegraphify-out/graph.jsonwas built from.graphify updateis run by hand) gates identically to a freshly-rebuilt one — the guard calls only.is_file()ongraph.json, never compares its age against the tracked tree.Both make the nudge fire on a majority of reads in a typical audit/ops/docs-heavy session (measured: ~100% of reads were on non-application-code targets in one such session), training the agent to habitually override "MANDATORY" language — which also blunts the signal on the minority of reads where the nudge is actually correct.
Proposed smallest fix:
.graphify_root/GRAPHIFY_REPO_ROOTroot-resolution convention already used by_rebuild_codeand friends elsewhere in__main__.py/build.py).generated_atstamp that PR Stamp graph.json with generated_at, warn on stale graphify query #1624 already proposes adding tograph.json, and soften the nudge language (e.g. drop "MANDATORY", note staleness) when the stamp is older than the newest mtime in the tracked corpus, or thangit status's latest relevant change — reusing Stamp graph.json with generated_at, warn on stale graphify query #1624's plumbing instead of adding a second staleness mechanism..md/.rst/.txt/.mdxout of the hard_HOOK_SOURCE_EXTSgate (or behind adocs/allowlist), since a knowledge graph built from AST/semantic hashing has limited signal for arbitrary non-project markdown — proposed as opt-in/config-gated rather than a default-behavior change, since the list is documented as "verbatim from the old hook".Test plan suggestion: a fake project root + graph.json; a Read call on a path outside that root should emit no nudge even though the extension matches; a
generated_atstamp older than the corpus's newest file mtime should downgrade the nudge's language.