Navegador

docs: comprehensive documentation update for 0.7.0 Updates all existing pages (index, getting-started, guide, api, architecture) to reflect 13 languages, 11 MCP tools, SDK, enrichment, analysis, intelligence, and cluster features. New pages: SDK guide, framework enrichment, structural analysis, intelligence layer, cluster mode, CI/CD integration, SDK API reference, analysis API reference. Updated mkdocs.yml nav to include all new pages.

lmata 2026-03-23 13:41 trunk
Commit 89816aa17fef324effc3dc58c03737a1547fc78cecc45aca51a32c7ddf0e598a
--- a/docs/api/analysis.md
+++ b/docs/api/analysis.md
@@ -0,0 +1,393 @@
1
+# Analysis API Reference
2
+
3
+```python
4
+from navegador.analysis import (
5
+ ImpactAnalyzer,
6
+ FlowTracer,
7
+ DeadCodeDetector,
8
+ CycleDetector,
9
+ TestMapper,
10
+)
11
+from navegador.graph import GraphStore
12
+```
13
+
14
+---
15
+
16
+## ImpactAnalyzer
17
+
18
+Traces downstream dependents of a function, class, or file by following `CALLS`, `INHERITS`, and `IMPORTS` edges.
19
+
20
+```python
21
+class ImpactAnalyzer:
22
+ def __init__(self, store: GraphStore) -> None: ...
23
+```
24
+
25
+### `analyze`
26
+
27
+```python
28
+def analyze(
29
+ self,
30
+ name: str,
31
+ *,
32
+ node_type: str = "",
33
+ file: str = "",
34
+ depth: int = 0,
35
+ include_tests: bool = False,
36
+ include_knowledge: bool = False,
37
+) -> ImpactResult
38
+```
39
+
40
+Compute the impact set for a given node.
41
+
42
+**Parameters:**
43
+
44
+| Name | Type | Default | Description |
45
+|---|---|---|---|
46
+| `name` | `str` | — | Name of the function, class, or file to analyze |
47
+| `node_type` | `str` | `""` | Node type hint: `"Function"`, `"Class"`, `"File"` |
48
+| `file` | `str` | `""` | Optional file path to disambiguate |
49
+| `depth` | `int` | `0` | Maximum hops to follow (0 = unlimited) |
50
+| `include_tests` | `bool` | `False` | Include test files in the impact set |
51
+| `include_knowledge` | `bool` | `False` | Include linked knowledge nodes (rules, concepts, decisions) |
52
+
53
+**Returns:** `ImpactResult`
54
+
55
+---
56
+
57
+### ImpactResult
58
+
59
+```python
60
+@dataclass
61
+class ImpactResult:
62
+ root: ContextNode
63
+ direct_dependents: list[ContextNode]
64
+ transitive_dependents: list[ContextNode]
65
+ affected_files: list[str]
66
+ knowledge_nodes: list[ContextNode] # empty unless include_knowledge=True
67
+ depth_reached: int
68
+```
69
+
70
+| Field | Type | Description |
71
+|---|---|---|
72
+| `root` | `ContextNode` | The analyzed node |
73
+| `direct_dependents` | `list[ContextNode]` | Nodes one hop away |
74
+| `transitive_dependents` | `list[ContextNode]` | All nodes reachable beyond one hop |
75
+| `affected_files` | `list[str]` | Unique file paths in the full dependent set |
76
+| `knowledge_nodes` | `list[ContextNode]` | Linked concepts, rules, decisions |
77
+| `depth_reached` | `int` | Actual maximum depth traversed |
78
+
79
+**Example:**
80
+
81
+```python
82
+store = GraphStore.sqlite(".navegador/navegador.db")
83
+analyzer = ImpactAnalyzer(store)
84
+
85
+result = analyzer.analyze("validate_token", depth=3, include_knowledge=True)
86
+print(f"{len(result.direct_dependents)} direct dependents")
87
+print(f"{len(result.transitive_dependents)} transitive dependents")
88
+print(f"Affects {len(result.affected_files)} files")
89
+for rule in [n for n in result.knowledge_nodes if n.label == "Rule"]:
90
+ print(f" Governed by: {rule.name} ({rule.properties.get('severity')})")
91
+```
92
+
93
+---
94
+
95
+## FlowTracer
96
+
97
+Finds call paths between two functions.
98
+
99
+```python
100
+class FlowTracer:
101
+ def __init__(self, store: GraphStore) -> None: ...
102
+```
103
+
104
+### `trace`
105
+
106
+```python
107
+def trace(
108
+ self,
109
+ from_name: str,
110
+ to_name: str,
111
+ *,
112
+ from_file: str = "",
113
+ to_file: str = "",
114
+ max_paths: int = 3,
115
+ max_depth: int = 10,
116
+) -> list[FlowPath]
117
+```
118
+
119
+Find call chains from `from_name` to `to_name`.
120
+
121
+**Parameters:**
122
+
123
+| Name | Type | Default | Description |
124
+|---|---|---|---|
125
+| `from_name` | `str` | — | Starting function name |
126
+| `to_name` | `str` | — | Target function name |
127
+| `from_file` | `str` | `""` | File path to disambiguate start |
128
+| `to_file` | `str` | `""` | File path to disambiguate target |
129
+| `max_paths` | `int` | `3` | Maximum number of paths to return |
130
+| `max_depth` | `int` | `10` | Maximum call chain length |
131
+
132
+**Returns:** `list[FlowPath]`
133
+
134
+---
135
+
136
+### FlowPath
137
+
138
+```python
139
+@dataclass
140
+class FlowPath:
141
+ nodes: list[str] # function names in order
142
+ node_details: list[ContextNode]
143
+ length: int
144
+```
145
+
146
+**Example:**
147
+
148
+```python
149
+tracer = FlowTracer(store)
150
+paths = tracer.trace("create_order", "process_payment", max_paths=5)
151
+for i, path in enumerate(paths, 1):
152
+ print(f"Path {i}: {' -> '.join(path.nodes)}")
153
+```
154
+
155
+---
156
+
157
+## DeadCodeDetector
158
+
159
+Identifies functions and classes that are never called, never imported, and not entry points.
160
+
161
+```python
162
+class DeadCodeDetector:
163
+ def __init__(self, store: GraphStore) -> None: ...
164
+```
165
+
166
+### `find`
167
+
168
+```python
169
+def find(
170
+ self,
171
+ path: str | Path,
172
+ *,
173
+ exclude_tests: bool = False,
174
+ min_confidence: int = 80,
175
+) -> list[DeadCodeCandidate]
176
+```
177
+
178
+Find potentially dead code within a path.
179
+
180
+**Parameters:**
181
+
182
+| Name | Type | Default | Description |
183
+|---|---|---|---|
184
+| `path` | `str \| Path` | — | Directory or file to analyze |
185
+| `exclude_tests` | `bool` | `False` | Skip test files |
186
+| `min_confidence` | `int` | `80` | Minimum confidence score to include (0–100) |
187
+
188
+**Returns:** `list[DeadCodeCandidate]`
189
+
190
+---
191
+
192
+### DeadCodeCandidate
193
+
194
+```python
195
+@dataclass
196
+class DeadCodeCandidate:
197
+ node: ContextNode
198
+ confidence: int # 0–100
199
+ reasons: list[str] # e.g. ["no callers", "no imports", "no decorator entry point"]
200
+```
201
+
202
+| Field | Type | Description |
203
+|---|---|---|
204
+| `node` | `ContextNode` | The potentially dead node |
205
+| `confidence` | `int` | Confidence that this is truly unreachable (higher = more confident) |
206
+| `reasons` | `list[str]` | Reasons for the classification |
207
+
208
+**Example:**
209
+
210
+```python
211
+detector = DeadCodeDetector(store)
212
+candidates = detector.find("./src", exclude_tests=True, min_confidence=90)
213
+for c in candidates:
214
+ print(f"[{c.confidence}%] {c.node.label}: {c.node.name} {c.node.properties['file']}")
215
+ print(f" Reasons: {', '.join(c.reasons)}")
216
+```
217
+
218
+---
219
+
220
+## CycleDetector
221
+
222
+Finds circular dependency chains in call and import graphs.
223
+
224
+```python
225
+class CycleDetector:
226
+ def __init__(self, store: GraphStore) -> None: ...
227
+```
228
+
229
+### `find_import_cycles`
230
+
231
+```python
232
+def find_import_cycles(
233
+ self,
234
+ path: str | Path,
235
+ *,
236
+ min_length: int = 2,
237
+) -> list[Cycle]
238
+```
239
+
240
+Find circular import chains within a path.
241
+
242
+---
243
+
244
+### `find_call_cycles`
245
+
246
+```python
247
+def find_call_cycles(
248
+ self,
249
+ path: str | Path,
250
+ *,
251
+ min_length: int = 2,
252
+) -> list[Cycle]
253
+```
254
+
255
+Find circular call chains within a path.
256
+
257
+---
258
+
259
+### `find_all`
260
+
261
+```python
262
+def find_all(
263
+ self,
264
+ path: str | Path,
265
+ *,
266
+ min_length: int = 2,
267
+) -> CycleReport
268
+```
269
+
270
+Find both import and call cycles.
271
+
272
+**Parameters (all methods):**
273
+
274
+| Name | Type | Default | Description |
275
+|---|---|---|---|
276
+| `path` | `str \| Path` | — | Directory or file to analyze |
277
+| `min_length` | `int` | `2` | Minimum cycle length to report |
278
+
279
+**Returns:** `list[Cycle]` or `CycleReport`
280
+
281
+---
282
+
283
+### Cycle
284
+
285
+```python
286
+@dataclass
287
+class Cycle:
288
+ path: list[str] # node names (files or functions) forming the cycle
289
+ cycle_type: str # "import" or "call"
290
+ length: int
291
+```
292
+
293
+### CycleReport
294
+
295
+```python
296
+@dataclass
297
+class CycleReport:
298
+ import_cycles: list[Cycle]
299
+ call_cycles: list[Cycle]
300
+ total: int
301
+```
302
+
303
+**Example:**
304
+
305
+```python
306
+detector = CycleDetector(store)
307
+report = detector.find_all("./src")
308
+print(f"{report.total} cycles found")
309
+for cycle in report.import_cycles:
310
+ print(f" Import cycle: {' -> '.join(cycle.path)}")
311
+```
312
+
313
+---
314
+
315
+## TestMapper
316
+
317
+Maps test functions to the production code they exercise via call graph analysis.
318
+
319
+```python
320
+class TestMapper:
321
+ def __init__(self, store: GraphStore) -> None: ...
322
+```
323
+
324
+### `map`
325
+
326
+```python
327
+def map(
328
+ self,
329
+ src_path: str | Path,
330
+ test_path: str | Path,
331
+ *,
332
+ target: str = "",
333
+) -> TestCoverageMap
334
+```
335
+
336
+Build a mapping of production functions to their covering tests.
337
+
338
+**Parameters:**
339
+
340
+| Name | Type | Default | Description |
341
+|---|---|---|---|
342
+| `src_path` | `str \| Path` | — | Production code directory |
343
+| `test_path` | `str \| Path` | — | Test directory |
344
+| `target` | `str` | `""` | If set, only map coverage for this specific function |
345
+
346
+**Returns:** `TestCoverageMap`
347
+
348
+---
349
+
350
+### `uncovered`
351
+
352
+```python
353
+def uncovered(
354
+ self,
355
+ src_path: str | Path,
356
+ test_path: str | Path,
357
+) -> list[ContextNode]
358
+```
359
+
360
+Return production functions and classes with no covering tests.
361
+
362
+---
363
+
364
+### TestCoverageMap
365
+
366
+```python
367
+@dataclass
368
+class TestCoverageMap:
369
+ coverage: dict[str, list[ContextNode]] # function name -> list of test nodes
370
+ uncovered: list[ContextNode]
371
+ coverage_percent: float
372
+```
373
+
374
+| Field | Type | Description |
375
+|---|---|---|
376
+| `coverage` | `dict[str, list[ContextNode]]` | Maps each production function to its test nodes |
377
+| `uncovered` | `list[ContextNode]` | Production functions with no tests |
378
+| `coverage_percent` | `float` | Percentage of functions with at least one test |
379
+
380
+**Example:**
381
+
382
+```python
383
+mapper = TestMapper(store)
384
+coverage_map = mapper.map("./src", "./tests")
385
+
386
+print(f"Coverage: {coverage_map.coverage_percent:.1f}%")
387
+print(f"Uncovered: {len(coverage_map.uncovered)} functions")
388
+
389
+for fn_name, tests in coverage_map.coverage.items():
390
+ print(f" {fn_name}: {len(tests)} tests")
391
+ for test in tests:
392
+ print(f" {test.properties['file']}::{test.name}")
393
+```
--- a/docs/api/analysis.md
+++ b/docs/api/analysis.md
@@ -0,0 +1,393 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/api/analysis.md
+++ b/docs/api/analysis.md
@@ -0,0 +1,393 @@
1 # Analysis API Reference
2
3 ```python
4 from navegador.analysis import (
5 ImpactAnalyzer,
6 FlowTracer,
7 DeadCodeDetector,
8 CycleDetector,
9 TestMapper,
10 )
11 from navegador.graph import GraphStore
12 ```
13
14 ---
15
16 ## ImpactAnalyzer
17
18 Traces downstream dependents of a function, class, or file by following `CALLS`, `INHERITS`, and `IMPORTS` edges.
19
20 ```python
21 class ImpactAnalyzer:
22 def __init__(self, store: GraphStore) -> None: ...
23 ```
24
25 ### `analyze`
26
27 ```python
28 def analyze(
29 self,
30 name: str,
31 *,
32 node_type: str = "",
33 file: str = "",
34 depth: int = 0,
35 include_tests: bool = False,
36 include_knowledge: bool = False,
37 ) -> ImpactResult
38 ```
39
40 Compute the impact set for a given node.
41
42 **Parameters:**
43
44 | Name | Type | Default | Description |
45 |---|---|---|---|
46 | `name` | `str` | — | Name of the function, class, or file to analyze |
47 | `node_type` | `str` | `""` | Node type hint: `"Function"`, `"Class"`, `"File"` |
48 | `file` | `str` | `""` | Optional file path to disambiguate |
49 | `depth` | `int` | `0` | Maximum hops to follow (0 = unlimited) |
50 | `include_tests` | `bool` | `False` | Include test files in the impact set |
51 | `include_knowledge` | `bool` | `False` | Include linked knowledge nodes (rules, concepts, decisions) |
52
53 **Returns:** `ImpactResult`
54
55 ---
56
57 ### ImpactResult
58
59 ```python
60 @dataclass
61 class ImpactResult:
62 root: ContextNode
63 direct_dependents: list[ContextNode]
64 transitive_dependents: list[ContextNode]
65 affected_files: list[str]
66 knowledge_nodes: list[ContextNode] # empty unless include_knowledge=True
67 depth_reached: int
68 ```
69
70 | Field | Type | Description |
71 |---|---|---|
72 | `root` | `ContextNode` | The analyzed node |
73 | `direct_dependents` | `list[ContextNode]` | Nodes one hop away |
74 | `transitive_dependents` | `list[ContextNode]` | All nodes reachable beyond one hop |
75 | `affected_files` | `list[str]` | Unique file paths in the full dependent set |
76 | `knowledge_nodes` | `list[ContextNode]` | Linked concepts, rules, decisions |
77 | `depth_reached` | `int` | Actual maximum depth traversed |
78
79 **Example:**
80
81 ```python
82 store = GraphStore.sqlite(".navegador/navegador.db")
83 analyzer = ImpactAnalyzer(store)
84
85 result = analyzer.analyze("validate_token", depth=3, include_knowledge=True)
86 print(f"{len(result.direct_dependents)} direct dependents")
87 print(f"{len(result.transitive_dependents)} transitive dependents")
88 print(f"Affects {len(result.affected_files)} files")
89 for rule in [n for n in result.knowledge_nodes if n.label == "Rule"]:
90 print(f" Governed by: {rule.name} ({rule.properties.get('severity')})")
91 ```
92
93 ---
94
95 ## FlowTracer
96
97 Finds call paths between two functions.
98
99 ```python
100 class FlowTracer:
101 def __init__(self, store: GraphStore) -> None: ...
102 ```
103
104 ### `trace`
105
106 ```python
107 def trace(
108 self,
109 from_name: str,
110 to_name: str,
111 *,
112 from_file: str = "",
113 to_file: str = "",
114 max_paths: int = 3,
115 max_depth: int = 10,
116 ) -> list[FlowPath]
117 ```
118
119 Find call chains from `from_name` to `to_name`.
120
121 **Parameters:**
122
123 | Name | Type | Default | Description |
124 |---|---|---|---|
125 | `from_name` | `str` | — | Starting function name |
126 | `to_name` | `str` | — | Target function name |
127 | `from_file` | `str` | `""` | File path to disambiguate start |
128 | `to_file` | `str` | `""` | File path to disambiguate target |
129 | `max_paths` | `int` | `3` | Maximum number of paths to return |
130 | `max_depth` | `int` | `10` | Maximum call chain length |
131
132 **Returns:** `list[FlowPath]`
133
134 ---
135
136 ### FlowPath
137
138 ```python
139 @dataclass
140 class FlowPath:
141 nodes: list[str] # function names in order
142 node_details: list[ContextNode]
143 length: int
144 ```
145
146 **Example:**
147
148 ```python
149 tracer = FlowTracer(store)
150 paths = tracer.trace("create_order", "process_payment", max_paths=5)
151 for i, path in enumerate(paths, 1):
152 print(f"Path {i}: {' -> '.join(path.nodes)}")
153 ```
154
155 ---
156
157 ## DeadCodeDetector
158
159 Identifies functions and classes that are never called, never imported, and not entry points.
160
161 ```python
162 class DeadCodeDetector:
163 def __init__(self, store: GraphStore) -> None: ...
164 ```
165
166 ### `find`
167
168 ```python
169 def find(
170 self,
171 path: str | Path,
172 *,
173 exclude_tests: bool = False,
174 min_confidence: int = 80,
175 ) -> list[DeadCodeCandidate]
176 ```
177
178 Find potentially dead code within a path.
179
180 **Parameters:**
181
182 | Name | Type | Default | Description |
183 |---|---|---|---|
184 | `path` | `str \| Path` | — | Directory or file to analyze |
185 | `exclude_tests` | `bool` | `False` | Skip test files |
186 | `min_confidence` | `int` | `80` | Minimum confidence score to include (0–100) |
187
188 **Returns:** `list[DeadCodeCandidate]`
189
190 ---
191
192 ### DeadCodeCandidate
193
194 ```python
195 @dataclass
196 class DeadCodeCandidate:
197 node: ContextNode
198 confidence: int # 0–100
199 reasons: list[str] # e.g. ["no callers", "no imports", "no decorator entry point"]
200 ```
201
202 | Field | Type | Description |
203 |---|---|---|
204 | `node` | `ContextNode` | The potentially dead node |
205 | `confidence` | `int` | Confidence that this is truly unreachable (higher = more confident) |
206 | `reasons` | `list[str]` | Reasons for the classification |
207
208 **Example:**
209
210 ```python
211 detector = DeadCodeDetector(store)
212 candidates = detector.find("./src", exclude_tests=True, min_confidence=90)
213 for c in candidates:
214 print(f"[{c.confidence}%] {c.node.label}: {c.node.name} {c.node.properties['file']}")
215 print(f" Reasons: {', '.join(c.reasons)}")
216 ```
217
218 ---
219
220 ## CycleDetector
221
222 Finds circular dependency chains in call and import graphs.
223
224 ```python
225 class CycleDetector:
226 def __init__(self, store: GraphStore) -> None: ...
227 ```
228
229 ### `find_import_cycles`
230
231 ```python
232 def find_import_cycles(
233 self,
234 path: str | Path,
235 *,
236 min_length: int = 2,
237 ) -> list[Cycle]
238 ```
239
240 Find circular import chains within a path.
241
242 ---
243
244 ### `find_call_cycles`
245
246 ```python
247 def find_call_cycles(
248 self,
249 path: str | Path,
250 *,
251 min_length: int = 2,
252 ) -> list[Cycle]
253 ```
254
255 Find circular call chains within a path.
256
257 ---
258
259 ### `find_all`
260
261 ```python
262 def find_all(
263 self,
264 path: str | Path,
265 *,
266 min_length: int = 2,
267 ) -> CycleReport
268 ```
269
270 Find both import and call cycles.
271
272 **Parameters (all methods):**
273
274 | Name | Type | Default | Description |
275 |---|---|---|---|
276 | `path` | `str \| Path` | — | Directory or file to analyze |
277 | `min_length` | `int` | `2` | Minimum cycle length to report |
278
279 **Returns:** `list[Cycle]` or `CycleReport`
280
281 ---
282
283 ### Cycle
284
285 ```python
286 @dataclass
287 class Cycle:
288 path: list[str] # node names (files or functions) forming the cycle
289 cycle_type: str # "import" or "call"
290 length: int
291 ```
292
293 ### CycleReport
294
295 ```python
296 @dataclass
297 class CycleReport:
298 import_cycles: list[Cycle]
299 call_cycles: list[Cycle]
300 total: int
301 ```
302
303 **Example:**
304
305 ```python
306 detector = CycleDetector(store)
307 report = detector.find_all("./src")
308 print(f"{report.total} cycles found")
309 for cycle in report.import_cycles:
310 print(f" Import cycle: {' -> '.join(cycle.path)}")
311 ```
312
313 ---
314
315 ## TestMapper
316
317 Maps test functions to the production code they exercise via call graph analysis.
318
319 ```python
320 class TestMapper:
321 def __init__(self, store: GraphStore) -> None: ...
322 ```
323
324 ### `map`
325
326 ```python
327 def map(
328 self,
329 src_path: str | Path,
330 test_path: str | Path,
331 *,
332 target: str = "",
333 ) -> TestCoverageMap
334 ```
335
336 Build a mapping of production functions to their covering tests.
337
338 **Parameters:**
339
340 | Name | Type | Default | Description |
341 |---|---|---|---|
342 | `src_path` | `str \| Path` | — | Production code directory |
343 | `test_path` | `str \| Path` | — | Test directory |
344 | `target` | `str` | `""` | If set, only map coverage for this specific function |
345
346 **Returns:** `TestCoverageMap`
347
348 ---
349
350 ### `uncovered`
351
352 ```python
353 def uncovered(
354 self,
355 src_path: str | Path,
356 test_path: str | Path,
357 ) -> list[ContextNode]
358 ```
359
360 Return production functions and classes with no covering tests.
361
362 ---
363
364 ### TestCoverageMap
365
366 ```python
367 @dataclass
368 class TestCoverageMap:
369 coverage: dict[str, list[ContextNode]] # function name -> list of test nodes
370 uncovered: list[ContextNode]
371 coverage_percent: float
372 ```
373
374 | Field | Type | Description |
375 |---|---|---|
376 | `coverage` | `dict[str, list[ContextNode]]` | Maps each production function to its test nodes |
377 | `uncovered` | `list[ContextNode]` | Production functions with no tests |
378 | `coverage_percent` | `float` | Percentage of functions with at least one test |
379
380 **Example:**
381
382 ```python
383 mapper = TestMapper(store)
384 coverage_map = mapper.map("./src", "./tests")
385
386 print(f"Coverage: {coverage_map.coverage_percent:.1f}%")
387 print(f"Uncovered: {len(coverage_map.uncovered)} functions")
388
389 for fn_name, tests in coverage_map.coverage.items():
390 print(f" {fn_name}: {len(tests)} tests")
391 for test in tests:
392 print(f" {test.properties['file']}::{test.name}")
393 ```
--- docs/api/graph.md
+++ docs/api/graph.md
@@ -57,10 +57,16 @@
5757
) -> None: ...
5858
5959
def clear(self) -> None: ...
6060
6161
def close(self) -> None: ...
62
+
63
+ def export_jsonl(self, fp: IO[str]) -> None: ...
64
+ """Write all nodes and edges to a JSONL stream."""
65
+
66
+ def import_jsonl(self, fp: IO[str]) -> None: ...
67
+ """Read nodes and edges from a JSONL stream and merge into the graph."""
6268
```
6369
6470
### Usage
6571
6672
```python
@@ -242,10 +248,23 @@
242248
to_id: str
243249
edge_type: str # e.g. "CALLS", "ANNOTATES"
244250
properties: dict
245251
```
246252
253
+---
254
+
255
+## Schema migrations
256
+
257
+```python
258
+from navegador.graph import migrate
259
+
260
+store = GraphStore.sqlite(".navegador/navegador.db")
261
+migrate(store) # applies any pending schema migrations; idempotent
262
+```
263
+
264
+The `migrate()` function is safe to call on every startup. It compares the stored migration version against the current schema and applies only missing migrations.
265
+
247266
---
248267
249268
## Formatting output
250269
251270
```python
252271
--- docs/api/graph.md
+++ docs/api/graph.md
@@ -57,10 +57,16 @@
57 ) -> None: ...
58
59 def clear(self) -> None: ...
60
61 def close(self) -> None: ...
 
 
 
 
 
 
62 ```
63
64 ### Usage
65
66 ```python
@@ -242,10 +248,23 @@
242 to_id: str
243 edge_type: str # e.g. "CALLS", "ANNOTATES"
244 properties: dict
245 ```
246
 
 
 
 
 
 
 
 
 
 
 
 
 
247 ---
248
249 ## Formatting output
250
251 ```python
252
--- docs/api/graph.md
+++ docs/api/graph.md
@@ -57,10 +57,16 @@
57 ) -> None: ...
58
59 def clear(self) -> None: ...
60
61 def close(self) -> None: ...
62
63 def export_jsonl(self, fp: IO[str]) -> None: ...
64 """Write all nodes and edges to a JSONL stream."""
65
66 def import_jsonl(self, fp: IO[str]) -> None: ...
67 """Read nodes and edges from a JSONL stream and merge into the graph."""
68 ```
69
70 ### Usage
71
72 ```python
@@ -242,10 +248,23 @@
248 to_id: str
249 edge_type: str # e.g. "CALLS", "ANNOTATES"
250 properties: dict
251 ```
252
253 ---
254
255 ## Schema migrations
256
257 ```python
258 from navegador.graph import migrate
259
260 store = GraphStore.sqlite(".navegador/navegador.db")
261 migrate(store) # applies any pending schema migrations; idempotent
262 ```
263
264 The `migrate()` function is safe to call on every startup. It compares the stored migration version against the current schema and applies only missing migrations.
265
266 ---
267
268 ## Formatting output
269
270 ```python
271
--- docs/api/ingestion.md
+++ docs/api/ingestion.md
@@ -35,15 +35,20 @@
3535
def ingest(
3636
self,
3737
path: str | Path,
3838
*,
3939
clear: bool = False,
40
+ incremental: bool = False,
41
+ redact: bool = False,
42
+ monorepo: bool = False,
4043
) -> IngestionResult: ...
4144
4245
def ingest_file(
4346
self,
4447
path: str | Path,
48
+ *,
49
+ redact: bool = False,
4550
) -> IngestionResult: ...
4651
```
4752
4853
### Usage
4954
@@ -53,24 +58,43 @@
5358
5459
# full repo ingest
5560
result = ingester.ingest("./src")
5661
print(f"{result.nodes_created} nodes, {result.edges_created} edges")
5762
63
+# incremental ingest — only reprocesses files whose content hash has changed
64
+result = ingester.ingest("./src", incremental=True)
65
+
5866
# incremental: single file
5967
result = ingester.ingest_file("./src/auth/service.py")
6068
6169
# wipe + rebuild
6270
result = ingester.ingest("./src", clear=True)
71
+
72
+# redact sensitive content (strips tokens, passwords, keys from string literals)
73
+result = ingester.ingest("./src", redact=True)
74
+
75
+# monorepo — traverse workspace sub-packages
76
+result = ingester.ingest("./monorepo", monorepo=True)
6377
```
6478
6579
### Supported languages
6680
67
-| Language | File extensions | Parser |
68
-|---|---|---|
69
-| Python | `.py` | tree-sitter-python |
70
-| TypeScript | `.ts`, `.tsx` | tree-sitter-typescript |
71
-| JavaScript | `.js`, `.jsx` | tree-sitter-javascript |
81
+| Language | File extensions | Parser | Extra required |
82
+|---|---|---|---|
83
+| Python | `.py` | tree-sitter-python | — (included) |
84
+| TypeScript | `.ts`, `.tsx` | tree-sitter-typescript | — (included) |
85
+| JavaScript | `.js`, `.jsx` | tree-sitter-javascript | — (included) |
86
+| Go | `.go` | tree-sitter-go | — (included) |
87
+| Rust | `.rs` | tree-sitter-rust | — (included) |
88
+| Java | `.java` | tree-sitter-java | — (included) |
89
+| Kotlin | `.kt`, `.kts` | tree-sitter-kotlin | `navegador[languages]` |
90
+| C# | `.cs` | tree-sitter-c-sharp | `navegador[languages]` |
91
+| PHP | `.php` | tree-sitter-php | `navegador[languages]` |
92
+| Ruby | `.rb` | tree-sitter-ruby | `navegador[languages]` |
93
+| Swift | `.swift` | tree-sitter-swift | `navegador[languages]` |
94
+| C | `.c`, `.h` | tree-sitter-c | `navegador[languages]` |
95
+| C++ | `.cpp`, `.cc`, `.cxx`, `.hpp` | tree-sitter-cpp | `navegador[languages]` |
7296
7397
### Adding a new language parser
7498
7599
1. Install the tree-sitter grammar: `pip install tree-sitter-<lang>`
76100
2. Subclass `navegador.ingest.base.LanguageParser`:
@@ -95,10 +119,25 @@
95119
PARSERS["ruby"] = RubyParser
96120
```
97121
98122
`RepoIngester` dispatches to registered parsers by file extension.
99123
124
+### Framework enrichers
125
+
126
+After parsing, `RepoIngester` runs framework-specific enrichers that annotate nodes with framework context. Enrichers are discovered automatically based on what frameworks are detected in the repo.
127
+
128
+| Framework | What gets enriched |
129
+|---|---|
130
+| Django | Models, views, URL patterns, admin registrations |
131
+| FastAPI | Route handlers, dependency injections, Pydantic schemas |
132
+| React | Components, hooks, prop types |
133
+| Express | Route handlers, middleware chains |
134
+| React Native | Screens, navigators |
135
+| Rails | Controllers, models, routes |
136
+| Spring Boot | Beans, controllers, repositories |
137
+| Laravel | Controllers, models, routes |
138
+
100139
---
101140
102141
## KnowledgeIngester
103142
104143
Writes knowledge layer nodes. Wraps the `navegador add` commands programmatically.
@@ -266,5 +305,55 @@
266305
```
267306
268307
`input_type` values: `"auto"`, `"manifest"`, `"kg"`, `"interchange"`, `"batch"`.
269308
270309
See [Planopticon guide](../guide/planopticon.md) for format details and entity mapping.
310
+
311
+---
312
+
313
+## Export and import
314
+
315
+Navegador can export the full graph (or a subset) to JSONL for backup, migration, or sharing. The JSONL format is one JSON object per line, where each object is either a node or an edge.
316
+
317
+```bash
318
+navegador export > graph.jsonl
319
+navegador export --nodes-only > nodes.jsonl
320
+navegador import graph.jsonl
321
+```
322
+
323
+Python API:
324
+
325
+```python
326
+from navegador.graph import GraphStore
327
+
328
+store = GraphStore.sqlite(".navegador/navegador.db")
329
+
330
+# export
331
+with open("graph.jsonl", "w") as f:
332
+ store.export_jsonl(f)
333
+
334
+# import into a new store
335
+new_store = GraphStore.sqlite(".navegador/new.db")
336
+with open("graph.jsonl") as f:
337
+ new_store.import_jsonl(f)
338
+```
339
+
340
+---
341
+
342
+## Schema migrations
343
+
344
+When upgrading navegador, run `navegador migrate` before re-ingesting to apply schema changes (new node properties, new edge types, index updates):
345
+
346
+```bash
347
+navegador migrate
348
+```
349
+
350
+Migrations are idempotent — safe to run multiple times. The migration state is stored in the graph itself under a `_MigrationState` node.
351
+
352
+Python API:
353
+
354
+```python
355
+from navegador.graph import GraphStore, migrate
356
+
357
+store = GraphStore.sqlite(".navegador/navegador.db")
358
+migrate(store) # applies any pending migrations
359
+```
271360
--- docs/api/ingestion.md
+++ docs/api/ingestion.md
@@ -35,15 +35,20 @@
35 def ingest(
36 self,
37 path: str | Path,
38 *,
39 clear: bool = False,
 
 
 
40 ) -> IngestionResult: ...
41
42 def ingest_file(
43 self,
44 path: str | Path,
 
 
45 ) -> IngestionResult: ...
46 ```
47
48 ### Usage
49
@@ -53,24 +58,43 @@
53
54 # full repo ingest
55 result = ingester.ingest("./src")
56 print(f"{result.nodes_created} nodes, {result.edges_created} edges")
57
 
 
 
58 # incremental: single file
59 result = ingester.ingest_file("./src/auth/service.py")
60
61 # wipe + rebuild
62 result = ingester.ingest("./src", clear=True)
 
 
 
 
 
 
63 ```
64
65 ### Supported languages
66
67 | Language | File extensions | Parser |
68 |---|---|---|
69 | Python | `.py` | tree-sitter-python |
70 | TypeScript | `.ts`, `.tsx` | tree-sitter-typescript |
71 | JavaScript | `.js`, `.jsx` | tree-sitter-javascript |
 
 
 
 
 
 
 
 
 
 
72
73 ### Adding a new language parser
74
75 1. Install the tree-sitter grammar: `pip install tree-sitter-<lang>`
76 2. Subclass `navegador.ingest.base.LanguageParser`:
@@ -95,10 +119,25 @@
95 PARSERS["ruby"] = RubyParser
96 ```
97
98 `RepoIngester` dispatches to registered parsers by file extension.
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100 ---
101
102 ## KnowledgeIngester
103
104 Writes knowledge layer nodes. Wraps the `navegador add` commands programmatically.
@@ -266,5 +305,55 @@
266 ```
267
268 `input_type` values: `"auto"`, `"manifest"`, `"kg"`, `"interchange"`, `"batch"`.
269
270 See [Planopticon guide](../guide/planopticon.md) for format details and entity mapping.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
--- docs/api/ingestion.md
+++ docs/api/ingestion.md
@@ -35,15 +35,20 @@
35 def ingest(
36 self,
37 path: str | Path,
38 *,
39 clear: bool = False,
40 incremental: bool = False,
41 redact: bool = False,
42 monorepo: bool = False,
43 ) -> IngestionResult: ...
44
45 def ingest_file(
46 self,
47 path: str | Path,
48 *,
49 redact: bool = False,
50 ) -> IngestionResult: ...
51 ```
52
53 ### Usage
54
@@ -53,24 +58,43 @@
58
59 # full repo ingest
60 result = ingester.ingest("./src")
61 print(f"{result.nodes_created} nodes, {result.edges_created} edges")
62
63 # incremental ingest — only reprocesses files whose content hash has changed
64 result = ingester.ingest("./src", incremental=True)
65
66 # incremental: single file
67 result = ingester.ingest_file("./src/auth/service.py")
68
69 # wipe + rebuild
70 result = ingester.ingest("./src", clear=True)
71
72 # redact sensitive content (strips tokens, passwords, keys from string literals)
73 result = ingester.ingest("./src", redact=True)
74
75 # monorepo — traverse workspace sub-packages
76 result = ingester.ingest("./monorepo", monorepo=True)
77 ```
78
79 ### Supported languages
80
81 | Language | File extensions | Parser | Extra required |
82 |---|---|---|---|
83 | Python | `.py` | tree-sitter-python | — (included) |
84 | TypeScript | `.ts`, `.tsx` | tree-sitter-typescript | — (included) |
85 | JavaScript | `.js`, `.jsx` | tree-sitter-javascript | — (included) |
86 | Go | `.go` | tree-sitter-go | — (included) |
87 | Rust | `.rs` | tree-sitter-rust | — (included) |
88 | Java | `.java` | tree-sitter-java | — (included) |
89 | Kotlin | `.kt`, `.kts` | tree-sitter-kotlin | `navegador[languages]` |
90 | C# | `.cs` | tree-sitter-c-sharp | `navegador[languages]` |
91 | PHP | `.php` | tree-sitter-php | `navegador[languages]` |
92 | Ruby | `.rb` | tree-sitter-ruby | `navegador[languages]` |
93 | Swift | `.swift` | tree-sitter-swift | `navegador[languages]` |
94 | C | `.c`, `.h` | tree-sitter-c | `navegador[languages]` |
95 | C++ | `.cpp`, `.cc`, `.cxx`, `.hpp` | tree-sitter-cpp | `navegador[languages]` |
96
97 ### Adding a new language parser
98
99 1. Install the tree-sitter grammar: `pip install tree-sitter-<lang>`
100 2. Subclass `navegador.ingest.base.LanguageParser`:
@@ -95,10 +119,25 @@
119 PARSERS["ruby"] = RubyParser
120 ```
121
122 `RepoIngester` dispatches to registered parsers by file extension.
123
124 ### Framework enrichers
125
126 After parsing, `RepoIngester` runs framework-specific enrichers that annotate nodes with framework context. Enrichers are discovered automatically based on what frameworks are detected in the repo.
127
128 | Framework | What gets enriched |
129 |---|---|
130 | Django | Models, views, URL patterns, admin registrations |
131 | FastAPI | Route handlers, dependency injections, Pydantic schemas |
132 | React | Components, hooks, prop types |
133 | Express | Route handlers, middleware chains |
134 | React Native | Screens, navigators |
135 | Rails | Controllers, models, routes |
136 | Spring Boot | Beans, controllers, repositories |
137 | Laravel | Controllers, models, routes |
138
139 ---
140
141 ## KnowledgeIngester
142
143 Writes knowledge layer nodes. Wraps the `navegador add` commands programmatically.
@@ -266,5 +305,55 @@
305 ```
306
307 `input_type` values: `"auto"`, `"manifest"`, `"kg"`, `"interchange"`, `"batch"`.
308
309 See [Planopticon guide](../guide/planopticon.md) for format details and entity mapping.
310
311 ---
312
313 ## Export and import
314
315 Navegador can export the full graph (or a subset) to JSONL for backup, migration, or sharing. The JSONL format is one JSON object per line, where each object is either a node or an edge.
316
317 ```bash
318 navegador export > graph.jsonl
319 navegador export --nodes-only > nodes.jsonl
320 navegador import graph.jsonl
321 ```
322
323 Python API:
324
325 ```python
326 from navegador.graph import GraphStore
327
328 store = GraphStore.sqlite(".navegador/navegador.db")
329
330 # export
331 with open("graph.jsonl", "w") as f:
332 store.export_jsonl(f)
333
334 # import into a new store
335 new_store = GraphStore.sqlite(".navegador/new.db")
336 with open("graph.jsonl") as f:
337 new_store.import_jsonl(f)
338 ```
339
340 ---
341
342 ## Schema migrations
343
344 When upgrading navegador, run `navegador migrate` before re-ingesting to apply schema changes (new node properties, new edge types, index updates):
345
346 ```bash
347 navegador migrate
348 ```
349
350 Migrations are idempotent — safe to run multiple times. The migration state is stored in the graph itself under a `_MigrationState` node.
351
352 Python API:
353
354 ```python
355 from navegador.graph import GraphStore, migrate
356
357 store = GraphStore.sqlite(".navegador/navegador.db")
358 migrate(store) # applies any pending migrations
359 ```
360
+152 -3
--- docs/api/mcp.md
+++ docs/api/mcp.md
@@ -12,16 +12,21 @@
1212
1313
```python
1414
def create_mcp_server(
1515
store: GraphStore | None = None,
1616
db_path: str = "",
17
+ read_only: bool = False,
18
+ max_query_complexity: int = 0,
1719
) -> MCPServer: ...
1820
```
1921
2022
Creates and returns an MCP server instance. If `store` is not provided, opens a `GraphStore.sqlite()` at `db_path` (or `NAVEGADOR_DB` env var, or `./navegador.db`).
2123
22
-The CLI command `navegador mcp [--db path]` calls this function and runs the server loop.
24
+- `read_only`: when `True`, disables the `ingest` tool and restricts the `query` tool to `MATCH`/`RETURN` only. Corresponds to `navegador mcp --read-only`.
25
+- `max_query_complexity`: if non-zero, rejects Cypher queries whose estimated complexity exceeds this value. Prevents runaway traversals in multi-agent environments.
26
+
27
+The CLI command `navegador mcp [--db path] [--read-only]` calls this function and runs the server loop.
2328
2429
### Usage
2530
2631
```python
2732
from navegador.graph import GraphStore
@@ -42,11 +47,11 @@
4247
4348
---
4449
4550
## Available MCP tools
4651
47
-All tools accept JSON input and return JSON output.
52
+All tools accept JSON input and return JSON output. There are 11 tools in total.
4853
4954
---
5055
5156
### `ingest`
5257
@@ -246,6 +251,150 @@
246251
```
247252
248253
**Output:** Array of result rows as JSON.
249254
250255
!!! warning
251
- This tool executes writes as well as reads. Agents should use read-only queries (`MATCH` / `RETURN`) unless explicitly performing graph updates.
256
+ This tool executes writes as well as reads. Agents should use read-only queries (`MATCH` / `RETURN`) unless explicitly performing graph updates. Use `--read-only` mode or `read_only=True` in `create_mcp_server()` to enforce this at the server level.
257
+
258
+---
259
+
260
+### `get_rationale`
261
+
262
+Return the rationale, decisions, and rules that govern a named code node.
263
+
264
+**Input schema:**
265
+```json
266
+{
267
+ "type": "object",
268
+ "properties": {
269
+ "name": {
270
+ "type": "string",
271
+ "description": "Function, class, or file name"
272
+ },
273
+ "file": {
274
+ "type": "string",
275
+ "description": "Optional file path to disambiguate"
276
+ }
277
+ },
278
+ "required": ["name"]
279
+}
280
+```
281
+
282
+**Output:** Array of `Decision` and `Rule` nodes with `rationale` fields, as JSON.
283
+
284
+---
285
+
286
+### `find_owners`
287
+
288
+Return the people and domains that own a code node, based on CODEOWNERS, annotation, and domain membership.
289
+
290
+**Input schema:**
291
+```json
292
+{
293
+ "type": "object",
294
+ "properties": {
295
+ "name": {
296
+ "type": "string",
297
+ "description": "Function, class, or file name"
298
+ },
299
+ "file": {
300
+ "type": "string",
301
+ "description": "Optional file path"
302
+ }
303
+ },
304
+ "required": ["name"]
305
+}
306
+```
307
+
308
+**Output:** Array of `Person` and `Domain` nodes as JSON.
309
+
310
+---
311
+
312
+### `search_knowledge`
313
+
314
+Search the knowledge layer only (concepts, rules, decisions, wiki pages, domains).
315
+
316
+**Input schema:**
317
+```json
318
+{
319
+ "type": "object",
320
+ "properties": {
321
+ "query": {
322
+ "type": "string",
323
+ "description": "Search query"
324
+ },
325
+ "limit": {
326
+ "type": "integer",
327
+ "description": "Maximum results to return",
328
+ "default": 20
329
+ }
330
+ },
331
+ "required": ["query"]
332
+}
333
+```
334
+
335
+**Output:** Array of knowledge layer `ContextNode` objects as JSON.
336
+
337
+---
338
+
339
+### `blast_radius`
340
+
341
+Return all code nodes transitively reachable from a given node via CALLS, IMPORTS, and INHERITS edges — the set of things that could break if this node changes.
342
+
343
+**Input schema:**
344
+```json
345
+{
346
+ "type": "object",
347
+ "properties": {
348
+ "name": {
349
+ "type": "string",
350
+ "description": "Starting node name"
351
+ },
352
+ "file": {
353
+ "type": "string",
354
+ "description": "Optional file path to disambiguate"
355
+ },
356
+ "depth": {
357
+ "type": "integer",
358
+ "description": "Maximum traversal depth",
359
+ "default": 3
360
+ }
361
+ },
362
+ "required": ["name"]
363
+}
364
+```
365
+
366
+**Output:** Array of `ContextNode` objects ordered by distance from the starting node.
367
+
368
+---
369
+
370
+## Security
371
+
372
+### Read-only mode
373
+
374
+Start the server in read-only mode to prevent agents from modifying the graph:
375
+
376
+```bash
377
+navegador mcp --read-only
378
+```
379
+
380
+In read-only mode:
381
+- The `ingest` tool is disabled (returns an error if called)
382
+- The `query` tool validates that queries contain only `MATCH`, `RETURN`, `WITH`, `WHERE`, `ORDER BY`, `LIMIT`, and `SKIP` clauses
383
+- Write Cypher keywords (`CREATE`, `MERGE`, `SET`, `DELETE`, `DETACH`) are rejected
384
+
385
+### Query complexity limits
386
+
387
+Set a maximum query complexity to prevent runaway traversals:
388
+
389
+```bash
390
+navegador mcp --max-query-complexity 100
391
+```
392
+
393
+Or in `.navegador/config.toml`:
394
+
395
+```toml
396
+[mcp]
397
+max_query_complexity = 100
398
+```
399
+
400
+Queries that exceed the complexity threshold return an error rather than executing.
252401
253402
ADDED docs/api/sdk.md
--- docs/api/mcp.md
+++ docs/api/mcp.md
@@ -12,16 +12,21 @@
12
13 ```python
14 def create_mcp_server(
15 store: GraphStore | None = None,
16 db_path: str = "",
 
 
17 ) -> MCPServer: ...
18 ```
19
20 Creates and returns an MCP server instance. If `store` is not provided, opens a `GraphStore.sqlite()` at `db_path` (or `NAVEGADOR_DB` env var, or `./navegador.db`).
21
22 The CLI command `navegador mcp [--db path]` calls this function and runs the server loop.
 
 
 
23
24 ### Usage
25
26 ```python
27 from navegador.graph import GraphStore
@@ -42,11 +47,11 @@
42
43 ---
44
45 ## Available MCP tools
46
47 All tools accept JSON input and return JSON output.
48
49 ---
50
51 ### `ingest`
52
@@ -246,6 +251,150 @@
246 ```
247
248 **Output:** Array of result rows as JSON.
249
250 !!! warning
251 This tool executes writes as well as reads. Agents should use read-only queries (`MATCH` / `RETURN`) unless explicitly performing graph updates.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
253 DDED docs/api/sdk.md
--- docs/api/mcp.md
+++ docs/api/mcp.md
@@ -12,16 +12,21 @@
12
13 ```python
14 def create_mcp_server(
15 store: GraphStore | None = None,
16 db_path: str = "",
17 read_only: bool = False,
18 max_query_complexity: int = 0,
19 ) -> MCPServer: ...
20 ```
21
22 Creates and returns an MCP server instance. If `store` is not provided, opens a `GraphStore.sqlite()` at `db_path` (or `NAVEGADOR_DB` env var, or `./navegador.db`).
23
24 - `read_only`: when `True`, disables the `ingest` tool and restricts the `query` tool to `MATCH`/`RETURN` only. Corresponds to `navegador mcp --read-only`.
25 - `max_query_complexity`: if non-zero, rejects Cypher queries whose estimated complexity exceeds this value. Prevents runaway traversals in multi-agent environments.
26
27 The CLI command `navegador mcp [--db path] [--read-only]` calls this function and runs the server loop.
28
29 ### Usage
30
31 ```python
32 from navegador.graph import GraphStore
@@ -42,11 +47,11 @@
47
48 ---
49
50 ## Available MCP tools
51
52 All tools accept JSON input and return JSON output. There are 11 tools in total.
53
54 ---
55
56 ### `ingest`
57
@@ -246,6 +251,150 @@
251 ```
252
253 **Output:** Array of result rows as JSON.
254
255 !!! warning
256 This tool executes writes as well as reads. Agents should use read-only queries (`MATCH` / `RETURN`) unless explicitly performing graph updates. Use `--read-only` mode or `read_only=True` in `create_mcp_server()` to enforce this at the server level.
257
258 ---
259
260 ### `get_rationale`
261
262 Return the rationale, decisions, and rules that govern a named code node.
263
264 **Input schema:**
265 ```json
266 {
267 "type": "object",
268 "properties": {
269 "name": {
270 "type": "string",
271 "description": "Function, class, or file name"
272 },
273 "file": {
274 "type": "string",
275 "description": "Optional file path to disambiguate"
276 }
277 },
278 "required": ["name"]
279 }
280 ```
281
282 **Output:** Array of `Decision` and `Rule` nodes with `rationale` fields, as JSON.
283
284 ---
285
286 ### `find_owners`
287
288 Return the people and domains that own a code node, based on CODEOWNERS, annotation, and domain membership.
289
290 **Input schema:**
291 ```json
292 {
293 "type": "object",
294 "properties": {
295 "name": {
296 "type": "string",
297 "description": "Function, class, or file name"
298 },
299 "file": {
300 "type": "string",
301 "description": "Optional file path"
302 }
303 },
304 "required": ["name"]
305 }
306 ```
307
308 **Output:** Array of `Person` and `Domain` nodes as JSON.
309
310 ---
311
312 ### `search_knowledge`
313
314 Search the knowledge layer only (concepts, rules, decisions, wiki pages, domains).
315
316 **Input schema:**
317 ```json
318 {
319 "type": "object",
320 "properties": {
321 "query": {
322 "type": "string",
323 "description": "Search query"
324 },
325 "limit": {
326 "type": "integer",
327 "description": "Maximum results to return",
328 "default": 20
329 }
330 },
331 "required": ["query"]
332 }
333 ```
334
335 **Output:** Array of knowledge layer `ContextNode` objects as JSON.
336
337 ---
338
339 ### `blast_radius`
340
341 Return all code nodes transitively reachable from a given node via CALLS, IMPORTS, and INHERITS edges — the set of things that could break if this node changes.
342
343 **Input schema:**
344 ```json
345 {
346 "type": "object",
347 "properties": {
348 "name": {
349 "type": "string",
350 "description": "Starting node name"
351 },
352 "file": {
353 "type": "string",
354 "description": "Optional file path to disambiguate"
355 },
356 "depth": {
357 "type": "integer",
358 "description": "Maximum traversal depth",
359 "default": 3
360 }
361 },
362 "required": ["name"]
363 }
364 ```
365
366 **Output:** Array of `ContextNode` objects ordered by distance from the starting node.
367
368 ---
369
370 ## Security
371
372 ### Read-only mode
373
374 Start the server in read-only mode to prevent agents from modifying the graph:
375
376 ```bash
377 navegador mcp --read-only
378 ```
379
380 In read-only mode:
381 - The `ingest` tool is disabled (returns an error if called)
382 - The `query` tool validates that queries contain only `MATCH`, `RETURN`, `WITH`, `WHERE`, `ORDER BY`, `LIMIT`, and `SKIP` clauses
383 - Write Cypher keywords (`CREATE`, `MERGE`, `SET`, `DELETE`, `DETACH`) are rejected
384
385 ### Query complexity limits
386
387 Set a maximum query complexity to prevent runaway traversals:
388
389 ```bash
390 navegador mcp --max-query-complexity 100
391 ```
392
393 Or in `.navegador/config.toml`:
394
395 ```toml
396 [mcp]
397 max_query_complexity = 100
398 ```
399
400 Queries that exceed the complexity threshold return an error rather than executing.
401
402 DDED docs/api/sdk.md
--- a/docs/api/sdk.md
+++ b/docs/api/sdk.md
@@ -0,0 +1,486 @@
1
+# Python SDK Reference
2
+
3
+Full API reference for the navegador Python SDK.
4
+
5
+```python
6
+from navegador.graph import GraphStore
7
+from navegador.context import ContextLoader, ContextBundle, ContextNode, ContextEdge
8
+from navegador.ingest import RepoIngester, KnowledgeIngester, WikiIngester, PlanopticonIngester
9
+```
10
+
11
+---
12
+
13
+## GraphStore
14
+
15
+Database abstraction layer. Both SQLite and Redis backends implement this interface.
16
+
17
+```python
18
+class GraphStore:
19
+ @classmethod
20
+ def sqlite(cls, path: str | Path = "navegador.db") -> "GraphStore": ...
21
+
22
+ @classmethod
23
+ def redis(cls, url: str = "redis://localhost:6379") -> "GraphStore": ...
24
+```
25
+
26
+### Class methods
27
+
28
+#### `GraphStore.sqlite`
29
+
30
+```python
31
+@classmethod
32
+def sqlite(cls, path: str | Path = "navegador.db") -> "GraphStore"
33
+```
34
+
35
+Open a local SQLite-backed graph. The file is created if it does not exist. Uses `falkordblite` (embedded engine — no daemon required).
36
+
37
+**Parameters:**
38
+
39
+| Name | Type | Default | Description |
40
+|---|---|---|---|
41
+| `path` | `str \| Path` | `"navegador.db"` | Path to the `.db` file |
42
+
43
+**Returns:** `GraphStore`
44
+
45
+#### `GraphStore.redis`
46
+
47
+```python
48
+@classmethod
49
+def redis(cls, url: str = "redis://localhost:6379") -> "GraphStore"
50
+```
51
+
52
+Connect to a Redis-backed FalkorDB instance.
53
+
54
+**Parameters:**
55
+
56
+| Name | Type | Default | Description |
57
+|---|---|---|---|
58
+| `url` | `str` | `"redis://localhost:6379"` | Redis connection URL |
59
+
60
+**Returns:** `GraphStore`
61
+
62
+---
63
+
64
+### Instance methods
65
+
66
+#### `query`
67
+
68
+```python
69
+def query(self, cypher: str, params: dict | None = None) -> list[dict]
70
+```
71
+
72
+Execute a Cypher query and return all result rows.
73
+
74
+**Parameters:**
75
+
76
+| Name | Type | Default | Description |
77
+|---|---|---|---|
78
+| `cypher` | `str` | — | Cypher query string |
79
+| `params` | `dict \| None` | `None` | Optional query parameters |
80
+
81
+**Returns:** `list[dict]` — one dict per result row, keyed by return variable name.
82
+
83
+---
84
+
85
+#### `create_node`
86
+
87
+```python
88
+def create_node(self, label: str, properties: dict) -> str
89
+```
90
+
91
+Create a new node and return its ID.
92
+
93
+**Parameters:**
94
+
95
+| Name | Type | Description |
96
+|---|---|---|
97
+| `label` | `str` | Node label (e.g., `"Function"`, `"Concept"`) |
98
+| `properties` | `dict` | Node properties |
99
+
100
+**Returns:** `str` — node ID
101
+
102
+---
103
+
104
+#### `merge_node`
105
+
106
+```python
107
+def merge_node(
108
+ self,
109
+ label: str,
110
+ match_properties: dict,
111
+ set_properties: dict | None = None,
112
+) -> str
113
+```
114
+
115
+Upsert a node: create it if no node with `match_properties` exists; otherwise update `set_properties` on the existing node.
116
+
117
+**Parameters:**
118
+
119
+| Name | Type | Default | Description |
120
+|---|---|---|---|
121
+| `label` | `str` | — | Node label |
122
+| `match_properties` | `dict` | — | Properties to match on (identity key) |
123
+| `set_properties` | `dict \| None` | `None` | Properties to set on create or update |
124
+
125
+**Returns:** `str` — node ID
126
+
127
+---
128
+
129
+#### `create_edge`
130
+
131
+```python
132
+def create_edge(
133
+ self,
134
+ from_id: str,
135
+ to_id: str,
136
+ edge_type: str,
137
+ properties: dict | None = None,
138
+) -> None
139
+```
140
+
141
+Create a directed edge between two nodes.
142
+
143
+**Parameters:**
144
+
145
+| Name | Type | Default | Description |
146
+|---|---|---|---|
147
+| `from_id` | `str` | — | Source node ID |
148
+| `to_id` | `str` | — | Target node ID |
149
+| `edge_type` | `str` | — | Relationship type (e.g., `"CALLS"`, `"ANNOTATES"`) |
150
+| `properties` | `dict \| None` | `None` | Optional edge properties |
151
+
152
+---
153
+
154
+#### `merge_edge`
155
+
156
+```python
157
+def merge_edge(
158
+ self,
159
+ from_label: str,
160
+ from_match: dict,
161
+ to_label: str,
162
+ to_match: dict,
163
+ edge_type: str,
164
+ properties: dict | None = None,
165
+) -> None
166
+```
167
+
168
+Upsert an edge between two nodes matched by label and properties.
169
+
170
+---
171
+
172
+#### `clear`
173
+
174
+```python
175
+def clear(self) -> None
176
+```
177
+
178
+Delete all nodes and edges from the graph.
179
+
180
+---
181
+
182
+#### `close`
183
+
184
+```python
185
+def close(self) -> None
186
+```
187
+
188
+Release the database connection. Called automatically when used as a context manager.
189
+
190
+---
191
+
192
+#### Context manager
193
+
194
+`GraphStore` implements `__enter__` / `__exit__`. Use with `with` to ensure the connection is closed:
195
+
196
+```python
197
+with GraphStore.sqlite(".navegador/navegador.db") as store:
198
+ results = store.query("MATCH (n) RETURN count(n) AS total")
199
+```
200
+
201
+---
202
+
203
+## ContextLoader
204
+
205
+Builds structured context bundles from graph queries.
206
+
207
+```python
208
+class ContextLoader:
209
+ def __init__(self, store: GraphStore) -> None: ...
210
+```
211
+
212
+### Methods
213
+
214
+#### `load_file`
215
+
216
+```python
217
+def load_file(self, path: str) -> ContextBundle
218
+```
219
+
220
+Return the full context bundle for a source file: the file node, its modules, classes, functions, imports, and their relationships.
221
+
222
+**Parameters:**
223
+
224
+| Name | Type | Description |
225
+|---|---|---|
226
+| `path` | `str` | Relative or absolute path to the source file |
227
+
228
+**Returns:** `ContextBundle`
229
+
230
+---
231
+
232
+#### `load_function`
233
+
234
+```python
235
+def load_function(
236
+ self,
237
+ name: str,
238
+ *,
239
+ file: str = "",
240
+ depth: int = 1,
241
+) -> ContextBundle
242
+```
243
+
244
+Return a function node with its callers, callees, decorators, containing class, and source.
245
+
246
+**Parameters:**
247
+
248
+| Name | Type | Default | Description |
249
+|---|---|---|---|
250
+| `name` | `str` | — | Function name |
251
+| `file` | `str` | `""` | Optional file path to disambiguate |
252
+| `depth` | `int` | `1` | Call graph traversal depth (1 = direct callers/callees only) |
253
+
254
+**Returns:** `ContextBundle`
255
+
256
+---
257
+
258
+#### `load_class`
259
+
260
+```python
261
+def load_class(
262
+ self,
263
+ name: str,
264
+ *,
265
+ file: str = "",
266
+) -> ContextBundle
267
+```
268
+
269
+Return a class node with its methods, base classes, subclasses, and references from other files.
270
+
271
+**Parameters:**
272
+
273
+| Name | Type | Default | Description |
274
+|---|---|---|---|
275
+| `name` | `str` | — | Class name |
276
+| `file` | `str` | `""` | Optional file path to disambiguate |
277
+
278
+**Returns:** `ContextBundle`
279
+
280
+---
281
+
282
+#### `explain`
283
+
284
+```python
285
+def explain(
286
+ self,
287
+ name: str,
288
+ *,
289
+ file: str = "",
290
+) -> ContextBundle
291
+```
292
+
293
+Universal lookup: explain any node (function, class, file, concept, rule, decision) by name.
294
+
295
+**Parameters:**
296
+
297
+| Name | Type | Default | Description |
298
+|---|---|---|---|
299
+| `name` | `str` | — | Node name or file path |
300
+| `file` | `str` | `""` | Optional file path to disambiguate code nodes |
301
+
302
+**Returns:** `ContextBundle`
303
+
304
+---
305
+
306
+#### `load_concept`
307
+
308
+```python
309
+def load_concept(self, name: str) -> ContextBundle
310
+```
311
+
312
+Return a concept node with its rules, linked wiki pages, and annotated code nodes.
313
+
314
+---
315
+
316
+#### `load_domain`
317
+
318
+```python
319
+def load_domain(self, name: str) -> ContextBundle
320
+```
321
+
322
+Return a domain and all nodes belonging to it: concepts, rules, decisions, people, and annotated code.
323
+
324
+---
325
+
326
+#### `search`
327
+
328
+```python
329
+def search(
330
+ self,
331
+ query: str,
332
+ *,
333
+ all_layers: bool = False,
334
+ docs_only: bool = False,
335
+ limit: int = 20,
336
+) -> list[ContextNode]
337
+```
338
+
339
+Search the graph by text query.
340
+
341
+**Parameters:**
342
+
343
+| Name | Type | Default | Description |
344
+|---|---|---|---|
345
+| `query` | `str` | — | Search string |
346
+| `all_layers` | `bool` | `False` | Search all layers including knowledge and docs |
347
+| `docs_only` | `bool` | `False` | Search docstrings and wiki content only |
348
+| `limit` | `int` | `20` | Maximum number of results |
349
+
350
+**Returns:** `list[ContextNode]`
351
+
352
+---
353
+
354
+#### `search_by_docstring`
355
+
356
+```python
357
+def search_by_docstring(self, query: str, *, limit: int = 20) -> list[ContextNode]
358
+```
359
+
360
+Search docstrings and wiki page content. Equivalent to `search(query, docs_only=True)`.
361
+
362
+---
363
+
364
+#### `decorated_by`
365
+
366
+```python
367
+def decorated_by(self, decorator: str) -> list[ContextNode]
368
+```
369
+
370
+Find all functions and classes that use a specific decorator.
371
+
372
+**Parameters:**
373
+
374
+| Name | Type | Description |
375
+|---|---|---|
376
+| `decorator` | `str` | Decorator name (e.g., `"login_required"`, `"pytest.mark.parametrize"`) |
377
+
378
+**Returns:** `list[ContextNode]`
379
+
380
+---
381
+
382
+## ContextBundle
383
+
384
+Structured result returned by `ContextLoader` methods.
385
+
386
+```python
387
+@dataclass
388
+class ContextBundle:
389
+ root: ContextNode
390
+ nodes: list[ContextNode]
391
+ edges: list[ContextEdge]
392
+ metadata: dict
393
+```
394
+
395
+### Fields
396
+
397
+| Field | Type | Description |
398
+|---|---|---|
399
+| `root` | `ContextNode` | The primary node (function, class, file, etc.) |
400
+| `nodes` | `list[ContextNode]` | All nodes in the bundle, including `root` |
401
+| `edges` | `list[ContextEdge]` | All edges between nodes in the bundle |
402
+| `metadata` | `dict` | Query metadata (depth, timing, node counts) |
403
+
404
+### Methods
405
+
406
+#### `to_json`
407
+
408
+```python
409
+def to_json(self) -> str
410
+```
411
+
412
+Serialize the bundle to a JSON string.
413
+
414
+#### `to_markdown`
415
+
416
+```python
417
+def to_markdown(self) -> str
418
+```
419
+
420
+Render the bundle as a Markdown string. Suitable for pasting into agent context.
421
+
422
+#### `to_dict`
423
+
424
+```python
425
+def to_dict(self) -> dict
426
+```
427
+
428
+Return the bundle as a plain Python dict.
429
+
430
+---
431
+
432
+## ContextNode
433
+
434
+A single node in a context bundle.
435
+
436
+```python
437
+@dataclass
438
+class ContextNode:
439
+ id: str
440
+ label: str # e.g. "Function", "Concept"
441
+ name: str
442
+ properties: dict # all node properties from the graph
443
+ layer: str # "code" or "knowledge"
444
+ score: float # relevance score (search results only)
445
+```
446
+
447
+---
448
+
449
+## ContextEdge
450
+
451
+A relationship between two nodes in a context bundle.
452
+
453
+```python
454
+@dataclass
455
+class ContextEdge:
456
+ from_id: str
457
+ to_id: str
458
+ edge_type: str # e.g. "CALLS", "ANNOTATES", "INHERITS"
459
+ properties: dict
460
+```
461
+
462
+---
463
+
464
+## IngestionResult
465
+
466
+Returned by all ingest methods.
467
+
468
+```python
469
+@dataclass
470
+class IngestionResult:
471
+ nodes_created: int
472
+ nodes_updated: int
473
+ edges_created: int
474
+ files_processed: int
475
+ errors: list[str]
476
+ duration_seconds: float
477
+```
478
+
479
+| Field | Type | Description |
480
+|---|---|---|
481
+| `nodes_created` | `int` | New nodes written to the graph |
482
+| `nodes_updated` | `int` | Existing nodes updated |
483
+| `edges_created` | `int` | New edges written |
484
+| `files_processed` | `int` | Source files walked |
485
+| `errors` | `list[str]` | Per-file parse errors (non-fatal) |
486
+| `duration_seconds` | `float` | Wall time for the ingest operation |
--- a/docs/api/sdk.md
+++ b/docs/api/sdk.md
@@ -0,0 +1,486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/api/sdk.md
+++ b/docs/api/sdk.md
@@ -0,0 +1,486 @@
1 # Python SDK Reference
2
3 Full API reference for the navegador Python SDK.
4
5 ```python
6 from navegador.graph import GraphStore
7 from navegador.context import ContextLoader, ContextBundle, ContextNode, ContextEdge
8 from navegador.ingest import RepoIngester, KnowledgeIngester, WikiIngester, PlanopticonIngester
9 ```
10
11 ---
12
13 ## GraphStore
14
15 Database abstraction layer. Both SQLite and Redis backends implement this interface.
16
17 ```python
18 class GraphStore:
19 @classmethod
20 def sqlite(cls, path: str | Path = "navegador.db") -> "GraphStore": ...
21
22 @classmethod
23 def redis(cls, url: str = "redis://localhost:6379") -> "GraphStore": ...
24 ```
25
26 ### Class methods
27
28 #### `GraphStore.sqlite`
29
30 ```python
31 @classmethod
32 def sqlite(cls, path: str | Path = "navegador.db") -> "GraphStore"
33 ```
34
35 Open a local SQLite-backed graph. The file is created if it does not exist. Uses `falkordblite` (embedded engine — no daemon required).
36
37 **Parameters:**
38
39 | Name | Type | Default | Description |
40 |---|---|---|---|
41 | `path` | `str \| Path` | `"navegador.db"` | Path to the `.db` file |
42
43 **Returns:** `GraphStore`
44
45 #### `GraphStore.redis`
46
47 ```python
48 @classmethod
49 def redis(cls, url: str = "redis://localhost:6379") -> "GraphStore"
50 ```
51
52 Connect to a Redis-backed FalkorDB instance.
53
54 **Parameters:**
55
56 | Name | Type | Default | Description |
57 |---|---|---|---|
58 | `url` | `str` | `"redis://localhost:6379"` | Redis connection URL |
59
60 **Returns:** `GraphStore`
61
62 ---
63
64 ### Instance methods
65
66 #### `query`
67
68 ```python
69 def query(self, cypher: str, params: dict | None = None) -> list[dict]
70 ```
71
72 Execute a Cypher query and return all result rows.
73
74 **Parameters:**
75
76 | Name | Type | Default | Description |
77 |---|---|---|---|
78 | `cypher` | `str` | — | Cypher query string |
79 | `params` | `dict \| None` | `None` | Optional query parameters |
80
81 **Returns:** `list[dict]` — one dict per result row, keyed by return variable name.
82
83 ---
84
85 #### `create_node`
86
87 ```python
88 def create_node(self, label: str, properties: dict) -> str
89 ```
90
91 Create a new node and return its ID.
92
93 **Parameters:**
94
95 | Name | Type | Description |
96 |---|---|---|
97 | `label` | `str` | Node label (e.g., `"Function"`, `"Concept"`) |
98 | `properties` | `dict` | Node properties |
99
100 **Returns:** `str` — node ID
101
102 ---
103
104 #### `merge_node`
105
106 ```python
107 def merge_node(
108 self,
109 label: str,
110 match_properties: dict,
111 set_properties: dict | None = None,
112 ) -> str
113 ```
114
115 Upsert a node: create it if no node with `match_properties` exists; otherwise update `set_properties` on the existing node.
116
117 **Parameters:**
118
119 | Name | Type | Default | Description |
120 |---|---|---|---|
121 | `label` | `str` | — | Node label |
122 | `match_properties` | `dict` | — | Properties to match on (identity key) |
123 | `set_properties` | `dict \| None` | `None` | Properties to set on create or update |
124
125 **Returns:** `str` — node ID
126
127 ---
128
129 #### `create_edge`
130
131 ```python
132 def create_edge(
133 self,
134 from_id: str,
135 to_id: str,
136 edge_type: str,
137 properties: dict | None = None,
138 ) -> None
139 ```
140
141 Create a directed edge between two nodes.
142
143 **Parameters:**
144
145 | Name | Type | Default | Description |
146 |---|---|---|---|
147 | `from_id` | `str` | — | Source node ID |
148 | `to_id` | `str` | — | Target node ID |
149 | `edge_type` | `str` | — | Relationship type (e.g., `"CALLS"`, `"ANNOTATES"`) |
150 | `properties` | `dict \| None` | `None` | Optional edge properties |
151
152 ---
153
154 #### `merge_edge`
155
156 ```python
157 def merge_edge(
158 self,
159 from_label: str,
160 from_match: dict,
161 to_label: str,
162 to_match: dict,
163 edge_type: str,
164 properties: dict | None = None,
165 ) -> None
166 ```
167
168 Upsert an edge between two nodes matched by label and properties.
169
170 ---
171
172 #### `clear`
173
174 ```python
175 def clear(self) -> None
176 ```
177
178 Delete all nodes and edges from the graph.
179
180 ---
181
182 #### `close`
183
184 ```python
185 def close(self) -> None
186 ```
187
188 Release the database connection. Called automatically when used as a context manager.
189
190 ---
191
192 #### Context manager
193
194 `GraphStore` implements `__enter__` / `__exit__`. Use with `with` to ensure the connection is closed:
195
196 ```python
197 with GraphStore.sqlite(".navegador/navegador.db") as store:
198 results = store.query("MATCH (n) RETURN count(n) AS total")
199 ```
200
201 ---
202
203 ## ContextLoader
204
205 Builds structured context bundles from graph queries.
206
207 ```python
208 class ContextLoader:
209 def __init__(self, store: GraphStore) -> None: ...
210 ```
211
212 ### Methods
213
214 #### `load_file`
215
216 ```python
217 def load_file(self, path: str) -> ContextBundle
218 ```
219
220 Return the full context bundle for a source file: the file node, its modules, classes, functions, imports, and their relationships.
221
222 **Parameters:**
223
224 | Name | Type | Description |
225 |---|---|---|
226 | `path` | `str` | Relative or absolute path to the source file |
227
228 **Returns:** `ContextBundle`
229
230 ---
231
232 #### `load_function`
233
234 ```python
235 def load_function(
236 self,
237 name: str,
238 *,
239 file: str = "",
240 depth: int = 1,
241 ) -> ContextBundle
242 ```
243
244 Return a function node with its callers, callees, decorators, containing class, and source.
245
246 **Parameters:**
247
248 | Name | Type | Default | Description |
249 |---|---|---|---|
250 | `name` | `str` | — | Function name |
251 | `file` | `str` | `""` | Optional file path to disambiguate |
252 | `depth` | `int` | `1` | Call graph traversal depth (1 = direct callers/callees only) |
253
254 **Returns:** `ContextBundle`
255
256 ---
257
258 #### `load_class`
259
260 ```python
261 def load_class(
262 self,
263 name: str,
264 *,
265 file: str = "",
266 ) -> ContextBundle
267 ```
268
269 Return a class node with its methods, base classes, subclasses, and references from other files.
270
271 **Parameters:**
272
273 | Name | Type | Default | Description |
274 |---|---|---|---|
275 | `name` | `str` | — | Class name |
276 | `file` | `str` | `""` | Optional file path to disambiguate |
277
278 **Returns:** `ContextBundle`
279
280 ---
281
282 #### `explain`
283
284 ```python
285 def explain(
286 self,
287 name: str,
288 *,
289 file: str = "",
290 ) -> ContextBundle
291 ```
292
293 Universal lookup: explain any node (function, class, file, concept, rule, decision) by name.
294
295 **Parameters:**
296
297 | Name | Type | Default | Description |
298 |---|---|---|---|
299 | `name` | `str` | — | Node name or file path |
300 | `file` | `str` | `""` | Optional file path to disambiguate code nodes |
301
302 **Returns:** `ContextBundle`
303
304 ---
305
306 #### `load_concept`
307
308 ```python
309 def load_concept(self, name: str) -> ContextBundle
310 ```
311
312 Return a concept node with its rules, linked wiki pages, and annotated code nodes.
313
314 ---
315
316 #### `load_domain`
317
318 ```python
319 def load_domain(self, name: str) -> ContextBundle
320 ```
321
322 Return a domain and all nodes belonging to it: concepts, rules, decisions, people, and annotated code.
323
324 ---
325
326 #### `search`
327
328 ```python
329 def search(
330 self,
331 query: str,
332 *,
333 all_layers: bool = False,
334 docs_only: bool = False,
335 limit: int = 20,
336 ) -> list[ContextNode]
337 ```
338
339 Search the graph by text query.
340
341 **Parameters:**
342
343 | Name | Type | Default | Description |
344 |---|---|---|---|
345 | `query` | `str` | — | Search string |
346 | `all_layers` | `bool` | `False` | Search all layers including knowledge and docs |
347 | `docs_only` | `bool` | `False` | Search docstrings and wiki content only |
348 | `limit` | `int` | `20` | Maximum number of results |
349
350 **Returns:** `list[ContextNode]`
351
352 ---
353
354 #### `search_by_docstring`
355
356 ```python
357 def search_by_docstring(self, query: str, *, limit: int = 20) -> list[ContextNode]
358 ```
359
360 Search docstrings and wiki page content. Equivalent to `search(query, docs_only=True)`.
361
362 ---
363
364 #### `decorated_by`
365
366 ```python
367 def decorated_by(self, decorator: str) -> list[ContextNode]
368 ```
369
370 Find all functions and classes that use a specific decorator.
371
372 **Parameters:**
373
374 | Name | Type | Description |
375 |---|---|---|
376 | `decorator` | `str` | Decorator name (e.g., `"login_required"`, `"pytest.mark.parametrize"`) |
377
378 **Returns:** `list[ContextNode]`
379
380 ---
381
382 ## ContextBundle
383
384 Structured result returned by `ContextLoader` methods.
385
386 ```python
387 @dataclass
388 class ContextBundle:
389 root: ContextNode
390 nodes: list[ContextNode]
391 edges: list[ContextEdge]
392 metadata: dict
393 ```
394
395 ### Fields
396
397 | Field | Type | Description |
398 |---|---|---|
399 | `root` | `ContextNode` | The primary node (function, class, file, etc.) |
400 | `nodes` | `list[ContextNode]` | All nodes in the bundle, including `root` |
401 | `edges` | `list[ContextEdge]` | All edges between nodes in the bundle |
402 | `metadata` | `dict` | Query metadata (depth, timing, node counts) |
403
404 ### Methods
405
406 #### `to_json`
407
408 ```python
409 def to_json(self) -> str
410 ```
411
412 Serialize the bundle to a JSON string.
413
414 #### `to_markdown`
415
416 ```python
417 def to_markdown(self) -> str
418 ```
419
420 Render the bundle as a Markdown string. Suitable for pasting into agent context.
421
422 #### `to_dict`
423
424 ```python
425 def to_dict(self) -> dict
426 ```
427
428 Return the bundle as a plain Python dict.
429
430 ---
431
432 ## ContextNode
433
434 A single node in a context bundle.
435
436 ```python
437 @dataclass
438 class ContextNode:
439 id: str
440 label: str # e.g. "Function", "Concept"
441 name: str
442 properties: dict # all node properties from the graph
443 layer: str # "code" or "knowledge"
444 score: float # relevance score (search results only)
445 ```
446
447 ---
448
449 ## ContextEdge
450
451 A relationship between two nodes in a context bundle.
452
453 ```python
454 @dataclass
455 class ContextEdge:
456 from_id: str
457 to_id: str
458 edge_type: str # e.g. "CALLS", "ANNOTATES", "INHERITS"
459 properties: dict
460 ```
461
462 ---
463
464 ## IngestionResult
465
466 Returned by all ingest methods.
467
468 ```python
469 @dataclass
470 class IngestionResult:
471 nodes_created: int
472 nodes_updated: int
473 edges_created: int
474 files_processed: int
475 errors: list[str]
476 duration_seconds: float
477 ```
478
479 | Field | Type | Description |
480 |---|---|---|
481 | `nodes_created` | `int` | New nodes written to the graph |
482 | `nodes_updated` | `int` | Existing nodes updated |
483 | `edges_created` | `int` | New edges written |
484 | `files_processed` | `int` | Source files walked |
485 | `errors` | `list[str]` | Per-file parse errors (non-fatal) |
486 | `duration_seconds` | `float` | Wall time for the ingest operation |
--- docs/architecture/graph-schema.md
+++ docs/architecture/graph-schema.md
@@ -47,10 +47,13 @@
4747
| `GOVERNS` | Rule | Function, Method, Class, File | Rule applies to code node |
4848
| `DOCUMENTS` | WikiPage | Concept, Function, Class, File | Documentation relationship |
4949
| `ANNOTATES` | Concept, Rule | Function, Method, Class, File, Module | Knowledge node annotates code node |
5050
| `ASSIGNED_TO` | Rule, Decision | Person | Work item or decision assigned to person |
5151
| `DECIDED_BY` | Decision | Person | Decision was made by person |
52
+| `TESTS` | Function, Method | Function, Method, Class | Test function exercises a source function or class |
53
+| `COUPLED_WITH` | File, Module | File, Module | Files that change together frequently (from churn analysis) |
54
+| `OWNS` | Person | File, Module, Class | Ownership from CODEOWNERS or annotation |
5255
5356
---
5457
5558
## Schema diagram
5659
@@ -101,10 +104,14 @@
101104
Concept -->|ANNOTATES| Function
102105
Concept -->|ANNOTATES| Class
103106
Class -->|IMPLEMENTS| Concept
104107
Decision -->|DECIDED_BY| Person
105108
Rule -->|ASSIGNED_TO| Person
109
+ Function -->|TESTS| Function
110
+ Function -->|TESTS| Class
111
+ File -->|COUPLED_WITH| File
112
+ Person -->|OWNS| File
106113
```
107114
108115
---
109116
110117
## Code vs knowledge layer distinction
@@ -118,5 +125,9 @@
118125
| Change rate | Fast (changes with every commit) | Slow (changes with design decisions) |
119126
| Authorship | Derived from code | Human or meeting-authored |
120127
| Queryability | Names, signatures, call graphs | Domain semantics, rationale, history |
121128
122129
Cross-layer edges (`ANNOTATES`, `GOVERNS`, `IMPLEMENTS`, `DOCUMENTS`) are the join points between the two layers. They are created explicitly by humans via `navegador annotate` or inferred during wiki/Planopticon ingestion.
130
+
131
+Analysis edges (`TESTS`, `COUPLED_WITH`) are created by analysis commands (`navegador testmap`, `navegador churn`) and are derived rather than curated. They are refreshed whenever those commands are re-run.
132
+
133
+`OWNS` edges are populated from CODEOWNERS file parsing (`navegador codeowners`) and from explicit `navegador annotate --owner` assignments.
123134
--- docs/architecture/graph-schema.md
+++ docs/architecture/graph-schema.md
@@ -47,10 +47,13 @@
47 | `GOVERNS` | Rule | Function, Method, Class, File | Rule applies to code node |
48 | `DOCUMENTS` | WikiPage | Concept, Function, Class, File | Documentation relationship |
49 | `ANNOTATES` | Concept, Rule | Function, Method, Class, File, Module | Knowledge node annotates code node |
50 | `ASSIGNED_TO` | Rule, Decision | Person | Work item or decision assigned to person |
51 | `DECIDED_BY` | Decision | Person | Decision was made by person |
 
 
 
52
53 ---
54
55 ## Schema diagram
56
@@ -101,10 +104,14 @@
101 Concept -->|ANNOTATES| Function
102 Concept -->|ANNOTATES| Class
103 Class -->|IMPLEMENTS| Concept
104 Decision -->|DECIDED_BY| Person
105 Rule -->|ASSIGNED_TO| Person
 
 
 
 
106 ```
107
108 ---
109
110 ## Code vs knowledge layer distinction
@@ -118,5 +125,9 @@
118 | Change rate | Fast (changes with every commit) | Slow (changes with design decisions) |
119 | Authorship | Derived from code | Human or meeting-authored |
120 | Queryability | Names, signatures, call graphs | Domain semantics, rationale, history |
121
122 Cross-layer edges (`ANNOTATES`, `GOVERNS`, `IMPLEMENTS`, `DOCUMENTS`) are the join points between the two layers. They are created explicitly by humans via `navegador annotate` or inferred during wiki/Planopticon ingestion.
 
 
 
 
123
--- docs/architecture/graph-schema.md
+++ docs/architecture/graph-schema.md
@@ -47,10 +47,13 @@
47 | `GOVERNS` | Rule | Function, Method, Class, File | Rule applies to code node |
48 | `DOCUMENTS` | WikiPage | Concept, Function, Class, File | Documentation relationship |
49 | `ANNOTATES` | Concept, Rule | Function, Method, Class, File, Module | Knowledge node annotates code node |
50 | `ASSIGNED_TO` | Rule, Decision | Person | Work item or decision assigned to person |
51 | `DECIDED_BY` | Decision | Person | Decision was made by person |
52 | `TESTS` | Function, Method | Function, Method, Class | Test function exercises a source function or class |
53 | `COUPLED_WITH` | File, Module | File, Module | Files that change together frequently (from churn analysis) |
54 | `OWNS` | Person | File, Module, Class | Ownership from CODEOWNERS or annotation |
55
56 ---
57
58 ## Schema diagram
59
@@ -101,10 +104,14 @@
104 Concept -->|ANNOTATES| Function
105 Concept -->|ANNOTATES| Class
106 Class -->|IMPLEMENTS| Concept
107 Decision -->|DECIDED_BY| Person
108 Rule -->|ASSIGNED_TO| Person
109 Function -->|TESTS| Function
110 Function -->|TESTS| Class
111 File -->|COUPLED_WITH| File
112 Person -->|OWNS| File
113 ```
114
115 ---
116
117 ## Code vs knowledge layer distinction
@@ -118,5 +125,9 @@
125 | Change rate | Fast (changes with every commit) | Slow (changes with design decisions) |
126 | Authorship | Derived from code | Human or meeting-authored |
127 | Queryability | Names, signatures, call graphs | Domain semantics, rationale, history |
128
129 Cross-layer edges (`ANNOTATES`, `GOVERNS`, `IMPLEMENTS`, `DOCUMENTS`) are the join points between the two layers. They are created explicitly by humans via `navegador annotate` or inferred during wiki/Planopticon ingestion.
130
131 Analysis edges (`TESTS`, `COUPLED_WITH`) are created by analysis commands (`navegador testmap`, `navegador churn`) and are derived rather than curated. They are refreshed whenever those commands are re-run.
132
133 `OWNS` edges are populated from CODEOWNERS file parsing (`navegador codeowners`) and from explicit `navegador annotate --owner` assignments.
134
--- docs/architecture/overview.md
+++ docs/architecture/overview.md
@@ -6,14 +6,22 @@
66
77
Most context tools for AI agents handle one or the other — either they parse code (AST tools, code search) or they surface docs (RAG over wikis, ADR files). Navegador stores both in the same property graph and connects them with typed edges. An agent asking "what does `process_payment` do?" gets back not just the function signature and call graph, but the business rules that govern it and the architectural decision that shaped its design — in a single structured query.
88
99
---
1010
11
-## Two-layer design
11
+## Architecture layers
1212
1313
```
1414
┌──────────────────────────────────────────────────────────────────┐
15
+│ INTELLIGENCE LAYER │
16
+│ LLM providers (Anthropic · OpenAI · Ollama) │
17
+│ Semantic search · NLP queries · Doc generation │
18
+├──────────────────────────────────────────────────────────────────┤
19
+│ ANALYSIS LAYER │
20
+│ Impact · Trace · Churn · Deadcode · Cycles · Testmap │
21
+│ Diff · Rename · Communities · Blast radius │
22
+├──────────────────────────────────────────────────────────────────┤
1523
│ KNOWLEDGE LAYER │
1624
│ │
1725
│ Domain ──BELONGS_TO── Concept ──RELATED_TO── Rule │
1826
│ │ │ │ │
1927
│ └──BELONGS_TO── Decision GOVERNS │ │
@@ -29,24 +37,43 @@
2937
│ Repository ──CONTAINS── File ──CONTAINS── Class │
3038
│ │ │ │
3139
│ CONTAINS DEFINES │
3240
│ ↓ ↓ │
3341
│ Function ──CALLS── Function │
34
-│ │ │
35
-│ DECORATES── Decorator │
42
+│ │ │ │
43
+│ DECORATES─Decorator TESTS──TestFn │
3644
│ │ │
3745
│ IMPORTS── Import │
46
+├──────────────────────────────────────────────────────────────────┤
47
+│ ENRICHMENT LAYER │
48
+│ Framework metadata (Django · FastAPI · React · Rails · Spring) │
49
+│ VCS (Git · Fossil) · CODEOWNERS · ADRs · OpenAPI · GraphQL │
50
+├──────────────────────────────────────────────────────────────────┤
51
+│ STORE LAYER │
52
+│ FalkorDB (falkordblite SQLite local / Redis cluster) │
3853
└──────────────────────────────────────────────────────────────────┘
3954
```
4055
4156
### Code layer
4257
43
-Populated automatically by `navegador ingest`. Contains the structural facts extracted from source code: which functions exist, what they call, which classes inherit from which, what decorators are applied. This layer changes whenever code changes; re-ingest is the refresh mechanism.
58
+Populated automatically by `navegador ingest`. Contains the structural facts extracted from source code across 13 languages: which functions exist, what they call, which classes inherit from which, what decorators are applied. Supports incremental ingestion (content hashing), watch mode, and parallel processing. This layer changes whenever code changes; re-ingest is the refresh mechanism.
4459
4560
### Knowledge layer
4661
47
-Populated by humans (via `navegador add`) or semi-automatically (via wiki and Planopticon ingestion). Contains the *why*: business concepts, architectural rules, recorded decisions, domain ownership, and documentation. This layer changes slowly and deliberately.
62
+Populated by humans (via `navegador add`) or semi-automatically (via wiki, Planopticon, ADR, OpenAPI, and PM ingestion). Contains the *why*: business concepts, architectural rules, recorded decisions, domain ownership, and documentation. This layer changes slowly and deliberately.
63
+
64
+### Enrichment layer
65
+
66
+Framework enrichers run after AST parsing to add framework-specific metadata — Django model field types, FastAPI route paths, React component display names, etc. VCS adapters (Git, Fossil) provide blame, history, and churn data. CODEOWNERS files are parsed to populate `Person`→`File` ownership edges.
67
+
68
+### Analysis layer
69
+
70
+Graph analysis commands operate over the populated code and knowledge layers without additional ingestion. They run Cypher traversals for impact analysis, cycle detection, dead code detection, test mapping, and community detection.
71
+
72
+### Intelligence layer
73
+
74
+NLP and LLM commands (`navegador ask`, `navegador semantic-search`, `navegador docs`) use configurable LLM providers (Anthropic, OpenAI, Ollama) to answer natural language queries grounded in graph data.
4875
4976
### Cross-layer edges
5077
5178
| Edge | Meaning | Direction |
5279
|---|---|---|
@@ -73,18 +100,26 @@
73100
---
74101
75102
## Ingestion pipeline
76103
77104
```
78
-Source code (Python · TypeScript · JavaScript · Go · Rust · Java)
105
+Source code (13 languages via tree-sitter)
79106
80107
81108
tree-sitter parser (per-language grammar)
109
+ + incremental parsing (LRU cache, content hashing)
110
+ + parallel ingestion (worker pool)
82111
83112
84113
AST visitor (extract nodes + relationships)
85114
115
+
116
+ Framework enrichers (Django · FastAPI · React · Rails · Spring · Laravel · …)
117
+
118
+
119
+ Graph diffing (only write changed nodes/edges)
120
+
86121
87122
GraphStore.merge_node / create_edge
88123
89124
90125
FalkorDB (SQLite or Redis)
@@ -92,13 +127,18 @@
92127
93128
```
94129
Human curation (navegador add)
95130
Wiki pages (navegador wiki ingest)
96131
Planopticon output (navegador planopticon ingest)
132
+ADRs (navegador adr ingest)
133
+OpenAPI / GraphQL schemas (navegador api ingest)
134
+PM issues (navegador pm ingest --github)
135
+External deps (navegador deps ingest)
136
+Submodules (navegador submodules ingest)
97137
98138
99
- KnowledgeIngester / WikiIngester / PlanopticonIngester
139
+ KnowledgeIngester / WikiIngester / PlanopticonIngester / …
100140
101141
102142
GraphStore.merge_node / create_edge
103143
104144
@@ -107,30 +147,56 @@
107147
108148
All ingesters write to the same graph. There is no separate code database and knowledge database.
109149
110150
---
111151
112
-## Query path
152
+## Query and analysis path
113153
114154
```
115155
User / agent
116156
117
- ▼ CLI command or MCP tool call
118
-navegador context / function / explain / search / ...
157
+ ▼ CLI command, MCP tool call, or Python SDK
158
+navegador context / function / explain / search / impact / trace / ...
119159
120160
121
-ContextLoader (builds Cypher query)
161
+ContextLoader / AnalysisEngine (builds Cypher query)
122162
123163
124
-GraphStore.query(cypher)
164
+GraphStore.query(cypher) ← MCP: query validation + complexity check
125165
126166
127167
FalkorDB (SQLite or Redis)
128168
129169
130
-ContextBundle (structured result)
170
+ContextBundle / AnalysisResult (structured result)
131171
132172
133173
JSON / Markdown / rich terminal output
134174
```
135175
136
-`ContextLoader` is the query abstraction layer. Each command (`function`, `class`, `explain`, etc.) corresponds to a `ContextLoader` method that constructs the appropriate Cypher query, fetches results, and assembles a `ContextBundle`. The CLI formats the bundle for output; the MCP server returns it as JSON.
176
+`ContextLoader` handles context retrieval commands (`function`, `class`, `explain`, etc.). `AnalysisEngine` handles graph analysis commands (`impact`, `trace`, `deadcode`, `cycles`, `churn`, `testmap`). Both construct Cypher queries, fetch results from `GraphStore`, and return structured output. The CLI formats output for the terminal; the MCP server returns JSON; the Python SDK returns typed Python objects.
177
+
178
+---
179
+
180
+## Cluster architecture
181
+
182
+For team and CI environments, navegador supports a cluster mode backed by a shared Redis graph:
183
+
184
+```
185
+Multiple agents / CI runners
186
+
187
+
188
+ navegador (each instance)
189
+
190
+
191
+ ┌────────────────────────────────────────┐
192
+ │ Shared Redis │
193
+ │ ├── FalkorDB graph (shared state) │
194
+ │ ├── Pub/sub (event broadcast) │
195
+ │ ├── Task queue (ingest jobs) │
196
+ │ ├── Sessions (agent state) │
197
+ │ ├── Checkpoints (long-running tasks) │
198
+ │ └── Observability (metrics, traces) │
199
+ └────────────────────────────────────────┘
200
+```
201
+
202
+Configure with `[cluster]` in `.navegador/config.toml`. See [Configuration](../getting-started/configuration.md) for details.
137203
--- docs/architecture/overview.md
+++ docs/architecture/overview.md
@@ -6,14 +6,22 @@
6
7 Most context tools for AI agents handle one or the other — either they parse code (AST tools, code search) or they surface docs (RAG over wikis, ADR files). Navegador stores both in the same property graph and connects them with typed edges. An agent asking "what does `process_payment` do?" gets back not just the function signature and call graph, but the business rules that govern it and the architectural decision that shaped its design — in a single structured query.
8
9 ---
10
11 ## Two-layer design
12
13 ```
14 ┌──────────────────────────────────────────────────────────────────┐
 
 
 
 
 
 
 
 
15 │ KNOWLEDGE LAYER │
16 │ │
17 │ Domain ──BELONGS_TO── Concept ──RELATED_TO── Rule │
18 │ │ │ │ │
19 │ └──BELONGS_TO── Decision GOVERNS │ │
@@ -29,24 +37,43 @@
29 │ Repository ──CONTAINS── File ──CONTAINS── Class │
30 │ │ │ │
31 │ CONTAINS DEFINES │
32 │ ↓ ↓ │
33 │ Function ──CALLS── Function │
34 │ │ │
35 │ DECORATES── Decorator │
36 │ │ │
37 │ IMPORTS── Import │
 
 
 
 
 
 
 
38 └──────────────────────────────────────────────────────────────────┘
39 ```
40
41 ### Code layer
42
43 Populated automatically by `navegador ingest`. Contains the structural facts extracted from source code: which functions exist, what they call, which classes inherit from which, what decorators are applied. This layer changes whenever code changes; re-ingest is the refresh mechanism.
44
45 ### Knowledge layer
46
47 Populated by humans (via `navegador add`) or semi-automatically (via wiki and Planopticon ingestion). Contains the *why*: business concepts, architectural rules, recorded decisions, domain ownership, and documentation. This layer changes slowly and deliberately.
 
 
 
 
 
 
 
 
 
 
 
 
48
49 ### Cross-layer edges
50
51 | Edge | Meaning | Direction |
52 |---|---|---|
@@ -73,18 +100,26 @@
73 ---
74
75 ## Ingestion pipeline
76
77 ```
78 Source code (Python · TypeScript · JavaScript · Go · Rust · Java)
79
80
81 tree-sitter parser (per-language grammar)
 
 
82
83
84 AST visitor (extract nodes + relationships)
85
 
 
 
 
 
 
86
87 GraphStore.merge_node / create_edge
88
89
90 FalkorDB (SQLite or Redis)
@@ -92,13 +127,18 @@
92
93 ```
94 Human curation (navegador add)
95 Wiki pages (navegador wiki ingest)
96 Planopticon output (navegador planopticon ingest)
 
 
 
 
 
97
98
99 KnowledgeIngester / WikiIngester / PlanopticonIngester
100
101
102 GraphStore.merge_node / create_edge
103
104
@@ -107,30 +147,56 @@
107
108 All ingesters write to the same graph. There is no separate code database and knowledge database.
109
110 ---
111
112 ## Query path
113
114 ```
115 User / agent
116
117 ▼ CLI command or MCP tool call
118 navegador context / function / explain / search / ...
119
120
121 ContextLoader (builds Cypher query)
122
123
124 GraphStore.query(cypher)
125
126
127 FalkorDB (SQLite or Redis)
128
129
130 ContextBundle (structured result)
131
132
133 JSON / Markdown / rich terminal output
134 ```
135
136 `ContextLoader` is the query abstraction layer. Each command (`function`, `class`, `explain`, etc.) corresponds to a `ContextLoader` method that constructs the appropriate Cypher query, fetches results, and assembles a `ContextBundle`. The CLI formats the bundle for output; the MCP server returns it as JSON.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
--- docs/architecture/overview.md
+++ docs/architecture/overview.md
@@ -6,14 +6,22 @@
6
7 Most context tools for AI agents handle one or the other — either they parse code (AST tools, code search) or they surface docs (RAG over wikis, ADR files). Navegador stores both in the same property graph and connects them with typed edges. An agent asking "what does `process_payment` do?" gets back not just the function signature and call graph, but the business rules that govern it and the architectural decision that shaped its design — in a single structured query.
8
9 ---
10
11 ## Architecture layers
12
13 ```
14 ┌──────────────────────────────────────────────────────────────────┐
15 │ INTELLIGENCE LAYER │
16 │ LLM providers (Anthropic · OpenAI · Ollama) │
17 │ Semantic search · NLP queries · Doc generation │
18 ├──────────────────────────────────────────────────────────────────┤
19 │ ANALYSIS LAYER │
20 │ Impact · Trace · Churn · Deadcode · Cycles · Testmap │
21 │ Diff · Rename · Communities · Blast radius │
22 ├──────────────────────────────────────────────────────────────────┤
23 │ KNOWLEDGE LAYER │
24 │ │
25 │ Domain ──BELONGS_TO── Concept ──RELATED_TO── Rule │
26 │ │ │ │ │
27 │ └──BELONGS_TO── Decision GOVERNS │ │
@@ -29,24 +37,43 @@
37 │ Repository ──CONTAINS── File ──CONTAINS── Class │
38 │ │ │ │
39 │ CONTAINS DEFINES │
40 │ ↓ ↓ │
41 │ Function ──CALLS── Function │
42 │ │ │ │
43 │ DECORATES─Decorator TESTS──TestFn │
44 │ │ │
45 │ IMPORTS── Import │
46 ├──────────────────────────────────────────────────────────────────┤
47 │ ENRICHMENT LAYER │
48 │ Framework metadata (Django · FastAPI · React · Rails · Spring) │
49 │ VCS (Git · Fossil) · CODEOWNERS · ADRs · OpenAPI · GraphQL │
50 ├──────────────────────────────────────────────────────────────────┤
51 │ STORE LAYER │
52 │ FalkorDB (falkordblite SQLite local / Redis cluster) │
53 └──────────────────────────────────────────────────────────────────┘
54 ```
55
56 ### Code layer
57
58 Populated automatically by `navegador ingest`. Contains the structural facts extracted from source code across 13 languages: which functions exist, what they call, which classes inherit from which, what decorators are applied. Supports incremental ingestion (content hashing), watch mode, and parallel processing. This layer changes whenever code changes; re-ingest is the refresh mechanism.
59
60 ### Knowledge layer
61
62 Populated by humans (via `navegador add`) or semi-automatically (via wiki, Planopticon, ADR, OpenAPI, and PM ingestion). Contains the *why*: business concepts, architectural rules, recorded decisions, domain ownership, and documentation. This layer changes slowly and deliberately.
63
64 ### Enrichment layer
65
66 Framework enrichers run after AST parsing to add framework-specific metadata — Django model field types, FastAPI route paths, React component display names, etc. VCS adapters (Git, Fossil) provide blame, history, and churn data. CODEOWNERS files are parsed to populate `Person`→`File` ownership edges.
67
68 ### Analysis layer
69
70 Graph analysis commands operate over the populated code and knowledge layers without additional ingestion. They run Cypher traversals for impact analysis, cycle detection, dead code detection, test mapping, and community detection.
71
72 ### Intelligence layer
73
74 NLP and LLM commands (`navegador ask`, `navegador semantic-search`, `navegador docs`) use configurable LLM providers (Anthropic, OpenAI, Ollama) to answer natural language queries grounded in graph data.
75
76 ### Cross-layer edges
77
78 | Edge | Meaning | Direction |
79 |---|---|---|
@@ -73,18 +100,26 @@
100 ---
101
102 ## Ingestion pipeline
103
104 ```
105 Source code (13 languages via tree-sitter)
106
107
108 tree-sitter parser (per-language grammar)
109 + incremental parsing (LRU cache, content hashing)
110 + parallel ingestion (worker pool)
111
112
113 AST visitor (extract nodes + relationships)
114
115
116 Framework enrichers (Django · FastAPI · React · Rails · Spring · Laravel · …)
117
118
119 Graph diffing (only write changed nodes/edges)
120
121
122 GraphStore.merge_node / create_edge
123
124
125 FalkorDB (SQLite or Redis)
@@ -92,13 +127,18 @@
127
128 ```
129 Human curation (navegador add)
130 Wiki pages (navegador wiki ingest)
131 Planopticon output (navegador planopticon ingest)
132 ADRs (navegador adr ingest)
133 OpenAPI / GraphQL schemas (navegador api ingest)
134 PM issues (navegador pm ingest --github)
135 External deps (navegador deps ingest)
136 Submodules (navegador submodules ingest)
137
138
139 KnowledgeIngester / WikiIngester / PlanopticonIngester / …
140
141
142 GraphStore.merge_node / create_edge
143
144
@@ -107,30 +147,56 @@
147
148 All ingesters write to the same graph. There is no separate code database and knowledge database.
149
150 ---
151
152 ## Query and analysis path
153
154 ```
155 User / agent
156
157 ▼ CLI command, MCP tool call, or Python SDK
158 navegador context / function / explain / search / impact / trace / ...
159
160
161 ContextLoader / AnalysisEngine (builds Cypher query)
162
163
164 GraphStore.query(cypher) ← MCP: query validation + complexity check
165
166
167 FalkorDB (SQLite or Redis)
168
169
170 ContextBundle / AnalysisResult (structured result)
171
172
173 JSON / Markdown / rich terminal output
174 ```
175
176 `ContextLoader` handles context retrieval commands (`function`, `class`, `explain`, etc.). `AnalysisEngine` handles graph analysis commands (`impact`, `trace`, `deadcode`, `cycles`, `churn`, `testmap`). Both construct Cypher queries, fetch results from `GraphStore`, and return structured output. The CLI formats output for the terminal; the MCP server returns JSON; the Python SDK returns typed Python objects.
177
178 ---
179
180 ## Cluster architecture
181
182 For team and CI environments, navegador supports a cluster mode backed by a shared Redis graph:
183
184 ```
185 Multiple agents / CI runners
186
187
188 navegador (each instance)
189
190
191 ┌────────────────────────────────────────┐
192 │ Shared Redis │
193 │ ├── FalkorDB graph (shared state) │
194 │ ├── Pub/sub (event broadcast) │
195 │ ├── Task queue (ingest jobs) │
196 │ ├── Sessions (agent state) │
197 │ ├── Checkpoints (long-running tasks) │
198 │ └── Observability (metrics, traces) │
199 └────────────────────────────────────────┘
200 ```
201
202 Configure with `[cluster]` in `.navegador/config.toml`. See [Configuration](../getting-started/configuration.md) for details.
203
--- docs/getting-started/configuration.md
+++ docs/getting-started/configuration.md
@@ -78,28 +78,81 @@
7878
7979
For public repos, wiki ingestion works without a token but will hit GitHub's unauthenticated rate limit (60 req/hr).
8080
8181
---
8282
83
-## Environment variable reference
84
-
85
-| Variable | Default | Description |
86
-|---|---|---|
87
-| `NAVEGADOR_DB` | `./navegador.db` | Path to SQLite file or `redis://` URL |
88
-| `GITHUB_TOKEN` | — | GitHub personal access token for wiki ingestion |
89
-
----
90
-
9183
## Project-local config
9284
93
-Drop a `.navegador/config.toml` in your project root for project-specific defaults (optional):
85
+Drop a `.navegador/config.toml` in your project root for project-specific defaults:
9486
9587
```toml
9688
[database]
9789
path = ".navegador/navegador.db"
9890
9991
[ingest]
10092
exclude = ["node_modules", "dist", ".venv", "migrations"]
93
+incremental = true # use content hashing by default
94
+redact = false # strip secrets from ingested content
95
+
96
+[mcp]
97
+read_only = false # set true to prevent agents from writing to the graph
98
+max_query_complexity = 100 # Cypher query complexity limit
99
+```
100
+
101
+---
102
+
103
+## LLM provider config
104
+
105
+Configure LLM providers used by `navegador ask`, `navegador docs`, and `navegador semantic-search`. Requires `pip install "navegador[llm]"`.
106
+
107
+```toml
108
+[llm]
109
+provider = "anthropic" # "anthropic", "openai", or "ollama"
110
+model = "claude-3-5-haiku-20241022"
111
+
112
+[llm.anthropic]
113
+api_key_env = "ANTHROPIC_API_KEY" # env var name (not the key itself)
114
+
115
+[llm.openai]
116
+api_key_env = "OPENAI_API_KEY"
117
+model = "gpt-4o-mini"
118
+
119
+[llm.ollama]
120
+base_url = "http://localhost:11434"
121
+model = "llama3"
122
+```
123
+
124
+---
125
+
126
+## Cluster config
127
+
128
+For team deployments using a shared Redis graph with pub/sub, task queue, and session coordination:
129
+
130
+```toml
131
+[cluster]
132
+enabled = true
133
+redis_url = "redis://redis.internal:6379"
134
+graph_name = "navegador-team"
135
+
136
+[cluster.pubsub]
137
+channel = "navegador:events"
138
+
139
+[cluster.queue]
140
+name = "navegador:tasks"
141
+
142
+[cluster.sessions]
143
+ttl_seconds = 3600
101144
```
102145
103
-!!! note
104
- `.navegador/config.toml` support is planned. Check `navegador --version` to confirm it is available in your installed version.
146
+See the [Cluster mode](../guide/cluster.md) guide for full setup instructions.
147
+
148
+---
149
+
150
+## Environment variable reference
151
+
152
+| Variable | Default | Description |
153
+|---|---|---|
154
+| `NAVEGADOR_DB` | `./navegador.db` | Path to SQLite file or `redis://` URL |
155
+| `GITHUB_TOKEN` | — | GitHub personal access token for wiki ingestion |
156
+| `ANTHROPIC_API_KEY` | — | Anthropic API key for LLM features |
157
+| `OPENAI_API_KEY` | — | OpenAI API key for LLM features |
158
+| `NAVEGADOR_CONFIG` | `.navegador/config.toml` | Override config file path |
105159
--- docs/getting-started/configuration.md
+++ docs/getting-started/configuration.md
@@ -78,28 +78,81 @@
78
79 For public repos, wiki ingestion works without a token but will hit GitHub's unauthenticated rate limit (60 req/hr).
80
81 ---
82
83 ## Environment variable reference
84
85 | Variable | Default | Description |
86 |---|---|---|
87 | `NAVEGADOR_DB` | `./navegador.db` | Path to SQLite file or `redis://` URL |
88 | `GITHUB_TOKEN` | — | GitHub personal access token for wiki ingestion |
89
----
90
91 ## Project-local config
92
93 Drop a `.navegador/config.toml` in your project root for project-specific defaults (optional):
94
95 ```toml
96 [database]
97 path = ".navegador/navegador.db"
98
99 [ingest]
100 exclude = ["node_modules", "dist", ".venv", "migrations"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101 ```
102
103 !!! note
104 `.navegador/config.toml` support is planned. Check `navegador --version` to confirm it is available in your installed version.
 
 
 
 
 
 
 
 
 
 
 
105
--- docs/getting-started/configuration.md
+++ docs/getting-started/configuration.md
@@ -78,28 +78,81 @@
78
79 For public repos, wiki ingestion works without a token but will hit GitHub's unauthenticated rate limit (60 req/hr).
80
81 ---
82
 
 
 
 
 
 
 
----
 
83 ## Project-local config
84
85 Drop a `.navegador/config.toml` in your project root for project-specific defaults:
86
87 ```toml
88 [database]
89 path = ".navegador/navegador.db"
90
91 [ingest]
92 exclude = ["node_modules", "dist", ".venv", "migrations"]
93 incremental = true # use content hashing by default
94 redact = false # strip secrets from ingested content
95
96 [mcp]
97 read_only = false # set true to prevent agents from writing to the graph
98 max_query_complexity = 100 # Cypher query complexity limit
99 ```
100
101 ---
102
103 ## LLM provider config
104
105 Configure LLM providers used by `navegador ask`, `navegador docs`, and `navegador semantic-search`. Requires `pip install "navegador[llm]"`.
106
107 ```toml
108 [llm]
109 provider = "anthropic" # "anthropic", "openai", or "ollama"
110 model = "claude-3-5-haiku-20241022"
111
112 [llm.anthropic]
113 api_key_env = "ANTHROPIC_API_KEY" # env var name (not the key itself)
114
115 [llm.openai]
116 api_key_env = "OPENAI_API_KEY"
117 model = "gpt-4o-mini"
118
119 [llm.ollama]
120 base_url = "http://localhost:11434"
121 model = "llama3"
122 ```
123
124 ---
125
126 ## Cluster config
127
128 For team deployments using a shared Redis graph with pub/sub, task queue, and session coordination:
129
130 ```toml
131 [cluster]
132 enabled = true
133 redis_url = "redis://redis.internal:6379"
134 graph_name = "navegador-team"
135
136 [cluster.pubsub]
137 channel = "navegador:events"
138
139 [cluster.queue]
140 name = "navegador:tasks"
141
142 [cluster.sessions]
143 ttl_seconds = 3600
144 ```
145
146 See the [Cluster mode](../guide/cluster.md) guide for full setup instructions.
147
148 ---
149
150 ## Environment variable reference
151
152 | Variable | Default | Description |
153 |---|---|---|
154 | `NAVEGADOR_DB` | `./navegador.db` | Path to SQLite file or `redis://` URL |
155 | `GITHUB_TOKEN` | — | GitHub personal access token for wiki ingestion |
156 | `ANTHROPIC_API_KEY` | — | Anthropic API key for LLM features |
157 | `OPENAI_API_KEY` | — | OpenAI API key for LLM features |
158 | `NAVEGADOR_CONFIG` | `.navegador/config.toml` | Override config file path |
159
--- docs/getting-started/installation.md
+++ docs/getting-started/installation.md
@@ -40,10 +40,38 @@
4040
export NAVEGADOR_DB=redis://localhost:6379
4141
navegador ingest ./repo
4242
```
4343
4444
See [Configuration](configuration.md) for full Redis setup details.
45
+
46
+=== "[languages]"
47
+
48
+ Additional tree-sitter grammars for Kotlin, C#, PHP, Ruby, Swift, C, and C++. The default install includes Python, TypeScript, JavaScript, Go, Rust, and Java.
49
+
50
+ ```bash
51
+ pip install "navegador[languages]"
52
+ ```
53
+
54
+ After installing, all 13 languages are parsed automatically by `navegador ingest`. No additional configuration is required.
55
+
56
+=== "[llm]"
57
+
58
+ LLM provider integrations for Anthropic, OpenAI, and Ollama. Required for `navegador ask`, `navegador docs`, and `navegador semantic-search`.
59
+
60
+ ```bash
61
+ pip install "navegador[llm]"
62
+ ```
63
+
64
+ Configure the provider in `.navegador/config.toml` or via environment variables. See [Configuration](configuration.md) for details.
65
+
66
+=== "all extras"
67
+
68
+ Install everything at once:
69
+
70
+ ```bash
71
+ pip install "navegador[sqlite,redis,languages,llm]"
72
+ ```
4573
4674
## Verify
4775
4876
```bash
4977
navegador --version
@@ -50,27 +78,54 @@
5078
```
5179
5280
Expected output:
5381
5482
```
55
-navegador, version 0.x.y
83
+navegador, version 0.7.0
84
+```
85
+
86
+## Shell completions
87
+
88
+Install shell completions for tab-completion of commands and flags:
89
+
90
+```bash
91
+navegador completions bash >> ~/.bashrc
92
+navegador completions zsh >> ~/.zshrc
93
+navegador completions fish > ~/.config/fish/completions/navegador.fish
94
+```
95
+
96
+## Python SDK
97
+
98
+The Python SDK wraps all CLI functionality in a single `Navegador` class:
99
+
100
+```python
101
+from navegador import Navegador
102
+
103
+nav = Navegador(".navegador/navegador.db")
104
+nav.ingest("./src")
105
+bundle = nav.explain("AuthService")
106
+print(bundle.to_markdown())
56107
```
108
+
109
+The SDK is included in the base install — no extra is required.
57110
58111
## Development install
59112
60113
```bash
61114
git clone https://github.com/ConflictHQ/navegador
62115
cd navegador
63
-pip install -e ".[sqlite,redis]"
116
+pip install -e ".[sqlite,redis,languages,llm,dev]"
64117
```
65118
66119
## Upgrading
67120
68121
```bash
69122
pip install --upgrade navegador
70123
```
71124
72
-After upgrading, re-ingest any existing repos to pick up new parser features or schema changes:
125
+After upgrading, run schema migrations first, then re-ingest to pick up new parser features:
73126
74127
```bash
75
-navegador ingest ./repo --clear
128
+navegador migrate # apply any schema changes from the new version
129
+navegador ingest ./repo # re-ingest with incremental updates (preferred)
130
+navegador ingest ./repo --clear # full rebuild if you prefer a clean slate
76131
```
77132
--- docs/getting-started/installation.md
+++ docs/getting-started/installation.md
@@ -40,10 +40,38 @@
40 export NAVEGADOR_DB=redis://localhost:6379
41 navegador ingest ./repo
42 ```
43
44 See [Configuration](configuration.md) for full Redis setup details.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
46 ## Verify
47
48 ```bash
49 navegador --version
@@ -50,27 +78,54 @@
50 ```
51
52 Expected output:
53
54 ```
55 navegador, version 0.x.y
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56 ```
 
 
57
58 ## Development install
59
60 ```bash
61 git clone https://github.com/ConflictHQ/navegador
62 cd navegador
63 pip install -e ".[sqlite,redis]"
64 ```
65
66 ## Upgrading
67
68 ```bash
69 pip install --upgrade navegador
70 ```
71
72 After upgrading, re-ingest any existing repos to pick up new parser features or schema changes:
73
74 ```bash
75 navegador ingest ./repo --clear
 
 
76 ```
77
--- docs/getting-started/installation.md
+++ docs/getting-started/installation.md
@@ -40,10 +40,38 @@
40 export NAVEGADOR_DB=redis://localhost:6379
41 navegador ingest ./repo
42 ```
43
44 See [Configuration](configuration.md) for full Redis setup details.
45
46 === "[languages]"
47
48 Additional tree-sitter grammars for Kotlin, C#, PHP, Ruby, Swift, C, and C++. The default install includes Python, TypeScript, JavaScript, Go, Rust, and Java.
49
50 ```bash
51 pip install "navegador[languages]"
52 ```
53
54 After installing, all 13 languages are parsed automatically by `navegador ingest`. No additional configuration is required.
55
56 === "[llm]"
57
58 LLM provider integrations for Anthropic, OpenAI, and Ollama. Required for `navegador ask`, `navegador docs`, and `navegador semantic-search`.
59
60 ```bash
61 pip install "navegador[llm]"
62 ```
63
64 Configure the provider in `.navegador/config.toml` or via environment variables. See [Configuration](configuration.md) for details.
65
66 === "all extras"
67
68 Install everything at once:
69
70 ```bash
71 pip install "navegador[sqlite,redis,languages,llm]"
72 ```
73
74 ## Verify
75
76 ```bash
77 navegador --version
@@ -50,27 +78,54 @@
78 ```
79
80 Expected output:
81
82 ```
83 navegador, version 0.7.0
84 ```
85
86 ## Shell completions
87
88 Install shell completions for tab-completion of commands and flags:
89
90 ```bash
91 navegador completions bash >> ~/.bashrc
92 navegador completions zsh >> ~/.zshrc
93 navegador completions fish > ~/.config/fish/completions/navegador.fish
94 ```
95
96 ## Python SDK
97
98 The Python SDK wraps all CLI functionality in a single `Navegador` class:
99
100 ```python
101 from navegador import Navegador
102
103 nav = Navegador(".navegador/navegador.db")
104 nav.ingest("./src")
105 bundle = nav.explain("AuthService")
106 print(bundle.to_markdown())
107 ```
108
109 The SDK is included in the base install — no extra is required.
110
111 ## Development install
112
113 ```bash
114 git clone https://github.com/ConflictHQ/navegador
115 cd navegador
116 pip install -e ".[sqlite,redis,languages,llm,dev]"
117 ```
118
119 ## Upgrading
120
121 ```bash
122 pip install --upgrade navegador
123 ```
124
125 After upgrading, run schema migrations first, then re-ingest to pick up new parser features:
126
127 ```bash
128 navegador migrate # apply any schema changes from the new version
129 navegador ingest ./repo # re-ingest with incremental updates (preferred)
130 navegador ingest ./repo --clear # full rebuild if you prefer a clean slate
131 ```
132
--- docs/getting-started/quickstart.md
+++ docs/getting-started/quickstart.md
@@ -9,11 +9,11 @@
99
```bash
1010
pip install navegador
1111
navegador --version
1212
```
1313
14
-Python 3.12+ is required. See [Installation](installation.md) for extras and Redis setup.
14
+Python 3.12+ is required. For additional languages (Kotlin, C#, PHP, Ruby, Swift, C, C++) install the `[languages]` extra. See [Installation](installation.md) for all extras and Redis setup.
1515
1616
---
1717
1818
## Step 2: Ingest a repo
1919
@@ -21,11 +21,23 @@
2121
2222
```bash
2323
navegador ingest ./my-repo
2424
```
2525
26
-On first run this builds the graph from scratch. Re-run anytime to pick up changes. Use `--clear` to wipe and rebuild:
26
+On first run this builds the graph from scratch. Re-run anytime to pick up changes. Use `--incremental` to skip files that haven't changed (based on content hashing — much faster on large repos):
27
+
28
+```bash
29
+navegador ingest ./my-repo --incremental
30
+```
31
+
32
+Use `--watch` to keep the graph in sync as files change:
33
+
34
+```bash
35
+navegador ingest ./my-repo --watch
36
+```
37
+
38
+Use `--clear` to wipe and rebuild from scratch:
2739
2840
```bash
2941
navegador ingest ./my-repo --clear
3042
```
3143
@@ -33,11 +45,11 @@
3345
3446
```bash
3547
navegador ingest ./my-repo --json
3648
```
3749
38
-Navegador walks the tree, parses every `.py` and `.ts`/`.tsx` file with tree-sitter, and writes nodes and edges for: files, modules, classes, functions, methods, imports, decorators, and call relationships.
50
+Navegador walks the tree, parses source files in 13 languages with tree-sitter, and writes nodes and edges for: files, modules, classes, functions, methods, imports, decorators, and call relationships. Framework enrichers automatically detect and annotate Django models, FastAPI routes, React components, Rails controllers, Spring Boot beans, and more.
3951
4052
---
4153
4254
## Step 3: Query the graph
4355
@@ -136,5 +148,60 @@
136148
| `--agent claude` | Install `.claude/hooks/claude-hook.py` |
137149
| `--agent gemini` | Install `.gemini/hooks/gemini-hook.py` |
138150
| `--agent openai` | Install `openai-hook.py` + `openai-tools.json` |
139151
140152
After bootstrap, every file the agent edits triggers a re-ingest so the graph stays in sync. See [Agent Hooks](../guide/agent-hooks.md) for manual setup and the `NAVEGADOR.md` template.
153
+
154
+---
155
+
156
+## Step 6 (optional): SDK quick start
157
+
158
+All CLI functionality is available through the Python SDK:
159
+
160
+```python
161
+from navegador import Navegador
162
+
163
+nav = Navegador(".navegador/navegador.db")
164
+
165
+# ingest (incremental by default in SDK)
166
+nav.ingest("./my-repo", incremental=True)
167
+
168
+# query
169
+bundle = nav.explain("AuthService")
170
+print(bundle.to_markdown())
171
+
172
+# analysis
173
+impact = nav.impact("validate_token")
174
+churn = nav.churn(days=30)
175
+cycles = nav.cycles()
176
+```
177
+
178
+The `Navegador` class wraps `GraphStore`, `ContextLoader`, all ingesters, and the analysis commands into one interface.
179
+
180
+---
181
+
182
+## Step 7 (optional): Code analysis
183
+
184
+Once the graph is populated, use the analysis commands to understand your codebase:
185
+
186
+```bash
187
+# impact of changing a function
188
+navegador impact validate_token
189
+
190
+# trace execution flow
191
+navegador trace process_payment --depth 3
192
+
193
+# find dead code
194
+navegador deadcode
195
+
196
+# detect dependency cycles
197
+navegador cycles
198
+
199
+# map tests to source files
200
+navegador testmap
201
+
202
+# code churn (files that change most)
203
+navegador churn --days 30
204
+
205
+# diff — what changed between two refs
206
+navegador diff HEAD~1 HEAD
207
+```
141208
142209
ADDED docs/guide/analysis.md
143210
ADDED docs/guide/ci-cd.md
144211
ADDED docs/guide/cluster.md
--- docs/getting-started/quickstart.md
+++ docs/getting-started/quickstart.md
@@ -9,11 +9,11 @@
9 ```bash
10 pip install navegador
11 navegador --version
12 ```
13
14 Python 3.12+ is required. See [Installation](installation.md) for extras and Redis setup.
15
16 ---
17
18 ## Step 2: Ingest a repo
19
@@ -21,11 +21,23 @@
21
22 ```bash
23 navegador ingest ./my-repo
24 ```
25
26 On first run this builds the graph from scratch. Re-run anytime to pick up changes. Use `--clear` to wipe and rebuild:
 
 
 
 
 
 
 
 
 
 
 
 
27
28 ```bash
29 navegador ingest ./my-repo --clear
30 ```
31
@@ -33,11 +45,11 @@
33
34 ```bash
35 navegador ingest ./my-repo --json
36 ```
37
38 Navegador walks the tree, parses every `.py` and `.ts`/`.tsx` file with tree-sitter, and writes nodes and edges for: files, modules, classes, functions, methods, imports, decorators, and call relationships.
39
40 ---
41
42 ## Step 3: Query the graph
43
@@ -136,5 +148,60 @@
136 | `--agent claude` | Install `.claude/hooks/claude-hook.py` |
137 | `--agent gemini` | Install `.gemini/hooks/gemini-hook.py` |
138 | `--agent openai` | Install `openai-hook.py` + `openai-tools.json` |
139
140 After bootstrap, every file the agent edits triggers a re-ingest so the graph stays in sync. See [Agent Hooks](../guide/agent-hooks.md) for manual setup and the `NAVEGADOR.md` template.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
142 DDED docs/guide/analysis.md
143 DDED docs/guide/ci-cd.md
144 DDED docs/guide/cluster.md
--- docs/getting-started/quickstart.md
+++ docs/getting-started/quickstart.md
@@ -9,11 +9,11 @@
9 ```bash
10 pip install navegador
11 navegador --version
12 ```
13
14 Python 3.12+ is required. For additional languages (Kotlin, C#, PHP, Ruby, Swift, C, C++) install the `[languages]` extra. See [Installation](installation.md) for all extras and Redis setup.
15
16 ---
17
18 ## Step 2: Ingest a repo
19
@@ -21,11 +21,23 @@
21
22 ```bash
23 navegador ingest ./my-repo
24 ```
25
26 On first run this builds the graph from scratch. Re-run anytime to pick up changes. Use `--incremental` to skip files that haven't changed (based on content hashing — much faster on large repos):
27
28 ```bash
29 navegador ingest ./my-repo --incremental
30 ```
31
32 Use `--watch` to keep the graph in sync as files change:
33
34 ```bash
35 navegador ingest ./my-repo --watch
36 ```
37
38 Use `--clear` to wipe and rebuild from scratch:
39
40 ```bash
41 navegador ingest ./my-repo --clear
42 ```
43
@@ -33,11 +45,11 @@
45
46 ```bash
47 navegador ingest ./my-repo --json
48 ```
49
50 Navegador walks the tree, parses source files in 13 languages with tree-sitter, and writes nodes and edges for: files, modules, classes, functions, methods, imports, decorators, and call relationships. Framework enrichers automatically detect and annotate Django models, FastAPI routes, React components, Rails controllers, Spring Boot beans, and more.
51
52 ---
53
54 ## Step 3: Query the graph
55
@@ -136,5 +148,60 @@
148 | `--agent claude` | Install `.claude/hooks/claude-hook.py` |
149 | `--agent gemini` | Install `.gemini/hooks/gemini-hook.py` |
150 | `--agent openai` | Install `openai-hook.py` + `openai-tools.json` |
151
152 After bootstrap, every file the agent edits triggers a re-ingest so the graph stays in sync. See [Agent Hooks](../guide/agent-hooks.md) for manual setup and the `NAVEGADOR.md` template.
153
154 ---
155
156 ## Step 6 (optional): SDK quick start
157
158 All CLI functionality is available through the Python SDK:
159
160 ```python
161 from navegador import Navegador
162
163 nav = Navegador(".navegador/navegador.db")
164
165 # ingest (incremental by default in SDK)
166 nav.ingest("./my-repo", incremental=True)
167
168 # query
169 bundle = nav.explain("AuthService")
170 print(bundle.to_markdown())
171
172 # analysis
173 impact = nav.impact("validate_token")
174 churn = nav.churn(days=30)
175 cycles = nav.cycles()
176 ```
177
178 The `Navegador` class wraps `GraphStore`, `ContextLoader`, all ingesters, and the analysis commands into one interface.
179
180 ---
181
182 ## Step 7 (optional): Code analysis
183
184 Once the graph is populated, use the analysis commands to understand your codebase:
185
186 ```bash
187 # impact of changing a function
188 navegador impact validate_token
189
190 # trace execution flow
191 navegador trace process_payment --depth 3
192
193 # find dead code
194 navegador deadcode
195
196 # detect dependency cycles
197 navegador cycles
198
199 # map tests to source files
200 navegador testmap
201
202 # code churn (files that change most)
203 navegador churn --days 30
204
205 # diff — what changed between two refs
206 navegador diff HEAD~1 HEAD
207 ```
208
209 DDED docs/guide/analysis.md
210 DDED docs/guide/ci-cd.md
211 DDED docs/guide/cluster.md
--- a/docs/guide/analysis.md
+++ b/docs/guide/analysis.md
@@ -0,0 +1,287 @@
1
+# Structural Analysis
2
+
3
+Navegador's analysis commands answer questions about how code fits together: what breaks if this function changes, where does data flow, which code is never called, and which tests cover what.
4
+
5
+All analysis commands work against the live graph. Run `navegador ingest` first to populate it.
6
+
7
+---
8
+
9
+## Impact analysis
10
+
11
+`navegador impact` traces the downstream effect of changing a function, class, or file. It follows `CALLS`, `INHERITS`, and `IMPORTS` edges to find everything that depends on the target — directly or transitively.
12
+
13
+```bash
14
+navegador impact validate_token
15
+navegador impact PaymentProcessor --depth 3
16
+navegador impact src/auth/service.py --format json
17
+```
18
+
19
+### Options
20
+
21
+| Flag | Effect |
22
+|---|---|
23
+| `--depth N` | How many hops to follow (default: unlimited) |
24
+| `--format json` | Machine-readable output |
25
+| `--include-tests` | Include test files in the impact set |
26
+
27
+### Output
28
+
29
+```
30
+validate_token (Function — src/auth/service.py:42)
31
+ Direct dependents (3):
32
+ check_permissions src/auth/permissions.py:18
33
+ require_auth src/auth/decorators.py:7
34
+ middleware_auth src/middleware/auth.py:31
35
+
36
+ Transitive dependents (11):
37
+ process_payment src/payments/processor.py:56
38
+ create_order src/orders/service.py:23
39
+ ... (8 more)
40
+
41
+ Affected files (5):
42
+ src/auth/permissions.py
43
+ src/auth/decorators.py
44
+ src/middleware/auth.py
45
+ src/payments/processor.py
46
+ src/orders/service.py
47
+```
48
+
49
+### Use cases
50
+
51
+- Before refactoring: understand the blast radius before changing a shared utility
52
+- Code review: verify a PR's changes are limited to the expected scope
53
+- Dependency triage: identify high-fan-out functions that deserve extra test coverage
54
+
55
+---
56
+
57
+## Flow tracing
58
+
59
+`navegador flow` traces the execution path from one function to another, returning every call chain that connects them.
60
+
61
+```bash
62
+navegador flow create_order process_payment
63
+navegador flow handle_request save_to_db --max-paths 5
64
+```
65
+
66
+### Options
67
+
68
+| Flag | Effect |
69
+|---|---|
70
+| `--max-paths N` | Maximum number of paths to return (default: 3) |
71
+| `--format json` | Machine-readable output |
72
+
73
+### Output
74
+
75
+```
76
+Paths from create_order to process_payment:
77
+
78
+Path 1 (3 hops):
79
+ create_order → validate_cart → charge_card → process_payment
80
+
81
+Path 2 (4 hops):
82
+ create_order → apply_discount → charge_card → process_payment
83
+```
84
+
85
+### Use cases
86
+
87
+- Debugging: find all code paths that reach a problematic function
88
+- Security review: trace every path to a sensitive operation (e.g., `delete_user`, `transfer_funds`)
89
+- Onboarding: understand how a high-level action maps to low-level implementation
90
+
91
+---
92
+
93
+## Dead code detection
94
+
95
+`navegador dead-code` finds functions and classes that are never called, never imported, and not decorated as entry points.
96
+
97
+```bash
98
+navegador dead-code ./src
99
+navegador dead-code ./src --exclude-tests --format json
100
+```
101
+
102
+### Options
103
+
104
+| Flag | Effect |
105
+|---|---|
106
+| `--exclude-tests` | Skip test files |
107
+| `--min-age-days N` | Only report code not called in the last N days (requires git history) |
108
+| `--format json` | Machine-readable output |
109
+| `--threshold N` | Minimum confidence score to report (0–100, default: 80) |
110
+
111
+### Output
112
+
113
+```
114
+Potentially dead code (12 items):
115
+
116
+ [Function] legacy_hash_password src/auth/legacy.py:14
117
+ [Function] _format_receipt_v1 src/payments/receipt.py:88
118
+ [Class] OldPaymentAdapter src/payments/adapters.py:201
119
+ ...
120
+```
121
+
122
+!!! note
123
+ Navegador performs static call graph analysis. Dynamic dispatch, `getattr`, and string-based imports are not traced. Review candidates before deleting them.
124
+
125
+### Use cases
126
+
127
+- Codebase cleanup: identify safe-to-delete code before a release
128
+- Migration audits: find old adapter classes after a library upgrade
129
+
130
+---
131
+
132
+## Cycle detection
133
+
134
+`navegador cycles` finds circular dependency chains in the call graph and import graph.
135
+
136
+```bash
137
+navegador cycles ./src
138
+navegador cycles ./src --type imports
139
+navegador cycles ./src --type calls --format json
140
+```
141
+
142
+### Options
143
+
144
+| Flag | Effect |
145
+|---|---|
146
+| `--type calls` | Find circular call chains (default) |
147
+| `--type imports` | Find circular import chains |
148
+| `--type both` | Find both |
149
+| `--min-length N` | Only report cycles with at least N nodes (default: 2) |
150
+| `--format json` | Machine-readable output |
151
+
152
+### Output
153
+
154
+```
155
+Import cycles (2 found):
156
+
157
+ Cycle 1 (length 3):
158
+ src/payments/processor.py
159
+ → src/payments/validators.py
160
+ → src/payments/utils.py
161
+ → src/payments/processor.py
162
+
163
+ Cycle 2 (length 2):
164
+ src/auth/service.py
165
+ → src/auth/models.py
166
+ → src/auth/service.py
167
+```
168
+
169
+### Use cases
170
+
171
+- CI gate: fail builds that introduce new circular imports
172
+- Refactoring prep: identify modules to split before a large restructure
173
+
174
+---
175
+
176
+## Test mapping
177
+
178
+`navegador test-map` maps test functions to the production code they exercise, using call graph analysis.
179
+
180
+```bash
181
+navegador test-map ./src ./tests
182
+navegador test-map ./src ./tests --target process_payment
183
+navegador test-map ./src ./tests --format json
184
+```
185
+
186
+### Options
187
+
188
+| Flag | Effect |
189
+|---|---|
190
+| `--target <name>` | Only show tests that cover a specific function |
191
+| `--uncovered` | Show production functions with no covering tests |
192
+| `--format json` | Machine-readable output |
193
+
194
+### Output
195
+
196
+```
197
+Test coverage map:
198
+
199
+ process_payment (src/payments/processor.py:56)
200
+ tests/payments/test_processor.py::test_process_payment_success
201
+ tests/payments/test_processor.py::test_process_payment_duplicate
202
+ tests/integration/test_checkout.py::test_full_checkout_flow
203
+
204
+ validate_token (src/auth/service.py:42)
205
+ tests/auth/test_service.py::test_validate_token_valid
206
+ tests/auth/test_service.py::test_validate_token_expired
207
+
208
+Uncovered functions (4):
209
+ legacy_hash_password src/auth/legacy.py:14
210
+ _format_receipt_v1 src/payments/receipt.py:88
211
+ ...
212
+```
213
+
214
+### Use cases
215
+
216
+- Coverage by semantics, not just lines: see which tests actually call a function
217
+- Regression targeting: when a function changes, which tests should run?
218
+- Review prep: check that new code has corresponding tests before merging
219
+
220
+---
221
+
222
+## Combining analysis with knowledge
223
+
224
+All analysis commands understand the knowledge layer. Add `--include-knowledge` to see rules, concepts, and decisions linked to the affected nodes:
225
+
226
+```bash
227
+navegador impact process_payment --include-knowledge
228
+```
229
+
230
+Output will include knowledge nodes like:
231
+
232
+```
233
+ Governed by:
234
+ Rule: RequireIdempotencyKey (critical)
235
+ Concept: Idempotency
236
+ Decisions:
237
+ UseStripeForPayments (accepted, 2025-01-15)
238
+```
239
+
240
+---
241
+
242
+## Python API
243
+
244
+```python
245
+from navegador.graph import GraphStore
246
+from navegador.analysis import (
247
+ ImpactAnalyzer,
248
+ FlowTracer,
249
+ DeadCodeDetector,
250
+ CycleDetector,
251
+ TestMapper,
252
+)
253
+
254
+store = GraphStore.sqlite(".navegador/navegador.db")
255
+
256
+# impact analysis
257
+analyzer = ImpactAnalyzer(store)
258
+result = analyzer.analyze("validate_token", depth=3)
259
+print(result.direct_dependents)
260
+print(result.transitive_dependents)
261
+
262
+# flow tracing
263
+tracer = FlowTracer(store)
264
+paths = tracer.trace("create_order", "process_payment", max_paths=5)
265
+for path in paths:
266
+ print(" -> ".join(path.nodes))
267
+
268
+# dead code
269
+detector = DeadCodeDetector(store)
270
+candidates = detector.find("./src", exclude_tests=True)
271
+for item in candidates:
272
+ print(f"{item.label}: {item.name} {item.file}:{item.line}")
273
+
274
+# cycle detection
275
+cycle_detector = CycleDetector(store)
276
+cycles = cycle_detector.find_import_cycles("./src")
277
+for cycle in cycles:
278
+ print(" -> ".join(cycle.path))
279
+
280
+# test mapping
281
+mapper = TestMapper(store)
282
+coverage = mapper.map("./src", "./tests")
283
+for fn, tests in coverage.items():
284
+ print(f"{fn}: {len(tests)} tests")
285
+```
286
+
287
+See the [Analysis API reference](../api/analysis.md) for full method signatures.
--- a/docs/guide/analysis.md
+++ b/docs/guide/analysis.md
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/guide/analysis.md
+++ b/docs/guide/analysis.md
@@ -0,0 +1,287 @@
1 # Structural Analysis
2
3 Navegador's analysis commands answer questions about how code fits together: what breaks if this function changes, where does data flow, which code is never called, and which tests cover what.
4
5 All analysis commands work against the live graph. Run `navegador ingest` first to populate it.
6
7 ---
8
9 ## Impact analysis
10
11 `navegador impact` traces the downstream effect of changing a function, class, or file. It follows `CALLS`, `INHERITS`, and `IMPORTS` edges to find everything that depends on the target — directly or transitively.
12
13 ```bash
14 navegador impact validate_token
15 navegador impact PaymentProcessor --depth 3
16 navegador impact src/auth/service.py --format json
17 ```
18
19 ### Options
20
21 | Flag | Effect |
22 |---|---|
23 | `--depth N` | How many hops to follow (default: unlimited) |
24 | `--format json` | Machine-readable output |
25 | `--include-tests` | Include test files in the impact set |
26
27 ### Output
28
29 ```
30 validate_token (Function — src/auth/service.py:42)
31 Direct dependents (3):
32 check_permissions src/auth/permissions.py:18
33 require_auth src/auth/decorators.py:7
34 middleware_auth src/middleware/auth.py:31
35
36 Transitive dependents (11):
37 process_payment src/payments/processor.py:56
38 create_order src/orders/service.py:23
39 ... (8 more)
40
41 Affected files (5):
42 src/auth/permissions.py
43 src/auth/decorators.py
44 src/middleware/auth.py
45 src/payments/processor.py
46 src/orders/service.py
47 ```
48
49 ### Use cases
50
51 - Before refactoring: understand the blast radius before changing a shared utility
52 - Code review: verify a PR's changes are limited to the expected scope
53 - Dependency triage: identify high-fan-out functions that deserve extra test coverage
54
55 ---
56
57 ## Flow tracing
58
59 `navegador flow` traces the execution path from one function to another, returning every call chain that connects them.
60
61 ```bash
62 navegador flow create_order process_payment
63 navegador flow handle_request save_to_db --max-paths 5
64 ```
65
66 ### Options
67
68 | Flag | Effect |
69 |---|---|
70 | `--max-paths N` | Maximum number of paths to return (default: 3) |
71 | `--format json` | Machine-readable output |
72
73 ### Output
74
75 ```
76 Paths from create_order to process_payment:
77
78 Path 1 (3 hops):
79 create_order → validate_cart → charge_card → process_payment
80
81 Path 2 (4 hops):
82 create_order → apply_discount → charge_card → process_payment
83 ```
84
85 ### Use cases
86
87 - Debugging: find all code paths that reach a problematic function
88 - Security review: trace every path to a sensitive operation (e.g., `delete_user`, `transfer_funds`)
89 - Onboarding: understand how a high-level action maps to low-level implementation
90
91 ---
92
93 ## Dead code detection
94
95 `navegador dead-code` finds functions and classes that are never called, never imported, and not decorated as entry points.
96
97 ```bash
98 navegador dead-code ./src
99 navegador dead-code ./src --exclude-tests --format json
100 ```
101
102 ### Options
103
104 | Flag | Effect |
105 |---|---|
106 | `--exclude-tests` | Skip test files |
107 | `--min-age-days N` | Only report code not called in the last N days (requires git history) |
108 | `--format json` | Machine-readable output |
109 | `--threshold N` | Minimum confidence score to report (0–100, default: 80) |
110
111 ### Output
112
113 ```
114 Potentially dead code (12 items):
115
116 [Function] legacy_hash_password src/auth/legacy.py:14
117 [Function] _format_receipt_v1 src/payments/receipt.py:88
118 [Class] OldPaymentAdapter src/payments/adapters.py:201
119 ...
120 ```
121
122 !!! note
123 Navegador performs static call graph analysis. Dynamic dispatch, `getattr`, and string-based imports are not traced. Review candidates before deleting them.
124
125 ### Use cases
126
127 - Codebase cleanup: identify safe-to-delete code before a release
128 - Migration audits: find old adapter classes after a library upgrade
129
130 ---
131
132 ## Cycle detection
133
134 `navegador cycles` finds circular dependency chains in the call graph and import graph.
135
136 ```bash
137 navegador cycles ./src
138 navegador cycles ./src --type imports
139 navegador cycles ./src --type calls --format json
140 ```
141
142 ### Options
143
144 | Flag | Effect |
145 |---|---|
146 | `--type calls` | Find circular call chains (default) |
147 | `--type imports` | Find circular import chains |
148 | `--type both` | Find both |
149 | `--min-length N` | Only report cycles with at least N nodes (default: 2) |
150 | `--format json` | Machine-readable output |
151
152 ### Output
153
154 ```
155 Import cycles (2 found):
156
157 Cycle 1 (length 3):
158 src/payments/processor.py
159 → src/payments/validators.py
160 → src/payments/utils.py
161 → src/payments/processor.py
162
163 Cycle 2 (length 2):
164 src/auth/service.py
165 → src/auth/models.py
166 → src/auth/service.py
167 ```
168
169 ### Use cases
170
171 - CI gate: fail builds that introduce new circular imports
172 - Refactoring prep: identify modules to split before a large restructure
173
174 ---
175
176 ## Test mapping
177
178 `navegador test-map` maps test functions to the production code they exercise, using call graph analysis.
179
180 ```bash
181 navegador test-map ./src ./tests
182 navegador test-map ./src ./tests --target process_payment
183 navegador test-map ./src ./tests --format json
184 ```
185
186 ### Options
187
188 | Flag | Effect |
189 |---|---|
190 | `--target <name>` | Only show tests that cover a specific function |
191 | `--uncovered` | Show production functions with no covering tests |
192 | `--format json` | Machine-readable output |
193
194 ### Output
195
196 ```
197 Test coverage map:
198
199 process_payment (src/payments/processor.py:56)
200 tests/payments/test_processor.py::test_process_payment_success
201 tests/payments/test_processor.py::test_process_payment_duplicate
202 tests/integration/test_checkout.py::test_full_checkout_flow
203
204 validate_token (src/auth/service.py:42)
205 tests/auth/test_service.py::test_validate_token_valid
206 tests/auth/test_service.py::test_validate_token_expired
207
208 Uncovered functions (4):
209 legacy_hash_password src/auth/legacy.py:14
210 _format_receipt_v1 src/payments/receipt.py:88
211 ...
212 ```
213
214 ### Use cases
215
216 - Coverage by semantics, not just lines: see which tests actually call a function
217 - Regression targeting: when a function changes, which tests should run?
218 - Review prep: check that new code has corresponding tests before merging
219
220 ---
221
222 ## Combining analysis with knowledge
223
224 All analysis commands understand the knowledge layer. Add `--include-knowledge` to see rules, concepts, and decisions linked to the affected nodes:
225
226 ```bash
227 navegador impact process_payment --include-knowledge
228 ```
229
230 Output will include knowledge nodes like:
231
232 ```
233 Governed by:
234 Rule: RequireIdempotencyKey (critical)
235 Concept: Idempotency
236 Decisions:
237 UseStripeForPayments (accepted, 2025-01-15)
238 ```
239
240 ---
241
242 ## Python API
243
244 ```python
245 from navegador.graph import GraphStore
246 from navegador.analysis import (
247 ImpactAnalyzer,
248 FlowTracer,
249 DeadCodeDetector,
250 CycleDetector,
251 TestMapper,
252 )
253
254 store = GraphStore.sqlite(".navegador/navegador.db")
255
256 # impact analysis
257 analyzer = ImpactAnalyzer(store)
258 result = analyzer.analyze("validate_token", depth=3)
259 print(result.direct_dependents)
260 print(result.transitive_dependents)
261
262 # flow tracing
263 tracer = FlowTracer(store)
264 paths = tracer.trace("create_order", "process_payment", max_paths=5)
265 for path in paths:
266 print(" -> ".join(path.nodes))
267
268 # dead code
269 detector = DeadCodeDetector(store)
270 candidates = detector.find("./src", exclude_tests=True)
271 for item in candidates:
272 print(f"{item.label}: {item.name} {item.file}:{item.line}")
273
274 # cycle detection
275 cycle_detector = CycleDetector(store)
276 cycles = cycle_detector.find_import_cycles("./src")
277 for cycle in cycles:
278 print(" -> ".join(cycle.path))
279
280 # test mapping
281 mapper = TestMapper(store)
282 coverage = mapper.map("./src", "./tests")
283 for fn, tests in coverage.items():
284 print(f"{fn}: {len(tests)} tests")
285 ```
286
287 See the [Analysis API reference](../api/analysis.md) for full method signatures.
--- a/docs/guide/ci-cd.md
+++ b/docs/guide/ci-cd.md
@@ -0,0 +1,272 @@
1
+# CI/CD Integration
2
+
3
+Navegador's `ci` subcommand is designed for non-interactive use in pipelines. All CI commands emit structured output and use exit codes that CI systems understand.
4
+
5
+---
6
+
7
+## CI commands
8
+
9
+### `navegador ci ingest`
10
+
11
+Ingest the repo and output a machine-readable summary. Exits non-zero on errors.
12
+
13
+```bash
14
+navegador ci ingest ./src
15
+```
16
+
17
+JSON output (always on in CI mode):
18
+
19
+```json
20
+{
21
+ "status": "ok",
22
+ "nodes_created": 1240,
23
+ "nodes_updated": 38,
24
+ "edges_created": 4821,
25
+ "files_processed": 87,
26
+ "errors": [],
27
+ "duration_seconds": 4.2
28
+}
29
+```
30
+
31
+### `navegador ci stats`
32
+
33
+Print graph statistics as JSON. Use to track graph growth over time or assert a minimum coverage threshold.
34
+
35
+```bash
36
+navegador ci stats
37
+```
38
+
39
+```json
40
+{
41
+ "repositories": 1,
42
+ "files": 87,
43
+ "classes": 143,
44
+ "functions": 891,
45
+ "methods": 412,
46
+ "concepts": 14,
47
+ "rules": 9,
48
+ "decisions": 6,
49
+ "total_edges": 4821
50
+}
51
+```
52
+
53
+### `navegador ci check`
54
+
55
+Run assertion checks against the graph. Exits non-zero if any check fails.
56
+
57
+```bash
58
+navegador ci check
59
+```
60
+
61
+Checks run by default:
62
+
63
+| Check | Condition for failure |
64
+|---|---|
65
+| `no-cycles` | Circular import chains detected |
66
+| `min-coverage` | Functions with no tests below threshold |
67
+| `critical-rules` | Code violates a `critical`-severity rule |
68
+| `dead-code` | High-confidence dead code above threshold |
69
+
70
+Configure checks in `navegador.toml`:
71
+
72
+```toml
73
+[ci.checks]
74
+no-cycles = true
75
+min-coverage = 60 # percent of functions with tests
76
+critical-rules = true
77
+dead-code = false # disable dead-code check
78
+
79
+[ci.thresholds]
80
+dead_code_max = 10 # fail if more than 10 dead-code candidates
81
+uncovered_max_percent = 40 # fail if more than 40% of functions lack tests
82
+```
83
+
84
+### Running specific checks
85
+
86
+```bash
87
+navegador ci check --only no-cycles
88
+navegador ci check --only critical-rules,min-coverage
89
+navegador ci check --skip dead-code
90
+```
91
+
92
+---
93
+
94
+## Exit codes
95
+
96
+| Code | Meaning |
97
+|---|---|
98
+| `0` | Success — all checks passed |
99
+| `1` | Check failure — one or more assertions failed |
100
+| `2` | Ingest error — files could not be parsed (partial result) |
101
+| `3` | Configuration error — bad flags or missing config |
102
+| `4` | Connection error — cannot reach database or Redis |
103
+
104
+---
105
+
106
+## GitHub Actions
107
+
108
+### Basic: ingest on push
109
+
110
+```yaml
111
+# .github/workflows/navegador.yml
112
+name: navegador
113
+
114
+on:
115
+ push:
116
+ branches: [main]
117
+ pull_request:
118
+
119
+jobs:
120
+ graph:
121
+ runs-on: ubuntu-latest
122
+ steps:
123
+ - uses: actions/checkout@v4
124
+
125
+ - name: Install navegador
126
+ run: pip install navegador
127
+
128
+ - name: Ingest
129
+ run: navegador ci ingest ./src
130
+
131
+ - name: Check
132
+ run: navegador ci check
133
+```
134
+
135
+### With graph caching
136
+
137
+Cache the SQLite database between runs to speed up incremental ingestion:
138
+
139
+```yaml
140
+ - name: Cache navegador graph
141
+ uses: actions/cache@v4
142
+ with:
143
+ path: .navegador/navegador.db
144
+ key: navegador-${{ runner.os }}-${{ hashFiles('src/**') }}
145
+ restore-keys: navegador-${{ runner.os }}-
146
+
147
+ - name: Ingest
148
+ run: navegador ci ingest ./src
149
+
150
+ - name: Check
151
+ run: navegador ci check
152
+```
153
+
154
+### Shared graph via Redis (cluster mode)
155
+
156
+Use a shared Redis instance for team-wide graph persistence across branches and PRs:
157
+
158
+```yaml
159
+ - name: Ingest to shared graph
160
+ env:
161
+ NAVEGADOR_REDIS_URL: ${{ secrets.NAVEGADOR_REDIS_URL }}
162
+ run: |
163
+ navegador ci ingest ./src --cluster
164
+ navegador ci check --cluster
165
+```
166
+
167
+### PR impact report
168
+
169
+Post an impact analysis comment on pull requests:
170
+
171
+```yaml
172
+ - name: Impact analysis
173
+ if: github.event_name == 'pull_request'
174
+ run: |
175
+ CHANGED=$(git diff --name-only origin/main...HEAD | grep '\.py$' | head -20)
176
+ for f in $CHANGED; do
177
+ navegador ci ingest "$f"
178
+ done
179
+ navegador impact --changed-since origin/main --format json > impact.json
180
+
181
+ - name: Comment impact
182
+ if: github.event_name == 'pull_request'
183
+ uses: actions/github-script@v7
184
+ with:
185
+ script: |
186
+ const impact = require('./impact.json')
187
+ const body = `## Navegador impact analysis\n\n${impact.summary}`
188
+ github.rest.issues.createComment({
189
+ issue_number: context.issue.number,
190
+ owner: context.repo.owner,
191
+ repo: context.repo.repo,
192
+ body
193
+ })
194
+```
195
+
196
+---
197
+
198
+## Editor integration
199
+
200
+### VS Code
201
+
202
+Install the [Navegador VS Code extension](https://marketplace.visualstudio.com/items?itemName=ConflictHQ.navegador) for inline context overlays and on-save re-ingest.
203
+
204
+Or configure a task in `.vscode/tasks.json` to run on save:
205
+
206
+```json
207
+{
208
+ "version": "2.0.0",
209
+ "tasks": [
210
+ {
211
+ "label": "Navegador: re-ingest on save",
212
+ "type": "shell",
213
+ "command": "navegador ingest ${file}",
214
+ "group": "build",
215
+ "presentation": {
216
+ "reveal": "silent",
217
+ "panel": "shared"
218
+ },
219
+ "runOptions": {
220
+ "runOn": "folderOpen"
221
+ }
222
+ }
223
+ ]
224
+}
225
+```
226
+
227
+### Neovim
228
+
229
+Add a post-write autocmd to trigger incremental ingest:
230
+
231
+```lua
232
+-- in your init.lua or a plugin config
233
+vim.api.nvim_create_autocmd("BufWritePost", {
234
+ pattern = { "*.py", "*.ts", "*.tsx", "*.js" },
235
+ callback = function(ev)
236
+ local file = ev.file
237
+ vim.fn.jobstart({ "navegador", "ingest", file }, { detach = true })
238
+ end,
239
+})
240
+```
241
+
242
+### Pre-commit hook
243
+
244
+Run checks before committing:
245
+
246
+```yaml
247
+# .pre-commit-config.yaml
248
+repos:
249
+ - repo: local
250
+ hooks:
251
+ - id: navegador-check
252
+ name: Navegador graph checks
253
+ entry: navegador ci check --only no-cycles,critical-rules
254
+ language: system
255
+ pass_filenames: false
256
+ stages: [commit]
257
+```
258
+
259
+---
260
+
261
+## Secrets and auth
262
+
263
+The graph database path and Redis URL should come from environment variables in CI, not from committed config:
264
+
265
+```bash
266
+# CI environment variables
267
+NAVEGADOR_DB=.navegador/navegador.db # SQLite path
268
+NAVEGADOR_REDIS_URL=redis://... # Redis URL (cluster mode)
269
+GITHUB_TOKEN=ghp_... # for wiki ingestion
270
+```
271
+
272
+Set these as [GitHub Actions secrets](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) and reference them in your workflow with `${{ secrets.NAME }}`.
--- a/docs/guide/ci-cd.md
+++ b/docs/guide/ci-cd.md
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/guide/ci-cd.md
+++ b/docs/guide/ci-cd.md
@@ -0,0 +1,272 @@
1 # CI/CD Integration
2
3 Navegador's `ci` subcommand is designed for non-interactive use in pipelines. All CI commands emit structured output and use exit codes that CI systems understand.
4
5 ---
6
7 ## CI commands
8
9 ### `navegador ci ingest`
10
11 Ingest the repo and output a machine-readable summary. Exits non-zero on errors.
12
13 ```bash
14 navegador ci ingest ./src
15 ```
16
17 JSON output (always on in CI mode):
18
19 ```json
20 {
21 "status": "ok",
22 "nodes_created": 1240,
23 "nodes_updated": 38,
24 "edges_created": 4821,
25 "files_processed": 87,
26 "errors": [],
27 "duration_seconds": 4.2
28 }
29 ```
30
31 ### `navegador ci stats`
32
33 Print graph statistics as JSON. Use to track graph growth over time or assert a minimum coverage threshold.
34
35 ```bash
36 navegador ci stats
37 ```
38
39 ```json
40 {
41 "repositories": 1,
42 "files": 87,
43 "classes": 143,
44 "functions": 891,
45 "methods": 412,
46 "concepts": 14,
47 "rules": 9,
48 "decisions": 6,
49 "total_edges": 4821
50 }
51 ```
52
53 ### `navegador ci check`
54
55 Run assertion checks against the graph. Exits non-zero if any check fails.
56
57 ```bash
58 navegador ci check
59 ```
60
61 Checks run by default:
62
63 | Check | Condition for failure |
64 |---|---|
65 | `no-cycles` | Circular import chains detected |
66 | `min-coverage` | Functions with no tests below threshold |
67 | `critical-rules` | Code violates a `critical`-severity rule |
68 | `dead-code` | High-confidence dead code above threshold |
69
70 Configure checks in `navegador.toml`:
71
72 ```toml
73 [ci.checks]
74 no-cycles = true
75 min-coverage = 60 # percent of functions with tests
76 critical-rules = true
77 dead-code = false # disable dead-code check
78
79 [ci.thresholds]
80 dead_code_max = 10 # fail if more than 10 dead-code candidates
81 uncovered_max_percent = 40 # fail if more than 40% of functions lack tests
82 ```
83
84 ### Running specific checks
85
86 ```bash
87 navegador ci check --only no-cycles
88 navegador ci check --only critical-rules,min-coverage
89 navegador ci check --skip dead-code
90 ```
91
92 ---
93
94 ## Exit codes
95
96 | Code | Meaning |
97 |---|---|
98 | `0` | Success — all checks passed |
99 | `1` | Check failure — one or more assertions failed |
100 | `2` | Ingest error — files could not be parsed (partial result) |
101 | `3` | Configuration error — bad flags or missing config |
102 | `4` | Connection error — cannot reach database or Redis |
103
104 ---
105
106 ## GitHub Actions
107
108 ### Basic: ingest on push
109
110 ```yaml
111 # .github/workflows/navegador.yml
112 name: navegador
113
114 on:
115 push:
116 branches: [main]
117 pull_request:
118
119 jobs:
120 graph:
121 runs-on: ubuntu-latest
122 steps:
123 - uses: actions/checkout@v4
124
125 - name: Install navegador
126 run: pip install navegador
127
128 - name: Ingest
129 run: navegador ci ingest ./src
130
131 - name: Check
132 run: navegador ci check
133 ```
134
135 ### With graph caching
136
137 Cache the SQLite database between runs to speed up incremental ingestion:
138
139 ```yaml
140 - name: Cache navegador graph
141 uses: actions/cache@v4
142 with:
143 path: .navegador/navegador.db
144 key: navegador-${{ runner.os }}-${{ hashFiles('src/**') }}
145 restore-keys: navegador-${{ runner.os }}-
146
147 - name: Ingest
148 run: navegador ci ingest ./src
149
150 - name: Check
151 run: navegador ci check
152 ```
153
154 ### Shared graph via Redis (cluster mode)
155
156 Use a shared Redis instance for team-wide graph persistence across branches and PRs:
157
158 ```yaml
159 - name: Ingest to shared graph
160 env:
161 NAVEGADOR_REDIS_URL: ${{ secrets.NAVEGADOR_REDIS_URL }}
162 run: |
163 navegador ci ingest ./src --cluster
164 navegador ci check --cluster
165 ```
166
167 ### PR impact report
168
169 Post an impact analysis comment on pull requests:
170
171 ```yaml
172 - name: Impact analysis
173 if: github.event_name == 'pull_request'
174 run: |
175 CHANGED=$(git diff --name-only origin/main...HEAD | grep '\.py$' | head -20)
176 for f in $CHANGED; do
177 navegador ci ingest "$f"
178 done
179 navegador impact --changed-since origin/main --format json > impact.json
180
181 - name: Comment impact
182 if: github.event_name == 'pull_request'
183 uses: actions/github-script@v7
184 with:
185 script: |
186 const impact = require('./impact.json')
187 const body = `## Navegador impact analysis\n\n${impact.summary}`
188 github.rest.issues.createComment({
189 issue_number: context.issue.number,
190 owner: context.repo.owner,
191 repo: context.repo.repo,
192 body
193 })
194 ```
195
196 ---
197
198 ## Editor integration
199
200 ### VS Code
201
202 Install the [Navegador VS Code extension](https://marketplace.visualstudio.com/items?itemName=ConflictHQ.navegador) for inline context overlays and on-save re-ingest.
203
204 Or configure a task in `.vscode/tasks.json` to run on save:
205
206 ```json
207 {
208 "version": "2.0.0",
209 "tasks": [
210 {
211 "label": "Navegador: re-ingest on save",
212 "type": "shell",
213 "command": "navegador ingest ${file}",
214 "group": "build",
215 "presentation": {
216 "reveal": "silent",
217 "panel": "shared"
218 },
219 "runOptions": {
220 "runOn": "folderOpen"
221 }
222 }
223 ]
224 }
225 ```
226
227 ### Neovim
228
229 Add a post-write autocmd to trigger incremental ingest:
230
231 ```lua
232 -- in your init.lua or a plugin config
233 vim.api.nvim_create_autocmd("BufWritePost", {
234 pattern = { "*.py", "*.ts", "*.tsx", "*.js" },
235 callback = function(ev)
236 local file = ev.file
237 vim.fn.jobstart({ "navegador", "ingest", file }, { detach = true })
238 end,
239 })
240 ```
241
242 ### Pre-commit hook
243
244 Run checks before committing:
245
246 ```yaml
247 # .pre-commit-config.yaml
248 repos:
249 - repo: local
250 hooks:
251 - id: navegador-check
252 name: Navegador graph checks
253 entry: navegador ci check --only no-cycles,critical-rules
254 language: system
255 pass_filenames: false
256 stages: [commit]
257 ```
258
259 ---
260
261 ## Secrets and auth
262
263 The graph database path and Redis URL should come from environment variables in CI, not from committed config:
264
265 ```bash
266 # CI environment variables
267 NAVEGADOR_DB=.navegador/navegador.db # SQLite path
268 NAVEGADOR_REDIS_URL=redis://... # Redis URL (cluster mode)
269 GITHUB_TOKEN=ghp_... # for wiki ingestion
270 ```
271
272 Set these as [GitHub Actions secrets](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) and reference them in your workflow with `${{ secrets.NAME }}`.
--- a/docs/guide/cluster.md
+++ b/docs/guide/cluster.md
@@ -0,0 +1,280 @@
1
+# Cluster Mode
2
+
3
+Cluster mode lets multiple machines share a single navegador graph over Redis. Use it when your team runs large ingestion jobs, want shared context across agents and CI, or need partitioned work processing.
4
+
5
+---
6
+
7
+## Prerequisites
8
+
9
+- Redis 7+ (or a managed Redis service — Upstash, Redis Cloud, etc.)
10
+- `pip install "navegador[redis]"`
11
+
12
+---
13
+
14
+## Setup
15
+
16
+### 1. Initialize cluster mode
17
+
18
+Point navegador at your Redis instance and run init:
19
+
20
+```bash
21
+navegador init --cluster --redis redis://your-redis-host:6379
22
+```
23
+
24
+This writes cluster config to `navegador.toml`:
25
+
26
+```toml
27
+[cluster]
28
+enabled = true
29
+redis_url = "redis://your-redis-host:6379"
30
+graph_name = "navegador"
31
+node_id = "worker-1" # auto-generated; override with --node-id
32
+```
33
+
34
+### 2. Verify connectivity
35
+
36
+```bash
37
+navegador cluster status
38
+```
39
+
40
+Output:
41
+
42
+```
43
+Cluster: connected
44
+Redis: redis://your-redis-host:6379
45
+Graph: navegador (47,231 nodes, 189,043 edges)
46
+Workers: 3 online (worker-1, worker-2, ci-runner-7)
47
+Queue: 0 tasks pending
48
+```
49
+
50
+---
51
+
52
+## Shared graph
53
+
54
+All cluster members read from and write to the same FalkorDB graph stored in Redis. Any ingestion or annotation from any node is immediately visible to all other nodes.
55
+
56
+```bash
57
+# on any machine in the cluster
58
+navegador ingest ./src
59
+
60
+# on any other machine — sees the result immediately
61
+navegador explain AuthService
62
+```
63
+
64
+### Local snapshots
65
+
66
+To work offline or reduce Redis round-trips, snapshot the graph to a local SQLite file:
67
+
68
+```bash
69
+# pull a snapshot from the shared graph
70
+navegador cluster snapshot --pull .navegador/local.db
71
+
72
+# use the snapshot for queries
73
+navegador --db .navegador/local.db explain AuthService
74
+
75
+# push local changes back to the shared graph
76
+navegador cluster snapshot --push .navegador/local.db
77
+```
78
+
79
+Snapshots are point-in-time copies. They do not auto-sync. Use `--pull` to refresh and `--push` to merge back.
80
+
81
+---
82
+
83
+## Task queue
84
+
85
+The cluster task queue distributes ingestion and analysis jobs across workers. Instead of running `navegador ingest` directly, submit a task:
86
+
87
+```bash
88
+# submit an ingestion task
89
+navegador cluster enqueue ingest ./src --clear
90
+
91
+# submit an analysis task
92
+navegador cluster enqueue analyze impact validate_token
93
+
94
+# list pending and active tasks
95
+navegador cluster queue
96
+```
97
+
98
+Workers pick up tasks from the queue automatically. See [work partitioning](#work-partitioning) for multi-worker ingestion.
99
+
100
+### Starting a worker
101
+
102
+```bash
103
+navegador cluster worker start
104
+```
105
+
106
+The worker polls the queue and processes tasks. Run one worker per machine.
107
+
108
+```bash
109
+# run in background
110
+navegador cluster worker start --daemon
111
+
112
+# stop the worker
113
+navegador cluster worker stop
114
+```
115
+
116
+---
117
+
118
+## Work partitioning
119
+
120
+For large monorepos, split ingestion across multiple workers:
121
+
122
+```bash
123
+# partition a directory across N workers
124
+navegador cluster partition ./src --workers 4
125
+
126
+# each worker then runs its assigned slice
127
+navegador cluster worker start --partition 0 --of 4 # worker 0
128
+navegador cluster worker start --partition 1 --of 4 # worker 1
129
+# ...
130
+```
131
+
132
+Partitioning splits the file list across workers by file count. All workers write to the same shared graph. The final graph is the union of all partitions.
133
+
134
+### In CI
135
+
136
+```yaml
137
+# .github/workflows/ingest.yml
138
+jobs:
139
+ ingest:
140
+ strategy:
141
+ matrix:
142
+ partition: [0, 1, 2, 3]
143
+ steps:
144
+ - run: navegador cluster worker start --partition ${{ matrix.partition }} --of 4 --run-once
145
+```
146
+
147
+`--run-once` processes the current queue and exits rather than running as a daemon.
148
+
149
+---
150
+
151
+## Sessions
152
+
153
+Sessions let multiple agents coordinate on the same task without interfering with each other.
154
+
155
+```bash
156
+# start a session (returns a session ID)
157
+SESSION=$(navegador cluster session start --name "feature/auth-refactor")
158
+echo "Session: $SESSION"
159
+
160
+# run commands scoped to the session
161
+navegador --session $SESSION ingest ./src/auth
162
+navegador --session $SESSION explain AuthService
163
+
164
+# end the session
165
+navegador cluster session end $SESSION
166
+```
167
+
168
+Sessions create a namespaced view of the graph. Writes within a session are visible to other session members but isolated from the main graph until committed.
169
+
170
+```bash
171
+# commit session changes to the main graph
172
+navegador cluster session commit $SESSION
173
+
174
+# discard session changes
175
+navegador cluster session discard $SESSION
176
+```
177
+
178
+---
179
+
180
+## Locking
181
+
182
+For writes that must not overlap (e.g., `--clear` ingest), navegador acquires a distributed lock:
183
+
184
+```bash
185
+navegador ingest ./src --clear
186
+# automatically acquires the graph write lock; other writers block until it releases
187
+```
188
+
189
+You can also acquire locks explicitly:
190
+
191
+```bash
192
+# acquire a named lock
193
+LOCK=$(navegador cluster lock acquire "ingest-lock" --ttl 300)
194
+
195
+# ... run your operations ...
196
+
197
+# release the lock
198
+navegador cluster lock release $LOCK
199
+```
200
+
201
+Locks have a TTL (seconds) and release automatically if the holder crashes.
202
+
203
+---
204
+
205
+## Messaging
206
+
207
+Workers and agents can exchange messages via the cluster bus:
208
+
209
+```bash
210
+# publish a message to a channel
211
+navegador cluster publish "ingest.complete" '{"repo": "myorg/myrepo", "nodes": 12450}'
212
+
213
+# subscribe to a channel (blocks; prints messages as they arrive)
214
+navegador cluster subscribe "ingest.complete"
215
+```
216
+
217
+Useful for triggering downstream steps (e.g., notify agents that a fresh ingest is ready) without polling.
218
+
219
+---
220
+
221
+## Observability
222
+
223
+### Cluster metrics
224
+
225
+```bash
226
+navegador cluster metrics
227
+```
228
+
229
+Output:
230
+
231
+```
232
+Graph
233
+ Nodes: 47,231
234
+ Edges: 189,043
235
+ Last ingest: 2026-03-23T14:22:11Z (worker-2)
236
+
237
+Workers (3 online)
238
+ worker-1 idle last seen 4s ago
239
+ worker-2 idle last seen 2s ago
240
+ ci-runner-7 processing task: ingest ./src/payments
241
+
242
+Queue
243
+ Pending: 0
244
+ Active: 1
245
+ Completed: 847 (last 24h)
246
+ Failed: 2 (last 24h)
247
+```
248
+
249
+### Logs
250
+
251
+Workers emit structured JSON logs. Stream them:
252
+
253
+```bash
254
+navegador cluster logs --follow
255
+navegador cluster logs --worker worker-2 --since 1h
256
+```
257
+
258
+### Health check
259
+
260
+```bash
261
+navegador cluster health
262
+# exits 0 if healthy, 1 if degraded, 2 if unavailable
263
+```
264
+
265
+Suitable for use in load balancer health checks and PagerDuty integrations.
266
+
267
+---
268
+
269
+## Configuration reference
270
+
271
+All cluster settings can be set in `navegador.toml` or as environment variables:
272
+
273
+| Setting | Env var | Default | Description |
274
+|---|---|---|---|
275
+| `redis_url` | `NAVEGADOR_REDIS_URL` | `redis://localhost:6379` | Redis connection URL |
276
+| `graph_name` | `NAVEGADOR_GRAPH_NAME` | `navegador` | FalkorDB graph name |
277
+| `node_id` | `NAVEGADOR_NODE_ID` | auto | Unique identifier for this worker |
278
+| `lock_ttl` | `NAVEGADOR_LOCK_TTL` | `300` | Default lock TTL in seconds |
279
+| `worker_poll_interval` | `NAVEGADOR_POLL_INTERVAL` | `2` | Queue poll interval in seconds |
280
+| `snapshot_dir` | `NAVEGADOR_SNAPSHOT_DIR` | `.navegador/snapshots` | Local snapshot directory |
--- a/docs/guide/cluster.md
+++ b/docs/guide/cluster.md
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/guide/cluster.md
+++ b/docs/guide/cluster.md
@@ -0,0 +1,280 @@
1 # Cluster Mode
2
3 Cluster mode lets multiple machines share a single navegador graph over Redis. Use it when your team runs large ingestion jobs, want shared context across agents and CI, or need partitioned work processing.
4
5 ---
6
7 ## Prerequisites
8
9 - Redis 7+ (or a managed Redis service — Upstash, Redis Cloud, etc.)
10 - `pip install "navegador[redis]"`
11
12 ---
13
14 ## Setup
15
16 ### 1. Initialize cluster mode
17
18 Point navegador at your Redis instance and run init:
19
20 ```bash
21 navegador init --cluster --redis redis://your-redis-host:6379
22 ```
23
24 This writes cluster config to `navegador.toml`:
25
26 ```toml
27 [cluster]
28 enabled = true
29 redis_url = "redis://your-redis-host:6379"
30 graph_name = "navegador"
31 node_id = "worker-1" # auto-generated; override with --node-id
32 ```
33
34 ### 2. Verify connectivity
35
36 ```bash
37 navegador cluster status
38 ```
39
40 Output:
41
42 ```
43 Cluster: connected
44 Redis: redis://your-redis-host:6379
45 Graph: navegador (47,231 nodes, 189,043 edges)
46 Workers: 3 online (worker-1, worker-2, ci-runner-7)
47 Queue: 0 tasks pending
48 ```
49
50 ---
51
52 ## Shared graph
53
54 All cluster members read from and write to the same FalkorDB graph stored in Redis. Any ingestion or annotation from any node is immediately visible to all other nodes.
55
56 ```bash
57 # on any machine in the cluster
58 navegador ingest ./src
59
60 # on any other machine — sees the result immediately
61 navegador explain AuthService
62 ```
63
64 ### Local snapshots
65
66 To work offline or reduce Redis round-trips, snapshot the graph to a local SQLite file:
67
68 ```bash
69 # pull a snapshot from the shared graph
70 navegador cluster snapshot --pull .navegador/local.db
71
72 # use the snapshot for queries
73 navegador --db .navegador/local.db explain AuthService
74
75 # push local changes back to the shared graph
76 navegador cluster snapshot --push .navegador/local.db
77 ```
78
79 Snapshots are point-in-time copies. They do not auto-sync. Use `--pull` to refresh and `--push` to merge back.
80
81 ---
82
83 ## Task queue
84
85 The cluster task queue distributes ingestion and analysis jobs across workers. Instead of running `navegador ingest` directly, submit a task:
86
87 ```bash
88 # submit an ingestion task
89 navegador cluster enqueue ingest ./src --clear
90
91 # submit an analysis task
92 navegador cluster enqueue analyze impact validate_token
93
94 # list pending and active tasks
95 navegador cluster queue
96 ```
97
98 Workers pick up tasks from the queue automatically. See [work partitioning](#work-partitioning) for multi-worker ingestion.
99
100 ### Starting a worker
101
102 ```bash
103 navegador cluster worker start
104 ```
105
106 The worker polls the queue and processes tasks. Run one worker per machine.
107
108 ```bash
109 # run in background
110 navegador cluster worker start --daemon
111
112 # stop the worker
113 navegador cluster worker stop
114 ```
115
116 ---
117
118 ## Work partitioning
119
120 For large monorepos, split ingestion across multiple workers:
121
122 ```bash
123 # partition a directory across N workers
124 navegador cluster partition ./src --workers 4
125
126 # each worker then runs its assigned slice
127 navegador cluster worker start --partition 0 --of 4 # worker 0
128 navegador cluster worker start --partition 1 --of 4 # worker 1
129 # ...
130 ```
131
132 Partitioning splits the file list across workers by file count. All workers write to the same shared graph. The final graph is the union of all partitions.
133
134 ### In CI
135
136 ```yaml
137 # .github/workflows/ingest.yml
138 jobs:
139 ingest:
140 strategy:
141 matrix:
142 partition: [0, 1, 2, 3]
143 steps:
144 - run: navegador cluster worker start --partition ${{ matrix.partition }} --of 4 --run-once
145 ```
146
147 `--run-once` processes the current queue and exits rather than running as a daemon.
148
149 ---
150
151 ## Sessions
152
153 Sessions let multiple agents coordinate on the same task without interfering with each other.
154
155 ```bash
156 # start a session (returns a session ID)
157 SESSION=$(navegador cluster session start --name "feature/auth-refactor")
158 echo "Session: $SESSION"
159
160 # run commands scoped to the session
161 navegador --session $SESSION ingest ./src/auth
162 navegador --session $SESSION explain AuthService
163
164 # end the session
165 navegador cluster session end $SESSION
166 ```
167
168 Sessions create a namespaced view of the graph. Writes within a session are visible to other session members but isolated from the main graph until committed.
169
170 ```bash
171 # commit session changes to the main graph
172 navegador cluster session commit $SESSION
173
174 # discard session changes
175 navegador cluster session discard $SESSION
176 ```
177
178 ---
179
180 ## Locking
181
182 For writes that must not overlap (e.g., `--clear` ingest), navegador acquires a distributed lock:
183
184 ```bash
185 navegador ingest ./src --clear
186 # automatically acquires the graph write lock; other writers block until it releases
187 ```
188
189 You can also acquire locks explicitly:
190
191 ```bash
192 # acquire a named lock
193 LOCK=$(navegador cluster lock acquire "ingest-lock" --ttl 300)
194
195 # ... run your operations ...
196
197 # release the lock
198 navegador cluster lock release $LOCK
199 ```
200
201 Locks have a TTL (seconds) and release automatically if the holder crashes.
202
203 ---
204
205 ## Messaging
206
207 Workers and agents can exchange messages via the cluster bus:
208
209 ```bash
210 # publish a message to a channel
211 navegador cluster publish "ingest.complete" '{"repo": "myorg/myrepo", "nodes": 12450}'
212
213 # subscribe to a channel (blocks; prints messages as they arrive)
214 navegador cluster subscribe "ingest.complete"
215 ```
216
217 Useful for triggering downstream steps (e.g., notify agents that a fresh ingest is ready) without polling.
218
219 ---
220
221 ## Observability
222
223 ### Cluster metrics
224
225 ```bash
226 navegador cluster metrics
227 ```
228
229 Output:
230
231 ```
232 Graph
233 Nodes: 47,231
234 Edges: 189,043
235 Last ingest: 2026-03-23T14:22:11Z (worker-2)
236
237 Workers (3 online)
238 worker-1 idle last seen 4s ago
239 worker-2 idle last seen 2s ago
240 ci-runner-7 processing task: ingest ./src/payments
241
242 Queue
243 Pending: 0
244 Active: 1
245 Completed: 847 (last 24h)
246 Failed: 2 (last 24h)
247 ```
248
249 ### Logs
250
251 Workers emit structured JSON logs. Stream them:
252
253 ```bash
254 navegador cluster logs --follow
255 navegador cluster logs --worker worker-2 --since 1h
256 ```
257
258 ### Health check
259
260 ```bash
261 navegador cluster health
262 # exits 0 if healthy, 1 if degraded, 2 if unavailable
263 ```
264
265 Suitable for use in load balancer health checks and PagerDuty integrations.
266
267 ---
268
269 ## Configuration reference
270
271 All cluster settings can be set in `navegador.toml` or as environment variables:
272
273 | Setting | Env var | Default | Description |
274 |---|---|---|---|
275 | `redis_url` | `NAVEGADOR_REDIS_URL` | `redis://localhost:6379` | Redis connection URL |
276 | `graph_name` | `NAVEGADOR_GRAPH_NAME` | `navegador` | FalkorDB graph name |
277 | `node_id` | `NAVEGADOR_NODE_ID` | auto | Unique identifier for this worker |
278 | `lock_ttl` | `NAVEGADOR_LOCK_TTL` | `300` | Default lock TTL in seconds |
279 | `worker_poll_interval` | `NAVEGADOR_POLL_INTERVAL` | `2` | Queue poll interval in seconds |
280 | `snapshot_dir` | `NAVEGADOR_SNAPSHOT_DIR` | `.navegador/snapshots` | Local snapshot directory |
--- docs/guide/context-loading.md
+++ docs/guide/context-loading.md
@@ -146,5 +146,168 @@
146146
navegador decorated pytest.mark.parametrize
147147
navegador decorated --format json login_required
148148
```
149149
150150
Returns function/class nodes with their file paths, line numbers, and the full decorator expression.
151
+
152
+---
153
+
154
+## impact — blast radius analysis
155
+
156
+Return the set of code nodes that could be affected if a given node changes, traversing CALLS, IMPORTS, and INHERITS edges transitively.
157
+
158
+```bash
159
+navegador impact validate_token
160
+navegador impact validate_token --depth 3
161
+navegador impact validate_token --format json
162
+```
163
+
164
+Useful before a refactor to understand the blast radius.
165
+
166
+---
167
+
168
+## trace — execution flow
169
+
170
+Trace the execution path through the call graph from a starting function:
171
+
172
+```bash
173
+navegador trace process_payment
174
+navegador trace process_payment --depth 4 --format json
175
+```
176
+
177
+Output shows the call chain as a tree, with each node annotated by file and line.
178
+
179
+---
180
+
181
+## diff — graph diff between refs
182
+
183
+Show what changed in the graph between two Git refs:
184
+
185
+```bash
186
+navegador diff HEAD~1 HEAD
187
+navegador diff main feature-branch
188
+```
189
+
190
+Reports added, removed, and changed nodes and edges.
191
+
192
+---
193
+
194
+## churn — code churn analysis
195
+
196
+Identify files and functions that change most frequently, based on Git history:
197
+
198
+```bash
199
+navegador churn
200
+navegador churn --days 30
201
+navegador churn --format json
202
+```
203
+
204
+High-churn nodes are often candidates for stabilization or better test coverage.
205
+
206
+---
207
+
208
+## deadcode — find unreachable code
209
+
210
+Find functions and classes with no callers and no references from outside their defining file:
211
+
212
+```bash
213
+navegador deadcode
214
+navegador deadcode --format json
215
+```
216
+
217
+---
218
+
219
+## cycles — dependency cycle detection
220
+
221
+Detect cycles in the IMPORTS and CALLS graphs:
222
+
223
+```bash
224
+navegador cycles
225
+navegador cycles --format json
226
+```
227
+
228
+Reports each cycle as an ordered list of node names.
229
+
230
+---
231
+
232
+## testmap — test-to-source mapping
233
+
234
+Map test functions to the source functions they exercise (based on naming conventions and import analysis):
235
+
236
+```bash
237
+navegador testmap
238
+navegador testmap src/auth/service.py
239
+navegador testmap --format json
240
+```
241
+
242
+Creates `TESTS` edges between test functions and their targets.
243
+
244
+---
245
+
246
+## semantic-search — vector similarity search
247
+
248
+Search using natural language against embeddings of docstrings and code. Requires `pip install "navegador[llm]"`.
249
+
250
+```bash
251
+navegador semantic-search "functions that validate user input"
252
+navegador semantic-search "payment retry logic" --limit 10
253
+```
254
+
255
+---
256
+
257
+## ask — NLP query interface
258
+
259
+Ask a natural language question about the codebase. Requires `pip install "navegador[llm]"`.
260
+
261
+```bash
262
+navegador ask "What handles authentication in this codebase?"
263
+navegador ask "Which functions touch the database?"
264
+```
265
+
266
+The answer is grounded in graph queries — not hallucinated from code text.
267
+
268
+---
269
+
270
+## rename — coordinated rename
271
+
272
+Rename a function or class across the graph and get a list of all files that reference the old name:
273
+
274
+```bash
275
+navegador rename validate_token validate_access_token
276
+```
277
+
278
+Output is a structured change plan. The command does not modify source files — it produces the list of locations to update.
279
+
280
+---
281
+
282
+## codeowners — ownership queries
283
+
284
+Query CODEOWNERS assignments and domain ownership:
285
+
286
+```bash
287
+navegador codeowners src/auth/service.py
288
+navegador codeowners AuthService
289
+```
290
+
291
+Returns owning teams and people from CODEOWNERS file and from `Person` nodes annotated to the matching code nodes.
292
+
293
+---
294
+
295
+## communities — module cluster detection
296
+
297
+Detect communities of highly-coupled modules using graph clustering:
298
+
299
+```bash
300
+navegador communities
301
+navegador communities --format json
302
+```
303
+
304
+---
305
+
306
+## explore — interactive graph explorer
307
+
308
+Open an interactive graph explorer in the terminal:
309
+
310
+```bash
311
+navegador explore
312
+navegador explore --start AuthService
313
+```
151314
152315
ADDED docs/guide/framework-enrichment.md
--- docs/guide/context-loading.md
+++ docs/guide/context-loading.md
@@ -146,5 +146,168 @@
146 navegador decorated pytest.mark.parametrize
147 navegador decorated --format json login_required
148 ```
149
150 Returns function/class nodes with their file paths, line numbers, and the full decorator expression.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
152 DDED docs/guide/framework-enrichment.md
--- docs/guide/context-loading.md
+++ docs/guide/context-loading.md
@@ -146,5 +146,168 @@
146 navegador decorated pytest.mark.parametrize
147 navegador decorated --format json login_required
148 ```
149
150 Returns function/class nodes with their file paths, line numbers, and the full decorator expression.
151
152 ---
153
154 ## impact — blast radius analysis
155
156 Return the set of code nodes that could be affected if a given node changes, traversing CALLS, IMPORTS, and INHERITS edges transitively.
157
158 ```bash
159 navegador impact validate_token
160 navegador impact validate_token --depth 3
161 navegador impact validate_token --format json
162 ```
163
164 Useful before a refactor to understand the blast radius.
165
166 ---
167
168 ## trace — execution flow
169
170 Trace the execution path through the call graph from a starting function:
171
172 ```bash
173 navegador trace process_payment
174 navegador trace process_payment --depth 4 --format json
175 ```
176
177 Output shows the call chain as a tree, with each node annotated by file and line.
178
179 ---
180
181 ## diff — graph diff between refs
182
183 Show what changed in the graph between two Git refs:
184
185 ```bash
186 navegador diff HEAD~1 HEAD
187 navegador diff main feature-branch
188 ```
189
190 Reports added, removed, and changed nodes and edges.
191
192 ---
193
194 ## churn — code churn analysis
195
196 Identify files and functions that change most frequently, based on Git history:
197
198 ```bash
199 navegador churn
200 navegador churn --days 30
201 navegador churn --format json
202 ```
203
204 High-churn nodes are often candidates for stabilization or better test coverage.
205
206 ---
207
208 ## deadcode — find unreachable code
209
210 Find functions and classes with no callers and no references from outside their defining file:
211
212 ```bash
213 navegador deadcode
214 navegador deadcode --format json
215 ```
216
217 ---
218
219 ## cycles — dependency cycle detection
220
221 Detect cycles in the IMPORTS and CALLS graphs:
222
223 ```bash
224 navegador cycles
225 navegador cycles --format json
226 ```
227
228 Reports each cycle as an ordered list of node names.
229
230 ---
231
232 ## testmap — test-to-source mapping
233
234 Map test functions to the source functions they exercise (based on naming conventions and import analysis):
235
236 ```bash
237 navegador testmap
238 navegador testmap src/auth/service.py
239 navegador testmap --format json
240 ```
241
242 Creates `TESTS` edges between test functions and their targets.
243
244 ---
245
246 ## semantic-search — vector similarity search
247
248 Search using natural language against embeddings of docstrings and code. Requires `pip install "navegador[llm]"`.
249
250 ```bash
251 navegador semantic-search "functions that validate user input"
252 navegador semantic-search "payment retry logic" --limit 10
253 ```
254
255 ---
256
257 ## ask — NLP query interface
258
259 Ask a natural language question about the codebase. Requires `pip install "navegador[llm]"`.
260
261 ```bash
262 navegador ask "What handles authentication in this codebase?"
263 navegador ask "Which functions touch the database?"
264 ```
265
266 The answer is grounded in graph queries — not hallucinated from code text.
267
268 ---
269
270 ## rename — coordinated rename
271
272 Rename a function or class across the graph and get a list of all files that reference the old name:
273
274 ```bash
275 navegador rename validate_token validate_access_token
276 ```
277
278 Output is a structured change plan. The command does not modify source files — it produces the list of locations to update.
279
280 ---
281
282 ## codeowners — ownership queries
283
284 Query CODEOWNERS assignments and domain ownership:
285
286 ```bash
287 navegador codeowners src/auth/service.py
288 navegador codeowners AuthService
289 ```
290
291 Returns owning teams and people from CODEOWNERS file and from `Person` nodes annotated to the matching code nodes.
292
293 ---
294
295 ## communities — module cluster detection
296
297 Detect communities of highly-coupled modules using graph clustering:
298
299 ```bash
300 navegador communities
301 navegador communities --format json
302 ```
303
304 ---
305
306 ## explore — interactive graph explorer
307
308 Open an interactive graph explorer in the terminal:
309
310 ```bash
311 navegador explore
312 navegador explore --start AuthService
313 ```
314
315 DDED docs/guide/framework-enrichment.md
--- a/docs/guide/framework-enrichment.md
+++ b/docs/guide/framework-enrichment.md
@@ -0,0 +1,51 @@
1
+# Framework Enrichment
2
+
3
+## What enrichment does
4
+
5
+After ingestion, navegador's graph contains generic structural nodes: `Function`, `Class`, `File`, `Import`. Enrichment promotes those generic nodes to **semantic types** that reflect how the code is actually used.
6
+
7
+For example, a Django view function becomes a `View` node. A pytest function becomes a `Test` node. A Flask route decorator triggers creation of a `Route` node with the URL pattern extracted.
8
+
9
+This lets you ask questions that wouldn't be possible from structure alone:
10
+
11
+```bash
12
+# without enrichment: grep for "def test_"
13
+# with enrichment: query the graph by semantic type
14
+navegador query "MATCH (t:Tting nodes and edges, applies framework-specific pattern matching (decorator names, base class names, naming conventions), and:
15
+
16
+1. Adds semantic labels to matched nodes (e.g., adds `View` label to Django view functions)
17
+2. Creates typed edges where the framework implies relationships (e.g., `HANDLES` from a `Route` to its handler function)
18
+3. Extracts framework-specific properties (e.g., HTTP method and URL pattern from route decorators)
19
+
20
+Enrichment is **non-destructive** — it never removes or modifies existing nodes, only adds labels and edges.
21
+
22
+---
23
+
24
+## Supported frameworks
25
+
26
+| Framework | Language | Detected patterns | Semantic types added |
27
+|---|---|---|---|
28
+| Django | Python | `View` subclasses, `urlpatterns`, `@login_required` | `View`, `Route`, `Model`, `Form`, `Middleware` oute`, `MethodView` | `Route`, `View`, `Blueprint` |
29
+| FastAPI | Python | `@router.get/post/put/delete/patch`, `APIRouter` | `Route`, `Schema`, `Dependency` |
30
+| pytest | Python | `def test_*`, `@pytest.mark.*`, `conftest.py` | `Test`, `Fixture`, `TestSuite` |
31
+| SQLAlchemy | Python | `Base` subclasses, `Column`, `relationship()` | `Model`, `Column`, `Relation` |
32
+| Next.js | TypeScript | `pages/`, `app/`, `getServerSideProps` | `Page`, `Route`, `ServerComponent` |
33
+| Express | JavaScript | `app.get/post/put/delete`, `Router` | `Route`, `Middleware` |
34
+| NestJS | TypeScript | `@Controller`, `@Injectable`, `@Module` | `Controller`, `Service`, `Module` |
35
+| **Terraform** | HCL | `main.tf`, `variables.tf`, `outputs.tf` | Cross-file module resolution, provider grouping |
36
+| **Chef** | Ruby | `metadata.rb`, `Berksfile` | `chef_recipe`, `chef_resource`, `chef_cookbook`, `chef_include` |
37
+
38
+!!! note
39
+ Framework detection is automatic when `--framework auto` is used (the default). Navegador inspects imports and decorator patterns to identify which frameworks are present.
40
+
41
+---
42
+
43
+## Usage
44
+
45
+### Auto-detect and enrich all frameworks
46
+
47
+```bash
48
+navegador enrich ./src
49
+```
50
+
51
+This runs after ingestion and enriches everything it can detect
--- a/docs/guide/framework-enrichment.md
+++ b/docs/guide/framework-enrichment.md
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/guide/framework-enrichment.md
+++ b/docs/guide/framework-enrichment.md
@@ -0,0 +1,51 @@
1 # Framework Enrichment
2
3 ## What enrichment does
4
5 After ingestion, navegador's graph contains generic structural nodes: `Function`, `Class`, `File`, `Import`. Enrichment promotes those generic nodes to **semantic types** that reflect how the code is actually used.
6
7 For example, a Django view function becomes a `View` node. A pytest function becomes a `Test` node. A Flask route decorator triggers creation of a `Route` node with the URL pattern extracted.
8
9 This lets you ask questions that wouldn't be possible from structure alone:
10
11 ```bash
12 # without enrichment: grep for "def test_"
13 # with enrichment: query the graph by semantic type
14 navegador query "MATCH (t:Tting nodes and edges, applies framework-specific pattern matching (decorator names, base class names, naming conventions), and:
15
16 1. Adds semantic labels to matched nodes (e.g., adds `View` label to Django view functions)
17 2. Creates typed edges where the framework implies relationships (e.g., `HANDLES` from a `Route` to its handler function)
18 3. Extracts framework-specific properties (e.g., HTTP method and URL pattern from route decorators)
19
20 Enrichment is **non-destructive** — it never removes or modifies existing nodes, only adds labels and edges.
21
22 ---
23
24 ## Supported frameworks
25
26 | Framework | Language | Detected patterns | Semantic types added |
27 |---|---|---|---|
28 | Django | Python | `View` subclasses, `urlpatterns`, `@login_required` | `View`, `Route`, `Model`, `Form`, `Middleware` oute`, `MethodView` | `Route`, `View`, `Blueprint` |
29 | FastAPI | Python | `@router.get/post/put/delete/patch`, `APIRouter` | `Route`, `Schema`, `Dependency` |
30 | pytest | Python | `def test_*`, `@pytest.mark.*`, `conftest.py` | `Test`, `Fixture`, `TestSuite` |
31 | SQLAlchemy | Python | `Base` subclasses, `Column`, `relationship()` | `Model`, `Column`, `Relation` |
32 | Next.js | TypeScript | `pages/`, `app/`, `getServerSideProps` | `Page`, `Route`, `ServerComponent` |
33 | Express | JavaScript | `app.get/post/put/delete`, `Router` | `Route`, `Middleware` |
34 | NestJS | TypeScript | `@Controller`, `@Injectable`, `@Module` | `Controller`, `Service`, `Module` |
35 | **Terraform** | HCL | `main.tf`, `variables.tf`, `outputs.tf` | Cross-file module resolution, provider grouping |
36 | **Chef** | Ruby | `metadata.rb`, `Berksfile` | `chef_recipe`, `chef_resource`, `chef_cookbook`, `chef_include` |
37
38 !!! note
39 Framework detection is automatic when `--framework auto` is used (the default). Navegador inspects imports and decorator patterns to identify which frameworks are present.
40
41 ---
42
43 ## Usage
44
45 ### Auto-detect and enrich all frameworks
46
47 ```bash
48 navegador enrich ./src
49 ```
50
51 This runs after ingestion and enriches everything it can detect
--- docs/guide/ingestion.md
+++ docs/guide/ingestion.md
@@ -12,18 +12,31 @@
1212
1313
### What gets extracted
1414
1515
Navegador walks all source files in the repo and uses tree-sitter to extract structure. Supported languages:
1616
17
-| Extension(s) | Language |
18
-|---|---|
19
-| `.py` | Python |
20
-| `.ts`, `.tsx` | TypeScript |
21
-| `.js`, `.jsx` | JavaScript |
22
-| `.go` | Go |
23
-| `.rs` | Rust |
24
-| `.java` | Java |
17
+| Extension(s) | Language | Extra |
18
+|---|---|---|
19
+| `.py` | Python | — |
20
+| `.ts`, `.tsx` | TypeScript | — |
21
+| `.js`, `.jsx` | JavaScript | — |
22
+| `.go` | Go | — |
23
+| `.rs` | Rust | — |
24
+| `.java` | Java | — |
25
+| `.kt`, `.kts` | Kotlin | `[languages]` |
26
+| `.cs` | C# | `[languages]` |
27
+| `.php` | PHP | `[languages]` |
28
+| `.rb` | Ruby | `[languages]` |
29
+| `.swift` | Swift | `[languages]` |
30
+| `.c`, `.h` | C | `[languages]` |
31
+| `.cpp`, `.cc`, `.cxx`, `.hpp` | C++ | `[languages]` |
32
+
33
+Install extended language support:
34
+
35
+```bash
36
+pip install "navegador[languages]"
37
+```
2538
2639
The following directories are always skipped: `.git`, `.venv`, `venv`, `node_modules`, `__pycache__`, `dist`, `build`, `.next`, `target` (Rust/Java builds), `vendor` (Go modules), `.gradle`.
2740
2841
### What gets extracted
2942
@@ -41,16 +54,56 @@
4154
### Options
4255
4356
| Flag | Effect |
4457
|---|---|
4558
| `--clear` | Wipe the graph before ingesting (full rebuild) |
59
+| `--incremental` | Only reprocess files whose content hash has changed |
60
+| `--watch` | Keep running and re-ingest on file changes |
61
+| `--redact` | Strip secrets (tokens, passwords, keys) from string literals |
62
+| `--monorepo` | Traverse workspace sub-packages (Turborepo, Nx, Yarn, pnpm, Cargo, Go) |
4663
| `--json` | Output a JSON summary of nodes and edges created |
4764
| `--db <path>` | Use a specific database file |
4865
4966
### Re-ingesting
5067
51
-Re-run `navegador ingest` anytime to pick up changes. Nodes are upserted by identity (file path + name), so repeated ingestion is idempotent for unchanged nodes. Use `--clear` when you need a clean slate (e.g., after a large rename refactor).
68
+Re-run `navegador ingest` anytime to pick up changes. Nodes are upserted by identity (file path + name), so repeated ingestion is idempotent for unchanged nodes. Use `--incremental` for large repos to skip unchanged files. Use `--clear` when you need a clean slate (e.g., after a large rename refactor).
69
+
70
+### Incremental ingestion
71
+
72
+`--incremental` uses SHA-256 content hashing to skip files that haven't changed since the last ingest. The hash is stored on each `File` node. On large repos this can reduce ingest time by 90%+ after the initial run.
73
+
74
+```bash
75
+navegador ingest ./repo --incremental
76
+```
77
+
78
+### Watch mode
79
+
80
+`--watch` starts a file-system watcher and automatically re-ingests any file that changes:
81
+
82
+```bash
83
+navegador ingest ./repo --watch
84
+```
85
+
86
+Press `Ctrl-C` to stop. Watch mode uses `--incremental` automatically.
87
+
88
+### Sensitive content redaction
89
+
90
+`--redact` scans string literals for patterns that look like API keys, tokens, and passwords, and replaces their values with `[REDACTED]` in the graph. Source files are never modified.
91
+
92
+```bash
93
+navegador ingest ./repo --redact
94
+```
95
+
96
+### Monorepo support
97
+
98
+`--monorepo` detects the workspace type and traverses all sub-packages:
99
+
100
+```bash
101
+navegador ingest ./monorepo --monorepo
102
+```
103
+
104
+Supported workspace formats: Turborepo, Nx, Yarn workspaces, pnpm workspaces, Cargo workspaces, Go workspaces.
52105
53106
---
54107
55108
## Knowledge curation
56109
57110
58111
ADDED docs/guide/intelligence.md
--- docs/guide/ingestion.md
+++ docs/guide/ingestion.md
@@ -12,18 +12,31 @@
12
13 ### What gets extracted
14
15 Navegador walks all source files in the repo and uses tree-sitter to extract structure. Supported languages:
16
17 | Extension(s) | Language |
18 |---|---|
19 | `.py` | Python |
20 | `.ts`, `.tsx` | TypeScript |
21 | `.js`, `.jsx` | JavaScript |
22 | `.go` | Go |
23 | `.rs` | Rust |
24 | `.java` | Java |
 
 
 
 
 
 
 
 
 
 
 
 
 
25
26 The following directories are always skipped: `.git`, `.venv`, `venv`, `node_modules`, `__pycache__`, `dist`, `build`, `.next`, `target` (Rust/Java builds), `vendor` (Go modules), `.gradle`.
27
28 ### What gets extracted
29
@@ -41,16 +54,56 @@
41 ### Options
42
43 | Flag | Effect |
44 |---|---|
45 | `--clear` | Wipe the graph before ingesting (full rebuild) |
 
 
 
 
46 | `--json` | Output a JSON summary of nodes and edges created |
47 | `--db <path>` | Use a specific database file |
48
49 ### Re-ingesting
50
51 Re-run `navegador ingest` anytime to pick up changes. Nodes are upserted by identity (file path + name), so repeated ingestion is idempotent for unchanged nodes. Use `--clear` when you need a clean slate (e.g., after a large rename refactor).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
53 ---
54
55 ## Knowledge curation
56
57
58 DDED docs/guide/intelligence.md
--- docs/guide/ingestion.md
+++ docs/guide/ingestion.md
@@ -12,18 +12,31 @@
12
13 ### What gets extracted
14
15 Navegador walks all source files in the repo and uses tree-sitter to extract structure. Supported languages:
16
17 | Extension(s) | Language | Extra |
18 |---|---|---|
19 | `.py` | Python | — |
20 | `.ts`, `.tsx` | TypeScript | — |
21 | `.js`, `.jsx` | JavaScript | — |
22 | `.go` | Go | — |
23 | `.rs` | Rust | — |
24 | `.java` | Java | — |
25 | `.kt`, `.kts` | Kotlin | `[languages]` |
26 | `.cs` | C# | `[languages]` |
27 | `.php` | PHP | `[languages]` |
28 | `.rb` | Ruby | `[languages]` |
29 | `.swift` | Swift | `[languages]` |
30 | `.c`, `.h` | C | `[languages]` |
31 | `.cpp`, `.cc`, `.cxx`, `.hpp` | C++ | `[languages]` |
32
33 Install extended language support:
34
35 ```bash
36 pip install "navegador[languages]"
37 ```
38
39 The following directories are always skipped: `.git`, `.venv`, `venv`, `node_modules`, `__pycache__`, `dist`, `build`, `.next`, `target` (Rust/Java builds), `vendor` (Go modules), `.gradle`.
40
41 ### What gets extracted
42
@@ -41,16 +54,56 @@
54 ### Options
55
56 | Flag | Effect |
57 |---|---|
58 | `--clear` | Wipe the graph before ingesting (full rebuild) |
59 | `--incremental` | Only reprocess files whose content hash has changed |
60 | `--watch` | Keep running and re-ingest on file changes |
61 | `--redact` | Strip secrets (tokens, passwords, keys) from string literals |
62 | `--monorepo` | Traverse workspace sub-packages (Turborepo, Nx, Yarn, pnpm, Cargo, Go) |
63 | `--json` | Output a JSON summary of nodes and edges created |
64 | `--db <path>` | Use a specific database file |
65
66 ### Re-ingesting
67
68 Re-run `navegador ingest` anytime to pick up changes. Nodes are upserted by identity (file path + name), so repeated ingestion is idempotent for unchanged nodes. Use `--incremental` for large repos to skip unchanged files. Use `--clear` when you need a clean slate (e.g., after a large rename refactor).
69
70 ### Incremental ingestion
71
72 `--incremental` uses SHA-256 content hashing to skip files that haven't changed since the last ingest. The hash is stored on each `File` node. On large repos this can reduce ingest time by 90%+ after the initial run.
73
74 ```bash
75 navegador ingest ./repo --incremental
76 ```
77
78 ### Watch mode
79
80 `--watch` starts a file-system watcher and automatically re-ingests any file that changes:
81
82 ```bash
83 navegador ingest ./repo --watch
84 ```
85
86 Press `Ctrl-C` to stop. Watch mode uses `--incremental` automatically.
87
88 ### Sensitive content redaction
89
90 `--redact` scans string literals for patterns that look like API keys, tokens, and passwords, and replaces their values with `[REDACTED]` in the graph. Source files are never modified.
91
92 ```bash
93 navegador ingest ./repo --redact
94 ```
95
96 ### Monorepo support
97
98 `--monorepo` detects the workspace type and traverses all sub-packages:
99
100 ```bash
101 navegador ingest ./monorepo --monorepo
102 ```
103
104 Supported workspace formats: Turborepo, Nx, Yarn workspaces, pnpm workspaces, Cargo workspaces, Go workspaces.
105
106 ---
107
108 ## Knowledge curation
109
110
111 DDED docs/guide/intelligence.md
--- a/docs/guide/intelligence.md
+++ b/docs/guide/intelligence.md
@@ -0,0 +1,267 @@
1
+# Intelligence Layer
2
+
3
+The intelligence layer adds capabilities that go beyond structural graph queries: semantic similarity search, community detection, natural language queries, and documentation generation. These features require an LLM provider or embedding model.
4
+
5
+---
6
+
7
+## Setup
8
+
9
+Install the intelligence extras:
10
+
11
+```bash
12
+pip install "navegador[intelligence]"
13
+```
14
+
15
+Configure your LLM provider:
16
+
17
+=== "OpenAI"
18
+
19
+ ```bash
20
+ export NAVEGADOR_LLM_PROVIDER=openai
21
+ export OPENAI_API_KEY=sk-...
22
+ ```
23
+
24
+=== "Anthropic"
25
+
26
+ ```bash
27
+ export NAVEGADOR_LLM_PROVIDER=anthropic
28
+ export ANTHROPIC_API_KEY=sk-ant-...
29
+ ```
30
+
31
+=== "Local (Ollama)"
32
+
33
+ ```bash
34
+ export NAVEGADOR_LLM_PROVIDER=ollama
35
+ export NAVEGADOR_LLM_MODEL=llama3.2
36
+ # no API key required; Ollama must be running on localhost:11434
37
+ ```
38
+
39
+Or set via `navegador.toml`:
40
+
41
+```toml
42
+[intelligence]
43
+provider = "openai"
44
+model = "text-embedding-3-small" # embedding model
45
+llm_model = "gpt-4o-mini" # generation model
46
+```
47
+
48
+---
49
+
50
+## Semantic search
51
+
52
+Standard `navegador search` matches on names and text. Semantic search matches on **meaning**: a query for "billing" finds code about "invoices", "subscriptions", and "charges" even when those words don't appear in the query.
53
+
54
+```bash
55
+navegador search "handle payment failure" --semantic
56
+navegador search "retry with backoff" --semantic --limit 10
57
+navegador search "authentication middleware" --semantic --all
58
+```
59
+
60
+!!! note
61
+ First run after ingestion builds the embedding index. This may take a minute on large codebases. The index is cached in the database and updated incrementally on re-ingest.
62
+
63
+### Combining semantic and text search
64
+
65
+```bash
66
+# semantic search scoped to a domain
67
+navegador search "billing failure" --semantic --domain Payments
68
+
69
+# hybrid: semantic ranking with text pre-filter
70
+navegador search "rate limit" --semantic --all
71
+```
72
+
73
+### Python API
74
+
75
+```python
76
+from navegador.graph import GraphStore
77
+from navegador.intelligence import SemanticSearch
78
+
79
+store = GraphStore.sqlite(".navegador/navegador.db")
80
+search = SemanticSearch(store)
81
+
82
+results = search.query("handle payment failure", limit=10)
83
+for node in results:
84
+ print(f"[{node.label}] {node.name} score={node.score:.3f}")
85
+```
86
+
87
+---
88
+
89
+## Community detection
90
+
91
+Community detection groups nodes in the graph into clusters based on structural connectivity. Clusters typically correspond to logical modules or subsystems, even when the code doesn't explicitly organize itself that way.
92
+
93
+```bash
94
+navegador intelligence communities
95
+navegador intelligence communities --algorithm louvain
96
+navegador intelligence communities --format json
97
+```
98
+
99
+### Algorithms
100
+
101
+| Algorithm | Best for |
102
+|---|---|
103
+| `louvain` (default) | Large codebases; fast and produces stable clusters |
104
+| `leiden` | Higher modularity; slower |
105
+| `label-propagation` | Very large graphs |
106
+
107
+### Output
108
+
109
+```
110
+Detected 6 communities:
111
+
112
+ Community 1 (47 nodes) — suggested name: Auth
113
+ Core: AuthService, validate_token, JWTManager
114
+ Files: src/auth/ (12 files)
115
+
116
+ Community 2 (38 nodes) — suggested name: Payments
117
+ Core: PaymentProcessor, charge_card, StripeClient
118
+ Files: src/payments/ (9 files)
119
+
120
+ Community 3 (22 nodes) — suggested name: Orders
121
+ Core: OrderService, create_order, OrderRepository
122
+ Files: src/orders/ (6 files)
123
+ ...
124
+```
125
+
126
+Suggested names are generated by the LLM by inspecting the core nodes of each cluster.
127
+
128
+### Persisting communities
129
+
130
+```bash
131
+navegador intelligence communities --save
132
+```
133
+
134
+This writes `Community` nodes and `MEMBER_OF` edges into the graph, making communities queryable:
135
+
136
+```bash
137
+navegador query "MATCH (f:Function)-[:MEMBER_OF]->(c:Community) WHERE c.name = 'Payments' RETURN f.name, f.file"
138
+```
139
+
140
+---
141
+
142
+## Natural language queries
143
+
144
+`navegador ask` lets you query the graph in plain English. The LLM translates your question into Cypher, executes it, and returns a natural language answer with citations.
145
+
146
+```bash
147
+navegador ask "Which functions call process_payment?"
148
+navegador ask "What rules govern the Payments domain?"
149
+navegador ask "Show me all classes that inherit from BaseProcessor"
150
+navegador ask "What decisions have been made about the database?"
151
+```
152
+
153
+### How it works
154
+
155
+1. Your question is embedded and matched against graph schema context
156
+2. The LLM generates a Cypher query based on the question and schema
157
+3. Navegador executes the query against the graph
158
+4. The LLM formats the results as a natural language answer with source references
159
+
160
+### Safety
161
+
162
+Generated queries are run in read-only mode. Write operations (`CREATE`, `MERGE`, `DELETE`, `SET`) in generated queries are blocked.
163
+
164
+```bash
165
+# show the generated Cypher without executing
166
+navegador ask "Which functions have no tests?" --show-query
167
+
168
+# execute and show both Cypher and answer
169
+navegador ask "Which functions have no tests?" --verbose
170
+```
171
+
172
+---
173
+
174
+## Documentation generation
175
+
176
+`navegador docgen` generates or improves docstrings for undocumented functions and classes, using graph context to produce accurate, context-aware descriptions.
177
+
178
+```bash
179
+# generate docs for all undocumented functions in a file
180
+navegador docgen src/payments/processor.py
181
+
182
+# generate docs for a specific function
183
+navegador docgen --target process_payment
184
+
185
+# dry run: show what would be generated without writing
186
+navegador docgen src/payments/processor.py --dry-run
187
+
188
+# write directly to source files
189
+navegador docgen src/payments/processor.py --write
190
+```
191
+
192
+### What it includes
193
+
194
+The generated docstring draws on:
195
+
196
+- The function's call graph (what it calls and what calls it)
197
+- Related concepts and rules from the knowledge layer
198
+- The class or module context
199
+- Existing docstrings in the same file as style examples
200
+
201
+### Output
202
+
203
+```python
204
+def process_payment(order_id: str, amount: Decimal, idempotency_key: str) -> PaymentResult:
205
+ """Process a payment for an order.
206
+
207
+ Charges the card on file for the given order using the Stripe payment
208
+ processor. Requires an idempotency key to prevent double-charging on
209
+ client retries (see: RequireIdempotencyKey rule, UseStripeForPayments
210
+ decision).
211
+
212
+ Args:
213
+ order_id: The unique identifier of the order to charge.
214
+ amount: The amount to charge in the order's currency.
215
+ idempotency_key: Client-supplied key for idempotent retries.
216
+
217
+ Returns:
218
+ PaymentResult with charge_id and status.
219
+
220
+ Raises:
221
+ PaymentError: If the charge fails or the card is declined.
222
+ DuplicatePaymentError: If a payment with this idempotency_key
223
+ already exists with a different amount.
224
+ """
225
+```
226
+
227
+### Batch generation
228
+
229
+```bash
230
+# generate docs for all undocumented functions in the repo
231
+navegador docgen ./src --write --format google
232
+
233
+# formats: google (default), numpy, sphinx
234
+```
235
+
236
+!!! warning
237
+ `--write` modifies source files in place. Review changes with `--dry-run` first and commit before running with `--write` so you can diff and revert.
238
+
239
+---
240
+
241
+## Python API
242
+
243
+```python
244
+from navegador.graph import GraphStore
245
+from navegador.intelligence import SemanticSearch, CommunityDetector, NaturalLanguageQuery, DocGenerator
246
+
247
+store = GraphStore.sqlite(".navegador/navegador.db")
248
+
249
+# semantic search
250
+search = SemanticSearch(store)
251
+results = search.query("retry logic", limit=5)
252
+
253
+# community detection
254
+detector = CommunityDetector(store)
255
+communities = detector.detect(algorithm="louvain", save=True)
256
+
257
+# natural language query
258
+nlq = NaturalLanguageQuery(store)
259
+answer = nlq.ask("What functions call process_payment?")
260
+print(answer.text)
261
+print(answer.cypher) # generated Cypher
262
+
263
+# doc generation
264
+docgen = DocGenerator(store)
265
+draft = docgen.generate_for_function("process_payment")
266
+print(draft.docstring)
267
+```
--- a/docs/guide/intelligence.md
+++ b/docs/guide/intelligence.md
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/guide/intelligence.md
+++ b/docs/guide/intelligence.md
@@ -0,0 +1,267 @@
1 # Intelligence Layer
2
3 The intelligence layer adds capabilities that go beyond structural graph queries: semantic similarity search, community detection, natural language queries, and documentation generation. These features require an LLM provider or embedding model.
4
5 ---
6
7 ## Setup
8
9 Install the intelligence extras:
10
11 ```bash
12 pip install "navegador[intelligence]"
13 ```
14
15 Configure your LLM provider:
16
17 === "OpenAI"
18
19 ```bash
20 export NAVEGADOR_LLM_PROVIDER=openai
21 export OPENAI_API_KEY=sk-...
22 ```
23
24 === "Anthropic"
25
26 ```bash
27 export NAVEGADOR_LLM_PROVIDER=anthropic
28 export ANTHROPIC_API_KEY=sk-ant-...
29 ```
30
31 === "Local (Ollama)"
32
33 ```bash
34 export NAVEGADOR_LLM_PROVIDER=ollama
35 export NAVEGADOR_LLM_MODEL=llama3.2
36 # no API key required; Ollama must be running on localhost:11434
37 ```
38
39 Or set via `navegador.toml`:
40
41 ```toml
42 [intelligence]
43 provider = "openai"
44 model = "text-embedding-3-small" # embedding model
45 llm_model = "gpt-4o-mini" # generation model
46 ```
47
48 ---
49
50 ## Semantic search
51
52 Standard `navegador search` matches on names and text. Semantic search matches on **meaning**: a query for "billing" finds code about "invoices", "subscriptions", and "charges" even when those words don't appear in the query.
53
54 ```bash
55 navegador search "handle payment failure" --semantic
56 navegador search "retry with backoff" --semantic --limit 10
57 navegador search "authentication middleware" --semantic --all
58 ```
59
60 !!! note
61 First run after ingestion builds the embedding index. This may take a minute on large codebases. The index is cached in the database and updated incrementally on re-ingest.
62
63 ### Combining semantic and text search
64
65 ```bash
66 # semantic search scoped to a domain
67 navegador search "billing failure" --semantic --domain Payments
68
69 # hybrid: semantic ranking with text pre-filter
70 navegador search "rate limit" --semantic --all
71 ```
72
73 ### Python API
74
75 ```python
76 from navegador.graph import GraphStore
77 from navegador.intelligence import SemanticSearch
78
79 store = GraphStore.sqlite(".navegador/navegador.db")
80 search = SemanticSearch(store)
81
82 results = search.query("handle payment failure", limit=10)
83 for node in results:
84 print(f"[{node.label}] {node.name} score={node.score:.3f}")
85 ```
86
87 ---
88
89 ## Community detection
90
91 Community detection groups nodes in the graph into clusters based on structural connectivity. Clusters typically correspond to logical modules or subsystems, even when the code doesn't explicitly organize itself that way.
92
93 ```bash
94 navegador intelligence communities
95 navegador intelligence communities --algorithm louvain
96 navegador intelligence communities --format json
97 ```
98
99 ### Algorithms
100
101 | Algorithm | Best for |
102 |---|---|
103 | `louvain` (default) | Large codebases; fast and produces stable clusters |
104 | `leiden` | Higher modularity; slower |
105 | `label-propagation` | Very large graphs |
106
107 ### Output
108
109 ```
110 Detected 6 communities:
111
112 Community 1 (47 nodes) — suggested name: Auth
113 Core: AuthService, validate_token, JWTManager
114 Files: src/auth/ (12 files)
115
116 Community 2 (38 nodes) — suggested name: Payments
117 Core: PaymentProcessor, charge_card, StripeClient
118 Files: src/payments/ (9 files)
119
120 Community 3 (22 nodes) — suggested name: Orders
121 Core: OrderService, create_order, OrderRepository
122 Files: src/orders/ (6 files)
123 ...
124 ```
125
126 Suggested names are generated by the LLM by inspecting the core nodes of each cluster.
127
128 ### Persisting communities
129
130 ```bash
131 navegador intelligence communities --save
132 ```
133
134 This writes `Community` nodes and `MEMBER_OF` edges into the graph, making communities queryable:
135
136 ```bash
137 navegador query "MATCH (f:Function)-[:MEMBER_OF]->(c:Community) WHERE c.name = 'Payments' RETURN f.name, f.file"
138 ```
139
140 ---
141
142 ## Natural language queries
143
144 `navegador ask` lets you query the graph in plain English. The LLM translates your question into Cypher, executes it, and returns a natural language answer with citations.
145
146 ```bash
147 navegador ask "Which functions call process_payment?"
148 navegador ask "What rules govern the Payments domain?"
149 navegador ask "Show me all classes that inherit from BaseProcessor"
150 navegador ask "What decisions have been made about the database?"
151 ```
152
153 ### How it works
154
155 1. Your question is embedded and matched against graph schema context
156 2. The LLM generates a Cypher query based on the question and schema
157 3. Navegador executes the query against the graph
158 4. The LLM formats the results as a natural language answer with source references
159
160 ### Safety
161
162 Generated queries are run in read-only mode. Write operations (`CREATE`, `MERGE`, `DELETE`, `SET`) in generated queries are blocked.
163
164 ```bash
165 # show the generated Cypher without executing
166 navegador ask "Which functions have no tests?" --show-query
167
168 # execute and show both Cypher and answer
169 navegador ask "Which functions have no tests?" --verbose
170 ```
171
172 ---
173
174 ## Documentation generation
175
176 `navegador docgen` generates or improves docstrings for undocumented functions and classes, using graph context to produce accurate, context-aware descriptions.
177
178 ```bash
179 # generate docs for all undocumented functions in a file
180 navegador docgen src/payments/processor.py
181
182 # generate docs for a specific function
183 navegador docgen --target process_payment
184
185 # dry run: show what would be generated without writing
186 navegador docgen src/payments/processor.py --dry-run
187
188 # write directly to source files
189 navegador docgen src/payments/processor.py --write
190 ```
191
192 ### What it includes
193
194 The generated docstring draws on:
195
196 - The function's call graph (what it calls and what calls it)
197 - Related concepts and rules from the knowledge layer
198 - The class or module context
199 - Existing docstrings in the same file as style examples
200
201 ### Output
202
203 ```python
204 def process_payment(order_id: str, amount: Decimal, idempotency_key: str) -> PaymentResult:
205 """Process a payment for an order.
206
207 Charges the card on file for the given order using the Stripe payment
208 processor. Requires an idempotency key to prevent double-charging on
209 client retries (see: RequireIdempotencyKey rule, UseStripeForPayments
210 decision).
211
212 Args:
213 order_id: The unique identifier of the order to charge.
214 amount: The amount to charge in the order's currency.
215 idempotency_key: Client-supplied key for idempotent retries.
216
217 Returns:
218 PaymentResult with charge_id and status.
219
220 Raises:
221 PaymentError: If the charge fails or the card is declined.
222 DuplicatePaymentError: If a payment with this idempotency_key
223 already exists with a different amount.
224 """
225 ```
226
227 ### Batch generation
228
229 ```bash
230 # generate docs for all undocumented functions in the repo
231 navegador docgen ./src --write --format google
232
233 # formats: google (default), numpy, sphinx
234 ```
235
236 !!! warning
237 `--write` modifies source files in place. Review changes with `--dry-run` first and commit before running with `--write` so you can diff and revert.
238
239 ---
240
241 ## Python API
242
243 ```python
244 from navegador.graph import GraphStore
245 from navegador.intelligence import SemanticSearch, CommunityDetector, NaturalLanguageQuery, DocGenerator
246
247 store = GraphStore.sqlite(".navegador/navegador.db")
248
249 # semantic search
250 search = SemanticSearch(store)
251 results = search.query("retry logic", limit=5)
252
253 # community detection
254 detector = CommunityDetector(store)
255 communities = detector.detect(algorithm="louvain", save=True)
256
257 # natural language query
258 nlq = NaturalLanguageQuery(store)
259 answer = nlq.ask("What functions call process_payment?")
260 print(answer.text)
261 print(answer.cypher) # generated Cypher
262
263 # doc generation
264 docgen = DocGenerator(store)
265 draft = docgen.generate_for_function("process_payment")
266 print(draft.docstring)
267 ```
--- docs/guide/mcp-integration.md
+++ docs/guide/mcp-integration.md
@@ -90,11 +90,11 @@
9090
9191
---
9292
9393
## Available MCP tools
9494
95
-All tools accept and return JSON.
95
+All tools accept and return JSON. There are 11 tools in total.
9696
9797
| Tool | Equivalent CLI | Description |
9898
|---|---|---|
9999
| `ingest` | `navegador ingest` | Ingest a repo into the graph |
100100
| `context` | `navegador context` | File-level context bundle |
@@ -101,10 +101,14 @@
101101
| `function` | `navegador function` | Function with call graph |
102102
| `class` | `navegador class` | Class with hierarchy |
103103
| `explain` | `navegador explain` | Universal node lookup |
104104
| `search` | `navegador search` | Text search across graph |
105105
| `query` | `navegador query` | Raw Cypher passthrough |
106
+| `get_rationale` | `navegador explain --rationale` | Decisions and rules governing a node |
107
+| `find_owners` | `navegador codeowners` | People and domains that own a node |
108
+| `search_knowledge` | `navegador search --knowledge` | Search knowledge layer only |
109
+| `blast_radius` | `navegador impact` | Transitive impact set for a node |
106110
107111
### Tool input schemas
108112
109113
**ingest**
110114
```json
@@ -139,14 +143,79 @@
139143
**query**
140144
```json
141145
{ "cypher": "MATCH (f:Function) RETURN f.name LIMIT 10" }
142146
```
143147
148
+**get_rationale**
149
+```json
150
+{ "name": "process_payment", "file": "src/payments/processor.py" }
151
+```
152
+
153
+**find_owners**
154
+```json
155
+{ "name": "AuthService", "file": "src/auth/service.py" }
156
+```
157
+
158
+**search_knowledge**
159
+```json
160
+{ "query": "idempotency", "limit": 10 }
161
+```
162
+
163
+**blast_radius**
164
+```json
165
+{ "name": "validate_token", "depth": 3 }
166
+```
167
+
168
+---
169
+
170
+## Read-only mode
171
+
172
+Start the MCP server in read-only mode to prevent agents from modifying the graph. This is recommended for shared or production environments.
173
+
174
+```bash
175
+navegador mcp --read-only
176
+```
177
+
178
+In read-only mode, the `ingest` tool is disabled and the `query` tool only accepts `MATCH`/`RETURN` queries. Write keywords (`CREATE`, `MERGE`, `SET`, `DELETE`) are rejected.
179
+
180
+Set in agent config:
181
+
182
+```json
183
+{
184
+ "mcpServers": {
185
+ "navegador": {
186
+ "command": "navegador",
187
+ "args": ["mcp", "--read-only"],
188
+ "env": {
189
+ "NAVEGADOR_DB": ".navegador/navegador.db"
190
+ }
191
+ }
192
+ }
193
+}
194
+```
195
+
196
+Or set `read_only = true` in `.navegador/config.toml` under `[mcp]`.
197
+
198
+---
199
+
200
+## Editor integration
201
+
202
+Instead of configuring MCP manually, use the editor setup command:
203
+
204
+```bash
205
+navegador editor setup claude-code
206
+navegador editor setup cursor
207
+navegador editor setup codex
208
+navegador editor setup windsurf
209
+```
210
+
211
+This writes the correct MCP config file for the selected editor and prompts for the database path.
212
+
144213
---
145214
146215
## When MCP makes sense
147216
148217
- You are in an interactive Claude or Cursor session and want to call `explain`, `search`, or `function` without dropping to a terminal
149218
- You want navegador tools auto-discovered by the agent without writing custom tool definitions
150219
- You are building an agent workflow that dynamically queries the graph mid-task
151220
152221
For automated background tasks (re-ingest on file save, sync on pull), use the CLI via [agent hooks](agent-hooks.md) instead.
153222
154223
ADDED docs/guide/sdk.md
--- docs/guide/mcp-integration.md
+++ docs/guide/mcp-integration.md
@@ -90,11 +90,11 @@
90
91 ---
92
93 ## Available MCP tools
94
95 All tools accept and return JSON.
96
97 | Tool | Equivalent CLI | Description |
98 |---|---|---|
99 | `ingest` | `navegador ingest` | Ingest a repo into the graph |
100 | `context` | `navegador context` | File-level context bundle |
@@ -101,10 +101,14 @@
101 | `function` | `navegador function` | Function with call graph |
102 | `class` | `navegador class` | Class with hierarchy |
103 | `explain` | `navegador explain` | Universal node lookup |
104 | `search` | `navegador search` | Text search across graph |
105 | `query` | `navegador query` | Raw Cypher passthrough |
 
 
 
 
106
107 ### Tool input schemas
108
109 **ingest**
110 ```json
@@ -139,14 +143,79 @@
139 **query**
140 ```json
141 { "cypher": "MATCH (f:Function) RETURN f.name LIMIT 10" }
142 ```
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144 ---
145
146 ## When MCP makes sense
147
148 - You are in an interactive Claude or Cursor session and want to call `explain`, `search`, or `function` without dropping to a terminal
149 - You want navegador tools auto-discovered by the agent without writing custom tool definitions
150 - You are building an agent workflow that dynamically queries the graph mid-task
151
152 For automated background tasks (re-ingest on file save, sync on pull), use the CLI via [agent hooks](agent-hooks.md) instead.
153
154 DDED docs/guide/sdk.md
--- docs/guide/mcp-integration.md
+++ docs/guide/mcp-integration.md
@@ -90,11 +90,11 @@
90
91 ---
92
93 ## Available MCP tools
94
95 All tools accept and return JSON. There are 11 tools in total.
96
97 | Tool | Equivalent CLI | Description |
98 |---|---|---|
99 | `ingest` | `navegador ingest` | Ingest a repo into the graph |
100 | `context` | `navegador context` | File-level context bundle |
@@ -101,10 +101,14 @@
101 | `function` | `navegador function` | Function with call graph |
102 | `class` | `navegador class` | Class with hierarchy |
103 | `explain` | `navegador explain` | Universal node lookup |
104 | `search` | `navegador search` | Text search across graph |
105 | `query` | `navegador query` | Raw Cypher passthrough |
106 | `get_rationale` | `navegador explain --rationale` | Decisions and rules governing a node |
107 | `find_owners` | `navegador codeowners` | People and domains that own a node |
108 | `search_knowledge` | `navegador search --knowledge` | Search knowledge layer only |
109 | `blast_radius` | `navegador impact` | Transitive impact set for a node |
110
111 ### Tool input schemas
112
113 **ingest**
114 ```json
@@ -139,14 +143,79 @@
143 **query**
144 ```json
145 { "cypher": "MATCH (f:Function) RETURN f.name LIMIT 10" }
146 ```
147
148 **get_rationale**
149 ```json
150 { "name": "process_payment", "file": "src/payments/processor.py" }
151 ```
152
153 **find_owners**
154 ```json
155 { "name": "AuthService", "file": "src/auth/service.py" }
156 ```
157
158 **search_knowledge**
159 ```json
160 { "query": "idempotency", "limit": 10 }
161 ```
162
163 **blast_radius**
164 ```json
165 { "name": "validate_token", "depth": 3 }
166 ```
167
168 ---
169
170 ## Read-only mode
171
172 Start the MCP server in read-only mode to prevent agents from modifying the graph. This is recommended for shared or production environments.
173
174 ```bash
175 navegador mcp --read-only
176 ```
177
178 In read-only mode, the `ingest` tool is disabled and the `query` tool only accepts `MATCH`/`RETURN` queries. Write keywords (`CREATE`, `MERGE`, `SET`, `DELETE`) are rejected.
179
180 Set in agent config:
181
182 ```json
183 {
184 "mcpServers": {
185 "navegador": {
186 "command": "navegador",
187 "args": ["mcp", "--read-only"],
188 "env": {
189 "NAVEGADOR_DB": ".navegador/navegador.db"
190 }
191 }
192 }
193 }
194 ```
195
196 Or set `read_only = true` in `.navegador/config.toml` under `[mcp]`.
197
198 ---
199
200 ## Editor integration
201
202 Instead of configuring MCP manually, use the editor setup command:
203
204 ```bash
205 navegador editor setup claude-code
206 navegador editor setup cursor
207 navegador editor setup codex
208 navegador editor setup windsurf
209 ```
210
211 This writes the correct MCP config file for the selected editor and prompts for the database path.
212
213 ---
214
215 ## When MCP makes sense
216
217 - You are in an interactive Claude or Cursor session and want to call `explain`, `search`, or `function` without dropping to a terminal
218 - You want navegador tools auto-discovered by the agent without writing custom tool definitions
219 - You are building an agent workflow that dynamically queries the graph mid-task
220
221 For automated background tasks (re-ingest on file save, sync on pull), use the CLI via [agent hooks](agent-hooks.md) instead.
222
223 DDED docs/guide/sdk.md
--- a/docs/guide/sdk.md
+++ b/docs/guide/sdk.md
@@ -0,0 +1,254 @@
1
+# Python SDK
2
+
3
+The navegador Python SDK lets you drive ingestion, query the graph, and load context from your own scripts and tools — without going through the CLI.
4
+
5
+---
6
+
7
+## Installation
8
+
9
+```bash
10
+pip install navegador
11
+```
12
+
13
+For Redis (production/team) support:
14
+
15
+```bash
16
+pip install "navegador[redis]"
17
+```
18
+
19
+---
20
+
21
+## Connecting to the graph
22
+
23
+=== "SQLite (local)"
24
+
25
+ ```python
26
+ from navegador.graph import GraphStore
27
+
28
+ store = GraphStore.sqlite(".navegador/navegador.db")
29
+ ```
30
+
31
+=== "Redis (production)"
32
+
33
+ ```python
34
+ from navegador.graph import GraphStore
35
+
36
+ store = GraphStore.redis("redis://localhost:6379")
37
+ ```
38
+
39
+Both backends implement the same interface. All examples below work with either.
40
+
41
+Use the context manager to ensure the connection is closed:
42
+
43
+```python
44
+with GraphStore.sqlite(".navegador/navegador.db") as store:
45
+ results = store.query("MATCH (n) RETURN count(n) AS total")
46
+ print(results[0]["total"])
47
+```
48
+
49
+---
50
+
51
+## Ingestion
52
+
53
+### Ingest a repo
54
+
55
+```python
56
+from navegador.graph import GraphStore
57
+from navegador.ingest import RepoIngester
58
+
59
+store = GraphStore.sqlite(".navegador/navegador.db")
60
+ingester = RepoIngester(store)
61
+
62
+result = ingester.ingest("./src")
63
+print(f"{result.nodes_created} nodes, {result.edges_created} edges in {result.duration_seconds:.2f}s")
64
+```
65
+
66
+### Incremental ingest (single file)
67
+
68
+```python
69
+result = ingester.ingest_file("./src/auth/service.py")
70
+```
71
+
72
+### Wipe and rebuild
73
+
74
+```python
75
+result = ingester.ingest("./src", clear=True)
76
+```
77
+
78
+### Add knowledge programmatically
79
+
80
+```python
81
+from navegador.ingest import KnowledgeIngester
82
+
83
+ki = KnowledgeIngester(store)
84
+
85
+ki.add_domain("Payments", description="Payment processing and billing")
86
+ki.add_concept("Idempotency", domain="Payments",
87
+ description="Operations safe to retry without side effects")
88
+ki.add_rule("RequireIdempotencyKey",
89
+ domain="Payments", severity="critical",
90
+ rationale="Card networks retry on timeout")
91
+ki.annotate("process_payment", node_type="Function",
92
+ concept="Idempotency", rule="RequireIdempotencyKey")
93
+```
94
+
95
+---
96
+
97
+## Loading context
98
+
99
+`ContextLoader` builds structured context bundles from the graph. Each method corresponds to a CLI command.
100
+
101
+```python
102
+from navegador.graph import GraphStore
103
+from navegador.context import ContextLoader
104
+
105
+store = GraphStore.sqlite(".navegador/navegador.db")
106
+loader = ContextLoader(store)
107
+```
108
+
109
+### File context
110
+
111
+```python
112
+bundle = loader.load_file("src/auth/service.py")
113
+print(bundle.to_markdown())
114
+```
115
+
116
+### Function with call graph
117
+
118
+```python
119
+# depth controls how many hops of callers/callees to include
120
+bundle = loader.load_function("validate_token", depth=2)
121
+print(bundle.to_json())
122
+```
123
+
124
+### Class hierarchy
125
+
126
+```python
127
+bundle = loader.load_class("PaymentProcessor", file="src/payments/processor.py")
128
+data = bundle.to_dict()
129
+```
130
+
131
+### Universal explain
132
+
133
+```python
134
+# works for any node type: function, class, file, concept, rule, decision
135
+bundle = loader.explain("AuthService")
136
+bundle = loader.explain("PaymentsMustBeIdempotent")
137
+```
138
+
139
+### Concept and domain
140
+
141
+```python
142
+bundle = loader.load_concept("Idempotency")
143
+bundle = loader.load_domain("Payments")
144
+```
145
+
146
+---
147
+
148
+## Search
149
+
150
+```python
151
+# search function and class names (default)
152
+nodes = loader.search("rate limit")
153
+
154
+# search all layers including knowledge and docs
155
+nodes = loader.search("rate limit", all_layers=True, limit=50)
156
+
157
+# search docstrings and wiki content only
158
+nodes = loader.search_by_docstring("retry logic")
159
+
160
+# find all functions using a specific decorator
161
+nodes = loader.decorated_by("login_required")
162
+
163
+for node in nodes:
164
+ print(f"{node.label}: {node.name} ({node.properties.get('file', '')})")
165
+```
166
+
167
+---
168
+
169
+## Knowledge queries
170
+
171
+```python
172
+# everything in the Payments domain
173
+bundle = loader.load_domain("Payments")
174
+for node in bundle.nodes:
175
+ print(f" [{node.label}] {node.name}")
176
+
177
+# all code annotated with a concept
178
+bundle = loader.load_concept("Idempotency")
179
+for node in bundle.nodes:
180
+ if node.layer == "code":
181
+ print(f" {node.name} {node.properties.get('file', '')}")
182
+```
183
+
184
+---
185
+
186
+## Exporting output
187
+
188
+Every `ContextBundle` supports three output formats:
189
+
190
+```python
191
+bundle = loader.load_function("process_payment")
192
+
193
+# JSON string — for agents, APIs, CI
194
+json_str = bundle.to_json()
195
+
196
+# Markdown — readable by humans and LLMs
197
+md_str = bundle.to_markdown()
198
+
199
+# Python dict — for further processing
200
+data = bundle.to_dict()
201
+print(data["root"]["name"])
202
+print(len(data["nodes"]))
203
+```
204
+
205
+---
206
+
207
+## Raw Cypher queries
208
+
209
+Drop to raw Cypher for anything the built-in methods don't cover:
210
+
211
+```python
212
+results = store.query(
213
+ "MATCH (f:Function)-[:CALLS]->(g:Function) "
214
+ "WHERE f.file = $file "
215
+ "RETURN f.name, g.name",
216
+ params={"file": "src/payments/processor.py"}
217
+)
218
+for row in results:
219
+ print(f"{row['f.name']} -> {row['g.name']}")
220
+```
221
+
222
+!!! warning
223
+ `store.query()` executes writes as well as reads. Stick to `MATCH` / `RETURN` for inspection queries.
224
+
225
+---
226
+
227
+## Wiki ingestion
228
+
229
+```python
230
+import os
231
+from navegador.ingest import WikiIngester
232
+
233
+ingester = WikiIngester(store)
234
+
235
+# from GitHub API
236
+result = ingester.ingest_repo("myorg/myrepo", token=os.environ["GITHUB_TOKEN"])
237
+
238
+# from a locally cloned wiki directory
239
+result = ingester.ingest_dir("./myrepo.wiki")
240
+```
241
+
242
+---
243
+
244
+## Error handling
245
+
246
+All ingesters return an `IngestionResult` dataclass. Check `errors` for per-file failures without crashing the whole run:
247
+
248
+```python
249
+result = ingester.ingest("./src")
250
+if result.errors:
251
+ for err in result.errors:
252
+ print(f"Warning: {err}")
253
+print(f"Processed {result.files_processed} files, {result.nodes_created} nodes created")
254
+```
--- a/docs/guide/sdk.md
+++ b/docs/guide/sdk.md
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/guide/sdk.md
+++ b/docs/guide/sdk.md
@@ -0,0 +1,254 @@
1 # Python SDK
2
3 The navegador Python SDK lets you drive ingestion, query the graph, and load context from your own scripts and tools — without going through the CLI.
4
5 ---
6
7 ## Installation
8
9 ```bash
10 pip install navegador
11 ```
12
13 For Redis (production/team) support:
14
15 ```bash
16 pip install "navegador[redis]"
17 ```
18
19 ---
20
21 ## Connecting to the graph
22
23 === "SQLite (local)"
24
25 ```python
26 from navegador.graph import GraphStore
27
28 store = GraphStore.sqlite(".navegador/navegador.db")
29 ```
30
31 === "Redis (production)"
32
33 ```python
34 from navegador.graph import GraphStore
35
36 store = GraphStore.redis("redis://localhost:6379")
37 ```
38
39 Both backends implement the same interface. All examples below work with either.
40
41 Use the context manager to ensure the connection is closed:
42
43 ```python
44 with GraphStore.sqlite(".navegador/navegador.db") as store:
45 results = store.query("MATCH (n) RETURN count(n) AS total")
46 print(results[0]["total"])
47 ```
48
49 ---
50
51 ## Ingestion
52
53 ### Ingest a repo
54
55 ```python
56 from navegador.graph import GraphStore
57 from navegador.ingest import RepoIngester
58
59 store = GraphStore.sqlite(".navegador/navegador.db")
60 ingester = RepoIngester(store)
61
62 result = ingester.ingest("./src")
63 print(f"{result.nodes_created} nodes, {result.edges_created} edges in {result.duration_seconds:.2f}s")
64 ```
65
66 ### Incremental ingest (single file)
67
68 ```python
69 result = ingester.ingest_file("./src/auth/service.py")
70 ```
71
72 ### Wipe and rebuild
73
74 ```python
75 result = ingester.ingest("./src", clear=True)
76 ```
77
78 ### Add knowledge programmatically
79
80 ```python
81 from navegador.ingest import KnowledgeIngester
82
83 ki = KnowledgeIngester(store)
84
85 ki.add_domain("Payments", description="Payment processing and billing")
86 ki.add_concept("Idempotency", domain="Payments",
87 description="Operations safe to retry without side effects")
88 ki.add_rule("RequireIdempotencyKey",
89 domain="Payments", severity="critical",
90 rationale="Card networks retry on timeout")
91 ki.annotate("process_payment", node_type="Function",
92 concept="Idempotency", rule="RequireIdempotencyKey")
93 ```
94
95 ---
96
97 ## Loading context
98
99 `ContextLoader` builds structured context bundles from the graph. Each method corresponds to a CLI command.
100
101 ```python
102 from navegador.graph import GraphStore
103 from navegador.context import ContextLoader
104
105 store = GraphStore.sqlite(".navegador/navegador.db")
106 loader = ContextLoader(store)
107 ```
108
109 ### File context
110
111 ```python
112 bundle = loader.load_file("src/auth/service.py")
113 print(bundle.to_markdown())
114 ```
115
116 ### Function with call graph
117
118 ```python
119 # depth controls how many hops of callers/callees to include
120 bundle = loader.load_function("validate_token", depth=2)
121 print(bundle.to_json())
122 ```
123
124 ### Class hierarchy
125
126 ```python
127 bundle = loader.load_class("PaymentProcessor", file="src/payments/processor.py")
128 data = bundle.to_dict()
129 ```
130
131 ### Universal explain
132
133 ```python
134 # works for any node type: function, class, file, concept, rule, decision
135 bundle = loader.explain("AuthService")
136 bundle = loader.explain("PaymentsMustBeIdempotent")
137 ```
138
139 ### Concept and domain
140
141 ```python
142 bundle = loader.load_concept("Idempotency")
143 bundle = loader.load_domain("Payments")
144 ```
145
146 ---
147
148 ## Search
149
150 ```python
151 # search function and class names (default)
152 nodes = loader.search("rate limit")
153
154 # search all layers including knowledge and docs
155 nodes = loader.search("rate limit", all_layers=True, limit=50)
156
157 # search docstrings and wiki content only
158 nodes = loader.search_by_docstring("retry logic")
159
160 # find all functions using a specific decorator
161 nodes = loader.decorated_by("login_required")
162
163 for node in nodes:
164 print(f"{node.label}: {node.name} ({node.properties.get('file', '')})")
165 ```
166
167 ---
168
169 ## Knowledge queries
170
171 ```python
172 # everything in the Payments domain
173 bundle = loader.load_domain("Payments")
174 for node in bundle.nodes:
175 print(f" [{node.label}] {node.name}")
176
177 # all code annotated with a concept
178 bundle = loader.load_concept("Idempotency")
179 for node in bundle.nodes:
180 if node.layer == "code":
181 print(f" {node.name} {node.properties.get('file', '')}")
182 ```
183
184 ---
185
186 ## Exporting output
187
188 Every `ContextBundle` supports three output formats:
189
190 ```python
191 bundle = loader.load_function("process_payment")
192
193 # JSON string — for agents, APIs, CI
194 json_str = bundle.to_json()
195
196 # Markdown — readable by humans and LLMs
197 md_str = bundle.to_markdown()
198
199 # Python dict — for further processing
200 data = bundle.to_dict()
201 print(data["root"]["name"])
202 print(len(data["nodes"]))
203 ```
204
205 ---
206
207 ## Raw Cypher queries
208
209 Drop to raw Cypher for anything the built-in methods don't cover:
210
211 ```python
212 results = store.query(
213 "MATCH (f:Function)-[:CALLS]->(g:Function) "
214 "WHERE f.file = $file "
215 "RETURN f.name, g.name",
216 params={"file": "src/payments/processor.py"}
217 )
218 for row in results:
219 print(f"{row['f.name']} -> {row['g.name']}")
220 ```
221
222 !!! warning
223 `store.query()` executes writes as well as reads. Stick to `MATCH` / `RETURN` for inspection queries.
224
225 ---
226
227 ## Wiki ingestion
228
229 ```python
230 import os
231 from navegador.ingest import WikiIngester
232
233 ingester = WikiIngester(store)
234
235 # from GitHub API
236 result = ingester.ingest_repo("myorg/myrepo", token=os.environ["GITHUB_TOKEN"])
237
238 # from a locally cloned wiki directory
239 result = ingester.ingest_dir("./myrepo.wiki")
240 ```
241
242 ---
243
244 ## Error handling
245
246 All ingesters return an `IngestionResult` dataclass. Check `errors` for per-file failures without crashing the whole run:
247
248 ```python
249 result = ingester.ingest("./src")
250 if result.errors:
251 for err in result.errors:
252 print(f"Warning: {err}")
253 print(f"Processed {result.files_processed} files, {result.nodes_created} nodes created")
254 ```
+59 -2
--- docs/index.md
+++ docs/index.md
@@ -3,10 +3,12 @@
33
**The project knowledge graph for AI coding agents.**
44
55
Navegador builds and maintains a queryable graph of your software project — combining static code analysis with human-curated business knowledge — so that AI coding agents always have precise, structured context instead of raw file dumps.
66
77
> *navegador* — Spanish for *navigator / sailor*. It helps agents navigate your code.
8
+>
9
+> **Current version: 0.7.0**
810
911
---
1012
1113
## Two layers, one graph
1214
@@ -22,11 +24,11 @@
2224
│ Variable · Import · Decorator · (call graphs, hierarchies) │
2325
└─────────────────────────────────────────────────────────────────┘
2426
stored in FalkorDB (SQLite local / Redis prod)
2527
```
2628
27
-The **code layer** is populated automatically by ingesting source trees. Python and TypeScript are supported out of the box via tree-sitter. The **knowledge layer** is populated by manual curation (`navegador add`), GitHub wiki ingestion, and [Planopticon](guide/planopticon.md) output (meeting and video knowledge graphs).
29
+The **code layer** is populated automatically by ingesting source trees. 13 languages are supported via tree-sitter (Python, TypeScript, JavaScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, Swift, C, C++). The **knowledge layer** is populated by manual curation (`navegador add`), GitHub wiki ingestion, and [Planopticon](guide/planopticon.md) output (meeting and video knowledge graphs).
2830
2931
---
3032
3133
## Quick start
3234
@@ -34,10 +36,21 @@
3436
pip install navegador # Python 3.12+ required
3537
navegador ingest ./my-repo # parse + index the codebase
3638
navegador explain AuthService # what is this thing?
3739
navegador search "rate limit" --all # search code + knowledge together
3840
```
41
+
42
+Or use the Python SDK:
43
+
44
+```python
45
+from navegador import Navegador
46
+
47
+nav = Navegador(".navegador/navegador.db")
48
+nav.ingest("./my-repo")
49
+bundle = nav.explain("AuthService")
50
+print(bundle.to_markdown())
51
+```
3952
4053
---
4154
4255
## What goes in the graph
4356
@@ -52,10 +65,11 @@
5265
| Knowledge | Decision | `navegador add decision` |
5366
| Knowledge | Person | `navegador add person` |
5467
| Knowledge | WikiPage | `navegador wiki ingest` |
5568
| Knowledge | (any) | `navegador planopticon ingest` |
5669
| Cross-layer | ANNOTATES, GOVERNS, IMPLEMENTS | `navegador annotate` |
70
+| Analysis | TESTS, COUPLED_WITH edges | `navegador testmap`, `navegador cycles` |
5771
5872
---
5973
6074
## Agent integration
6175
@@ -87,11 +101,11 @@
87101
}
88102
}
89103
}
90104
```
91105
92
- See [MCP Integration](guide/mcp-integration.md) for the full tool list and per-agent config snippets.
106
+ 11 tools available. See [MCP Integration](guide/mcp-integration.md) for the full tool list and per-agent config snippets. Use `--read-only` mode to restrict agents to query-only access.
93107
94108
=== "Bootstrap"
95109
96110
One command to install navegador, ingest a repo, and wire the agent hook for your preferred AI coding assistant.
97111
@@ -99,10 +113,53 @@
99113
./bootstrap.sh --repo owner/repo --wiki --agent claude
100114
```
101115
102116
Supports `--agent claude`, `--agent gemini`, and `--agent openai`. See [Agent Hooks](guide/agent-hooks.md) for what the hook does and how to configure it manually.
103117
118
+=== "Editor integration"
119
+
120
+ Wire navegador into your editor with one command:
121
+
122
+ ```bash
123
+ navegador editor setup claude-code
124
+ navegador editor setup cursor
125
+ navegador editor setup codex
126
+ navegador editor setup windsurf
127
+ ```
128
+
129
+=== "CI/CD"
130
+
131
+ Run navegador in CI pipelines for automated context checks:
132
+
133
+ ```bash
134
+ navegador ci ingest
135
+ navegador ci stats
136
+ navegador ci check
137
+ ```
138
+
139
+---
140
+
141
+## What's new in 0.7.0
142
+
143
+| Feature | Command / API |
144
+|---|---|
145
+| **13 languages** (added Kotlin, C#, PHP, Ruby, Swift, C, C++) | `pip install "navegador[languages]"` |
146
+| **Python SDK** | `from navegador import Navegador` |
147
+| **Incremental ingestion** | `navegador ingest --incremental`, `--watch` |
148
+| **Schema migrations** | `navegador migrate` |
149
+| **Export / import** | `navegador export`, `navegador import` (JSONL) |
150
+| **Editor integrations** | `navegador editor setup <editor>` |
151
+| **Analysis commands** | `navegador diff`, `navegador churn`, `navegador impact`, `navegador trace`, `navegador deadcode`, `navegador cycles`, `navegador testmap` |
152
+| **Multi-repo** | `navegador repo add/list/ingest-all/search` |
153
+| **Semantic search** | `navegador semantic-search`, `navegador ask` |
154
+| **Framework enrichment** | Django, FastAPI, React, Rails, Spring Boot, Laravel, and more |
155
+| **Monorepo support** | Turborepo, Nx, Yarn, pnpm, Cargo, Go workspaces |
156
+| **Cluster mode** | Shared Redis graph, pub/sub, task queue, sessions |
157
+| **11 MCP tools** (was 7) | `get_rationale`, `find_owners`, `search_knowledge`, `blast_radius` added |
158
+| **Sensitive content redaction** | `navegador ingest --redact` |
159
+| **Shell completions** | `navegador completions bash/zsh/fish` |
160
+
104161
---
105162
106163
## License
107164
108165
Navegador is open source under the [MIT License](https://github.com/ConflictHQ/navegador/blob/main/LICENSE). Copyright 2026 CONFLICT LLC.
109166
--- docs/index.md
+++ docs/index.md
@@ -3,10 +3,12 @@
3 **The project knowledge graph for AI coding agents.**
4
5 Navegador builds and maintains a queryable graph of your software project — combining static code analysis with human-curated business knowledge — so that AI coding agents always have precise, structured context instead of raw file dumps.
6
7 > *navegador* — Spanish for *navigator / sailor*. It helps agents navigate your code.
 
 
8
9 ---
10
11 ## Two layers, one graph
12
@@ -22,11 +24,11 @@
22 │ Variable · Import · Decorator · (call graphs, hierarchies) │
23 └─────────────────────────────────────────────────────────────────┘
24 stored in FalkorDB (SQLite local / Redis prod)
25 ```
26
27 The **code layer** is populated automatically by ingesting source trees. Python and TypeScript are supported out of the box via tree-sitter. The **knowledge layer** is populated by manual curation (`navegador add`), GitHub wiki ingestion, and [Planopticon](guide/planopticon.md) output (meeting and video knowledge graphs).
28
29 ---
30
31 ## Quick start
32
@@ -34,10 +36,21 @@
34 pip install navegador # Python 3.12+ required
35 navegador ingest ./my-repo # parse + index the codebase
36 navegador explain AuthService # what is this thing?
37 navegador search "rate limit" --all # search code + knowledge together
38 ```
 
 
 
 
 
 
 
 
 
 
 
39
40 ---
41
42 ## What goes in the graph
43
@@ -52,10 +65,11 @@
52 | Knowledge | Decision | `navegador add decision` |
53 | Knowledge | Person | `navegador add person` |
54 | Knowledge | WikiPage | `navegador wiki ingest` |
55 | Knowledge | (any) | `navegador planopticon ingest` |
56 | Cross-layer | ANNOTATES, GOVERNS, IMPLEMENTS | `navegador annotate` |
 
57
58 ---
59
60 ## Agent integration
61
@@ -87,11 +101,11 @@
87 }
88 }
89 }
90 ```
91
92 See [MCP Integration](guide/mcp-integration.md) for the full tool list and per-agent config snippets.
93
94 === "Bootstrap"
95
96 One command to install navegador, ingest a repo, and wire the agent hook for your preferred AI coding assistant.
97
@@ -99,10 +113,53 @@
99 ./bootstrap.sh --repo owner/repo --wiki --agent claude
100 ```
101
102 Supports `--agent claude`, `--agent gemini`, and `--agent openai`. See [Agent Hooks](guide/agent-hooks.md) for what the hook does and how to configure it manually.
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104 ---
105
106 ## License
107
108 Navegador is open source under the [MIT License](https://github.com/ConflictHQ/navegador/blob/main/LICENSE). Copyright 2026 CONFLICT LLC.
109
--- docs/index.md
+++ docs/index.md
@@ -3,10 +3,12 @@
3 **The project knowledge graph for AI coding agents.**
4
5 Navegador builds and maintains a queryable graph of your software project — combining static code analysis with human-curated business knowledge — so that AI coding agents always have precise, structured context instead of raw file dumps.
6
7 > *navegador* — Spanish for *navigator / sailor*. It helps agents navigate your code.
8 >
9 > **Current version: 0.7.0**
10
11 ---
12
13 ## Two layers, one graph
14
@@ -22,11 +24,11 @@
24 │ Variable · Import · Decorator · (call graphs, hierarchies) │
25 └─────────────────────────────────────────────────────────────────┘
26 stored in FalkorDB (SQLite local / Redis prod)
27 ```
28
29 The **code layer** is populated automatically by ingesting source trees. 13 languages are supported via tree-sitter (Python, TypeScript, JavaScript, Go, Rust, Java, Kotlin, C#, PHP, Ruby, Swift, C, C++). The **knowledge layer** is populated by manual curation (`navegador add`), GitHub wiki ingestion, and [Planopticon](guide/planopticon.md) output (meeting and video knowledge graphs).
30
31 ---
32
33 ## Quick start
34
@@ -34,10 +36,21 @@
36 pip install navegador # Python 3.12+ required
37 navegador ingest ./my-repo # parse + index the codebase
38 navegador explain AuthService # what is this thing?
39 navegador search "rate limit" --all # search code + knowledge together
40 ```
41
42 Or use the Python SDK:
43
44 ```python
45 from navegador import Navegador
46
47 nav = Navegador(".navegador/navegador.db")
48 nav.ingest("./my-repo")
49 bundle = nav.explain("AuthService")
50 print(bundle.to_markdown())
51 ```
52
53 ---
54
55 ## What goes in the graph
56
@@ -52,10 +65,11 @@
65 | Knowledge | Decision | `navegador add decision` |
66 | Knowledge | Person | `navegador add person` |
67 | Knowledge | WikiPage | `navegador wiki ingest` |
68 | Knowledge | (any) | `navegador planopticon ingest` |
69 | Cross-layer | ANNOTATES, GOVERNS, IMPLEMENTS | `navegador annotate` |
70 | Analysis | TESTS, COUPLED_WITH edges | `navegador testmap`, `navegador cycles` |
71
72 ---
73
74 ## Agent integration
75
@@ -87,11 +101,11 @@
101 }
102 }
103 }
104 ```
105
106 11 tools available. See [MCP Integration](guide/mcp-integration.md) for the full tool list and per-agent config snippets. Use `--read-only` mode to restrict agents to query-only access.
107
108 === "Bootstrap"
109
110 One command to install navegador, ingest a repo, and wire the agent hook for your preferred AI coding assistant.
111
@@ -99,10 +113,53 @@
113 ./bootstrap.sh --repo owner/repo --wiki --agent claude
114 ```
115
116 Supports `--agent claude`, `--agent gemini`, and `--agent openai`. See [Agent Hooks](guide/agent-hooks.md) for what the hook does and how to configure it manually.
117
118 === "Editor integration"
119
120 Wire navegador into your editor with one command:
121
122 ```bash
123 navegador editor setup claude-code
124 navegador editor setup cursor
125 navegador editor setup codex
126 navegador editor setup windsurf
127 ```
128
129 === "CI/CD"
130
131 Run navegador in CI pipelines for automated context checks:
132
133 ```bash
134 navegador ci ingest
135 navegador ci stats
136 navegador ci check
137 ```
138
139 ---
140
141 ## What's new in 0.7.0
142
143 | Feature | Command / API |
144 |---|---|
145 | **13 languages** (added Kotlin, C#, PHP, Ruby, Swift, C, C++) | `pip install "navegador[languages]"` |
146 | **Python SDK** | `from navegador import Navegador` |
147 | **Incremental ingestion** | `navegador ingest --incremental`, `--watch` |
148 | **Schema migrations** | `navegador migrate` |
149 | **Export / import** | `navegador export`, `navegador import` (JSONL) |
150 | **Editor integrations** | `navegador editor setup <editor>` |
151 | **Analysis commands** | `navegador diff`, `navegador churn`, `navegador impact`, `navegador trace`, `navegador deadcode`, `navegador cycles`, `navegador testmap` |
152 | **Multi-repo** | `navegador repo add/list/ingest-all/search` |
153 | **Semantic search** | `navegador semantic-search`, `navegador ask` |
154 | **Framework enrichment** | Django, FastAPI, React, Rails, Spring Boot, Laravel, and more |
155 | **Monorepo support** | Turborepo, Nx, Yarn, pnpm, Cargo, Go workspaces |
156 | **Cluster mode** | Shared Redis graph, pub/sub, task queue, sessions |
157 | **11 MCP tools** (was 7) | `get_rationale`, `find_owners`, `search_knowledge`, `blast_radius` added |
158 | **Sensitive content redaction** | `navegador ingest --redact` |
159 | **Shell completions** | `navegador completions bash/zsh/fish` |
160
161 ---
162
163 ## License
164
165 Navegador is open source under the [MIT License](https://github.com/ConflictHQ/navegador/blob/main/LICENSE). Copyright 2026 CONFLICT LLC.
166
+8
--- mkdocs.yml
+++ mkdocs.yml
@@ -79,19 +79,27 @@
7979
- Quick Start: getting-started/quickstart.md
8080
- Configuration: getting-started/configuration.md
8181
- Guide:
8282
- Ingesting a Repo: guide/ingestion.md
8383
- Loading Context: guide/context-loading.md
84
+ - Framework Enrichment: guide/framework-enrichment.md
85
+ - Structural Analysis: guide/analysis.md
86
+ - Intelligence Layer: guide/intelligence.md
87
+ - Python SDK: guide/sdk.md
8488
- Graph Queries: guide/graph-queries.md
8589
- MCP Integration: guide/mcp-integration.md
90
+ - CI/CD: guide/ci-cd.md
91
+ - Cluster Mode: guide/cluster.md
8692
- Agent Hooks: guide/agent-hooks.md
8793
- Planopticon: guide/planopticon.md
8894
- Architecture:
8995
- Overview: architecture/overview.md
9096
- Graph Schema: architecture/graph-schema.md
9197
- API Reference:
98
+ - Python SDK: api/sdk.md
9299
- Ingestion: api/ingestion.md
100
+ - Analysis: api/analysis.md
93101
- Graph: api/graph.md
94102
- MCP Server: api/mcp.md
95103
96104
extra:
97105
social:
98106
--- mkdocs.yml
+++ mkdocs.yml
@@ -79,19 +79,27 @@
79 - Quick Start: getting-started/quickstart.md
80 - Configuration: getting-started/configuration.md
81 - Guide:
82 - Ingesting a Repo: guide/ingestion.md
83 - Loading Context: guide/context-loading.md
 
 
 
 
84 - Graph Queries: guide/graph-queries.md
85 - MCP Integration: guide/mcp-integration.md
 
 
86 - Agent Hooks: guide/agent-hooks.md
87 - Planopticon: guide/planopticon.md
88 - Architecture:
89 - Overview: architecture/overview.md
90 - Graph Schema: architecture/graph-schema.md
91 - API Reference:
 
92 - Ingestion: api/ingestion.md
 
93 - Graph: api/graph.md
94 - MCP Server: api/mcp.md
95
96 extra:
97 social:
98
--- mkdocs.yml
+++ mkdocs.yml
@@ -79,19 +79,27 @@
79 - Quick Start: getting-started/quickstart.md
80 - Configuration: getting-started/configuration.md
81 - Guide:
82 - Ingesting a Repo: guide/ingestion.md
83 - Loading Context: guide/context-loading.md
84 - Framework Enrichment: guide/framework-enrichment.md
85 - Structural Analysis: guide/analysis.md
86 - Intelligence Layer: guide/intelligence.md
87 - Python SDK: guide/sdk.md
88 - Graph Queries: guide/graph-queries.md
89 - MCP Integration: guide/mcp-integration.md
90 - CI/CD: guide/ci-cd.md
91 - Cluster Mode: guide/cluster.md
92 - Agent Hooks: guide/agent-hooks.md
93 - Planopticon: guide/planopticon.md
94 - Architecture:
95 - Overview: architecture/overview.md
96 - Graph Schema: architecture/graph-schema.md
97 - API Reference:
98 - Python SDK: api/sdk.md
99 - Ingestion: api/ingestion.md
100 - Analysis: api/analysis.md
101 - Graph: api/graph.md
102 - MCP Server: api/mcp.md
103
104 extra:
105 social:
106

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button