trailhead 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.
- trailhead-0.1.0/LICENSE +21 -0
- trailhead-0.1.0/PKG-INFO +520 -0
- trailhead-0.1.0/README.md +428 -0
- trailhead-0.1.0/pyproject.toml +91 -0
- trailhead-0.1.0/setup.cfg +4 -0
- trailhead-0.1.0/src/tests/conftest.py +12 -0
- trailhead-0.1.0/src/tests/test_config.py +133 -0
- trailhead-0.1.0/src/tests/test_embeddings.py +257 -0
- trailhead-0.1.0/src/tests/test_indexing.py +631 -0
- trailhead-0.1.0/src/tests/test_live_indexer.py +160 -0
- trailhead-0.1.0/src/tests/test_query.py +253 -0
- trailhead-0.1.0/src/tests/test_server.py +457 -0
- trailhead-0.1.0/src/tests/test_smoke.py +38 -0
- trailhead-0.1.0/src/trailhead/__init__.py +4 -0
- trailhead-0.1.0/src/trailhead/__main__.py +5 -0
- trailhead-0.1.0/src/trailhead/cli/__init__.py +3 -0
- trailhead-0.1.0/src/trailhead/cli/__main__.py +5 -0
- trailhead-0.1.0/src/trailhead/cli/app.py +28 -0
- trailhead-0.1.0/src/trailhead/cli/commands/__init__.py +1 -0
- trailhead-0.1.0/src/trailhead/cli/commands/embed.py +58 -0
- trailhead-0.1.0/src/trailhead/cli/commands/index.py +243 -0
- trailhead-0.1.0/src/trailhead/cli/commands/query.py +198 -0
- trailhead-0.1.0/src/trailhead/cli/commands/serve.py +158 -0
- trailhead-0.1.0/src/trailhead/server/__init__.py +5 -0
- trailhead-0.1.0/src/trailhead/server/__main__.py +3 -0
- trailhead-0.1.0/src/trailhead/server/app.py +348 -0
- trailhead-0.1.0/src/trailhead/server/rate_limit.py +51 -0
- trailhead-0.1.0/src/trailhead/services/__init__.py +1 -0
- trailhead-0.1.0/src/trailhead/services/config/__init__.py +7 -0
- trailhead-0.1.0/src/trailhead/services/config/cache.py +10 -0
- trailhead-0.1.0/src/trailhead/services/config/models.py +31 -0
- trailhead-0.1.0/src/trailhead/services/embeddings/__init__.py +17 -0
- trailhead-0.1.0/src/trailhead/services/embeddings/generator.py +44 -0
- trailhead-0.1.0/src/trailhead/services/embeddings/model_store.py +44 -0
- trailhead-0.1.0/src/trailhead/services/indexing/__init__.py +33 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/__init__.py +87 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/base.py +162 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/bash.py +97 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/c.py +183 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/cpp.py +178 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/csharp.py +196 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/go.py +243 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/html.py +176 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/java.py +180 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/javascript.py +220 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/php.py +219 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/python.py +374 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/registry.py +46 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/ruby.py +179 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/rust.py +229 -0
- trailhead-0.1.0/src/trailhead/services/indexing/adapters/typescript.py +283 -0
- trailhead-0.1.0/src/trailhead/services/indexing/graph.py +110 -0
- trailhead-0.1.0/src/trailhead/services/indexing/graph_query.py +176 -0
- trailhead-0.1.0/src/trailhead/services/indexing/live_indexer.py +195 -0
- trailhead-0.1.0/src/trailhead/services/indexing/parser.py +4 -0
- trailhead-0.1.0/src/trailhead/services/indexing/query.py +112 -0
- trailhead-0.1.0/src/trailhead/services/indexing/query_templates.py +554 -0
- trailhead-0.1.0/src/trailhead/services/indexing/sqlite_store.py +542 -0
- trailhead-0.1.0/src/trailhead/services/indexing/walker.py +45 -0
- trailhead-0.1.0/src/trailhead.egg-info/PKG-INFO +520 -0
- trailhead-0.1.0/src/trailhead.egg-info/SOURCES.txt +63 -0
- trailhead-0.1.0/src/trailhead.egg-info/dependency_links.txt +1 -0
- trailhead-0.1.0/src/trailhead.egg-info/entry_points.txt +2 -0
- trailhead-0.1.0/src/trailhead.egg-info/requires.txt +61 -0
- trailhead-0.1.0/src/trailhead.egg-info/top_level.txt +2 -0
trailhead-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cliff Bressette
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
trailhead-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trailhead
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Codebase indexing and semantic search using tree-sitter parsing, vector embeddings, and SQLite graph storage.
|
|
5
|
+
Author-email: Cliff Bressette <cliffordbressette@mcindi.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Cliff Bressette
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/McIndi/trailhead
|
|
29
|
+
Project-URL: Repository, https://github.com/McIndi/trailhead
|
|
30
|
+
Project-URL: Issues, https://github.com/McIndi/trailhead/issues
|
|
31
|
+
Keywords: indexing,semantic-search,rag,sqlite,vectors,tree-sitter,embeddings,code-search
|
|
32
|
+
Classifier: Development Status :: 3 - Alpha
|
|
33
|
+
Classifier: Intended Audience :: Developers
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
39
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
40
|
+
Classifier: Topic :: Text Processing :: Indexing
|
|
41
|
+
Requires-Python: >=3.10
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
License-File: LICENSE
|
|
44
|
+
Requires-Dist: sentence-transformers
|
|
45
|
+
Requires-Dist: tree-sitter>=0.21
|
|
46
|
+
Requires-Dist: tree-sitter-python>=0.21
|
|
47
|
+
Requires-Dist: sqliteai-vector
|
|
48
|
+
Requires-Dist: fastapi>=0.115
|
|
49
|
+
Requires-Dist: uvicorn>=0.30
|
|
50
|
+
Requires-Dist: watchfiles>=0.24
|
|
51
|
+
Provides-Extra: dev
|
|
52
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
53
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
54
|
+
Provides-Extra: javascript
|
|
55
|
+
Requires-Dist: tree-sitter-javascript>=0.21; extra == "javascript"
|
|
56
|
+
Provides-Extra: typescript
|
|
57
|
+
Requires-Dist: tree-sitter-typescript>=0.21; extra == "typescript"
|
|
58
|
+
Provides-Extra: rust
|
|
59
|
+
Requires-Dist: tree-sitter-rust>=0.21; extra == "rust"
|
|
60
|
+
Provides-Extra: go
|
|
61
|
+
Requires-Dist: tree-sitter-go>=0.21; extra == "go"
|
|
62
|
+
Provides-Extra: java
|
|
63
|
+
Requires-Dist: tree-sitter-java>=0.21; extra == "java"
|
|
64
|
+
Provides-Extra: csharp
|
|
65
|
+
Requires-Dist: tree-sitter-c-sharp>=0.21; extra == "csharp"
|
|
66
|
+
Provides-Extra: c
|
|
67
|
+
Requires-Dist: tree-sitter-c>=0.21; extra == "c"
|
|
68
|
+
Provides-Extra: cpp
|
|
69
|
+
Requires-Dist: tree-sitter-cpp>=0.21; extra == "cpp"
|
|
70
|
+
Provides-Extra: ruby
|
|
71
|
+
Requires-Dist: tree-sitter-ruby>=0.21; extra == "ruby"
|
|
72
|
+
Provides-Extra: php
|
|
73
|
+
Requires-Dist: tree-sitter-php>=0.21; extra == "php"
|
|
74
|
+
Provides-Extra: bash
|
|
75
|
+
Requires-Dist: tree-sitter-bash>=0.21; extra == "bash"
|
|
76
|
+
Provides-Extra: html
|
|
77
|
+
Requires-Dist: tree-sitter-html>=0.21; extra == "html"
|
|
78
|
+
Provides-Extra: all-languages
|
|
79
|
+
Requires-Dist: tree-sitter-javascript>=0.21; extra == "all-languages"
|
|
80
|
+
Requires-Dist: tree-sitter-typescript>=0.21; extra == "all-languages"
|
|
81
|
+
Requires-Dist: tree-sitter-rust>=0.21; extra == "all-languages"
|
|
82
|
+
Requires-Dist: tree-sitter-go>=0.21; extra == "all-languages"
|
|
83
|
+
Requires-Dist: tree-sitter-java>=0.21; extra == "all-languages"
|
|
84
|
+
Requires-Dist: tree-sitter-c-sharp>=0.21; extra == "all-languages"
|
|
85
|
+
Requires-Dist: tree-sitter-c>=0.21; extra == "all-languages"
|
|
86
|
+
Requires-Dist: tree-sitter-cpp>=0.21; extra == "all-languages"
|
|
87
|
+
Requires-Dist: tree-sitter-ruby>=0.21; extra == "all-languages"
|
|
88
|
+
Requires-Dist: tree-sitter-php>=0.21; extra == "all-languages"
|
|
89
|
+
Requires-Dist: tree-sitter-bash>=0.21; extra == "all-languages"
|
|
90
|
+
Requires-Dist: tree-sitter-html>=0.21; extra == "all-languages"
|
|
91
|
+
Dynamic: license-file
|
|
92
|
+
|
|
93
|
+
# trailhead
|
|
94
|
+
|
|
95
|
+
Command-line code indexing and semantic search tool. It parses source files into a **property graph** (modules, classes, functions, and their relationships) stored in SQLite, generates text embeddings with sentence-transformers, and exposes everything through a CLI and HTTP API.
|
|
96
|
+
|
|
97
|
+
- Single CLI command: `th`
|
|
98
|
+
- Text embeddings powered by sentence-transformers (models cached locally)
|
|
99
|
+
- Polyglot code indexing via tree-sitter (Python built-in; 12 additional languages optional)
|
|
100
|
+
- Property graph persisted in a single SQLite file with optional vector search
|
|
101
|
+
- Warm-model FastAPI server keeps the embedding model loaded in memory
|
|
102
|
+
- Background file watcher incrementally re-indexes on change
|
|
103
|
+
- Interactive browser UI for querying and visualizing the code graph
|
|
104
|
+
|
|
105
|
+
## Requirements
|
|
106
|
+
|
|
107
|
+
- Python 3.10+
|
|
108
|
+
|
|
109
|
+
## Install
|
|
110
|
+
|
|
111
|
+
Create and activate a virtual environment, then install the project in editable mode with dev dependencies:
|
|
112
|
+
|
|
113
|
+
```powershell
|
|
114
|
+
python -m venv .venv
|
|
115
|
+
.\.venv\Scripts\Activate.ps1
|
|
116
|
+
python -m pip install --upgrade pip
|
|
117
|
+
python -m pip install -e .[dev]
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Language support
|
|
121
|
+
|
|
122
|
+
Python is supported out of the box. Additional languages are installed as optional extras. Only the packages you install will be active; missing ones are silently skipped at startup.
|
|
123
|
+
|
|
124
|
+
Install individual languages:
|
|
125
|
+
|
|
126
|
+
```powershell
|
|
127
|
+
pip install -e .[javascript]
|
|
128
|
+
pip install -e .[typescript]
|
|
129
|
+
pip install -e .[rust]
|
|
130
|
+
pip install -e .[go]
|
|
131
|
+
pip install -e .[java]
|
|
132
|
+
pip install -e .[csharp]
|
|
133
|
+
pip install -e .[c]
|
|
134
|
+
pip install -e .[cpp]
|
|
135
|
+
pip install -e .[ruby]
|
|
136
|
+
pip install -e .[php]
|
|
137
|
+
pip install -e .[bash]
|
|
138
|
+
pip install -e .[html]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Or install everything at once:
|
|
142
|
+
|
|
143
|
+
```powershell
|
|
144
|
+
pip install -e .[all-languages]
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
| Extra | Language | File extensions |
|
|
148
|
+
|-------|----------|-----------------|
|
|
149
|
+
| `python` *(built-in)* | Python | `.py` |
|
|
150
|
+
| `javascript` | JavaScript | `.js` `.mjs` `.cjs` |
|
|
151
|
+
| `typescript` | TypeScript / TSX | `.ts` `.tsx` |
|
|
152
|
+
| `rust` | Rust | `.rs` |
|
|
153
|
+
| `go` | Go | `.go` |
|
|
154
|
+
| `java` | Java | `.java` |
|
|
155
|
+
| `csharp` | C# | `.cs` |
|
|
156
|
+
| `c` | C | `.c` `.h` |
|
|
157
|
+
| `cpp` | C++ | `.cpp` `.cc` `.cxx` `.hpp` `.hxx` `.h++` |
|
|
158
|
+
| `ruby` | Ruby | `.rb` |
|
|
159
|
+
| `php` | PHP | `.php` |
|
|
160
|
+
| `bash` | Bash / Shell | `.sh` `.bash` |
|
|
161
|
+
| `html` | HTML | `.html` `.htm` |
|
|
162
|
+
|
|
163
|
+
## Quick start
|
|
164
|
+
|
|
165
|
+
The typical workflow is: index your source tree once, then serve and query it.
|
|
166
|
+
|
|
167
|
+
```powershell
|
|
168
|
+
# 1. Index a project (writes .cindex/db.sqlite by default)
|
|
169
|
+
th index . --sqlite-db ./.cindex/graph.db --embed-model sentence-transformers/all-MiniLM-L6-v2
|
|
170
|
+
|
|
171
|
+
# 2. Start the server (watches for changes, keeps embeddings warm)
|
|
172
|
+
th serve . --sqlite-db ./.cindex/graph.db --model sentence-transformers/all-MiniLM-L6-v2
|
|
173
|
+
|
|
174
|
+
# 3. Open the browser UI
|
|
175
|
+
start http://localhost:8000
|
|
176
|
+
|
|
177
|
+
# 4. Or query from the CLI or another terminal
|
|
178
|
+
th query similar "HTTP route registration"
|
|
179
|
+
curl "http://localhost:8000/api/query/similar?text=HTTP+route+registration"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The server re-indexes changed files automatically in the background. You do not need to re-run `th index` while the server is running.
|
|
183
|
+
|
|
184
|
+
## Usage
|
|
185
|
+
|
|
186
|
+
### embed
|
|
187
|
+
|
|
188
|
+
Generate an embedding for a piece of text:
|
|
189
|
+
|
|
190
|
+
```powershell
|
|
191
|
+
th embed "A short sentence to embed"
|
|
192
|
+
th embed "A short sentence to embed" --model sentence-transformers/all-mpnet-base-v2
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The command prints the embedding as a JSON array of floats.
|
|
196
|
+
|
|
197
|
+
Optional cache override:
|
|
198
|
+
|
|
199
|
+
```powershell
|
|
200
|
+
$env:CINDEX_CACHE_DIR = "C:\models\cache"
|
|
201
|
+
th embed "A short sentence to embed"
|
|
202
|
+
th embed "A short sentence to embed" --cache-dir "C:\another\cache"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### index
|
|
206
|
+
|
|
207
|
+
Index a directory of source files. The graph is persisted to `.cindex/db.sqlite` by default (smart sync: full build on first run, incremental on subsequent runs):
|
|
208
|
+
|
|
209
|
+
```powershell
|
|
210
|
+
th index .
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Use `--in-memory` to build the graph without writing to disk and print a summary:
|
|
214
|
+
|
|
215
|
+
```powershell
|
|
216
|
+
th index . --in-memory
|
|
217
|
+
th index . --in-memory --output json
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Watch for file changes and reindex incrementally (Ctrl-C to stop):
|
|
221
|
+
|
|
222
|
+
```powershell
|
|
223
|
+
th index . --watch
|
|
224
|
+
th index . --sqlite-db ./.cindex/graph.db --embed-model sentence-transformers/all-MiniLM-L6-v2 --watch
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Use a custom database path or add embeddings:
|
|
228
|
+
|
|
229
|
+
```powershell
|
|
230
|
+
th index . --sqlite-db ./.cindex/graph.db
|
|
231
|
+
th index . --sqlite-db ./.cindex/graph.db --embed-model sentence-transformers/all-MiniLM-L6-v2
|
|
232
|
+
th index . --sqlite-db ./.cindex/graph.db --embed-model sentence-transformers/all-MiniLM-L6-v2 --embed-cache-dir C:\models\cache
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
When `sqlite-vector` can be loaded, trailhead also initializes vector search for the `vertex_embeddings.embedding` column. If extension loading is unavailable on your platform build, embeddings are still stored as Float32 BLOBs in SQLite.
|
|
236
|
+
|
|
237
|
+
### serve
|
|
238
|
+
|
|
239
|
+
Run the warm-model API server with a background indexer. The server watches the source tree, keeps the SQLite graph fresh, and reuses the loaded embedding model across index updates. The database defaults to `.cindex/db.sqlite` under the watched directory:
|
|
240
|
+
|
|
241
|
+
```powershell
|
|
242
|
+
th serve .
|
|
243
|
+
th serve . --model sentence-transformers/all-MiniLM-L6-v2
|
|
244
|
+
th serve . --sqlite-db ./.cindex/graph.db --model sentence-transformers/all-MiniLM-L6-v2
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
The browser UI is available at `http://localhost:8000` once the server starts.
|
|
248
|
+
|
|
249
|
+
### query
|
|
250
|
+
|
|
251
|
+
Run a read-only SQL query against the SQLite database (defaults to `./.cindex/db.sqlite`):
|
|
252
|
+
|
|
253
|
+
```powershell
|
|
254
|
+
th query sql --sql "SELECT label, COUNT(*) AS n FROM vertices GROUP BY label ORDER BY label"
|
|
255
|
+
th query sql --sqlite-db ./.cindex/graph.db --sql "SELECT label, COUNT(*) AS n FROM vertices GROUP BY label ORDER BY label"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Run a semantic similarity query against stored vertex embeddings:
|
|
259
|
+
|
|
260
|
+
```powershell
|
|
261
|
+
th query similar "find sqlite vector initialization code"
|
|
262
|
+
th query similar "find sqlite vector initialization code" --sqlite-db ./.cindex/graph.db
|
|
263
|
+
th query similar "graph persistence" --sqlite-db ./.cindex/graph.db --label function --k 5 --output json
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## HTTP API
|
|
267
|
+
|
|
268
|
+
When the server is running, the full API schema is available at:
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
http://localhost:8000/openapi.json
|
|
272
|
+
http://localhost:8000/docs
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
The schema documents every endpoint, parameter name, type, default, and constraint. **Check it first** before probing endpoints manually.
|
|
276
|
+
|
|
277
|
+
### Endpoints
|
|
278
|
+
|
|
279
|
+
| Method | Path | Description |
|
|
280
|
+
|--------|------|-------------|
|
|
281
|
+
| `GET` | `/` | Browser UI |
|
|
282
|
+
| `GET` | `/api/health` | Server status and configuration |
|
|
283
|
+
| `POST` | `/api/embed` | Embed a single text string |
|
|
284
|
+
| `POST` | `/api/embed/batch` | Embed multiple texts |
|
|
285
|
+
| `POST` | `/api/query/sql` | Run a read-only SQL query |
|
|
286
|
+
| `GET` | `/api/query/templates` | List built-in query templates |
|
|
287
|
+
| `GET` | `/api/query/templates/{name}` | Get a template's SQL |
|
|
288
|
+
| `POST` | `/api/query/templates/{name}/run` | Run a template against the database |
|
|
289
|
+
| `GET` | `/api/query/similar` | Semantic similarity search (parameter: `text`, `k`) |
|
|
290
|
+
| `GET` | `/api/graph/vertices` | Search vertices by name, label, or path |
|
|
291
|
+
| `GET` | `/api/graph/traverse` | Traverse the graph from a vertex |
|
|
292
|
+
|
|
293
|
+
### SQL schema
|
|
294
|
+
|
|
295
|
+
The two core tables are:
|
|
296
|
+
|
|
297
|
+
**`vertices`** — one row per code symbol:
|
|
298
|
+
|
|
299
|
+
| Column | Type | Notes |
|
|
300
|
+
|--------|------|-------|
|
|
301
|
+
| `id` | TEXT | UUID, used for graph traversal |
|
|
302
|
+
| `label` | TEXT | `module`, `class`, `function`, `external` |
|
|
303
|
+
| `name` | TEXT | Symbol name |
|
|
304
|
+
| `path` | TEXT | Absolute file path |
|
|
305
|
+
| `line` | INTEGER | Line number (null for modules) |
|
|
306
|
+
| `complexity` | INTEGER | McCabe complexity (functions only) |
|
|
307
|
+
| `properties_json` | TEXT | JSON blob with `source`, `docstring`, and all other properties |
|
|
308
|
+
|
|
309
|
+
**`edges`** — relationships between vertices:
|
|
310
|
+
|
|
311
|
+
| Column | Type | Notes |
|
|
312
|
+
|--------|------|-------|
|
|
313
|
+
| `id` | TEXT | UUID |
|
|
314
|
+
| `label` | TEXT | `defines`, `has_method`, `imports`, `calls` |
|
|
315
|
+
| `out_v_id` | TEXT | Source vertex id |
|
|
316
|
+
| `in_v_id` | TEXT | Target vertex id |
|
|
317
|
+
| `properties_json` | TEXT | Always `{}` currently |
|
|
318
|
+
|
|
319
|
+
Edge labels and their meaning:
|
|
320
|
+
|
|
321
|
+
| Label | Meaning |
|
|
322
|
+
|-------|---------|
|
|
323
|
+
| `defines` | Module → class or function it defines |
|
|
324
|
+
| `has_method` | Class → method |
|
|
325
|
+
| `imports` | Module → external symbol it imports |
|
|
326
|
+
| `calls` | Function → function it calls |
|
|
327
|
+
|
|
328
|
+
`source` and `docstring` live inside `properties_json` rather than as top-level columns. To filter on them in SQL, use `json_extract`:
|
|
329
|
+
|
|
330
|
+
```sql
|
|
331
|
+
-- Functions whose source mentions "HTTPException"
|
|
332
|
+
SELECT name, path, line
|
|
333
|
+
FROM vertices
|
|
334
|
+
WHERE label = 'function'
|
|
335
|
+
AND json_extract(properties_json, '$.source') LIKE '%HTTPException%'
|
|
336
|
+
|
|
337
|
+
-- Functions with a docstring
|
|
338
|
+
SELECT name, path
|
|
339
|
+
FROM vertices
|
|
340
|
+
WHERE label = 'function'
|
|
341
|
+
AND json_extract(properties_json, '$.docstring') IS NOT NULL
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### HTTP query examples
|
|
345
|
+
|
|
346
|
+
```powershell
|
|
347
|
+
# Health check
|
|
348
|
+
curl http://localhost:8000/api/health
|
|
349
|
+
|
|
350
|
+
# Embed text
|
|
351
|
+
curl -X POST http://localhost:8000/api/embed \
|
|
352
|
+
-H "Content-Type: application/json" \
|
|
353
|
+
-d '{"text": "hello world"}'
|
|
354
|
+
|
|
355
|
+
# Semantic search — note the parameter is "k", not "limit"
|
|
356
|
+
curl "http://localhost:8000/api/query/similar?text=route+registration&k=5"
|
|
357
|
+
|
|
358
|
+
# Filter semantic search to functions only
|
|
359
|
+
curl "http://localhost:8000/api/query/similar?text=route+registration&k=5&label=function"
|
|
360
|
+
|
|
361
|
+
# SQL query
|
|
362
|
+
curl -X POST http://localhost:8000/api/query/sql \
|
|
363
|
+
-H "Content-Type: application/json" \
|
|
364
|
+
-d '{"sql": "SELECT label, COUNT(*) AS n FROM vertices GROUP BY label"}'
|
|
365
|
+
|
|
366
|
+
# Find a vertex by name, then get its id for traversal
|
|
367
|
+
curl "http://localhost:8000/api/graph/vertices?name=ui_dashboard&label=function"
|
|
368
|
+
|
|
369
|
+
# Traverse outward along call edges only (shows what a function calls)
|
|
370
|
+
curl "http://localhost:8000/api/graph/traverse?vertex_id=<id>&direction=out&depth=2&edge_labels=calls"
|
|
371
|
+
|
|
372
|
+
# Traverse inward along call edges only (shows what calls a function)
|
|
373
|
+
curl "http://localhost:8000/api/graph/traverse?vertex_id=<id>&direction=in&depth=2&edge_labels=calls"
|
|
374
|
+
|
|
375
|
+
# Run a built-in query template
|
|
376
|
+
curl http://localhost:8000/api/query/templates
|
|
377
|
+
curl -X POST http://localhost:8000/api/query/templates/function_complexity/run
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Built-in query templates
|
|
381
|
+
|
|
382
|
+
Templates are pre-built SQL queries runnable without writing any SQL. Categories:
|
|
383
|
+
|
|
384
|
+
| Category | Templates |
|
|
385
|
+
|----------|-----------|
|
|
386
|
+
| `quality` | `function_complexity`, `missing_docstrings`, `undocumented_public_api`, `todo_fixme_inventory` |
|
|
387
|
+
| `testing` | `symbols_not_represented_by_tests`, `test_coverage_ratio_by_file`, `largest_untested_symbols` |
|
|
388
|
+
| `architecture` | `duplicate_symbol_names`, `dependency_hotspots`, `external_dependency_pressure` |
|
|
389
|
+
| `calls` | `most_called_functions`, `call_graph_hubs` |
|
|
390
|
+
| `data_health` | `missing_source_for_functions`, `orphan_edges` |
|
|
391
|
+
|
|
392
|
+
### Typical workflow for code exploration
|
|
393
|
+
|
|
394
|
+
1. **Find a starting point** — use semantic search or `/api/graph/vertices?name=...` to locate a vertex and grab its `id`.
|
|
395
|
+
2. **Understand its call chain** — traverse outward with `edge_labels=calls` to see what it calls; inward to see its callers.
|
|
396
|
+
3. **Understand its structure** — traverse with `edge_labels=defines,has_method` to see what a module or class contains.
|
|
397
|
+
4. **Run quality checks** — use the built-in templates for complexity, missing docs, or dependency hotspots without writing SQL.
|
|
398
|
+
5. **Ad-hoc queries** — use `/api/query/sql` with `json_extract` to filter on source content, docstrings, or any property.
|
|
399
|
+
|
|
400
|
+
## Tests
|
|
401
|
+
|
|
402
|
+
```powershell
|
|
403
|
+
pytest
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Project Layout
|
|
407
|
+
|
|
408
|
+
```text
|
|
409
|
+
.
|
|
410
|
+
|-- pyproject.toml
|
|
411
|
+
|-- README.md
|
|
412
|
+
|-- src/
|
|
413
|
+
| `-- cindex/
|
|
414
|
+
| |-- __init__.py
|
|
415
|
+
| |-- __main__.py
|
|
416
|
+
| |-- cli/
|
|
417
|
+
| | |-- __init__.py
|
|
418
|
+
| | |-- __main__.py
|
|
419
|
+
| | |-- app.py
|
|
420
|
+
| | `-- commands/
|
|
421
|
+
| | |-- __init__.py
|
|
422
|
+
| | |-- embed.py
|
|
423
|
+
| | |-- index.py
|
|
424
|
+
| | |-- query.py
|
|
425
|
+
| | `-- serve.py
|
|
426
|
+
| |-- server/
|
|
427
|
+
| | |-- __init__.py
|
|
428
|
+
| | |-- __main__.py
|
|
429
|
+
| | |-- app.py
|
|
430
|
+
| | `-- templates/
|
|
431
|
+
| | `-- query_ui.html
|
|
432
|
+
| `-- services/
|
|
433
|
+
| |-- config/
|
|
434
|
+
| | `-- cache.py
|
|
435
|
+
| |-- indexing/
|
|
436
|
+
| | |-- __init__.py
|
|
437
|
+
| | |-- graph.py
|
|
438
|
+
| | |-- graph_query.py
|
|
439
|
+
| | |-- live_indexer.py
|
|
440
|
+
| | |-- parser.py # re-exports parse_python_file (backwards compat)
|
|
441
|
+
| | |-- query.py
|
|
442
|
+
| | |-- sqlite_store.py
|
|
443
|
+
| | |-- walker.py
|
|
444
|
+
| | `-- adapters/ # language adapter registry
|
|
445
|
+
| | |-- __init__.py # auto-registers available adapters
|
|
446
|
+
| | |-- base.py # LanguageAdapter ABC + shared utilities
|
|
447
|
+
| | |-- registry.py # extension → adapter map, parse_file()
|
|
448
|
+
| | |-- python.py # Python (built-in)
|
|
449
|
+
| | |-- javascript.py # JavaScript (optional)
|
|
450
|
+
| | |-- typescript.py # TypeScript / TSX (optional)
|
|
451
|
+
| | |-- rust.py # Rust (optional)
|
|
452
|
+
| | |-- go.py # Go (optional)
|
|
453
|
+
| | |-- java.py # Java (optional)
|
|
454
|
+
| | |-- csharp.py # C# (optional)
|
|
455
|
+
| | |-- c.py # C (optional)
|
|
456
|
+
| | |-- cpp.py # C++ (optional)
|
|
457
|
+
| | |-- ruby.py # Ruby (optional)
|
|
458
|
+
| | |-- php.py # PHP (optional)
|
|
459
|
+
| | |-- bash.py # Bash / Shell (optional)
|
|
460
|
+
| | `-- html.py # HTML (optional)
|
|
461
|
+
| `-- embeddings/
|
|
462
|
+
| |-- generator.py
|
|
463
|
+
| `-- model_store.py
|
|
464
|
+
`-- tests/
|
|
465
|
+
|-- conftest.py
|
|
466
|
+
|-- test_indexing.py
|
|
467
|
+
|-- test_query.py
|
|
468
|
+
|-- test_server.py
|
|
469
|
+
`-- test_smoke.py
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
## Adding a custom language adapter
|
|
473
|
+
|
|
474
|
+
Any language with a tree-sitter Python binding can be supported in three steps:
|
|
475
|
+
|
|
476
|
+
```python
|
|
477
|
+
# 1. Create your adapter (e.g. my_adapters/kotlin.py)
|
|
478
|
+
from cindex.services.indexing.adapters.base import LanguageAdapter, _node_text, _complexity
|
|
479
|
+
from cindex.services.indexing.graph import PropertyGraph, Vertex
|
|
480
|
+
from pathlib import Path
|
|
481
|
+
|
|
482
|
+
class KotlinAdapter(LanguageAdapter):
|
|
483
|
+
extensions = frozenset({".kt", ".kts"})
|
|
484
|
+
|
|
485
|
+
@classmethod
|
|
486
|
+
def is_available(cls) -> bool:
|
|
487
|
+
try:
|
|
488
|
+
import tree_sitter_kotlin # noqa: F401
|
|
489
|
+
return True
|
|
490
|
+
except ImportError:
|
|
491
|
+
return False
|
|
492
|
+
|
|
493
|
+
def parse(self, path: Path, graph: PropertyGraph) -> Vertex:
|
|
494
|
+
import tree_sitter_kotlin as tskotlin
|
|
495
|
+
from tree_sitter import Language, Parser
|
|
496
|
+
source = path.read_bytes()
|
|
497
|
+
language = Language(tskotlin.language())
|
|
498
|
+
parser = Parser(language)
|
|
499
|
+
tree = parser.parse(source)
|
|
500
|
+
module_v = graph.add_vertex("module", name=path.stem, path=str(path))
|
|
501
|
+
# ... walk tree and add vertices/edges ...
|
|
502
|
+
return module_v
|
|
503
|
+
|
|
504
|
+
# 2. Register it at startup (e.g. in your app's __init__ or conftest)
|
|
505
|
+
from cindex.services.indexing.adapters import register
|
|
506
|
+
register(KotlinAdapter())
|
|
507
|
+
|
|
508
|
+
# 3. Done — th index, serve, and query all pick it up automatically.
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
What each adapter should produce:
|
|
512
|
+
|
|
513
|
+
| Vertex label | Meaning | Required properties |
|
|
514
|
+
|---|---|---|
|
|
515
|
+
| `module` | one per source file | `name`, `path` |
|
|
516
|
+
| `class` | class / struct / interface / trait | `name`, `path`, `line` |
|
|
517
|
+
| `function` | function / method | `name`, `path`, `line`, `source`, `complexity` |
|
|
518
|
+
| `external` | imported module name | `name` |
|
|
519
|
+
|
|
520
|
+
Edges: `defines` (module→class, module→function), `has_method` (class→function), `imports` (module→external), `calls` (function→function).
|