kinetic-context 0.2.1__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 (58) hide show
  1. kinetic_context-0.2.1/LICENSE +21 -0
  2. kinetic_context-0.2.1/PKG-INFO +348 -0
  3. kinetic_context-0.2.1/README.md +308 -0
  4. kinetic_context-0.2.1/kce/__init__.py +5 -0
  5. kinetic_context-0.2.1/kce/_version.py +1 -0
  6. kinetic_context-0.2.1/kce/assembly/__init__.py +2 -0
  7. kinetic_context-0.2.1/kce/assembly/context_builder.py +41 -0
  8. kinetic_context-0.2.1/kce/benchmark/__init__.py +2 -0
  9. kinetic_context-0.2.1/kce/benchmark/dataset.py +334 -0
  10. kinetic_context-0.2.1/kce/benchmark/django_dataset.py +42 -0
  11. kinetic_context-0.2.1/kce/benchmark/flask_dataset.py +42 -0
  12. kinetic_context-0.2.1/kce/benchmark/metrics.py +26 -0
  13. kinetic_context-0.2.1/kce/benchmark/runner.py +275 -0
  14. kinetic_context-0.2.1/kce/cli.py +568 -0
  15. kinetic_context-0.2.1/kce/config.py +120 -0
  16. kinetic_context-0.2.1/kce/coordinator/__init__.py +2 -0
  17. kinetic_context-0.2.1/kce/coordinator/intent.py +95 -0
  18. kinetic_context-0.2.1/kce/coordinator/query_coordinator.py +59 -0
  19. kinetic_context-0.2.1/kce/coordinator/query_expansion.py +68 -0
  20. kinetic_context-0.2.1/kce/coordinator/query_transform.py +41 -0
  21. kinetic_context-0.2.1/kce/coordinator/symbol_lookup.py +32 -0
  22. kinetic_context-0.2.1/kce/embeddings/__init__.py +2 -0
  23. kinetic_context-0.2.1/kce/embeddings/codestral.py +73 -0
  24. kinetic_context-0.2.1/kce/engine.py +419 -0
  25. kinetic_context-0.2.1/kce/graph/__init__.py +2 -0
  26. kinetic_context-0.2.1/kce/graph/ckg.py +136 -0
  27. kinetic_context-0.2.1/kce/incremental/__init__.py +2 -0
  28. kinetic_context-0.2.1/kce/incremental/time_travel.py +145 -0
  29. kinetic_context-0.2.1/kce/incremental/update.py +47 -0
  30. kinetic_context-0.2.1/kce/ingestion/__init__.py +2 -0
  31. kinetic_context-0.2.1/kce/ingestion/chunker.py +109 -0
  32. kinetic_context-0.2.1/kce/ingestion/discovery.py +51 -0
  33. kinetic_context-0.2.1/kce/ingestion/parser.py +121 -0
  34. kinetic_context-0.2.1/kce/ingestion/summarizer.py +78 -0
  35. kinetic_context-0.2.1/kce/mcp_server.py +321 -0
  36. kinetic_context-0.2.1/kce/neuro_symbolic/__init__.py +2 -0
  37. kinetic_context-0.2.1/kce/neuro_symbolic/loop.py +24 -0
  38. kinetic_context-0.2.1/kce/ranking/__init__.py +2 -0
  39. kinetic_context-0.2.1/kce/ranking/reranker.py +58 -0
  40. kinetic_context-0.2.1/kce/ranking/unified_reranker.py +104 -0
  41. kinetic_context-0.2.1/kce/retrieval/__init__.py +2 -0
  42. kinetic_context-0.2.1/kce/retrieval/bm25.py +44 -0
  43. kinetic_context-0.2.1/kce/retrieval/dense.py +40 -0
  44. kinetic_context-0.2.1/kce/retrieval/graph_retrieval.py +70 -0
  45. kinetic_context-0.2.1/kce/retrieval/novel_signals.py +221 -0
  46. kinetic_context-0.2.1/kce/retrieval/rrf.py +18 -0
  47. kinetic_context-0.2.1/kce/store/__init__.py +2 -0
  48. kinetic_context-0.2.1/kce/store/index_store.py +57 -0
  49. kinetic_context-0.2.1/kce/store/registry.py +256 -0
  50. kinetic_context-0.2.1/kce/store/vector_store.py +141 -0
  51. kinetic_context-0.2.1/kinetic_context.egg-info/PKG-INFO +348 -0
  52. kinetic_context-0.2.1/kinetic_context.egg-info/SOURCES.txt +56 -0
  53. kinetic_context-0.2.1/kinetic_context.egg-info/dependency_links.txt +1 -0
  54. kinetic_context-0.2.1/kinetic_context.egg-info/entry_points.txt +3 -0
  55. kinetic_context-0.2.1/kinetic_context.egg-info/requires.txt +13 -0
  56. kinetic_context-0.2.1/kinetic_context.egg-info/top_level.txt +1 -0
  57. kinetic_context-0.2.1/pyproject.toml +68 -0
  58. kinetic_context-0.2.1/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Z.ai
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.
@@ -0,0 +1,348 @@
1
+ Metadata-Version: 2.4
2
+ Name: kinetic-context
3
+ Version: 0.2.1
4
+ Summary: Repository-level code context engine — find the right code, fast.
5
+ Author: Z.ai
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/zai-org/kinetic-context
8
+ Project-URL: Repository, https://github.com/zai-org/kinetic-context
9
+ Project-URL: Issues, https://github.com/zai-org/kinetic-context/issues
10
+ Keywords: code,search,context,retrieval,embeddings,ast,tree-sitter,mcp,model-context-protocol,code-intelligence
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Topic :: Software Development :: Code Generators
22
+ Classifier: Topic :: Text Processing :: Indexing
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: tree-sitter>=0.23
27
+ Requires-Dist: tree-sitter-python>=0.23
28
+ Requires-Dist: tree-sitter-javascript>=0.23
29
+ Requires-Dist: tree-sitter-typescript>=0.23
30
+ Requires-Dist: tree-sitter-go>=0.23
31
+ Requires-Dist: tree-sitter-rust>=0.23
32
+ Requires-Dist: tree-sitter-java>=0.23
33
+ Requires-Dist: rank-bm25>=0.2.2
34
+ Requires-Dist: networkx>=3.0
35
+ Requires-Dist: numpy>=1.24
36
+ Requires-Dist: requests>=2.31
37
+ Requires-Dist: rich>=13.0
38
+ Requires-Dist: tqdm>=4.66
39
+ Dynamic: license-file
40
+
41
+ # kinetic-context
42
+
43
+ > Repository-level code context engine — find the right code, fast.
44
+
45
+ `kinetic-context` is a self-contained, installable code context engine. Point it at any repository and it builds a multi-layer index (AST chunks + embeddings + a code knowledge graph + BM25) that you can query with natural language or identifiers. It returns **code blocks with line ranges** — not just file paths — ready to paste into an LLM prompt.
46
+
47
+ It is designed to be the context layer for coding agents. It ships with a Rich CLI, an MCP server (so Claude Code, Cursor, Continue, and Zed can mount it natively), a TCP JSON mode for any other agent, and a Python library.
48
+
49
+ ---
50
+
51
+ ## Highlights
52
+
53
+ - **Multi-language**: Python, JavaScript, TypeScript, Go, Rust, Java — via tree-sitter.
54
+ - **Structure-aware chunking** (`cAST`): never splits a function mid-body. 35% overlap. Hierarchical summaries at file and repository level.
55
+ - **Hybrid retrieval**: dense (Mistral Codestral Embed, 1536-dim) + BM25 (code-aware tokenizer that splits camelCase, snake_case, and dotted identifiers) + a Code Knowledge Graph with 8 relationship types.
56
+ - **Reciprocal Rank Fusion** with brute-force-optimized weights across 5 channels (dense, BM25, graph, PRF, patch-reverse-engineering).
57
+ - **Zerank-2 reranker** with instruction-following via XML tags, tuned per query intent.
58
+ - **Novel signals** invented for this engine:
59
+ - **Cross-resolution resonance** — L2+L3+L4 consensus boost
60
+ - **Code DNA fingerprinting** — structural similarity (param count, complexity, call count)
61
+ - **Semantic bridges** — virtual graph edges between similar functions
62
+ - **File cohort memory** — files that co-occur in correct answers get boosted across queries
63
+ - **Score distribution shape analysis** — adaptive cutoff detects bimodal / uniform / power-law score distributions
64
+ - **Score gap amplification** — sigmoid sharpening of close scores
65
+ - **Post-rerank filename tie-breaker** — the fix for "correct directory, wrong file" at scale
66
+ - **Adversarial anti-centroid** — penalty for chunks near the worst BM25 hits
67
+ - **Query-to-patch reverse engineering** — generate a hypothetical fix, embed it as a 5th RRF channel
68
+ - **Incremental indexing** with SHA-256 Merkle root hashing. Only changed files are re-embedded. Subsequent `index` runs are fast.
69
+ - **Per-repo isolated storage** under `~/.kinetic/<slug>_<hash>/`. Same-name folders in different parents do not collide. A `manifest.json` records the source path, root hash, file count, and last-indexed timestamp so `kinetic status` can answer "reindex needed?" in <50ms without spinning up the engine.
70
+ - **Hookable everywhere**: MCP server (stdio JSON-RPC), TCP JSON, Python library, Rich CLI.
71
+
72
+ ---
73
+
74
+ ## Install
75
+
76
+ ```bash
77
+ pip install kinetic-context
78
+ ```
79
+
80
+ Requires Python 3.10+. All heavy dependencies (tree-sitter, numpy, networkx, rich) are bundled — no Qdrant/Pinecone/Milvus/Postgres to install.
81
+
82
+ Set your API keys (a Mistral key for embeddings + a Zerank key for reranking):
83
+
84
+ ```bash
85
+ export MISTRAL_API_KEY=...
86
+ export ZEROENTROPY_API_KEY=...
87
+ ```
88
+
89
+ You can also override the embedder / reranker URLs and model IDs in `KCEConfig` if you want to point at a different provider.
90
+
91
+ ---
92
+
93
+ ## Quick start
94
+
95
+ ```bash
96
+ # Index a repo (first run; takes a few minutes for a 1k-file repo)
97
+ kinetic index ./my-repo
98
+
99
+ # Subsequent runs only re-embed files whose SHA-256 hash changed
100
+ kinetic index ./my-repo
101
+
102
+ # Search — returns code blocks with line ranges, not just file paths
103
+ kinetic query "authentication middleware" --code
104
+
105
+ # JSON output (for agent hooks / piping)
106
+ kinetic query "how does routing work" --json | jq '.results[0]'
107
+
108
+ # Check if the index is up to date
109
+ kinetic status ./my-repo
110
+
111
+ # List all indexed repos
112
+ kinetic list
113
+ ```
114
+
115
+ ### Query output example
116
+
117
+ ```
118
+ ────────────────────────────────────────────────────────────────────────
119
+ kinetic-context • semantic_question • zerank • 68ms
120
+ ────────────────────────────────────────────────────────────────────────
121
+ Query: how does routing work in flask
122
+ ────────────────────────────────────────────────────────────────────────
123
+ Found 8 code blocks across 8 files
124
+
125
+ #1 src/flask/sansio/app.py L240-262 (23 lines) • add_url_rule (function) • python
126
+ def add_url_rule(self, rule, endpoint=None, view_func=None, ...)
127
+ 240 │ def add_url_rule(
128
+ 241 │ self,
129
+ 242 │ rule: str,
130
+ 243 │ endpoint: str | None = None,
131
+ ...
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Hooking into coding agents
137
+
138
+ ### MCP server (Claude Code, Cursor, Continue, Zed, anything MCP-aware)
139
+
140
+ Start the MCP server in the background:
141
+
142
+ ```bash
143
+ kinetic mcp
144
+ ```
145
+
146
+ Or add it to your agent's MCP config:
147
+
148
+ ```json
149
+ {
150
+ "mcpServers": {
151
+ "kinetic": {
152
+ "command": "kinetic",
153
+ "args": ["mcp"]
154
+ }
155
+ }
156
+ }
157
+ ```
158
+
159
+ Four tools are exposed:
160
+
161
+ | Tool | Description |
162
+ |---|---|
163
+ | `kinetic_index` | Index (or incrementally update) a repo |
164
+ | `kinetic_query` | Search the indexed codebase, returns code blocks with line ranges |
165
+ | `kinetic_status` | Check whether the index is up to date |
166
+ | `kinetic_list_indexes` | List all indexed repos |
167
+
168
+ ### TCP JSON server (any agent)
169
+
170
+ ```bash
171
+ kinetic serve --port 7878
172
+ ```
173
+
174
+ Send a single-line JSON request, get a single-line JSON response:
175
+
176
+ ```bash
177
+ echo '{"query": "session cookie signing", "top": 5}' | nc localhost 7878
178
+ ```
179
+
180
+ ### Python library
181
+
182
+ ```python
183
+ from kce.engine import KCEEngine
184
+ from kce.config import KCEConfig
185
+ from kce.store.registry import Registry
186
+
187
+ cfg = KCEConfig()
188
+ cfg.index_dir = Registry().resolve("/path/to/repo")
189
+ cfg.ensure_dirs()
190
+ engine = KCEEngine(cfg)
191
+ engine.index("/path/to/repo")
192
+
193
+ result = engine.query("how does authentication work")
194
+ for cid in result.final_chunk_ids[:10]:
195
+ chunk = engine.chunk_index[cid]
196
+ print(f"{chunk.rel_path}:{chunk.start_line}-{chunk.end_line} {chunk.name}")
197
+ print(chunk.content)
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Storage layout
203
+
204
+ Every indexed repo gets its own directory under `~/.kinetic/`:
205
+
206
+ ```
207
+ ~/.kinetic/
208
+ flask_f9cbd6f6/ <- slug = name + short hash of abspath
209
+ manifest.json <- source path, root hash, file count, last indexed
210
+ chunks.jsonl <- one CodeChunk per line
211
+ embeddings.npy <- (N, 1536) float32 matrix
212
+ embeddings_ids.json <- row order
213
+ ckg.graphml <- Code Knowledge Graph
214
+ incremental_state.json <- per-file SHA-256 hashes
215
+ change_log.jsonl <- append-only change history
216
+ embed_cache/embeddings.db <- Mistral API cache (SQLite)
217
+ zerank_cache/rerank.db <- Zerank API cache (SQLite)
218
+ file_summaries.json
219
+ repo_summary.txt
220
+ django_ea20f8f1/
221
+ ...
222
+ ```
223
+
224
+ ### Why per-repo isolation?
225
+
226
+ - Two repos with the same folder name (e.g. `~/work/api` and `~/side/api`) get different slugs because the slug includes a short hash of the absolute path. No collisions.
227
+ - Caches live next to the index, so deleting a repo's index (`kinetic forget`) also frees its cache.
228
+ - The `manifest.json` records a Merkle root hash over all file content hashes. Recomputing this on startup is <50ms even for a 1k-file repo, so `kinetic status` is instant.
229
+
230
+ ### Efficient incremental updates
231
+
232
+ 1. On `kinetic index <repo>`, we first compute the current Merkle root from disk.
233
+ 2. We compare to the stored root in `manifest.json`. If they match, the index is up to date — we're done in <100ms.
234
+ 3. If they differ, we walk the per-file SHA-256 hashes in `incremental_state.json` and identify exactly which files were added, modified, or removed.
235
+ 4. Only those files are re-parsed, re-summarized, and re-embedded. Existing chunks for unchanged files are reused.
236
+ 5. The Mistral embed cache (SQLite, keyed by SHA-256 of the embed text) means even a chunk whose text didn't change but whose `chunk_id` was regenerated will not trigger an API call.
237
+
238
+ For a 1k-file repo where 5 files changed, a re-index takes seconds, not minutes.
239
+
240
+ ---
241
+
242
+ ## Architecture
243
+
244
+ ![Architecture](docs/architecture.png)
245
+
246
+ The pipeline has four layers:
247
+
248
+ 1. **Ingestion** — tree-sitter parses each source file into an AST. The `cAST` chunker walks the AST and produces chunks that respect syntactic boundaries (a function is never split mid-body). Each chunk is enriched with its signature, docstring, decorators, and scope. A Code Knowledge Graph (NetworkX) is built with 8 relationship types: `CALLS`, `INHERITS`, `IMPLEMENTS`, `IMPORTS`, `CONTAINS`, `USES_TYPE`, `OVERRIDES`, `DEPENDS_ON`.
249
+
250
+ 2. **Storage** — chunks go to JSONL, embeddings go to a single numpy matrix on disk (+ L2-normalized in memory for fast cosine), the graph goes to GraphML. Each repo gets its own directory under `~/.kinetic/`. SHA-256 Merkle root hashing drives incremental updates.
251
+
252
+ 3. **Retrieval & Ranking** — the query coordinator picks one of 5 query types (identifier lookup, semantic question, code completion, bug diagnosis, architecture query). For each type, it applies intent-aware boosts (source vs test vs config files), runs multi-query BM25 + dense + graph retrieval, fuses the results with weighted Reciprocal Rank Fusion, applies novel signals (resonance, DNA, semantic bridges, cohort memory), then reranks the top candidates with Zerank-2.
253
+
254
+ 4. **Output** — the final ranked chunks are returned as code blocks with line ranges, signature, and docstring. They can be rendered by the Rich CLI, serialized to JSON, or shipped over MCP / TCP to any coding agent.
255
+
256
+ ---
257
+
258
+ ## Benchmarks
259
+
260
+ We benchmark on two real-world repos with hand-curated query sets. We report Context F1@10, Recall@10, Precision@10, and end-to-end latency. **We deliberately do not compare to other context engines** — those numbers are easy to get wrong and we'd rather show our own results honestly than risk an unfair comparison.
261
+
262
+ ### Aggregate metrics
263
+
264
+ ![Aggregate metrics](docs/benchmarks/aggregate_metrics.png)
265
+
266
+ ### Per-query F1 (sorted, so the worst queries are at the top)
267
+
268
+ ![Per-query F1](docs/benchmarks/per_query_f1.png)
269
+
270
+ ### Query outcome distribution (perfect / partial / failed)
271
+
272
+ ![Perfect vs failed](docs/benchmarks/perfect_vs_failed.png)
273
+
274
+ ### Latency distribution
275
+
276
+ ![Latency distribution](docs/benchmarks/latency_distribution.png)
277
+
278
+ ### Quality vs repository scale
279
+
280
+ ![Scale vs quality](docs/benchmarks/scale_vs_quality.png)
281
+
282
+ ### Numbers
283
+
284
+ | Corpus | Files | Chunks | Graph (nodes/edges) | Queries | F1@10 | Recall@10 | Precision@10 | Avg latency |
285
+ |---|---:|---:|---:|---:|---:|---:|---:|---:|
286
+ | Flask | 83 | 1,382 | 1,594 / 7,906 | 30 | 0.659 | 0.833 | 0.599 | 68 ms |
287
+ | Django (core) | 308 | 7,207 | 6,574 / 46,408 | 30 | 0.647 | 0.867 | 0.559 | 433 ms |
288
+
289
+ The Django benchmark uses the core Django packages (`django/db/`, `django/http/`, `django/urls/`, `django/template/`, `django/forms/`, `django/core/`, `django/contrib/auth/`, `django/contrib/sessions/`) — the parts of Django that real coding agents actually search. The full Django repo includes 3,000+ files of migrations, tests, and docs that bloat the index without improving retrieval quality on real-world queries.
290
+
291
+ Run the benchmarks yourself:
292
+
293
+ ```bash
294
+ git clone https://github.com/pallets/flask /tmp/flask
295
+ git clone https://github.com/django/django /tmp/django
296
+ kinetic index /tmp/flask
297
+ kinetic index /tmp/django
298
+ python scripts/run_bench.py flask
299
+ python scripts/run_bench.py django
300
+ python scripts/gen_charts.py
301
+ ```
302
+
303
+ ---
304
+
305
+ ## Configuration
306
+
307
+ All knobs are in `KCEConfig`. The defaults are tuned for the Mistral Codestral Embed + Zerank-2 combination. You can override:
308
+
309
+ | Setting | Default | What it controls |
310
+ |---|---|---|
311
+ | `mistral_embed_model` | `codestral-embed` | Embedding model |
312
+ | `zerank_model` | `zerank-2` | Reranker model |
313
+ | `chunk_max_tokens` | 512 | Max chunk size |
314
+ | `chunk_overlap_pct` | 0.35 | Chunk overlap |
315
+ | `bm25_k1`, `bm25_b` | 1.5, 0.75 | BM25 params |
316
+ | `rrf_dense`, `rrf_bm25`, `rrf_graph` | 0.75, 0.05, 0.03 | RRF channel weights |
317
+ | `retrieval_top_k` | 50 | Candidates per channel |
318
+ | `rerank_top_n` | 15 | Candidates sent to reranker |
319
+ | `final_top_n` | 10 | Final results returned |
320
+ | `filename_keyword_boost` | 2.0 | Post-rerank filename tie-breaker |
321
+ | `tier_c_penalty` | 0.4 | Penalty for abstract base classes |
322
+ | `context_budget_tokens` | 4096 | Context assembly budget |
323
+
324
+ API keys are read from `MISTRAL_API_KEY` and `ZEROENTROPY_API_KEY` env vars.
325
+
326
+ ---
327
+
328
+ ## Why not just use ripgrep / the IDE's built-in search?
329
+
330
+ Lexical search finds the keyword. It doesn't find the *concept*. Asking "how does routing work in flask" with grep gives you every line containing "route" — most of which is irrelevant. `kinetic-context` returns the 8 functions that actually implement routing, with their full bodies and signatures, in 68ms.
331
+
332
+ ## Why not just stuff the whole repo into the LLM context window?
333
+
334
+ A 1k-file repo is ~500k tokens just for the source. That's expensive, slow, and the LLM's attention degrades badly past ~100k tokens. `kinetic-context` returns the 10 chunks that matter, fits in any context window, and costs 100x less to query.
335
+
336
+ ## Why a Code Knowledge Graph?
337
+
338
+ Because "what calls what" matters. When you ask "where is `request` used?", the graph says "the `request` proxy is defined in `flask/globals.py`, used in 47 places, and its setter is in `flask/app.py`". Pure lexical search sees the word `request` 500 times. The graph sees the relationship.
339
+
340
+ ---
341
+
342
+ ## License
343
+
344
+ MIT. See [LICENSE](LICENSE).
345
+
346
+ ## Contributing
347
+
348
+ Issues and PRs welcome at [github.com/zai-org/kinetic-context](https://github.com/zai-org/kinetic-context).
@@ -0,0 +1,308 @@
1
+ # kinetic-context
2
+
3
+ > Repository-level code context engine — find the right code, fast.
4
+
5
+ `kinetic-context` is a self-contained, installable code context engine. Point it at any repository and it builds a multi-layer index (AST chunks + embeddings + a code knowledge graph + BM25) that you can query with natural language or identifiers. It returns **code blocks with line ranges** — not just file paths — ready to paste into an LLM prompt.
6
+
7
+ It is designed to be the context layer for coding agents. It ships with a Rich CLI, an MCP server (so Claude Code, Cursor, Continue, and Zed can mount it natively), a TCP JSON mode for any other agent, and a Python library.
8
+
9
+ ---
10
+
11
+ ## Highlights
12
+
13
+ - **Multi-language**: Python, JavaScript, TypeScript, Go, Rust, Java — via tree-sitter.
14
+ - **Structure-aware chunking** (`cAST`): never splits a function mid-body. 35% overlap. Hierarchical summaries at file and repository level.
15
+ - **Hybrid retrieval**: dense (Mistral Codestral Embed, 1536-dim) + BM25 (code-aware tokenizer that splits camelCase, snake_case, and dotted identifiers) + a Code Knowledge Graph with 8 relationship types.
16
+ - **Reciprocal Rank Fusion** with brute-force-optimized weights across 5 channels (dense, BM25, graph, PRF, patch-reverse-engineering).
17
+ - **Zerank-2 reranker** with instruction-following via XML tags, tuned per query intent.
18
+ - **Novel signals** invented for this engine:
19
+ - **Cross-resolution resonance** — L2+L3+L4 consensus boost
20
+ - **Code DNA fingerprinting** — structural similarity (param count, complexity, call count)
21
+ - **Semantic bridges** — virtual graph edges between similar functions
22
+ - **File cohort memory** — files that co-occur in correct answers get boosted across queries
23
+ - **Score distribution shape analysis** — adaptive cutoff detects bimodal / uniform / power-law score distributions
24
+ - **Score gap amplification** — sigmoid sharpening of close scores
25
+ - **Post-rerank filename tie-breaker** — the fix for "correct directory, wrong file" at scale
26
+ - **Adversarial anti-centroid** — penalty for chunks near the worst BM25 hits
27
+ - **Query-to-patch reverse engineering** — generate a hypothetical fix, embed it as a 5th RRF channel
28
+ - **Incremental indexing** with SHA-256 Merkle root hashing. Only changed files are re-embedded. Subsequent `index` runs are fast.
29
+ - **Per-repo isolated storage** under `~/.kinetic/<slug>_<hash>/`. Same-name folders in different parents do not collide. A `manifest.json` records the source path, root hash, file count, and last-indexed timestamp so `kinetic status` can answer "reindex needed?" in <50ms without spinning up the engine.
30
+ - **Hookable everywhere**: MCP server (stdio JSON-RPC), TCP JSON, Python library, Rich CLI.
31
+
32
+ ---
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ pip install kinetic-context
38
+ ```
39
+
40
+ Requires Python 3.10+. All heavy dependencies (tree-sitter, numpy, networkx, rich) are bundled — no Qdrant/Pinecone/Milvus/Postgres to install.
41
+
42
+ Set your API keys (a Mistral key for embeddings + a Zerank key for reranking):
43
+
44
+ ```bash
45
+ export MISTRAL_API_KEY=...
46
+ export ZEROENTROPY_API_KEY=...
47
+ ```
48
+
49
+ You can also override the embedder / reranker URLs and model IDs in `KCEConfig` if you want to point at a different provider.
50
+
51
+ ---
52
+
53
+ ## Quick start
54
+
55
+ ```bash
56
+ # Index a repo (first run; takes a few minutes for a 1k-file repo)
57
+ kinetic index ./my-repo
58
+
59
+ # Subsequent runs only re-embed files whose SHA-256 hash changed
60
+ kinetic index ./my-repo
61
+
62
+ # Search — returns code blocks with line ranges, not just file paths
63
+ kinetic query "authentication middleware" --code
64
+
65
+ # JSON output (for agent hooks / piping)
66
+ kinetic query "how does routing work" --json | jq '.results[0]'
67
+
68
+ # Check if the index is up to date
69
+ kinetic status ./my-repo
70
+
71
+ # List all indexed repos
72
+ kinetic list
73
+ ```
74
+
75
+ ### Query output example
76
+
77
+ ```
78
+ ────────────────────────────────────────────────────────────────────────
79
+ kinetic-context • semantic_question • zerank • 68ms
80
+ ────────────────────────────────────────────────────────────────────────
81
+ Query: how does routing work in flask
82
+ ────────────────────────────────────────────────────────────────────────
83
+ Found 8 code blocks across 8 files
84
+
85
+ #1 src/flask/sansio/app.py L240-262 (23 lines) • add_url_rule (function) • python
86
+ def add_url_rule(self, rule, endpoint=None, view_func=None, ...)
87
+ 240 │ def add_url_rule(
88
+ 241 │ self,
89
+ 242 │ rule: str,
90
+ 243 │ endpoint: str | None = None,
91
+ ...
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Hooking into coding agents
97
+
98
+ ### MCP server (Claude Code, Cursor, Continue, Zed, anything MCP-aware)
99
+
100
+ Start the MCP server in the background:
101
+
102
+ ```bash
103
+ kinetic mcp
104
+ ```
105
+
106
+ Or add it to your agent's MCP config:
107
+
108
+ ```json
109
+ {
110
+ "mcpServers": {
111
+ "kinetic": {
112
+ "command": "kinetic",
113
+ "args": ["mcp"]
114
+ }
115
+ }
116
+ }
117
+ ```
118
+
119
+ Four tools are exposed:
120
+
121
+ | Tool | Description |
122
+ |---|---|
123
+ | `kinetic_index` | Index (or incrementally update) a repo |
124
+ | `kinetic_query` | Search the indexed codebase, returns code blocks with line ranges |
125
+ | `kinetic_status` | Check whether the index is up to date |
126
+ | `kinetic_list_indexes` | List all indexed repos |
127
+
128
+ ### TCP JSON server (any agent)
129
+
130
+ ```bash
131
+ kinetic serve --port 7878
132
+ ```
133
+
134
+ Send a single-line JSON request, get a single-line JSON response:
135
+
136
+ ```bash
137
+ echo '{"query": "session cookie signing", "top": 5}' | nc localhost 7878
138
+ ```
139
+
140
+ ### Python library
141
+
142
+ ```python
143
+ from kce.engine import KCEEngine
144
+ from kce.config import KCEConfig
145
+ from kce.store.registry import Registry
146
+
147
+ cfg = KCEConfig()
148
+ cfg.index_dir = Registry().resolve("/path/to/repo")
149
+ cfg.ensure_dirs()
150
+ engine = KCEEngine(cfg)
151
+ engine.index("/path/to/repo")
152
+
153
+ result = engine.query("how does authentication work")
154
+ for cid in result.final_chunk_ids[:10]:
155
+ chunk = engine.chunk_index[cid]
156
+ print(f"{chunk.rel_path}:{chunk.start_line}-{chunk.end_line} {chunk.name}")
157
+ print(chunk.content)
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Storage layout
163
+
164
+ Every indexed repo gets its own directory under `~/.kinetic/`:
165
+
166
+ ```
167
+ ~/.kinetic/
168
+ flask_f9cbd6f6/ <- slug = name + short hash of abspath
169
+ manifest.json <- source path, root hash, file count, last indexed
170
+ chunks.jsonl <- one CodeChunk per line
171
+ embeddings.npy <- (N, 1536) float32 matrix
172
+ embeddings_ids.json <- row order
173
+ ckg.graphml <- Code Knowledge Graph
174
+ incremental_state.json <- per-file SHA-256 hashes
175
+ change_log.jsonl <- append-only change history
176
+ embed_cache/embeddings.db <- Mistral API cache (SQLite)
177
+ zerank_cache/rerank.db <- Zerank API cache (SQLite)
178
+ file_summaries.json
179
+ repo_summary.txt
180
+ django_ea20f8f1/
181
+ ...
182
+ ```
183
+
184
+ ### Why per-repo isolation?
185
+
186
+ - Two repos with the same folder name (e.g. `~/work/api` and `~/side/api`) get different slugs because the slug includes a short hash of the absolute path. No collisions.
187
+ - Caches live next to the index, so deleting a repo's index (`kinetic forget`) also frees its cache.
188
+ - The `manifest.json` records a Merkle root hash over all file content hashes. Recomputing this on startup is <50ms even for a 1k-file repo, so `kinetic status` is instant.
189
+
190
+ ### Efficient incremental updates
191
+
192
+ 1. On `kinetic index <repo>`, we first compute the current Merkle root from disk.
193
+ 2. We compare to the stored root in `manifest.json`. If they match, the index is up to date — we're done in <100ms.
194
+ 3. If they differ, we walk the per-file SHA-256 hashes in `incremental_state.json` and identify exactly which files were added, modified, or removed.
195
+ 4. Only those files are re-parsed, re-summarized, and re-embedded. Existing chunks for unchanged files are reused.
196
+ 5. The Mistral embed cache (SQLite, keyed by SHA-256 of the embed text) means even a chunk whose text didn't change but whose `chunk_id` was regenerated will not trigger an API call.
197
+
198
+ For a 1k-file repo where 5 files changed, a re-index takes seconds, not minutes.
199
+
200
+ ---
201
+
202
+ ## Architecture
203
+
204
+ ![Architecture](docs/architecture.png)
205
+
206
+ The pipeline has four layers:
207
+
208
+ 1. **Ingestion** — tree-sitter parses each source file into an AST. The `cAST` chunker walks the AST and produces chunks that respect syntactic boundaries (a function is never split mid-body). Each chunk is enriched with its signature, docstring, decorators, and scope. A Code Knowledge Graph (NetworkX) is built with 8 relationship types: `CALLS`, `INHERITS`, `IMPLEMENTS`, `IMPORTS`, `CONTAINS`, `USES_TYPE`, `OVERRIDES`, `DEPENDS_ON`.
209
+
210
+ 2. **Storage** — chunks go to JSONL, embeddings go to a single numpy matrix on disk (+ L2-normalized in memory for fast cosine), the graph goes to GraphML. Each repo gets its own directory under `~/.kinetic/`. SHA-256 Merkle root hashing drives incremental updates.
211
+
212
+ 3. **Retrieval & Ranking** — the query coordinator picks one of 5 query types (identifier lookup, semantic question, code completion, bug diagnosis, architecture query). For each type, it applies intent-aware boosts (source vs test vs config files), runs multi-query BM25 + dense + graph retrieval, fuses the results with weighted Reciprocal Rank Fusion, applies novel signals (resonance, DNA, semantic bridges, cohort memory), then reranks the top candidates with Zerank-2.
213
+
214
+ 4. **Output** — the final ranked chunks are returned as code blocks with line ranges, signature, and docstring. They can be rendered by the Rich CLI, serialized to JSON, or shipped over MCP / TCP to any coding agent.
215
+
216
+ ---
217
+
218
+ ## Benchmarks
219
+
220
+ We benchmark on two real-world repos with hand-curated query sets. We report Context F1@10, Recall@10, Precision@10, and end-to-end latency. **We deliberately do not compare to other context engines** — those numbers are easy to get wrong and we'd rather show our own results honestly than risk an unfair comparison.
221
+
222
+ ### Aggregate metrics
223
+
224
+ ![Aggregate metrics](docs/benchmarks/aggregate_metrics.png)
225
+
226
+ ### Per-query F1 (sorted, so the worst queries are at the top)
227
+
228
+ ![Per-query F1](docs/benchmarks/per_query_f1.png)
229
+
230
+ ### Query outcome distribution (perfect / partial / failed)
231
+
232
+ ![Perfect vs failed](docs/benchmarks/perfect_vs_failed.png)
233
+
234
+ ### Latency distribution
235
+
236
+ ![Latency distribution](docs/benchmarks/latency_distribution.png)
237
+
238
+ ### Quality vs repository scale
239
+
240
+ ![Scale vs quality](docs/benchmarks/scale_vs_quality.png)
241
+
242
+ ### Numbers
243
+
244
+ | Corpus | Files | Chunks | Graph (nodes/edges) | Queries | F1@10 | Recall@10 | Precision@10 | Avg latency |
245
+ |---|---:|---:|---:|---:|---:|---:|---:|---:|
246
+ | Flask | 83 | 1,382 | 1,594 / 7,906 | 30 | 0.659 | 0.833 | 0.599 | 68 ms |
247
+ | Django (core) | 308 | 7,207 | 6,574 / 46,408 | 30 | 0.647 | 0.867 | 0.559 | 433 ms |
248
+
249
+ The Django benchmark uses the core Django packages (`django/db/`, `django/http/`, `django/urls/`, `django/template/`, `django/forms/`, `django/core/`, `django/contrib/auth/`, `django/contrib/sessions/`) — the parts of Django that real coding agents actually search. The full Django repo includes 3,000+ files of migrations, tests, and docs that bloat the index without improving retrieval quality on real-world queries.
250
+
251
+ Run the benchmarks yourself:
252
+
253
+ ```bash
254
+ git clone https://github.com/pallets/flask /tmp/flask
255
+ git clone https://github.com/django/django /tmp/django
256
+ kinetic index /tmp/flask
257
+ kinetic index /tmp/django
258
+ python scripts/run_bench.py flask
259
+ python scripts/run_bench.py django
260
+ python scripts/gen_charts.py
261
+ ```
262
+
263
+ ---
264
+
265
+ ## Configuration
266
+
267
+ All knobs are in `KCEConfig`. The defaults are tuned for the Mistral Codestral Embed + Zerank-2 combination. You can override:
268
+
269
+ | Setting | Default | What it controls |
270
+ |---|---|---|
271
+ | `mistral_embed_model` | `codestral-embed` | Embedding model |
272
+ | `zerank_model` | `zerank-2` | Reranker model |
273
+ | `chunk_max_tokens` | 512 | Max chunk size |
274
+ | `chunk_overlap_pct` | 0.35 | Chunk overlap |
275
+ | `bm25_k1`, `bm25_b` | 1.5, 0.75 | BM25 params |
276
+ | `rrf_dense`, `rrf_bm25`, `rrf_graph` | 0.75, 0.05, 0.03 | RRF channel weights |
277
+ | `retrieval_top_k` | 50 | Candidates per channel |
278
+ | `rerank_top_n` | 15 | Candidates sent to reranker |
279
+ | `final_top_n` | 10 | Final results returned |
280
+ | `filename_keyword_boost` | 2.0 | Post-rerank filename tie-breaker |
281
+ | `tier_c_penalty` | 0.4 | Penalty for abstract base classes |
282
+ | `context_budget_tokens` | 4096 | Context assembly budget |
283
+
284
+ API keys are read from `MISTRAL_API_KEY` and `ZEROENTROPY_API_KEY` env vars.
285
+
286
+ ---
287
+
288
+ ## Why not just use ripgrep / the IDE's built-in search?
289
+
290
+ Lexical search finds the keyword. It doesn't find the *concept*. Asking "how does routing work in flask" with grep gives you every line containing "route" — most of which is irrelevant. `kinetic-context` returns the 8 functions that actually implement routing, with their full bodies and signatures, in 68ms.
291
+
292
+ ## Why not just stuff the whole repo into the LLM context window?
293
+
294
+ A 1k-file repo is ~500k tokens just for the source. That's expensive, slow, and the LLM's attention degrades badly past ~100k tokens. `kinetic-context` returns the 10 chunks that matter, fits in any context window, and costs 100x less to query.
295
+
296
+ ## Why a Code Knowledge Graph?
297
+
298
+ Because "what calls what" matters. When you ask "where is `request` used?", the graph says "the `request` proxy is defined in `flask/globals.py`, used in 47 places, and its setter is in `flask/app.py`". Pure lexical search sees the word `request` 500 times. The graph sees the relationship.
299
+
300
+ ---
301
+
302
+ ## License
303
+
304
+ MIT. See [LICENSE](LICENSE).
305
+
306
+ ## Contributing
307
+
308
+ Issues and PRs welcome at [github.com/zai-org/kinetic-context](https://github.com/zai-org/kinetic-context).
@@ -0,0 +1,5 @@
1
+ """kinetic-context — repository-level code context engine."""
2
+ __version__ = "0.2.0"
3
+
4
+ from .engine import KCEEngine # noqa: F401
5
+ from .config import KCEConfig # noqa: F401