nogrep 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +91 -0
  2. package/commands/init.md +241 -0
  3. package/commands/off.md +11 -0
  4. package/commands/on.md +21 -0
  5. package/commands/query.md +13 -0
  6. package/commands/status.md +15 -0
  7. package/commands/update.md +89 -0
  8. package/dist/chunk-SMUAF6SM.js +12 -0
  9. package/dist/chunk-SMUAF6SM.js.map +1 -0
  10. package/dist/query.d.ts +12 -0
  11. package/dist/query.js +272 -0
  12. package/dist/query.js.map +1 -0
  13. package/dist/settings.d.ts +6 -0
  14. package/dist/settings.js +75 -0
  15. package/dist/settings.js.map +1 -0
  16. package/dist/signals.d.ts +9 -0
  17. package/dist/signals.js +174 -0
  18. package/dist/signals.js.map +1 -0
  19. package/dist/trim.d.ts +3 -0
  20. package/dist/trim.js +266 -0
  21. package/dist/trim.js.map +1 -0
  22. package/dist/types.d.ts +141 -0
  23. package/dist/types.js +7 -0
  24. package/dist/types.js.map +1 -0
  25. package/dist/validate.d.ts +10 -0
  26. package/dist/validate.js +143 -0
  27. package/dist/validate.js.map +1 -0
  28. package/dist/write.d.ts +8 -0
  29. package/dist/write.js +267 -0
  30. package/dist/write.js.map +1 -0
  31. package/docs/ARCHITECTURE.md +239 -0
  32. package/docs/CLAUDE.md +161 -0
  33. package/docs/CONVENTIONS.md +162 -0
  34. package/docs/SPEC.md +803 -0
  35. package/docs/TASKS.md +216 -0
  36. package/hooks/hooks.json +35 -0
  37. package/hooks/pre-tool-use.sh +37 -0
  38. package/hooks/prompt-submit.sh +26 -0
  39. package/hooks/session-start.sh +21 -0
  40. package/package.json +24 -0
  41. package/scripts/query.ts +290 -0
  42. package/scripts/settings.ts +98 -0
  43. package/scripts/signals.ts +237 -0
  44. package/scripts/trim.ts +379 -0
  45. package/scripts/types.ts +186 -0
  46. package/scripts/validate.ts +181 -0
  47. package/scripts/write.ts +346 -0
  48. package/templates/claude-md-patch.md +8 -0
package/docs/SPEC.md ADDED
@@ -0,0 +1,803 @@
1
+ # nogrep — Technical Specification
2
+
3
+ > A Claude Code plugin + CLI that generates a navigable index for any codebase so AI agents stop doing blind grep/find exploration.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Problem](#1-problem)
10
+ 2. [The One Thing](#2-the-one-thing)
11
+ 3. [Output Structure](#3-output-structure)
12
+ 4. [File Schemas](#4-file-schemas)
13
+ 5. [CLI Interface](#5-cli-interface)
14
+ 6. [Init Pipeline](#6-init-pipeline)
15
+ 7. [Update Pipeline](#7-update-pipeline)
16
+ 8. [Query System](#8-query-system)
17
+ 9. [Tag Taxonomy](#9-tag-taxonomy)
18
+ 10. [CC Plugin](#10-cc-plugin)
19
+ 11. [Settings](#11-settings)
20
+ 12. [CI Integration](#12-ci-integration)
21
+ 13. [AI Prompts](#13-ai-prompts)
22
+
23
+ ---
24
+
25
+ ## 1. Problem
26
+
27
+ Claude Code has no navigational index. Every query triggers a full codebase scan:
28
+
29
+ ```
30
+ find . -name "*.ts" → discovery
31
+ grep -r "keyword" src/ → content scan
32
+ read file → wrong file → repeat
33
+ ```
34
+
35
+ This is a full table scan on every query — slow, token-expensive, and imprecise.
36
+
37
+ A senior developer doesn't grep. They have a mental map:
38
+ > "Payment issue → src/billing/ → StripeService → webhook idempotency gotcha there"
39
+
40
+ `nogrep` encodes that mental map into a machine-queryable index.
41
+
42
+ ---
43
+
44
+ ## 2. The One Thing
45
+
46
+ **nogrep does one thing: give AI agents a navigable index so they stop full-scanning codebases.**
47
+
48
+ It is NOT:
49
+ - A documentation generator (that's GSD, Compodoc, JSDoc)
50
+ - A code search engine (that's Sourcegraph, ctags)
51
+ - A runtime service (no servers, no databases)
52
+ - Comprehensive docs — nodes are intentionally minimal
53
+
54
+ It IS:
55
+ - A navigation layer
56
+ - A reverse index
57
+ - A thin context node per domain
58
+ - A CC plugin that intercepts grep at the tool-call level
59
+
60
+ ---
61
+
62
+ ## 3. Output Structure
63
+
64
+ Generated inside the target project:
65
+
66
+ ```
67
+ .nogrep/
68
+ ├── _index.json # master reverse index — primary lookup file
69
+ ├── _registry.json # source path glob → context file mapping (for CI/update)
70
+ ├── _taxonomy.json # allowed tags for this project
71
+ ├── domains/ # one file per business domain
72
+ │ ├── billing.md
73
+ │ └── auth.md
74
+ ├── architecture/ # cross-domain architectural concerns
75
+ │ ├── database.md
76
+ │ └── api-design.md
77
+ ├── flows/ # multi-domain business flows
78
+ │ └── checkout.md
79
+ └── entities/ # data models (if applicable)
80
+ └── user.md
81
+ ```
82
+
83
+ Also patched in the target project:
84
+ ```
85
+ CLAUDE.md # navigation instructions appended
86
+ .claude/settings.json # nogrep.enabled flag
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 4. File Schemas
92
+
93
+ ### 4.1 Context Node (e.g. `.nogrep/domains/billing.md`)
94
+
95
+ ```markdown
96
+ ---
97
+ id: billing
98
+ title: Billing & Payments
99
+ category: domain
100
+ tags:
101
+ domain: [billing]
102
+ layer: [business, data, infrastructure]
103
+ tech: [stripe, postgres]
104
+ concern: [error-handling, idempotency]
105
+ type: [module]
106
+ relates_to:
107
+ - id: notifications
108
+ reason: "triggers invoice emails after payment events"
109
+ inverse_relations:
110
+ - id: checkout-flow
111
+ reason: "orchestrates billing as primary step"
112
+ src_paths:
113
+ - src/billing/**
114
+ keywords:
115
+ - stripe
116
+ - webhook
117
+ - invoice
118
+ - retry
119
+ - idempotent
120
+ last_synced:
121
+ commit: abc1234
122
+ timestamp: 2025-03-13T10:00:00Z
123
+ src_hash: sha256:ef9a3c...
124
+ ---
125
+
126
+ ## Purpose
127
+ _2-3 sentences of business intent. What this domain exists to do, not how._
128
+
129
+ ## Public Surface
130
+ _What other domains call. Exported functions, routes, events._
131
+
132
+ ```
133
+ POST /billing/webhook
134
+ BillingService.createSubscription(userId, planId)
135
+ event: billing.invoice.created
136
+ ```
137
+
138
+ ## Does Not Own
139
+ - Email delivery → notifications
140
+ - User identity → auth
141
+
142
+ ## Gotchas
143
+ - Webhook handler must be idempotent — check event.id before processing
144
+ - All monetary values in cents (integer), never floats
145
+
146
+ ## Manual Notes
147
+ _Human annotations. Never overwritten by nogrep update._
148
+ ```
149
+
150
+ **Node design principles:**
151
+ - Purpose: max 3 sentences
152
+ - Gotchas: max 5 bullets
153
+ - If a node is getting long, it's doing too much
154
+ - Nodes answer "should CC look here?" — not "how does this work?"
155
+
156
+ ---
157
+
158
+ ### 4.2 `_index.json`
159
+
160
+ ```json
161
+ {
162
+ "version": "1.0",
163
+ "generated_at": "2025-03-13T10:00:00Z",
164
+ "commit": "abc1234",
165
+ "stack": {
166
+ "primary_language": "typescript",
167
+ "frameworks": ["nestjs", "react"],
168
+ "architecture": "monolith"
169
+ },
170
+ "tags": {
171
+ "tech:stripe": [
172
+ ".nogrep/domains/billing.md",
173
+ ".nogrep/flows/checkout.md"
174
+ ],
175
+ "tech:redis": [
176
+ ".nogrep/domains/auth.md",
177
+ ".nogrep/architecture/caching.md"
178
+ ],
179
+ "domain:billing": [
180
+ ".nogrep/domains/billing.md",
181
+ ".nogrep/flows/checkout.md"
182
+ ],
183
+ "concern:security": [
184
+ ".nogrep/domains/auth.md",
185
+ ".nogrep/architecture/api-design.md"
186
+ ]
187
+ },
188
+ "keywords": {
189
+ "webhook": [".nogrep/domains/billing.md"],
190
+ "jwt": [".nogrep/domains/auth.md"],
191
+ "retry": [".nogrep/domains/billing.md", ".nogrep/architecture/event-system.md"]
192
+ },
193
+ "paths": {
194
+ "src/billing/**": {
195
+ "context": ".nogrep/domains/billing.md",
196
+ "tags": ["domain:billing", "tech:stripe", "layer:business"]
197
+ },
198
+ "src/auth/**": {
199
+ "context": ".nogrep/domains/auth.md",
200
+ "tags": ["domain:auth", "concern:security", "tech:redis"]
201
+ }
202
+ }
203
+ }
204
+ ```
205
+
206
+ ---
207
+
208
+ ### 4.3 `_registry.json`
209
+
210
+ ```json
211
+ {
212
+ "mappings": [
213
+ {
214
+ "glob": "src/billing/**",
215
+ "context_file": ".nogrep/domains/billing.md",
216
+ "watch": true
217
+ },
218
+ {
219
+ "glob": "prisma/schema.prisma",
220
+ "context_file": ".nogrep/architecture/database.md",
221
+ "watch": true
222
+ }
223
+ ]
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ### 4.4 `_taxonomy.json`
230
+
231
+ ```json
232
+ {
233
+ "static": {
234
+ "layer": ["presentation", "business", "data", "infrastructure", "cross-cutting"],
235
+ "concern": ["security", "performance", "caching", "validation", "error-handling", "idempotency", "observability"],
236
+ "type": ["module", "flow", "entity", "integration", "config", "ui", "test"]
237
+ },
238
+ "dynamic": {
239
+ "domain": [],
240
+ "tech": []
241
+ },
242
+ "custom": {}
243
+ }
244
+ ```
245
+
246
+ `dynamic` values are detected per project during init.
247
+ `custom` is user-editable, never overwritten.
248
+
249
+ ---
250
+
251
+ ### 4.5 `.claude/settings.json` (team-shared)
252
+
253
+ ```json
254
+ {
255
+ "nogrep": {
256
+ "enabled": true
257
+ }
258
+ }
259
+ ```
260
+
261
+ ### 4.6 `.claude/settings.local.json` (personal, gitignored)
262
+
263
+ ```json
264
+ {
265
+ "nogrep": {
266
+ "enabled": false
267
+ }
268
+ }
269
+ ```
270
+
271
+ `settings.local.json` takes precedence over `settings.json` for the `enabled` flag.
272
+
273
+ ---
274
+
275
+ ## 5. Plugin Commands
276
+
277
+ All user interaction happens through CC slash commands. No standalone CLI.
278
+
279
+ ### Commands
280
+
281
+ ```
282
+ /nogrep:init # full init — Claude analyzes project, generates .nogrep/
283
+ /nogrep:update # diff-based update of stale nodes
284
+ /nogrep:query # index lookup
285
+ /nogrep:validate # staleness check
286
+ /nogrep:status # coverage + freshness summary
287
+ /nogrep:on # enable in settings, check index
288
+ /nogrep:off # disable in settings
289
+ ```
290
+
291
+ Hooks call a thin internal script (`nogrep-run`) for mechanical operations (query lookup, validation). This is not user-facing.
292
+
293
+ ---
294
+
295
+ ## 6. Init Pipeline
296
+
297
+ ```
298
+ Phase 1 Phase 2 Phase 3 Phase 4
299
+ Universal → Stack Detection → Deep Analysis → Write
300
+ Signals (Claude analyzes (Claude analyzes .nogrep/
301
+ (script) signals) 1 per cluster) _index.json
302
+ ```
303
+
304
+ Claude orchestrates the entire pipeline during `/nogrep:init`. Phase 1 runs a script to collect signals. Phases 2-3 are Claude's own analysis. Phase 4 uses writer scripts for structured output.
305
+
306
+ ### Phase 1 — Universal Signals (No AI)
307
+
308
+ Collect language-agnostic signals:
309
+
310
+ | Signal | Method |
311
+ |--------|--------|
312
+ | Directory tree | `walk(root, depth=4)`, exclude node_modules/dist/build |
313
+ | File extensions | group files by extension |
314
+ | Dependency manifests | find `package.json`, `requirements.txt`, `pom.xml`, `go.mod`, `Podfile`, `Cargo.toml`, `pubspec.yaml` — note depth (root vs subfolder) |
315
+ | Entry points | find `main.*`, `index.*`, `app.*`, `server.*` |
316
+ | Git churn | `git log --stat` — top 20 most changed files |
317
+ | File size | top 20 largest files |
318
+ | Env files | find `.env*`, `config/**` |
319
+ | Test files | group test files — `*.test.*`, `*.spec.*` |
320
+
321
+ Output: `signals.json` object passed to Phase 2.
322
+
323
+ ---
324
+
325
+ ### Phase 2 — Stack Detection (Claude)
326
+
327
+ Input: `signals.json`
328
+ Output: `stack.json`
329
+
330
+ ```typescript
331
+ interface StackResult {
332
+ primary_language: string
333
+ frameworks: string[]
334
+ architecture: 'monolith' | 'monorepo' | 'multi-repo' | 'microservice' | 'library'
335
+ domain_clusters: Array<{
336
+ name: string
337
+ path: string
338
+ confidence: number
339
+ }>
340
+ conventions: {
341
+ entry_pattern: string
342
+ test_pattern: string
343
+ config_location: string
344
+ }
345
+ stack_hints: string // reading hints for Phase 3 prompt
346
+ dynamic_taxonomy: {
347
+ domain: string[]
348
+ tech: string[]
349
+ }
350
+ }
351
+ ```
352
+
353
+ **Architecture detection heuristics:**
354
+ - `monolith` — single dependency manifest at root, one primary framework
355
+ - `monorepo` — multiple dependency manifests with shared tooling (nx, turborepo, lerna, workspaces)
356
+ - `multi-repo` — multiple dependency manifests at depth 1, no shared tooling, separate stacks per subfolder (e.g. backend/, frontend/, mobile/)
357
+ - `microservice` — multiple independently deployable services, often with Docker/K8s config
358
+ - `library` — single package, exports API surface, no application entry points
359
+
360
+ See Section 13 for the prompt structure (embedded in `/nogrep:init` slash command).
361
+
362
+ ---
363
+
364
+ ### Phase 3 — Deep Analysis (Claude, Per Cluster)
365
+
366
+ For each `domain_cluster` from Phase 2:
367
+
368
+ **Source preparation (language-agnostic trimming):**
369
+ - Keep: file headers, function/method signatures, class/interface declarations, decorators/annotations, exported symbols, inline comments
370
+ - Strip: function bodies, implementation details
371
+ - Target: 100–300 lines per cluster
372
+
373
+ **Output per cluster:** a `ContextNode` object (see types). See Section 13 for the prompt structure.
374
+
375
+ ---
376
+
377
+ ### Phase 3b — Flow Detection
378
+
379
+ A cluster qualifies as a cross-domain **flow** when:
380
+ - Its import graph touches 3+ distinct domain clusters, OR
381
+ - It is named with flow keywords: `checkout`, `onboarding`, `signup`, `pipeline`, `workflow`, `process`
382
+
383
+ Flows get nodes in `.nogrep/flows/`.
384
+
385
+ ---
386
+
387
+ ### Phase 4 — Write
388
+
389
+ 1. Write all `.md` context node files (with frontmatter + AI content + empty Manual Notes)
390
+ 2. Populate `inverse_relations` by scanning all `relates_to` references across nodes
391
+ 3. Build `_index.json` aggregating all frontmatter
392
+ 4. Build `_registry.json` from `src_paths` in each node
393
+ 5. Write `_taxonomy.json` with static + dynamic values
394
+ 6. Compute `src_hash` per node (SHA256 of all files matching `src_paths`)
395
+ 7. Append navigation instructions to target project `CLAUDE.md`
396
+ 8. Write `nogrep.enabled: true` to `.claude/settings.json`
397
+
398
+ ---
399
+
400
+ ## 7. Update Pipeline
401
+
402
+ ```
403
+ git diff origin/main --name-only
404
+
405
+ Map changed files → affected nodes (via _registry.json globs)
406
+
407
+ For each affected node:
408
+ 1. Re-run Phase 1 signals for that cluster only
409
+ 2. Re-run Phase 3 deep analysis
410
+ 3. Extract and preserve ## Manual Notes
411
+ 4. Update src_hash and last_synced
412
+
413
+ Rebuild _index.json
414
+
415
+ (CI: commit .nogrep/ changes)
416
+ ```
417
+
418
+ ### Manual Notes Preservation
419
+
420
+ ```typescript
421
+ function extractManualNotes(content: string): string {
422
+ const match = content.match(
423
+ /## Manual Notes\n([\s\S]*?)(?=\n## |\n---|\s*$)/
424
+ )
425
+ return match ? match[1].trim() : ''
426
+ }
427
+ // re-inject after AI regeneration
428
+ ```
429
+
430
+ ---
431
+
432
+ ## 8. Query System
433
+
434
+ ### Resolution Order
435
+
436
+ ```
437
+ 1. Keyword match → _index.json .keywords
438
+ 2. Tag match → _index.json .tags
439
+ 3. Path match → _index.json .paths
440
+ 4. NL question → extract keywords/tags → repeat 1-3
441
+ ```
442
+
443
+ No AI needed for query. Pure index lookup.
444
+
445
+ ### Natural Language Extraction
446
+
447
+ For `--question` input:
448
+
449
+ ```
450
+ Question: "how does payment retry work after a failed webhook?"
451
+
452
+ Extracted keywords: [payment, retry, webhook, failed]
453
+ Extracted tags: [domain:billing, concern:error-handling]
454
+
455
+ Lookup: union of all nodes matching any keyword or tag
456
+ Rank: by match count (most relevant first)
457
+ ```
458
+
459
+ Extraction is keyword-based (no AI) — match words in question against taxonomy values and keywords in `_index.json`.
460
+
461
+ ---
462
+
463
+ ## 9. Tag Taxonomy
464
+
465
+ ### Static (universal)
466
+
467
+ **`layer`**
468
+ | Value | Maps to |
469
+ |-------|---------|
470
+ | `presentation` | controllers, views, routes, screens |
471
+ | `business` | services, use-cases, view-models |
472
+ | `data` | repositories, DAOs, stores |
473
+ | `infrastructure` | config, adapters, external clients |
474
+ | `cross-cutting` | middleware, guards, interceptors, hooks |
475
+
476
+ **`concern`**
477
+ `security` · `performance` · `caching` · `validation` · `error-handling` · `idempotency` · `observability`
478
+
479
+ **`type`**
480
+ `module` · `flow` · `entity` · `integration` · `config` · `ui` · `test`
481
+
482
+ ### Dynamic (per project)
483
+
484
+ **`domain`** — detected from directory structure in Phase 2
485
+ **`tech`** — detected from dependency manifests in Phase 2
486
+
487
+ ---
488
+
489
+ ## 10. CC Plugin
490
+
491
+ This is the **only** interface. Everything runs inside Claude Code.
492
+
493
+ ### Plugin Structure
494
+
495
+ ```
496
+ nogrep/
497
+ ├── plugin.json
498
+ ├── commands/
499
+ │ ├── init.md # orchestrates full init pipeline
500
+ │ ├── on.md
501
+ │ ├── off.md
502
+ │ ├── update.md
503
+ │ ├── status.md
504
+ │ └── query.md
505
+ ├── hooks/
506
+ │ ├── pre-tool-use.sh
507
+ │ ├── session-start.sh
508
+ │ └── prompt-submit.sh
509
+ └── scripts/
510
+ ├── signals.ts # Phase 1 signal collection
511
+ ├── query.ts # index lookup (called by hooks)
512
+ ├── validate.ts # staleness check (called by hooks)
513
+ ├── write.ts # structured file writer
514
+ └── settings.ts # read/write .claude/settings.json
515
+ ```
516
+
517
+ ### `plugin.json`
518
+
519
+ ```json
520
+ {
521
+ "name": "nogrep",
522
+ "version": "1.0.0",
523
+ "description": "Navigable codebase index for Claude Code — stop grepping, start navigating",
524
+ "scope": "project",
525
+ "hooks": {
526
+ "PreToolUse": {
527
+ "matcher": "Bash",
528
+ "command": "hooks/pre-tool-use.sh"
529
+ },
530
+ "SessionStart": {
531
+ "command": "hooks/session-start.sh"
532
+ },
533
+ "UserPromptSubmit": {
534
+ "command": "hooks/prompt-submit.sh"
535
+ }
536
+ }
537
+ }
538
+ ```
539
+
540
+ ---
541
+
542
+ ### Hook: `pre-tool-use.sh`
543
+
544
+ Intercepts grep/find/rg/ag bash commands and injects nogrep results as `additionalContext` before CC proceeds.
545
+
546
+ ```bash
547
+ #!/bin/bash
548
+ INPUT=$(cat)
549
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
550
+
551
+ # Only intercept search commands
552
+ if ! echo "$COMMAND" | grep -qE '^\s*(grep|find|rg|ag|fd)\s'; then
553
+ exit 0
554
+ fi
555
+
556
+ # Check nogrep is enabled
557
+ ENABLED=$(cat .claude/settings.json 2>/dev/null | jq -r '.nogrep.enabled // false')
558
+ LOCAL_ENABLED=$(cat .claude/settings.local.json 2>/dev/null | jq -r '.nogrep.enabled // empty')
559
+ [ -n "$LOCAL_ENABLED" ] && ENABLED="$LOCAL_ENABLED"
560
+ [ "$ENABLED" != "true" ] && exit 0
561
+
562
+ # Check index exists
563
+ [ ! -f ".nogrep/_index.json" ] && exit 0
564
+
565
+ # Extract keywords from the grep command
566
+ KEYWORDS=$(echo "$COMMAND" \
567
+ | sed -E 's/(grep|rg|ag|find)\s+(-[a-zA-Z]+\s+)*//' \
568
+ | tr -d '"'"'" \
569
+ | awk '{print $1}')
570
+
571
+ [ -z "$KEYWORDS" ] && exit 0
572
+
573
+ # Query nogrep
574
+ SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT}/dist"
575
+ RESULT=$(node "$SCRIPT_DIR/query.js" --keywords "$KEYWORDS" --format summary --limit 3 2>/dev/null)
576
+
577
+ if [ -n "$RESULT" ]; then
578
+ jq -n \
579
+ --arg ctx "⚡ nogrep — read these context files before searching:\n\n$RESULT\n\nThese files tell you exactly where to look. Only proceed with the grep if they don't answer your question." \
580
+ '{ additionalContext: $ctx }'
581
+ fi
582
+
583
+ exit 0
584
+ ```
585
+
586
+ ---
587
+
588
+ ### Hook: `session-start.sh`
589
+
590
+ Checks index freshness at session start and warns CC.
591
+
592
+ ```bash
593
+ #!/bin/bash
594
+ ENABLED=$(cat .claude/settings.json 2>/dev/null | jq -r '.nogrep.enabled // false')
595
+ LOCAL_ENABLED=$(cat .claude/settings.local.json 2>/dev/null | jq -r '.nogrep.enabled // empty')
596
+ [ -n "$LOCAL_ENABLED" ] && ENABLED="$LOCAL_ENABLED"
597
+ [ "$ENABLED" != "true" ] && exit 0
598
+
599
+ if [ ! -f ".nogrep/_index.json" ]; then
600
+ jq -n '{ additionalContext: "⚠️ nogrep is enabled but no index found. Run `/nogrep:init` to generate the codebase index before starting work." }'
601
+ exit 0
602
+ fi
603
+
604
+ SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT}/dist"
605
+ STALE=$(node "$SCRIPT_DIR/validate.js" --format json 2>/dev/null | jq -r '.stale[]?.file' | head -3)
606
+
607
+ if [ -n "$STALE" ]; then
608
+ jq -n \
609
+ --arg s "$STALE" \
610
+ '{ additionalContext: ("⚠️ nogrep index may be stale. Consider running `/nogrep:update` before starting.\nStale nodes:\n" + $s) }'
611
+ fi
612
+
613
+ exit 0
614
+ ```
615
+
616
+ ---
617
+
618
+ ### Hook: `prompt-submit.sh`
619
+
620
+ Injects relevant context nodes at the moment a user submits a prompt.
621
+
622
+ ```bash
623
+ #!/bin/bash
624
+ INPUT=$(cat)
625
+ PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty')
626
+
627
+ ENABLED=$(cat .claude/settings.json 2>/dev/null | jq -r '.nogrep.enabled // false')
628
+ LOCAL_ENABLED=$(cat .claude/settings.local.json 2>/dev/null | jq -r '.nogrep.enabled // empty')
629
+ [ -n "$LOCAL_ENABLED" ] && ENABLED="$LOCAL_ENABLED"
630
+ [ "$ENABLED" != "true" ] && exit 0
631
+ [ ! -f ".nogrep/_index.json" ] && exit 0
632
+ [ -z "$PROMPT" ] && exit 0
633
+
634
+ # Only inject for prompts that seem to be about code navigation
635
+ if ! echo "$PROMPT" | grep -qiE '(where|how|which|what|find|look|show|implement|fix|add|change|update|refactor)'; then
636
+ exit 0
637
+ fi
638
+
639
+ SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT}/dist"
640
+ RESULT=$(node "$SCRIPT_DIR/query.js" --question "$PROMPT" --format summary --limit 3 2>/dev/null)
641
+
642
+ if [ -n "$RESULT" ]; then
643
+ jq -n \
644
+ --arg ctx "📍 nogrep context for your question:\n\n$RESULT\n\nRead these files first before exploring source." \
645
+ '{ additionalContext: $ctx }'
646
+ fi
647
+
648
+ exit 0
649
+ ```
650
+
651
+ ---
652
+
653
+ ### Slash Commands
654
+
655
+ Each command file in `commands/` is a markdown prompt that guides Claude through the operation. Unlike simple shell wrappers, these are rich prompts — Claude does the AI work directly.
656
+
657
+ **`commands/init.md`** — The most important command. Contains:
658
+ - Instructions to run `node "${CLAUDE_PLUGIN_ROOT}/dist/signals.js" --root .` to collect Phase 1 data
659
+ - The Phase 2 prompt (stack detection) — Claude analyzes signals directly
660
+ - The Phase 3 prompt (cluster analysis) — Claude analyzes each cluster
661
+ - Instructions to run `node "${CLAUDE_PLUGIN_ROOT}/dist/write.js"` to generate structured output
662
+ - Instructions to patch CLAUDE.md and write settings
663
+
664
+ **`commands/update.md`** — Guides Claude through:
665
+ - Running `git diff origin/main --name-only` to find changed files
666
+ - Mapping changed files to affected nodes via `_registry.json`
667
+ - Re-analyzing affected clusters
668
+ - Running `node "${CLAUDE_PLUGIN_ROOT}/dist/write.js"` to update nodes (preserving Manual Notes)
669
+
670
+ **`commands/on.md`** — Enable nogrep:
671
+ - Run `node "${CLAUDE_PLUGIN_ROOT}/dist/settings.js" --set enabled=true`
672
+ - Check if `.nogrep/_index.json` exists
673
+ - If missing, suggest running `/nogrep:init`
674
+
675
+ **`commands/off.md`** — Disable nogrep:
676
+ - Run `node "${CLAUDE_PLUGIN_ROOT}/dist/settings.js" --set enabled=false`
677
+
678
+ **`commands/status.md`** — Show index health:
679
+ - Run `node "${CLAUDE_PLUGIN_ROOT}/dist/validate.js" --format text`
680
+ - Show node counts by category, freshness summary
681
+
682
+ **`commands/query.md`** — Manual index lookup:
683
+ - Run `node "${CLAUDE_PLUGIN_ROOT}/dist/query.js" --question "$ARGUMENTS"`
684
+
685
+ ---
686
+
687
+ ## 11. Settings
688
+
689
+ ### Resolution Order
690
+
691
+ ```
692
+ 1. .claude/settings.local.json (personal, gitignored, highest priority)
693
+ 2. .claude/settings.json (team, committed to repo)
694
+ 3. default: enabled = false
695
+ ```
696
+
697
+ ### Settings Script
698
+
699
+ `scripts/settings.ts` handles read/write of settings JSON:
700
+
701
+ ```typescript
702
+ // read: merges both files, local takes precedence
703
+ readSettings(projectRoot: string): { enabled: boolean }
704
+
705
+ // write: writes to settings.json by default, settings.local.json with --local flag
706
+ writeSettings(projectRoot: string, settings: { enabled?: boolean }, local?: boolean): void
707
+ ```
708
+
709
+ ---
710
+
711
+ ## 12. CI Integration
712
+
713
+ Out of scope for v1. The index is maintained via `/nogrep:update` during CC sessions. CI support (validation, auto-update) is a future concern.
714
+
715
+ ---
716
+
717
+ ## 13. Prompts (Embedded in Slash Commands)
718
+
719
+ These prompts are embedded in `commands/init.md` and `commands/update.md`. Claude executes them directly — no separate API calls.
720
+
721
+ ### Phase 2 — Stack Detection Prompt
722
+
723
+ ```
724
+ Analyze this project's signals and return JSON only. No prose, no markdown fences.
725
+
726
+ ## Directory tree:
727
+ {directory_tree}
728
+
729
+ ## Dependency manifests:
730
+ {manifests}
731
+
732
+ ## File extension distribution:
733
+ {extension_map}
734
+
735
+ ## Entry point candidates:
736
+ {entry_points}
737
+
738
+ Return this exact shape:
739
+ {
740
+ "primary_language": "typescript",
741
+ "frameworks": ["nestjs", "react"],
742
+ "architecture": "monolith", // or "monorepo", "multi-repo", "microservice", "library"
743
+ "domain_clusters": [
744
+ { "name": "billing", "path": "src/billing/", "confidence": 0.95 }
745
+ ],
746
+ "conventions": {
747
+ "entry_pattern": "*.module.ts",
748
+ "test_pattern": "*.spec.ts",
749
+ "config_location": "src/config/"
750
+ },
751
+ "stack_hints": "NestJS: *.module.ts = module boundary, *.service.ts = business logic, *.controller.ts = HTTP handlers",
752
+ "dynamic_taxonomy": {
753
+ "domain": ["billing", "auth", "users"],
754
+ "tech": ["stripe", "redis", "postgres"]
755
+ }
756
+ }
757
+ ```
758
+
759
+ ---
760
+
761
+ ### Phase 3 — Context Node Generation Prompt
762
+
763
+ ```
764
+ You are generating a navigation node for an AI coding agent.
765
+ Nodes must be MINIMAL — the agent uses them to decide WHERE to look, not to understand everything.
766
+
767
+ ## Project stack:
768
+ {stack_json}
769
+
770
+ ## Stack reading hints:
771
+ {stack_hints}
772
+
773
+ ## Source files (trimmed to signatures only):
774
+ {trimmed_source}
775
+
776
+ ## Allowed tags (use ONLY these exact values — never invent new ones):
777
+ {taxonomy_json}
778
+
779
+ Generate a context node. Return JSON only, no prose, no markdown fences.
780
+
781
+ {
782
+ "purpose": "2-3 sentences MAX. Business intent, not technical description.",
783
+ "public_surface": ["list of exported functions/routes/events other domains use"],
784
+ "does_not_own": ["what this module delegates elsewhere, with → target domain"],
785
+ "external_deps": [{"name": "stripe", "usage": "payment processing"}],
786
+ "tags": {
787
+ "domain": [],
788
+ "layer": [],
789
+ "tech": [],
790
+ "concern": [],
791
+ "type": []
792
+ },
793
+ "keywords": ["terms a developer would search to find this domain"],
794
+ "gotchas": ["max 5 non-obvious behaviors, footguns, or constraints"]
795
+ }
796
+
797
+ Rules:
798
+ - purpose: max 3 sentences
799
+ - gotchas: max 5 items
800
+ - keywords: 5-15 items, think about what words someone would grep for
801
+ - tags: use taxonomy values only, never invent new tag values
802
+ - does_not_own: include explicit redirections ("email delivery → notifications")
803
+ ```