Navegador

navegador / docs / guide / framework-enrichment.md
Source Blame History 185 lines
89816aa… lmata 1 # Framework Enrichment
89816aa… lmata 2
89816aa… lmata 3 ## What enrichment does
89816aa… lmata 4
89816aa… lmata 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.
89816aa… lmata 6
89816aa… lmata 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.
89816aa… lmata 8
89816aa… lmata 9 This lets you ask questions that wouldn't be possible from structure alone:
89816aa… lmata 10
89816aa… lmata 11 ```bash
89816aa… lmata 12 # without enrichment: grep for "def test_"
89816aa… lmata 13 # with enrichment: query the graph by semantic type
89816aa… lmata 14 navegador query "MATCH (t:Test) RETURN t.name, t.file ORDER BY t.file"
89816aa… lmata 15
89816aa… lmata 16 # find all API routes
89816aa… lmata 17 navegador query "MATCH (r:Route) RETURN r.method, r.path, r.handler ORDER BY r.path"
89816aa… lmata 18 ```
89816aa… lmata 19
89816aa… lmata 20 ---
89816aa… lmata 21
89816aa… lmata 22 ## How it works
89816aa… lmata 23
89816aa… lmata 24 Enrichment runs as a post-ingest pass. It reads existing nodes and edges, applies framework-specific pattern matching (decorator names, base class names, naming conventions), and:
89816aa… lmata 25
89816aa… lmata 26 1. Adds semantic labels to matched nodes (e.g., adds `View` label to Django view functions)
89816aa… lmata 27 2. Creates typed edges where the framework implies relationships (e.g., `HANDLES` from a `Route` to its handler function)
89816aa… lmata 28 3. Extracts framework-specific properties (e.g., HTTP method and URL pattern from route decorators)
89816aa… lmata 29
89816aa… lmata 30 Enrichment is **non-destructive** — it never removes or modifies existing nodes, only adds labels and edges.
89816aa… lmata 31
89816aa… lmata 32 ---
89816aa… lmata 33
89816aa… lmata 34 ## Supported frameworks
89816aa… lmata 35
89816aa… lmata 36 | Framework | Language | Detected patterns | Semantic types added |
89816aa… lmata 37 |---|---|---|---|
89816aa… lmata 38 | Django | Python | `View` subclasses, `urlpatterns`, `@login_required` | `View`, `Route`, `Model`, `Form`, `Middleware` |
89816aa… lmata 39 | Flask | Python | `@app.route`, `@blueprint.route`, `MethodView` | `Route`, `View`, `Blueprint` |
89816aa… lmata 40 | FastAPI | Python | `@router.get/post/put/delete/patch`, `APIRouter` | `Route`, `Schema`, `Dependency` |
89816aa… lmata 41 | pytest | Python | `def test_*`, `@pytest.mark.*`, `conftest.py` | `Test`, `Fixture`, `TestSuite` |
89816aa… lmata 42 | SQLAlchemy | Python | `Base` subclasses, `Column`, `relationship()` | `Model`, `Column`, `Relation` |
89816aa… lmata 43 | Next.js | TypeScript | `pages/`, `app/`, `getServerSideProps` | `Page`, `Route`, `ServerComponent` |
89816aa… lmata 44 | Express | JavaScript | `app.get/post/put/delete`, `Router` | `Route`, `Middleware` |
89816aa… lmata 45 | NestJS | TypeScript | `@Controller`, `@Injectable`, `@Module` | `Controller`, `Service`, `Module` |
dcf17e9… lmata 46 | **Terraform** | HCL | `main.tf`, `variables.tf`, `outputs.tf` | Cross-file module resolution, provider grouping |
dcf17e9… lmata 47 | **Chef** | Ruby | `metadata.rb`, `Berksfile` | `chef_recipe`, `chef_resource`, `chef_cookbook`, `chef_include` |
89816aa… lmata 48
89816aa… lmata 49 !!! note
89816aa… lmata 50 Framework detection is automatic when `--framework auto` is used (the default). Navegador inspects imports and decorator patterns to identify which frameworks are present.
89816aa… lmata 51
89816aa… lmata 52 ---
89816aa… lmata 53
89816aa… lmata 54 ## Usage
89816aa… lmata 55
89816aa… lmata 56 ### Auto-detect and enrich all frameworks
89816aa… lmata 57
89816aa… lmata 58 ```bash
89816aa… lmata 59 navegador enrich ./src
89816aa… lmata 60 ```
89816aa… lmata 61
89816aa… lmata 62 This runs after ingestion and enriches everything it can detect automatically.
89816aa… lmata 63
89816aa… lmata 64 ### Enrich immediately after ingestion
89816aa… lmata 65
89816aa… lmata 66 ```bash
89816aa… lmata 67 navegador ingest ./src && navegador enrich ./src
89816aa… lmata 68 ```
89816aa… lmata 69
89816aa… lmata 70 Or use the `--enrich` flag on ingest:
89816aa… lmata 71
89816aa… lmata 72 ```bash
89816aa… lmata 73 navegador ingest ./src --enrich
89816aa… lmata 74 ```
89816aa… lmata 75
89816aa… lmata 76 ### Target a specific framework
89816aa… lmata 77
89816aa… lmata 78 ```bash
89816aa… lmata 79 navegador enrich ./src --framework django
89816aa… lmata 80 navegador enrich ./src --framework fastapi
89816aa… lmata 81 navegador enrich ./src --framework pytest
89816aa… lmata 82 ```
89816aa… lmata 83
dcf17e9… lmata 84 Valid values: `django`, `flask`, `fastapi`, `pytest`, `sqlalchemy`, `nextjs`, `express`, `nestjs`, `terraform`, `chef`, `auto` (default).
89816aa… lmata 85
89816aa… lmata 86 ### JSON output
89816aa… lmata 87
89816aa… lmata 88 ```bash
89816aa… lmata 89 navegador enrich ./src --json
89816aa… lmata 90 ```
89816aa… lmata 91
89816aa… lmata 92 Returns a summary of labels and edges added per framework.
89816aa… lmata 93
89816aa… lmata 94 ---
89816aa… lmata 95
89816aa… lmata 96 ## Querying enriched nodes
89816aa… lmata 97
89816aa… lmata 98 Once enriched, the semantic types are queryable via Cypher:
89816aa… lmata 99
89816aa… lmata 100 ```bash
89816aa… lmata 101 # all FastAPI routes with their HTTP methods
89816aa… lmata 102 navegador query "MATCH (r:Route) RETURN r.method, r.path, r.handler ORDER BY r.path"
89816aa… lmata 103
89816aa… lmata 104 # all SQLAlchemy models and their columns
89816aa… lmata 105 navegador query "MATCH (m:Model)-[:HAS_COLUMN]->(c:Column) RETURN m.name, c.name, c.type ORDER BY m.name"
89816aa… lmata 106
89816aa… lmata 107 # all pytest tests that reference a specific function
89816aa… lmata 108 navegador query "MATCH (t:Test)-[:CALLS]->(f:Function {name: 'process_payment'}) RETURN t.name, t.file"
89816aa… lmata 109
89816aa… lmata 110 # all Django views governed by a rule
89816aa… lmata 111 navegador query "MATCH (r:Rule)-[:GOVERNS]->(v:View) RETURN r.name, v.name, v.file"
89816aa… lmata 112 ```
89816aa… lmata 113
89816aa… lmata 114 ---
89816aa… lmata 115
89816aa… lmata 116 ## Adding custom enrichers
89816aa… lmata 117
89816aa… lmata 118 Enrichers are subclasses of `FrameworkEnricher`. Create one to add support for an internal framework or library.
89816aa… lmata 119
89816aa… lmata 120 ### 1. Create the enricher
89816aa… lmata 121
89816aa… lmata 122 ```python
89816aa… lmata 123 # myproject/enrichers/celery.py
89816aa… lmata 124 from navegador.enrichment.base import FrameworkEnricher, EnrichmentResult
89816aa… lmata 125 from navegador.graph import GraphStore
89816aa… lmata 126
89816aa… lmata 127 class CeleryEnricher(FrameworkEnricher):
89816aa… lmata 128 name = "celery"
89816aa… lmata 129
89816aa… lmata 130 def detect(self, store: GraphStore) -> bool:
89816aa… lmata 131 """Return True if this framework is present in the graph."""
89816aa… lmata 132 results = store.query(
89816aa… lmata 133 "MATCH (i:Import {name: 'celery'}) RETURN count(i) AS n"
89816aa… lmata 134 )
89816aa… lmata 135 return results[0]["n"] > 0
89816aa… lmata 136
89816aa… lmata 137 def enrich(self, store: GraphStore) -> EnrichmentResult:
89816aa… lmata 138 """Add semantic labels and edges for Celery tasks."""
89816aa… lmata 139 # Find functions decorated with @shared_task or @app.task
89816aa… lmata 140 tasks = store.query(
89816aa… lmata 141 "MATCH (d:Decorator)-[:DECORATES]->(f:Function) "
89816aa… lmata 142 "WHERE d.name IN ['shared_task', 'task'] "
89816aa… lmata 143 "RETURN f.id, f.name"
89816aa… lmata 144 )
89816aa… lmata 145 labels_added = 0
89816aa… lmata 146 for row in tasks:
89816aa… lmata 147 store.query(
89816aa… lmata 148 "MATCH (f:Function) WHERE id(f) = $id "
89816aa… lmata 149 "SET f:Task",
89816aa… lmata 150 params={"id": row["f.id"]}
89816aa… lmata 151 )
89816aa… lmata 152 labels_added += 1
89816aa… lmata 153
89816aa… lmata 154 return EnrichmentResult(labels_added=labels_added, edges_added=0)
89816aa… lmata 155 ```
89816aa… lmata 156
89816aa… lmata 157 ### 2. Register the enricher
89816aa… lmata 158
89816aa… lmata 159 ```python
89816aa… lmata 160 # myproject/enrichers/__init__.py
89816aa… lmata 161 from navegador.enrichment.registry import register_enricher
89816aa… lmata 162 from .celery import CeleryEnricher
89816aa… lmata 163
89816aa… lmata 164 register_enricher(CeleryEnricher())
89816aa… lmata 165 ```
89816aa… lmata 166
89816aa… lmata 167 ### 3. Load at startup
89816aa… lmata 168
89816aa… lmata 169 Import the registration module before running enrichment. In a CLI wrapper or agent hook:
89816aa… lmata 170
89816aa… lmata 171 ```python
89816aa… lmata 172 import myproject.enrichers # registers the enricher
89816aa… lmata 173 from navegador.enrichment import run_enrichment
89816aa… lmata 174 from navegador.graph import GraphStore
89816aa… lmata 175
89816aa… lmata 176 store = GraphStore.sqlite(".navegador/navegador.db")
89816aa… lmata 177 result = run_enrichment(store, framework="celery")
89816aa… lmata 178 print(f"Added {result.labels_added} labels")
89816aa… lmata 179 ```
89816aa… lmata 180
89816aa… lmata 181 Or pass the module path to the CLI via `NAVEGADOR_ENRICHERS`:
89816aa… lmata 182
89816aa… lmata 183 ```bash
89816aa… lmata 184 NAVEGADOR_ENRICHERS=myproject.enrichers navegador enrich ./src --framework celery
89816aa… lmata 185 ```

Keyboard Shortcuts

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