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.
- pygraph_mcp-0.1.0/.github/workflows/publish.yml +34 -0
- pygraph_mcp-0.1.0/.gitignore +16 -0
- pygraph_mcp-0.1.0/AGENTS.md +69 -0
- pygraph_mcp-0.1.0/PKG-INFO +186 -0
- pygraph_mcp-0.1.0/README.md +161 -0
- pygraph_mcp-0.1.0/TODOS.md +109 -0
- pygraph_mcp-0.1.0/opencode.json +22 -0
- pygraph_mcp-0.1.0/pyproject.toml +78 -0
- pygraph_mcp-0.1.0/src/pygraph/__init__.py +1 -0
- pygraph_mcp-0.1.0/src/pygraph/__main__.py +3 -0
- pygraph_mcp-0.1.0/src/pygraph/builder.py +561 -0
- pygraph_mcp-0.1.0/src/pygraph/cli.py +308 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/__init__.py +53 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/boundaries.py +18 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/callees.py +13 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/callers.py +12 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/changes.py +49 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/complexity.py +27 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/context.py +41 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/coupling.py +26 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/deps.py +15 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/focus.py +37 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/graph_report.py +50 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/hotspot.py +18 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/impact.py +12 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/imports_cmd.py +13 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/node.py +50 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/opencode_plugin.py +41 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/orphans.py +17 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/path_cmd.py +13 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/plan.py +52 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/public.py +12 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/query_cmd.py +13 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/review.py +63 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/source.py +11 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/stale.py +19 -0
- pygraph_mcp-0.1.0/src/pygraph/commands/trace.py +21 -0
- pygraph_mcp-0.1.0/src/pygraph/config.py +26 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/__init__.py +0 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/calls.py +63 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/decorators.py +0 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/env.py +81 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/errors.py +52 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/flask.py +400 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/implements.py +61 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/imports.py +161 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/symbols.py +256 -0
- pygraph_mcp-0.1.0/src/pygraph/extractors/tests.py +58 -0
- pygraph_mcp-0.1.0/src/pygraph/graph/__init__.py +0 -0
- pygraph_mcp-0.1.0/src/pygraph/graph/boundaries.py +40 -0
- pygraph_mcp-0.1.0/src/pygraph/graph/cache.py +43 -0
- pygraph_mcp-0.1.0/src/pygraph/graph/serialize.py +157 -0
- pygraph_mcp-0.1.0/src/pygraph/graph/types.py +368 -0
- pygraph_mcp-0.1.0/src/pygraph/query.py +975 -0
- pygraph_mcp-0.1.0/src/pygraph/scanner/__init__.py +0 -0
- pygraph_mcp-0.1.0/src/pygraph/scanner/gitignore.py +0 -0
- pygraph_mcp-0.1.0/src/pygraph/scanner/walker.py +138 -0
- pygraph_mcp-0.1.0/src/pygraph/server.py +442 -0
- pygraph_mcp-0.1.0/tests/__init__.py +0 -0
- pygraph_mcp-0.1.0/tests/conftest.py +0 -0
- pygraph_mcp-0.1.0/tests/fixtures/__init__.py +0 -0
- pygraph_mcp-0.1.0/tests/test_boundaries.py +317 -0
- pygraph_mcp-0.1.0/tests/test_changes_stale.py +176 -0
- pygraph_mcp-0.1.0/tests/test_commands.py +757 -0
- pygraph_mcp-0.1.0/tests/test_extractors.py +428 -0
- pygraph_mcp-0.1.0/tests/test_graph_report.py +101 -0
- pygraph_mcp-0.1.0/tests/test_graph_types.py +433 -0
- pygraph_mcp-0.1.0/tests/test_incremental_build.py +207 -0
- pygraph_mcp-0.1.0/tests/test_mcp_server.py +541 -0
- pygraph_mcp-0.1.0/tests/test_opencode_plugin.py +57 -0
- pygraph_mcp-0.1.0/tests/test_plan_review.py +129 -0
- pygraph_mcp-0.1.0/tests/test_plugins.py +111 -0
- pygraph_mcp-0.1.0/tests/test_scanner.py +81 -0
- 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,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"
|