Skip to content

Commit 635a4a0

Browse files
master12coderclaude
andcommitted
feat(nlm): auto-query hook — enforced, not optional
Replace passive reminder with active hook script that: - Reads user prompt from stdin - Extracts keywords automatically - Runs nlm query with extracted keywords - Injects results + phase status as systemMessage - Fires on EVERY UserPromptSubmit — cannot be skipped Claude Code now receives nlm context WHETHER IT WANTS TO OR NOT. No trust needed — technically enforced. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3c981c5 commit 635a4a0

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

tools/nlm/auto-query.sh

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/bin/bash
2+
# Auto-query NLM on every user prompt submission.
3+
# Called by Claude Code UserPromptSubmit hook.
4+
# Reads user prompt from stdin, extracts keywords, queries nlm, injects results.
5+
6+
set -e
7+
8+
PROJECT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
9+
PHASE_FILE="$PROJECT_DIR/docs/architecture/phase-status.md"
10+
11+
# Read user prompt from stdin (JSON: {"user_message": "..."})
12+
INPUT=$(cat)
13+
USER_MSG=$(echo "$INPUT" | python3 -c "
14+
import sys, json
15+
try:
16+
data = json.load(sys.stdin)
17+
print(data.get('user_message', data.get('message', '')))
18+
except:
19+
print('')
20+
" 2>/dev/null || echo "")
21+
22+
# Skip if empty or very short prompt (greetings, etc.)
23+
if [ ${#USER_MSG} -lt 10 ]; then
24+
exit 0
25+
fi
26+
27+
# Extract keywords (remove common words, take first 8 meaningful words)
28+
KEYWORDS=$(echo "$USER_MSG" | python3 -c "
29+
import sys
30+
stop = {'the','a','an','is','are','was','were','be','been','being','have','has','had',
31+
'do','does','did','will','would','shall','should','may','might','must','can',
32+
'could','i','you','we','they','he','she','it','my','your','our','their','this',
33+
'that','these','those','what','which','who','whom','when','where','why','how',
34+
'not','no','yes','and','or','but','if','then','else','for','to','from','with',
35+
'in','on','at','by','of','into','about','as','all','each','every','both','few',
36+
'more','most','other','some','such','than','too','very','just','also','now',
37+
'here','there','please','want','need','make','let','me','its','so','up','out',
38+
'like','get','go','know','see','look','think','take','come','give','tell','use',
39+
'done','start','check','review','before','after','next','phase','layer'}
40+
words = sys.stdin.read().lower().split()
41+
keywords = [w for w in words if w not in stop and len(w) > 2][:8]
42+
print(' '.join(keywords))
43+
" 2>/dev/null || echo "")
44+
45+
if [ -z "$KEYWORDS" ]; then
46+
exit 0
47+
fi
48+
49+
# Query nlm with extracted keywords
50+
NLM_RESULT=$(nlm query "$KEYWORDS" --top-k 2 --quiet 2>/dev/null || echo "")
51+
52+
# Get current phase from phase-status.md
53+
PHASE_LINE=""
54+
if [ -f "$PHASE_FILE" ]; then
55+
PHASE_LINE=$(grep "NOT STARTED\|PARTIAL\|DONE" "$PHASE_FILE" | head -5 2>/dev/null || echo "")
56+
fi
57+
58+
# Build system message
59+
if [ -n "$NLM_RESULT" ] || [ -n "$PHASE_LINE" ]; then
60+
# Truncate nlm result to save tokens (max 1500 chars)
61+
NLM_SHORT=$(echo "$NLM_RESULT" | head -40)
62+
63+
MSG="[NLM Auto-Query: '$KEYWORDS']"
64+
if [ -n "$NLM_SHORT" ]; then
65+
MSG="$MSG\n$NLM_SHORT"
66+
fi
67+
if [ -n "$PHASE_LINE" ]; then
68+
MSG="$MSG\n\n[Phase Status]\n$PHASE_LINE"
69+
fi
70+
71+
# Output as JSON systemMessage (Claude Code injects this into context)
72+
python3 -c "
73+
import json, sys
74+
msg = '''$MSG'''
75+
print(json.dumps({'systemMessage': msg}))
76+
" 2>/dev/null
77+
fi

0 commit comments

Comments
 (0)