cocoindex-code 0.2.36__tar.gz → 0.2.38__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. cocoindex_code-0.2.36/README.md → cocoindex_code-0.2.38/PKG-INFO +160 -3
  2. cocoindex_code-0.2.36/PKG-INFO → cocoindex_code-0.2.38/README.md +116 -47
  3. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/pyproject.toml +5 -5
  4. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/_daemon_paths.py +50 -0
  5. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/_version.py +2 -2
  6. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/cli.py +134 -19
  7. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/client.py +106 -19
  8. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/daemon.py +175 -29
  9. cocoindex_code-0.2.36/src/cocoindex_code/indexer.py → cocoindex_code-0.2.38/src/cocoindex_code/file_walk.py +63 -118
  10. cocoindex_code-0.2.38/src/cocoindex_code/grep.py +411 -0
  11. cocoindex_code-0.2.38/src/cocoindex_code/indexer.py +123 -0
  12. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/protocol.py +25 -0
  13. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/server.py +50 -2
  14. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/settings.py +18 -1
  15. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/.gitignore +0 -0
  16. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/LICENSE +0 -0
  17. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/__init__.py +0 -0
  18. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/__main__.py +0 -0
  19. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/chunking.py +0 -0
  20. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/embedder_defaults.py +0 -0
  21. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/embedder_params.py +0 -0
  22. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/litellm_embedder.py +0 -0
  23. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/project.py +0 -0
  24. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/query.py +0 -0
  25. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/schema.py +0 -0
  26. {cocoindex_code-0.2.36 → cocoindex_code-0.2.38}/src/cocoindex_code/shared.py +0 -0
@@ -1,3 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: cocoindex-code
3
+ Version: 0.2.38
4
+ Summary: MCP server for indexing and querying codebases using CocoIndex
5
+ Project-URL: Homepage, https://github.com/cocoindex-io/cocoindex-code
6
+ Project-URL: Repository, https://github.com/cocoindex-io/cocoindex-code
7
+ Project-URL: Issues, https://github.com/cocoindex-io/cocoindex-code/issues
8
+ License-Expression: Apache-2.0
9
+ License-File: LICENSE
10
+ Keywords: cocoindex,codebase,indexing,mcp,vector-search
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: cocoindex[litellm]<1.1.0,>=1.0.13
21
+ Requires-Dist: einops>=0.8.2
22
+ Requires-Dist: mcp>=1.0.0
23
+ Requires-Dist: msgspec>=0.19.0
24
+ Requires-Dist: numpy>=1.24.0
25
+ Requires-Dist: pathspec>=0.12.1
26
+ Requires-Dist: pydantic>=2.0.0
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: questionary>=2.0.0
29
+ Requires-Dist: sqlite-vec>=0.1.0
30
+ Requires-Dist: typer>=0.9.0
31
+ Provides-Extra: dev
32
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.13; extra == 'dev'
33
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
+ Requires-Dist: prek>=0.1.0; extra == 'dev'
35
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
36
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
37
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
38
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
39
+ Provides-Extra: embeddings-local
40
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.13; extra == 'embeddings-local'
41
+ Provides-Extra: full
42
+ Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.13; extra == 'full'
43
+ Description-Content-Type: text/markdown
44
+
1
45
  <p align="center">
2
46
  <img width="2428" alt="cocoindex code" src="https://github.com/user-attachments/assets/d05961b4-0b7b-42ea-834a-59c3c01717ca" />
3
47
  </p>
@@ -63,6 +107,8 @@ Next, set up your [coding agent integration](#coding-agent-integration) — or j
63
107
 
64
108
  ## Coding Agent Integration
65
109
 
110
+ This repository is a **single plugin marketplace** (`.claude-plugin/marketplace.json`) consumed by both **Claude Code** and **Grok** — same plugin id `cocoindex-code`, same `ccc` skill. Grok optionally activates the bundled hooks and MCP server with `--trust`; Claude Code users can install the same marketplace and rely on the skill alone or load hooks/MCP from the plugin as needed.
111
+
66
112
  ### Skill (Recommended)
67
113
 
68
114
  Install the `ccc` skill so your coding agent automatically uses semantic search when needed:
@@ -82,11 +128,59 @@ Works with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and oth
82
128
  For Claude Code users, this repository is also a [plugin marketplace](https://code.claude.com/docs/en/plugin-marketplaces). Install the skill from inside Claude Code with:
83
129
 
84
130
  ```text
85
- /plugin marketplace add Roxabi/cocoindex-code
131
+ /plugin marketplace add cocoindex-io/cocoindex-code
86
132
  /plugin install cocoindex-code@cocoindex-code
87
133
  ```
88
134
 
89
- This bundles the same `ccc` skill, with version pinning and `/plugin marketplace update` for updates.
135
+ This bundles the same `ccc` skill, with version pinning and `/plugin marketplace update` for updates. The repository also ships `hooks/hooks.json` and `.mcp.json` for Grok (and Claude Code plugin installs that load those files); Claude users who want skill-only search can rely on the skill alone and add MCP manually in the [MCP Server](#mcp-server) section below instead of using the bundled `.mcp.json`.
136
+
137
+ #### Grok plugin
138
+
139
+ For [Grok](https://github.com/xai-org/grok) users, install via Grok's plugin system. The plugin bundles three components:
140
+
141
+ | Component | Purpose |
142
+ |-----------|---------|
143
+ | **Skill** (`skills/ccc/`) | Agent runs `ccc search` / `ccc index` via the CLI (same as Claude Code above) |
144
+ | **Hook** (`hooks/hooks.json`) | `SessionStart` → incremental `ccc index` when `.cocoindex_code/` exists |
145
+ | **MCP** (`.mcp.json`) | `ccc mcp` stdio server — `search` tool with `refresh_index=true` by default |
146
+
147
+ Grok does **not** import Claude's `enabledPlugins` or plugin cache; install separately even if you already use cocoindex in Claude Code.
148
+
149
+ **Full install** (skill + hook + MCP):
150
+
151
+ ```bash
152
+ grok plugin marketplace add cocoindex-io/cocoindex-code
153
+ grok plugin install cocoindex-io/cocoindex-code --trust
154
+ grok plugin enable cocoindex-code
155
+ ```
156
+
157
+ Prefer the GitHub shorthand (`cocoindex-io/cocoindex-code`) for install — `grok plugin install cocoindex-code` can fail when no marketplace plugin matches that bare name.
158
+
159
+ `--trust` is required so Grok activates the plugin's hooks and MCP server (skills load when the plugin is enabled).
160
+
161
+ **Skill-only** (match Claude Code — no auto-index hook, no MCP tool):
162
+
163
+ Install and enable as above, then disable the optional components:
164
+
165
+ 1. **Hooks** — open `/hooks`, select the `SessionStart` hook from `cocoindex-code`, press `Space` to disable.
166
+ 2. **MCP** — open `/mcps`, select `cocoindex-code`, press `Space` to disable; or persist in `~/.grok/config.toml`:
167
+
168
+ ```toml
169
+ [mcp_servers.cocoindex-code]
170
+ enabled = false
171
+ ```
172
+
173
+ The agent still owns indexing via the `ccc` skill (`ccc index` / `ccc search --refresh` when stale), same as Claude Code.
174
+
175
+ To avoid importing MCP servers from your Claude/Cursor user config (unrelated to this plugin):
176
+
177
+ ```toml
178
+ [compat.claude]
179
+ mcps = false
180
+
181
+ [compat.cursor]
182
+ mcps = false
183
+ ```
90
184
 
91
185
  ### MCP Server
92
186
 
@@ -134,6 +228,24 @@ Or use opencode.json:
134
228
  ```
135
229
  </details>
136
230
 
231
+ <details>
232
+ <summary>Kilo Code</summary>
233
+
234
+ Add a local MCP server in `~/.config/kilo/kilo.jsonc`, `kilo.jsonc`, or `.kilo/kilo.jsonc`:
235
+
236
+ ```json
237
+ {
238
+ "mcp": {
239
+ "cocoindex-code": {
240
+ "type": "local",
241
+ "command": ["ccc", "mcp"],
242
+ "enabled": true
243
+ }
244
+ }
245
+ }
246
+ ```
247
+ </details>
248
+
137
249
  Once configured, the agent automatically decides when semantic code search is helpful — finding code by description, exploring unfamiliar codebases, fuzzy/conceptual matches, or locating implementations without knowing exact names.
138
250
 
139
251
  > **Note:** The `cocoindex-code` command (without subcommand) still works as an MCP server for backward compatibility. It auto-creates settings from environment variables on first run.
@@ -171,7 +283,7 @@ ccc search "authentication logic" # search!
171
283
 
172
284
  The background daemon starts automatically on first use.
173
285
 
174
- > **Tip:** `ccc index` auto-initializes if you haven't run `ccc init` yet, so you can skip straight to indexing.
286
+ > **Tip:** You can skip `ccc init` and go straight to `ccc index` — it auto-initializes new projects with default settings. If global settings are missing too (first use on the machine), it walks you through the same model setup as `ccc init` when run interactively; non-interactive runs (scripts, hooks) still require a one-time `ccc init` first.
175
287
 
176
288
  ### CLI Reference
177
289
 
@@ -180,6 +292,7 @@ The background daemon starts automatically on first use.
180
292
  | `ccc init` | Initialize a project — creates settings files, adds `.cocoindex_code/` to `.gitignore` |
181
293
  | `ccc index` | Build or update the index (auto-inits if needed). Shows streaming progress. |
182
294
  | `ccc search <query>` | Semantic search across the codebase |
295
+ | `ccc grep <pattern> [path]` | Structural code search by example (no index needed) |
183
296
  | `ccc status` | Show index stats (chunk count, file count, language breakdown) |
184
297
  | `ccc mcp` | Run as MCP server in stdio mode |
185
298
  | `ccc doctor` | Run diagnostics — checks settings, daemon, model, file matching, and index health |
@@ -200,6 +313,36 @@ ccc search --refresh database schema # update index first, then
200
313
 
201
314
  By default, `ccc search` scopes results to your current working directory (relative to the project root). Use `--path` to override.
202
315
 
316
+ ### Structural Search (`ccc grep`)
317
+
318
+ `ccc grep` finds code by **structure**, not text — you write a by-example pattern
319
+ and it matches the syntax tree (via cocoindex's `code_match`), so formatting,
320
+ whitespace, and intervening tokens don't matter. It runs entirely locally: no
321
+ index, daemon, or embeddings required.
322
+
323
+ ```bash
324
+ ccc grep 'def \NAME(\(ARGS*\)):' # every Python function def under the cwd
325
+ ccc grep 'foo(\(ARGS*\))' src/ # calls to foo(...) anywhere under src/
326
+ ccc grep 'fn \NAME(\(A*\))' --lang rust # restrict to one language
327
+ ccc grep 'class \NAME:' --path 'tests/**' # restrict to a path glob
328
+ ccc grep 'TODO(\(A*\))' path/to/file.py # a single file
329
+ ```
330
+
331
+ Metavariables use the `\` sigil: `\NAME` captures one node, `\(NAME*\)` a run of
332
+ siblings, `\_`/`\*` match anonymously. The pattern is matched per language, so a
333
+ single invocation scans every supported source file (others are skipped). Inside
334
+ an initialized project, `ccc grep` honors the project's include/exclude patterns
335
+ and `.gitignore`; otherwise it scans all supported source files under the path.
336
+
337
+ Results stream to the terminal file-by-file as each match is found (in completion
338
+ order, since files are matched in parallel) rather than all at once at the end.
339
+ Each matching file shows its matched line range; under a TTY the path is colored,
340
+ line numbers are dimmed, and the unmatched context around a match is dimmed so the
341
+ match stands out.
342
+
343
+ > **Note:** `ccc grep` relies on cocoindex's structural `code_match` feature.
344
+ > Until it ships in a released cocoindex, run against a local cocoindex build.
345
+
203
346
  ## Docker
204
347
 
205
348
  A Docker image is available for teams who want a reproducible, dependency-free
@@ -416,10 +559,15 @@ embedding:
416
559
 
417
560
  envs: # extra environment variables for the daemon
418
561
  OPENAI_API_KEY: your-key # only needed if not already in your shell environment
562
+
563
+ daemon:
564
+ idle_timeout_minutes: 180 # optional: exit the daemon after this long without client activity (default 180, 0 = never)
419
565
  ```
420
566
 
421
567
  > **Note:** The daemon inherits your shell environment. If an API key (e.g. `OPENAI_API_KEY`) is already set as an environment variable, you don't need to duplicate it in `envs`. The `envs` field is only for values that aren't in your environment.
422
568
 
569
+ > **Idle timeout:** the background daemon holds the embedding model in RAM, so it exits after `daemon.idle_timeout_minutes` without client activity and is restarted automatically on your next `ccc` command or MCP search. A live MCP session sends periodic heartbeats, so the daemon never idles out while your coding agent is connected. Set `0` to keep the daemon running forever.
570
+
423
571
  > **Custom location:** set `COCOINDEX_CODE_DIR` to place `global_settings.yml` somewhere other than `~/.cocoindex_code/` — useful if you want the file to live alongside your projects (e.g. on a synced folder).
424
572
 
425
573
  #### `indexing_params` / `query_params`
@@ -477,6 +625,14 @@ chunkers:
477
625
 
478
626
  > `.cocoindex_code/` is automatically added to `.gitignore` during init.
479
627
 
628
+ After editing `include_patterns`, `exclude_patterns`, or `language_overrides`:
629
+
630
+ - Run `ccc doctor` to preview which files match.
631
+ - Run `ccc index` or `ccc search --refresh ...` to update the existing index.
632
+ - You do not need to delete the index or restart the daemon for these file-matching changes.
633
+
634
+ If you add or change custom `chunkers`, restart the daemon first so the chunker registry is reloaded, then run `ccc index`.
635
+
480
636
  Use `chunkers` when you want to control how a file type is split into chunks before indexing.
481
637
 
482
638
  `module: example_toml_chunker:toml_chunker` means:
@@ -675,6 +831,7 @@ embedding:
675
831
  | cpp | c++ | `.cpp`, `.cc`, `.cxx`, `.h`, `.hpp` |
676
832
  | csharp | csharp, cs | `.cs` |
677
833
  | css | | `.css`, `.scss` |
834
+ | dart | | `.dart` |
678
835
  | dtd | | `.dtd` |
679
836
  | fortran | f, f90, f95, f03 | `.f`, `.f90`, `.f95`, `.f03` |
680
837
  | go | golang | `.go` |
@@ -1,47 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: cocoindex-code
3
- Version: 0.2.36
4
- Summary: MCP server for indexing and querying codebases using CocoIndex
5
- Project-URL: Homepage, https://github.com/cocoindex-io/cocoindex-code
6
- Project-URL: Repository, https://github.com/cocoindex-io/cocoindex-code
7
- Project-URL: Issues, https://github.com/cocoindex-io/cocoindex-code/issues
8
- License-Expression: Apache-2.0
9
- License-File: LICENSE
10
- Keywords: cocoindex,codebase,indexing,mcp,vector-search
11
- Classifier: Development Status :: 3 - Alpha
12
- Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: Apache Software License
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: Programming Language :: Python :: 3.11
16
- Classifier: Programming Language :: Python :: 3.12
17
- Classifier: Programming Language :: Python :: 3.13
18
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
- Requires-Python: >=3.11
20
- Requires-Dist: cocoindex[litellm]<1.1.0,>=1.0.6
21
- Requires-Dist: einops>=0.8.2
22
- Requires-Dist: mcp>=1.0.0
23
- Requires-Dist: msgspec>=0.19.0
24
- Requires-Dist: numpy>=1.24.0
25
- Requires-Dist: pathspec>=0.12.1
26
- Requires-Dist: pydantic>=2.0.0
27
- Requires-Dist: pyyaml>=6.0
28
- Requires-Dist: questionary>=2.0.0
29
- Requires-Dist: sqlite-vec>=0.1.0
30
- Requires-Dist: typer>=0.9.0
31
- Provides-Extra: dev
32
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'dev'
33
- Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
- Requires-Dist: prek>=0.1.0; extra == 'dev'
35
- Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
36
- Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
37
- Requires-Dist: pytest>=7.0.0; extra == 'dev'
38
- Requires-Dist: ruff>=0.1.0; extra == 'dev'
39
- Provides-Extra: embeddings-local
40
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'embeddings-local'
41
- Provides-Extra: full
42
- Requires-Dist: cocoindex[sentence-transformers]<1.1.0,>=1.0.6; extra == 'full'
43
- Description-Content-Type: text/markdown
44
-
45
1
  <p align="center">
46
2
  <img width="2428" alt="cocoindex code" src="https://github.com/user-attachments/assets/d05961b4-0b7b-42ea-834a-59c3c01717ca" />
47
3
  </p>
@@ -107,6 +63,8 @@ Next, set up your [coding agent integration](#coding-agent-integration) — or j
107
63
 
108
64
  ## Coding Agent Integration
109
65
 
66
+ This repository is a **single plugin marketplace** (`.claude-plugin/marketplace.json`) consumed by both **Claude Code** and **Grok** — same plugin id `cocoindex-code`, same `ccc` skill. Grok optionally activates the bundled hooks and MCP server with `--trust`; Claude Code users can install the same marketplace and rely on the skill alone or load hooks/MCP from the plugin as needed.
67
+
110
68
  ### Skill (Recommended)
111
69
 
112
70
  Install the `ccc` skill so your coding agent automatically uses semantic search when needed:
@@ -126,11 +84,59 @@ Works with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and oth
126
84
  For Claude Code users, this repository is also a [plugin marketplace](https://code.claude.com/docs/en/plugin-marketplaces). Install the skill from inside Claude Code with:
127
85
 
128
86
  ```text
129
- /plugin marketplace add Roxabi/cocoindex-code
87
+ /plugin marketplace add cocoindex-io/cocoindex-code
130
88
  /plugin install cocoindex-code@cocoindex-code
131
89
  ```
132
90
 
133
- This bundles the same `ccc` skill, with version pinning and `/plugin marketplace update` for updates.
91
+ This bundles the same `ccc` skill, with version pinning and `/plugin marketplace update` for updates. The repository also ships `hooks/hooks.json` and `.mcp.json` for Grok (and Claude Code plugin installs that load those files); Claude users who want skill-only search can rely on the skill alone and add MCP manually in the [MCP Server](#mcp-server) section below instead of using the bundled `.mcp.json`.
92
+
93
+ #### Grok plugin
94
+
95
+ For [Grok](https://github.com/xai-org/grok) users, install via Grok's plugin system. The plugin bundles three components:
96
+
97
+ | Component | Purpose |
98
+ |-----------|---------|
99
+ | **Skill** (`skills/ccc/`) | Agent runs `ccc search` / `ccc index` via the CLI (same as Claude Code above) |
100
+ | **Hook** (`hooks/hooks.json`) | `SessionStart` → incremental `ccc index` when `.cocoindex_code/` exists |
101
+ | **MCP** (`.mcp.json`) | `ccc mcp` stdio server — `search` tool with `refresh_index=true` by default |
102
+
103
+ Grok does **not** import Claude's `enabledPlugins` or plugin cache; install separately even if you already use cocoindex in Claude Code.
104
+
105
+ **Full install** (skill + hook + MCP):
106
+
107
+ ```bash
108
+ grok plugin marketplace add cocoindex-io/cocoindex-code
109
+ grok plugin install cocoindex-io/cocoindex-code --trust
110
+ grok plugin enable cocoindex-code
111
+ ```
112
+
113
+ Prefer the GitHub shorthand (`cocoindex-io/cocoindex-code`) for install — `grok plugin install cocoindex-code` can fail when no marketplace plugin matches that bare name.
114
+
115
+ `--trust` is required so Grok activates the plugin's hooks and MCP server (skills load when the plugin is enabled).
116
+
117
+ **Skill-only** (match Claude Code — no auto-index hook, no MCP tool):
118
+
119
+ Install and enable as above, then disable the optional components:
120
+
121
+ 1. **Hooks** — open `/hooks`, select the `SessionStart` hook from `cocoindex-code`, press `Space` to disable.
122
+ 2. **MCP** — open `/mcps`, select `cocoindex-code`, press `Space` to disable; or persist in `~/.grok/config.toml`:
123
+
124
+ ```toml
125
+ [mcp_servers.cocoindex-code]
126
+ enabled = false
127
+ ```
128
+
129
+ The agent still owns indexing via the `ccc` skill (`ccc index` / `ccc search --refresh` when stale), same as Claude Code.
130
+
131
+ To avoid importing MCP servers from your Claude/Cursor user config (unrelated to this plugin):
132
+
133
+ ```toml
134
+ [compat.claude]
135
+ mcps = false
136
+
137
+ [compat.cursor]
138
+ mcps = false
139
+ ```
134
140
 
135
141
  ### MCP Server
136
142
 
@@ -178,6 +184,24 @@ Or use opencode.json:
178
184
  ```
179
185
  </details>
180
186
 
187
+ <details>
188
+ <summary>Kilo Code</summary>
189
+
190
+ Add a local MCP server in `~/.config/kilo/kilo.jsonc`, `kilo.jsonc`, or `.kilo/kilo.jsonc`:
191
+
192
+ ```json
193
+ {
194
+ "mcp": {
195
+ "cocoindex-code": {
196
+ "type": "local",
197
+ "command": ["ccc", "mcp"],
198
+ "enabled": true
199
+ }
200
+ }
201
+ }
202
+ ```
203
+ </details>
204
+
181
205
  Once configured, the agent automatically decides when semantic code search is helpful — finding code by description, exploring unfamiliar codebases, fuzzy/conceptual matches, or locating implementations without knowing exact names.
182
206
 
183
207
  > **Note:** The `cocoindex-code` command (without subcommand) still works as an MCP server for backward compatibility. It auto-creates settings from environment variables on first run.
@@ -215,7 +239,7 @@ ccc search "authentication logic" # search!
215
239
 
216
240
  The background daemon starts automatically on first use.
217
241
 
218
- > **Tip:** `ccc index` auto-initializes if you haven't run `ccc init` yet, so you can skip straight to indexing.
242
+ > **Tip:** You can skip `ccc init` and go straight to `ccc index` — it auto-initializes new projects with default settings. If global settings are missing too (first use on the machine), it walks you through the same model setup as `ccc init` when run interactively; non-interactive runs (scripts, hooks) still require a one-time `ccc init` first.
219
243
 
220
244
  ### CLI Reference
221
245
 
@@ -224,6 +248,7 @@ The background daemon starts automatically on first use.
224
248
  | `ccc init` | Initialize a project — creates settings files, adds `.cocoindex_code/` to `.gitignore` |
225
249
  | `ccc index` | Build or update the index (auto-inits if needed). Shows streaming progress. |
226
250
  | `ccc search <query>` | Semantic search across the codebase |
251
+ | `ccc grep <pattern> [path]` | Structural code search by example (no index needed) |
227
252
  | `ccc status` | Show index stats (chunk count, file count, language breakdown) |
228
253
  | `ccc mcp` | Run as MCP server in stdio mode |
229
254
  | `ccc doctor` | Run diagnostics — checks settings, daemon, model, file matching, and index health |
@@ -244,6 +269,36 @@ ccc search --refresh database schema # update index first, then
244
269
 
245
270
  By default, `ccc search` scopes results to your current working directory (relative to the project root). Use `--path` to override.
246
271
 
272
+ ### Structural Search (`ccc grep`)
273
+
274
+ `ccc grep` finds code by **structure**, not text — you write a by-example pattern
275
+ and it matches the syntax tree (via cocoindex's `code_match`), so formatting,
276
+ whitespace, and intervening tokens don't matter. It runs entirely locally: no
277
+ index, daemon, or embeddings required.
278
+
279
+ ```bash
280
+ ccc grep 'def \NAME(\(ARGS*\)):' # every Python function def under the cwd
281
+ ccc grep 'foo(\(ARGS*\))' src/ # calls to foo(...) anywhere under src/
282
+ ccc grep 'fn \NAME(\(A*\))' --lang rust # restrict to one language
283
+ ccc grep 'class \NAME:' --path 'tests/**' # restrict to a path glob
284
+ ccc grep 'TODO(\(A*\))' path/to/file.py # a single file
285
+ ```
286
+
287
+ Metavariables use the `\` sigil: `\NAME` captures one node, `\(NAME*\)` a run of
288
+ siblings, `\_`/`\*` match anonymously. The pattern is matched per language, so a
289
+ single invocation scans every supported source file (others are skipped). Inside
290
+ an initialized project, `ccc grep` honors the project's include/exclude patterns
291
+ and `.gitignore`; otherwise it scans all supported source files under the path.
292
+
293
+ Results stream to the terminal file-by-file as each match is found (in completion
294
+ order, since files are matched in parallel) rather than all at once at the end.
295
+ Each matching file shows its matched line range; under a TTY the path is colored,
296
+ line numbers are dimmed, and the unmatched context around a match is dimmed so the
297
+ match stands out.
298
+
299
+ > **Note:** `ccc grep` relies on cocoindex's structural `code_match` feature.
300
+ > Until it ships in a released cocoindex, run against a local cocoindex build.
301
+
247
302
  ## Docker
248
303
 
249
304
  A Docker image is available for teams who want a reproducible, dependency-free
@@ -460,10 +515,15 @@ embedding:
460
515
 
461
516
  envs: # extra environment variables for the daemon
462
517
  OPENAI_API_KEY: your-key # only needed if not already in your shell environment
518
+
519
+ daemon:
520
+ idle_timeout_minutes: 180 # optional: exit the daemon after this long without client activity (default 180, 0 = never)
463
521
  ```
464
522
 
465
523
  > **Note:** The daemon inherits your shell environment. If an API key (e.g. `OPENAI_API_KEY`) is already set as an environment variable, you don't need to duplicate it in `envs`. The `envs` field is only for values that aren't in your environment.
466
524
 
525
+ > **Idle timeout:** the background daemon holds the embedding model in RAM, so it exits after `daemon.idle_timeout_minutes` without client activity and is restarted automatically on your next `ccc` command or MCP search. A live MCP session sends periodic heartbeats, so the daemon never idles out while your coding agent is connected. Set `0` to keep the daemon running forever.
526
+
467
527
  > **Custom location:** set `COCOINDEX_CODE_DIR` to place `global_settings.yml` somewhere other than `~/.cocoindex_code/` — useful if you want the file to live alongside your projects (e.g. on a synced folder).
468
528
 
469
529
  #### `indexing_params` / `query_params`
@@ -521,6 +581,14 @@ chunkers:
521
581
 
522
582
  > `.cocoindex_code/` is automatically added to `.gitignore` during init.
523
583
 
584
+ After editing `include_patterns`, `exclude_patterns`, or `language_overrides`:
585
+
586
+ - Run `ccc doctor` to preview which files match.
587
+ - Run `ccc index` or `ccc search --refresh ...` to update the existing index.
588
+ - You do not need to delete the index or restart the daemon for these file-matching changes.
589
+
590
+ If you add or change custom `chunkers`, restart the daemon first so the chunker registry is reloaded, then run `ccc index`.
591
+
524
592
  Use `chunkers` when you want to control how a file type is split into chunks before indexing.
525
593
 
526
594
  `module: example_toml_chunker:toml_chunker` means:
@@ -719,6 +787,7 @@ embedding:
719
787
  | cpp | c++ | `.cpp`, `.cc`, `.cxx`, `.h`, `.hpp` |
720
788
  | csharp | csharp, cs | `.cs` |
721
789
  | css | | `.css`, `.scss` |
790
+ | dart | | `.dart` |
722
791
  | dtd | | `.dtd` |
723
792
  | fortran | f, f90, f95, f03 | `.f`, `.f90`, `.f95`, `.f03` |
724
793
  | go | golang | `.go` |
@@ -23,7 +23,7 @@ classifiers = [
23
23
 
24
24
  dependencies = [
25
25
  "mcp>=1.0.0",
26
- "cocoindex[litellm]>=1.0.6,<1.1.0",
26
+ "cocoindex[litellm]>=1.0.13,<1.1.0",
27
27
  "sqlite-vec>=0.1.0",
28
28
  "pydantic>=2.0.0",
29
29
  "numpy>=1.24.0",
@@ -39,7 +39,7 @@ dependencies = [
39
39
  # `embeddings-local` is the primary feature extra: it pulls in
40
40
  # `sentence-transformers` (via cocoindex) so local embeddings work without
41
41
  # an API key.
42
- embeddings-local = ["cocoindex[sentence-transformers]>=1.0.6,<1.1.0"]
42
+ embeddings-local = ["cocoindex[sentence-transformers]>=1.0.13,<1.1.0"]
43
43
  # `full` is the umbrella "batteries-included" alias. Today it's just
44
44
  # `embeddings-local`, but we expect to bundle more optional niceties under
45
45
  # it over time — users who want everything can keep using `[full]` and pick
@@ -47,7 +47,7 @@ embeddings-local = ["cocoindex[sentence-transformers]>=1.0.6,<1.1.0"]
47
47
  # `:full` image variant for consistency across install paths. Contents are
48
48
  # inlined rather than self-referencing `cocoindex-code[embeddings-local]`
49
49
  # to avoid resolver edge cases with older pip.
50
- full = ["cocoindex[sentence-transformers]>=1.0.6,<1.1.0"]
50
+ full = ["cocoindex[sentence-transformers]>=1.0.13,<1.1.0"]
51
51
  dev = [
52
52
  "pytest>=7.0.0",
53
53
  "pytest-asyncio>=0.21.0",
@@ -55,7 +55,7 @@ dev = [
55
55
  "ruff>=0.1.0",
56
56
  "mypy>=1.0.0",
57
57
  "prek>=0.1.0",
58
- "cocoindex[sentence-transformers]>=1.0.6,<1.1.0",
58
+ "cocoindex[sentence-transformers]>=1.0.13,<1.1.0",
59
59
  ]
60
60
 
61
61
  [project.scripts]
@@ -89,7 +89,7 @@ dev = [
89
89
  "mypy>=1.0.0",
90
90
  "prek>=0.1.0",
91
91
  "types-pyyaml>=6.0.12.20250915",
92
- "cocoindex[sentence-transformers]>=1.0.7,<1.1.0",
92
+ "cocoindex[sentence-transformers]>=1.0.13,<1.1.0",
93
93
  ]
94
94
 
95
95
  [tool.ruff]
@@ -6,8 +6,11 @@ can import these without pulling in the full daemon stack.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
+ import json
9
10
  import os
10
11
  import sys
12
+ import time
13
+ from dataclasses import dataclass
11
14
  from pathlib import Path
12
15
 
13
16
  from .settings import user_settings_dir
@@ -58,3 +61,50 @@ def daemon_pid_path() -> Path:
58
61
  def daemon_log_path() -> Path:
59
62
  """Return the path for the daemon's log file."""
60
63
  return daemon_runtime_dir() / "daemon.log"
64
+
65
+
66
+ def daemon_last_exit_path() -> Path:
67
+ """Return the path for the daemon's graceful-exit marker file."""
68
+ return daemon_runtime_dir() / "last_exit"
69
+
70
+
71
+ @dataclass
72
+ class LastExitMarker:
73
+ """Record of the most recent *graceful* daemon exit.
74
+
75
+ Written by the daemon's graceful shutdown path (``StopRequest``,
76
+ SIGTERM/SIGINT) and removed again at the next daemon startup. A crashed
77
+ daemon (SIGKILL, OOM, segfault) never writes it — that absence is how the
78
+ client tells a crash from a graceful exit.
79
+ """
80
+
81
+ pid: int
82
+ reason: str
83
+ timestamp: float
84
+
85
+
86
+ def write_last_exit_marker(pid: int, reason: str) -> None:
87
+ """Persist the graceful-exit marker. Best-effort — never raises."""
88
+ payload = json.dumps({"pid": pid, "reason": reason, "timestamp": time.time()})
89
+ try:
90
+ daemon_last_exit_path().write_text(payload)
91
+ except OSError:
92
+ pass
93
+
94
+
95
+ def read_last_exit_marker() -> LastExitMarker | None:
96
+ """Read the graceful-exit marker, or None when absent/unreadable."""
97
+ try:
98
+ data = json.loads(daemon_last_exit_path().read_text())
99
+ return LastExitMarker(
100
+ pid=int(data["pid"]),
101
+ reason=str(data["reason"]),
102
+ timestamp=float(data["timestamp"]),
103
+ )
104
+ except (OSError, ValueError, KeyError, TypeError):
105
+ return None
106
+
107
+
108
+ def clear_last_exit_marker() -> None:
109
+ """Remove the marker (daemon startup) so it always refers to the most recent exit."""
110
+ daemon_last_exit_path().unlink(missing_ok=True)
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.2.36'
22
- __version_tuple__ = version_tuple = (0, 2, 36)
21
+ __version__ = version = '0.2.38'
22
+ __version_tuple__ = version_tuple = (0, 2, 38)
23
23
 
24
24
  __commit_id__ = commit_id = None