1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#!/usr/bin/env bash
# basemind PreToolUse guard.
#
# Fires only for the codebase-search tools (matcher "Grep|Glob" in hooks.json) and
# steers the agent toward basemind's indexed tools, which return paths + line numbers
# instead of file bodies. Three modes via the BASEMIND_GUARD env var:
#
# nudge (default) — allow the call, attach a one-time advisory pointing at the
# cheaper basemind tool. Fires once per session per tool.
# redirect — deny the call with a reason telling the agent to use the
# basemind tool instead. Enforcing; no dedup.
# off — no-op.
#
# Caveat: whether Claude Code fires PreToolUse inside subagents is undocumented, so
# this reliably covers main-session tool calls; subagent coverage is best-effort.
#
# Output is the PreToolUse JSON result on stdout; the hook never blocks startup and
# degrades to a silent no-op (exit 0 = proceed normally) when it cannot run.
MODE=""
[ &&
# Need jq to read the event payload + emit well-formed JSON; degrade to no-op if absent.
||
input=""
[ ||
tool=""
session=""
# Tailor the suggestion to the tool. Anything outside the matcher set just proceeds.
if [; then
fi
# nudge: one advisory per session per tool so it informs without nagging.
# Sanitize session_id before building a path from it — it is untrusted input, and a
# value containing "/" or ".." would otherwise let the marker escape marker_dir.
# Collapse everything outside [A-Za-z0-9._-] to "_".
safe_session=""
[ || safe_session="nosession"
marker_dir="/basemind-guard"
marker="/."
||
if [; then
fi
||