pygraph-mcp 0.1.0__tar.gz

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 (74) hide show
  1. pygraph_mcp-0.1.0/.github/workflows/publish.yml +34 -0
  2. pygraph_mcp-0.1.0/.gitignore +16 -0
  3. pygraph_mcp-0.1.0/AGENTS.md +69 -0
  4. pygraph_mcp-0.1.0/PKG-INFO +186 -0
  5. pygraph_mcp-0.1.0/README.md +161 -0
  6. pygraph_mcp-0.1.0/TODOS.md +109 -0
  7. pygraph_mcp-0.1.0/opencode.json +22 -0
  8. pygraph_mcp-0.1.0/pyproject.toml +78 -0
  9. pygraph_mcp-0.1.0/src/pygraph/__init__.py +1 -0
  10. pygraph_mcp-0.1.0/src/pygraph/__main__.py +3 -0
  11. pygraph_mcp-0.1.0/src/pygraph/builder.py +561 -0
  12. pygraph_mcp-0.1.0/src/pygraph/cli.py +308 -0
  13. pygraph_mcp-0.1.0/src/pygraph/commands/__init__.py +53 -0
  14. pygraph_mcp-0.1.0/src/pygraph/commands/boundaries.py +18 -0
  15. pygraph_mcp-0.1.0/src/pygraph/commands/callees.py +13 -0
  16. pygraph_mcp-0.1.0/src/pygraph/commands/callers.py +12 -0
  17. pygraph_mcp-0.1.0/src/pygraph/commands/changes.py +49 -0
  18. pygraph_mcp-0.1.0/src/pygraph/commands/complexity.py +27 -0
  19. pygraph_mcp-0.1.0/src/pygraph/commands/context.py +41 -0
  20. pygraph_mcp-0.1.0/src/pygraph/commands/coupling.py +26 -0
  21. pygraph_mcp-0.1.0/src/pygraph/commands/deps.py +15 -0
  22. pygraph_mcp-0.1.0/src/pygraph/commands/focus.py +37 -0
  23. pygraph_mcp-0.1.0/src/pygraph/commands/graph_report.py +50 -0
  24. pygraph_mcp-0.1.0/src/pygraph/commands/hotspot.py +18 -0
  25. pygraph_mcp-0.1.0/src/pygraph/commands/impact.py +12 -0
  26. pygraph_mcp-0.1.0/src/pygraph/commands/imports_cmd.py +13 -0
  27. pygraph_mcp-0.1.0/src/pygraph/commands/node.py +50 -0
  28. pygraph_mcp-0.1.0/src/pygraph/commands/opencode_plugin.py +41 -0
  29. pygraph_mcp-0.1.0/src/pygraph/commands/orphans.py +17 -0
  30. pygraph_mcp-0.1.0/src/pygraph/commands/path_cmd.py +13 -0
  31. pygraph_mcp-0.1.0/src/pygraph/commands/plan.py +52 -0
  32. pygraph_mcp-0.1.0/src/pygraph/commands/public.py +12 -0
  33. pygraph_mcp-0.1.0/src/pygraph/commands/query_cmd.py +13 -0
  34. pygraph_mcp-0.1.0/src/pygraph/commands/review.py +63 -0
  35. pygraph_mcp-0.1.0/src/pygraph/commands/source.py +11 -0
  36. pygraph_mcp-0.1.0/src/pygraph/commands/stale.py +19 -0
  37. pygraph_mcp-0.1.0/src/pygraph/commands/trace.py +21 -0
  38. pygraph_mcp-0.1.0/src/pygraph/config.py +26 -0
  39. pygraph_mcp-0.1.0/src/pygraph/extractors/__init__.py +0 -0
  40. pygraph_mcp-0.1.0/src/pygraph/extractors/calls.py +63 -0
  41. pygraph_mcp-0.1.0/src/pygraph/extractors/decorators.py +0 -0
  42. pygraph_mcp-0.1.0/src/pygraph/extractors/env.py +81 -0
  43. pygraph_mcp-0.1.0/src/pygraph/extractors/errors.py +52 -0
  44. pygraph_mcp-0.1.0/src/pygraph/extractors/flask.py +400 -0
  45. pygraph_mcp-0.1.0/src/pygraph/extractors/implements.py +61 -0
  46. pygraph_mcp-0.1.0/src/pygraph/extractors/imports.py +161 -0
  47. pygraph_mcp-0.1.0/src/pygraph/extractors/symbols.py +256 -0
  48. pygraph_mcp-0.1.0/src/pygraph/extractors/tests.py +58 -0
  49. pygraph_mcp-0.1.0/src/pygraph/graph/__init__.py +0 -0
  50. pygraph_mcp-0.1.0/src/pygraph/graph/boundaries.py +40 -0
  51. pygraph_mcp-0.1.0/src/pygraph/graph/cache.py +43 -0
  52. pygraph_mcp-0.1.0/src/pygraph/graph/serialize.py +157 -0
  53. pygraph_mcp-0.1.0/src/pygraph/graph/types.py +368 -0
  54. pygraph_mcp-0.1.0/src/pygraph/query.py +975 -0
  55. pygraph_mcp-0.1.0/src/pygraph/scanner/__init__.py +0 -0
  56. pygraph_mcp-0.1.0/src/pygraph/scanner/gitignore.py +0 -0
  57. pygraph_mcp-0.1.0/src/pygraph/scanner/walker.py +138 -0
  58. pygraph_mcp-0.1.0/src/pygraph/server.py +442 -0
  59. pygraph_mcp-0.1.0/tests/__init__.py +0 -0
  60. pygraph_mcp-0.1.0/tests/conftest.py +0 -0
  61. pygraph_mcp-0.1.0/tests/fixtures/__init__.py +0 -0
  62. pygraph_mcp-0.1.0/tests/test_boundaries.py +317 -0
  63. pygraph_mcp-0.1.0/tests/test_changes_stale.py +176 -0
  64. pygraph_mcp-0.1.0/tests/test_commands.py +757 -0
  65. pygraph_mcp-0.1.0/tests/test_extractors.py +428 -0
  66. pygraph_mcp-0.1.0/tests/test_graph_report.py +101 -0
  67. pygraph_mcp-0.1.0/tests/test_graph_types.py +433 -0
  68. pygraph_mcp-0.1.0/tests/test_incremental_build.py +207 -0
  69. pygraph_mcp-0.1.0/tests/test_mcp_server.py +541 -0
  70. pygraph_mcp-0.1.0/tests/test_opencode_plugin.py +57 -0
  71. pygraph_mcp-0.1.0/tests/test_plan_review.py +129 -0
  72. pygraph_mcp-0.1.0/tests/test_plugins.py +111 -0
  73. pygraph_mcp-0.1.0/tests/test_scanner.py +81 -0
  74. pygraph_mcp-0.1.0/uv.lock +1219 -0
@@ -0,0 +1,34 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v5
16
+
17
+ - name: Set up Python 3.11
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.11"
21
+
22
+ - name: Install dependencies
23
+ run: uv sync --group dev
24
+
25
+ - name: Run tests
26
+ run: uv run pytest
27
+
28
+ - name: Build
29
+ run: uv build
30
+
31
+ - name: Publish
32
+ run: uv publish
33
+ env:
34
+ UV_PUBLISH_TOKEN: ${{ secrets.UV_PUBLISH_TOKEN }}
@@ -0,0 +1,16 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .pygraph/
7
+ .pygraph/ref-*.json
8
+ .graph/
9
+ *.egg
10
+ venv/
11
+ .venv/
12
+ .env
13
+ .coverage
14
+ .mypy_cache/
15
+ .pytest_cache/
16
+ .ruff_cache/
@@ -0,0 +1,69 @@
1
+ # pygraph — Project DNA
2
+
3
+ ## Vision
4
+ A fast, local-only CLI tool that indexes Python / Flask codebases using AST parsing
5
+ into a queryable graph.json for AI coding agents. Equivalent to gograph / tsgraph but for Python.
6
+ Output is Markdown + JSON. No network calls, no telemetry, no SaaS backend.
7
+
8
+ ## Design Philosophy (Go/TS → Python Adaptation)
9
+ pygraph is inspired by gograph (Go) and tsgraph (TypeScript) but adapted for Python / Flask.
10
+ Key language-driven differences:
11
+ - **Export model**: Python uses `__all__` and `_name` convention (private by underscore); `isExported` maps to `not name.startswith('_')` or `name in __all__`
12
+ - **No goroutines/channels or async/promise** — Python has `asyncio`, threads, and generators
13
+ - **No struct tags** — Python has no native equivalent; use `dataclass` fields or type annotations
14
+ - **Router detection** is Flask route decorators (`@app.route`), Blueprints (`register_blueprint`), not Gin/mux or Next.js
15
+ - **Flask components** are tracked: views, Blueprints, CLI commands (`@app.cli.command`), template rendering, error handlers
16
+ - **Decorator support** — Python decorators are first-class; tracked as edges in the graph
17
+ - **Interface satisfaction** — Python uses `ABC` / `Protocol` (PEP 544) structural subtyping
18
+ - **Module-level code** — Python modules execute on import; side effects are tracked
19
+ - **Class methods / static methods / properties** — `@classmethod`, `@staticmethod`, `@property` tracked distinctly
20
+ - Go-specific concepts (structs with fields+tests, `MutationEdge`, `StructField.tags`) are replaced by Python equivalents (dataclass fields, test functions matching `test_*`)
21
+
22
+ ## Tech Stack
23
+ - Runtime: Python 3.11+
24
+ - Package manager: `uv`
25
+ - AST: `ast` (stdlib) + `astroid` for enhanced traversal
26
+ - CLI: `typer`
27
+ - MCP: `mcp` Python SDK
28
+ - Testing: `pytest` + `pytest-cov`
29
+ - Linting: `ruff`
30
+ - Type checking: `mypy` (strict mode)
31
+
32
+ ## Agent Rules
33
+
34
+ ### Task Management
35
+ - READ TODOS.md at session start to know what's done and what's next
36
+ - UPDATE TODOS.md when you start/finish a task (`[.]` in-progress, `[x]` done)
37
+ - Work in phase order unless a task has no blockers
38
+ - After a phase completes (all items `[x]`), run `git init` if not yet done, then commit: `git add -A && git commit -m "phase N: <title>"`
39
+
40
+ ### Orchestration
41
+ - This is a single-orchestrator project. When a task has multiple independent
42
+ sub-tasks, delegate via the `task` tool (`subagent_type: general`) rather
43
+ than doing them sequentially.
44
+ - For each delegated sub-task, specify:
45
+ 1. Exact files the sub-agent may modify
46
+ 2. Which phase from TODOS.md it belongs to
47
+ 3. What to return (never let sub-agents commit or merge)
48
+ - After all sub-tasks complete, run `uv run pytest && uv run mypy src && uv run ruff check` and fix any issues directly. Do NOT re-delegate broken builds.
49
+
50
+ ### Quality
51
+ - Run `uv run pytest`, `uv run mypy src`, and `uv run ruff check` after every task completion
52
+ - Fix all failures before marking `[x]`
53
+ - If the project is already broken when you start, note it in TODOS.md and fix it first
54
+
55
+ ### Research
56
+ - Use webfetch when unsure about an API — check Python `ast` docs, Flask docs,
57
+ or reference tsgraph source or gograph Go source
58
+ - DO NOT guess API signatures
59
+
60
+ ### Code Style
61
+ - No comments in source files unless logic is non-obvious
62
+ - Type annotations everywhere, avoid `Any`
63
+ - Follow patterns from adjacent files in the codebase
64
+ - No emojis in source code or commit messages
65
+ - Follow PEP 8 conventions (enforced by ruff)
66
+
67
+ ### Communication
68
+ - Be concise. Use TODOS.md for status, respond with only what's needed.
69
+ - If stuck, explain the blocker clearly rather than overthinking.
@@ -0,0 +1,186 @@
1
+ Metadata-Version: 2.4
2
+ Name: pygraph-mcp
3
+ Version: 0.1.0
4
+ Summary: AST-based Python/Flask codebase indexer for AI agents
5
+ Project-URL: Homepage, https://github.com/shvmgyl15/pygraph
6
+ Project-URL: Repository, https://github.com/shvmgyl15/pygraph
7
+ Project-URL: Issues, https://github.com/shvmgyl15/pygraph/issues
8
+ Author-email: Shivam Goel <sg15rokz@gmail.com>
9
+ License-Expression: MIT
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development :: Code Generators
17
+ Classifier: Topic :: Utilities
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: astroid>=3.3
20
+ Requires-Dist: mcp>=1.0
21
+ Requires-Dist: pathspec>=1.1.1
22
+ Requires-Dist: pydantic>=2.0
23
+ Requires-Dist: typer>=0.12
24
+ Description-Content-Type: text/markdown
25
+
26
+ # pygraph
27
+
28
+ AST-based Python/Flask codebase indexer for AI coding agents.
29
+
30
+ `pygraph` parses your Python project into a queryable graph (`graph.json`) using static analysis (AST). It detects Flask routes, blueprints, templates, CLI commands, decorators, dependencies, and more — with **zero network calls** and **no telemetry**.
31
+
32
+ Designed as a companion tool for AI agents (opencode, Cline, etc.) via MCP, or for direct CLI use during development.
33
+
34
+ ---
35
+
36
+ ## Quick Start
37
+
38
+ ```bash
39
+ pip install pygraph-mcp
40
+
41
+ # Or with uv:
42
+ uv pip install pygraph-mcp
43
+ ```
44
+
45
+ Index your project and start querying:
46
+
47
+ ```bash
48
+ cd my-python-project
49
+ pygraph build
50
+ pygraph public
51
+ pygraph node "my_function"
52
+ pygraph callers "my_function"
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Commands
58
+
59
+ | Command | Description |
60
+ |---------|-------------|
61
+ | `build` | Index project into `.pygraph/graph.json` |
62
+ | `node` | Show details of a symbol |
63
+ | `callers` | Show who calls the given symbol |
64
+ | `callees` | Show what the given symbol calls |
65
+ | `source` | Show source code of a file |
66
+ | `query` | Search symbols by pattern (regex or substring) |
67
+ | `context` | Show symbol with callers, callees, tests, and source |
68
+ | `imports` | Show imports of a file |
69
+ | `public` | List all exported (public) symbols |
70
+ | `focus` | Show JSON detail for a symbol |
71
+ | `impact` | Show downstream impact (BFS from symbol) |
72
+ | `path` | Show shortest call path between two symbols |
73
+ | `orphans` | List uncalled private symbols |
74
+ | `trace` | Find error messages and trace their call paths |
75
+ | `complexity` | Show McCabe cyclomatic complexity |
76
+ | `coupling` | Show afferent/efferent coupling metrics |
77
+ | `hotspot` | Show high-risk symbols (complexity x coupling) |
78
+ | `deps` | List external dependencies |
79
+ | `boundaries` | Check architecture boundary violations |
80
+ | `changes` | Show symbol changes since a git ref |
81
+ | `stale` | List files not modified in N days |
82
+ | `plan` | Generate a change plan report |
83
+ | `review` | Generate a Markdown code review report |
84
+ | `graph-report` | Generate a Markdown report about the codebase |
85
+ | `add-opencode-plugin` | Create `.opencode.json` with pygraph MCP config |
86
+ | `mcp` | Start MCP stdio server for AI agent integration |
87
+
88
+ ---
89
+
90
+ ## MCP Integration
91
+
92
+ Start the MCP server and connect your AI agent:
93
+
94
+ ```bash
95
+ pygraph mcp --root /path/to/project
96
+ ```
97
+
98
+ All query commands are exposed as MCP tools, making them callable from opencode, Cline, and any MCP-compatible client.
99
+
100
+ ---
101
+
102
+ ## Flask Support
103
+
104
+ pygraph detects Flask-specific constructs out of the box:
105
+
106
+ - Route decorators (`@app.route`) with HTTP methods and URL parameters
107
+ - Blueprint creation and registration (`register_blueprint`)
108
+ - Template rendering (`render_template`, `render_template_string`)
109
+ - Error handlers (`@app.errorhandler`)
110
+ - CLI commands (`@app.cli.command`)
111
+ - Flask extension usage
112
+
113
+ ---
114
+
115
+ ## Architecture Enforcement
116
+
117
+ Create `.pygraph/boundaries.json`:
118
+
119
+ ```json
120
+ {
121
+ "layers": [
122
+ {"name": "views", "pattern": "src/views/", "allowed": ["services"]},
123
+ {"name": "services", "pattern": "src/services/", "allowed": ["models", "repos"]},
124
+ {"name": "models", "pattern": "src/models/", "allowed": []},
125
+ {"name": "repos", "pattern": "src/repos/", "allowed": ["models"]}
126
+ ]
127
+ }
128
+ ```
129
+
130
+ Then run:
131
+
132
+ ```bash
133
+ pygraph boundaries
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Requirements
139
+
140
+ - Python 3.11+
141
+ - `uv` (recommended) or `pip`
142
+
143
+ ---
144
+
145
+ ## Development
146
+
147
+ ```bash
148
+ git clone https://github.com/shvmgyl15/pygraph.git
149
+ cd pygraph
150
+ uv sync
151
+ uv run pytest
152
+ uv run mypy src
153
+ uv run ruff check
154
+ ```
155
+
156
+ ---
157
+
158
+ ## How It Works
159
+
160
+ ```
161
+ ┌──────────┐ ┌──────────────┐ ┌───────────┐
162
+ │ Scanner │ → │ Extractors │ → │ Graph │
163
+ │ (walker) │ │ (AST, Flask) │ │ (JSON) │
164
+ └──────────┘ └──────────────┘ └───────────┘
165
+
166
+ ┌──────────┐
167
+ │ Query │
168
+ │ Engine │
169
+ └──────────┘
170
+ ```
171
+
172
+ 1. **Scan** — walks the project tree, respects `.gitignore`, classifies files
173
+ 2. **Extract** — parses Python source with `ast`, extracts symbols, calls, imports, Flask decorators, dependencies
174
+ 3. **Graph** — serializes everything to `.pygraph/graph.json` (incremental builds supported)
175
+ 4. **Query** — CLI or MCP tools query the graph for callers, callees, impact, paths, orphans, complexity, coupling, etc.
176
+
177
+ ---
178
+
179
+ ## Inspiration
180
+
181
+ pygraph was inspired by and follows the same design philosophy as:
182
+
183
+ - [tsgraph](https://github.com/shvmgyl15/tsgraph) — TypeScript codebase indexer
184
+ - [gograph](https://github.com/ozgurcd/gograph) — Go codebase indexer
185
+
186
+ Both projects use AST-based static analysis to create queryable code graphs for AI coding agents. pygraph adapts the same concept to Python and Flask.
@@ -0,0 +1,161 @@
1
+ # pygraph
2
+
3
+ AST-based Python/Flask codebase indexer for AI coding agents.
4
+
5
+ `pygraph` parses your Python project into a queryable graph (`graph.json`) using static analysis (AST). It detects Flask routes, blueprints, templates, CLI commands, decorators, dependencies, and more — with **zero network calls** and **no telemetry**.
6
+
7
+ Designed as a companion tool for AI agents (opencode, Cline, etc.) via MCP, or for direct CLI use during development.
8
+
9
+ ---
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ pip install pygraph-mcp
15
+
16
+ # Or with uv:
17
+ uv pip install pygraph-mcp
18
+ ```
19
+
20
+ Index your project and start querying:
21
+
22
+ ```bash
23
+ cd my-python-project
24
+ pygraph build
25
+ pygraph public
26
+ pygraph node "my_function"
27
+ pygraph callers "my_function"
28
+ ```
29
+
30
+ ---
31
+
32
+ ## Commands
33
+
34
+ | Command | Description |
35
+ |---------|-------------|
36
+ | `build` | Index project into `.pygraph/graph.json` |
37
+ | `node` | Show details of a symbol |
38
+ | `callers` | Show who calls the given symbol |
39
+ | `callees` | Show what the given symbol calls |
40
+ | `source` | Show source code of a file |
41
+ | `query` | Search symbols by pattern (regex or substring) |
42
+ | `context` | Show symbol with callers, callees, tests, and source |
43
+ | `imports` | Show imports of a file |
44
+ | `public` | List all exported (public) symbols |
45
+ | `focus` | Show JSON detail for a symbol |
46
+ | `impact` | Show downstream impact (BFS from symbol) |
47
+ | `path` | Show shortest call path between two symbols |
48
+ | `orphans` | List uncalled private symbols |
49
+ | `trace` | Find error messages and trace their call paths |
50
+ | `complexity` | Show McCabe cyclomatic complexity |
51
+ | `coupling` | Show afferent/efferent coupling metrics |
52
+ | `hotspot` | Show high-risk symbols (complexity x coupling) |
53
+ | `deps` | List external dependencies |
54
+ | `boundaries` | Check architecture boundary violations |
55
+ | `changes` | Show symbol changes since a git ref |
56
+ | `stale` | List files not modified in N days |
57
+ | `plan` | Generate a change plan report |
58
+ | `review` | Generate a Markdown code review report |
59
+ | `graph-report` | Generate a Markdown report about the codebase |
60
+ | `add-opencode-plugin` | Create `.opencode.json` with pygraph MCP config |
61
+ | `mcp` | Start MCP stdio server for AI agent integration |
62
+
63
+ ---
64
+
65
+ ## MCP Integration
66
+
67
+ Start the MCP server and connect your AI agent:
68
+
69
+ ```bash
70
+ pygraph mcp --root /path/to/project
71
+ ```
72
+
73
+ All query commands are exposed as MCP tools, making them callable from opencode, Cline, and any MCP-compatible client.
74
+
75
+ ---
76
+
77
+ ## Flask Support
78
+
79
+ pygraph detects Flask-specific constructs out of the box:
80
+
81
+ - Route decorators (`@app.route`) with HTTP methods and URL parameters
82
+ - Blueprint creation and registration (`register_blueprint`)
83
+ - Template rendering (`render_template`, `render_template_string`)
84
+ - Error handlers (`@app.errorhandler`)
85
+ - CLI commands (`@app.cli.command`)
86
+ - Flask extension usage
87
+
88
+ ---
89
+
90
+ ## Architecture Enforcement
91
+
92
+ Create `.pygraph/boundaries.json`:
93
+
94
+ ```json
95
+ {
96
+ "layers": [
97
+ {"name": "views", "pattern": "src/views/", "allowed": ["services"]},
98
+ {"name": "services", "pattern": "src/services/", "allowed": ["models", "repos"]},
99
+ {"name": "models", "pattern": "src/models/", "allowed": []},
100
+ {"name": "repos", "pattern": "src/repos/", "allowed": ["models"]}
101
+ ]
102
+ }
103
+ ```
104
+
105
+ Then run:
106
+
107
+ ```bash
108
+ pygraph boundaries
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Requirements
114
+
115
+ - Python 3.11+
116
+ - `uv` (recommended) or `pip`
117
+
118
+ ---
119
+
120
+ ## Development
121
+
122
+ ```bash
123
+ git clone https://github.com/shvmgyl15/pygraph.git
124
+ cd pygraph
125
+ uv sync
126
+ uv run pytest
127
+ uv run mypy src
128
+ uv run ruff check
129
+ ```
130
+
131
+ ---
132
+
133
+ ## How It Works
134
+
135
+ ```
136
+ ┌──────────┐ ┌──────────────┐ ┌───────────┐
137
+ │ Scanner │ → │ Extractors │ → │ Graph │
138
+ │ (walker) │ │ (AST, Flask) │ │ (JSON) │
139
+ └──────────┘ └──────────────┘ └───────────┘
140
+
141
+ ┌──────────┐
142
+ │ Query │
143
+ │ Engine │
144
+ └──────────┘
145
+ ```
146
+
147
+ 1. **Scan** — walks the project tree, respects `.gitignore`, classifies files
148
+ 2. **Extract** — parses Python source with `ast`, extracts symbols, calls, imports, Flask decorators, dependencies
149
+ 3. **Graph** — serializes everything to `.pygraph/graph.json` (incremental builds supported)
150
+ 4. **Query** — CLI or MCP tools query the graph for callers, callees, impact, paths, orphans, complexity, coupling, etc.
151
+
152
+ ---
153
+
154
+ ## Inspiration
155
+
156
+ pygraph was inspired by and follows the same design philosophy as:
157
+
158
+ - [tsgraph](https://github.com/shvmgyl15/tsgraph) — TypeScript codebase indexer
159
+ - [gograph](https://github.com/ozgurcd/gograph) — Go codebase indexer
160
+
161
+ Both projects use AST-based static analysis to create queryable code graphs for AI coding agents. pygraph adapts the same concept to Python and Flask.
@@ -0,0 +1,109 @@
1
+ # pygraph — Implementation Plan
2
+
3
+ ## Phase 1: Project Scaffold
4
+ - [x] Update opencode.json with AGENTS.md reference
5
+ - [x] Create AGENTS.md with project DNA
6
+ - [x] Create TODOS.md (this file)
7
+ - [x] Git init + Phase 1 commit
8
+ - [x] Initialize pyproject.toml with dependencies (typer, astroid, mcp, pytest, mypy, ruff)
9
+ - [x] Configure mypy (strict mode)
10
+ - [x] Configure ruff (PEP 8, import sorting)
11
+ - [x] Create src/pygraph directory structure (commands/, scanner/, graph/, extractors/)
12
+ - [x] Setup pytest config (conftest.py, test fixtures)
13
+
14
+ ## Phase 2: Core Data Model
15
+ - [x] Define graph types (Graph, PackageNode, FileNode, SymbolNode, and all edge types)
16
+ - [x] Add JSON serialization / deserialization (dataclasses)
17
+ - [x] Write unit tests for graph types (42 tests)
18
+
19
+ ## Phase 3: Scanner + Parser Core
20
+ - [x] Implement file scanner (walk tree, gitignore support, file classification)
21
+ - [x] Implement symbol extractor (ast: functions, classes, methods, variables, constants)
22
+ - [x] Implement call expression extractor
23
+ - [x] Implement import edge + dependency extractor (requirements.txt, pyproject.toml)
24
+ - [x] Implement decorator tracking (inline in symbol extraction)
25
+ - [x] Wire up `build` command end-to-end (builder.py orchestrates scan → parse → write)
26
+ - [x] Write parser/scanner unit tests (25 tests for scanner + extractors)
27
+
28
+ ## Phase 4: Query Commands
29
+ - [x] GraphQuery engine (query.py) — symbol lookup, callers/callees, imports, regex, context, impact, path, orphans, trace/errorflow
30
+ - [x] callers / callees CLI commands
31
+ - [x] node / source / query CLI commands
32
+ - [x] context (bundle — node + source + callers + callees + tests)
33
+ - [x] imports / public / focus CLI commands
34
+ - [x] impact / path / orphans / trace CLI commands (basic BFS, refined in Phase 7)
35
+ - [x] query regex support (fallback to substring)
36
+ - [x] Write query command tests (60 tests)
37
+
38
+ ## Phase 5: Flask-Specific Extractors
39
+ - [x] Route detection (`@app.route`, method, URL params)
40
+ - [x] Blueprint detection and registration
41
+ - [x] Template rendering detection (`render_template`)
42
+ - [x] Error handler detection (`@app.errorhandler`)
43
+ - [x] CLI command detection (`@app.cli.command`)
44
+ - [x] Flask extension detection and usage
45
+ - [x] Write extractor tests
46
+
47
+ ## Phase 6: Analysis Commands
48
+ - [x] complexity (McCabe / cyclomatic)
49
+ - [x] hotspot / coupling / deps
50
+ - [x] Write analysis tests
51
+
52
+ ## Phase 7: Graph Traversal
53
+ - [x] impact (BFS downstream blast radius with deque, max_depth, transitive)
54
+ - [x] path (BFS shortest path with deque, file/line in steps)
55
+ - [x] orphans (dead code detection via reachability from entry points)
56
+ - [x] trace / errorflow (reverse BFS from string literal through callers)
57
+ - [x] Write traversal tests (169 tests, up from 159)
58
+
59
+ ## Phase 8: MCP Server
60
+ - [x] MCP stdio server wrapping all query tools (`src/pygraph/server.py`)
61
+ - [x] Tool definition for each search/query command (18 tools)
62
+ - [x] MCP unit test (30 tests, unit-test style via `_query_override`)
63
+ - [x] `--root` flag for running MCP server against any project
64
+
65
+ ## Phase 9: Advanced Features
66
+ - [x] boundaries (architecture enforcement via .pygraph/boundaries.json)
67
+ - [x] Incremental builds (mtime tracking, merge unchanged data, skip re-parse)
68
+ - [x] changes / stale (git-aware incremental analysis)
69
+ - [x] plan / review (change planning reports)
70
+ - [x] add-opencode-plugin (auto-configure opencode MCP + agent)
71
+ - [x] Enhanced GRAPH_REPORT.md (hotspots, boundaries, coupling, stale)
72
+
73
+ ## Phase 10: Query Engine Fixes + Missing Extractors
74
+ - [x] Rewrite `_resolve_callee` to parse `ClassName(args).method()` patterns
75
+ - [x] Fix `get_callers` to use `_resolve_callee`
76
+ - [x] Fix `get_callees` to aggregate calls from class methods
77
+ - [x] Fix coupling/hotspot to use qualified names (`ClassName.method`)
78
+ - [x] Fix `_callers_by_name` index to also key by receiver
79
+ - [x] Fix `get_path` visited tracking redundant check
80
+ - [x] Build env_reads extractor (`os.environ.get`, `os.getenv`, `environ[]`)
81
+ - [x] Build errors extractor (`raise` / `raise ... from ...`)
82
+ - [x] Build test_edges extractor (test functions → called project symbols)
83
+ - [x] Build implements extractor (ABC/Protocol subclassing)
84
+ - [x] Better error messages for `changes`/`plan`/`review` snapshot misses
85
+ - [x] `orphans --all` flag for public uncalled symbols
86
+ - [x] `context` structured summary (source behind `--source` flag)
87
+ - [x] P0: Fix `caller_symbol_id` mismatch — qualify class.method name in calls.py
88
+ - [x] P1: Add `app.add_url_rule()` route extractor in flask.py
89
+ - [x] P2: Add Poetry dependency parsing in imports.py
90
+ - [x] P4: Auto-build graph from git ref with caching (`._load_git_graph` fallback)
91
+ - [x] P4: Update `.gitignore` for `ref-*.json` cache files
92
+ - [x] Run `pytest && mypy src && ruff check` — fix all failures
93
+
94
+ ## Phase 11: Post-Build Plugin System
95
+ - [x] Add `src/pygraph/config.py` — load `[tool.pygraph]` from `pyproject.toml`
96
+ - [x] Add `_run_plugins()` in `builder.py` — import & run each plugin script's `run(graph)`
97
+ - [x] Wire into `build_graph()` — plugins run after graph assembly, before return
98
+ - [x] Errors, missing scripts, missing `run` function all warn and continue
99
+ - [x] Multiple plugins supported in order; failure of one doesn't block the next
100
+ - [x] Tests: plugin runs + adds edges, missing plugin, no run function, exception, no plugins, multiple, partial failure
101
+
102
+ ## Phase 12: PyPI Publishing Prep
103
+ - [x] Add author, license, readme, classifiers, urls to pyproject.toml
104
+ - [x] Add `__version__` to `src/pygraph/__init__.py`
105
+ - [x] Update package name to `pygraph-mcp` (pygraph taken on PyPI)
106
+ - [x] Update README.md install instructions for PyPI
107
+ - [x] Create `.github/workflows/publish.yml` for auto-publishing on tags
108
+ - [x] Fix unwanted imports in tests/test_plugins.py
109
+ - [x] Verify build, tests, mypy, ruff all pass
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "model": "opencode-go/deepseek-v4-flash",
4
+ "default_agent": "plan",
5
+ "instructions": ["AGENTS.md"],
6
+ "permission": {
7
+ "read": {
8
+ "*": "allow",
9
+ "*.env": "allow",
10
+ "*.env.*": "allow"
11
+ },
12
+ "external_directory": {
13
+ "/tmp/**": "allow"
14
+ },
15
+ "grep": "allow",
16
+ "glob": "allow",
17
+ "lsp": "allow",
18
+ "skill": "allow",
19
+ "webfetch": "allow",
20
+ "websearch": "allow"
21
+ }
22
+ }
@@ -0,0 +1,78 @@
1
+ [project]
2
+ name = "pygraph-mcp"
3
+ version = "0.1.0"
4
+ description = "AST-based Python/Flask codebase indexer for AI agents"
5
+ requires-python = ">=3.11"
6
+ authors = [{name = "Shivam Goel", email = "sg15rokz@gmail.com"}]
7
+ license = "MIT"
8
+ readme = "README.md"
9
+ classifiers = [
10
+ "Development Status :: 4 - Beta",
11
+ "Intended Audience :: Developers",
12
+ "License :: OSI Approved :: MIT License",
13
+ "Operating System :: OS Independent",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Topic :: Software Development :: Code Generators",
17
+ "Topic :: Utilities",
18
+ ]
19
+ dependencies = [
20
+ "typer>=0.12",
21
+ "astroid>=3.3",
22
+ "mcp>=1.0",
23
+ "pydantic>=2.0",
24
+ "pathspec>=1.1.1",
25
+ ]
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/shvmgyl15/pygraph"
29
+ Repository = "https://github.com/shvmgyl15/pygraph"
30
+ Issues = "https://github.com/shvmgyl15/pygraph/issues"
31
+
32
+ [project.scripts]
33
+ pygraph = "pygraph.cli:app"
34
+
35
+ [tool.hatch.build.targets.wheel]
36
+ packages = ["src/pygraph"]
37
+
38
+ [build-system]
39
+ requires = ["hatchling"]
40
+ build-backend = "hatchling.build"
41
+
42
+ [tool.mypy]
43
+ strict = true
44
+ python_version = "3.11"
45
+ files = ["src"]
46
+ exclude = ["tests/"]
47
+ disallow_any_unimported = true
48
+ disallow_any_decorated = true
49
+ disallow_subclassing_any = true
50
+ warn_unused_ignores = true
51
+ warn_redundant_casts = true
52
+ warn_return_any = true
53
+ no_implicit_optional = true
54
+ check_untyped_defs = true
55
+
56
+ [tool.ruff]
57
+ src = ["src"]
58
+ line-length = 100
59
+ target-version = "py311"
60
+
61
+ [tool.ruff.lint]
62
+ select = ["E", "F", "I", "N", "W", "UP", "B", "SIM"]
63
+
64
+ [tool.ruff.format]
65
+ quote-style = "double"
66
+
67
+ [tool.pytest.ini_options]
68
+ testpaths = ["tests"]
69
+ pythonpath = ["src"]
70
+ addopts = "-v --cov=pygraph --cov-report=term-missing"
71
+
72
+ [dependency-groups]
73
+ dev = [
74
+ "mypy>=2.1.0",
75
+ "pytest>=9.0.3",
76
+ "pytest-cov>=7.1.0",
77
+ "ruff>=0.15.13",
78
+ ]
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from pygraph.cli import app
2
+
3
+ app()