codecortex 0.21.0__tar.gz → 0.23.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {codecortex-0.21.0/src/codecortex.egg-info → codecortex-0.23.0}/PKG-INFO +62 -9
- {codecortex-0.21.0 → codecortex-0.23.0}/README.md +59 -8
- {codecortex-0.21.0 → codecortex-0.23.0}/pyproject.toml +19 -0
- {codecortex-0.21.0 → codecortex-0.23.0/src/codecortex.egg-info}/PKG-INFO +62 -9
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codecortex.egg-info/SOURCES.txt +9 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codecortex.egg-info/requires.txt +3 -0
- codecortex-0.23.0/src/codeintel/__init__.py +1 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/__main__.py +35 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/c4.py +174 -31
- codecortex-0.23.0/src/codeintel/c4_check.py +438 -0
- codecortex-0.23.0/src/codeintel/c4_layers.py +657 -0
- codecortex-0.23.0/src/codeintel/commands/c4.py +349 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/setup.py +1 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/gateway.py +5 -1
- codecortex-0.23.0/src/codeintel/lang_config.py +291 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/mapper.py +91 -26
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/onboarding.py +41 -3
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/providers/graph.py +336 -59
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/providers/lsp.py +53 -1
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/providers/semantic.py +20 -1
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/server.py +6 -4
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/verify.py +53 -7
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/wire_text.py +19 -5
- codecortex-0.23.0/tests/test_bench_oracle.py +203 -0
- codecortex-0.23.0/tests/test_bench_oracle_ts.py +218 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_c4.py +198 -0
- codecortex-0.23.0/tests/test_c4_check.py +458 -0
- codecortex-0.23.0/tests/test_c4_layers.py +331 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_c4_output.py +2 -1
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_cli_commands.py +5 -3
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_cold_process.py +6 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_edge_confidence.py +11 -6
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_graph_failure_population.py +3 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_graph_provider.py +37 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_graph_real.py +15 -3
- codecortex-0.23.0/tests/test_hard_exit.py +132 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_incompleteness.py +16 -10
- codecortex-0.23.0/tests/test_lang_config.py +260 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_lsp_provider.py +114 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_mapper.py +185 -4
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_null_reason_and_ripple.py +153 -1
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_onboarding.py +48 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_semantic_provider.py +108 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_verify.py +85 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_wire_text.py +30 -0
- codecortex-0.21.0/src/codeintel/__init__.py +0 -1
- codecortex-0.21.0/src/codeintel/commands/c4.py +0 -182
- {codecortex-0.21.0 → codecortex-0.23.0}/LICENSE +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/setup.cfg +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codecortex.egg-info/dependency_links.txt +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codecortex.egg-info/entry_points.txt +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codecortex.egg-info/top_level.txt +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/agent_prompt.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/auth.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/cache.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/__init__.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/_common.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/doctor.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/gen_token.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/graph.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/index.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/install.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/map.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/prompt.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/query.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/reset.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/serve.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/serve_http.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/commands/status.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/config.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/containment.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/doctor.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/graph_backend.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/graph_render.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/graph_resolution.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/grapher.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/http_server.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/indexer.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/injector.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/installer.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/loc.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/logconfig.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/metrics.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/outcome.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/paths.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/policy.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/progress.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/provider.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/providers/__init__.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/providers/none.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/py.typed +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/query_ops.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/redact.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/reindexer.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/reset.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/searcher.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/semantic_db.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/source_kind.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/term.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/viewer/__init__.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/src/codeintel/viewer/graph_template.html +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_agent_prompt.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_backend_reaper.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_c4_model.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_cache.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_chunking.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_cli_help.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_cli_install_dry_run.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_cli_install_offer_injection.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_config.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_corpus.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_docs_ci_claims.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_docs_deadcode_withdrawal.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_doctor.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_e2e.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_engine_adoption.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_enterprise.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_gateway.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_graph_stdin.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_grapher.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_hardening.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_http_auth.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_http_server.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_index_progress.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_indexer_binary.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_installer.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_integration.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_loc_census.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_lsp_language_coverage.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_lsp_real.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_mcp_handshake.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_mcp_server.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_model_dimension.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_never_raise.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_rbac.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_redaction_boundary.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_reindexer.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_rerank.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_reset.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_source_kind.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_staleness.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_symbol_context.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_term.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_treesitter.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_verify_call.py +0 -0
- {codecortex-0.21.0 → codecortex-0.23.0}/tests/test_version_skew.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
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
|
|
@@ -33,6 +33,8 @@ Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
|
33
33
|
Requires-Dist: numpy>=1.24; extra == "dev"
|
|
34
34
|
Requires-Dist: ruff>=0.16; extra == "dev"
|
|
35
35
|
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
36
|
+
Provides-Extra: bench
|
|
37
|
+
Requires-Dist: anthropic>=0.40; extra == "bench"
|
|
36
38
|
Dynamic: license-file
|
|
37
39
|
|
|
38
40
|
# codeintel
|
|
@@ -61,9 +63,9 @@ Prefer plain text? `codeintel map` writes a **readable architecture overview** t
|
|
|
61
63
|
|
|
62
64
|
**What `CODE_INTEL.md` is for.** It's a *static, committable* snapshot of a codebase's shape — meant to be read (by a person or an agent) **first**, instead of reconstructing structure by grepping. It covers the cases the live `code.query` tool doesn't:
|
|
63
65
|
|
|
64
|
-
- **Agents & hosts that don't speak MCP.** Not every agent supports MCP, and the server isn't always running. `codeintel map` writes a plain file any agent can read; `codeintel map --inject` also drops a short, tool-naming pointer block into `AGENTS.md` (the cross-tool surface read by Codex, Cursor, Zed, and others — created with your consent if it doesn't exist yet) plus a one-line `@AGENTS.md` import into `CLAUDE.md`, and writes the fuller
|
|
66
|
+
- **Agents & hosts that don't speak MCP.** Not every agent supports MCP, and the server isn't always running. `codeintel map` writes a plain file any agent can read; `codeintel map --inject` also drops a short, tool-naming pointer block into `AGENTS.md` (the cross-tool surface read by Codex, Cursor, Zed, and others — created with your consent if it doesn't exist yet) plus a one-line `@AGENTS.md` import into `CLAUDE.md`, and writes the fuller `USING_CODEINTEL.md` guide the block points to — into **your** repo, which is why there is no such file to click here — so an agent knows to reach for `code.query` before it reaches for grep, not just that a `CODE_INTEL.md` exists.
|
|
65
67
|
- **A committed, diffable overview.** It lives *in the repo* — reviewable in a PR, browsable on GitHub, available offline. Re-run `codeintel map` after `codeintel index` to refresh it.
|
|
66
|
-
- **The load-bearing code at a glance.** Ranking symbols by caller count surfaces what most of the codebase depends on (the risky-to-change core) plus the entry points — the first things a newcomer, or an agent, should understand before touching anything.
|
|
68
|
+
- **The load-bearing code at a glance.** Ranking symbols by caller count surfaces what most of the codebase depends on (the risky-to-change core) plus the entry points — the first things a newcomer, or an agent, should understand before touching anything. The ranking counts `CALLS` edges into **callable** nodes only (functions, methods, classes, interfaces, routes), and skips test, generated and archived files. Both constraints are load-bearing rather than tidy-up: without them a 12,638-node TypeScript repo ranked `logger` (a *folder* node) at 716 and `onClick` at 107, and a Python repo ranked YAML and JSON keys — `flow` from a `.flow.yaml`, `feature` from a `.schema.json` — as its most depended-on symbols. This repo's own map is Python-heavy and barely showed it, which is exactly why dogfooding did not catch it.
|
|
67
69
|
|
|
68
70
|
See **[docs/map-file.md](docs/map-file.md)** for the format and the `--inject` flow.
|
|
69
71
|
|
|
@@ -91,7 +93,7 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
91
93
|
| Who calls this? | `callers` | graph | caller symbols + files |
|
|
92
94
|
| What does this call? | `callees` | graph | callee symbols + files |
|
|
93
95
|
| Blast radius of a change | `impact` | graph | callers **and** callees together |
|
|
94
|
-
| Trace a call chain up/downstream | `chain` | graph | ordered,
|
|
96
|
+
| Trace a call chain up/downstream | `chain` | graph | ordered hops, each labelled with how it was resolved |
|
|
95
97
|
| Find symbols by pattern | `pattern` | graph | matching nodes + locations |
|
|
96
98
|
| Project shape at a glance | `overview` | graph → lsp | modules, node/edge counts, languages |
|
|
97
99
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
@@ -153,6 +155,57 @@ no benefit to set against that error rate.
|
|
|
153
155
|
**Use `callers` on a specific symbol instead.** "Does anything call this?" is exactly the question
|
|
154
156
|
`deadcode` was trying to answer in bulk, and `callers` answers it accurately, one symbol at a time.
|
|
155
157
|
|
|
158
|
+
## An architecture model, as source
|
|
159
|
+
|
|
160
|
+
`codeintel c4` turns the graph index into a [LikeC4](https://likec4.dev) model — architecture-as-code
|
|
161
|
+
you can commit, diff and hand-edit, rather than a rendered picture you have to regenerate to read.
|
|
162
|
+
Abridged output, from `--scope src/codeintel/providers`:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
// Generated by codeintel from the graph index — do not edit by hand.
|
|
166
|
+
// edges: union of IMPORTS (static module-level imports) and CALLS|USAGE (call/usage references)
|
|
167
|
+
// coverage is NOT complete: dispatch through a name/lookup table can still be invisible to both
|
|
168
|
+
// hotspot ranking uses IMPORTS-only fan-in, never the CALLS|USAGE union
|
|
169
|
+
|
|
170
|
+
model {
|
|
171
|
+
src = area 'src' {
|
|
172
|
+
codeintel = area 'codeintel' {
|
|
173
|
+
providers = area 'providers' {
|
|
174
|
+
lsp = module 'lsp' {
|
|
175
|
+
technology 'Python'
|
|
176
|
+
metadata { path 'src/codeintel/providers/lsp.py' churn '12' fan_out '2' }
|
|
177
|
+
}
|
|
178
|
+
graph = module 'graph' { /* … */ }
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
src.codeintel.providers.lsp -[calls_usage]-> src.codeintel.providers.graph { metadata { n '2' } }
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Directories become `area`, files become `module`, and every element carries its real path plus churn
|
|
188
|
+
and fan-in as `metadata` — so the model is queryable, not only drawable. Each file opens with what it
|
|
189
|
+
cannot know: which edge sources it used, that coverage is incomplete, and how many references were
|
|
190
|
+
folded or dropped. `npx likec4 start codeintel-c4` renders it; nothing else here needs Node.
|
|
191
|
+
|
|
192
|
+
**Two edge sources, and the choice matters more than it sounds.** The default unions static `IMPORTS`
|
|
193
|
+
with `CALLS|USAGE`, which recovers lazy and function-body imports. On this repo at
|
|
194
|
+
`--scope src --depth 3` that is 179 relations — **134 of them `CALLS|USAGE`-only**, which renders as a
|
|
195
|
+
hairball. `--edges imports` leaves the same 45 elements with 45 edges: legible, and roughly layered,
|
|
196
|
+
because every remaining edge descends.
|
|
197
|
+
|
|
198
|
+
**It also answers two questions without drawing anything.** `--layers` infers architectural bands
|
|
199
|
+
from the import graph — 7 bands over 35 of those 45 elements, the other 10 having no module-level
|
|
200
|
+
import edge either way. `--check` gates CI on a declared
|
|
201
|
+
`[layers]` block in `.codeintel.toml`, exiting **2** on architectural drift — deliberately distinct
|
|
202
|
+
from exit 1 for a broken run, so a CI step can tell "your architecture drifted" from "codeintel is
|
|
203
|
+
broken". A config generated by `--suggest-config` is a *provably* green baseline on the commit that
|
|
204
|
+
produced it, so adoption is paste-confirm-tighten rather than a wall of false positives.
|
|
205
|
+
|
|
206
|
+
Full reference: **[docs/c4.md](docs/c4.md)**. Why LikeC4 and not something else, measured:
|
|
207
|
+
[docs/eval-2026-08-26-likec4.md](docs/eval-2026-08-26-likec4.md).
|
|
208
|
+
|
|
156
209
|
## What makes it good
|
|
157
210
|
|
|
158
211
|
- **Local-first and private.** One process on your machine — no cloud service, no API keys, no telemetry, no per-query network. Safe to point at a private repo, even with `--engine all`. (The one-time exception: `fastembed` downloads its embedding model once, then runs fully offline.)
|
|
@@ -281,7 +334,7 @@ Then it launches the exact command it registered and drives a real MCP handshake
|
|
|
281
334
|
```text
|
|
282
335
|
v claude: registered at /Users/you/.claude.json
|
|
283
336
|
|
|
284
|
-
v verified: codeintel 0.
|
|
337
|
+
v verified: codeintel 0.23.0 — 4 tools (code.query, code.status, code.doctor, code.map)
|
|
285
338
|
```
|
|
286
339
|
|
|
287
340
|
If the command is not on `PATH`, or the server fails to start, install says so and exits non-zero
|
|
@@ -343,7 +396,7 @@ The optional keys are the ones worth reading when an answer surprises you:
|
|
|
343
396
|
|
|
344
397
|
| Engine | Key ops | Install prereq |
|
|
345
398
|
|---|---|---|
|
|
346
|
-
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x** on PATH (`pip install 'codebase-memory-mcp==0.
|
|
399
|
+
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x or 0.10.x** on PATH — both wire dialects are read; `0.10.x` is the more accurate backend and is recommended (`pip install 'codebase-memory-mcp==0.10.*'`). See [docs/graph.md](docs/graph.md) |
|
|
347
400
|
| `lsp` | `symbol`, `overview`, `context` | `uvx` on PATH — serena is fetched from GitHub on first use; see [docs/lsp.md](docs/lsp.md) |
|
|
348
401
|
| `semantic` | `search`, `context` | `fastembed` + `sqlite-vec` (installed with the package) — see [docs/semantic.md](docs/semantic.md) |
|
|
349
402
|
|
|
@@ -396,7 +449,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
396
449
|
|---|---|
|
|
397
450
|
| `codeintel help` | Every command grouped by task, with descriptions and examples (also the bare `codeintel`). A mistyped command suggests what you meant. |
|
|
398
451
|
| `codeintel install [--agent auto\|claude\|codex\|gemini\|zed\|all] [--no-verify] [--relative-command]` | Register codeintel with the agents installed on this machine (`auto`, the default), then prove it by completing a real MCP handshake against the registered command |
|
|
399
|
-
| `codeintel setup [project_root] [--all] [--index] [--warm] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
452
|
+
| `codeintel setup [project_root] [--all] [--index] [--warm] [--languages] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
400
453
|
| `codeintel prompt [project_root] [--agent auto\|claude\|codex\|gemini\|zed] [--fresh] [--deep]` | Print a paste-to-your-agent setup prompt; probes health and emits only the outstanding steps (or "just restart me" when already healthy). `--fresh` = the full sequence from `pip install`, to send a friend |
|
|
401
454
|
| `codeintel index [project_root] [--quiet]` | Index a repo (semantic embeddings + best-effort graph & map refresh), with a live progress display; `--quiet` prints only the result line |
|
|
402
455
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
@@ -406,7 +459,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
406
459
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
407
460
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
408
461
|
| `codeintel graph [project_root] [--html] [--out FILE] [--limit N]` | Emit the call graph as `{nodes,edges}` JSON, or `--html` a self-contained interactive viewer — see [docs/graph-viewer.md](docs/graph-viewer.md) |
|
|
409
|
-
| `codeintel c4 [project_root] [--out DIR] [--depth N] [--scope PATH] [--include-tests] [--no-index] [--json]` | Write a LikeC4 architecture model (`.c4`) of the repo's
|
|
462
|
+
| `codeintel c4 [project_root] [--out DIR] [--depth N] [--scope PATH] [--include-tests] [--no-index] [--edges union\|imports] [--json] [--layers] [--suggest-config] [--check] [--layers-from auto\|inferred\|declared]` | Write a LikeC4 architecture model (`.c4`) of the repo's files and import graph. Indexes the repo first if it has no graph index. `--edges imports` drops the lower-confidence edges for a legible diagram; `--layers` reports inferred architectural bands; `--check` gates CI on a declared `[layers]` config, exit 2 on drift. See [An architecture model, as source](#an-architecture-model-as-source) and [docs/c4.md](docs/c4.md) |
|
|
410
463
|
| `codeintel reset [project_root] [--all] [--yes] [--json]` | Clear this repo's index — **both** semantic and graph — so it's as if never indexed; `--all` wipes every repo. Recovers from a corrupt/stale DB |
|
|
411
464
|
| `codeintel gen-token` | Print a secure random bearer token (for `serve-http` / RBAC `auth.toml`) |
|
|
412
465
|
|
|
@@ -646,7 +699,7 @@ cd codeintel
|
|
|
646
699
|
pip install -e .[dev]
|
|
647
700
|
|
|
648
701
|
pytest tests/ -q # ~740 tests, ~30s; fails under 83% coverage
|
|
649
|
-
ruff check src tests
|
|
702
|
+
ruff check src tests bench # lint
|
|
650
703
|
mypy # types (src/ only)
|
|
651
704
|
```
|
|
652
705
|
|
|
@@ -24,9 +24,9 @@ Prefer plain text? `codeintel map` writes a **readable architecture overview** t
|
|
|
24
24
|
|
|
25
25
|
**What `CODE_INTEL.md` is for.** It's a *static, committable* snapshot of a codebase's shape — meant to be read (by a person or an agent) **first**, instead of reconstructing structure by grepping. It covers the cases the live `code.query` tool doesn't:
|
|
26
26
|
|
|
27
|
-
- **Agents & hosts that don't speak MCP.** Not every agent supports MCP, and the server isn't always running. `codeintel map` writes a plain file any agent can read; `codeintel map --inject` also drops a short, tool-naming pointer block into `AGENTS.md` (the cross-tool surface read by Codex, Cursor, Zed, and others — created with your consent if it doesn't exist yet) plus a one-line `@AGENTS.md` import into `CLAUDE.md`, and writes the fuller
|
|
27
|
+
- **Agents & hosts that don't speak MCP.** Not every agent supports MCP, and the server isn't always running. `codeintel map` writes a plain file any agent can read; `codeintel map --inject` also drops a short, tool-naming pointer block into `AGENTS.md` (the cross-tool surface read by Codex, Cursor, Zed, and others — created with your consent if it doesn't exist yet) plus a one-line `@AGENTS.md` import into `CLAUDE.md`, and writes the fuller `USING_CODEINTEL.md` guide the block points to — into **your** repo, which is why there is no such file to click here — so an agent knows to reach for `code.query` before it reaches for grep, not just that a `CODE_INTEL.md` exists.
|
|
28
28
|
- **A committed, diffable overview.** It lives *in the repo* — reviewable in a PR, browsable on GitHub, available offline. Re-run `codeintel map` after `codeintel index` to refresh it.
|
|
29
|
-
- **The load-bearing code at a glance.** Ranking symbols by caller count surfaces what most of the codebase depends on (the risky-to-change core) plus the entry points — the first things a newcomer, or an agent, should understand before touching anything.
|
|
29
|
+
- **The load-bearing code at a glance.** Ranking symbols by caller count surfaces what most of the codebase depends on (the risky-to-change core) plus the entry points — the first things a newcomer, or an agent, should understand before touching anything. The ranking counts `CALLS` edges into **callable** nodes only (functions, methods, classes, interfaces, routes), and skips test, generated and archived files. Both constraints are load-bearing rather than tidy-up: without them a 12,638-node TypeScript repo ranked `logger` (a *folder* node) at 716 and `onClick` at 107, and a Python repo ranked YAML and JSON keys — `flow` from a `.flow.yaml`, `feature` from a `.schema.json` — as its most depended-on symbols. This repo's own map is Python-heavy and barely showed it, which is exactly why dogfooding did not catch it.
|
|
30
30
|
|
|
31
31
|
See **[docs/map-file.md](docs/map-file.md)** for the format and the `--inject` flow.
|
|
32
32
|
|
|
@@ -54,7 +54,7 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
54
54
|
| Who calls this? | `callers` | graph | caller symbols + files |
|
|
55
55
|
| What does this call? | `callees` | graph | callee symbols + files |
|
|
56
56
|
| Blast radius of a change | `impact` | graph | callers **and** callees together |
|
|
57
|
-
| Trace a call chain up/downstream | `chain` | graph | ordered,
|
|
57
|
+
| Trace a call chain up/downstream | `chain` | graph | ordered hops, each labelled with how it was resolved |
|
|
58
58
|
| Find symbols by pattern | `pattern` | graph | matching nodes + locations |
|
|
59
59
|
| Project shape at a glance | `overview` | graph → lsp | modules, node/edge counts, languages |
|
|
60
60
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
@@ -116,6 +116,57 @@ no benefit to set against that error rate.
|
|
|
116
116
|
**Use `callers` on a specific symbol instead.** "Does anything call this?" is exactly the question
|
|
117
117
|
`deadcode` was trying to answer in bulk, and `callers` answers it accurately, one symbol at a time.
|
|
118
118
|
|
|
119
|
+
## An architecture model, as source
|
|
120
|
+
|
|
121
|
+
`codeintel c4` turns the graph index into a [LikeC4](https://likec4.dev) model — architecture-as-code
|
|
122
|
+
you can commit, diff and hand-edit, rather than a rendered picture you have to regenerate to read.
|
|
123
|
+
Abridged output, from `--scope src/codeintel/providers`:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
// Generated by codeintel from the graph index — do not edit by hand.
|
|
127
|
+
// edges: union of IMPORTS (static module-level imports) and CALLS|USAGE (call/usage references)
|
|
128
|
+
// coverage is NOT complete: dispatch through a name/lookup table can still be invisible to both
|
|
129
|
+
// hotspot ranking uses IMPORTS-only fan-in, never the CALLS|USAGE union
|
|
130
|
+
|
|
131
|
+
model {
|
|
132
|
+
src = area 'src' {
|
|
133
|
+
codeintel = area 'codeintel' {
|
|
134
|
+
providers = area 'providers' {
|
|
135
|
+
lsp = module 'lsp' {
|
|
136
|
+
technology 'Python'
|
|
137
|
+
metadata { path 'src/codeintel/providers/lsp.py' churn '12' fan_out '2' }
|
|
138
|
+
}
|
|
139
|
+
graph = module 'graph' { /* … */ }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
src.codeintel.providers.lsp -[calls_usage]-> src.codeintel.providers.graph { metadata { n '2' } }
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Directories become `area`, files become `module`, and every element carries its real path plus churn
|
|
149
|
+
and fan-in as `metadata` — so the model is queryable, not only drawable. Each file opens with what it
|
|
150
|
+
cannot know: which edge sources it used, that coverage is incomplete, and how many references were
|
|
151
|
+
folded or dropped. `npx likec4 start codeintel-c4` renders it; nothing else here needs Node.
|
|
152
|
+
|
|
153
|
+
**Two edge sources, and the choice matters more than it sounds.** The default unions static `IMPORTS`
|
|
154
|
+
with `CALLS|USAGE`, which recovers lazy and function-body imports. On this repo at
|
|
155
|
+
`--scope src --depth 3` that is 179 relations — **134 of them `CALLS|USAGE`-only**, which renders as a
|
|
156
|
+
hairball. `--edges imports` leaves the same 45 elements with 45 edges: legible, and roughly layered,
|
|
157
|
+
because every remaining edge descends.
|
|
158
|
+
|
|
159
|
+
**It also answers two questions without drawing anything.** `--layers` infers architectural bands
|
|
160
|
+
from the import graph — 7 bands over 35 of those 45 elements, the other 10 having no module-level
|
|
161
|
+
import edge either way. `--check` gates CI on a declared
|
|
162
|
+
`[layers]` block in `.codeintel.toml`, exiting **2** on architectural drift — deliberately distinct
|
|
163
|
+
from exit 1 for a broken run, so a CI step can tell "your architecture drifted" from "codeintel is
|
|
164
|
+
broken". A config generated by `--suggest-config` is a *provably* green baseline on the commit that
|
|
165
|
+
produced it, so adoption is paste-confirm-tighten rather than a wall of false positives.
|
|
166
|
+
|
|
167
|
+
Full reference: **[docs/c4.md](docs/c4.md)**. Why LikeC4 and not something else, measured:
|
|
168
|
+
[docs/eval-2026-08-26-likec4.md](docs/eval-2026-08-26-likec4.md).
|
|
169
|
+
|
|
119
170
|
## What makes it good
|
|
120
171
|
|
|
121
172
|
- **Local-first and private.** One process on your machine — no cloud service, no API keys, no telemetry, no per-query network. Safe to point at a private repo, even with `--engine all`. (The one-time exception: `fastembed` downloads its embedding model once, then runs fully offline.)
|
|
@@ -244,7 +295,7 @@ Then it launches the exact command it registered and drives a real MCP handshake
|
|
|
244
295
|
```text
|
|
245
296
|
v claude: registered at /Users/you/.claude.json
|
|
246
297
|
|
|
247
|
-
v verified: codeintel 0.
|
|
298
|
+
v verified: codeintel 0.23.0 — 4 tools (code.query, code.status, code.doctor, code.map)
|
|
248
299
|
```
|
|
249
300
|
|
|
250
301
|
If the command is not on `PATH`, or the server fails to start, install says so and exits non-zero
|
|
@@ -306,7 +357,7 @@ The optional keys are the ones worth reading when an answer surprises you:
|
|
|
306
357
|
|
|
307
358
|
| Engine | Key ops | Install prereq |
|
|
308
359
|
|---|---|---|
|
|
309
|
-
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x** on PATH (`pip install 'codebase-memory-mcp==0.
|
|
360
|
+
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x or 0.10.x** on PATH — both wire dialects are read; `0.10.x` is the more accurate backend and is recommended (`pip install 'codebase-memory-mcp==0.10.*'`). See [docs/graph.md](docs/graph.md) |
|
|
310
361
|
| `lsp` | `symbol`, `overview`, `context` | `uvx` on PATH — serena is fetched from GitHub on first use; see [docs/lsp.md](docs/lsp.md) |
|
|
311
362
|
| `semantic` | `search`, `context` | `fastembed` + `sqlite-vec` (installed with the package) — see [docs/semantic.md](docs/semantic.md) |
|
|
312
363
|
|
|
@@ -359,7 +410,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
359
410
|
|---|---|
|
|
360
411
|
| `codeintel help` | Every command grouped by task, with descriptions and examples (also the bare `codeintel`). A mistyped command suggests what you meant. |
|
|
361
412
|
| `codeintel install [--agent auto\|claude\|codex\|gemini\|zed\|all] [--no-verify] [--relative-command]` | Register codeintel with the agents installed on this machine (`auto`, the default), then prove it by completing a real MCP handshake against the registered command |
|
|
362
|
-
| `codeintel setup [project_root] [--all] [--index] [--warm] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
413
|
+
| `codeintel setup [project_root] [--all] [--index] [--warm] [--languages] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
363
414
|
| `codeintel prompt [project_root] [--agent auto\|claude\|codex\|gemini\|zed] [--fresh] [--deep]` | Print a paste-to-your-agent setup prompt; probes health and emits only the outstanding steps (or "just restart me" when already healthy). `--fresh` = the full sequence from `pip install`, to send a friend |
|
|
364
415
|
| `codeintel index [project_root] [--quiet]` | Index a repo (semantic embeddings + best-effort graph & map refresh), with a live progress display; `--quiet` prints only the result line |
|
|
365
416
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
@@ -369,7 +420,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
369
420
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
370
421
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
371
422
|
| `codeintel graph [project_root] [--html] [--out FILE] [--limit N]` | Emit the call graph as `{nodes,edges}` JSON, or `--html` a self-contained interactive viewer — see [docs/graph-viewer.md](docs/graph-viewer.md) |
|
|
372
|
-
| `codeintel c4 [project_root] [--out DIR] [--depth N] [--scope PATH] [--include-tests] [--no-index] [--json]` | Write a LikeC4 architecture model (`.c4`) of the repo's
|
|
423
|
+
| `codeintel c4 [project_root] [--out DIR] [--depth N] [--scope PATH] [--include-tests] [--no-index] [--edges union\|imports] [--json] [--layers] [--suggest-config] [--check] [--layers-from auto\|inferred\|declared]` | Write a LikeC4 architecture model (`.c4`) of the repo's files and import graph. Indexes the repo first if it has no graph index. `--edges imports` drops the lower-confidence edges for a legible diagram; `--layers` reports inferred architectural bands; `--check` gates CI on a declared `[layers]` config, exit 2 on drift. See [An architecture model, as source](#an-architecture-model-as-source) and [docs/c4.md](docs/c4.md) |
|
|
373
424
|
| `codeintel reset [project_root] [--all] [--yes] [--json]` | Clear this repo's index — **both** semantic and graph — so it's as if never indexed; `--all` wipes every repo. Recovers from a corrupt/stale DB |
|
|
374
425
|
| `codeintel gen-token` | Print a secure random bearer token (for `serve-http` / RBAC `auth.toml`) |
|
|
375
426
|
|
|
@@ -609,7 +660,7 @@ cd codeintel
|
|
|
609
660
|
pip install -e .[dev]
|
|
610
661
|
|
|
611
662
|
pytest tests/ -q # ~740 tests, ~30s; fails under 83% coverage
|
|
612
|
-
ruff check src tests
|
|
663
|
+
ruff check src tests bench # lint
|
|
613
664
|
mypy # types (src/ only)
|
|
614
665
|
```
|
|
615
666
|
|
|
@@ -54,6 +54,14 @@ codeintel = "codeintel.__main__:main"
|
|
|
54
54
|
[project.optional-dependencies]
|
|
55
55
|
dev = ["pytest>=8", "pytest-cov>=5", "numpy>=1.24", "ruff>=0.16", "mypy>=1.11"]
|
|
56
56
|
|
|
57
|
+
# `bench/agent_bench.py` only. Deliberately NOT in `dev`, and emphatically not a runtime dependency:
|
|
58
|
+
# codeintel's own code makes zero outbound HTTP calls and that claim is load-bearing in the README.
|
|
59
|
+
# The agent-cost benchmark is the one artifact here that talks to a model API, it is a manual paid
|
|
60
|
+
# run, and nothing in `src/` or the test suite imports this. Its own extra keeps `dev` (and CI) from
|
|
61
|
+
# installing an API client for code they never execute.
|
|
62
|
+
# pip install -e '.[bench]'
|
|
63
|
+
bench = ["anthropic>=0.40"]
|
|
64
|
+
|
|
57
65
|
# Single source of truth for the version: read from codeintel.__version__ (AST-parsed, no import).
|
|
58
66
|
[tool.setuptools.dynamic]
|
|
59
67
|
version = { attr = "codeintel.__version__" }
|
|
@@ -100,6 +108,17 @@ ignore = [
|
|
|
100
108
|
# manager is a bad trade in code whose whole contract is degrading quietly.
|
|
101
109
|
|
|
102
110
|
[tool.ruff.lint.per-file-ignores]
|
|
111
|
+
# The oracle's fixture corpus is a micro-repository whose SOURCE is the test input. Every finding
|
|
112
|
+
# ruff has here is the property under test: an import that is never used is the `IMPORT` case, a
|
|
113
|
+
# star import is the abstention case, an undefined name is the injected-global case. Fixing them
|
|
114
|
+
# would delete the fixtures. They are ignored as a group rather than with inline `noqa`s, so the
|
|
115
|
+
# corpus keeps looking like the ordinary code it is standing in for.
|
|
116
|
+
"bench/fixtures/corpus/**" = [
|
|
117
|
+
"F401", # imported and never used -> `imports_only.py`, and both re-export links
|
|
118
|
+
"F403", # `import *` -> the star-import abstention
|
|
119
|
+
"F405", # name may be undefined from a star import -> the same file
|
|
120
|
+
"F821", # undefined name -> `injected.py`, the `describe` shape
|
|
121
|
+
]
|
|
103
122
|
# Tests stand up fake servers on loopback, assert on hardcoded fixture tokens, and shell out to
|
|
104
123
|
# the CLI under test. Flagging that as a security finding is noise.
|
|
105
124
|
"tests/*" = [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codecortex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
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
|
|
@@ -33,6 +33,8 @@ Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
|
33
33
|
Requires-Dist: numpy>=1.24; extra == "dev"
|
|
34
34
|
Requires-Dist: ruff>=0.16; extra == "dev"
|
|
35
35
|
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
36
|
+
Provides-Extra: bench
|
|
37
|
+
Requires-Dist: anthropic>=0.40; extra == "bench"
|
|
36
38
|
Dynamic: license-file
|
|
37
39
|
|
|
38
40
|
# codeintel
|
|
@@ -61,9 +63,9 @@ Prefer plain text? `codeintel map` writes a **readable architecture overview** t
|
|
|
61
63
|
|
|
62
64
|
**What `CODE_INTEL.md` is for.** It's a *static, committable* snapshot of a codebase's shape — meant to be read (by a person or an agent) **first**, instead of reconstructing structure by grepping. It covers the cases the live `code.query` tool doesn't:
|
|
63
65
|
|
|
64
|
-
- **Agents & hosts that don't speak MCP.** Not every agent supports MCP, and the server isn't always running. `codeintel map` writes a plain file any agent can read; `codeintel map --inject` also drops a short, tool-naming pointer block into `AGENTS.md` (the cross-tool surface read by Codex, Cursor, Zed, and others — created with your consent if it doesn't exist yet) plus a one-line `@AGENTS.md` import into `CLAUDE.md`, and writes the fuller
|
|
66
|
+
- **Agents & hosts that don't speak MCP.** Not every agent supports MCP, and the server isn't always running. `codeintel map` writes a plain file any agent can read; `codeintel map --inject` also drops a short, tool-naming pointer block into `AGENTS.md` (the cross-tool surface read by Codex, Cursor, Zed, and others — created with your consent if it doesn't exist yet) plus a one-line `@AGENTS.md` import into `CLAUDE.md`, and writes the fuller `USING_CODEINTEL.md` guide the block points to — into **your** repo, which is why there is no such file to click here — so an agent knows to reach for `code.query` before it reaches for grep, not just that a `CODE_INTEL.md` exists.
|
|
65
67
|
- **A committed, diffable overview.** It lives *in the repo* — reviewable in a PR, browsable on GitHub, available offline. Re-run `codeintel map` after `codeintel index` to refresh it.
|
|
66
|
-
- **The load-bearing code at a glance.** Ranking symbols by caller count surfaces what most of the codebase depends on (the risky-to-change core) plus the entry points — the first things a newcomer, or an agent, should understand before touching anything.
|
|
68
|
+
- **The load-bearing code at a glance.** Ranking symbols by caller count surfaces what most of the codebase depends on (the risky-to-change core) plus the entry points — the first things a newcomer, or an agent, should understand before touching anything. The ranking counts `CALLS` edges into **callable** nodes only (functions, methods, classes, interfaces, routes), and skips test, generated and archived files. Both constraints are load-bearing rather than tidy-up: without them a 12,638-node TypeScript repo ranked `logger` (a *folder* node) at 716 and `onClick` at 107, and a Python repo ranked YAML and JSON keys — `flow` from a `.flow.yaml`, `feature` from a `.schema.json` — as its most depended-on symbols. This repo's own map is Python-heavy and barely showed it, which is exactly why dogfooding did not catch it.
|
|
67
69
|
|
|
68
70
|
See **[docs/map-file.md](docs/map-file.md)** for the format and the `--inject` flow.
|
|
69
71
|
|
|
@@ -91,7 +93,7 @@ It's one call: `code.query(op, target, engine="auto")`. In `auto` mode (the defa
|
|
|
91
93
|
| Who calls this? | `callers` | graph | caller symbols + files |
|
|
92
94
|
| What does this call? | `callees` | graph | callee symbols + files |
|
|
93
95
|
| Blast radius of a change | `impact` | graph | callers **and** callees together |
|
|
94
|
-
| Trace a call chain up/downstream | `chain` | graph | ordered,
|
|
96
|
+
| Trace a call chain up/downstream | `chain` | graph | ordered hops, each labelled with how it was resolved |
|
|
95
97
|
| Find symbols by pattern | `pattern` | graph | matching nodes + locations |
|
|
96
98
|
| Project shape at a glance | `overview` | graph → lsp | modules, node/edge counts, languages |
|
|
97
99
|
| Everything about one symbol | `context` | graph + lsp | both views merged |
|
|
@@ -153,6 +155,57 @@ no benefit to set against that error rate.
|
|
|
153
155
|
**Use `callers` on a specific symbol instead.** "Does anything call this?" is exactly the question
|
|
154
156
|
`deadcode` was trying to answer in bulk, and `callers` answers it accurately, one symbol at a time.
|
|
155
157
|
|
|
158
|
+
## An architecture model, as source
|
|
159
|
+
|
|
160
|
+
`codeintel c4` turns the graph index into a [LikeC4](https://likec4.dev) model — architecture-as-code
|
|
161
|
+
you can commit, diff and hand-edit, rather than a rendered picture you have to regenerate to read.
|
|
162
|
+
Abridged output, from `--scope src/codeintel/providers`:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
// Generated by codeintel from the graph index — do not edit by hand.
|
|
166
|
+
// edges: union of IMPORTS (static module-level imports) and CALLS|USAGE (call/usage references)
|
|
167
|
+
// coverage is NOT complete: dispatch through a name/lookup table can still be invisible to both
|
|
168
|
+
// hotspot ranking uses IMPORTS-only fan-in, never the CALLS|USAGE union
|
|
169
|
+
|
|
170
|
+
model {
|
|
171
|
+
src = area 'src' {
|
|
172
|
+
codeintel = area 'codeintel' {
|
|
173
|
+
providers = area 'providers' {
|
|
174
|
+
lsp = module 'lsp' {
|
|
175
|
+
technology 'Python'
|
|
176
|
+
metadata { path 'src/codeintel/providers/lsp.py' churn '12' fan_out '2' }
|
|
177
|
+
}
|
|
178
|
+
graph = module 'graph' { /* … */ }
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
src.codeintel.providers.lsp -[calls_usage]-> src.codeintel.providers.graph { metadata { n '2' } }
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Directories become `area`, files become `module`, and every element carries its real path plus churn
|
|
188
|
+
and fan-in as `metadata` — so the model is queryable, not only drawable. Each file opens with what it
|
|
189
|
+
cannot know: which edge sources it used, that coverage is incomplete, and how many references were
|
|
190
|
+
folded or dropped. `npx likec4 start codeintel-c4` renders it; nothing else here needs Node.
|
|
191
|
+
|
|
192
|
+
**Two edge sources, and the choice matters more than it sounds.** The default unions static `IMPORTS`
|
|
193
|
+
with `CALLS|USAGE`, which recovers lazy and function-body imports. On this repo at
|
|
194
|
+
`--scope src --depth 3` that is 179 relations — **134 of them `CALLS|USAGE`-only**, which renders as a
|
|
195
|
+
hairball. `--edges imports` leaves the same 45 elements with 45 edges: legible, and roughly layered,
|
|
196
|
+
because every remaining edge descends.
|
|
197
|
+
|
|
198
|
+
**It also answers two questions without drawing anything.** `--layers` infers architectural bands
|
|
199
|
+
from the import graph — 7 bands over 35 of those 45 elements, the other 10 having no module-level
|
|
200
|
+
import edge either way. `--check` gates CI on a declared
|
|
201
|
+
`[layers]` block in `.codeintel.toml`, exiting **2** on architectural drift — deliberately distinct
|
|
202
|
+
from exit 1 for a broken run, so a CI step can tell "your architecture drifted" from "codeintel is
|
|
203
|
+
broken". A config generated by `--suggest-config` is a *provably* green baseline on the commit that
|
|
204
|
+
produced it, so adoption is paste-confirm-tighten rather than a wall of false positives.
|
|
205
|
+
|
|
206
|
+
Full reference: **[docs/c4.md](docs/c4.md)**. Why LikeC4 and not something else, measured:
|
|
207
|
+
[docs/eval-2026-08-26-likec4.md](docs/eval-2026-08-26-likec4.md).
|
|
208
|
+
|
|
156
209
|
## What makes it good
|
|
157
210
|
|
|
158
211
|
- **Local-first and private.** One process on your machine — no cloud service, no API keys, no telemetry, no per-query network. Safe to point at a private repo, even with `--engine all`. (The one-time exception: `fastembed` downloads its embedding model once, then runs fully offline.)
|
|
@@ -281,7 +334,7 @@ Then it launches the exact command it registered and drives a real MCP handshake
|
|
|
281
334
|
```text
|
|
282
335
|
v claude: registered at /Users/you/.claude.json
|
|
283
336
|
|
|
284
|
-
v verified: codeintel 0.
|
|
337
|
+
v verified: codeintel 0.23.0 — 4 tools (code.query, code.status, code.doctor, code.map)
|
|
285
338
|
```
|
|
286
339
|
|
|
287
340
|
If the command is not on `PATH`, or the server fails to start, install says so and exits non-zero
|
|
@@ -343,7 +396,7 @@ The optional keys are the ones worth reading when an answer surprises you:
|
|
|
343
396
|
|
|
344
397
|
| Engine | Key ops | Install prereq |
|
|
345
398
|
|---|---|---|
|
|
346
|
-
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x** on PATH (`pip install 'codebase-memory-mcp==0.
|
|
399
|
+
| `graph` | `impact`, `callers`, `callees`, `chain`, `pattern`, `overview`, `context` | `codebase-memory-mcp` **0.9.x or 0.10.x** on PATH — both wire dialects are read; `0.10.x` is the more accurate backend and is recommended (`pip install 'codebase-memory-mcp==0.10.*'`). See [docs/graph.md](docs/graph.md) |
|
|
347
400
|
| `lsp` | `symbol`, `overview`, `context` | `uvx` on PATH — serena is fetched from GitHub on first use; see [docs/lsp.md](docs/lsp.md) |
|
|
348
401
|
| `semantic` | `search`, `context` | `fastembed` + `sqlite-vec` (installed with the package) — see [docs/semantic.md](docs/semantic.md) |
|
|
349
402
|
|
|
@@ -396,7 +449,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
396
449
|
|---|---|
|
|
397
450
|
| `codeintel help` | Every command grouped by task, with descriptions and examples (also the bare `codeintel`). A mistyped command suggests what you meant. |
|
|
398
451
|
| `codeintel install [--agent auto\|claude\|codex\|gemini\|zed\|all] [--no-verify] [--relative-command]` | Register codeintel with the agents installed on this machine (`auto`, the default), then prove it by completing a real MCP handshake against the registered command |
|
|
399
|
-
| `codeintel setup [project_root] [--all] [--index] [--warm] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
452
|
+
| `codeintel setup [project_root] [--all] [--index] [--warm] [--languages] [--install-uv] [--install-deps] [--json]` | Prepare backends + index this repo (`--all` = one command: do everything automatable, idempotent); ends with a health report + **Next:** steps |
|
|
400
453
|
| `codeintel prompt [project_root] [--agent auto\|claude\|codex\|gemini\|zed] [--fresh] [--deep]` | Print a paste-to-your-agent setup prompt; probes health and emits only the outstanding steps (or "just restart me" when already healthy). `--fresh` = the full sequence from `pip install`, to send a friend |
|
|
401
454
|
| `codeintel index [project_root] [--quiet]` | Index a repo (semantic embeddings + best-effort graph & map refresh), with a live progress display; `--quiet` prints only the result line |
|
|
402
455
|
| `codeintel serve` | Start the MCP server (stdio transport) |
|
|
@@ -406,7 +459,7 @@ Full system docs live in [`docs/`](docs/) — start with the index:
|
|
|
406
459
|
| `codeintel doctor [project_root] [--deep] [--json]` | Diagnose per-engine health + repo index status, with a fix for each gap |
|
|
407
460
|
| `codeintel map [project_root]` | Generate the `CODE_INTEL.md` orientation file |
|
|
408
461
|
| `codeintel graph [project_root] [--html] [--out FILE] [--limit N]` | Emit the call graph as `{nodes,edges}` JSON, or `--html` a self-contained interactive viewer — see [docs/graph-viewer.md](docs/graph-viewer.md) |
|
|
409
|
-
| `codeintel c4 [project_root] [--out DIR] [--depth N] [--scope PATH] [--include-tests] [--no-index] [--json]` | Write a LikeC4 architecture model (`.c4`) of the repo's
|
|
462
|
+
| `codeintel c4 [project_root] [--out DIR] [--depth N] [--scope PATH] [--include-tests] [--no-index] [--edges union\|imports] [--json] [--layers] [--suggest-config] [--check] [--layers-from auto\|inferred\|declared]` | Write a LikeC4 architecture model (`.c4`) of the repo's files and import graph. Indexes the repo first if it has no graph index. `--edges imports` drops the lower-confidence edges for a legible diagram; `--layers` reports inferred architectural bands; `--check` gates CI on a declared `[layers]` config, exit 2 on drift. See [An architecture model, as source](#an-architecture-model-as-source) and [docs/c4.md](docs/c4.md) |
|
|
410
463
|
| `codeintel reset [project_root] [--all] [--yes] [--json]` | Clear this repo's index — **both** semantic and graph — so it's as if never indexed; `--all` wipes every repo. Recovers from a corrupt/stale DB |
|
|
411
464
|
| `codeintel gen-token` | Print a secure random bearer token (for `serve-http` / RBAC `auth.toml`) |
|
|
412
465
|
|
|
@@ -646,7 +699,7 @@ cd codeintel
|
|
|
646
699
|
pip install -e .[dev]
|
|
647
700
|
|
|
648
701
|
pytest tests/ -q # ~740 tests, ~30s; fails under 83% coverage
|
|
649
|
-
ruff check src tests
|
|
702
|
+
ruff check src tests bench # lint
|
|
650
703
|
mypy # types (src/ only)
|
|
651
704
|
```
|
|
652
705
|
|
|
@@ -12,6 +12,8 @@ src/codeintel/__main__.py
|
|
|
12
12
|
src/codeintel/agent_prompt.py
|
|
13
13
|
src/codeintel/auth.py
|
|
14
14
|
src/codeintel/c4.py
|
|
15
|
+
src/codeintel/c4_check.py
|
|
16
|
+
src/codeintel/c4_layers.py
|
|
15
17
|
src/codeintel/cache.py
|
|
16
18
|
src/codeintel/config.py
|
|
17
19
|
src/codeintel/containment.py
|
|
@@ -25,6 +27,7 @@ src/codeintel/http_server.py
|
|
|
25
27
|
src/codeintel/indexer.py
|
|
26
28
|
src/codeintel/injector.py
|
|
27
29
|
src/codeintel/installer.py
|
|
30
|
+
src/codeintel/lang_config.py
|
|
28
31
|
src/codeintel/loc.py
|
|
29
32
|
src/codeintel/logconfig.py
|
|
30
33
|
src/codeintel/mapper.py
|
|
@@ -72,7 +75,11 @@ src/codeintel/viewer/__init__.py
|
|
|
72
75
|
src/codeintel/viewer/graph_template.html
|
|
73
76
|
tests/test_agent_prompt.py
|
|
74
77
|
tests/test_backend_reaper.py
|
|
78
|
+
tests/test_bench_oracle.py
|
|
79
|
+
tests/test_bench_oracle_ts.py
|
|
75
80
|
tests/test_c4.py
|
|
81
|
+
tests/test_c4_check.py
|
|
82
|
+
tests/test_c4_layers.py
|
|
76
83
|
tests/test_c4_model.py
|
|
77
84
|
tests/test_c4_output.py
|
|
78
85
|
tests/test_cache.py
|
|
@@ -97,6 +104,7 @@ tests/test_graph_provider.py
|
|
|
97
104
|
tests/test_graph_real.py
|
|
98
105
|
tests/test_graph_stdin.py
|
|
99
106
|
tests/test_grapher.py
|
|
107
|
+
tests/test_hard_exit.py
|
|
100
108
|
tests/test_hardening.py
|
|
101
109
|
tests/test_http_auth.py
|
|
102
110
|
tests/test_http_server.py
|
|
@@ -105,6 +113,7 @@ tests/test_index_progress.py
|
|
|
105
113
|
tests/test_indexer_binary.py
|
|
106
114
|
tests/test_installer.py
|
|
107
115
|
tests/test_integration.py
|
|
116
|
+
tests/test_lang_config.py
|
|
108
117
|
tests/test_loc_census.py
|
|
109
118
|
tests/test_lsp_language_coverage.py
|
|
110
119
|
tests/test_lsp_provider.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.23.0"
|
|
@@ -518,7 +518,36 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
518
518
|
c4_parser.add_argument("--no-index", action="store_true",
|
|
519
519
|
help="Fail instead of indexing an un-indexed repo (default: index it "
|
|
520
520
|
"first, so one command always produces a model)")
|
|
521
|
+
# The union is the default because it has higher recall; a lower-recall default would silently
|
|
522
|
+
# hide real dependencies from anyone who never read this flag. But the union is already excluded
|
|
523
|
+
# from hotspot ranking and layer inference, and it is 75% of the edges on this repo — so the
|
|
524
|
+
# diagram, the one artifact a human reads, needs a way to opt out.
|
|
525
|
+
c4_parser.add_argument("--edges", choices=["union", "imports"], default="union",
|
|
526
|
+
help="Which edges enter the model: `union` (default — IMPORTS plus "
|
|
527
|
+
"CALLS|USAGE, higher recall) or `imports` (static module-level "
|
|
528
|
+
"imports only, far more legible on a large model)")
|
|
521
529
|
c4_parser.add_argument("--json", action="store_true", help="Print the payload; write nothing")
|
|
530
|
+
# Phase 1 of the layer feature is inference only: `--layers` REPORTS the inferred bands, it does
|
|
531
|
+
# not add a view to the model. Named now rather than later so the flag does not change meaning
|
|
532
|
+
# between releases — a `--layers` that printed a summary in one version and emitted a diagram in
|
|
533
|
+
# the next would be the same flag doing two jobs.
|
|
534
|
+
c4_parser.add_argument("--layers", action="store_true",
|
|
535
|
+
help="Print the inferred architectural layers (from IMPORTS only) and "
|
|
536
|
+
"any import cycles. Reports; does not add a view to the model.")
|
|
537
|
+
c4_parser.add_argument("--suggest-config", action="store_true",
|
|
538
|
+
help="Print a pasteable [layers] TOML block from the inferred ranks and "
|
|
539
|
+
"write nothing — a green baseline on the tree that generated it")
|
|
540
|
+
# Exit 2, not 1. A CI step must be able to tell "codeintel is broken / the repo is not indexed"
|
|
541
|
+
# from "your architecture drifted": conflate them and the first person to hit a broken index
|
|
542
|
+
# allowlists the failure, and the gate is dead.
|
|
543
|
+
c4_parser.add_argument("--check", action="store_true",
|
|
544
|
+
help="Check the declared [layers] config in .codeintel.toml and exit 2 "
|
|
545
|
+
"on gating findings. Still writes the model. Exits 0 with a note if "
|
|
546
|
+
"no [layers] block exists — nobody gets a wall they did not ask for.")
|
|
547
|
+
c4_parser.add_argument("--layers-from", choices=["auto", "inferred", "declared"], default="auto",
|
|
548
|
+
help="Which ranking to report (default: auto — declared if a [layers] "
|
|
549
|
+
"block exists, else inferred). `declared` exits 1 if none exists, so "
|
|
550
|
+
"CI can assert that a config had better be present.")
|
|
522
551
|
|
|
523
552
|
# doctor subcommand
|
|
524
553
|
doctor_parser = subparsers.add_parser(
|
|
@@ -543,6 +572,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
543
572
|
setup_parser.add_argument("--index", action="store_true",
|
|
544
573
|
help="Index this repo now (first run downloads the ~50MB model)")
|
|
545
574
|
setup_parser.add_argument("--warm", action="store_true", help="Boot serena now (first run pulls it via uvx; slow)")
|
|
575
|
+
# Editing the user's serena config is a real side effect, so it needs its own flag — `run_setup`'s
|
|
576
|
+
# rule is that each flag IS consent. Without it the step still runs and reports what it WOULD do.
|
|
577
|
+
setup_parser.add_argument("--languages", action="store_true",
|
|
578
|
+
help="Add every language this repo contains to `language_servers:` in "
|
|
579
|
+
".serena/project.yml, so the LSP engine stops silently returning "
|
|
580
|
+
"nothing for the languages serena was not configured to serve")
|
|
546
581
|
setup_parser.add_argument("--json", action="store_true", help="Emit the structured JSON report")
|
|
547
582
|
|
|
548
583
|
# prompt subcommand
|