purecontext-mcp 1.5.2 → 1.11.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 (196) hide show
  1. package/AGENT_INSTRUCTIONS.md +18 -10
  2. package/AGENT_REFERENCE.md +684 -561
  3. package/CHANGELOG.md +567 -445
  4. package/CODE-HISTORY.md +29 -1
  5. package/FRAMEWORK-ADAPTERS.md +368 -351
  6. package/FULL-INSTALLATION-GUIDE.md +351 -341
  7. package/README.md +411 -339
  8. package/REFACTORING-SAFELY.md +338 -279
  9. package/SAFE-CHANGES.md +208 -156
  10. package/USER-GUIDE.md +3 -1
  11. package/WHY-PURECONTEXT.md +103 -73
  12. package/WORKFLOW-PR-REVIEW.md +245 -199
  13. package/dist/adapters/astro-preprocessor.d.ts +25 -0
  14. package/dist/adapters/astro-preprocessor.d.ts.map +1 -0
  15. package/dist/adapters/astro-preprocessor.js +50 -0
  16. package/dist/adapters/astro-preprocessor.js.map +1 -0
  17. package/dist/adapters/astro.d.ts +13 -0
  18. package/dist/adapters/astro.d.ts.map +1 -0
  19. package/dist/adapters/astro.js +83 -0
  20. package/dist/adapters/astro.js.map +1 -0
  21. package/dist/adapters/detect-utils.d.ts +38 -0
  22. package/dist/adapters/detect-utils.d.ts.map +1 -0
  23. package/dist/adapters/detect-utils.js +95 -0
  24. package/dist/adapters/detect-utils.js.map +1 -0
  25. package/dist/adapters/nuxt.d.ts +20 -0
  26. package/dist/adapters/nuxt.d.ts.map +1 -1
  27. package/dist/adapters/nuxt.js +128 -13
  28. package/dist/adapters/nuxt.js.map +1 -1
  29. package/dist/adapters/svelte-preprocessor.d.ts +29 -0
  30. package/dist/adapters/svelte-preprocessor.d.ts.map +1 -0
  31. package/dist/adapters/svelte-preprocessor.js +83 -0
  32. package/dist/adapters/svelte-preprocessor.js.map +1 -0
  33. package/dist/adapters/svelte.d.ts +13 -0
  34. package/dist/adapters/svelte.d.ts.map +1 -0
  35. package/dist/adapters/svelte.js +96 -0
  36. package/dist/adapters/svelte.js.map +1 -0
  37. package/dist/adapters/vue.d.ts.map +1 -1
  38. package/dist/adapters/vue.js +87 -20
  39. package/dist/adapters/vue.js.map +1 -1
  40. package/dist/bin.d.ts +16 -0
  41. package/dist/bin.d.ts.map +1 -0
  42. package/dist/bin.js +21 -0
  43. package/dist/bin.js.map +1 -0
  44. package/dist/cli/hooks.d.ts +2 -2
  45. package/dist/cli/hooks.d.ts.map +1 -1
  46. package/dist/cli/hooks.js +123 -135
  47. package/dist/cli/hooks.js.map +1 -1
  48. package/dist/cli/install-writers.d.ts.map +1 -1
  49. package/dist/cli/install-writers.js +281 -36
  50. package/dist/cli/install-writers.js.map +1 -1
  51. package/dist/cli/resolve-node.d.ts +53 -0
  52. package/dist/cli/resolve-node.d.ts.map +1 -0
  53. package/dist/cli/resolve-node.js +84 -0
  54. package/dist/cli/resolve-node.js.map +1 -0
  55. package/dist/config/config-loader.js +24 -0
  56. package/dist/config/config-loader.js.map +1 -1
  57. package/dist/config/config-schema.d.ts +71 -0
  58. package/dist/config/config-schema.d.ts.map +1 -1
  59. package/dist/config/config-schema.js +102 -0
  60. package/dist/config/config-schema.js.map +1 -1
  61. package/dist/core/db/api-keys.d.ts +1 -1
  62. package/dist/core/db/api-keys.d.ts.map +1 -1
  63. package/dist/core/db/api-keys.js +39 -39
  64. package/dist/core/db/api-keys.js.map +1 -1
  65. package/dist/core/db/co-change-store.d.ts +34 -0
  66. package/dist/core/db/co-change-store.d.ts.map +1 -0
  67. package/dist/core/db/co-change-store.js +78 -0
  68. package/dist/core/db/co-change-store.js.map +1 -0
  69. package/dist/core/db/schema.d.ts +3 -3
  70. package/dist/core/db/schema.d.ts.map +1 -1
  71. package/dist/core/db/schema.js +12 -30
  72. package/dist/core/db/schema.js.map +1 -1
  73. package/dist/core/db/sqlite-loader.d.ts +51 -0
  74. package/dist/core/db/sqlite-loader.d.ts.map +1 -0
  75. package/dist/core/db/sqlite-loader.js +94 -0
  76. package/dist/core/db/sqlite-loader.js.map +1 -0
  77. package/dist/core/db/wasm-sqlite.d.ts +4 -0
  78. package/dist/core/db/wasm-sqlite.d.ts.map +1 -0
  79. package/dist/core/db/wasm-sqlite.js +270 -0
  80. package/dist/core/db/wasm-sqlite.js.map +1 -0
  81. package/dist/core/diff-parser.d.ts.map +1 -1
  82. package/dist/core/diff-parser.js +6 -1
  83. package/dist/core/diff-parser.js.map +1 -1
  84. package/dist/core/git-log-reader.d.ts +28 -0
  85. package/dist/core/git-log-reader.d.ts.map +1 -1
  86. package/dist/core/git-log-reader.js +74 -3
  87. package/dist/core/git-log-reader.js.map +1 -1
  88. package/dist/core/index-manager.d.ts.map +1 -1
  89. package/dist/core/index-manager.js +29 -3
  90. package/dist/core/index-manager.js.map +1 -1
  91. package/dist/core/indexing-worker.d.ts +2 -0
  92. package/dist/core/indexing-worker.d.ts.map +1 -1
  93. package/dist/core/indexing-worker.js +2 -0
  94. package/dist/core/indexing-worker.js.map +1 -1
  95. package/dist/core/watcher/file-watcher.d.ts +6 -0
  96. package/dist/core/watcher/file-watcher.d.ts.map +1 -1
  97. package/dist/core/watcher/file-watcher.js +11 -1
  98. package/dist/core/watcher/file-watcher.js.map +1 -1
  99. package/dist/graph/path-resolver.js +86 -17
  100. package/dist/graph/path-resolver.js.map +1 -1
  101. package/dist/index.d.ts +3 -0
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +11 -1
  104. package/dist/index.js.map +1 -1
  105. package/dist/node-guard.d.ts +15 -0
  106. package/dist/node-guard.d.ts.map +1 -0
  107. package/dist/node-guard.js +33 -0
  108. package/dist/node-guard.js.map +1 -0
  109. package/dist/server/admin-api.d.ts +1 -1
  110. package/dist/server/admin-api.d.ts.map +1 -1
  111. package/dist/server/admin-api.js +2 -2
  112. package/dist/server/admin-api.js.map +1 -1
  113. package/dist/server/auth/api-key.d.ts +1 -1
  114. package/dist/server/auth/api-key.d.ts.map +1 -1
  115. package/dist/server/mcp-server.d.ts.map +1 -1
  116. package/dist/server/mcp-server.js +25 -0
  117. package/dist/server/mcp-server.js.map +1 -1
  118. package/dist/server/tools/analyze-diff.d.ts +8 -0
  119. package/dist/server/tools/analyze-diff.d.ts.map +1 -1
  120. package/dist/server/tools/analyze-diff.js +80 -16
  121. package/dist/server/tools/analyze-diff.js.map +1 -1
  122. package/dist/server/tools/change-synthesis.d.ts +90 -0
  123. package/dist/server/tools/change-synthesis.d.ts.map +1 -0
  124. package/dist/server/tools/change-synthesis.js +236 -0
  125. package/dist/server/tools/change-synthesis.js.map +1 -0
  126. package/dist/server/tools/co-change.d.ts +65 -0
  127. package/dist/server/tools/co-change.d.ts.map +1 -0
  128. package/dist/server/tools/co-change.js +146 -0
  129. package/dist/server/tools/co-change.js.map +1 -0
  130. package/dist/server/tools/compare-change-impact.d.ts +58 -0
  131. package/dist/server/tools/compare-change-impact.d.ts.map +1 -0
  132. package/dist/server/tools/compare-change-impact.js +0 -0
  133. package/dist/server/tools/compare-change-impact.js.map +1 -0
  134. package/dist/server/tools/find-refactoring-opportunities.d.ts +1 -1
  135. package/dist/server/tools/get-architecture-snapshot.d.ts.map +1 -1
  136. package/dist/server/tools/get-architecture-snapshot.js +28 -14
  137. package/dist/server/tools/get-architecture-snapshot.js.map +1 -1
  138. package/dist/server/tools/get-churn-metrics.d.ts.map +1 -1
  139. package/dist/server/tools/get-churn-metrics.js +1 -12
  140. package/dist/server/tools/get-churn-metrics.js.map +1 -1
  141. package/dist/server/tools/get-co-change.d.ts +37 -0
  142. package/dist/server/tools/get-co-change.d.ts.map +1 -0
  143. package/dist/server/tools/get-co-change.js +120 -0
  144. package/dist/server/tools/get-co-change.js.map +1 -0
  145. package/dist/server/tools/get-context-bundle.d.ts.map +1 -1
  146. package/dist/server/tools/get-context-bundle.js +56 -3
  147. package/dist/server/tools/get-context-bundle.js.map +1 -1
  148. package/dist/server/tools/get-entry-points.d.ts +1 -1
  149. package/dist/server/tools/get-symbol-risk.d.ts +25 -0
  150. package/dist/server/tools/get-symbol-risk.d.ts.map +1 -0
  151. package/dist/server/tools/get-symbol-risk.js +60 -0
  152. package/dist/server/tools/get-symbol-risk.js.map +1 -0
  153. package/dist/server/tools/get-symbol-source.d.ts +2 -0
  154. package/dist/server/tools/get-symbol-source.d.ts.map +1 -1
  155. package/dist/server/tools/get-symbol-source.js +18 -1
  156. package/dist/server/tools/get-symbol-source.js.map +1 -1
  157. package/dist/server/tools/index-repo.d.ts.map +1 -1
  158. package/dist/server/tools/index-repo.js +8 -2
  159. package/dist/server/tools/index-repo.js.map +1 -1
  160. package/dist/server/tools/prepare-change.d.ts +61 -0
  161. package/dist/server/tools/prepare-change.d.ts.map +1 -0
  162. package/dist/server/tools/prepare-change.js +262 -0
  163. package/dist/server/tools/prepare-change.js.map +1 -0
  164. package/dist/server/tools/search-symbols.d.ts +2 -0
  165. package/dist/server/tools/search-symbols.d.ts.map +1 -1
  166. package/dist/server/tools/search-symbols.js +33 -0
  167. package/dist/server/tools/search-symbols.js.map +1 -1
  168. package/dist/server/tools/symbol-lines.d.ts +25 -0
  169. package/dist/server/tools/symbol-lines.d.ts.map +1 -0
  170. package/dist/server/tools/symbol-lines.js +40 -0
  171. package/dist/server/tools/symbol-lines.js.map +1 -0
  172. package/dist/server/tools/symbol-risk.d.ts +109 -0
  173. package/dist/server/tools/symbol-risk.d.ts.map +1 -0
  174. package/dist/server/tools/symbol-risk.js +251 -0
  175. package/dist/server/tools/symbol-risk.js.map +1 -0
  176. package/dist/server/tools/verify-change.d.ts +40 -0
  177. package/dist/server/tools/verify-change.d.ts.map +1 -0
  178. package/dist/server/tools/verify-change.js +149 -0
  179. package/dist/server/tools/verify-change.js.map +1 -0
  180. package/dist/version.d.ts +1 -1
  181. package/dist/version.d.ts.map +1 -1
  182. package/dist/version.js +1 -1
  183. package/dist/version.js.map +1 -1
  184. package/docs/01-introduction.md +2 -2
  185. package/docs/02-installation.md +97 -89
  186. package/docs/03-quick-start.md +138 -135
  187. package/docs/04-configuration.md +247 -214
  188. package/docs/05-cli-reference.md +236 -219
  189. package/docs/06-tools-reference.md +902 -499
  190. package/docs/14-transport-modes.md +170 -167
  191. package/docs/18-git-history.md +43 -0
  192. package/docs/23-performance.md +123 -121
  193. package/docs/26-troubleshooting.md +249 -234
  194. package/grammars/README.md +88 -0
  195. package/package.json +7 -25
  196. package/AGENT_INSTRUCTIONS_SHORT.md +0 -150
@@ -1,214 +1,247 @@
1
- # Configuration
2
-
3
-
4
- ## Config file location
5
-
6
- ```
7
- ~/.purecontext/config.json
8
- ```
9
-
10
- Generate a default file with:
11
-
12
- ```bash
13
- purecontext-mcp config --init
14
- ```
15
-
16
- View the effective configuration (defaults merged with your overrides):
17
-
18
- ```bash
19
- purecontext-mcp config
20
- ```
21
-
22
- Validate the config and check prerequisites:
23
-
24
- ```bash
25
- purecontext-mcp config --check
26
- ```
27
-
28
- ## Full schema reference
29
-
30
- ```json
31
- {
32
- "indexDir": "~/.purecontext/indexes",
33
- "fileLimit": 1000,
34
- "watchDebounceMs": 2000,
35
- "excludePatterns": [],
36
- "adapters": "auto",
37
- "maxFileSizeBytes": 1048576,
38
- "allowSymlinks": false,
39
- "transport": "stdio",
40
-
41
- "ai": {
42
- "provider": "none",
43
- "allowRemoteAI": false,
44
- "apiKey": "",
45
- "endpoint": null,
46
- "model": "claude-haiku-4-5-20251001",
47
- "batchSize": 50,
48
- "embeddingModel": null,
49
- "embeddingProvider": null,
50
- "openaiApiKey": ""
51
- },
52
-
53
- "semantic": {
54
- "enabled": false,
55
- "provider": "none",
56
- "localEmbeddingEndpoint": null,
57
- "dimension": null,
58
- "threshold": 50000,
59
- "batchSize": 500,
60
- "concurrency": 2
61
- },
62
-
63
- "http": {
64
- "port": 3000,
65
- "host": "127.0.0.1",
66
- "corsOrigins": ["http://localhost:*"],
67
- "auth": {
68
- "enabled": false,
69
- "token": ""
70
- }
71
- },
72
-
73
- "rateLimit": {
74
- "enabled": true,
75
- "maxTokens": 100,
76
- "refillRate": 10,
77
- "perToolLimits": {
78
- "index_folder": 10,
79
- "index_repo": 10,
80
- "get_context_bundle": 3,
81
- "get_blast_radius": 3,
82
- "get_repo_outline": 2,
83
- "find_dead_code": 5
84
- }
85
- },
86
-
87
- "telemetry": {
88
- "enabled": false,
89
- "endpoint": "https://telemetry.purecontext.dev/v1/event"
90
- },
91
-
92
- "layers": {
93
- "definitions": [],
94
- "rules": []
95
- }
96
- }
97
- ```
98
-
99
- ## Field reference
100
-
101
- ### Storage and indexing
102
-
103
- | Field | Type | Default | Description |
104
- |-------|------|---------|-------------|
105
- | `indexDir` | `string` | `~/.purecontext/indexes` | Directory where SQLite index files are stored |
106
- | `fileLimit` | `number` | `1000` | Max files indexed per project. Increase for large repos. `0` means unlimited. |
107
- | `watchDebounceMs` | `number` | `2000` | Milliseconds to wait after a file change before re-indexing |
108
- | `excludePatterns` | `string[]` | `[]` | Additional glob patterns to exclude (on top of built-ins: `node_modules/`, `.git/`, `dist/`, etc.) |
109
- | `adapters` | `string` or `string[]` | `"auto"` | `"auto"` = detect from project files; `"none"` = disable all; `["vue", "nuxt"]` = explicit list |
110
- | `maxFileSizeBytes` | `number` | `1048576` | Files larger than this (default: 1 MB) are skipped |
111
- | `allowSymlinks` | `boolean` | `false` | When `false`, symlinks that resolve outside the project root are blocked |
112
-
113
- ### Transport
114
-
115
- | Field | Type | Default | Description |
116
- |-------|------|---------|-------------|
117
- | `transport` | `string` | `"stdio"` | `"stdio"` for Claude Code; `"http"` for browser/remote; `"both"` for both simultaneously |
118
-
119
- ### AI summarization (`ai.*`)
120
-
121
- | Field | Type | Default | Description |
122
- |-------|------|---------|-------------|
123
- | `ai.provider` | `string` | `"none"` | `"none"`, `"anthropic"`, `"openai"`, `"openai-compatible"`, `"google"` |
124
- | `ai.allowRemoteAI` | `boolean` | `false` | Must be `true` to enable any outbound AI API calls |
125
- | `ai.apiKey` | `string` | `""` | API key. Prefer environment variable interpolation: `"${ANTHROPIC_API_KEY}"` |
126
- | `ai.model` | `string` | `"claude-haiku-4-5-20251001"` | Model for summarization |
127
- | `ai.batchSize` | `number` | `50` | Symbols per AI batch request |
128
- | `ai.endpoint` | `string \| null` | `null` | Custom endpoint for `openai-compatible` providers (e.g., Ollama) |
129
-
130
- ### Semantic search (`semantic.*`)
131
-
132
- | Field | Type | Default | Description |
133
- |-------|------|---------|-------------|
134
- | `semantic.enabled` | `boolean` | `false` | Enable HNSW vector search |
135
- | `semantic.provider` | `string` | `"none"` | `"openai"`, `"local"`, or `"none"` |
136
- | `semantic.localEmbeddingEndpoint` | `string \| null` | `null` | Local embedding server URL (e.g., Ollama) |
137
- | `semantic.threshold` | `number` | `50000` | Min symbols before HNSW index is built. Lower for small repos. |
138
- | `semantic.batchSize` | `number` | `500` | Symbols per embedding batch |
139
- | `semantic.concurrency` | `number` | `2` | Concurrent embedding requests |
140
-
141
- ### HTTP server (`http.*`)
142
-
143
- | Field | Type | Default | Description |
144
- |-------|------|---------|-------------|
145
- | `http.port` | `number` | `3000` | Port for HTTP transport |
146
- | `http.host` | `string` | `"127.0.0.1"` | Bind address. Use `"0.0.0.0"` for network access. |
147
- | `http.corsOrigins` | `string[]` | `["http://localhost:*"]` | Allowed CORS origins |
148
- | `http.auth.enabled` | `boolean` | `false` | Require bearer token authentication |
149
- | `http.auth.token` | `string` | `""` | Bearer token. If empty and auth is enabled, a random token is generated at startup. |
150
-
151
- ### Rate limiting (`rateLimit.*`)
152
-
153
- | Field | Type | Default | Description |
154
- |-------|------|---------|-------------|
155
- | `rateLimit.enabled` | `boolean` | `true` | Enable token-bucket rate limiting |
156
- | `rateLimit.maxTokens` | `number` | `100` | Bucket capacity |
157
- | `rateLimit.refillRate` | `number` | `10` | Tokens refilled per second |
158
- | `rateLimit.perToolLimits` | `object` | see above | Per-tool token cost overrides |
159
-
160
- ### Telemetry (`telemetry.*`)
161
-
162
- | Field | Type | Default | Description |
163
- |-------|------|---------|-------------|
164
- | `telemetry.enabled` | `boolean` | `false` | Opt-in anonymous usage telemetry. **Never enabled without explicit opt-in.** |
165
- | `telemetry.endpoint` | `string` | `"https://telemetry.purecontext.dev/v1/event"` | Override the telemetry endpoint |
166
-
167
- See [Telemetry](TELEMETRY.md) for full details on what is and is not collected.
168
-
169
- ### Architecture layer rules (`layers.*`)
170
-
171
- Used by the `get_layer_violations` tool to enforce import boundaries.
172
-
173
- ```json
174
- {
175
- "layers": {
176
- "definitions": [
177
- { "name": "core", "paths": ["src/core/**"] },
178
- { "name": "handlers", "paths": ["src/handlers/**"] }
179
- ],
180
- "rules": [
181
- { "from": "core", "to": "handlers", "allowed": false }
182
- ]
183
- }
184
- }
185
- ```
186
-
187
- ## Environment variable interpolation
188
-
189
- API keys in `config.json` can reference environment variables to avoid storing secrets in the file:
190
-
191
- ```json
192
- {
193
- "ai": {
194
- "apiKey": "${ANTHROPIC_API_KEY}"
195
- },
196
- "http": {
197
- "auth": {
198
- "token": "${PURECONTEXT_API_TOKEN}"
199
- }
200
- }
201
- }
202
- ```
203
-
204
- The server also reads the following environment variables directly (they override `config.json`):
205
-
206
- | Variable | Config field |
207
- |----------|-------------|
208
- | `PCTX_ADMIN_KEY` | Admin key for multi-tenant deployments |
209
- | `PCTX_DATA_DIR` | `indexDir` |
210
- | `PCTX_PORT` | `http.port` |
211
- | `PCTX_HOST` | `http.host` |
212
- | `ANTHROPIC_API_KEY` | `ai.apiKey` (when `ai.provider = "anthropic"`) |
213
- | `OPENAI_API_KEY` | `ai.openaiApiKey` |
214
- | `GEMINI_API_KEY` | Used when `ai.provider = "google"` |
1
+ # Configuration
2
+
3
+
4
+ ## Config file location
5
+
6
+ ```
7
+ ~/.purecontext/config.json
8
+ ```
9
+
10
+ Generate a default file with:
11
+
12
+ ```bash
13
+ purecontext-mcp config --init
14
+ ```
15
+
16
+ View the effective configuration (defaults merged with your overrides):
17
+
18
+ ```bash
19
+ purecontext-mcp config
20
+ ```
21
+
22
+ Validate the config and check prerequisites:
23
+
24
+ ```bash
25
+ purecontext-mcp config --check
26
+ ```
27
+
28
+ ## Full schema reference
29
+
30
+ ```json
31
+ {
32
+ "indexDir": "~/.purecontext/indexes",
33
+ "fileLimit": 1000,
34
+ "watchDebounceMs": 2000,
35
+ "excludePatterns": [],
36
+ "adapters": "auto",
37
+ "maxFileSizeBytes": 1048576,
38
+ "allowSymlinks": false,
39
+ "transport": "stdio",
40
+
41
+ "ai": {
42
+ "provider": "none",
43
+ "allowRemoteAI": false,
44
+ "apiKey": "",
45
+ "endpoint": null,
46
+ "model": "claude-haiku-4-5-20251001",
47
+ "batchSize": 50,
48
+ "embeddingModel": null,
49
+ "embeddingProvider": null,
50
+ "openaiApiKey": ""
51
+ },
52
+
53
+ "semantic": {
54
+ "enabled": false,
55
+ "provider": "none",
56
+ "localEmbeddingEndpoint": null,
57
+ "dimension": null,
58
+ "threshold": 50000,
59
+ "batchSize": 500,
60
+ "concurrency": 2
61
+ },
62
+
63
+ "http": {
64
+ "port": 3000,
65
+ "host": "127.0.0.1",
66
+ "corsOrigins": ["http://localhost:*"],
67
+ "auth": {
68
+ "enabled": false,
69
+ "token": ""
70
+ }
71
+ },
72
+
73
+ "rateLimit": {
74
+ "enabled": true,
75
+ "maxTokens": 100,
76
+ "refillRate": 10,
77
+ "perToolLimits": {
78
+ "index_folder": 10,
79
+ "index_repo": 10,
80
+ "get_context_bundle": 3,
81
+ "get_blast_radius": 3,
82
+ "get_repo_outline": 2,
83
+ "find_dead_code": 5
84
+ }
85
+ },
86
+
87
+ "telemetry": {
88
+ "enabled": false,
89
+ "endpoint": "https://telemetry.purecontext.dev/v1/event"
90
+ },
91
+
92
+ "layers": {
93
+ "definitions": [],
94
+ "rules": []
95
+ }
96
+ }
97
+ ```
98
+
99
+ ## Field reference
100
+
101
+ ### Storage and indexing
102
+
103
+ | Field | Type | Default | Description |
104
+ |-------|------|---------|-------------|
105
+ | `indexDir` | `string` | `~/.purecontext/indexes` | Directory where SQLite index files are stored |
106
+ | `fileLimit` | `number` | `1000` | Max files indexed per project. Increase for large repos. `0` means unlimited. |
107
+ | `watchDebounceMs` | `number` | `2000` | Milliseconds to wait after a file change before re-indexing |
108
+ | `excludePatterns` | `string[]` | `[]` | Additional glob patterns to exclude (on top of built-ins: `node_modules/`, `.git/`, `dist/`, etc.) |
109
+ | `adapters` | `string` or `string[]` | `"auto"` | `"auto"` = detect from project files; `"none"` = disable all; `["vue", "nuxt"]` = explicit list |
110
+ | `maxFileSizeBytes` | `number` | `1048576` | Files larger than this (default: 1 MB) are skipped |
111
+ | `allowSymlinks` | `boolean` | `false` | When `false`, symlinks that resolve outside the project root are blocked |
112
+
113
+ ### Git & temporal coupling (`git.*`)
114
+
115
+ Powers `get_co_change`, `get_symbol_risk`, and `get_context_bundle`'s `historicalNeighbors` (Phase 76).
116
+
117
+ | Field | Type | Default | Description |
118
+ |-------|------|---------|-------------|
119
+ | `git.coChangeDepth` | `number` | `300` | Recent commits captured at the repo root (one `git log --name-only`) for co-change analysis. `0` disables capture entirely — zero extra git work, identical behavior to before. |
120
+ | `git.megaCommitThreshold` | `number` | `30` | Commits touching more files than this (reformats, lockfile sweeps, codemods) are excluded / down-weighted so they don't manufacture spurious coupling. |
121
+
122
+ ### Change-risk weights (`risk.weights.*`)
123
+
124
+ Tunable factor weights for `get_symbol_risk`. Each scales the repo-relative (0–1) normalized factor; weights need not sum to 1 (normalized at scoring time).
125
+
126
+ | Field | Type | Default | Description |
127
+ |-------|------|---------|-------------|
128
+ | `risk.weights.churn` | `number` | `0.25` | How often the symbol's file changes (90 d) |
129
+ | `risk.weights.centrality` | `number` | `0.25` | Afferent coupling + reverse blast radius |
130
+ | `risk.weights.complexity` | `number` | `0.2` | Cyclomatic complexity of the symbol |
131
+ | `risk.weights.testGap` | `number` | `0.15` | Whether the symbol appears untested |
132
+ | `risk.weights.coChange` | `number` | `0.15` | How many files historically move with it |
133
+
134
+ ### Change synthesis & refactoring (`changeSynthesis.*`, `refactoring.*`)
135
+
136
+ Bound the impact-aware change report (used by `analyze_diff`, `prepare_change`, `verify_change`) so it stays token-disciplined on large diffs.
137
+
138
+ | Field | Type | Default | Description |
139
+ |-------|------|---------|-------------|
140
+ | `changeSynthesis.coChangeConfidenceThreshold` | `number` | `0.4` | Minimum directional co-change confidence for a historically-coupled file to be flagged as missing from a change |
141
+ | `changeSynthesis.maxSymbolsScored` | `number` | `25` | Max changed symbols scored for risk per diff (the rest are ranked out by afferent coupling) |
142
+ | `changeSynthesis.maxCoChangeGaps` | `number` | `10` | Max absent co-change partners reported |
143
+ | `changeSynthesis.maxRecommendedTests` | `number` | `15` | Max recommended test files reported |
144
+ | `refactoring.maxCandidates` | `number` | `5` | How many candidate symbols `prepare_change` returns when disambiguating a free-text `query` (verdict `ambiguous_target`) |
145
+
146
+ ### Transport
147
+
148
+ | Field | Type | Default | Description |
149
+ |-------|------|---------|-------------|
150
+ | `transport` | `string` | `"stdio"` | `"stdio"` for Claude Code; `"http"` for browser/remote; `"both"` for both simultaneously |
151
+
152
+ ### AI summarization (`ai.*`)
153
+
154
+ | Field | Type | Default | Description |
155
+ |-------|------|---------|-------------|
156
+ | `ai.provider` | `string` | `"none"` | `"none"`, `"anthropic"`, `"openai"`, `"openai-compatible"`, `"google"` |
157
+ | `ai.allowRemoteAI` | `boolean` | `false` | Must be `true` to enable any outbound AI API calls |
158
+ | `ai.apiKey` | `string` | `""` | API key. Prefer environment variable interpolation: `"${ANTHROPIC_API_KEY}"` |
159
+ | `ai.model` | `string` | `"claude-haiku-4-5-20251001"` | Model for summarization |
160
+ | `ai.batchSize` | `number` | `50` | Symbols per AI batch request |
161
+ | `ai.endpoint` | `string \| null` | `null` | Custom endpoint for `openai-compatible` providers (e.g., Ollama) |
162
+
163
+ ### Semantic search (`semantic.*`)
164
+
165
+ | Field | Type | Default | Description |
166
+ |-------|------|---------|-------------|
167
+ | `semantic.enabled` | `boolean` | `false` | Enable HNSW vector search |
168
+ | `semantic.provider` | `string` | `"none"` | `"openai"`, `"local"`, or `"none"` |
169
+ | `semantic.localEmbeddingEndpoint` | `string \| null` | `null` | Local embedding server URL (e.g., Ollama) |
170
+ | `semantic.threshold` | `number` | `50000` | Min symbols before HNSW index is built. Lower for small repos. |
171
+ | `semantic.batchSize` | `number` | `500` | Symbols per embedding batch |
172
+ | `semantic.concurrency` | `number` | `2` | Concurrent embedding requests |
173
+
174
+ ### HTTP server (`http.*`)
175
+
176
+ | Field | Type | Default | Description |
177
+ |-------|------|---------|-------------|
178
+ | `http.port` | `number` | `3000` | Port for HTTP transport |
179
+ | `http.host` | `string` | `"127.0.0.1"` | Bind address. Use `"0.0.0.0"` for network access. |
180
+ | `http.corsOrigins` | `string[]` | `["http://localhost:*"]` | Allowed CORS origins |
181
+ | `http.auth.enabled` | `boolean` | `false` | Require bearer token authentication |
182
+ | `http.auth.token` | `string` | `""` | Bearer token. If empty and auth is enabled, a random token is generated at startup. |
183
+
184
+ ### Rate limiting (`rateLimit.*`)
185
+
186
+ | Field | Type | Default | Description |
187
+ |-------|------|---------|-------------|
188
+ | `rateLimit.enabled` | `boolean` | `true` | Enable token-bucket rate limiting |
189
+ | `rateLimit.maxTokens` | `number` | `100` | Bucket capacity |
190
+ | `rateLimit.refillRate` | `number` | `10` | Tokens refilled per second |
191
+ | `rateLimit.perToolLimits` | `object` | see above | Per-tool token cost overrides |
192
+
193
+ ### Telemetry (`telemetry.*`)
194
+
195
+ | Field | Type | Default | Description |
196
+ |-------|------|---------|-------------|
197
+ | `telemetry.enabled` | `boolean` | `false` | Opt-in anonymous usage telemetry. **Never enabled without explicit opt-in.** |
198
+ | `telemetry.endpoint` | `string` | `"https://telemetry.purecontext.dev/v1/event"` | Override the telemetry endpoint |
199
+
200
+ See [Telemetry](TELEMETRY.md) for full details on what is and is not collected.
201
+
202
+ ### Architecture layer rules (`layers.*`)
203
+
204
+ Used by the `get_layer_violations` tool to enforce import boundaries.
205
+
206
+ ```json
207
+ {
208
+ "layers": {
209
+ "definitions": [
210
+ { "name": "core", "paths": ["src/core/**"] },
211
+ { "name": "handlers", "paths": ["src/handlers/**"] }
212
+ ],
213
+ "rules": [
214
+ { "from": "core", "to": "handlers", "allowed": false }
215
+ ]
216
+ }
217
+ }
218
+ ```
219
+
220
+ ## Environment variable interpolation
221
+
222
+ API keys in `config.json` can reference environment variables to avoid storing secrets in the file:
223
+
224
+ ```json
225
+ {
226
+ "ai": {
227
+ "apiKey": "${ANTHROPIC_API_KEY}"
228
+ },
229
+ "http": {
230
+ "auth": {
231
+ "token": "${PURECONTEXT_API_TOKEN}"
232
+ }
233
+ }
234
+ }
235
+ ```
236
+
237
+ The server also reads the following environment variables directly (they override `config.json`):
238
+
239
+ | Variable | Config field |
240
+ |----------|-------------|
241
+ | `PCTX_ADMIN_KEY` | Admin key for multi-tenant deployments |
242
+ | `PCTX_DATA_DIR` | `indexDir` |
243
+ | `PCTX_PORT` | `http.port` |
244
+ | `PCTX_HOST` | `http.host` |
245
+ | `ANTHROPIC_API_KEY` | `ai.apiKey` (when `ai.provider = "anthropic"`) |
246
+ | `OPENAI_API_KEY` | `ai.openaiApiKey` |
247
+ | `GEMINI_API_KEY` | Used when `ai.provider = "google"` |