@neat.is/claude-skill 0.5.2 → 0.5.3

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.
package/GRAPH_FIRST.md ADDED
@@ -0,0 +1,35 @@
1
+ <!-- NEAT graph-first guidance. Paste this block into your agent's project
2
+ instructions — CLAUDE.md, AGENTS.md, .cursorrules, or the equivalent —
3
+ so the agent reaches for NEAT's graph before scanning files by hand.
4
+ Agent-agnostic: it is plain guidance, no Claude Code features required. -->
5
+
6
+ ## Reach for NEAT's graph before grepping
7
+
8
+ This project has NEAT wired in. NEAT keeps a live semantic graph of the system —
9
+ code, infrastructure, and runtime behaviour fused into one model — reachable over
10
+ MCP (and a REST API). Every edge carries provenance: `EXTRACTED` from source,
11
+ `OBSERVED` from OpenTelemetry, `INFERRED` where the trace stitcher bridges a gap,
12
+ `STALE` when runtime goes quiet — so you know how much to trust each answer.
13
+
14
+ When you need to understand this codebase, query the graph first. It is usually
15
+ faster and more accurate than `grep`/`glob`/`find`, and it can tell you what the
16
+ system *actually does at runtime*, not only what the source declares.
17
+
18
+ Reach for these MCP tools before raw text search:
19
+
20
+ - `semantic_search` — find code/nodes by a natural-language description.
21
+ - `get_dependencies` — a node's transitive outgoing dependencies (declared, `EXTRACTED`).
22
+ - `get_observed_dependencies` — only what a node calls *in production* (`OBSERVED` via OTel).
23
+ - `get_divergences` — where the code (`EXTRACTED`) and production (`OBSERVED`) disagree.
24
+ The most NEAT-shaped query; reach for it on "is anything weird here?"
25
+ - `get_root_cause` — trace a failing node up its dependency graph to the culprit.
26
+ - `get_blast_radius` — everything downstream of a node: what breaks if it changes or fails.
27
+ - `get_incident_history` — recent OTel error events recorded against a node.
28
+ - `check_policies` — the project's `policy.json` violations, actual or hypothetical.
29
+
30
+ Text search is still a fine fallback. If the graph does not have what you need —
31
+ comments, string literals, config minutiae, a file NEAT does not model — go ahead
32
+ and `grep`. The point is order: ask the graph first, then fall back to scanning.
33
+
34
+ If the tools are not available, the NEAT daemon may not be running (`neatd status`)
35
+ or the MCP server may not be wired in (`neat skill --apply`).
package/README.md CHANGED
@@ -6,9 +6,13 @@ See [SKILL.md](./SKILL.md) for the tool list, install steps, and prerequisites.
6
6
 
7
7
  The shipped artifact is `claude_code_config.json` — a single object you merge into your `~/.claude.json` under `mcpServers.neat`. The `neat skill` CLI verb (in `@neat.is/core`) handles the merge for you.
8
8
 
9
+ Alongside the MCP config, this package ships the affordances that make an agent reach for the graph before it grep-scans a repo: a Claude Code search-nudge `PreToolUse` hook (`hooks/neat-search-nudge.mjs`) and agent-agnostic graph-first guidance (`GRAPH_FIRST.md`). `neat hooks --apply` installs both. See [SKILL.md](./SKILL.md#reach-for-the-graph-first).
10
+
9
11
  ## Files
10
12
 
11
13
  - `claude_code_config.json` — the MCP server snippet
14
+ - `hooks/neat-search-nudge.mjs` — the Claude Code search-nudge PreToolUse hook
15
+ - `GRAPH_FIRST.md` — agent-agnostic graph-first guidance to paste into project instructions
12
16
  - `SKILL.md` — what the skill exposes and how to install
13
17
  - `package.json` — workspace metadata; this package ships no compiled code
14
18
 
package/SKILL.md CHANGED
@@ -69,6 +69,42 @@ neat skill --apply
69
69
 
70
70
  This merges the `neat` server into `~/.claude.json` without touching other entries.
71
71
 
72
+ ## Reach for the graph first
73
+
74
+ Wiring the tools in is half the job; the other half is getting your agent to
75
+ *use* them instead of falling straight to text search. NEAT ships two nudges:
76
+
77
+ ```bash
78
+ neat hooks --apply
79
+ ```
80
+
81
+ That installs both:
82
+
83
+ 1. **A Claude Code search-nudge hook.** A `PreToolUse` hook (materialised to
84
+ `~/.neat/hooks/neat-search-nudge.mjs`, wired into `~/.claude/settings.json`)
85
+ that fires when the agent reaches for `Grep`, `Glob`, or a Bash
86
+ `grep`/`rg`/`find`. It injects a short note steering the agent to
87
+ `semantic_search` / `get_dependencies` / `get_divergences` first. It is a
88
+ **gentle, non-blocking nudge** — the search still runs; the agent just sees
89
+ the graph as the better first move. Your existing hooks are left in place,
90
+ and re-running is idempotent.
91
+
92
+ 2. **Agent-agnostic graph-first guidance** (`GRAPH_FIRST.md`, also written to
93
+ `~/.neat/neat-graph-first.md`). A markdown block you paste into your project
94
+ instructions — `CLAUDE.md`, `AGENTS.md`, `.cursorrules`, whatever your agent
95
+ reads — so the same "ask the graph before grepping" steer reaches agents on
96
+ any harness.
97
+
98
+ The hook is Claude-Code-specific; agents on other harnesses (Codex, Gemini,
99
+ Cursor, …) don't get the `PreToolUse` interception, but the guidance block
100
+ gives them the same instruction. Preview either without installing:
101
+
102
+ ```bash
103
+ neat hooks --print-hook # the hook script
104
+ neat hooks --print-guide # the graph-first guidance
105
+ neat hooks --print-settings # the settings.json block --apply merges
106
+ ```
107
+
72
108
  ## Prerequisites
73
109
 
74
110
  - `neat init <repo>` has registered at least one project.
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ // NEAT search-nudge — a Claude Code PreToolUse hook.
3
+ //
4
+ // When the agent reaches for raw text search — the Grep or Glob tools, or a
5
+ // Bash command that shells out to grep / rg / ag / ack / find / fd — this hook
6
+ // injects a short note suggesting NEAT's graph tools first. NEAT already holds
7
+ // this project's structure, dependencies, and runtime behaviour, so a graph
8
+ // query is usually faster and more accurate than scanning files by hand.
9
+ //
10
+ // It is a NUDGE, not a gate. The hook only ever adds context; it never denies
11
+ // the call and always exits 0, so the search runs regardless. Anything that is
12
+ // not a text search is a silent no-op.
13
+ //
14
+ // Wired by `neat hooks --apply`, which copies this script under ~/.neat/hooks/
15
+ // and adds a PreToolUse entry to ~/.claude/settings.json. The hook itself is
16
+ // Claude-Code-specific; agents on other harnesses get the same steer from the
17
+ // graph-first guidance NEAT ships instead (see `neat hooks --print-guide`).
18
+ //
19
+ // This file is a documentation copy. The source of truth is NEAT_SEARCH_HOOK
20
+ // in @neat.is/core (packages/core/src/hooks-cli.ts); a contract test keeps the
21
+ // two byte-aligned.
22
+
23
+ import process from 'node:process'
24
+
25
+ // grep-family and file-finder binaries. Matched at a word boundary so a path
26
+ // like agent.ts does not trip it, and after a shell separator so the binary in
27
+ // a pipe (... | grep foo) still counts.
28
+ const SEARCH_BINARY = /(?:^|[\s|;&(){}])(?:grep|egrep|fgrep|rg|ripgrep|ag|ack|find|fd)(?=\s|$)/
29
+
30
+ function bashLooksLikeSearch(command) {
31
+ return typeof command === 'string' && SEARCH_BINARY.test(command)
32
+ }
33
+
34
+ function nudge(toolName) {
35
+ return [
36
+ 'NEAT is wired into this project — its live graph already knows this codebase',
37
+ 'structure, dependencies, and runtime behaviour. Before leaning on ' + toolName + ', consider',
38
+ 'asking the graph over MCP; it answers with structured, provenance-tagged results',
39
+ 'rather than line matches:',
40
+ '',
41
+ ' - semantic_search — find code/nodes by a natural-language description',
42
+ ' - get_dependencies / get_observed_dependencies — what a thing calls, as declared',
43
+ ' in code (EXTRACTED) vs. what it actually calls in production (OBSERVED)',
44
+ ' - get_divergences — where the code and production disagree',
45
+ ' - get_root_cause / get_blast_radius — trace a failure, or a change reach',
46
+ '',
47
+ 'Text search is still a fine fallback — go ahead and run it if the graph does not',
48
+ 'have what you need.',
49
+ ].join('\n')
50
+ }
51
+
52
+ function readStdin() {
53
+ return new Promise((resolve) => {
54
+ let data = ''
55
+ process.stdin.setEncoding('utf8')
56
+ process.stdin.on('data', (chunk) => {
57
+ data += chunk
58
+ })
59
+ process.stdin.on('end', () => resolve(data))
60
+ process.stdin.on('error', () => resolve(data))
61
+ })
62
+ }
63
+
64
+ const raw = await readStdin()
65
+
66
+ let payload
67
+ try {
68
+ payload = JSON.parse(raw)
69
+ } catch {
70
+ // No parseable payload — nothing to nudge about. Let the call proceed.
71
+ process.exit(0)
72
+ }
73
+
74
+ const toolName = typeof payload?.tool_name === 'string' ? payload.tool_name : ''
75
+ const toolInput = payload?.tool_input ?? {}
76
+
77
+ let isSearch = false
78
+ if (toolName === 'Grep' || toolName === 'Glob') isSearch = true
79
+ else if (toolName === 'Bash') isSearch = bashLooksLikeSearch(toolInput.command)
80
+
81
+ if (!isSearch) process.exit(0)
82
+
83
+ process.stdout.write(
84
+ JSON.stringify({
85
+ hookSpecificOutput: {
86
+ hookEventName: 'PreToolUse',
87
+ additionalContext: nudge(toolName),
88
+ },
89
+ }),
90
+ )
91
+ process.exit(0)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neat.is/claude-skill",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Claude Code skill drop-in for NEAT — wires the @neat.is/mcp server into Claude's MCP config",
5
5
  "license": "BUSL-1.1",
6
6
  "homepage": "https://neat.is",
@@ -18,7 +18,9 @@
18
18
  "files": [
19
19
  "README.md",
20
20
  "SKILL.md",
21
- "claude_code_config.json"
21
+ "GRAPH_FIRST.md",
22
+ "claude_code_config.json",
23
+ "hooks/neat-search-nudge.mjs"
22
24
  ],
23
25
  "scripts": {
24
26
  "test": "vitest run --passWithNoTests",