codegraph-engine 2.1.2__py3-none-any.whl → 2.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. codegraph/__init__.py +1 -1
  2. codegraph/agent_brain.py +1961 -0
  3. codegraph/agent_capabilities.py +3500 -0
  4. codegraph/agent_rules.py +530 -0
  5. codegraph/architecture.py +48 -5
  6. codegraph/binding_resolver.py +616 -0
  7. codegraph/cli.py +345 -5
  8. codegraph/config.py +2 -0
  9. codegraph/context.py +845 -93
  10. codegraph/database/__init__.py +58 -0
  11. codegraph/database/extractor.py +2956 -0
  12. codegraph/database/interrogation.py +1085 -0
  13. codegraph/database/models.py +310 -0
  14. codegraph/epistemic.py +95 -0
  15. codegraph/errors.py +7 -0
  16. codegraph/evidence/citations.py +22 -1
  17. codegraph/evidence_contract.py +455 -0
  18. codegraph/frameworks.py +372 -11
  19. codegraph/git.py +92 -10
  20. codegraph/graph/models.py +15 -0
  21. codegraph/graph/traversal.py +680 -121
  22. codegraph/indexing/__init__.py +15 -1
  23. codegraph/indexing/classifier.py +343 -58
  24. codegraph/indexing/indexer.py +1515 -141
  25. codegraph/indexing/models.py +75 -0
  26. codegraph/indexing/parser.py +1843 -70
  27. codegraph/indexing/scanner.py +4 -1
  28. codegraph/indexing/telemetry.py +326 -0
  29. codegraph/installer.py +1652 -0
  30. codegraph/interrogation.py +708 -122
  31. codegraph/mcp/server.py +525 -107
  32. codegraph/mcp_diagnostics.py +879 -0
  33. codegraph/models.py +14 -0
  34. codegraph/monorepo.py +922 -0
  35. codegraph/observability.py +113 -2
  36. codegraph/optimizer.py +647 -42
  37. codegraph/ranking.py +61 -16
  38. codegraph/resolver.py +2006 -77
  39. codegraph/resources/monitor.py +1 -1
  40. codegraph/retrieval_policy.py +96 -17
  41. codegraph/route_composer.py +363 -0
  42. codegraph/runtime/__init__.py +32 -0
  43. codegraph/runtime/ingestor.py +672 -0
  44. codegraph/runtime/models.py +130 -0
  45. codegraph/runtime/reconciliation.py +492 -0
  46. codegraph/search/__init__.py +2 -0
  47. codegraph/search/hybrid.py +572 -53
  48. codegraph/security/__init__.py +50 -2
  49. codegraph/security/paths.py +162 -8
  50. codegraph/security/redaction.py +633 -0
  51. codegraph/semantic_decorators.py +341 -0
  52. codegraph/target_resolver.py +6 -6
  53. codegraph/tool_selection_eval.py +1158 -0
  54. codegraph_engine-2.1.7.dist-info/METADATA +617 -0
  55. codegraph_engine-2.1.7.dist-info/RECORD +84 -0
  56. {codegraph_engine-2.1.2.dist-info → codegraph_engine-2.1.7.dist-info}/licenses/LICENSE +1 -1
  57. codegraph_engine-2.1.2.dist-info/METADATA +0 -336
  58. codegraph_engine-2.1.2.dist-info/RECORD +0 -63
  59. {codegraph_engine-2.1.2.dist-info → codegraph_engine-2.1.7.dist-info}/WHEEL +0 -0
  60. {codegraph_engine-2.1.2.dist-info → codegraph_engine-2.1.7.dist-info}/entry_points.txt +0 -0
  61. {codegraph_engine-2.1.2.dist-info → codegraph_engine-2.1.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,530 @@
1
+ """Canonical Agent Rule Pack, Detailed Skill & Deep Agent Brain Writer.
2
+
3
+ Generates:
4
+ - Layer 1: Deterministic, compact (< 6,000 characters) always-on agent rules (`agent-rules/*.md`, `.agents/rules/codegraph.md`)
5
+ - Layer 1b: Compact capability summary (`agent-rules/tool-capabilities-summary.md`)
6
+ - Layer 2: Detailed operational skill playbook (`.agents/skills/codegraph/SKILL.md`)
7
+ - Layer 3: Deep implementation-derived reference (`docs/agent-brain.md`)
8
+
9
+ Supported agent targets:
10
+ - antigravity (.agents/rules/codegraph.md and agent-rules/antigravity.md)
11
+ - agents (agent-rules/AGENTS.md)
12
+ - gemini (agent-rules/GEMINI.md)
13
+ - claude (agent-rules/claude.md)
14
+ - cursor (agent-rules/cursor.md)
15
+ - codex (agent-rules/codex.md)
16
+ - cline (agent-rules/cline.md)
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import json
21
+ from pathlib import Path
22
+
23
+ SUPPORTED_AGENTS: tuple[str, ...] = (
24
+ "antigravity",
25
+ "agents",
26
+ "gemini",
27
+ "claude",
28
+ "cursor",
29
+ "codex",
30
+ "cline",
31
+ )
32
+
33
+ _AGENT_HEADERS: dict[str, str] = {
34
+ "antigravity": "# CodeGraph MCP Rules for Antigravity",
35
+ "agents": "# CodeGraph MCP Rules (AGENTS.md)",
36
+ "gemini": "# CodeGraph MCP Rules for Gemini (GEMINI.md)",
37
+ "claude": "# CodeGraph MCP Rules for Claude Code",
38
+ "cursor": "# CodeGraph MCP Rules for Cursor",
39
+ "codex": "# CodeGraph MCP Rules for Codex",
40
+ "cline": "# CodeGraph MCP Rules for Cline",
41
+ }
42
+
43
+ _CANONICAL_MENTAL_MODEL_SECTION = """\
44
+ ## CodeGraph Mental Model
45
+
46
+ - **Division of Labor**: The AI coding agent reasons, plans, and edits source code; CodeGraph interrogates the repository for AST-, framework-, and dataflow-verified facts.
47
+ - **Core Strength**: CodeGraph is preferred for relationship-heavy and multi-file repository questions (callers/callees, HTTP routes and router mounts, dependency injection, registries/dispatch, events/tasks/commands, test coverage, monorepo package boundaries, and change impact)."""
48
+
49
+ _CANONICAL_ALWAYS_ON_SECTION = """\
50
+ ## Always-On Principles
51
+
52
+ 1. **When to Use CodeGraph**: Use CodeGraph when repository relationships, multi-file reasoning, or literal text discovery make it materially useful—specifically for callers/callees, route-to-handler chains, dependency injection (`Depends`, providers, containers), task/command/event decorators, test coverage discovery, monorepo package boundaries, change-impact analysis, and literal text/template search (`search_code`).
53
+ 2. **When Direct File Reading Is Sufficient (`LOCAL_EDIT`)**: Bypass CodeGraph graph queries for trivial single-file edits (typos, formatting, docstrings, or local variable changes inside an already-identified function). Use `get_file(path, start_line, end_line)` or `read_file` directly.
54
+ 3. **Smallest-Sufficient-Tool Principle (`find_*`, `get_*`, `trace_*`)**: Pick the smallest tool that answers the question (`find_symbol`/`resolve_symbol` -> `find_callers`/`get_callers`, `find_routes`/`list_routes` -> `trace_path`, `search_code` -> `get_file`, or `get_context`). Stop as soon as verified evidence answers the question.
55
+ 4. **Preserve Semantic Distinctions**: Never invent relationships and never collapse `REGISTERS`, `DISPATCHES_TO`, `MOUNTS`, `INJECTS`, `PROVIDES`, or `RESOLVES_DEPENDENCY` into generic `CALLS`. `search_code` returns literal text hits only and never creates semantic graph edges.
56
+ 5. **Targeted Source Reads After Discovery (`get_file` / `read_file`)**: Once `search_code`, `find_symbol`, `find_routes`, or `get_context` identifies the target file and line range, call `get_file(path, start_line=..., end_line=..., max_lines=200)` (or `read_file`) to open only the needed lines.
57
+ 6. **Anti-Loop Discipline**: Never call `resolve_symbol` or `find_symbol` repeatedly for the same symbol or spam redundant CodeGraph tools once a `canonical_id` or `ContextPacket` is obtained."""
58
+
59
+ _CANONICAL_TASK_SECTION = """\
60
+ ## Task-Specific Tool Selection
61
+
62
+ | Developer Question / Task Type | Recommended CodeGraph Tool Sequence |
63
+ | :--- | :--- |
64
+ | **Single-file local edit** (`LOCAL_EDIT`) | Bypass graph tools -> `get_file(path, start_line, end_line)` or `read_file` directly |
65
+ | **Where is symbol X defined?** (`SYMBOL_LOOKUP`) | `find_symbol(symbol=...)` or `resolve_symbol(symbol=...)` (or `search_symbols` if partial) -> `get_symbol` |
66
+ | **Where is literal text / HTML / UI string / config key?** | `search_code(query=...)` -> `get_file(path=..., start_line=..., end_line=...)` |
67
+ | **Who calls X / What does X call?** (`RELATIONSHIP`) | `find_callers(symbol=...)` / `get_callers(symbol=...)` or `find_callees(symbol=...)` / `get_callees(symbol=...)` |
68
+ | **Where is X referenced / registered / dispatched?** (`RELATIONSHIP`) | `find_references(symbol=...)` or `get_references(symbol=...)` |
69
+ | **Which HTTP route reaches handler Y?** (`ROUTE_DISCOVERY` / `TRACE`) | `find_routes` / `list_routes` -> `resolve_symbol` -> `trace_path` |
70
+ | **How does this bug / DI chain work?** (`DEBUG`) | `resolve_symbol` -> `get_context(query=..., intent="DEBUG")` |
71
+ | **What tests cover symbol X?** (`TEST_DISCOVERY`) | `find_tests(symbol=...)` or `find_related_tests(symbol=...)` |
72
+ | **What breaks if X or git diff changes?** (`CHANGE_IMPACT`) | `get_git_impact` or `analyze_impact(symbol=...)` -> `find_tests` |
73
+ | **How are packages / modules structured?** (`ARCHITECTURE` / `PACKAGE`) | `get_architecture()` -> `get_context(query=..., intent="ARCHITECTURE")` |
74
+ | **Which database tables / columns / writers exist?** (`DATABASE`) | `find_db_tables` / `get_db_table` / `find_db_writers` / `get_db_impact` |
75
+ | **What happened at runtime vs static analysis?** (`RUNTIME`) | `get_runtime_trace` -> `reconcile_static_runtime` |
76
+ | **Where is feature Z implemented?** (`MULTI_FILE_INVESTIGATION`) | `search_symbols` / `search_code` -> `resolve_symbol` -> `get_context` |"""
77
+
78
+ _CANONICAL_EPISTEMIC_SECTION = """\
79
+ ## Epistemic & Fallback Rules (`UNKNOWN` / `POSSIBLE` / `AMBIGUOUS` / `RUNTIME_OBSERVED`)
80
+
81
+ - **Verified Evidence (`AST_VERIFIED`, `STATIC_VERIFIED`, `FRAMEWORK_VERIFIED`, `DATAFLOW_VERIFIED`)**: Rely on these relationships as proven static/framework/dataflow facts.
82
+ - **Runtime Evidence (`RUNTIME_OBSERVED` vs `RUNTIME_UNOBSERVED`)**: `RUNTIME_OBSERVED` records ingested trace edges; never convert it into static `AST_VERIFIED` proof, and never treat `NOT_OBSERVED_AT_RUNTIME` (`RUNTIME_UNOBSERVED`) as proof a path cannot execute.
83
+ - **How to Interpret `UNKNOWN`**: `UNKNOWN` means *static analysis could not establish the relationship* (e.g., dynamic `getattr`, `eval`, or runtime config). `UNKNOWN` **NEVER** means "there is no relationship." Inspect the cited call site with `get_file` or `read_file`.
84
+ - **How to Interpret `POSSIBLE`**: `POSSIBLE` indicates a plausible static candidate (such as conditional registration or interface implementation) that is not statically guaranteed. Verify the cited source lines with `get_file` or `read_file` before claiming as fact.
85
+ - **How to Handle `AMBIGUOUS`**: When `resolve_symbol` or `get_context` reports `AMBIGUOUS` with multiple candidates, inspect `alternatives` and disambiguate by module/package path—never pick `matches[0]` blindly.
86
+ - **Safe Fallback (`STALE` / `DISCONNECTED`)**: If CodeGraph MCP is disconnected, unavailable, or reports `freshness="STALE"`, fall back to targeted `get_file` / `read_file` / search and state the static limitation clearly."""
87
+
88
+
89
+ def render_agent_rules(agent: str = "antigravity") -> str:
90
+ """Render deterministic, compact (< 6,000 chars) agent rules for the specified agent."""
91
+ key = agent.strip().lower()
92
+ if key not in _AGENT_HEADERS:
93
+ raise ValueError(f"Unsupported agent '{agent}'. Supported: {', '.join(SUPPORTED_AGENTS)}")
94
+
95
+ header = _AGENT_HEADERS[key]
96
+ agent_note = (
97
+ f"Target environment: `{key}`. "
98
+ "CodeGraph MCP (`codegraph mcp serve`) provides deterministic, local-first repository intelligence."
99
+ )
100
+
101
+ content = "\n\n".join(
102
+ [
103
+ header,
104
+ agent_note,
105
+ _CANONICAL_MENTAL_MODEL_SECTION,
106
+ _CANONICAL_ALWAYS_ON_SECTION,
107
+ _CANONICAL_TASK_SECTION,
108
+ _CANONICAL_EPISTEMIC_SECTION,
109
+ ]
110
+ ).strip() + "\n"
111
+
112
+ return content
113
+
114
+
115
+ def render_antigravity_mcp_config() -> dict[str, object]:
116
+ """Return the canonical Antigravity MCP configuration example using `codegraph mcp serve`."""
117
+ return {
118
+ "mcpServers": {
119
+ "codegraph": {
120
+ "command": "codegraph",
121
+ "args": ["mcp", "serve"],
122
+ }
123
+ }
124
+ }
125
+
126
+
127
+ def render_antigravity_skill() -> str:
128
+ """Render `.agents/skills/codegraph/SKILL.md` (Layer 2 detailed operational playbook)."""
129
+ return """\
130
+ ---
131
+ name: codegraph
132
+ description: Deterministic repository relationship, route, dependency-injection, test-impact, package-boundary, literal text search, and bounded file inspection via CodeGraph MCP. Activate when a task involves multi-file code navigation, callers/callees, HTTP routes, DI providers, test discovery, change impact, or repository text/template discovery.
133
+ ---
134
+
135
+ # CodeGraph Agent Skill
136
+
137
+ CodeGraph is a deterministic, local-first repository intelligence engine exposed via MCP (`codegraph mcp serve`).
138
+ Core operating principle:
139
+
140
+ The AI Agent reasons.
141
+ CodeGraph interrogates the repository.
142
+
143
+ End-to-end agent workflow:
144
+
145
+ understand architecture (get_architecture / get_context)
146
+ ↓
147
+ find exact symbol or literal text (find_symbol / search_code / find_routes)
148
+ ↓
149
+ open targeted source lines (get_file)
150
+ ↓
151
+ reason with verified evidence (find_callers / find_callees / trace_path / find_tests)
152
+ ↓
153
+ edit the repository
154
+
155
+ ---
156
+
157
+ ## When to activate
158
+
159
+ Activate this skill whenever a developer task requires:
160
+ 1. **Symbol & Definition Lookup (`SYMBOL_LOOKUP`)**: Locating canonical definitions of classes, functions, methods, or interfaces across a repository (`find_symbol`, `resolve_symbol`, `get_symbol`).
161
+ 2. **Literal Text, UI, HTML/Jinja & Config Discovery (`search_code`)**: Locating button labels, HTML/Jinja template IDs, JS/TS snippets, CSS selectors, config keys, SQL fragments, or route strings across `.py`, `.html`, `.jinja`, `.js`, `.ts`, `.css`, `.yaml`, `.json`, and `.md` files.
162
+ 3. **Bounded Source File Inspection (`get_file`)**: Opening targeted line ranges (`start_line`, `end_line`, `max_lines`) or AST outlines of repository files without loading huge files into context.
163
+ 4. **Caller / Callee & Reference Interrogation (`RELATIONSHIP`)**: Answering "Who calls X?" (`find_callers` / `get_callers`), "What does X call?" (`find_callees` / `get_callees`), or "Where is X referenced, imported, or registered?" (`find_references` / `get_references`).
164
+ 5. **HTTP/RPC Route & Mount Composition (`ROUTE_DISCOVERY`)**: Locating FastAPI, Flask, Django, Express, or NestJS routes (`find_routes` / `list_routes`), especially when prefixes are composed via `MOUNTS` (`include_router`, `register_blueprint`, `app.use`).
165
+ 6. **Multi-Hop Execution Tracing (`TRACE`)**: Proving how an entrypoint, route, CLI command, or background task reaches a downstream service or database query (`trace_path`, `trace_flow`).
166
+ 7. **Dependency Injection & Configuration (`DEBUG` / DI)**: Tracing `INJECTS`, `PROVIDES`, `RESOLVES_DEPENDENCY`, `CONFIGURES`, and `DI_CYCLE` chains (`Depends(...)`, `Annotated[..., Depends(...)]`, container bindings).
167
+ 8. **Registries, Dispatch, Events, Tasks & Commands**: Inspecting `REGISTERS`, `REGISTERED_HANDLER`, `DISPATCHES_TO`, `EVENT_LISTENER`, `TASK_HANDLER`, and `COMMAND_HANDLER` edges.
168
+ 9. **Test Coverage Discovery (`TEST_DISCOVERY`)**: Finding tests statically linked to a symbol, route, provider, or event handler (`find_tests` / `find_related_tests` returning `TESTS_SYMBOL`, `TESTS_ROUTE`, `TESTS_PROVIDER`, `TESTS_EVENT_HANDLER`).
169
+ 10. **Blast Radius & Git Change Impact (`CHANGE_IMPACT`)**: Evaluating what callers, routes, workspace packages, and tests are impacted by modifying a symbol or commit range (`get_git_impact`, `analyze_impact`).
170
+ 11. **Monorepo & Workspace Boundaries (`PACKAGE` / `ARCHITECTURE`)**: Inspecting manifest-backed workspace packages (`DEPENDS_ON_PACKAGE`, `CROSS_PACKAGE_IMPORT`, `PACKAGE_IMPORTS`, `CONTAINS_PACKAGE`) and system entrypoints (`get_architecture`).
171
+ 12. **Multi-File Bug Investigation (`DEBUG` / `MULTI_FILE_INVESTIGATION`)**: Assembling a token-bounded, coverage-optimized `ContextPacket` via `get_context`.
172
+
173
+ ---
174
+
175
+ ## When NOT to activate
176
+
177
+ Do **NOT** call CodeGraph graph tools when:
178
+ 1. **Trivial Single-File Local Edits (`LOCAL_EDIT`)**: Fixing a typo, editing a docstring or comment, adjusting formatting/indentation, or renaming a purely local variable inside a single already-known file and function. Use `get_file(path, start_line, end_line)` or `read_file` and standard editing tools directly.
179
+ 2. **Canonical Evidence Is Already in Context**: If the current turn already resolved the symbol's `canonical_id`, callers, or `ContextPacket`, do not re-run the same CodeGraph tool.
180
+ 3. **Sensitive Credential Files**: Never use CodeGraph, `get_file`, or `read_file` to inspect `.env`, `.pem`, `id_rsa`, or secret files (blocked by security policy).
181
+
182
+ ---
183
+
184
+ ## STEP 1 — Classify task
185
+
186
+ Classify the developer request into one of the 13 canonical categories (`AgentTaskCategory`) or explicit routing keys (`ROUTING_MANIFEST`):
187
+ - `LOCAL_EDIT`
188
+ - `SYMBOL_LOOKUP` (`symbol_discovery` -> `find_symbol` / `resolve_symbol`)
189
+ - `RELATIONSHIP` (`caller_discovery` -> `find_callers`, `callee_discovery` -> `find_callees`, `reference_discovery` -> `find_references`)
190
+ - `TRACE` (`relationship_trace` -> `trace_path` / `trace_flow`)
191
+ - `DEBUG` (`context_synthesis` -> `get_context`)
192
+ - `CHANGE_IMPACT` (`change_impact` -> `get_git_impact`)
193
+ - `TEST_DISCOVERY` (`test_discovery` -> `find_tests`)
194
+ - `ROUTE_DISCOVERY` (`route_discovery` -> `find_routes`)
195
+ - `DIAGNOSTIC` (`get_repository_status`)
196
+ - `ARCHITECTURE` (`architecture_analysis` -> `get_architecture`)
197
+ - `PACKAGE` (`get_architecture` / `get_context`)
198
+ - `MULTI_FILE_INVESTIGATION` (`literal_search` -> `search_code`, `source_inspection` -> `get_file`, or `get_context`)
199
+ - `EXPLANATION` (`context_synthesis` -> `get_context`)
200
+
201
+ ---
202
+
203
+ ## STEP 2 — Decide whether repository relationships or text search matter
204
+
205
+ - If the task is `LOCAL_EDIT` on a single known file: **stop here and use `get_file(path, start_line, end_line)` or `read_file` directly**.
206
+ - If searching for literal UI text, HTML/Jinja button IDs, CSS selectors, or config keys: call `search_code(query="...")` then open the matched lines with `get_file(path=..., start_line=..., end_line=...)`.
207
+ - If the task involves symbol definitions across files, callers/callees, routes, DI, registries, events, tasks, tests, packages, or impact: proceed to Step 3.
208
+
209
+ ---
210
+
211
+ ## STEP 3 — Ground the target
212
+
213
+ Before querying relationships, ground bare names into canonical repository identities:
214
+ - **Known symbol name**: Call `find_symbol(symbol="<symbol>")` or `resolve_symbol(symbol="<symbol>")` to obtain `canonical_id`, `file`, `start_line`, `end_line`, and `ambiguity_state`.
215
+ - **Partial or uncertain symbol name**: Call `search_symbols(query="<keyword>", top_k=10)` to discover candidate symbols, then select or resolve the canonical target.
216
+ - **Literal text / HTML template / UI label**: Call `search_code(query="<literal>", top_k=10)` to find exact `path`, `line`, and `matched_text`.
217
+ - **HTTP route path**: Call `find_routes(method="...", path="...")` or `list_routes(method="...", path="...")` to resolve composed mount prefixes (`MOUNTS`) and identify the handler's `canonical_id`.
218
+ - **Rule**: Never call `resolve_symbol` more than once for the same symbol in a session.
219
+
220
+ ---
221
+
222
+ ## STEP 4 — Choose the smallest sufficient tool
223
+
224
+ Select the smallest targeted tool that answers the question without over-fetching (all symbol-oriented tools accept `symbol=...` as canonical input and `canonical_id=...` as an explicit alias):
225
+ - **Symbol definition lookup**: `find_symbol(symbol=...)` or `resolve_symbol(symbol=...)`
226
+ - **Literal text / HTML / template / config search**: `search_code(query=..., top_k=10)`
227
+ - **Bounded file opening & AST outline**: `get_file(path=..., start_line=..., end_line=..., max_lines=200)`
228
+ - **Definition signature & decorators**: `get_symbol(symbol=...)`
229
+ - **Direct callers**: `find_callers(symbol=...)` or `get_callers(symbol=...)`
230
+ - **Direct callees**: `find_callees(symbol=...)` or `get_callees(symbol=...)`
231
+ - **All references / registrations / DI bindings**: `find_references(symbol=...)` or `get_references(symbol=...)`
232
+ - **Path between two known symbols**: `trace_path(from_symbol=..., to_symbol=..., max_depth=5)`
233
+ - **Bidirectional call flow around one symbol**: `trace_flow(symbol=..., depth=2)`
234
+ - **Forward module imports**: `get_imports(file=...)`
235
+ - **Reverse module/symbol dependents**: `get_dependents(symbol=...)`
236
+ - **Related test functions**: `find_tests(symbol=...)` or `find_related_tests(symbol=...)`
237
+ - **HTTP/RPC routes**: `find_routes(method=..., path=...)` or `list_routes(method=..., path=...)`
238
+ - **Symbol modification blast radius**: `analyze_impact(symbol=..., max_depth=3)`
239
+ - **Git commit diff impact**: `get_git_impact(base="HEAD~1", head="HEAD")`
240
+ - **Architecture & workspace packages**: `get_architecture()`
241
+ - **Multi-file debugging / DI / comprehensive task context**: `get_context(query=..., intent="DEBUG" | "TRACE" | "UNDERSTAND" | "IMPACT" | "ARCHITECTURE", max_tokens=4000, max_files=15, max_lines=500)` (`task=...` is also supported as an alias)
242
+
243
+ ---
244
+
245
+ ## STEP 5 — Retrieve structured evidence
246
+
247
+ Invoke the selected tool with exact schema arguments. Inspect the structured payload fields:
248
+ - `canonical_id`, `qualified_name`, `file` / `path`, `start_line`, `end_line`
249
+ - `relationship` (e.g., `CALLS`, `HANDLED_BY`, `MOUNTS`, `INJECTS`, `PROVIDES`, `REGISTERS`, `DISPATCHES_TO`, `DEPENDS_ON_PACKAGE`, `TESTS_SYMBOL`)
250
+ - `evidence_class` (`AST_VERIFIED`, `FRAMEWORK_VERIFIED`, `DATAFLOW_VERIFIED`, `POSSIBLE`, `UNKNOWN`)
251
+ - `confidence` (`HIGH`, `MEDIUM`, `LOW`, `UNKNOWN`)
252
+ - `freshness` (`FRESH` vs `STALE`)
253
+
254
+ ---
255
+
256
+ ## STEP 6 — Interpret evidence
257
+
258
+ Respect CodeGraph's semantic and epistemic contract:
259
+ - **`AST_VERIFIED` / `FRAMEWORK_VERIFIED` / `DATAFLOW_VERIFIED`**: Proven static, framework, or conservative dataflow facts. Cite them directly with `file:start_line`.
260
+ - **Text Search != Semantic Graph**: `search_code` finds literal text matches across code, templates, and configs; it never proves semantic `CALLS`, `IMPORTS`, or `HANDLED_BY` edges.
261
+ - **`REGISTERS` != `CALLS`**: Registration into a dict or decorator registry proves `REGISTERS` / `REGISTERED_HANDLER`, not direct invocation. Invocation happens at `DISPATCHES_TO`.
262
+ - **DI != `CALLS`**: `INJECTS`, `PROVIDES`, and `RESOLVES_DEPENDENCY` express dependency injection wiring, not direct helper calls.
263
+ - **`MOUNTS` != `CALLS`**: Router prefix mounting is `MOUNTS`, connected to endpoints via `HANDLED_BY` / `ROUTE_HANDLER`.
264
+ - **Artifact Priority**: Prefer authored `SOURCE` and `TEST` files over `GENERATED`, `BUNDLE`, `MINIFIED`, or `VENDOR` artifacts.
265
+
266
+ ---
267
+
268
+ ## STEP 7 — Expand only when necessary
269
+
270
+ - If the first targeted tool (`find_callers`/`get_callers`, `find_routes`/`list_routes`, `find_tests`/`find_related_tests`, `trace_path`, `search_code`) already answers the developer's question with verified evidence, **STOP graph interrogation**.
271
+ - Expand with `get_context` or a follow-up relationship tool only if intermediate hops, DI providers, or package boundaries are still missing.
272
+
273
+ ---
274
+
275
+ ## STEP 8 — Targeted source read
276
+
277
+ CodeGraph tells you **WHERE** and **HOW** symbols or text relate; `get_file(path, start_line, end_line)` (or `read_file`) tells you **EXACTLY** what implementation statements exist.
278
+ - Call `get_file(path="<file>", start_line=<start>, end_line=<end>, max_lines=200)` on the exact line span returned by CodeGraph when:
279
+ - You are about to edit a Python, HTML, Jinja, JS, TS, CSS, or config file.
280
+ - You need to inspect conditional branch logic, HTML form fields, exception types, or literal values inside the file.
281
+ - An edge is marked `POSSIBLE` or `UNKNOWN` and requires call-site verification.
282
+
283
+ ---
284
+
285
+ ## STEP 9 — Validate uncertainty
286
+
287
+ Never hide or launder epistemic uncertainty:
288
+ 1. **`UNKNOWN` Workflow**:
289
+ - `UNKNOWN` means static analysis could not establish the target (e.g., `getattr(obj, dynamic_attr)()`, `eval`, runtime config).
290
+ - **Never** claim "no relationship exists" or "nothing calls X" from `UNKNOWN`.
291
+ - Perform a targeted `get_file` / `read_file` on the cited call site; if still runtime-dependent, report it as statically `UNKNOWN`.
292
+ 2. **`POSSIBLE` Workflow**:
293
+ - Treat `POSSIBLE` / `POSSIBLE_CALLS` as a static lead (e.g., conditional registration or interface candidate).
294
+ - Read the cited lines with `get_file` / `read_file` to confirm or reject before stating as fact.
295
+ 3. **`AMBIGUOUS` Workflow**:
296
+ - When `ambiguity_state == "AMBIGUOUS"`, inspect `alternatives`, compare `canonical_id`, owning package, and file path, and disambiguate using task context. Never blindly pick `alternatives[0]`.
297
+ 4. **`STALE` Index Workflow**:
298
+ - If `freshness == "STALE"`, one or more files in `modified_files` changed on disk since indexing. Verify modified files directly with `get_file` / `read_file` or run `codegraph index`.
299
+
300
+ ---
301
+
302
+ ## STEP 10 — Answer/edit
303
+
304
+ Synthesize the final answer or apply the code edit:
305
+ - Cite verified symbol names, relationship types, and `file:start_line` coordinates.
306
+ - Clearly distinguish verified facts (`AST_VERIFIED`, `FRAMEWORK_VERIFIED`, `DATAFLOW_VERIFIED`) from `POSSIBLE` leads or `UNKNOWN` dynamic boundaries.
307
+
308
+ ---
309
+
310
+ ## Tool selection matrix
311
+
312
+ | Task Category / Routing Intent | Primary Tool | Follow-Up Tool(s) | When to Use Targeted `get_file` / `read_file` |
313
+ | :--- | :--- | :--- | :--- |
314
+ | `LOCAL_EDIT` | `get_file` / `read_file` (Bypass Graph) | None | Immediately on the target file/lines |
315
+ | `SYMBOL_LOOKUP` (`symbol_discovery`) | `find_symbol` / `resolve_symbol` | `get_symbol` | Only if full implementation body beyond snippet is needed |
316
+ | `LITERAL_SEARCH` (`literal_search`) | `search_code` | `get_file(path, start_line, end_line)` | Immediately to inspect surrounding HTML/JS/Python lines |
317
+ | `RELATIONSHIP` (`caller_discovery`) | `find_callers` / `get_callers` | `get_file` | Only to inspect call-site argument expressions |
318
+ | `RELATIONSHIP` (`callee_discovery`) | `find_callees` / `get_callees` | `get_file` | Only to inspect branch conditions around calls |
319
+ | `RELATIONSHIP` (`reference_discovery`) | `find_references` / `get_references` | `get_file` | When checking conditional `REGISTERS` or `DISPATCHES_TO` sites |
320
+ | `ROUTE_DISCOVERY` (`route_discovery`) | `find_routes` / `list_routes` | `resolve_symbol` / `trace_path` | Only to inspect handler body statements |
321
+ | `TRACE` (`relationship_trace`) | `trace_path` / `trace_flow` | `get_context(intent="TRACE")` | When a hop is `POSSIBLE`/`UNKNOWN` or branch logic matters |
322
+ | `DEBUG` (`context_synthesis`) | `get_context(intent="DEBUG")` | `get_file` | On the exact fault or provider line span |
323
+ | `TEST_DISCOVERY` (`test_discovery`) | `find_tests` / `find_related_tests` | `get_file` | Only if test assertion details need inspection |
324
+ | `CHANGE_IMPACT` (`change_impact`) | `get_git_impact` / `analyze_impact` | `find_tests` | On direct callers that require signature updates |
325
+ | `PACKAGE` | `get_architecture` | `get_context(intent="ARCHITECTURE")` / `get_dependents` | Only if manifest version constraints need inspection |
326
+ | `ARCHITECTURE` (`architecture_analysis`) | `get_architecture` | `get_context(intent="ARCHITECTURE")` | Rarely needed for macro overview |
327
+ | `DATABASE` (`db_tables`, `db_writers`, `db_impact`) | `find_db_tables` / `get_db_table` | `find_db_writers` / `find_db_callers` / `get_db_impact` | On ORM model, SQL query, or migration file lines |
328
+ | `RUNTIME` (`runtime_trace`, `runtime_reconcile`) | `get_runtime_trace` / `reconcile_static_runtime` | `ingest_runtime_traces` / `get_file` | On `runtime_only_observed` or `static_runtime_conflicts` call sites |
329
+ | `DIAGNOSTIC` | `get_repository_status` | `get_resource_status` / `verify_evidence` | On `modified_files` if `freshness == "STALE"` |
330
+
331
+ ---
332
+
333
+ ## Evidence matrix
334
+
335
+ | Evidence Class | Meaning | Allowed Claim Strength | Required Agent Action |
336
+ | :--- | :--- | :--- | :--- |
337
+ | `AST_VERIFIED` | Directly proven by syntax tree (`DEFINES`, `CALLS`, `IMPORTS`, `EXTENDS`) | Verified Fact (`FACT`) | Cite directly; no extra verification required unless editing body. |
338
+ | `STATIC_VERIFIED` | Directly proven by static SQL DDL/DML or migration parsing (`CREATE TABLE`, `INSERT INTO`, `MIGRATES_TABLE`) | Verified Fact (`FACT`) | Cite with SQL/migration file and line coordinates. |
339
+ | `FRAMEWORK_VERIFIED` | Proven by deterministic framework rules (`HANDLED_BY`, `MOUNTS`, `INJECTS`, `PROVIDES`, `MAPS_TO_TABLE`, `TASK_HANDLER`, `EVENT_LISTENER`) | Verified Fact (`FACT`) | Cite with framework relationship type; never collapse into `CALLS`. |
340
+ | `DATAFLOW_VERIFIED` | Proven by conservative local/attribute/registry binding (`BINDS_TO`, `RESOLVES_DEPENDENCY`, `REGISTERS`, `DISPATCHES_TO`) | Verified Fact (`FACT`) | Cite with resolved target and binding location. |
341
+ | `RUNTIME_OBSERVED` | Observed in an ingested runtime trace (`observation_count`, `first_seen`, `last_seen`, `runtime_generation`) | Observed Runtime Fact | Cite as runtime observation; never promote into static `AST_VERIFIED` proof. |
342
+ | `RUNTIME_UNOBSERVED` | Static edge not observed in the ingested runtime trace sample (`NOT_OBSERVED_AT_RUNTIME`) | Unobserved in Sample | Never claim the path is dead code or impossible at runtime. |
343
+ | `POSSIBLE` | Plausible static candidate (`POSSIBLE_CALLS`, `POSSIBLE_TABLE`, conditional registration, multiple providers) | Candidate Lead (`POSSIBLE`) | Inspect cited lines via `get_file` / `read_file` before making a definitive claim. |
344
+ | `UNKNOWN` | Static analysis could not resolve target (`getattr`, `eval`, `UNKNOWN_TABLE`, dynamic dispatch) | Unresolved (`UNKNOWN`) | **Never** claim "no relationship exists"; read call site and report dynamic boundary. |
345
+ | `AMBIGUOUS` | Multiple candidate symbols or tables match the target name | Ambiguous (`AMBIGUOUS`) | Inspect `alternatives` and disambiguate by module/package/schema; never pick `alternatives[0]` blindly. |
346
+
347
+ ---
348
+
349
+ ## Relationship matrix
350
+
351
+ | Domain | Canonical Relationships | Key Rule |
352
+ | :--- | :--- | :--- |
353
+ | **Direct Calls** | `CALLS`, `CALLED_BY`, `POSSIBLE_CALLS` | `CALLS` is strictly `AST_VERIFIED`, `DATAFLOW_VERIFIED`, or `RUNTIME_OBSERVED`; uncertain static calls are `POSSIBLE_CALLS`. |
354
+ | **Routing & Mounts** | `MOUNTS`, `ROUTE_HANDLER`, `HANDLED_BY`, `ROUTES_TO` | Composes nested router prefixes (`include_router`, `app.use`); never collapsed into `CALLS`. |
355
+ | **Database & Persistence** | `MAPS_TO_TABLE`, `MAPS_TO_COLUMN`, `READS_TABLE`, `WRITES_TABLE`, `READS_COLUMN`, `WRITES_COLUMN`, `REFERENCES_TABLE`, `REFERENCES_COLUMN`, `FOREIGN_KEY_TO`, `HAS_PRIMARY_KEY`, `HAS_INDEX`, `HAS_UNIQUE_CONSTRAINT`, `HAS_CHECK_CONSTRAINT`, `MIGRATES_TABLE`, `QUERIES_DATABASE`, `ORM_RELATION`, `POSSIBLE_TABLE`, `UNKNOWN_TABLE`, `READS_ENV` | Preserves explicit database schema, ORM, query, and migration semantics; never collapsed into generic `DEPENDS_ON`. |
356
+ | **Registries & Dispatch** | `REGISTERS`, `REGISTERED_HANDLER`, `DISPATCHES_TO` | `REGISTERS` records registration; `DISPATCHES_TO` records dispatcher-to-handler routing. |
357
+ | **Events, Tasks & Commands** | `EVENT_LISTENER`, `TASK_HANDLER`, `COMMAND_HANDLER` | Captures decorator/bus subscriptions for events, Celery/Dramatiq tasks, and CLI commands. |
358
+ | **Dependency Injection** | `INJECTS`, `PROVIDES`, `RESOLVES_DEPENDENCY`, `CONFIGURES`, `DI_CYCLE` | Traces consumer -> `INJECTS` -> provider -> `PROVIDES` -> implementation. |
359
+ | **Packages & Monorepo** | `DEPENDS_ON_PACKAGE`, `PACKAGE_IMPORTS`, `CROSS_PACKAGE_IMPORT`, `CONTAINS_PACKAGE` | Requires manifest proof (`package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`); never folder names alone. |
360
+ | **Test Coverage** | `TESTS`, `TESTS_SYMBOL`, `TESTS_ROUTE`, `TESTS_PROVIDER`, `TESTS_EVENT_HANDLER` | Proven by static call, import, route client, or provider override; never lexical guessing. |
361
+ | **Structural & Binding** | `IMPORTS`, `EXPORTS`, `REEXPORTS`, `EXTENDS`, `IMPLEMENTS`, `DEFINES`, `CONTAINS`, `RESOLVES_TO`, `BINDS_TO`, `ALIASED_TO`, `REFERENCES`, `USES`, `DEPENDS_ON`, `UNRESOLVED_REFERENCE` | Structural AST containment, inheritance, exports, and conservative variable bindings. |
362
+
363
+ ---
364
+
365
+ ## Common workflows
366
+
367
+ 1. **Trace HTTP Route to Database**:
368
+ `find_routes(path="/api/v1/auth/login")` -> `find_symbol(symbol="login_endpoint")` -> `trace_path(from_symbol="login_endpoint", to_symbol="find_by_email")` -> `find_db_callers(table="users")` -> targeted `get_file` if branch details needed.
369
+ 2. **Add UI + Backend Feature (HTML Template -> Route -> Service -> Tests)**:
370
+ `get_architecture()` -> `search_code(query="Add Manual Entry")` -> `get_file(path="templates/dashboard.html", start_line=1, end_line=120)` -> `find_routes(path="/api/scan-bill")` -> `find_symbol(symbol="parse_bill")` -> `find_callers(symbol="parse_bill")` -> `find_tests(symbol="parse_bill")`.
371
+ 3. **Database Schema, Writers & Bidirectional Impact Audit**:
372
+ `find_db_tables()` -> `get_db_table(table="products")` -> `find_db_writers(table="products")` -> `get_db_impact(table="products", column="shop_id")`.
373
+ 4. **Runtime Trace Ingestion & Static-vs-Runtime Reconciliation**:
374
+ `ingest_runtime_traces(source_path="traces/otel.json")` -> `get_runtime_trace(route="/api/scan-bill")` -> `reconcile_static_runtime(route="/api/scan-bill")`.
375
+ 5. **Inspect Dependency Injection Chain**:
376
+ `resolve_symbol(symbol="get_current_user")` -> `get_context(query="DI chain for get_current_user", intent="DEBUG", max_tokens=4000)` -> inspect `INJECTS`, `PROVIDES`, `RESOLVES_DEPENDENCY`, and `DI_CYCLE`.
377
+ 6. **Investigate Registry / Plugin Dispatch**:
378
+ `resolve_symbol(symbol="command_registry")` -> `get_references(symbol="command_registry")` -> separate `REGISTERS` sites from `DISPATCHES_TO` sites.
379
+ 7. **Pre-Refactor Impact & Test Selection**:
380
+ `resolve_symbol(symbol="OrderRepository.save")` -> `analyze_impact(symbol="OrderRepository.save")` -> `find_tests(symbol="OrderRepository.save")` -> `get_file` on direct callers to update call sites.
381
+ 8. **Monorepo Package Dependency Audit**:
382
+ `get_architecture()` -> `get_context(query="package dependencies of @acme/orders", intent="ARCHITECTURE", max_tokens=4000)` -> inspect `DEPENDS_ON_PACKAGE` and `CROSS_PACKAGE_IMPORT`.
383
+
384
+ ---
385
+
386
+ ## Failure/fallback workflow
387
+
388
+ 1. **MCP Server Disconnected or Unavailable**:
389
+ - Fall back to workspace file search and targeted `read_file`. State clearly that static graph verification was unavailable.
390
+ 2. **Index Freshness is `STALE`**:
391
+ - Call `get_repository_status()` to see `modified_files`. Use `get_file` or `read_file` on any modified files before trusting cached graph edges, or run `codegraph index`.
392
+ 3. **Target Resolution Returns `not_found`**:
393
+ - Do not repeat `resolve_symbol` with the same string. Call `search_symbols(query="<stem>")`, `search_code(query="<literal>")`, or `find_routes()` to discover the actual identifier or file.
394
+ 4. **Path Trace Returns Empty at Default Depth**:
395
+ - Check if intermediate hops use DI (`INJECTS`/`PROVIDES`) or registry dispatch (`DISPATCHES_TO`) via `get_context(intent="TRACE")`, or inspect `unknowns` for dynamic dispatch boundaries.
396
+
397
+ ---
398
+
399
+ ## Stop conditions
400
+
401
+ Stop calling CodeGraph tools immediately when:
402
+ 1. **Verified Answer Obtained**: The requested symbol definition, caller list, route handler, database table/writer, test list, literal text match, or trace path has been returned with `AST_VERIFIED`, `STATIC_VERIFIED`, `FRAMEWORK_VERIFIED`, or `DATAFLOW_VERIFIED` evidence.
403
+ 2. **Single-File Local Scope Reached**: The remaining work is reading or editing specific lines inside an already-located file (`use get_file or read_file`).
404
+ 3. **Dynamic Boundary Confirmed**: CodeGraph reported `UNKNOWN` (e.g., dynamic `getattr`/`eval` or `UNKNOWN_TABLE`) and you have read the call site with `get_file` / `read_file` to confirm the runtime-dependent expression.
405
+ 4. **Maximum Sequence Bound**: Never exceed 3–4 CodeGraph tool calls for a single question without synthesizing findings.
406
+ """
407
+
408
+
409
+ def render_agent_rules_readme() -> str:
410
+ """Render `agent-rules/README.md` documenting rule pack usage and MCP profiles."""
411
+ return """\
412
+ # CodeGraph Agent Rule Pack
413
+
414
+ Deterministic, compact agent rules generated from `src/codegraph/agent_rules.py`.
415
+
416
+ ## Rule Files
417
+
418
+ | File | Target Agent / Environment |
419
+ | :--- | :--- |
420
+ | `AGENTS.md` | Universal `AGENTS.md` standard |
421
+ | `GEMINI.md` | Gemini CLI / Google AI agents |
422
+ | `antigravity.md` | Google Antigravity IDE & CLI (`.agents/rules/codegraph.md`) |
423
+ | `claude.md` | Claude Code (`CLAUDE.md`) |
424
+ | `cursor.md` | Cursor (`.cursorrules`) |
425
+ | `codex.md` | OpenAI Codex agents |
426
+ | `cline.md` | Cline (`.clinerules`) |
427
+ | `tool-capabilities-summary.md` | Compact task -> preferred tool -> follow-up -> evidence table |
428
+
429
+ ## MCP Server Configuration
430
+
431
+ ```json
432
+ {
433
+ "mcpServers": {
434
+ "codegraph": {
435
+ "command": "codegraph",
436
+ "args": ["mcp", "serve"]
437
+ }
438
+ }
439
+ }
440
+ ```
441
+
442
+ ## Recommended MCP Profiles
443
+
444
+ - **`agent`** (`--profile agent`): Focused 14-tool agent workflow (`find_symbol`, `search_code`, `find_references`, `find_callers`, `find_callees`, `find_tests`, `find_routes`, `get_symbol`, `get_file`, `get_context`, `get_architecture`, `get_git_impact`, `trace_path`, `trace_flow`).
445
+ - **`core`** (`--profile core`): Simple symbol lookup, relationship queries, and context-light sessions (13 core tools).
446
+ - **`graph`** (`--profile graph`): Tracing, change-impact, test discovery, and architecture sessions (17 tools).
447
+ - **`minimal`** (`--profile minimal`): Core interrogation + `get_context` and `read_file` (21 tools).
448
+ - **`developer`** (`--profile developer`): Full interactive development with git history and impact tools (34 tools).
449
+ - **`full`** (`--profile full`): All 56 MCP tools (including Database Intelligence and Runtime Reconciliation) for complete administration and diagnostics.
450
+ """
451
+
452
+
453
+ def write_agent_rule_pack(root_dir: Path) -> list[str]:
454
+ """Write all deterministic `agent-rules/` and `.agents/` files under `root_dir`.
455
+
456
+ Returns sorted list of the 11 canonical rule-pack relative POSIX paths.
457
+ """
458
+ written: list[str] = []
459
+
460
+ rules_dir = root_dir / "agent-rules"
461
+ rules_dir.mkdir(parents=True, exist_ok=True)
462
+
463
+ file_map = {
464
+ "README.md": render_agent_rules_readme(),
465
+ "AGENTS.md": render_agent_rules("agents"),
466
+ "GEMINI.md": render_agent_rules("gemini"),
467
+ "claude.md": render_agent_rules("claude"),
468
+ "cursor.md": render_agent_rules("cursor"),
469
+ "codex.md": render_agent_rules("codex"),
470
+ "cline.md": render_agent_rules("cline"),
471
+ "antigravity.md": render_agent_rules("antigravity"),
472
+ }
473
+
474
+ for fname, text in sorted(file_map.items()):
475
+ target = rules_dir / fname
476
+ target.write_text(text, encoding="utf-8")
477
+ written.append(target.relative_to(root_dir).as_posix())
478
+
479
+ # Antigravity .agents/ directory
480
+ agy_dir = root_dir / ".agents"
481
+ agy_rules_dir = agy_dir / "rules"
482
+ agy_skill_dir = agy_dir / "skills" / "codegraph"
483
+ agy_rules_dir.mkdir(parents=True, exist_ok=True)
484
+ agy_skill_dir.mkdir(parents=True, exist_ok=True)
485
+
486
+ mcp_cfg_path = agy_dir / "mcp_config.json.example"
487
+ mcp_cfg_path.write_text(
488
+ json.dumps(render_antigravity_mcp_config(), indent=2) + "\n",
489
+ encoding="utf-8",
490
+ )
491
+ written.append(mcp_cfg_path.relative_to(root_dir).as_posix())
492
+
493
+ agy_rule_path = agy_rules_dir / "codegraph.md"
494
+ agy_rule_path.write_text(render_agent_rules("antigravity"), encoding="utf-8")
495
+ written.append(agy_rule_path.relative_to(root_dir).as_posix())
496
+
497
+ agy_skill_path = agy_skill_dir / "SKILL.md"
498
+ agy_skill_path.write_text(render_antigravity_skill(), encoding="utf-8")
499
+ written.append(agy_skill_path.relative_to(root_dir).as_posix())
500
+
501
+ return sorted(written)
502
+
503
+
504
+ def write_agent_brain_artifacts(root_dir: Path) -> list[str]:
505
+ """Write all Layer 1, Layer 2, and Layer 3 Agent Brain artifacts to `root_dir`.
506
+
507
+ Includes:
508
+ - All 11 files from `write_agent_rule_pack(root_dir)`
509
+ - `agent-rules/tool-capabilities-summary.md`
510
+ - `docs/agent-brain.md`
511
+ """
512
+ from codegraph.agent_brain import (
513
+ render_deep_agent_brain,
514
+ render_tool_capabilities_summary,
515
+ )
516
+
517
+ written = list(write_agent_rule_pack(root_dir))
518
+
519
+ summary_path = root_dir / "agent-rules" / "tool-capabilities-summary.md"
520
+ summary_path.parent.mkdir(parents=True, exist_ok=True)
521
+ summary_path.write_text(render_tool_capabilities_summary(), encoding="utf-8")
522
+ written.append(summary_path.relative_to(root_dir).as_posix())
523
+
524
+ docs_dir = root_dir / "docs"
525
+ docs_dir.mkdir(parents=True, exist_ok=True)
526
+ brain_path = docs_dir / "agent-brain.md"
527
+ brain_path.write_text(render_deep_agent_brain(), encoding="utf-8")
528
+ written.append(brain_path.relative_to(root_dir).as_posix())
529
+
530
+ return sorted(written)
codegraph/architecture.py CHANGED
@@ -224,13 +224,28 @@ def get_architecture(
224
224
  # Frameworks
225
225
  frameworks = detect_frameworks(con, repository)
226
226
 
227
- # Top-level modules
227
+ from codegraph.monorepo import detect_workspace
228
+ workspace_info = detect_workspace(repository, con=con)
229
+
230
+ # Top-level modules (excluding build artifacts, vendors, and bundles, enriched with package boundaries)
228
231
  modules: list[str] = []
229
232
  try:
230
233
  mod_rows = con.execute(
231
- "SELECT DISTINCT module FROM symbols WHERE module != '' ORDER BY module LIMIT 20"
234
+ """
235
+ SELECT DISTINCT s.module
236
+ FROM symbols s
237
+ LEFT JOIN files f ON s.path = f.path
238
+ WHERE s.module != ''
239
+ AND (f.category IS NULL OR f.category NOT IN ('BUILD_ARTIFACT', 'VENDOR', 'BUNDLE', 'MINIFIED'))
240
+ ORDER BY s.module LIMIT 20
241
+ """
232
242
  ).fetchall()
233
243
  modules = [r[0] for r in mod_rows]
244
+ if workspace_info.packages:
245
+ for p in workspace_info.packages.values():
246
+ if p.root_path and p.root_path not in modules:
247
+ modules.append(p.root_path)
248
+ modules = sorted(modules)[:max_per_category]
234
249
  except sqlite3.OperationalError:
235
250
  pass
236
251
 
@@ -244,11 +259,31 @@ def get_architecture(
244
259
  except sqlite3.OperationalError:
245
260
  pass
246
261
 
247
- # Generated artifacts
262
+ # Artifact directory separation
263
+ import posixpath
264
+ source_dirs: set[str] = set()
265
+ test_dirs: set[str] = set()
266
+ build_dirs: set[str] = set()
267
+ vendor_dirs: set[str] = set()
268
+ generated_dirs: set[str] = set()
248
269
  generated_files: list[str] = []
270
+
249
271
  try:
250
- gen_rows = con.execute("SELECT path FROM files WHERE category='GENERATED' ORDER BY path LIMIT 20").fetchall()
251
- generated_files = [r[0] for r in gen_rows]
272
+ file_rows = con.execute("SELECT path, category FROM files WHERE status='ok'").fetchall()
273
+ for fr in file_rows:
274
+ p_dir = posixpath.dirname(fr["path"]) or "."
275
+ cat = str(fr["category"])
276
+ if cat in ("SOURCE", ""):
277
+ source_dirs.add(p_dir)
278
+ elif cat == "TEST":
279
+ test_dirs.add(p_dir)
280
+ elif cat in ("BUILD_ARTIFACT", "BUNDLE", "MINIFIED"):
281
+ build_dirs.add(p_dir)
282
+ elif cat == "VENDOR":
283
+ vendor_dirs.add(p_dir)
284
+ elif cat == "GENERATED":
285
+ generated_dirs.add(p_dir)
286
+ generated_files.append(fr["path"])
252
287
  except sqlite3.OperationalError:
253
288
  pass
254
289
 
@@ -299,6 +334,9 @@ def get_architecture(
299
334
  },
300
335
  "languages": lang_counts,
301
336
  "frameworks": frameworks,
337
+ "workspace": workspace_info.as_dict(),
338
+ "packages": [p.as_dict() for p in workspace_info.packages.values()],
339
+ "package_dependencies": [d.as_dict() for d in workspace_info.dependencies],
302
340
  "entry_points": entry_points[:max_per_category],
303
341
  "top_level_modules": modules,
304
342
  "dependency_summary": dependencies,
@@ -306,6 +344,11 @@ def get_architecture(
306
344
  "test_summary": test_summary,
307
345
  "data_model_summary": data_model_summary,
308
346
  "external_services": sorted(set(integrations))[:max_per_category],
347
+ "source_directories": sorted(source_dirs)[:max_per_category],
348
+ "test_directories": sorted(test_dirs)[:max_per_category],
349
+ "build_directories": sorted(build_dirs)[:max_per_category],
350
+ "vendor_directories": sorted(vendor_dirs)[:max_per_category],
351
+ "generated_directories": sorted(generated_dirs)[:max_per_category],
309
352
  "generated_artifact_summary": {
310
353
  "count": len(generated_files),
311
354
  "files": generated_files,