codecortex 0.14.2__tar.gz → 0.15.2__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.
Potentially problematic release.
This version of codecortex might be problematic. Click here for more details.
- {codecortex-0.14.2/src/codecortex.egg-info → codecortex-0.15.2}/PKG-INFO +119 -10
- {codecortex-0.14.2 → codecortex-0.15.2}/README.md +117 -8
- {codecortex-0.14.2 → codecortex-0.15.2}/pyproject.toml +5 -1
- {codecortex-0.14.2 → codecortex-0.15.2/src/codecortex.egg-info}/PKG-INFO +119 -10
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codecortex.egg-info/SOURCES.txt +3 -0
- codecortex-0.15.2/src/codeintel/__init__.py +1 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/__main__.py +6 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/query.py +40 -11
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/status.py +24 -4
- codecortex-0.15.2/src/codeintel/containment.py +80 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/doctor.py +7 -1
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/gateway.py +28 -4
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/grapher.py +26 -6
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/http_server.py +10 -2
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/indexer.py +137 -30
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/mapper.py +27 -2
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/onboarding.py +13 -3
- codecortex-0.15.2/src/codeintel/providers/graph.py +1264 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/providers/semantic.py +29 -8
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/searcher.py +32 -6
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/semantic_db.py +91 -2
- codecortex-0.15.2/src/codeintel/source_kind.py +191 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_chunking.py +62 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_cli_commands.py +46 -1
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_doctor.py +78 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_gateway.py +91 -0
- codecortex-0.15.2/tests/test_graph_provider.py +801 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_graph_real.py +8 -2
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_graph_stdin.py +9 -2
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_grapher.py +37 -2
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_hardening.py +2 -2
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_http_auth.py +7 -1
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_http_server.py +10 -4
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_mapper.py +5 -2
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_rbac.py +170 -3
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_reindexer.py +92 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_rerank.py +18 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_semantic_provider.py +16 -0
- codecortex-0.15.2/tests/test_source_kind.py +228 -0
- codecortex-0.14.2/src/codeintel/__init__.py +0 -1
- codecortex-0.14.2/src/codeintel/providers/graph.py +0 -717
- codecortex-0.14.2/tests/test_graph_provider.py +0 -332
- {codecortex-0.14.2 → codecortex-0.15.2}/LICENSE +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/setup.cfg +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codecortex.egg-info/dependency_links.txt +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codecortex.egg-info/entry_points.txt +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codecortex.egg-info/requires.txt +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codecortex.egg-info/top_level.txt +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/auth.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/cache.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/__init__.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/_common.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/doctor.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/gen_token.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/graph.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/index.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/install.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/map.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/reset.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/serve.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/serve_http.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/commands/setup.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/config.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/injector.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/installer.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/logconfig.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/metrics.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/policy.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/provider.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/providers/__init__.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/providers/lsp.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/providers/none.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/py.typed +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/reindexer.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/reset.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/server.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/term.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/verify.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/viewer/__init__.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/src/codeintel/viewer/graph_template.html +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_cache.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_cli_help.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_config.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_e2e.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_engine_adoption.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_enterprise.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_installer.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_integration.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_lsp_provider.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_lsp_real.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_mcp_handshake.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_mcp_server.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_model_dimension.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_never_raise.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_onboarding.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_reset.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_term.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_treesitter.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_verify.py +0 -0
- {codecortex-0.14.2 → codecortex-0.15.2}/tests/test_verify_call.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.2
|
|
4
4
|
Summary: Local-first, MCP-native code-intelligence server — graph, LSP, and semantic search behind one safe code.query tool for coding agents.
|
|
5
5
|
Author: Shammai Hamilton
|
|
6
6
|
License-Expression: MIT
|
|
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/hamilton-sky/codeintel
|
|
|
9
9
|
Project-URL: Issues, https://github.com/hamilton-sky/codeintel/issues
|
|
10
10
|
Project-URL: Changelog, https://github.com/hamilton-sky/codeintel/blob/main/CHANGELOG.md
|
|
11
11
|
Keywords: mcp,model-context-protocol,code-intelligence,code-search,llm,agents,lsp,semantic-search,knowledge-graph,static-analysis,developer-tools
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Environment :: Console
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
@@ -40,6 +40,16 @@ Dynamic: license-file
|
|
|
40
40
|
**One MCP tool that lets a coding agent search, trace, and *understand* a codebase — structurally, not by grepping.** codeintel unifies three engines — a call/import **graph**, an **LSP** for exact symbols, and **semantic** embedding search — behind a single `code.query` call that routes to the right engine, caches the answer, and **never throws**. The agent always gets back a clean, well-formed result to reason over.
|
|
41
41
|
|
|
42
42
|
[](https://github.com/hamilton-sky/codeintel/actions/workflows/ci.yml)
|
|
43
|
+
[](https://pypi.org/project/codecortex/)
|
|
44
|
+
[](https://pypi.org/project/codecortex/)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
|
|
47
|
+
> **Status: beta (`0.x`), and young.** The `code.query` surface is one call and has been stable
|
|
48
|
+
> since `0.8`, the suite is thorough, and every release is gated by a canary that runs a real query
|
|
49
|
+
> against a built wheel. But this is a new project with a single maintainer, and each time it has
|
|
50
|
+
> been pointed at an unfamiliar codebase it has found real bugs. **Use it locally, on a developer
|
|
51
|
+
> machine, for a single user** — that is the case it is built and tested for. Before relying on it
|
|
52
|
+
> for anything beyond that, read **[Project status](#project-status)**.
|
|
43
53
|
|
|
44
54
|

|
|
45
55
|
|
|
@@ -85,10 +95,24 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
85
95
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
86
96
|
| **Impact of your uncommitted edits** | `changed` | graph | changed files → impacted symbols |
|
|
87
97
|
| Refactor-risk hotspots | `hotspots` | graph | highest complexity / fan-in symbols |
|
|
88
|
-
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers |
|
|
98
|
+
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers, **verified against the source** — [treat as candidates, not instructions](#deadcode-is-a-candidate-list-not-a-delete-list) |
|
|
89
99
|
|
|
90
100
|
Pin one engine with `--engine graph│lsp│semantic`, or fan out with `--engine both` / `all` to merge results.
|
|
91
101
|
|
|
102
|
+
#### `deadcode` is a candidate list, not a delete list
|
|
103
|
+
|
|
104
|
+
`deadcode` is the one op whose output invites a destructive action, so it gets an explicit caveat.
|
|
105
|
+
Every hit is re-read and verified against the source before it is reported, which removes the
|
|
106
|
+
common false positives — but **no reachability analysis sees every caller.** Dynamic dispatch,
|
|
107
|
+
registries and decorators, `getattr` lookups, entry points declared in packaging metadata, plugin
|
|
108
|
+
discovery, reflection, and calls from languages the graph does not parse are all invisible to it.
|
|
109
|
+
Through `0.14.x` it was systematically wrong on callback-heavy code and confident about it; that
|
|
110
|
+
class of defect is fixed, but the underlying limit is structural and permanent.
|
|
111
|
+
|
|
112
|
+
**So: review each hit before deleting anything, and never wire `deadcode` into an agent that
|
|
113
|
+
deletes without a human in the loop.** Used as a ranked list of *places worth looking*, it is
|
|
114
|
+
genuinely useful. Used as a work order, it will eventually remove live code.
|
|
115
|
+
|
|
92
116
|
**Example — "who uses `safe_null_result`?"**
|
|
93
117
|
|
|
94
118
|
```jsonc
|
|
@@ -262,13 +286,25 @@ Every `Gateway.query()` call returns a dict with exactly these keys:
|
|
|
262
286
|
{"ok": true, "op": "search", "target": "auth", "result": null, "engine": "semantic", "cached": false}
|
|
263
287
|
```
|
|
264
288
|
|
|
265
|
-
`ok` is always `true`. `result` is `null` when no provider has an answer — never an exception, never a 500.
|
|
289
|
+
`ok` is always `true`. `result` is `null` when no provider has an answer — never an exception, never a 500. Callers must check `result is not None` before using the value.
|
|
290
|
+
|
|
291
|
+
The optional keys are the ones worth reading when an answer surprises you:
|
|
292
|
+
|
|
293
|
+
| Key | Meaning |
|
|
294
|
+
|---|---|
|
|
295
|
+
| `reason` | Why `result` is null — `engine-unavailable`, `no-result`, `not-in-graph` (the symbol isn't in the index — usually a stale index), `project-not-indexed`, `unsupported-op`, `root-not-allowed-for-role` (RBAC) |
|
|
296
|
+
| `hint` | The specific command that resolves this `reason`, when there is one |
|
|
297
|
+
| `engine` | Which engine actually answered — not necessarily the one you asked for, under `auto` |
|
|
298
|
+
| `cached` | Whether it came from the content-hash cache |
|
|
299
|
+
| `reindexing` | Present and `true` when a reindex was running, i.e. the answer reflects the last *completed* index. See [Keeping answers fresh](#keeping-answers-fresh) |
|
|
300
|
+
|
|
301
|
+
`codeintel query --json` prints this envelope from the CLI.
|
|
266
302
|
|
|
267
303
|
## Engines
|
|
268
304
|
|
|
269
305
|
| Engine | Key ops | Install prereq |
|
|
270
306
|
|---|---|---|
|
|
271
|
-
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp`
|
|
307
|
+
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x** on PATH (`pip install 'codebase-memory-mcp==0.9.*'`) — 0.10.x changed its response format and returns nothing for every op but resolution; see [docs/graph.md](docs/graph.md) |
|
|
272
308
|
| `lsp` | `symbol`, `overview`, `context` | `uvx` on PATH — serena is fetched from GitHub on first use; see [docs/lsp.md](docs/lsp.md) |
|
|
273
309
|
| `semantic` | `search`, `context` | `fastembed` + `sqlite-vec` (installed with the package) — see [docs/semantic.md](docs/semantic.md) |
|
|
274
310
|
|
|
@@ -325,7 +361,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
325
361
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
326
362
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
327
363
|
| `codeintel serve-http [--host HOST] [--port 8766] [--allow-remote] [--token TOKEN]` | Start the HTTP transport (loopback-only unless `--allow-remote`; `--token` requires a bearer token on every request) |
|
|
328
|
-
| `codeintel query --op OP --target TARGET [--engine auto] [--project-root DIR]` | Run a single query and print the result |
|
|
364
|
+
| `codeintel query --op OP --target TARGET [--engine auto] [--project-root DIR] [--json]` | Run a single query and print the result |
|
|
329
365
|
| `codeintel status [project_root]` | Show engine availability and index age |
|
|
330
366
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
331
367
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
@@ -335,6 +371,14 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
335
371
|
|
|
336
372
|
Human-facing commands (`doctor`, `status`, `query`, `setup`, `reset`) honor `--no-color` / `NO_COLOR` and `--ascii`, and auto-degrade to plain text when piped.
|
|
337
373
|
|
|
374
|
+
**Exit codes**, so a `make` target or CI step can gate on `$?`:
|
|
375
|
+
|
|
376
|
+
| | |
|
|
377
|
+
|---|---|
|
|
378
|
+
| `0` | The command did its job. For `query` this includes an empty result — "nothing found" is an answer, not a failure. |
|
|
379
|
+
| `1` | The command could not do its job: a file it exists to write wasn't written (`map`, `graph`), an index didn't happen (`index`), a project root doesn't exist, or an engine is unhealthy (`doctor`, `setup`). |
|
|
380
|
+
| `2` | Bad usage — an unknown command or a missing required flag. |
|
|
381
|
+
|
|
338
382
|
## Config
|
|
339
383
|
|
|
340
384
|
Create `.codeintel.toml` at your project root to override defaults:
|
|
@@ -362,6 +406,7 @@ Config is **validated on load** — an out-of-range number, a misspelled enum, o
|
|
|
362
406
|
| `CODEINTEL_HTTP_ACCESS_LOG=1` | One log line per HTTP request (method, path, status, latency) |
|
|
363
407
|
| `CODEINTEL_DEBUG=1` | Log the full traceback of any error the never-throw contract swallows (silent by default) — the switch for diagnosing an unexpected `null` |
|
|
364
408
|
| `CODEINTEL_REINDEX=off` | Disable the background reindexer; queries then index inline to stay fresh |
|
|
409
|
+
| `CODEINTEL_HOME` | Where the index cache lives (default `~/.codeintel`). Set this when the process has **no resolvable home directory** — a container running as a UID with no passwd entry and no `$HOME`, which is common when an agent runs in one. Without it, `Path.home()` raises and every command fails somewhere far from the cause. |
|
|
365
410
|
|
|
366
411
|
## Privacy & dependencies
|
|
367
412
|
|
|
@@ -439,6 +484,63 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
439
484
|
-e CODEINTEL_HTTP_TOKEN="$(openssl rand -hex 32)" codeintel
|
|
440
485
|
```
|
|
441
486
|
|
|
487
|
+
## Project status
|
|
488
|
+
|
|
489
|
+
An honest picture, so you can decide what to trust this with.
|
|
490
|
+
|
|
491
|
+
**What's solid.** The suite is large and real — more test code than source, a coverage floor
|
|
492
|
+
enforced in CI, and fault-injection tests behind the never-raise contract. CI runs lint, `mypy`,
|
|
493
|
+
and the full suite on Python 3.11/3.12/3.13, then builds the wheel, installs it into a clean
|
|
494
|
+
environment, and runs a **release canary** that registers the build with Codex and Claude Code in a
|
|
495
|
+
throwaway `HOME`, boots the server those configs name, and asserts on the answer text of a real
|
|
496
|
+
`code.query`. A release that installs into a file no host reads, or that boots and answers nothing,
|
|
497
|
+
fails before it ships. The `code.query` envelope has been stable since `0.8`.
|
|
498
|
+
|
|
499
|
+
**What's young.** The project is pre-1.0 and moves fast. The honest signal is in the
|
|
500
|
+
[CHANGELOG](CHANGELOG.md): `0.15.0` and `0.15.1` were written almost entirely from pointing the
|
|
501
|
+
tool at four repositories it had never seen, and several of those defects had survived multiple
|
|
502
|
+
adversarial review rounds. **The rate at which new codebases surface new bugs has not yet flattened.**
|
|
503
|
+
Expect to be the first person to hit something, and please report it — see below.
|
|
504
|
+
|
|
505
|
+
**Use it for.** Local, single-user code intelligence on a developer machine. That is the designed
|
|
506
|
+
case, it is the tested case, and the blast radius of a wrong answer is a wasted tool call: the
|
|
507
|
+
safe-null contract means a failing engine degrades to `null` with a reason, so your agent falls
|
|
508
|
+
back to grep rather than crashing.
|
|
509
|
+
|
|
510
|
+
**Be careful with.**
|
|
511
|
+
|
|
512
|
+
| Area | Why |
|
|
513
|
+
|---|---|
|
|
514
|
+
| `deadcode` | It suggests deletions and cannot see every caller — [read the caveat](#deadcode-is-a-candidate-list-not-a-delete-list). |
|
|
515
|
+
| Non-loopback serving | `serve-http` is stdlib `http.server`. It binds loopback by default for a reason; front it with a reverse proxy and see [docs/deploy.md](docs/deploy.md). |
|
|
516
|
+
| RBAC between **untrusting** tenants | It separates privilege levels among callers you already trust. It is not a wall against an adversary with write access to their own root — see the warning in [docs/deploy.md](docs/deploy.md). |
|
|
517
|
+
| Unattended automation | Anything that acts on a result without a human reading it deserves a pilot first. |
|
|
518
|
+
|
|
519
|
+
**On the test numbers.** The suite is large and the coverage floor is enforced, but read the figure
|
|
520
|
+
with its caveat: the graph and LSP backends are external binaries that are **not installed in CI**,
|
|
521
|
+
so those two engines are exercised against hand-authored mocks rather than the real wire contract,
|
|
522
|
+
and the release canary — which does assert on real answer text against a built wheel — currently
|
|
523
|
+
covers the semantic engine only. Line coverage measures how much of the intended behavior runs, not
|
|
524
|
+
how much of reality it has met.
|
|
525
|
+
|
|
526
|
+
**The honest one-paragraph version.** codeintel has been run on very few repositories its author did
|
|
527
|
+
not write, and that is where its bugs have come from — every fix in `0.15.x` came from pointing it
|
|
528
|
+
at an unfamiliar codebase. Its characteristic failure mode is **answering confidently from the
|
|
529
|
+
wrong index rather than failing loudly**, which the never-raise contract makes harder to notice: a
|
|
530
|
+
wrong answer and a right one are the same shape. Run `codeintel doctor` before trusting a repo-wide
|
|
531
|
+
answer, treat `deadcode` as candidates for review, and if something looks off please
|
|
532
|
+
[report it](#reporting-a-problem) — an issue from someone who is not the author is the single most
|
|
533
|
+
useful thing this project can receive right now.
|
|
534
|
+
|
|
535
|
+
**Engine coverage depends on external binaries.** Semantic search works out of the box. The graph
|
|
536
|
+
engine needs `codebase-memory-mcp` and the LSP engine needs `uvx` on `PATH` — without them those
|
|
537
|
+
engines safe-null and you get a fraction of the capability table above. `codeintel setup --all`
|
|
538
|
+
installs what it can and `codeintel doctor` tells you exactly what is missing and how to fix it.
|
|
539
|
+
Run `doctor` first if the tool seems quieter than the docs suggest.
|
|
540
|
+
|
|
541
|
+
**Maintenance.** One maintainer, MIT licensed, issues and PRs welcome. There is no support
|
|
542
|
+
guarantee — factor that into anything load-bearing.
|
|
543
|
+
|
|
442
544
|
## Reporting a problem
|
|
443
545
|
|
|
444
546
|
`codeintel doctor --json` prints a complete, machine-readable picture of what's installed, what's
|
|
@@ -452,9 +554,16 @@ codeintel doctor --json
|
|
|
452
554
|
It reports only local engine and index state. Over the HTTP transport the `registrations` field —
|
|
453
555
|
which names agent config files on the machine running the server — is deliberately omitted.
|
|
454
556
|
|
|
455
|
-
If a *result* looks wrong rather than a command failing,
|
|
456
|
-
|
|
457
|
-
|
|
557
|
+
If a *result* looks wrong rather than a command failing, send the envelope rather than the
|
|
558
|
+
rendered text:
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
codeintel query --op callers --target yourSymbol --json
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
`engine` says which engine answered, `cached` whether it came from the cache, `reindexing` whether
|
|
565
|
+
the index was mid-rebuild, and `reason`/`hint` why an empty answer was empty. Those five fields are
|
|
566
|
+
usually the whole diagnosis.
|
|
458
567
|
|
|
459
568
|
## Development
|
|
460
569
|
|
|
@@ -463,7 +572,7 @@ git clone https://github.com/hamilton-sky/codeintel.git
|
|
|
463
572
|
cd codeintel
|
|
464
573
|
pip install -e .[dev]
|
|
465
574
|
|
|
466
|
-
pytest tests/ -q # ~
|
|
575
|
+
pytest tests/ -q # ~620 tests, ~30s; fails under 83% coverage
|
|
467
576
|
ruff check src tests # lint
|
|
468
577
|
mypy # types (src/ only)
|
|
469
578
|
```
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
**One MCP tool that lets a coding agent search, trace, and *understand* a codebase — structurally, not by grepping.** codeintel unifies three engines — a call/import **graph**, an **LSP** for exact symbols, and **semantic** embedding search — behind a single `code.query` call that routes to the right engine, caches the answer, and **never throws**. The agent always gets back a clean, well-formed result to reason over.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/hamilton-sky/codeintel/actions/workflows/ci.yml)
|
|
6
|
+
[](https://pypi.org/project/codecortex/)
|
|
7
|
+
[](https://pypi.org/project/codecortex/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
> **Status: beta (`0.x`), and young.** The `code.query` surface is one call and has been stable
|
|
11
|
+
> since `0.8`, the suite is thorough, and every release is gated by a canary that runs a real query
|
|
12
|
+
> against a built wheel. But this is a new project with a single maintainer, and each time it has
|
|
13
|
+
> been pointed at an unfamiliar codebase it has found real bugs. **Use it locally, on a developer
|
|
14
|
+
> machine, for a single user** — that is the case it is built and tested for. Before relying on it
|
|
15
|
+
> for anything beyond that, read **[Project status](#project-status)**.
|
|
6
16
|
|
|
7
17
|

|
|
8
18
|
|
|
@@ -48,10 +58,24 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
48
58
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
49
59
|
| **Impact of your uncommitted edits** | `changed` | graph | changed files → impacted symbols |
|
|
50
60
|
| Refactor-risk hotspots | `hotspots` | graph | highest complexity / fan-in symbols |
|
|
51
|
-
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers |
|
|
61
|
+
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers, **verified against the source** — [treat as candidates, not instructions](#deadcode-is-a-candidate-list-not-a-delete-list) |
|
|
52
62
|
|
|
53
63
|
Pin one engine with `--engine graph│lsp│semantic`, or fan out with `--engine both` / `all` to merge results.
|
|
54
64
|
|
|
65
|
+
#### `deadcode` is a candidate list, not a delete list
|
|
66
|
+
|
|
67
|
+
`deadcode` is the one op whose output invites a destructive action, so it gets an explicit caveat.
|
|
68
|
+
Every hit is re-read and verified against the source before it is reported, which removes the
|
|
69
|
+
common false positives — but **no reachability analysis sees every caller.** Dynamic dispatch,
|
|
70
|
+
registries and decorators, `getattr` lookups, entry points declared in packaging metadata, plugin
|
|
71
|
+
discovery, reflection, and calls from languages the graph does not parse are all invisible to it.
|
|
72
|
+
Through `0.14.x` it was systematically wrong on callback-heavy code and confident about it; that
|
|
73
|
+
class of defect is fixed, but the underlying limit is structural and permanent.
|
|
74
|
+
|
|
75
|
+
**So: review each hit before deleting anything, and never wire `deadcode` into an agent that
|
|
76
|
+
deletes without a human in the loop.** Used as a ranked list of *places worth looking*, it is
|
|
77
|
+
genuinely useful. Used as a work order, it will eventually remove live code.
|
|
78
|
+
|
|
55
79
|
**Example — "who uses `safe_null_result`?"**
|
|
56
80
|
|
|
57
81
|
```jsonc
|
|
@@ -225,13 +249,25 @@ Every `Gateway.query()` call returns a dict with exactly these keys:
|
|
|
225
249
|
{"ok": true, "op": "search", "target": "auth", "result": null, "engine": "semantic", "cached": false}
|
|
226
250
|
```
|
|
227
251
|
|
|
228
|
-
`ok` is always `true`. `result` is `null` when no provider has an answer — never an exception, never a 500.
|
|
252
|
+
`ok` is always `true`. `result` is `null` when no provider has an answer — never an exception, never a 500. Callers must check `result is not None` before using the value.
|
|
253
|
+
|
|
254
|
+
The optional keys are the ones worth reading when an answer surprises you:
|
|
255
|
+
|
|
256
|
+
| Key | Meaning |
|
|
257
|
+
|---|---|
|
|
258
|
+
| `reason` | Why `result` is null — `engine-unavailable`, `no-result`, `not-in-graph` (the symbol isn't in the index — usually a stale index), `project-not-indexed`, `unsupported-op`, `root-not-allowed-for-role` (RBAC) |
|
|
259
|
+
| `hint` | The specific command that resolves this `reason`, when there is one |
|
|
260
|
+
| `engine` | Which engine actually answered — not necessarily the one you asked for, under `auto` |
|
|
261
|
+
| `cached` | Whether it came from the content-hash cache |
|
|
262
|
+
| `reindexing` | Present and `true` when a reindex was running, i.e. the answer reflects the last *completed* index. See [Keeping answers fresh](#keeping-answers-fresh) |
|
|
263
|
+
|
|
264
|
+
`codeintel query --json` prints this envelope from the CLI.
|
|
229
265
|
|
|
230
266
|
## Engines
|
|
231
267
|
|
|
232
268
|
| Engine | Key ops | Install prereq |
|
|
233
269
|
|---|---|---|
|
|
234
|
-
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp`
|
|
270
|
+
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x** on PATH (`pip install 'codebase-memory-mcp==0.9.*'`) — 0.10.x changed its response format and returns nothing for every op but resolution; see [docs/graph.md](docs/graph.md) |
|
|
235
271
|
| `lsp` | `symbol`, `overview`, `context` | `uvx` on PATH — serena is fetched from GitHub on first use; see [docs/lsp.md](docs/lsp.md) |
|
|
236
272
|
| `semantic` | `search`, `context` | `fastembed` + `sqlite-vec` (installed with the package) — see [docs/semantic.md](docs/semantic.md) |
|
|
237
273
|
|
|
@@ -288,7 +324,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
288
324
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
289
325
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
290
326
|
| `codeintel serve-http [--host HOST] [--port 8766] [--allow-remote] [--token TOKEN]` | Start the HTTP transport (loopback-only unless `--allow-remote`; `--token` requires a bearer token on every request) |
|
|
291
|
-
| `codeintel query --op OP --target TARGET [--engine auto] [--project-root DIR]` | Run a single query and print the result |
|
|
327
|
+
| `codeintel query --op OP --target TARGET [--engine auto] [--project-root DIR] [--json]` | Run a single query and print the result |
|
|
292
328
|
| `codeintel status [project_root]` | Show engine availability and index age |
|
|
293
329
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
294
330
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
@@ -298,6 +334,14 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
298
334
|
|
|
299
335
|
Human-facing commands (`doctor`, `status`, `query`, `setup`, `reset`) honor `--no-color` / `NO_COLOR` and `--ascii`, and auto-degrade to plain text when piped.
|
|
300
336
|
|
|
337
|
+
**Exit codes**, so a `make` target or CI step can gate on `$?`:
|
|
338
|
+
|
|
339
|
+
| | |
|
|
340
|
+
|---|---|
|
|
341
|
+
| `0` | The command did its job. For `query` this includes an empty result — "nothing found" is an answer, not a failure. |
|
|
342
|
+
| `1` | The command could not do its job: a file it exists to write wasn't written (`map`, `graph`), an index didn't happen (`index`), a project root doesn't exist, or an engine is unhealthy (`doctor`, `setup`). |
|
|
343
|
+
| `2` | Bad usage — an unknown command or a missing required flag. |
|
|
344
|
+
|
|
301
345
|
## Config
|
|
302
346
|
|
|
303
347
|
Create `.codeintel.toml` at your project root to override defaults:
|
|
@@ -325,6 +369,7 @@ Config is **validated on load** — an out-of-range number, a misspelled enum, o
|
|
|
325
369
|
| `CODEINTEL_HTTP_ACCESS_LOG=1` | One log line per HTTP request (method, path, status, latency) |
|
|
326
370
|
| `CODEINTEL_DEBUG=1` | Log the full traceback of any error the never-throw contract swallows (silent by default) — the switch for diagnosing an unexpected `null` |
|
|
327
371
|
| `CODEINTEL_REINDEX=off` | Disable the background reindexer; queries then index inline to stay fresh |
|
|
372
|
+
| `CODEINTEL_HOME` | Where the index cache lives (default `~/.codeintel`). Set this when the process has **no resolvable home directory** — a container running as a UID with no passwd entry and no `$HOME`, which is common when an agent runs in one. Without it, `Path.home()` raises and every command fails somewhere far from the cause. |
|
|
328
373
|
|
|
329
374
|
## Privacy & dependencies
|
|
330
375
|
|
|
@@ -402,6 +447,63 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
402
447
|
-e CODEINTEL_HTTP_TOKEN="$(openssl rand -hex 32)" codeintel
|
|
403
448
|
```
|
|
404
449
|
|
|
450
|
+
## Project status
|
|
451
|
+
|
|
452
|
+
An honest picture, so you can decide what to trust this with.
|
|
453
|
+
|
|
454
|
+
**What's solid.** The suite is large and real — more test code than source, a coverage floor
|
|
455
|
+
enforced in CI, and fault-injection tests behind the never-raise contract. CI runs lint, `mypy`,
|
|
456
|
+
and the full suite on Python 3.11/3.12/3.13, then builds the wheel, installs it into a clean
|
|
457
|
+
environment, and runs a **release canary** that registers the build with Codex and Claude Code in a
|
|
458
|
+
throwaway `HOME`, boots the server those configs name, and asserts on the answer text of a real
|
|
459
|
+
`code.query`. A release that installs into a file no host reads, or that boots and answers nothing,
|
|
460
|
+
fails before it ships. The `code.query` envelope has been stable since `0.8`.
|
|
461
|
+
|
|
462
|
+
**What's young.** The project is pre-1.0 and moves fast. The honest signal is in the
|
|
463
|
+
[CHANGELOG](CHANGELOG.md): `0.15.0` and `0.15.1` were written almost entirely from pointing the
|
|
464
|
+
tool at four repositories it had never seen, and several of those defects had survived multiple
|
|
465
|
+
adversarial review rounds. **The rate at which new codebases surface new bugs has not yet flattened.**
|
|
466
|
+
Expect to be the first person to hit something, and please report it — see below.
|
|
467
|
+
|
|
468
|
+
**Use it for.** Local, single-user code intelligence on a developer machine. That is the designed
|
|
469
|
+
case, it is the tested case, and the blast radius of a wrong answer is a wasted tool call: the
|
|
470
|
+
safe-null contract means a failing engine degrades to `null` with a reason, so your agent falls
|
|
471
|
+
back to grep rather than crashing.
|
|
472
|
+
|
|
473
|
+
**Be careful with.**
|
|
474
|
+
|
|
475
|
+
| Area | Why |
|
|
476
|
+
|---|---|
|
|
477
|
+
| `deadcode` | It suggests deletions and cannot see every caller — [read the caveat](#deadcode-is-a-candidate-list-not-a-delete-list). |
|
|
478
|
+
| Non-loopback serving | `serve-http` is stdlib `http.server`. It binds loopback by default for a reason; front it with a reverse proxy and see [docs/deploy.md](docs/deploy.md). |
|
|
479
|
+
| RBAC between **untrusting** tenants | It separates privilege levels among callers you already trust. It is not a wall against an adversary with write access to their own root — see the warning in [docs/deploy.md](docs/deploy.md). |
|
|
480
|
+
| Unattended automation | Anything that acts on a result without a human reading it deserves a pilot first. |
|
|
481
|
+
|
|
482
|
+
**On the test numbers.** The suite is large and the coverage floor is enforced, but read the figure
|
|
483
|
+
with its caveat: the graph and LSP backends are external binaries that are **not installed in CI**,
|
|
484
|
+
so those two engines are exercised against hand-authored mocks rather than the real wire contract,
|
|
485
|
+
and the release canary — which does assert on real answer text against a built wheel — currently
|
|
486
|
+
covers the semantic engine only. Line coverage measures how much of the intended behavior runs, not
|
|
487
|
+
how much of reality it has met.
|
|
488
|
+
|
|
489
|
+
**The honest one-paragraph version.** codeintel has been run on very few repositories its author did
|
|
490
|
+
not write, and that is where its bugs have come from — every fix in `0.15.x` came from pointing it
|
|
491
|
+
at an unfamiliar codebase. Its characteristic failure mode is **answering confidently from the
|
|
492
|
+
wrong index rather than failing loudly**, which the never-raise contract makes harder to notice: a
|
|
493
|
+
wrong answer and a right one are the same shape. Run `codeintel doctor` before trusting a repo-wide
|
|
494
|
+
answer, treat `deadcode` as candidates for review, and if something looks off please
|
|
495
|
+
[report it](#reporting-a-problem) — an issue from someone who is not the author is the single most
|
|
496
|
+
useful thing this project can receive right now.
|
|
497
|
+
|
|
498
|
+
**Engine coverage depends on external binaries.** Semantic search works out of the box. The graph
|
|
499
|
+
engine needs `codebase-memory-mcp` and the LSP engine needs `uvx` on `PATH` — without them those
|
|
500
|
+
engines safe-null and you get a fraction of the capability table above. `codeintel setup --all`
|
|
501
|
+
installs what it can and `codeintel doctor` tells you exactly what is missing and how to fix it.
|
|
502
|
+
Run `doctor` first if the tool seems quieter than the docs suggest.
|
|
503
|
+
|
|
504
|
+
**Maintenance.** One maintainer, MIT licensed, issues and PRs welcome. There is no support
|
|
505
|
+
guarantee — factor that into anything load-bearing.
|
|
506
|
+
|
|
405
507
|
## Reporting a problem
|
|
406
508
|
|
|
407
509
|
`codeintel doctor --json` prints a complete, machine-readable picture of what's installed, what's
|
|
@@ -415,9 +517,16 @@ codeintel doctor --json
|
|
|
415
517
|
It reports only local engine and index state. Over the HTTP transport the `registrations` field —
|
|
416
518
|
which names agent config files on the machine running the server — is deliberately omitted.
|
|
417
519
|
|
|
418
|
-
If a *result* looks wrong rather than a command failing,
|
|
419
|
-
|
|
420
|
-
|
|
520
|
+
If a *result* looks wrong rather than a command failing, send the envelope rather than the
|
|
521
|
+
rendered text:
|
|
522
|
+
|
|
523
|
+
```bash
|
|
524
|
+
codeintel query --op callers --target yourSymbol --json
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
`engine` says which engine answered, `cached` whether it came from the cache, `reindexing` whether
|
|
528
|
+
the index was mid-rebuild, and `reason`/`hint` why an empty answer was empty. Those five fields are
|
|
529
|
+
usually the whole diagnosis.
|
|
421
530
|
|
|
422
531
|
## Development
|
|
423
532
|
|
|
@@ -426,7 +535,7 @@ git clone https://github.com/hamilton-sky/codeintel.git
|
|
|
426
535
|
cd codeintel
|
|
427
536
|
pip install -e .[dev]
|
|
428
537
|
|
|
429
|
-
pytest tests/ -q # ~
|
|
538
|
+
pytest tests/ -q # ~620 tests, ~30s; fails under 83% coverage
|
|
430
539
|
ruff check src tests # lint
|
|
431
540
|
mypy # types (src/ only)
|
|
432
541
|
```
|
|
@@ -19,7 +19,11 @@ keywords = [
|
|
|
19
19
|
"lsp", "semantic-search", "knowledge-graph", "static-analysis", "developer-tools",
|
|
20
20
|
]
|
|
21
21
|
classifiers = [
|
|
22
|
-
|
|
22
|
+
# Beta, deliberately. The package is well-tested and the `code.query` surface has been stable
|
|
23
|
+
# since 0.8, but the project is young, pre-1.0, and still finding real defects each time it
|
|
24
|
+
# meets an unfamiliar repository. "Production/Stable" is a claim to make after that curve
|
|
25
|
+
# flattens and external users have exercised it — not before.
|
|
26
|
+
"Development Status :: 4 - Beta",
|
|
23
27
|
"Intended Audience :: Developers",
|
|
24
28
|
"Environment :: Console",
|
|
25
29
|
"Operating System :: OS Independent",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.2
|
|
4
4
|
Summary: Local-first, MCP-native code-intelligence server — graph, LSP, and semantic search behind one safe code.query tool for coding agents.
|
|
5
5
|
Author: Shammai Hamilton
|
|
6
6
|
License-Expression: MIT
|
|
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/hamilton-sky/codeintel
|
|
|
9
9
|
Project-URL: Issues, https://github.com/hamilton-sky/codeintel/issues
|
|
10
10
|
Project-URL: Changelog, https://github.com/hamilton-sky/codeintel/blob/main/CHANGELOG.md
|
|
11
11
|
Keywords: mcp,model-context-protocol,code-intelligence,code-search,llm,agents,lsp,semantic-search,knowledge-graph,static-analysis,developer-tools
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Intended Audience :: Developers
|
|
14
14
|
Classifier: Environment :: Console
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
@@ -40,6 +40,16 @@ Dynamic: license-file
|
|
|
40
40
|
**One MCP tool that lets a coding agent search, trace, and *understand* a codebase — structurally, not by grepping.** codeintel unifies three engines — a call/import **graph**, an **LSP** for exact symbols, and **semantic** embedding search — behind a single `code.query` call that routes to the right engine, caches the answer, and **never throws**. The agent always gets back a clean, well-formed result to reason over.
|
|
41
41
|
|
|
42
42
|
[](https://github.com/hamilton-sky/codeintel/actions/workflows/ci.yml)
|
|
43
|
+
[](https://pypi.org/project/codecortex/)
|
|
44
|
+
[](https://pypi.org/project/codecortex/)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
|
|
47
|
+
> **Status: beta (`0.x`), and young.** The `code.query` surface is one call and has been stable
|
|
48
|
+
> since `0.8`, the suite is thorough, and every release is gated by a canary that runs a real query
|
|
49
|
+
> against a built wheel. But this is a new project with a single maintainer, and each time it has
|
|
50
|
+
> been pointed at an unfamiliar codebase it has found real bugs. **Use it locally, on a developer
|
|
51
|
+
> machine, for a single user** — that is the case it is built and tested for. Before relying on it
|
|
52
|
+
> for anything beyond that, read **[Project status](#project-status)**.
|
|
43
53
|
|
|
44
54
|

|
|
45
55
|
|
|
@@ -85,10 +95,24 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
85
95
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
86
96
|
| **Impact of your uncommitted edits** | `changed` | graph | changed files → impacted symbols |
|
|
87
97
|
| Refactor-risk hotspots | `hotspots` | graph | highest complexity / fan-in symbols |
|
|
88
|
-
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers |
|
|
98
|
+
| Unreferenced (dead) code | `deadcode` | graph | non-test symbols with no callers, **verified against the source** — [treat as candidates, not instructions](#deadcode-is-a-candidate-list-not-a-delete-list) |
|
|
89
99
|
|
|
90
100
|
Pin one engine with `--engine graph│lsp│semantic`, or fan out with `--engine both` / `all` to merge results.
|
|
91
101
|
|
|
102
|
+
#### `deadcode` is a candidate list, not a delete list
|
|
103
|
+
|
|
104
|
+
`deadcode` is the one op whose output invites a destructive action, so it gets an explicit caveat.
|
|
105
|
+
Every hit is re-read and verified against the source before it is reported, which removes the
|
|
106
|
+
common false positives — but **no reachability analysis sees every caller.** Dynamic dispatch,
|
|
107
|
+
registries and decorators, `getattr` lookups, entry points declared in packaging metadata, plugin
|
|
108
|
+
discovery, reflection, and calls from languages the graph does not parse are all invisible to it.
|
|
109
|
+
Through `0.14.x` it was systematically wrong on callback-heavy code and confident about it; that
|
|
110
|
+
class of defect is fixed, but the underlying limit is structural and permanent.
|
|
111
|
+
|
|
112
|
+
**So: review each hit before deleting anything, and never wire `deadcode` into an agent that
|
|
113
|
+
deletes without a human in the loop.** Used as a ranked list of *places worth looking*, it is
|
|
114
|
+
genuinely useful. Used as a work order, it will eventually remove live code.
|
|
115
|
+
|
|
92
116
|
**Example — "who uses `safe_null_result`?"**
|
|
93
117
|
|
|
94
118
|
```jsonc
|
|
@@ -262,13 +286,25 @@ Every `Gateway.query()` call returns a dict with exactly these keys:
|
|
|
262
286
|
{"ok": true, "op": "search", "target": "auth", "result": null, "engine": "semantic", "cached": false}
|
|
263
287
|
```
|
|
264
288
|
|
|
265
|
-
`ok` is always `true`. `result` is `null` when no provider has an answer — never an exception, never a 500.
|
|
289
|
+
`ok` is always `true`. `result` is `null` when no provider has an answer — never an exception, never a 500. Callers must check `result is not None` before using the value.
|
|
290
|
+
|
|
291
|
+
The optional keys are the ones worth reading when an answer surprises you:
|
|
292
|
+
|
|
293
|
+
| Key | Meaning |
|
|
294
|
+
|---|---|
|
|
295
|
+
| `reason` | Why `result` is null — `engine-unavailable`, `no-result`, `not-in-graph` (the symbol isn't in the index — usually a stale index), `project-not-indexed`, `unsupported-op`, `root-not-allowed-for-role` (RBAC) |
|
|
296
|
+
| `hint` | The specific command that resolves this `reason`, when there is one |
|
|
297
|
+
| `engine` | Which engine actually answered — not necessarily the one you asked for, under `auto` |
|
|
298
|
+
| `cached` | Whether it came from the content-hash cache |
|
|
299
|
+
| `reindexing` | Present and `true` when a reindex was running, i.e. the answer reflects the last *completed* index. See [Keeping answers fresh](#keeping-answers-fresh) |
|
|
300
|
+
|
|
301
|
+
`codeintel query --json` prints this envelope from the CLI.
|
|
266
302
|
|
|
267
303
|
## Engines
|
|
268
304
|
|
|
269
305
|
| Engine | Key ops | Install prereq |
|
|
270
306
|
|---|---|---|
|
|
271
|
-
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp`
|
|
307
|
+
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x** on PATH (`pip install 'codebase-memory-mcp==0.9.*'`) — 0.10.x changed its response format and returns nothing for every op but resolution; see [docs/graph.md](docs/graph.md) |
|
|
272
308
|
| `lsp` | `symbol`, `overview`, `context` | `uvx` on PATH — serena is fetched from GitHub on first use; see [docs/lsp.md](docs/lsp.md) |
|
|
273
309
|
| `semantic` | `search`, `context` | `fastembed` + `sqlite-vec` (installed with the package) — see [docs/semantic.md](docs/semantic.md) |
|
|
274
310
|
|
|
@@ -325,7 +361,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
325
361
|
| `codeintel index [project_root]` | Index a project for semantic search |
|
|
326
362
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
327
363
|
| `codeintel serve-http [--host HOST] [--port 8766] [--allow-remote] [--token TOKEN]` | Start the HTTP transport (loopback-only unless `--allow-remote`; `--token` requires a bearer token on every request) |
|
|
328
|
-
| `codeintel query --op OP --target TARGET [--engine auto] [--project-root DIR]` | Run a single query and print the result |
|
|
364
|
+
| `codeintel query --op OP --target TARGET [--engine auto] [--project-root DIR] [--json]` | Run a single query and print the result |
|
|
329
365
|
| `codeintel status [project_root]` | Show engine availability and index age |
|
|
330
366
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
331
367
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
@@ -335,6 +371,14 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
335
371
|
|
|
336
372
|
Human-facing commands (`doctor`, `status`, `query`, `setup`, `reset`) honor `--no-color` / `NO_COLOR` and `--ascii`, and auto-degrade to plain text when piped.
|
|
337
373
|
|
|
374
|
+
**Exit codes**, so a `make` target or CI step can gate on `$?`:
|
|
375
|
+
|
|
376
|
+
| | |
|
|
377
|
+
|---|---|
|
|
378
|
+
| `0` | The command did its job. For `query` this includes an empty result — "nothing found" is an answer, not a failure. |
|
|
379
|
+
| `1` | The command could not do its job: a file it exists to write wasn't written (`map`, `graph`), an index didn't happen (`index`), a project root doesn't exist, or an engine is unhealthy (`doctor`, `setup`). |
|
|
380
|
+
| `2` | Bad usage — an unknown command or a missing required flag. |
|
|
381
|
+
|
|
338
382
|
## Config
|
|
339
383
|
|
|
340
384
|
Create `.codeintel.toml` at your project root to override defaults:
|
|
@@ -362,6 +406,7 @@ Config is **validated on load** — an out-of-range number, a misspelled enum, o
|
|
|
362
406
|
| `CODEINTEL_HTTP_ACCESS_LOG=1` | One log line per HTTP request (method, path, status, latency) |
|
|
363
407
|
| `CODEINTEL_DEBUG=1` | Log the full traceback of any error the never-throw contract swallows (silent by default) — the switch for diagnosing an unexpected `null` |
|
|
364
408
|
| `CODEINTEL_REINDEX=off` | Disable the background reindexer; queries then index inline to stay fresh |
|
|
409
|
+
| `CODEINTEL_HOME` | Where the index cache lives (default `~/.codeintel`). Set this when the process has **no resolvable home directory** — a container running as a UID with no passwd entry and no `$HOME`, which is common when an agent runs in one. Without it, `Path.home()` raises and every command fails somewhere far from the cause. |
|
|
365
410
|
|
|
366
411
|
## Privacy & dependencies
|
|
367
412
|
|
|
@@ -439,6 +484,63 @@ docker build -t codeintel . && docker run -p 127.0.0.1:8766:8766 \
|
|
|
439
484
|
-e CODEINTEL_HTTP_TOKEN="$(openssl rand -hex 32)" codeintel
|
|
440
485
|
```
|
|
441
486
|
|
|
487
|
+
## Project status
|
|
488
|
+
|
|
489
|
+
An honest picture, so you can decide what to trust this with.
|
|
490
|
+
|
|
491
|
+
**What's solid.** The suite is large and real — more test code than source, a coverage floor
|
|
492
|
+
enforced in CI, and fault-injection tests behind the never-raise contract. CI runs lint, `mypy`,
|
|
493
|
+
and the full suite on Python 3.11/3.12/3.13, then builds the wheel, installs it into a clean
|
|
494
|
+
environment, and runs a **release canary** that registers the build with Codex and Claude Code in a
|
|
495
|
+
throwaway `HOME`, boots the server those configs name, and asserts on the answer text of a real
|
|
496
|
+
`code.query`. A release that installs into a file no host reads, or that boots and answers nothing,
|
|
497
|
+
fails before it ships. The `code.query` envelope has been stable since `0.8`.
|
|
498
|
+
|
|
499
|
+
**What's young.** The project is pre-1.0 and moves fast. The honest signal is in the
|
|
500
|
+
[CHANGELOG](CHANGELOG.md): `0.15.0` and `0.15.1` were written almost entirely from pointing the
|
|
501
|
+
tool at four repositories it had never seen, and several of those defects had survived multiple
|
|
502
|
+
adversarial review rounds. **The rate at which new codebases surface new bugs has not yet flattened.**
|
|
503
|
+
Expect to be the first person to hit something, and please report it — see below.
|
|
504
|
+
|
|
505
|
+
**Use it for.** Local, single-user code intelligence on a developer machine. That is the designed
|
|
506
|
+
case, it is the tested case, and the blast radius of a wrong answer is a wasted tool call: the
|
|
507
|
+
safe-null contract means a failing engine degrades to `null` with a reason, so your agent falls
|
|
508
|
+
back to grep rather than crashing.
|
|
509
|
+
|
|
510
|
+
**Be careful with.**
|
|
511
|
+
|
|
512
|
+
| Area | Why |
|
|
513
|
+
|---|---|
|
|
514
|
+
| `deadcode` | It suggests deletions and cannot see every caller — [read the caveat](#deadcode-is-a-candidate-list-not-a-delete-list). |
|
|
515
|
+
| Non-loopback serving | `serve-http` is stdlib `http.server`. It binds loopback by default for a reason; front it with a reverse proxy and see [docs/deploy.md](docs/deploy.md). |
|
|
516
|
+
| RBAC between **untrusting** tenants | It separates privilege levels among callers you already trust. It is not a wall against an adversary with write access to their own root — see the warning in [docs/deploy.md](docs/deploy.md). |
|
|
517
|
+
| Unattended automation | Anything that acts on a result without a human reading it deserves a pilot first. |
|
|
518
|
+
|
|
519
|
+
**On the test numbers.** The suite is large and the coverage floor is enforced, but read the figure
|
|
520
|
+
with its caveat: the graph and LSP backends are external binaries that are **not installed in CI**,
|
|
521
|
+
so those two engines are exercised against hand-authored mocks rather than the real wire contract,
|
|
522
|
+
and the release canary — which does assert on real answer text against a built wheel — currently
|
|
523
|
+
covers the semantic engine only. Line coverage measures how much of the intended behavior runs, not
|
|
524
|
+
how much of reality it has met.
|
|
525
|
+
|
|
526
|
+
**The honest one-paragraph version.** codeintel has been run on very few repositories its author did
|
|
527
|
+
not write, and that is where its bugs have come from — every fix in `0.15.x` came from pointing it
|
|
528
|
+
at an unfamiliar codebase. Its characteristic failure mode is **answering confidently from the
|
|
529
|
+
wrong index rather than failing loudly**, which the never-raise contract makes harder to notice: a
|
|
530
|
+
wrong answer and a right one are the same shape. Run `codeintel doctor` before trusting a repo-wide
|
|
531
|
+
answer, treat `deadcode` as candidates for review, and if something looks off please
|
|
532
|
+
[report it](#reporting-a-problem) — an issue from someone who is not the author is the single most
|
|
533
|
+
useful thing this project can receive right now.
|
|
534
|
+
|
|
535
|
+
**Engine coverage depends on external binaries.** Semantic search works out of the box. The graph
|
|
536
|
+
engine needs `codebase-memory-mcp` and the LSP engine needs `uvx` on `PATH` — without them those
|
|
537
|
+
engines safe-null and you get a fraction of the capability table above. `codeintel setup --all`
|
|
538
|
+
installs what it can and `codeintel doctor` tells you exactly what is missing and how to fix it.
|
|
539
|
+
Run `doctor` first if the tool seems quieter than the docs suggest.
|
|
540
|
+
|
|
541
|
+
**Maintenance.** One maintainer, MIT licensed, issues and PRs welcome. There is no support
|
|
542
|
+
guarantee — factor that into anything load-bearing.
|
|
543
|
+
|
|
442
544
|
## Reporting a problem
|
|
443
545
|
|
|
444
546
|
`codeintel doctor --json` prints a complete, machine-readable picture of what's installed, what's
|
|
@@ -452,9 +554,16 @@ codeintel doctor --json
|
|
|
452
554
|
It reports only local engine and index state. Over the HTTP transport the `registrations` field —
|
|
453
555
|
which names agent config files on the machine running the server — is deliberately omitted.
|
|
454
556
|
|
|
455
|
-
If a *result* looks wrong rather than a command failing,
|
|
456
|
-
|
|
457
|
-
|
|
557
|
+
If a *result* looks wrong rather than a command failing, send the envelope rather than the
|
|
558
|
+
rendered text:
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
codeintel query --op callers --target yourSymbol --json
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
`engine` says which engine answered, `cached` whether it came from the cache, `reindexing` whether
|
|
565
|
+
the index was mid-rebuild, and `reason`/`hint` why an empty answer was empty. Those five fields are
|
|
566
|
+
usually the whole diagnosis.
|
|
458
567
|
|
|
459
568
|
## Development
|
|
460
569
|
|
|
@@ -463,7 +572,7 @@ git clone https://github.com/hamilton-sky/codeintel.git
|
|
|
463
572
|
cd codeintel
|
|
464
573
|
pip install -e .[dev]
|
|
465
574
|
|
|
466
|
-
pytest tests/ -q # ~
|
|
575
|
+
pytest tests/ -q # ~620 tests, ~30s; fails under 83% coverage
|
|
467
576
|
ruff check src tests # lint
|
|
468
577
|
mypy # types (src/ only)
|
|
469
578
|
```
|