serpentine-parser 0.1.3__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.
- serpentine_parser-0.1.3/LICENCE +14 -0
- serpentine_parser-0.1.3/PKG-INFO +423 -0
- serpentine_parser-0.1.3/README.md +393 -0
- serpentine_parser-0.1.3/pyproject.toml +61 -0
- serpentine_parser-0.1.3/rust/CLAUDE.md +61 -0
- serpentine_parser-0.1.3/rust/Cargo.lock +459 -0
- serpentine_parser-0.1.3/rust/Cargo.toml +19 -0
- serpentine_parser-0.1.3/rust/src/events.rs +509 -0
- serpentine_parser-0.1.3/rust/src/graph/builder.rs +185 -0
- serpentine_parser-0.1.3/rust/src/graph/loaders.rs +918 -0
- serpentine_parser-0.1.3/rust/src/graph/mod.rs +251 -0
- serpentine_parser-0.1.3/rust/src/graph/pdg.rs +94 -0
- serpentine_parser-0.1.3/rust/src/graph/resolvers.rs +411 -0
- serpentine_parser-0.1.3/rust/src/javascript/config.rs +117 -0
- serpentine_parser-0.1.3/rust/src/javascript/mod.rs +1816 -0
- serpentine_parser-0.1.3/rust/src/lib.rs +381 -0
- serpentine_parser-0.1.3/rust/src/message_bus.rs +77 -0
- serpentine_parser-0.1.3/rust/src/python/config.rs +271 -0
- serpentine_parser-0.1.3/rust/src/python/mod.rs +1577 -0
- serpentine_parser-0.1.3/rust/src/rust_lang/config.rs +48 -0
- serpentine_parser-0.1.3/rust/src/rust_lang/mod.rs +1247 -0
- serpentine_parser-0.1.3/rust/src/subscribers/README.md +354 -0
- serpentine_parser-0.1.3/rust/src/subscribers/code_snippet.rs +182 -0
- serpentine_parser-0.1.3/rust/src/subscribers/definitions.rs +258 -0
- serpentine_parser-0.1.3/rust/src/subscribers/event_counter.rs +88 -0
- serpentine_parser-0.1.3/rust/src/subscribers/imports.rs +195 -0
- serpentine_parser-0.1.3/rust/src/subscribers/mod.rs +22 -0
- serpentine_parser-0.1.3/rust/src/subscribers/pdg.rs +977 -0
- serpentine_parser-0.1.3/rust/src/subscribers/raw_bindings.rs +659 -0
- serpentine_parser-0.1.3/rust/src/subscribers/scope_tree.rs +232 -0
- serpentine_parser-0.1.3/rust/src/subscribers/uses.rs +201 -0
- serpentine_parser-0.1.3/src/serpentine/__init__.py +36 -0
- serpentine_parser-0.1.3/src/serpentine/_analyzer.pyi +14 -0
- serpentine_parser-0.1.3/src/serpentine/cache.py +100 -0
- serpentine_parser-0.1.3/src/serpentine/cli.py +573 -0
- serpentine_parser-0.1.3/src/serpentine/config.py +147 -0
- serpentine_parser-0.1.3/src/serpentine/selector.py +440 -0
- serpentine_parser-0.1.3/src/serpentine/server/__init__.py +16 -0
- serpentine_parser-0.1.3/src/serpentine/server/app.py +264 -0
- serpentine_parser-0.1.3/src/serpentine/server/routes.py +241 -0
- serpentine_parser-0.1.3/src/serpentine/server/websocket.py +124 -0
- serpentine_parser-0.1.3/src/serpentine/state.py +511 -0
- serpentine_parser-0.1.3/src/serpentine/static/assets/elk-worker.min-BdOC9sib.js +6263 -0
- serpentine_parser-0.1.3/src/serpentine/static/assets/index-BsyBZio8.css +1 -0
- serpentine_parser-0.1.3/src/serpentine/static/assets/index-CpvmYCe_.js +219 -0
- serpentine_parser-0.1.3/src/serpentine/static/assets/layoutWorker-Dd3vNlDT.js +24 -0
- serpentine_parser-0.1.3/src/serpentine/static/assets/svgToPng-CCU1Oj7k.js +2 -0
- serpentine_parser-0.1.3/src/serpentine/static/index.html +13 -0
- serpentine_parser-0.1.3/src/serpentine/static/logo.svg +39 -0
- serpentine_parser-0.1.3/src/serpentine/watcher.py +201 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
Copyright 2026 Christopher Garretty
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: serpentine-parser
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Environment :: Console
|
|
6
|
+
Classifier: Environment :: Web Environment
|
|
7
|
+
Classifier: Intended Audience :: Developers
|
|
8
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Rust
|
|
13
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
15
|
+
Requires-Dist: watchdog>=6.0.0
|
|
16
|
+
Requires-Dist: click>=8.1.0
|
|
17
|
+
Requires-Dist: starlette>=0.38.0
|
|
18
|
+
Requires-Dist: uvicorn[standard]>=0.30.0
|
|
19
|
+
Requires-Dist: websockets>=12.0
|
|
20
|
+
License-File: LICENCE
|
|
21
|
+
Summary: Fast dependency graph analysis and visualization for Python, JavaScript/TypeScript, and Rust projects
|
|
22
|
+
Keywords: dependency-graph,visualization,static-analysis,python,javascript,rust,tree-sitter
|
|
23
|
+
Author: Christopher Garretty
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
26
|
+
Project-URL: Homepage, https://github.com/serpentine-parser/serpentine
|
|
27
|
+
Project-URL: Issues, https://github.com/serpentine-parser/serpentine/issues
|
|
28
|
+
Project-URL: Repository, https://github.com/serpentine-parser/serpentine
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="frontend/public/logo.svg" alt="Serpentine" width="64" />
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
# Serpentine
|
|
35
|
+
|
|
36
|
+
Fast dependency graph analysis and visualization for Python, JavaScript/TypeScript, and Rust projects.
|
|
37
|
+
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
Serpentine analyzes your codebase using a Rust-powered parser and displays an interactive dependency graph in your browser. It resolves dependencies down to the variable and call level and watches for file changes in real time.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **Multi-language**: Python, JavaScript, TypeScript, and Rust
|
|
47
|
+
- **Deep resolution**: Resolves calls and type references, not just import edges
|
|
48
|
+
- **Interactive graph**: Expandable nodes, search, pan/zoom, collapsible modules
|
|
49
|
+
- **Real-time updates**: File watcher pushes changes via WebSocket
|
|
50
|
+
- **Agent-ready CLI**: Structured JSON output with selectors for use in AI agent workflows
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
### PyPI (recommended)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install serpentine-parser
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Or with [uv](https://docs.astral.sh/uv/):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uv tool install serpentine-parser
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### From source
|
|
69
|
+
|
|
70
|
+
> **Prerequisites**: Python 3.12+, [Rust toolchain](https://rustup.rs), Node.js 18+
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/serpentine-parser/serpentine.git
|
|
74
|
+
cd serpentine
|
|
75
|
+
|
|
76
|
+
# 1. Build the frontend
|
|
77
|
+
cd frontend && npm install && npm run build && cd ..
|
|
78
|
+
|
|
79
|
+
# 2. Build the Rust extension and install the CLI
|
|
80
|
+
make install
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This installs the `serpentine` CLI globally via `uv tool`, which you will need to [install separately](https://docs.astral.sh/uv/getting-started/installation/).
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Quick Start
|
|
88
|
+
|
|
89
|
+
Navigate to any Python, JavaScript/TypeScript, or Rust project and run:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
serpentine serve
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Serpentine will analyze the project, start a local server at `http://127.0.0.1:8765`, and open the visualization in your browser. File changes are detected automatically and the graph updates in real time.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## CLI Reference
|
|
100
|
+
|
|
101
|
+
### `serpentine serve`
|
|
102
|
+
|
|
103
|
+
Start the visualization server with live file watching.
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
serpentine serve [PATH] [OPTIONS]
|
|
107
|
+
|
|
108
|
+
Arguments:
|
|
109
|
+
PATH Directory to analyze (default: current directory)
|
|
110
|
+
|
|
111
|
+
Options:
|
|
112
|
+
-p, --port INT Port to run the server on (default: 8765)
|
|
113
|
+
-h, --host TEXT Host to bind to (default: 127.0.0.1)
|
|
114
|
+
--no-browser Don't open browser automatically
|
|
115
|
+
--no-watch Disable file watching (static analysis only)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `serpentine analyze`
|
|
119
|
+
|
|
120
|
+
Analyze a project and output the full dependency graph as JSON.
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
serpentine analyze [PATH] [OPTIONS]
|
|
124
|
+
|
|
125
|
+
Options:
|
|
126
|
+
-o, --output PATH Write output to file instead of stdout
|
|
127
|
+
--pretty Pretty-print JSON
|
|
128
|
+
--select TEXT Selector expression to filter nodes (see below)
|
|
129
|
+
--exclude TEXT Exclusion pattern (same syntax as --select)
|
|
130
|
+
--no-cfg Strip control-flow graph data from nodes
|
|
131
|
+
--edges-only Output only the edges array (compact)
|
|
132
|
+
--include-standard Include stdlib nodes (default: off)
|
|
133
|
+
--include-third-party Include third-party nodes (default: off)
|
|
134
|
+
--state TEXT Filter by change state: modified,added,deleted
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `serpentine catalog`
|
|
138
|
+
|
|
139
|
+
Flat list of all nodes — useful for discovering node IDs before building selectors.
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
serpentine catalog [PATH] [OPTIONS]
|
|
143
|
+
|
|
144
|
+
Options:
|
|
145
|
+
--filter TEXT Glob pattern matched against node id and name
|
|
146
|
+
(repeatable; multiple patterns = union)
|
|
147
|
+
--no-assignments Exclude variable/assignment nodes
|
|
148
|
+
-o, --output PATH Write output to file instead of stdout
|
|
149
|
+
--pretty Pretty-print JSON
|
|
150
|
+
--include-standard Include stdlib nodes
|
|
151
|
+
--include-third-party Include third-party nodes
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### `serpentine stats`
|
|
155
|
+
|
|
156
|
+
Quick summary of project scale: node/edge counts by type and origin.
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
serpentine stats [PATH] [OPTIONS]
|
|
160
|
+
|
|
161
|
+
Options:
|
|
162
|
+
--pretty Pretty-print JSON
|
|
163
|
+
--include-standard Include stdlib nodes
|
|
164
|
+
--include-third-party Include third-party nodes
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Querying the Graph
|
|
170
|
+
|
|
171
|
+
`serpentine analyze` and `serpentine catalog` accept `--select` and `--exclude` to slice the graph down to just the nodes you care about. This is useful for large codebases where the full graph is too noisy, or for piping results into other tools.
|
|
172
|
+
|
|
173
|
+
### Step 1 — Find your node IDs
|
|
174
|
+
|
|
175
|
+
Every node has a dotted ID that reflects its location in the codebase. Use `catalog` to discover them:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
serpentine catalog . --no-assignments --pretty
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
This outputs a flat list of every module, class, and function with its ID:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"nodes": [
|
|
186
|
+
{ "id": "src.auth.models.User", "name": "User", "type": "class", ... },
|
|
187
|
+
{ "id": "src.auth.views.login", "name": "login", "type": "function", ... },
|
|
188
|
+
{ "id": "src.payments.stripe.charge", "name": "charge", "type": "function", ... }
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Narrow it down with `--filter` (glob matched against both ID and name):
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
# Find everything related to auth
|
|
197
|
+
serpentine catalog . --filter "*auth*" --no-assignments --pretty
|
|
198
|
+
|
|
199
|
+
# Find by name across modules
|
|
200
|
+
serpentine catalog . --filter "*User*" --no-assignments --pretty
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Step 2 — Select nodes and their dependencies
|
|
204
|
+
|
|
205
|
+
Once you have IDs, use `--select` with `serpentine analyze`. The selector controls which nodes (and their relationships) appear in the output.
|
|
206
|
+
|
|
207
|
+
**Plain pattern** — just the matching nodes:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
serpentine analyze --select "src.auth.*" --no-cfg --pretty
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**`+pattern`** — the matching nodes _plus everything they depend on_ (upstream):
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# What does the login view need to work?
|
|
217
|
+
serpentine analyze --select "+src.auth.views.login" --no-cfg --pretty
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**`pattern+`** — the matching nodes _plus everything that depends on them_ (downstream):
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# What breaks if I change the User model?
|
|
224
|
+
serpentine analyze --select "src.auth.models.User+" --no-cfg --pretty
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**`+pattern+`** — both directions (full blast radius):
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
serpentine analyze --select "+src.payments.*+" --no-cfg --pretty
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
**`@pattern`** — the full connected component (everything reachable in any direction):
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
serpentine analyze --select "@src.auth.*" --no-cfg --pretty
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Bounded hops** — limit how many levels to traverse:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# 2 levels of dependencies upstream, 1 level downstream
|
|
243
|
+
serpentine analyze --select "2+src.auth.views.login+1" --no-cfg --pretty
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Multiple selectors** — comma-separated, combined as a union:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
serpentine analyze --select "+src.auth.*,+src.payments.*" --no-cfg --pretty
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Step 3 — Exclude noise
|
|
253
|
+
|
|
254
|
+
`--exclude` removes nodes from the result (including their descendants):
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Show auth and its deps, but skip test files
|
|
258
|
+
serpentine analyze --select "+src.auth.*" --exclude "*test*" --no-cfg --pretty
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Glob pattern rules
|
|
262
|
+
|
|
263
|
+
`*` in a selector matches any characters **including dots**, so it crosses module boundaries:
|
|
264
|
+
|
|
265
|
+
| You want | Use |
|
|
266
|
+
| ---------------------------------- | ------------ |
|
|
267
|
+
| All nodes whose ID contains "auth" | `*auth*` |
|
|
268
|
+
| All children of a specific module | `src.auth.*` |
|
|
269
|
+
| A class anywhere in the project | `*.User` |
|
|
270
|
+
| All test files | `*test*` |
|
|
271
|
+
|
|
272
|
+
> **Tip**: `**` is equivalent to `*` — both match across dots.
|
|
273
|
+
|
|
274
|
+
### Compact output for large graphs
|
|
275
|
+
|
|
276
|
+
Use `--edges-only` to get just the edge list (much smaller than the full node tree):
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
serpentine analyze --select "+src.auth.*+" --edges-only --pretty
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Each edge has a `from` and `to` field with node IDs, and a `type` field (`calls`, `is-a`, or `has-a`).
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Configuration
|
|
287
|
+
|
|
288
|
+
Serpentine looks for `.serpentine.yml` or `serpentine.yml` in the project root. All settings are optional.
|
|
289
|
+
|
|
290
|
+
```yaml
|
|
291
|
+
analysis:
|
|
292
|
+
# File extensions to analyze (default: all supported)
|
|
293
|
+
extensions: [".py", ".js", ".jsx", ".ts", ".tsx", ".rs"]
|
|
294
|
+
|
|
295
|
+
# Directories to skip
|
|
296
|
+
exclude_dirs:
|
|
297
|
+
- node_modules
|
|
298
|
+
- .venv
|
|
299
|
+
- dist
|
|
300
|
+
- build
|
|
301
|
+
|
|
302
|
+
# Glob patterns for files to skip
|
|
303
|
+
exclude_patterns:
|
|
304
|
+
- "**/*.test.ts"
|
|
305
|
+
- "**/generated/**"
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Using Serpentine with AI Agents
|
|
311
|
+
|
|
312
|
+
Serpentine's CLI is designed to be consumed by AI coding agents (Claude, Cursor, Copilot, etc.). The structured JSON output, selector syntax, and `--edges-only` / `--no-assignments` flags exist specifically to give agents precise, low-noise subgraphs without requiring file reads.
|
|
313
|
+
|
|
314
|
+
### The problem it solves
|
|
315
|
+
|
|
316
|
+
When an agent starts a non-trivial task, it faces a cold-start problem: it doesn't know which files are relevant, how components relate, or what the blast radius of a change might be. The usual approach — grep, glob, read files one at a time — is expensive in tokens and often incomplete.
|
|
317
|
+
|
|
318
|
+
Serpentine collapses that exploration into 2-3 CLI calls. The agent gets a structural picture of the relevant code _before_ it starts reading files or writing a plan. In practice this means:
|
|
319
|
+
|
|
320
|
+
- Plans are scoped to the right files and boundaries from the start
|
|
321
|
+
- Less back-and-forth between reading files to trace call chains
|
|
322
|
+
- Fewer surprises mid-implementation when a dependency was missed
|
|
323
|
+
|
|
324
|
+
### Recommended workflow for agents
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# 1. Get the lay of the land — module names, rough scale
|
|
328
|
+
serpentine stats .
|
|
329
|
+
|
|
330
|
+
# 2. Find relevant node IDs by name
|
|
331
|
+
serpentine catalog . --filter "*auth*" --no-assignments --pretty
|
|
332
|
+
|
|
333
|
+
# 3. Get the subgraph for the relevant area
|
|
334
|
+
serpentine analyze . --select "+src.auth.*+" --no-cfg --edges-only --pretty
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Read the edges to understand what connects to what, then read only the files that are actually relevant.
|
|
338
|
+
|
|
339
|
+
### Scenarios where this pays off
|
|
340
|
+
|
|
341
|
+
**Before refactoring a module**
|
|
342
|
+
Use `--select "module+"` to map everything that depends on the module before writing a plan. This ensures the plan accounts for every callsite and doesn't discover new dependents halfway through.
|
|
343
|
+
|
|
344
|
+
**Before adding a feature that spans modules**
|
|
345
|
+
Use `--select "+moduleA.*,+moduleB.*"` to get the combined subgraph of two areas and understand exactly where they intersect. The boundaries of the work become clear before any code is written.
|
|
346
|
+
|
|
347
|
+
**Orienting to an unfamiliar codebase**
|
|
348
|
+
`serpentine stats` gives you the top-level module list and scale. `serpentine catalog . --no-assignments` gives a flat index of every class and function. Together these give structural orientation without reading a single file.
|
|
349
|
+
|
|
350
|
+
**Before deleting code**
|
|
351
|
+
Use `--select "*.TargetFunction+"` to get all downstream dependents. An empty result confirms the code is truly unused.
|
|
352
|
+
|
|
353
|
+
**Tracing a call chain**
|
|
354
|
+
Use `--select "+*.entrypoint+3"` to get 3 hops downstream from an entry point and understand the execution path before adding instrumentation or fixing a bug.
|
|
355
|
+
|
|
356
|
+
### Claude Code skill
|
|
357
|
+
|
|
358
|
+
This repository includes a Claude Code skill at `.claude/commands/serpentine.md`. If you're using Claude Code in a project analyzed by Serpentine, you can copy this file into your project's `.claude/commands/` directory. It instructs Claude to use Serpentine as its first step before reading files or grepping — running `stats`, then `catalog`, then `analyze` in sequence before answering structural questions or planning changes.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Development
|
|
363
|
+
|
|
364
|
+
### Project Structure
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
serpentine/
|
|
368
|
+
├── rust/ # Rust analyzer (tree-sitter + PyO3)
|
|
369
|
+
│ └── src/
|
|
370
|
+
│ ├── lib.rs # PyO3 module entry point
|
|
371
|
+
│ ├── python/ # Python parser
|
|
372
|
+
│ ├── javascript/ # JS/TS parser
|
|
373
|
+
│ ├── rust_lang/ # Rust parser
|
|
374
|
+
│ ├── subscribers/ # Event processors (imports, calls, defs)
|
|
375
|
+
│ └── graph/ # Graph builder and resolvers
|
|
376
|
+
├── src/serpentine/ # Python package
|
|
377
|
+
│ ├── cli.py # CLI commands
|
|
378
|
+
│ ├── state.py # Graph state management
|
|
379
|
+
│ ├── watcher.py # File watcher
|
|
380
|
+
│ ├── selector.py # Graph selector engine
|
|
381
|
+
│ ├── config.py # Config loading
|
|
382
|
+
│ └── server/ # Starlette web server + WebSocket
|
|
383
|
+
├── frontend/ # React frontend (Vite + TypeScript)
|
|
384
|
+
│ └── src/
|
|
385
|
+
├── Makefile # Build targets
|
|
386
|
+
└── pyproject.toml
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Building for Development
|
|
390
|
+
|
|
391
|
+
[Tilt](https://tilt.dev) is recommended for development — it rebuilds the Rust extension and frontend in parallel when files change:
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
tilt up
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Or manually:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
# Build Rust extension (rerun after changes to rust/src/)
|
|
401
|
+
uv run maturin develop
|
|
402
|
+
|
|
403
|
+
# Build frontend (rerun after changes to frontend/src/)
|
|
404
|
+
cd frontend && npm run build
|
|
405
|
+
|
|
406
|
+
# Run server
|
|
407
|
+
uv run serpentine serve --no-browser
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Adding a Language
|
|
411
|
+
|
|
412
|
+
1. Create a parser module in `rust/src/<language>/`
|
|
413
|
+
2. Emit `ImportStatement`, `UseName`, and `CallExpression` events via the message bus
|
|
414
|
+
3. Register the parser in `rust/src/lib.rs`
|
|
415
|
+
|
|
416
|
+
See `rust/src/python/` for a complete reference implementation and `CONTRIBUTING.md` for full details.
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## License
|
|
421
|
+
|
|
422
|
+
[Apache 2.0](LICENCE)
|
|
423
|
+
|