memtrace 0.3.10 → 0.3.12

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/README.md CHANGED
@@ -297,6 +297,27 @@ Already ran `npm uninstall` first? The cleanup script is persisted at `~/.memtra
297
297
  node ~/.memtrace/uninstall.js
298
298
  ```
299
299
 
300
+ ### A note on install
301
+
302
+ `npm install -g memtrace` ships a small main package + a platform-specific binary (one of `@memtrace/darwin-arm64`, `@memtrace/linux-x64`, or `@memtrace/win32-x64`) that npm picks automatically.
303
+
304
+ Most setups just work. If `memtrace start` ever says **"Could not find binary for your platform"**, any of these will fix it:
305
+
306
+ ```bash
307
+ # Option 1 — re-run install, asking npm to keep optional deps
308
+ npm install -g memtrace --include=optional
309
+
310
+ # Option 2 — refresh from latest
311
+ memtrace install # built-in self-update
312
+ # or:
313
+ npm install -g memtrace@latest --force
314
+
315
+ # Option 3 — install the platform binary directly (Apple Silicon shown — swap for your platform)
316
+ npm install -g @memtrace/darwin-arm64
317
+ ```
318
+
319
+ This typically only happens on machines where npm is configured to skip optional dependencies (some corporate npmrc setups, certain CI caches). Postinstall self-heals on most installs; the options above cover the rest.
320
+
300
321
  ## Languages
301
322
 
302
323
  Rust · Go · TypeScript · JavaScript · Python · Java · C · C++ · C# · Swift · Kotlin · Ruby · PHP · Dart · Scala · Perl — and more via Tree-sitter.
package/bin/memtrace.js CHANGED
@@ -13,6 +13,64 @@ const { getBinaryPath } = require("../install.js");
13
13
 
14
14
  const args = process.argv.slice(2);
15
15
 
16
+ // ── Handle `memtrace install` — always pull latest, then run remaining args ──
17
+ //
18
+ // `npm install -g memtrace` fetches latest from the registry on a fresh
19
+ // install, but a user who already has memtrace 0.3.4 globally will not
20
+ // receive 0.3.5 unless they explicitly re-run `npm install`. This
21
+ // subcommand runs the upgrade for them and then chains to whatever
22
+ // command they actually wanted: `memtrace install start` upgrades AND
23
+ // boots the daemon; `memtrace install index .` upgrades AND indexes.
24
+ //
25
+ // We use `spawnSync` so output streams in real time. After the npm
26
+ // upgrade completes, we shell out to `memtrace <rest>` via PATH —
27
+ // which now resolves to the freshly-installed shim, not this old one.
28
+
29
+ if (args[0] === "install" || args[0] === "update" || args[0] === "upgrade") {
30
+ const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
31
+ const memtraceCmd = process.platform === "win32" ? "memtrace.cmd" : "memtrace";
32
+
33
+ process.stdout.write("memtrace: fetching latest from npm registry…\n");
34
+ const installResult = spawnSync(
35
+ npmCmd,
36
+ ["install", "-g", "memtrace@latest"],
37
+ { stdio: "inherit", env: process.env }
38
+ );
39
+
40
+ if (installResult.error) {
41
+ console.error(
42
+ `memtrace install: failed to spawn npm — ${installResult.error.message}\n` +
43
+ `Is npm on your PATH? Try: which npm`
44
+ );
45
+ process.exit(1);
46
+ }
47
+ if (installResult.status !== 0) {
48
+ console.error("memtrace install: npm install -g memtrace@latest failed");
49
+ process.exit(installResult.status ?? 1);
50
+ }
51
+
52
+ const rest = args.slice(1);
53
+ if (rest.length === 0) {
54
+ process.stdout.write("memtrace: latest installed.\n");
55
+ process.exit(0);
56
+ }
57
+
58
+ // Chain into the upgraded binary. PATH now resolves `memtrace` to the
59
+ // newly-installed shim, so we get the latest behaviour for free.
60
+ process.stdout.write(
61
+ `memtrace: upgrade complete — running 'memtrace ${rest.join(" ")}'\n`
62
+ );
63
+ const runResult = spawnSync(memtraceCmd, rest, {
64
+ stdio: "inherit",
65
+ env: process.env,
66
+ });
67
+ if (runResult.error) {
68
+ console.error(`memtrace: failed to chain command — ${runResult.error.message}`);
69
+ process.exit(1);
70
+ }
71
+ process.exit(runResult.status ?? 0);
72
+ }
73
+
16
74
  if (args[0] === "uninstall" || args[0] === "cleanup") {
17
75
  const candidates = [
18
76
  path.join(__dirname, "..", "uninstall.js"),
@@ -106,22 +164,26 @@ function checkForUpdate(currentVersion) {
106
164
  });
107
165
  }
108
166
 
109
- // ── MCP mode: async spawn so the event loop stays alive for the update check ─
167
+ // ── Fire the (cached) update check in the background, regardless of mode ────
168
+ // Cache lives in ~/.memtrace/update-check.json with a 24 h TTL, so we hit
169
+ // registry.npmjs.org at most once per day per user. Result is printed to
170
+ // stderr when a newer version exists. The check is non-blocking and never
171
+ // fails the user's command.
172
+
173
+ const { version: currentVersion } = require("../package.json");
174
+ const updateCheckPromise = checkForUpdate(currentVersion).then((latest) => {
175
+ if (latest) {
176
+ process.stderr.write(
177
+ `\n[memtrace] Update available: ${currentVersion} → ${latest}\n` +
178
+ ` Run: \x1b[1mmemtrace install\x1b[0m ` +
179
+ `(upgrades + can chain commands, e.g. \`memtrace install start\`)\n\n`
180
+ );
181
+ }
182
+ });
110
183
 
111
184
  if (args[0] === "mcp") {
112
- const { version: currentVersion } = require("../package.json");
113
-
114
- // Fire the update check in the background — result prints to stderr if newer
115
- checkForUpdate(currentVersion).then((latest) => {
116
- if (latest) {
117
- process.stderr.write(
118
- `\n[memtrace] Update available: ${currentVersion} → ${latest}\n` +
119
- ` Run: npm install -g memtrace\n\n`
120
- );
121
- }
122
- });
123
-
124
- // Use async spawn (not spawnSync) so Node's event loop keeps running
185
+ // MCP mode: async spawn so Node's event loop keeps running long enough
186
+ // for the update check to print its notice to the agent's stderr.
125
187
  const child = spawn(binaryPath, args, {
126
188
  stdio: "inherit",
127
189
  env: process.env,
@@ -136,8 +198,10 @@ if (args[0] === "mcp") {
136
198
  });
137
199
 
138
200
  } else {
139
- // ── All other commands: synchronous pass-through ────────────────────────────
140
-
201
+ // All other commands: synchronous pass-through. The update check
202
+ // already fired above; cache write happens in the background and we
203
+ // don't block on it (the http GET timeout is 3 s, well under any
204
+ // reasonable user-visible startup budget).
141
205
  const result = spawnSync(binaryPath, args, {
142
206
  stdio: "inherit",
143
207
  env: process.env,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memtrace",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "Code intelligence graph — MCP server + AI agent skills + visualization UI",
5
5
  "keywords": [
6
6
  "mcp",
@@ -36,9 +36,9 @@
36
36
  "fs-extra": "^11.0.0"
37
37
  },
38
38
  "optionalDependencies": {
39
- "@memtrace/darwin-arm64": "0.3.10",
40
- "@memtrace/linux-x64": "0.3.10",
41
- "@memtrace/win32-x64": "0.3.10"
39
+ "@memtrace/darwin-arm64": "0.3.12",
40
+ "@memtrace/linux-x64": "0.3.12",
41
+ "@memtrace/win32-x64": "0.3.12"
42
42
  },
43
43
  "engines": {
44
44
  "node": ">=18"
@@ -1,42 +1,32 @@
1
1
  ---
2
2
  name: memtrace-graph
3
- description: "Use when the user asks about architectural bottlenecks, important symbols, PageRank, centrality, bridge functions, code communities, logical modules, service boundaries, chokepoints, or wants to understand the high-level architecture of a codebase"
3
+ description: "Use when the user asks about architectural bottlenecks, important symbols, PageRank, centrality, bridge functions, code communities, logical modules, service boundaries, chokepoints, dependency paths between symbols, or wants to understand the high-level architecture of a codebase"
4
4
  allowed-tools:
5
5
  - mcp__memtrace__find_bridge_symbols
6
6
  - mcp__memtrace__find_central_symbols
7
+ - mcp__memtrace__find_dependency_path
7
8
  - mcp__memtrace__list_communities
8
9
  - mcp__memtrace__list_processes
9
10
  - mcp__memtrace__get_process_flow
10
- - mcp__memtrace__execute_cypher
11
11
  user-invocable: true
12
12
  ---
13
13
 
14
14
  ## Overview
15
15
 
16
- Graph algorithms that reveal the structural architecture of a codebase — community detection (Louvain), centrality ranking (PageRank/degree), bridge symbol identification (betweenness), and execution flow tracing.
16
+ Graph algorithms that reveal the structural architecture of a codebase — community detection (Louvain), centrality ranking (PageRank), bridge symbol identification (Tarjan articulation points), shortest-path discovery, and execution flow tracing.
17
+
18
+ All four algorithm tools (`find_central_symbols`, `find_bridge_symbols`, `find_dependency_path`, `list_communities`) run natively against the MemDB-backed knowledge graph — no Cypher required.
17
19
 
18
20
  ## Quick Reference
19
21
 
20
22
  | Tool | Purpose |
21
23
  |------|---------|
22
- | `find_bridge_symbols` | Architectural chokepoints — symbols that connect otherwise-separate modules |
23
- | `find_central_symbols` | Most important symbols (PageRank via ArcadeDB `algo.pagerank`) |
24
+ | `find_bridge_symbols` | Architectural chokepoints — symbols whose removal disconnects the graph (Tarjan articulation points) |
25
+ | `find_central_symbols` | Most important symbols by **PageRank** (default) or degree centrality |
26
+ | `find_dependency_path` | Shortest call/import path between two symbols (BFS over typed edges) |
24
27
  | `list_communities` | Louvain-detected logical modules/services |
25
28
  | `list_processes` | Execution flows: HTTP handlers, background jobs, CLI commands, event handlers |
26
29
  | `get_process_flow` | Trace a single process step-by-step |
27
- | `execute_cypher` | Direct read-only Cypher queries for custom analysis |
28
-
29
- ## Parameter Types — Read This First
30
-
31
- All memtrace MCP tools are **strictly typed**. Numbers must be JSON numbers, not strings.
32
-
33
- | Parameter shape | Correct | Wrong (will fail deserialization) |
34
- |-----------------|---------|-----------------------------------|
35
- | Integer/count (`limit`, `min_size`, `depth`) | `limit: 20` | `limit: "20"` |
36
- | String identifier (`repo_id`, `branch`, `name`) | `repo_id: "my-repo"` | `repo_id: my-repo` |
37
- | Boolean (`fuzzy`, `include_tests`) | `fuzzy: true` | `fuzzy: "true"` |
38
-
39
- If you see `MCP error -32602: invalid type: string "N", expected usize`, you passed a string where a number was required. Remove the quotes.
40
30
 
41
31
  ## Steps
42
32
 
@@ -44,77 +34,42 @@ If you see `MCP error -32602: invalid type: string "N", expected usize`, you pas
44
34
 
45
35
  Start with `list_communities` to see how the codebase is naturally partitioned into logical modules. Each community has a name, member count, and representative symbols.
46
36
 
47
- **`list_communities` parameters:**
48
- - `repo_id` — string, required. Repository ID (from `list_indexed_repositories`).
49
- - `branch` — string, optional. Defaults to `"main"`.
50
- - `min_size` — **integer**, optional. Minimum community size to include. Default `3`.
51
- - `limit` — **integer**, optional. Max communities to return. Default `50`, capped at `200`.
52
-
53
- Example (correct):
54
- ```json
55
- { "repo_id": "Memtrace", "limit": 20 }
56
- ```
57
- Example (WRONG — will fail):
58
- ```json
59
- { "repo_id": "Memtrace", "limit": "20" }
60
- ```
61
-
62
37
  ### 2. Find critical infrastructure
63
38
 
64
39
  Use `find_central_symbols` to identify the most important symbols:
40
+ - `method: "pagerank"` — importance by link structure (default; same algorithm Google uses)
41
+ - `method: "degree"` — importance by direct connection count
42
+ - `limit` — how many to return
65
43
 
66
- **`find_central_symbols` parameters:**
67
- - `repo_id` — string, required.
68
- - `branch` — string, optional. Defaults to `"main"`.
69
- - `limit` — **integer**, optional. How many to return. Default `20`, capped at `100`.
70
-
71
- Returns the top-N symbols ranked by **PageRank** (ArcadeDB's native `algo.pagerank` procedure). Filters the global run to Function/Method/Class/Interface/Struct in the requested repo + branch. Falls back to in-degree centrality only if the native procedure isn't registered on the connected ArcadeDB build.
44
+ The PageRank pass walks every CALLS / REFERENCES edge in the repo, distributes rank with the standard 0.85 damping factor, and converges on a stable ordering. The output is sorted by score descending, with each entry carrying `name`, `kind`, `file_path`, `score`, and the `in_degree`/`out_degree` it accumulated during the walk.
72
45
 
73
46
  ### 3. Find architectural chokepoints
74
47
 
75
- Use `find_bridge_symbols` to find symbols that, if removed, would disconnect parts of the graph. These are:
48
+ Use `find_bridge_symbols` to find symbols that, if removed, would disconnect parts of the graph (Tarjan articulation points). These are:
76
49
  - **Single points of failure** — if they break, cascading failures occur
77
50
  - **Integration points** — good places for interfaces/contracts
78
51
  - **Refactoring targets** — often too much responsibility concentrated in one place
79
52
 
80
- **`find_bridge_symbols` parameters:**
81
- - `repo_id` — string, required.
82
- - `branch` — string, optional. Defaults to `"main"`.
83
- - `limit` — **integer**, optional. Default `15`, capped at `50`.
53
+ ### 4. Discover the path between two symbols
84
54
 
85
- Ranks symbols by **betweenness centrality** (ArcadeDB's native `algo.betweenness` with `normalized: true`)how many shortest paths between other symbols pass through each one. Falls back to an in-degree × out-degree heuristic only if the native procedure isn't registered.
55
+ Use `find_dependency_path` to answer "how does symbol A reach symbol B?"returns the shortest call/import chain via BFS over typed edges. Useful for:
56
+ - "Why does the auth handler depend on the database client?"
57
+ - "How does this CLI command reach the logging subsystem?"
58
+ - "Confirm symbol X actually transitively depends on Y."
86
59
 
87
- ### 4. Trace execution flows
60
+ ### 5. Trace execution flows
88
61
 
89
62
  Use `list_processes` to see all entry points (HTTP handlers, background jobs, CLI commands, event handlers).
90
63
 
91
- **`list_processes` parameters:**
92
- - `repo_id` — string, required.
93
- - `branch` — string, optional. Defaults to `"main"`.
94
- - `limit` — **integer**, optional. Default `50`.
95
-
96
- Use `get_process_flow` with a process name to trace a specific flow step-by-step — shows the full call chain from entry point through business logic to data access.
97
-
98
- **`get_process_flow` parameters:**
99
- - `process` — string, required. Process name or entry-point symbol name (from `list_processes`).
100
- - `repo_id` — string, required.
101
- - `branch` — string, optional. Defaults to `"main"`.
102
-
103
- ### 5. Custom queries
104
-
105
- Use `execute_cypher` for advanced graph queries not covered by built-in tools. This is read-only and runs directly against the knowledge graph.
106
-
107
- **`execute_cypher` parameters:**
108
- - `query` — string, required. A read-only Cypher query. Write keywords (CREATE, MERGE, DELETE, SET, etc.) are forbidden. Use `$repo_id` to scope to a repository.
109
- - `params` — object, optional. JSON object of parameter bindings.
110
- - `repo_id` — string, optional. If provided, injected as `$repo_id` into `params`.
64
+ Use `get_process_flow` with a process name to trace a specific flow step-by-step — shows the full call chain from entry point through business logic to data access, ordered by the indexed `step` property on each STEP_IN_PROCESS edge.
111
65
 
112
66
  ## Decision Points
113
67
 
114
68
  | Question | Tool |
115
69
  |----------|------|
116
70
  | "What are the main modules?" | `list_communities` |
117
- | "What are the most important functions?" | `find_central_symbols` (PageRank, native) |
71
+ | "What are the most important functions?" | `find_central_symbols` with method=pagerank |
118
72
  | "Where are the bottlenecks?" | `find_bridge_symbols` |
73
+ | "How does symbol A reach symbol B?" | `find_dependency_path` |
119
74
  | "How does a request flow through the system?" | `list_processes` → `get_process_flow` |
120
75
  | "What's the entry point for feature X?" | `list_processes`, then filter by name |
@@ -50,7 +50,7 @@ Each community represents a cohesive module — these are the "areas" of the cod
50
50
 
51
51
  ### 4. Find the most important symbols
52
52
 
53
- Call `find_central_symbols` with `limit: 15`. It ranks symbols by PageRank (ArcadeDB's native `algo.pagerank`) no extra parameter needed.
53
+ Call `find_central_symbols` with `limit: 15`. It ranks symbols by PageRank over the repo's CALLS / REFERENCES edges (default `method: "pagerank"`, 0.85 damping factor).
54
54
 
55
55
  These are the symbols that the rest of the codebase depends on most heavily. They form the "skeleton" of the architecture.
56
56
 
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: memtrace-continuous-memory
3
+ description: "Use when the user asks to keep memtrace fresh while editing, watch a directory for live updates, enable incremental indexing, set up always-on memory, or wants their just-saved code to be queryable immediately"
4
+ allowed-tools:
5
+ - mcp__memtrace__watch_directory
6
+ - mcp__memtrace__list_watched_paths
7
+ - mcp__memtrace__unwatch_directory
8
+ - mcp__memtrace__index_directory
9
+ - mcp__memtrace__list_indexed_repositories
10
+ - mcp__memtrace__check_job_status
11
+ user-invocable: true
12
+ ---
13
+
14
+ ## Overview
15
+
16
+ Memtrace keeps the knowledge graph live as you edit. Once you call `watch_directory`, every save runs through the **incremental indexing fast-path** — a notify-based file watcher debounces saves, the indexer re-parses only the touched files, and the engine commits the delta in a single WAL transaction. Steady-state latency is **~80 ms from save to queryable** on a typical project.
17
+
18
+ This is what makes "session continuity" actually work: by the time you ask `find_symbol` after a save, the new symbol is already in the graph.
19
+
20
+ ## Steps
21
+
22
+ ### 1. Confirm the repo is indexed
23
+
24
+ ```
25
+ mcp__memtrace__list_indexed_repositories
26
+ ```
27
+
28
+ If the repo isn't there, run `index_directory` first. The watcher requires an existing repo_id — it never bootstraps from scratch.
29
+
30
+ ### 2. Start watching
31
+
32
+ ```
33
+ mcp__memtrace__watch_directory(
34
+ path: "/abs/path/to/repo"
35
+ )
36
+ ```
37
+
38
+ The tool registers a `notify` watcher on the directory tree, debounces save bursts (so a `:wq` that touches a swap file doesn't trigger twice), and routes deltas through the indexer's incremental fast-path. Returns immediately — watching runs in the background.
39
+
40
+ ### 3. Confirm it's live
41
+
42
+ ```
43
+ mcp__memtrace__list_watched_paths
44
+ ```
45
+
46
+ Each entry shows the watched root, the bound repo_id, and the last delta's `persist_ms`.
47
+
48
+ ### 4. Edit normally — Memtrace catches up
49
+
50
+ After every save the watcher emits a `labels_updated` WebSocket event:
51
+
52
+ ```json
53
+ {
54
+ "event": "labels_updated",
55
+ "repo_id": "demo",
56
+ "nodes_changed": 12,
57
+ "persist_ms": 78,
58
+ "timestamp": "2026-04-27T10:42:13Z"
59
+ }
60
+ ```
61
+
62
+ Dashboards and IDE plugins subscribe to this on `/ws` and refresh themselves. As an agent you don't have to listen — your next `find_symbol` / `find_code` / `get_symbol_context` call will see the new state automatically.
63
+
64
+ ### 5. Stop watching
65
+
66
+ ```
67
+ mcp__memtrace__unwatch_directory(path: "/abs/path/to/repo")
68
+ ```
69
+
70
+ Idempotent — unwatching an already-unwatched path is a no-op.
71
+
72
+ ## When to Use
73
+
74
+ - **Long sessions on the same repo** — keeps `get_symbol_context` accurate without rerunning `index_directory`
75
+ - **Pair programming with an IDE plugin** — the dashboard's WebSocket subscription auto-refreshes panels
76
+ - **Demo / live coding** — every save reflects in the graph within 80–150 ms
77
+ - **Long-running agents** — instead of polling `index_directory`, the watcher pushes deltas
78
+
79
+ ## When NOT to Use
80
+
81
+ - **One-shot batch edits** — running `index_directory --incremental` at the end is cheaper than spinning up a watcher
82
+ - **Generated / build output trees** — exclude paths under `target/`, `dist/`, `node_modules/` (the watcher honours common ignore patterns but a noisy build can still saturate the debounce queue)
83
+ - **CI / containerised runs** — file events are unreliable across container boundaries; index explicitly instead
84
+
85
+ ## Latency Expectations
86
+
87
+ | Operation | Typical wall time |
88
+ |---|---|
89
+ | File save → watcher fires | < 5 ms |
90
+ | Debounce window | 50 ms |
91
+ | Incremental parse + delta persist | ~80 ms |
92
+ | `labels_updated` broadcast | < 1 ms after persist |
93
+ | Total: save → queryable | ~80–150 ms |
94
+
95
+ If you see `persist_ms` consistently above 500 ms, the saved files are larger than expected (e.g., generated bundles) — narrow the watch root or add ignore patterns.
96
+
97
+ ## Common Mistakes
98
+
99
+ | Mistake | Reality |
100
+ |---|---|
101
+ | Calling `watch_directory` on an unindexed repo | Returns an error — run `index_directory` first |
102
+ | Watching `node_modules/` or `target/` | Saturates the watcher with build noise — point at the source root only |
103
+ | Polling `find_symbol` every second to "wait" for indexing | Subscribe to the `labels_updated` WS event, or just call once after the save — the delta is already there |
104
+ | Forgetting to `unwatch_directory` between sessions | Watchers are per-process; restarting `memtrace start` wipes them, but for hosted instances unwatching cleanly avoids leaks |
@@ -9,12 +9,46 @@ description: "Use when working on any indexed codebase before searching files, r
9
9
 
10
10
  ```
11
11
  IF THE REPO IS INDEXED IN MEMTRACE → USE MEMTRACE TOOLS FIRST.
12
- NEVER reach for Grep/Glob/Read to discover or understand code.
12
+ Memtrace returns exact file_path + start_line + end_line for every result.
13
+ Read the file at THAT location. Do not Grep/Glob/Find to "locate" anything
14
+ already in the graph.
13
15
  ```
14
16
 
15
17
  Memtrace is the memory layer of the codebase. It has the full knowledge graph: every symbol, call, import, community, process, and API — with time dimension. File tools are blind to this structure.
16
18
 
17
- **97% better accuracy. 83% fewer wasted tokens. No exceptions.**
19
+ **97% better accuracy. 83% fewer wasted tokens. No exceptions for what's in the graph.**
20
+
21
+ ## What Memtrace actually indexes
22
+
23
+ Memtrace's hybrid search = **BM25 over symbol metadata** (name, signature, file_path, kind) **+ semantic vector search over embedded code bodies** (first ~1500 chars of every Function / Method / Class / Struct / Interface body), fused via Reciprocal Rank Fusion.
24
+
25
+ The semantic side means **string literals, error messages, magic constants, log strings, and any text inside an indexed symbol's body are findable through `find_code`**. The body got embedded; the embedding catches it. You do NOT need `Grep` to hunt for `STRIPE_KEY_FOO_BAR` if it lives inside a function in your indexed codebase.
26
+
27
+ ## The narrow exceptions where grep/glob are still right
28
+
29
+ These are the ONLY cases where file tools beat memtrace:
30
+
31
+ - **Files outside the indexed repo.** Vendored deps, system headers, dirs `walker::is_excluded_path` skipped (`.git`, `node_modules`, `target`, `dist`). Memtrace literally cannot see them.
32
+ - **Non-source artifacts.** `.env`, `package.json`, build scripts, top-level `README.md`, raw config files. Memtrace indexes parseable code, not configuration text.
33
+ - **Pure file-inventory questions.** "How many `*.test.ts` files exist", "list every Markdown file in `docs/`". You're asking for a file count, not a symbol search.
34
+ - **Reading at a known path.** Once memtrace has handed you `file_path:start_line:end_line`, use `Read` — never substitute `Grep` for `Read`.
35
+
36
+ For everything else inside the indexed repo, memtrace is the right tool.
37
+
38
+ ## The decision rule
39
+
40
+ | Question Claude is asking | Right tool |
41
+ |---|---|
42
+ | "Where is symbol `foo` defined?" | `find_symbol(name="foo")` → file:line. Then `Read` that range. |
43
+ | "What calls `foo`?" | `get_symbol_context(name="foo")` → callers with file:line each. |
44
+ | "How does authentication work?" | `find_code(query="authentication")` → ranked symbols with file:line. |
45
+ | "Find the function that uses `STRIPE_KEY_FOO_BAR`" | `find_code(query="STRIPE_KEY_FOO_BAR")` → semantic finds it inside any embedded body. |
46
+ | "Where's that error message `'connection refused for tenant'`?" | `find_code(query="connection refused for tenant")` → semantic catches it. |
47
+ | "What breaks if I change `foo`?" | `get_impact(name="foo")` → blast radius with file:line. |
48
+ | "What changed in `auth.ts` last week?" | `get_evolution(file_path="auth.ts", from="7d ago")`. |
49
+ | "List all `*.test.ts` files." | `Glob` (file inventory, not symbol search). |
50
+ | "Find this string in my `.env`." | `Grep` (non-source artifact). |
51
+ | "Read file I already have the path of." | `Read` (path is known). |
18
52
 
19
53
  ## Parameter Types — Read This Before Calling Any Tool
20
54