codedebrief 0.11.0__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 (48) hide show
  1. codedebrief/__init__.py +12 -0
  2. codedebrief/analysis/__init__.py +16 -0
  3. codedebrief/analysis/common.py +527 -0
  4. codedebrief/analysis/discovery.py +100 -0
  5. codedebrief/analysis/languages/__init__.py +6 -0
  6. codedebrief/analysis/languages/_common.py +68 -0
  7. codedebrief/analysis/languages/c.py +96 -0
  8. codedebrief/analysis/languages/cpp.py +146 -0
  9. codedebrief/analysis/languages/csharp.py +137 -0
  10. codedebrief/analysis/languages/go.py +157 -0
  11. codedebrief/analysis/languages/java.py +158 -0
  12. codedebrief/analysis/languages/php.py +83 -0
  13. codedebrief/analysis/languages/ruby.py +75 -0
  14. codedebrief/analysis/languages/rust.py +96 -0
  15. codedebrief/analysis/project.py +373 -0
  16. codedebrief/analysis/python.py +939 -0
  17. codedebrief/analysis/registry.py +320 -0
  18. codedebrief/analysis/treesitter.py +884 -0
  19. codedebrief/analysis/typescript.py +1019 -0
  20. codedebrief/artifacts.py +49 -0
  21. codedebrief/cli.py +585 -0
  22. codedebrief/config.py +226 -0
  23. codedebrief/doctor.py +175 -0
  24. codedebrief/install.py +441 -0
  25. codedebrief/mcp_server.py +2720 -0
  26. codedebrief/model.py +189 -0
  27. codedebrief/py.typed +1 -0
  28. codedebrief/quality.py +392 -0
  29. codedebrief/query.py +641 -0
  30. codedebrief/render/__init__.py +6 -0
  31. codedebrief/render/assets/generated/codedebrief-viewer-runtime.iife.js +10 -0
  32. codedebrief/render/assets/panels.js +462 -0
  33. codedebrief/render/assets/shell.js +1649 -0
  34. codedebrief/render/assets/styles.css +1715 -0
  35. codedebrief/render/assets/tree.js +616 -0
  36. codedebrief/render/html.py +191 -0
  37. codedebrief/render/markdown.py +153 -0
  38. codedebrief/render/payload.py +326 -0
  39. codedebrief/render/snapshot.py +769 -0
  40. codedebrief/schema/codedebrief.schema.json +449 -0
  41. codedebrief/util.py +65 -0
  42. codedebrief/validation.py +214 -0
  43. codedebrief-0.11.0.dist-info/METADATA +426 -0
  44. codedebrief-0.11.0.dist-info/RECORD +48 -0
  45. codedebrief-0.11.0.dist-info/WHEEL +4 -0
  46. codedebrief-0.11.0.dist-info/entry_points.txt +2 -0
  47. codedebrief-0.11.0.dist-info/licenses/LICENSE +176 -0
  48. codedebrief-0.11.0.dist-info/licenses/NOTICE +9 -0
@@ -0,0 +1,214 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from dataclasses import dataclass, field
5
+ from importlib import resources
6
+ from pathlib import Path
7
+ from typing import Any, cast
8
+
9
+ from codedebrief.analysis import ProjectAnalyzer
10
+ from codedebrief.analysis.registry import supported_language_ids
11
+ from codedebrief.artifacts import output_paths
12
+ from codedebrief.config import CodeDebriefConfig
13
+ from codedebrief.model import ProjectModel
14
+ from codedebrief.quality import model_quality
15
+ from codedebrief.util import read_json
16
+
17
+
18
+ @dataclass(slots=True)
19
+ class ValidationReport:
20
+ ok: bool = True
21
+ errors: list[str] = field(default_factory=list)
22
+ warnings: list[str] = field(default_factory=list)
23
+ artifact: str = ""
24
+ quality: dict[str, Any] | None = None
25
+
26
+ def add_error(self, message: str) -> None:
27
+ self.ok = False
28
+ self.errors.append(message)
29
+
30
+ def to_dict(self) -> dict[str, Any]:
31
+ payload = {
32
+ "ok": self.ok,
33
+ "artifact": self.artifact,
34
+ "errors": self.errors,
35
+ "warnings": self.warnings,
36
+ }
37
+ if self.quality is not None:
38
+ payload["quality"] = self.quality
39
+ return payload
40
+
41
+
42
+ def validate_codedebrief(
43
+ root: Path,
44
+ *,
45
+ config: CodeDebriefConfig | None = None,
46
+ check_sync: bool = False,
47
+ include_quality: bool = False,
48
+ quality_thresholds: dict[str, float | int] | None = None,
49
+ ) -> ValidationReport:
50
+ """Validate the persisted CodeDebrief artifact and optional source sync.
51
+
52
+ The baseline validation is read-only: it loads the JSON model, checks it against the
53
+ bundled JSON Schema when `jsonschema` is installed, and verifies that every language in
54
+ the artifact is registered by the current analyzer. `check_sync` intentionally runs the
55
+ analyzer to compare the current source tree against the committed model.
56
+ """
57
+ active_config = config or CodeDebriefConfig.load(root)
58
+ json_path, _, _ = output_paths(root, active_config)
59
+ report = ValidationReport(artifact=str(json_path))
60
+
61
+ try:
62
+ artifact = read_json(json_path)
63
+ except OSError as error:
64
+ report.add_error(f"Could not read {json_path}: {error}")
65
+ return report
66
+ except ValueError as error:
67
+ report.add_error(f"Malformed JSON in {json_path}: {error}")
68
+ return report
69
+
70
+ try:
71
+ model = ProjectModel.from_dict(artifact)
72
+ except ValueError as error:
73
+ report.add_error(str(error))
74
+ return report
75
+
76
+ _validate_languages(model, report)
77
+ _validate_json_schema(artifact, report)
78
+ active_thresholds = quality_thresholds or {}
79
+ if include_quality or active_thresholds:
80
+ report.quality = model.metadata.get("quality") or model_quality(model)
81
+ if active_thresholds and report.quality is not None:
82
+ _validate_quality_thresholds(report, report.quality, active_thresholds)
83
+
84
+ if check_sync:
85
+ try:
86
+ fresh = ProjectAnalyzer(root, active_config).analyze(full=True).model
87
+ except (OSError, ValueError, SyntaxError) as error:
88
+ report.add_error(f"Could not re-analyze sources for sync check: {error}")
89
+ else:
90
+ if _without_generated_at(fresh.to_dict()) != _without_generated_at(model.to_dict()):
91
+ report.add_error(
92
+ "codedebrief.json is stale; run `codedebrief update` and commit the artifacts."
93
+ )
94
+
95
+ return report
96
+
97
+
98
+ def schema_language_ids(schema: dict[str, Any]) -> tuple[str, ...]:
99
+ return _schema_language_ids(schema, "flow")
100
+
101
+
102
+ def schema_file_language_ids(schema: dict[str, Any]) -> tuple[str, ...]:
103
+ return _schema_language_ids(schema, "file")
104
+
105
+
106
+ def _schema_language_ids(schema: dict[str, Any], definition: str) -> tuple[str, ...]:
107
+ flow_language = (
108
+ schema.get("$defs", {})
109
+ .get(definition, {})
110
+ .get("properties", {})
111
+ .get("language", {})
112
+ .get("enum", [])
113
+ )
114
+ return tuple(str(item) for item in flow_language)
115
+
116
+
117
+ def _validate_languages(model: ProjectModel, report: ValidationReport) -> None:
118
+ supported = set(supported_language_ids())
119
+ found = {flow.language for flow in model.flows} | {record.language for record in model.files}
120
+ unknown = sorted(found - supported)
121
+ if unknown:
122
+ report.add_error("Artifact uses unregistered language ids: " + ", ".join(unknown))
123
+
124
+
125
+ def _validate_json_schema(artifact: dict[str, Any], report: ValidationReport) -> None:
126
+ try:
127
+ schema = _read_bundled_schema()
128
+ except (OSError, ValueError) as error:
129
+ report.add_error(f"Could not read bundled schema: {error}")
130
+ return
131
+
132
+ schema_languages = set(schema_language_ids(schema))
133
+ schema_file_languages = set(schema_file_language_ids(schema))
134
+ supported = set(supported_language_ids())
135
+ if schema_languages != supported or schema_file_languages != supported:
136
+ report.add_error(
137
+ "Schema language enums are out of sync with registry: "
138
+ f"flow={sorted(schema_languages)} file={sorted(schema_file_languages)} "
139
+ f"registry={sorted(supported)}"
140
+ )
141
+
142
+ try:
143
+ from jsonschema import Draft202012Validator # type: ignore[import-untyped]
144
+ except ImportError:
145
+ report.warnings.append("jsonschema is not installed; skipped JSON Schema validation.")
146
+ return
147
+
148
+ validator = Draft202012Validator(schema)
149
+ errors = sorted(validator.iter_errors(artifact), key=lambda item: list(item.path))
150
+ for validation_error in errors:
151
+ location = "/".join(str(part) for part in validation_error.path) or "<root>"
152
+ report.add_error(f"{location}: {validation_error.message}")
153
+
154
+
155
+ def _validate_quality_thresholds(
156
+ report: ValidationReport, quality: dict[str, Any], thresholds: dict[str, float | int]
157
+ ) -> None:
158
+ files = quality.get("files", {})
159
+ calls = quality.get("calls", {})
160
+ labels = quality.get("labels", {})
161
+ skipped = files.get("skipped", {}) if isinstance(files, dict) else {}
162
+ parse_errors = files.get("parse_errors", {}) if isinstance(files, dict) else {}
163
+ if "max_skipped_files" in thresholds:
164
+ actual_skipped = int(_number(skipped.get("total"), 0))
165
+ skipped_limit = int(thresholds["max_skipped_files"])
166
+ if actual_skipped > skipped_limit:
167
+ report.add_error(
168
+ f"quality threshold failed: skipped files {actual_skipped} > max {skipped_limit}"
169
+ )
170
+ if "max_parse_warnings" in thresholds:
171
+ actual_parse_warnings = int(_number(parse_errors.get("total"), 0))
172
+ parse_warning_limit = int(thresholds["max_parse_warnings"])
173
+ if actual_parse_warnings > parse_warning_limit:
174
+ report.add_error(
175
+ "quality threshold failed: parse warnings "
176
+ f"{actual_parse_warnings} > max {parse_warning_limit}"
177
+ )
178
+ if "min_call_resolution" in thresholds:
179
+ actual_resolution = _number(calls.get("resolution_rate"), 0.0)
180
+ resolution_limit = float(thresholds["min_call_resolution"])
181
+ if actual_resolution < resolution_limit:
182
+ report.add_error(
183
+ "quality threshold failed: call resolution "
184
+ f"{actual_resolution:.0%} < min {resolution_limit:.0%}"
185
+ )
186
+ if "max_generic_label_ratio" in thresholds:
187
+ actual_generic = _number(labels.get("generic_ratio"), 0.0)
188
+ generic_limit = float(thresholds["max_generic_label_ratio"])
189
+ if actual_generic > generic_limit:
190
+ report.add_error(
191
+ "quality threshold failed: generic label ratio "
192
+ f"{actual_generic:.0%} > max {generic_limit:.0%}"
193
+ )
194
+
195
+
196
+ def _number(value: Any, default: float) -> float:
197
+ return float(value) if isinstance(value, (int, float)) else default
198
+
199
+
200
+ def _without_generated_at(payload: dict[str, Any]) -> dict[str, Any]:
201
+ clone = dict(payload)
202
+ clone.pop("generated_at", None)
203
+ return clone
204
+
205
+
206
+ def _read_bundled_schema() -> dict[str, Any]:
207
+ checkout_schema = Path(__file__).parents[2] / "schema" / "codedebrief.schema.json"
208
+ if checkout_schema.exists():
209
+ return read_json(checkout_schema)
210
+
211
+ schema_resource = (
212
+ resources.files("codedebrief").joinpath("schema").joinpath("codedebrief.schema.json")
213
+ )
214
+ return cast(dict[str, Any], json.loads(schema_resource.read_text(encoding="utf-8")))
@@ -0,0 +1,426 @@
1
+ Metadata-Version: 2.4
2
+ Name: codedebrief
3
+ Version: 0.11.0
4
+ Summary: Visual code workflow explorer for coding agents. Builds deterministic, source-grounded Mermaid flowcharts via MCP, local-first, with no API key.
5
+ Project-URL: Homepage, https://github.com/ferdinandobons/CodeDebrief
6
+ Project-URL: Documentation, https://github.com/ferdinandobons/CodeDebrief#readme
7
+ Project-URL: Issues, https://github.com/ferdinandobons/CodeDebrief/issues
8
+ Project-URL: Source, https://github.com/ferdinandobons/CodeDebrief
9
+ Author: Ferdinando Bonsegna
10
+ License-Expression: Apache-2.0
11
+ License-File: LICENSE
12
+ License-File: NOTICE
13
+ Keywords: ai-agents,code-comprehension,code-navigation,coding-agents,cpp,developer-tools,flowchart,javascript,local-first,mcp,mcp-server,mermaid,model-context-protocol,python,source-code-analysis,static-analysis,tree-sitter,typescript,visualization,workflow
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Environment :: Console
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: Apache Software License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Software Development :: Documentation
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: jsonschema>=4.23
28
+ Requires-Dist: mcp<2,>=1.27
29
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
30
+ Requires-Dist: tree-sitter-c-sharp<0.24,>=0.23
31
+ Requires-Dist: tree-sitter-c<0.24,>=0.23
32
+ Requires-Dist: tree-sitter-cpp<0.24,>=0.23
33
+ Requires-Dist: tree-sitter-go<0.24,>=0.23
34
+ Requires-Dist: tree-sitter-java<0.24,>=0.23
35
+ Requires-Dist: tree-sitter-php<0.24,>=0.23
36
+ Requires-Dist: tree-sitter-ruby<0.24,>=0.23
37
+ Requires-Dist: tree-sitter-rust<0.24,>=0.23
38
+ Requires-Dist: tree-sitter-typescript<0.24,>=0.23.2
39
+ Requires-Dist: tree-sitter<0.26,>=0.25.2
40
+ Provides-Extra: dev
41
+ Requires-Dist: mypy>=1.15; extra == 'dev'
42
+ Requires-Dist: pytest-cov>=6; extra == 'dev'
43
+ Requires-Dist: pytest>=8.3; extra == 'dev'
44
+ Requires-Dist: ruff>=0.11; extra == 'dev'
45
+ Requires-Dist: tomli>=2.0; extra == 'dev'
46
+ Provides-Extra: mcp
47
+ Description-Content-Type: text/markdown
48
+
49
+ # CodeDebrief
50
+
51
+ CodeDebrief turns source code into deterministic, source-grounded workflow flowcharts for
52
+ humans and coding agents.
53
+
54
+ It is a local-first code comprehension tool that builds a source-grounded workflow model
55
+ of a codebase and exposes that model in two ways:
56
+
57
+ - `codedebrief view` for manual exploration of the complete graph.
58
+ - MCP `agent_context` for coding agents that need a bounded, source-grounded
59
+ `workflow_slice`.
60
+
61
+ The product unit is the `workflow_slice`: a deterministic slice of the modeled code
62
+ logic selected from a question, changed file, symbol, state, flow id, or dependency path.
63
+ Agents can render that slice visually, explain it, expand it, or trace a path without
64
+ inventing steps that are not in the graph.
65
+
66
+ CodeDebrief is not a bug finder, a generic graph database, or an LLM enrichment service.
67
+ The core workflow is deterministic, local, and offline. No LLM provider key is required.
68
+
69
+ ![Compact source-backed workflow visual generated from a CodeDebrief slice](docs/assets/codedebrief-workflow-preview.png)
70
+
71
+ Example output: a compact presentation layer generated from local CodeDebrief artifacts.
72
+ Canonical workflow visuals are vertical by default; horizontal diagrams are used when the
73
+ user explicitly asks for a compact overview.
74
+
75
+ > Status: pre-1.0 alpha. The model is versioned, but schema and MCP payloads may evolve
76
+ > before 1.0.
77
+ >
78
+ > Latest release: [v0.11.0](https://github.com/ferdinandobons/CodeDebrief/releases/tag/v0.11.0)
79
+ > · [Changelog](CHANGELOG.md)
80
+
81
+ ## Why It Exists
82
+
83
+ Coding agents are useful only when they understand the logic they are about to explain or
84
+ change. Reading files one by one is slow and inconsistent; asking an LLM to reconstruct a
85
+ workflow from source often produces different diagrams for the same prompt.
86
+
87
+ CodeDebrief gives agents a deterministic navigation layer:
88
+
89
+ - entrypoints, decisions, branches, calls, outcomes, and source ranges;
90
+ - domain concepts such as statuses, roles, permissions, enums, and feature flags;
91
+ - affected-workflow context for changed files, symbols, flows, and dependency paths;
92
+ - canonical visual slices with stable diagram hashes;
93
+ - optional language-friendly labels derived as a presentation layer from analyzer facts.
94
+
95
+ ## Quick Start
96
+
97
+ Install from PyPI. MCP support is included by default:
98
+
99
+ ```bash
100
+ uv tool install codedebrief
101
+ ```
102
+
103
+ To install a pinned GitHub release instead:
104
+
105
+ ```bash
106
+ uv tool install "git+https://github.com/ferdinandobons/CodeDebrief.git@v0.11.0"
107
+ ```
108
+
109
+ Or install from a source checkout:
110
+
111
+ ```bash
112
+ git clone https://github.com/ferdinandobons/CodeDebrief.git codedebrief
113
+ cd codedebrief
114
+ uv tool install .
115
+ ```
116
+
117
+ From the codebase you want to analyze:
118
+
119
+ ```bash
120
+ codedebrief setup-agent codex
121
+ ```
122
+
123
+ `setup-agent` creates `codedebrief.toml` when needed, installs the selected agent
124
+ instruction file, installs a provider-native CodeDebrief skill where supported, registers
125
+ project-scoped MCP where supported, generates initial artifacts, runs `doctor`, and
126
+ validates the result.
127
+
128
+ After setup, ask the coding agent ordinary questions:
129
+
130
+ ```text
131
+ How does checkout work?
132
+ Show me the workflow for certificate upload.
133
+ Which workflows are affected by this change?
134
+ Where is this status handled?
135
+ What should I test after editing this file?
136
+ ```
137
+
138
+ For manual exploration:
139
+
140
+ ```bash
141
+ codedebrief view
142
+ ```
143
+
144
+ For explicit refresh during development:
145
+
146
+ ```bash
147
+ codedebrief update
148
+ codedebrief validate --check-sync
149
+ ```
150
+
151
+ The generated agent instructions treat CodeDebrief artifacts as part of done for
152
+ workflow-relevant changes: after meaningful source, route, config, or agent-instruction
153
+ edits, run `codedebrief update` and `codedebrief validate --check-sync` before finalizing
154
+ or committing so MCP answers and `codedebrief view` use current graphs.
155
+
156
+ ## Ask Your Agent
157
+
158
+ Once `setup-agent` has configured the project MCP server and agent instructions, ask
159
+ ordinary code-logic questions:
160
+
161
+ ```text
162
+ Show me a visual workflow for the invitation system.
163
+ Explain this code path with a source-grounded flowchart.
164
+ Which workflows are affected by this change?
165
+ Where is this status handled?
166
+ Expand the omitted branches in this workflow_slice.
167
+ Rewrite the diagram labels in plain English.
168
+ ```
169
+
170
+ The agent should use CodeDebrief first, then decide how much of the deterministic graph to
171
+ show for the specific question.
172
+
173
+ ## Setup-Agent
174
+
175
+ Supported targets:
176
+
177
+ ```bash
178
+ codedebrief setup-agent codex
179
+ codedebrief setup-agent claude ../my-app
180
+ codedebrief setup-agent gemini
181
+ codedebrief setup-agent cursor --full
182
+ ```
183
+
184
+ The selected target controls which files are written:
185
+
186
+ | Target | Files |
187
+ | --- | --- |
188
+ | `codex` | `AGENTS.md`, `.agents/skills/codedebrief/SKILL.md`, project MCP config |
189
+ | `claude` | `CLAUDE.md`, `.claude/skills/codedebrief/SKILL.md`, project MCP config |
190
+ | `gemini` | `GEMINI.md`, `.gemini/skills/codedebrief/SKILL.md`, `.gemini/settings.json` MCP config |
191
+ | `cursor` | `.cursor/rules/codedebrief.mdc`, project MCP config |
192
+
193
+ `setup-agent <target>` writes only that target's files. Run it separately for each agent
194
+ surface you want to configure.
195
+
196
+ The `gemini` target follows Gemini CLI / Antigravity conventions: `GEMINI.md` provides
197
+ project context, `.gemini/skills/codedebrief/SKILL.md` provides provider-native workflow
198
+ guidance, and `.gemini/settings.json` registers the project-scoped CodeDebrief MCP server.
199
+
200
+ ## Agent Workflow
201
+
202
+ For natural-language questions, agents should start with MCP `agent_context`.
203
+
204
+ `agent_context` returns a `workflow_slice` with:
205
+
206
+ - normalized intent and task type;
207
+ - primary and supporting flows;
208
+ - ordered source-grounded steps;
209
+ - decision nodes, branches, values, and outcomes;
210
+ - calls, callers, callees, and unresolved call context;
211
+ - domain logic for relevant state-like concepts;
212
+ - source ranges the agent can cite;
213
+ - visual handles for `snapshot_slice` and `codedebrief view`;
214
+ - omissions caused by token budget, ambiguity, stale artifacts, or unsupported capability;
215
+ - follow-up tools for expansion, path tracing, focused explanation, and snapshots.
216
+
217
+ When a user asks for a visual workflow, the agent should first render the deterministic
218
+ Mermaid visual returned by CodeDebrief:
219
+
220
+ 1. Render `workflow_slice.presentation.canonical_visual.diagram` exactly as returned only
221
+ when the client renders Mermaid inline.
222
+ 2. If the client cannot render Mermaid inline, use `snapshot_slice` with
223
+ `include_svg=false` and provide the returned `.mmd` or Mermaid Markdown artifact
224
+ before prose. Do not paste a long Mermaid code block as the primary visual unless the
225
+ user asks for raw or copyable Mermaid. These generated files are meant to be opened
226
+ with the best available local preview path, for example opening the Markdown artifact
227
+ in VS Code and using Markdown/Mermaid preview support.
228
+ 3. Use SVG snapshot artifacts only when the user explicitly asks for SVG or local
229
+ inspection; they are not the canonical chat visual.
230
+
231
+ The model may choose the first visible depth, but the text inside shown blocks must come
232
+ from CodeDebrief payloads. The answer should say that the diagram is a bounded summary and
233
+ can be expanded. If the user wants a more language-friendly view, the agent may rewrite
234
+ labels in the user's language as a separate presentation layer, preserving ids or source
235
+ anchors and without adding facts.
236
+
237
+ ## MCP Surface
238
+
239
+ Primary MCP tools:
240
+
241
+ | Tool | Purpose |
242
+ | --- | --- |
243
+ | `agent_context` | Default entrypoint for natural-language questions and changed-code context. |
244
+ | `expand_slice` | Widen or deepen a workflow slice from stable flow handles. |
245
+ | `workflow_path` | Trace a deterministic path between flows, symbols, or concepts. |
246
+ | `snapshot_slice` | Render a deterministic visual snapshot for a slice. |
247
+ | `explain_flow` | Explain one flow with ordered steps, decisions, calls, and source anchors. |
248
+ | `explain_node` | Explain one flowchart node with local edge and source context. |
249
+ | `explain_edge` | Explain one modeled edge with source context. |
250
+ | `validate_artifacts` | Check generated model validity and optional sync. |
251
+ | `update_codedebrief` | Refresh JSON, Markdown, and HTML artifacts from local source. |
252
+
253
+ Use `codedebrief view` for the manual UI. The CLI intentionally stays small:
254
+ `setup-agent`, `update`, `view`, `validate`, `doctor`, and `mcp`.
255
+
256
+ ## Generated Artifacts
257
+
258
+ CodeDebrief writes deterministic artifacts under `codedebrief-out/`:
259
+
260
+ | File | Commit? | Purpose |
261
+ | --- | --- | --- |
262
+ | `codedebrief.json` | Yes | Canonical model consumed by MCP, CI, scripts, and the viewer. |
263
+ | `codedebrief.md` | Yes | Human-readable Markdown summary with Mermaid flowcharts. |
264
+ | `codedebrief.html` | Usually no | Local interactive viewer generated from the model. |
265
+
266
+ Commit `codedebrief.json` and `codedebrief.md` when CodeDebrief is part of the project
267
+ workflow. Regenerate HTML locally when a human needs the viewer.
268
+
269
+ ## Manual Viewer
270
+
271
+ `codedebrief view` opens the complete interactive flowchart for a human. It is the official
272
+ manual experience for broad exploration:
273
+
274
+ ```bash
275
+ codedebrief view
276
+ codedebrief view --render-only --no-open
277
+ ```
278
+
279
+ Use the viewer when you need to inspect the whole project graph, navigate scopes, compare
280
+ neighboring flows, or visually follow callers and callees. Use MCP when an agent should
281
+ answer a bounded question with a focused `workflow_slice`.
282
+
283
+ ## Domain Logic
284
+
285
+ CodeDebrief extracts and aggregates domain concepts such as:
286
+
287
+ - enum members;
288
+ - status and lifecycle states;
289
+ - roles and permissions;
290
+ - feature flags;
291
+ - handled values and the decisions that branch on them.
292
+
293
+ `agent_context` includes relevant domain logic inside the returned `workflow_slice`, with
294
+ links back to flows, nodes, source ranges, snapshots, and viewer targets. Value matching
295
+ uses modeled code facts, including enum-style suffix matches such as `PAID` for
296
+ `Status.PAID`.
297
+
298
+ ## Supported Code
299
+
300
+ CodeDebrief currently extracts control flow for 11 language ids:
301
+
302
+ | Language | Current coverage |
303
+ | --- | --- |
304
+ | Python (`.py`) | AST analyzer with functions, methods, decisions, loops, calls, returns, exceptions, tests, enum harvest, and import dependencies. |
305
+ | TypeScript / TSX (`.ts`, `.tsx`) | Tree-sitter analyzer with Next.js and React entrypoint detection, decisions, loops, calls, returns, expression-bodied arrows, tests, enum harvest, and import dependencies. |
306
+ | JavaScript / JSX (`.js`, `.jsx`, `.mjs`, `.cjs`) | Tree-sitter analyzer with JavaScript labeling, decisions, loops, calls, returns, expression-bodied arrows, tests, and import dependencies. |
307
+ | Go (`.go`) | Profile-driven tree-sitter analyzer with functions, methods, decisions, loops, calls, returns, tests, and import dependencies. |
308
+ | Java (`.java`) | Profile-driven tree-sitter analyzer with methods, decisions, loops, calls, returns, exceptions, tests, imports, and Spring route annotations. |
309
+ | C# (`.cs`) | Profile-driven tree-sitter analyzer with methods, decisions, loops, calls, returns, exceptions, and tests. |
310
+ | PHP (`.php`) | Profile-driven tree-sitter analyzer with functions, methods, decisions, loops, calls, returns, exceptions, and tests. |
311
+ | C (`.c`, `.h`) | Profile-driven tree-sitter analyzer with functions, decisions, loops, calls, returns, and tests. |
312
+ | C++ (`.cc`, `.cpp`, `.cxx`, `.hh`, `.hpp`, `.hxx`, `.ipp`, `.tpp`) | Profile-driven tree-sitter analyzer with functions, methods, decisions, loops, calls, returns, exceptions, and tests. |
313
+ | Rust (`.rs`) | Profile-driven tree-sitter analyzer with functions, decisions, loops, calls, match handling, returns, and tests. |
314
+ | Ruby (`.rb`) | Profile-driven tree-sitter analyzer with methods, decisions, loops, calls, returns, and tests. |
315
+
316
+ Generated models include `metadata.language_capabilities`, with feature flags and
317
+ limitation notes per language. Agents should use that contract when explaining analyzer
318
+ depth.
319
+
320
+ ## Configuration
321
+
322
+ CodeDebrief works without config. Add `codedebrief.toml` only when defaults are not enough:
323
+
324
+ ```toml
325
+ [codedebrief]
326
+ source_roots = ["."]
327
+ exclude = []
328
+ exclude_dirs = []
329
+ include_public_functions = true
330
+ max_call_depth = 4
331
+ output_dir = "codedebrief-out"
332
+ self_exclude = true
333
+
334
+ [codedebrief.entrypoints]
335
+ include = []
336
+ exclude = []
337
+
338
+ [codedebrief.scopes]
339
+ backend = ["backend/**", "services/**"]
340
+ frontend = ["frontend/**", "web/**"]
341
+ edge = ["edge/**", "workers/**"]
342
+ ```
343
+
344
+ Defaults prune common VCS, dependency, cache, temporary, generated, and output
345
+ directories, including `.git`, `node_modules`, virtualenv folders, `.next`, `.turbo`,
346
+ `.svelte-kit`, `dist`, `build`, `out`, `target`, `coverage`, `vendor`, `Pods`, and
347
+ `codedebrief-out`.
348
+
349
+ ## Limitations
350
+
351
+ CodeDebrief does not run code, observe runtime state, perform full symbolic execution,
352
+ prove business correctness, or reconstruct deep framework state. It statically models
353
+ source files, control flow, selected framework conventions, and resolvable internal calls.
354
+
355
+ Important practical limits:
356
+
357
+ - dynamic dispatch may remain unresolved;
358
+ - language capability varies by analyzer frontend;
359
+ - generated or unsupported files may be skipped;
360
+ - large slices are token-budgeted and report omissions;
361
+ - the displayed first slice is a bounded summary and can be expanded with MCP tools.
362
+
363
+ ## FAQ
364
+
365
+ ### Is CodeDebrief an AI code review tool?
366
+
367
+ No. CodeDebrief is for code comprehension and workflow navigation. It helps humans and
368
+ coding agents understand modeled logic; it does not present possible defects as product
369
+ output.
370
+
371
+ ### Does CodeDebrief require an LLM API key?
372
+
373
+ No. The analyzer, artifacts, Mermaid diagrams, manual viewer, and MCP server are
374
+ local-first and deterministic. Coding agents can use the MCP tools without any required
375
+ provider key.
376
+
377
+ ### How is CodeDebrief different from a call graph?
378
+
379
+ A call graph shows relationships between symbols. CodeDebrief models workflow slices with
380
+ entrypoints, decisions, branches, ordered steps, source ranges, domain concepts, visual
381
+ targets, and expansion tools for coding agents.
382
+
383
+ ### Can CodeDebrief generate Mermaid workflow diagrams from code?
384
+
385
+ Yes. `agent_context` returns a canonical top-to-bottom Mermaid visual for the selected
386
+ `workflow_slice`, and `snapshot_slice` can persist Mermaid files for clients that cannot
387
+ render Mermaid inline.
388
+
389
+ ### Can I use CodeDebrief only as a manual visual explorer?
390
+
391
+ Yes. Run `codedebrief view` to open the interactive local viewer. MCP is the primary agent
392
+ surface, but the viewer remains the official manual exploration surface.
393
+
394
+ ## Development
395
+
396
+ For local development in this repository:
397
+
398
+ ```bash
399
+ uv sync --extra dev
400
+ uv run codedebrief --help
401
+ ```
402
+
403
+ Standard gates:
404
+
405
+ ```bash
406
+ UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run ruff check .
407
+ UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run ruff format --check .
408
+ UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run mypy
409
+ UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run pytest --cov
410
+ UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run codedebrief validate . --check-sync --json
411
+ ```
412
+
413
+ Viewer gates:
414
+
415
+ ```bash
416
+ npm run viewer:typecheck
417
+ npm run viewer:test
418
+ npm run viewer:build
419
+ UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run codedebrief update
420
+ UV_CACHE_DIR=/tmp/codedebrief-uv-cache uv run codedebrief view --render-only --no-open
421
+ ```
422
+
423
+ Schemas:
424
+
425
+ - [schema/codedebrief.schema.json](schema/codedebrief.schema.json) documents the canonical
426
+ artifact model.
@@ -0,0 +1,48 @@
1
+ codedebrief/__init__.py,sha256=AX7wdOPFDwuJYbfG8VSiyc509n5WPKfhut2L0zMaXU4,375
2
+ codedebrief/artifacts.py,sha256=BIAgDjcP2Y3GxjaIXkSR-nvpYTuZq_3FzwhYrfXEbB4,1809
3
+ codedebrief/cli.py,sha256=LI6PK91cn9YnQhIJaWbe01vqLGb-UfMU413mg-04Uf0,19723
4
+ codedebrief/config.py,sha256=SqWIvGm8qx8mn2n6uIy5ICC_QFHUe5LUFwDhDabnnXQ,7632
5
+ codedebrief/doctor.py,sha256=qMKgBqZJXEzfWQ_TQxlZViTjta1fqD1YkjjNbLwFhOU,5943
6
+ codedebrief/install.py,sha256=BacXTwP99t0RLBRgBFZacXC3AJeNMLzuiYcgPESKb9s,21243
7
+ codedebrief/mcp_server.py,sha256=BDi_-COX7ktPGBO-wIo5JhV88a70xmZ8u1Ksm01txTs,98619
8
+ codedebrief/model.py,sha256=VIUKL9sSVHsNn2CSB0W-Q9slgUZ1Gvfjkg9PWLF1DuA,5623
9
+ codedebrief/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
10
+ codedebrief/quality.py,sha256=Z0LX9yR_IHaLR61Ej7FULSWmFCiXu15rz7BbkT5M1Hw,15403
11
+ codedebrief/query.py,sha256=qpEI3jcsuswQVElzqZY63HT4wPE9b5gVRF2zQzeHMV0,23074
12
+ codedebrief/util.py,sha256=5vTbub_uikjd6U3xpRSBYQWTC52tYVmYaRSmUJ__TqU,1970
13
+ codedebrief/validation.py,sha256=fhhVbztDoDvdA_I5tr4QuCOH-2qrczlxgysvxsC1iHU,8315
14
+ codedebrief/analysis/__init__.py,sha256=wSpZMiXlX6G5hU8dIk85BH4xuWwMsSRl25l9o42REog,554
15
+ codedebrief/analysis/common.py,sha256=pQQNDrTwG0QnWWSvxOYXlBw2d240Y5UQDfR0Qub7p-I,17920
16
+ codedebrief/analysis/discovery.py,sha256=rpTcTSMylAHb0x9w4nwcT4BlAlRR3pg69fiQOgqD6lc,4232
17
+ codedebrief/analysis/project.py,sha256=y7dQeBKBhzloN__xQ5vON37rsf0IWw68oTT0P3wrrb4,16151
18
+ codedebrief/analysis/python.py,sha256=kCKbomOi7GUCUd3Y-x7nerTJrOWW2Siosxt53w6Itjs,34408
19
+ codedebrief/analysis/registry.py,sha256=5YFUbbTleyVoCLZeHAl6mzxRNSlqffIIDWASxUJJvgA,10442
20
+ codedebrief/analysis/treesitter.py,sha256=y6KVLiuL5TzxiTg90g3E8f1g75GI70gFGGD0oriLWzo,36200
21
+ codedebrief/analysis/typescript.py,sha256=5DOFFuHr6IB4Uc0v84r6dLZEO3jbVqdX8KxS9_IhVB4,38420
22
+ codedebrief/analysis/languages/__init__.py,sha256=u-Fa3xrUW5AAhVGPt2bk0XiZfRFDSPDwc106bGU8noY,320
23
+ codedebrief/analysis/languages/_common.py,sha256=7UBqj0sHJf1aaozzkrq7lNavLRTGkU04vlvdSpo3JPk,2526
24
+ codedebrief/analysis/languages/c.py,sha256=S7PoP2T_WtnhkV9JK74-_rRJLyzCiDjVFX0NvJxoNoQ,3403
25
+ codedebrief/analysis/languages/cpp.py,sha256=X2XlZYnYgktjwXtU1YpPyv1cLOpRDJy9ABGEBfzPJu0,5020
26
+ codedebrief/analysis/languages/csharp.py,sha256=M_lSGjj1ZjiFOjwsRDt9V_7kRAzHUrmMDrM0CLH6fCk,5420
27
+ codedebrief/analysis/languages/go.py,sha256=dkHPfk-6RHTkSfMBO2G7X-05AaFl0Vj-YLchFMYLYQA,5483
28
+ codedebrief/analysis/languages/java.py,sha256=tV0uoqSD6HyrcFF8oHrfyw-szWkji6wv-8PJz5ySko8,6072
29
+ codedebrief/analysis/languages/php.py,sha256=hzNcRhSQYoOaTofXM_XrCAAZj39wMS4LZhIbjK7A8bM,3260
30
+ codedebrief/analysis/languages/ruby.py,sha256=48axyjdg6e7U_488y9t6ePmKJx-3xRePJ4Lre2Qhk-E,2768
31
+ codedebrief/analysis/languages/rust.py,sha256=efn1rdCGofHuAUmTe40cbyXfVL5J9sENYQx7rXn5Zs4,3807
32
+ codedebrief/render/__init__.py,sha256=ghDW516vY7T-nWbYvj38Ns8GR40lAYEdzUfbM7yiJM8,208
33
+ codedebrief/render/html.py,sha256=sKUMF1UWSWkGdTtd3p_X-0LqK8gLwPENygQM2iB38FE,10640
34
+ codedebrief/render/markdown.py,sha256=3RbXAKi6PZfp6OvK1GqvHrS-AXvdEwHW-tL1YqEJJnk,5347
35
+ codedebrief/render/payload.py,sha256=k3u9LRDvrjXuWQ_RbnXX3cqKsS8UHzVc6lY5dWFABYE,14400
36
+ codedebrief/render/snapshot.py,sha256=AueLKF4axnHeRibGqiBXBsthu9m2BMWFLHnm4lvNGno,25548
37
+ codedebrief/render/assets/panels.js,sha256=nZ3PHIs0-JhyPopv126lo1OMVSVRtuSe7HiFtBe3VX4,17742
38
+ codedebrief/render/assets/shell.js,sha256=TLZ0IQzSzs51R6FSCgiRPgBOC2QwQdzF6hqpaog30ns,69483
39
+ codedebrief/render/assets/styles.css,sha256=kw877xa96kaUBD05yCQ1SX69KZRHhPnL3BTMCq_czX8,52278
40
+ codedebrief/render/assets/tree.js,sha256=WYx97jOQUt3e3hcy8RELKInnO-y4J4RZQU4AhD8cnV4,24180
41
+ codedebrief/render/assets/generated/codedebrief-viewer-runtime.iife.js,sha256=d2cmGiGqqTBgsgdQQvGV-rklXi-l2HjBh0EalZmfj1A,276745
42
+ codedebrief/schema/codedebrief.schema.json,sha256=CJTEgEcXvS09PYvciPkqjyLR9f4vzGHaCgvQ1gNFSoM,9760
43
+ codedebrief-0.11.0.dist-info/METADATA,sha256=ezkG6ADp0YAQHhIHEUH7pWJUaCFrbEhRFHLQPLkFynw,17493
44
+ codedebrief-0.11.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
45
+ codedebrief-0.11.0.dist-info/entry_points.txt,sha256=NLdCH2kxaZPfdGVhtzd1uhJ7xm36IlMqUAw9hXz_sk4,53
46
+ codedebrief-0.11.0.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
47
+ codedebrief-0.11.0.dist-info/licenses/NOTICE,sha256=1SKC2iM-7PF9gSHkpbqnxUW1dI8Pt6BKddq0-0BPSb4,365
48
+ codedebrief-0.11.0.dist-info/RECORD,,