* docs(rust): document how the port uses the CocoIndex Rust SDK
Add a "How it uses the CocoIndex Rust SDK" section to rust/PORTING.md — a
code-grounded walkthrough of the SDK API the port exercises (Environment/App/run,
ContextKey DI + change detection, #[cocoindex::function] memoization, walk_dir +
mount_each!, the sqlite/vec0 table target + declare_row, and the sqlite-vec
from_pool gotcha). Snippets cite live file:line anchors so the doc stays
verifiable against the source.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(rust): make it a standalone Rust README (drop Python framing)
Rename rust/PORTING.md -> rust/README.md and rewrite as a Rust-only usage doc:
drop the Python->Rust module map, the parity audit, the Python backward-compat
section, and the "vs Python" deltas. Keep build/run, architecture, the
"How it uses the CocoIndex Rust SDK" walkthrough, CLI commands, configuration,
testing, and a plain limitations/follow-ups list. Update the e2e fixture that
copies the doc as a sample markdown file.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(rust): rewrite README as a user guide (install / CLI / MCP / config)
Drop the SDK-internals walkthrough. The Rust README now mirrors the main
cocoindex-code README's user-facing structure — Install (build from source),
Quick start, Coding Agent Integration (Skill + MCP), CLI Reference, Search
options, MCP tool reference, Configuration (user/project settings), Supported
languages, and a short "Differences from the Python build" note (local-only
embeddings; no custom Python chunkers).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Feature-parity Rust implementation of the Python `ccc` CLI on the CocoIndex
Rust SDK: daemon/client over a Unix socket (length-prefixed msgpack), MCP
stdio server, fastembed local embeddings, sqlite-vec (vec0) storage,
tree-sitter chunking, and gitignore-aware walking.
Includes fixes from a deep review:
- daemon: fix lost-wakeup in wait_for_indexing_done (enable the Notified future
before the flag check); bind before claiming the PID file and refuse to
clobber a live daemon's socket; drain in-flight connections on shutdown.
- query: clamp negative limit/offset (avoid as-usize wrap / unbounded LIMIT).
- protocol: cap inbound frame size before allocating.
- mcp: reply to unknown JSON-RPC methods with -32601 instead of hanging the
client; reject an empty `query`.
- main: `reset --all` uses remove_dir_all (SQLite -wal/-shm sidecars);
POSIX-separated GLOB path for cross-platform matching.
- db: WAL + busy_timeout so the read-only query pool reads concurrently with
the indexer.
Verified: cargo test + 67 e2e checks (tests/e2e_cli.sh, tests/e2e_advanced.sh).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix: remove logging.basicConfig from __init__.py
Calling logging.basicConfig() at import time configures the root logger
for the entire Python process, which interferes with logging setups in
applications that use cocoindex-code as a dependency.
Libraries should not configure the root logger — that is the
application's responsibility.
Closes#124
* Update __init__.py
---------
Co-authored-by: Jiangzhou <jiangzhou@cocoindex.io>
Add a Troubleshooting entry for `MDB_MAP_FULL: Environment mapsize limit
reached`, explaining the 4 GiB LMDB default and how to raise it via
`COCOINDEX_LMDB_MAP_SIZE` (both global_settings.yml `envs:` and shell
forms). Note the value is read at daemon startup and that the workaround
is temporary pending cocoindex#2108. Cross-link from the Large codebase
section.
Rewrite the Contributing section to match the actual dev setup. The
old instructions used pip + upstream pre-commit, but the repo uses
prek (a dev dependency) and CI runs `uv run prek run --all-files`.
New steps: `uv sync` to install dev deps, `uv run prek run
--all-files` to reproduce the full CI gate before opening a PR, and
an optional `uv run prek install` for the per-commit git hook.
* feat: ship as a Claude Code plugin marketplace
Adds `.claude-plugin/marketplace.json` and `.claude-plugin/plugin.json`
so this repo can be installed directly from inside Claude Code:
/plugin marketplace add cocoindex-io/cocoindex-code
/plugin install cocoindex-code@cocoindex-code
The existing `skills/ccc/SKILL.md` is auto-discovered as the plugin's
skill — no file moves, the `npx skills add` workflow keeps working
unchanged. README gets a short subsection under "Skill (Recommended)"
linking the new install path.
Refs: https://code.claude.com/docs/en/plugin-marketplaces
* chore: point plugin manifests to Roxabi fork
Update owner, homepage, repository, and README install command
from cocoindex-io to Roxabi/cocoindex-code.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Addresses the `ccc init` issues reported in #181:
- Relabel embedding providers so local Ollama is clearly under `litellm`
("litellm (100+ providers — cloud APIs & local Ollama)") and
sentence-transformers is marked as built-in HuggingFace models.
- Reject `ollama/` models inline at the sentence-transformers prompt, before
anything is written or tested, instead of crashing later.
- On a failed init model check, loop with an interactive "try a different
model / keep & finish" choice, pre-filling the previous provider and model
on retry, and print a prominent "Next steps" recovery block.
- Add `ccc doctor -v` to show full tracebacks; by default show the one-line
error plus a hint to rerun with `-v`.
- Fix the retry crash where a rewritten global_settings.yml made the already
-ensured daemon report a bogus "version mismatch": restart the daemon on a
stale-settings handshake even after it was ensured, while still failing fast
on a genuine mid-session version mismatch. Make DaemonVersionError's message
reflect the actual cause.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
When a daemon-side `ccc doctor` check failed (e.g. the model check), only a
one-line, 500-char-truncated summary reached the CLI; the full traceback was
logged to daemon.log but never surfaced, making failures hard to debug.
Carry the full traceback across both daemon→CLI error paths:
- Per-check failures: add `traceback` to `EmbeddingCheckResult` and
`DoctorCheckResult`; `check_embedding` captures `format_exc()` and
`_check_model` propagates it. The CLI prints it dimmed under the error.
- Streaming exceptions: add `traceback` to `ErrorResponse`, populated by the
daemon's streaming handler and appended to the client-raised RuntimeError.
Both new fields default to None, keeping the msgpack wire format
backward-compatible.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump cocoindex (and the sentence-transformers extra) lower bound to 1.0.6,
the first release including cocoindex-io/cocoindex#1992 which adds the
optional `COCOINDEX_APPLICATION_FOR_TRACKING` env var.
Set `COCOINDEX_APPLICATION_FOR_TRACKING=cocoindex-code` at the top of
`cocoindex_code/__init__.py` (before any submodule imports `cocoindex`)
so aggregate telemetry can identify this application. Uses `setdefault`
to leave any explicit user value untouched.
Document the telemetry behavior and `COCOINDEX_DISABLE_USAGE_TRACKING`
opt-out in the README.
The lockfile pinned typer==0.24.1 alongside typer-slim==0.21.1, two
versions that both ship into the `typer/` namespace and overwrite each
other on install. When the install order leaves typer-slim's stale
`_completion_shared.py` next to typer's new `core.py`, importing typer
fails with
ImportError: cannot import name 'HAS_SHELLINGHAM' from 'typer.core'
which is what broke pre-commit (windows-latest, 3.11) on PR #168.
Since typer-slim 0.22.0 it's been a meta-package that just depends on
`typer` and ships no `typer/*.py` of its own, so upgrading typer-slim
to 0.24.0 removes the conflict.
Add an "OpenAI-compatible (custom endpoint)" section under Embedding
Models showing the `openai/` prefix plus `OPENAI_BASE_URL` /
`OPENAI_API_KEY` env vars, and link the LiteLLM "Setting API Keys" doc
from the general LiteLLM note so users of any provider can find the
canonical env-var list.
Adds two sections to the `ccc` skill:
- `Describing Files and Directories` — `ccc describe <path>` for
per-file/dir summaries when the path is known.
- `Concept Guides` — `ccc guide [slug]` for cross-cutting
architectural docs (`.cocoindex_code/guides.yml`), plus an
"Authoring guides.yml interactively" subsection that gives the
agent a 5-step collaborative flow (survey → propose → iterate →
write → generate) and a YAML schema reference.
Inserts a `Following Hints in Search Output` subsection under
search: when a hit is tagged `[summary]` or `[guide]`, follow the
embedded `ccc describe`/`ccc guide` hint rather than running those
commands proactively as a triage step. This reflects empirical
finding that explicit guide-tier triage hurts (matched-vs-unmatched
guide reads are net-neutral in aggregate); search-driven discovery
is strictly better (~−34% tools, −26% time vs no-ccc on a 10-Q
battery).
Frontmatter trigger phrases extended to include `describe this
file` and `read the concept guide`.
Cuts `ccc status` cold-cache startup from ~0.5-0.9s to ~0.15s.
- `cocoindex_code/__init__.py`: replace eager `from .server import main`
with a PEP 562 `__getattr__` so importing the package no longer pulls
`mcp.server.fastmcp` (~300ms). The `cocoindex-code = "cocoindex_code:main"`
console script still resolves.
- `settings.py`: defer `from pathspec import GitIgnoreSpec` into
`load_gitignore_spec()` (only called by indexer/daemon).
- `cli.py`: move protocol type-only imports under `TYPE_CHECKING`
(safe with `from __future__ import annotations`); lazy-import
`DaemonStartError` inside the wrapper and `DoctorCheckResult` next to
the existing lazy `client` import.
Also drops a stale paragraph from CLAUDE.md.
Point reviewers at the `/review-changes` skill for the full detection
checklist, and collapse the per-rule sections (Imports / Type Annotations
/ Multi-Value Returns / Single Source of Truth / Dead Code) into a
shorter bulleted "General principles" list. Project-specific rules
(Internal vs External Modules, Testing) stay in full.
Wire up the new Svelte and Vue tree-sitter languages from cocoindex 1.0.3
(cocoindex-io/cocoindex#1937) so `.svelte` and `.vue` files are picked up
by the default include patterns and chunked syntax-aware.
- Add `**/*.svelte` and `**/*.vue` to DEFAULT_INCLUDED_PATTERNS
- Document svelte/vue in the Supported Languages table
- Bump cocoindex dev-group floor to >=1.0.3 (the version that adds the
tree-sitter parsers); lockfile follows
Voyage models (e.g. voyage/voyage-code-3) reject encoding_format="float"
and require base64. Only inject encoding_format/drop_params for providers
that accept the float hint, leaving voyage/ and bedrock/ to use their
native defaults.
Fixes#148
- Remove `dimensions` from the litellm whitelist in `_ACCEPTED_KWARGS`.
Output dimension must be identical for indexing and query for vectors to
be comparable, so it's a model-wide setting, not a per-side knob —
exposing it under `indexing_params` / `query_params` invited
misconfiguration. Updated comment template, README, design doc, and
testing plan accordingly.
- Plumb `indexing_params` into `create_embedder` and pass them as
constructor kwargs to `PacedLiteLLMEmbedder`. The values land in
`self._kwargs` and become defaults forwarded into every
`litellm.aembedding` call — including paths that don't go through the
`INDEXING_EMBED_PARAMS` context var (e.g. the dim probe in `_get_dim`).
Per-call overrides (`query_params` spread at query time) still win
because `_embed` overlays kwargs on top of `self._kwargs`. Sentence-
transformers ignores `indexing_params` (its constructor doesn't accept
arbitrary kwargs; `prompt_name` is per-call only).
Users can now set `indexing_params` and `query_params` under `embedding:` in
`global_settings.yml` to pass extra kwargs to the embedder separately for
indexing vs. query — supporting asymmetric retrieval models (Cohere v3,
Voyage, Nvidia NIM, Gemini, nomic-ai code/text models, Snowflake arctic,
etc.).
- `ccc init` auto-populates these from a curated table of known models and
prints the applied defaults; unknown models get a commented-out template
for the accepted keys (`prompt_name` for sentence-transformers;
`input_type`, `dimensions` for litellm).
- Daemon validates the effective params at startup; invalid keys fail fast
with a clear error.
- Backward compat: configs for `nomic-ai/CodeRankEmbed` /
`nomic-ai/nomic-embed-code` that predate this feature keep the previous
hardcoded `prompt_name=query` behavior, and a one-time handshake warning
asks users to make the setting explicit. The warning is suppressible by
any non-None `query_params` (including `{}`).
- `ccc doctor` now tests indexing and query separately so asymmetric
misconfigurations surface independently.
Drops the legacy `shared.query_prompt_name` module variable and
`_QUERY_PROMPT_MODELS` set; the new resolution path is centralized in
`embedder_params.resolve_embedder_params` and the curated defaults live in
`embedder_defaults._DEFAULT_PARAMS`.
Also enables `litellm.drop_params = True` so provider-specific kwargs that
a particular model doesn't accept are silently dropped instead of failing.
The module-level `shared.embedder` global was written by `create_embedder()`
but never read from production code — the embedder flows through the
`EMBEDDER` ContextKey via `context.provide` / `use_context`.
Drop the global along with the two test readers that kept it alive:
- `tests/test_daemon.py` — the `daemon_sock` fixture pre-loaded an embedder
and monkeypatched `dm.create_embedder` to reuse it. That was only useful
as a cross-module cache via the now-dead global; with a session-scoped
fixture, `run_daemon()` loads the embedder once from the saved settings
regardless.
- `tests/test_chunker_registry.py` — removed a stale
`monkeypatch.setattr(_shared, "embedder", stub)` whose comment claimed
CodeChunk.embedding read the global at schema resolution time. It reads
the EMBEDDER ContextKey instead; the stub is already wired through
`Project.create(..., stub, ...)`.
Now that cocoindex 1.0.0 is stable, we no longer need `--prerelease`
or explicit prerelease version pins in install instructions.
- README.md: simplify `uv tool install` commands
- docker/Dockerfile: drop `--prerelease=allow` and the redundant
`cocoindex>=1.0.0a33` pin (pyproject.toml already constrains
`cocoindex[litellm]>=1.0.0,<1.1.0`)
LiteLLM documents encoding_format as defaulting to float, but in
practice some providers (e.g. nvidia_nim) error out when it's not
provided. Pass it explicitly as a workaround.
- Bump cocoindex from 1.0.0a43 to >=1.0.0,<1.1.0
- Drop `[tool.uv] prerelease = "explicit"` now that the dep is stable
- Adapt ContextKey usage to 1.0 API: opt-in `detect_change=True`
replaces opt-out `tracked=False`
- README: bash/zsh one-liner using `docker compose -f <(curl ...)`,
plus keep the clone-the-file path for non-POSIX shells.
- docker-compose.yml: `image:` now reads `${COCOINDEX_CODE_IMAGE:-...}`
so users can switch to `:full` or GHCR without editing the file.
- pyproject: scope mypy to `src/` and collapse single-entry extras arrays.
The previous `type=gha` cache was scoped per Git ref, so each release
tag created a new cache scope and never reused a previous release's
layers. Add to that GHA's 10 GB per-repo limit (which we already hit at
~10 GB before the v0.2.26 release), and the cache effectively never
helped consecutive releases.
Move to `type=registry` cache stored as separate `buildcache-<variant>`
tags on the same GHCR package. Branch/tag-independent, no LRU eviction,
unlimited size for our purposes. Standard pattern for multi-arch
buildx + multi-registry publishes.
Per-variant cache tag (`buildcache-slim`, `buildcache-full`) so the two
variants don't evict each other's layers.
`mode=max` exports all intermediate layers, not just the final ones —
needed for the per-RUN-layer reuse strategy in the Dockerfile.
Also cleaned up 23 orphaned GHA cache entries on the deleted
g/docker-layer-cache-v2 branch (3.4 GB freed).
Reshape the Dockerfile so heavy deps live in a stable early layer (digest
reproducible across releases, users cache it) and per-release cocoindex +
cocoindex-code installs land in their own small layer at the end. Cuts
the per-release `docker pull` from ~5 GB to ~470 MB.
Specifically:
- Drop the multi-stage builder/model_cache layout; do everything in one
runtime image so each install RUN produces its own distinct layer.
BuildKit COPY in a multi-stage emits the full copied tree as a layer
(not a diff) — that's what made the previous two-COPY split bloat the
image to ~10 GB without saving any pull cost.
- Order layers so per-release content (the source-tree-dependent install)
is last; everything before reuses across releases.
- Use `RUN --mount=type=bind,source=.,target=/ccc-src,rw=true` instead of
`COPY . /ccc-src` so hatch-vcs can write `_version.py` during the PEP 517
build without persisting the source tree as a layer in the final image.
Image sizes: slim 534 MB (was 598 MB), full 5.77 GB (was 5.83 GB).
Per-release layer: 468 MB (uv install on top of pre-installed ST).
Verified: docker E2E suite passes (6 passed, 2 Linux-only skipped on macOS).
* perf(docker): split install into stable deps + per-release layers; add GHA cache
Dockerfile previously installed cocoindex-code, cocoindex, torch,
sentence-transformers, and all transitive deps in one RUN. Any change to
the source tree (via COPY . /ccc-src) invalidated that single layer,
forcing a full re-install — ~1 GB of wheels for torch + friends — on
every release. Under QEMU for the arm64 cross-build this was slow
enough to be painful.
Split into two stages:
- `deps`: install cocoindex + cocoindex-code[default] from PyPI. Cache
key is just the RUN command string, so this layer is reused across
releases until we bump the pins.
- `builder`: overlay the release version via
`CCC_INSTALL_SPEC=/ccc-src[default]` with `--no-deps
--force-reinstall` — only the cocoindex-code package is touched; the
heavy deps layer stays untouched.
Also add BuildKit layer cache (`type=gha`) to the publish-docker job so
the deps layer persists across workflow runs, not just within a single
build.
* feat(docker,packaging): slim/full image variants; rename [default]→[full] extra
Build two Docker image variants per release:
- slim (:latest, default) — ~450 MB. LiteLLM-only. cocoindex + cocoindex-code
without sentence-transformers. Targets cloud-backed embeddings.
- full (:full) — ~5 GB. Bundles sentence-transformers + torch +
a pre-baked default model. Targets offline-ready local embeddings.
Dockerfile gains a CCC_VARIANT build arg that gates stage 1's
sentence-transformers install and stage 3's model bake. Release workflow
matrices on {slim, full}; each variant has its own GHA cache scope so
layer reuse works across releases without the variants evicting each
other.
Also rename the PyPI `[default]` umbrella extra to `[full]` so pip and
Docker names match. `[embeddings-local]` remains the canonical primary
extra (the one that specifically pulls in sentence-transformers); `[full]`
is its umbrella alias that may bundle additional optional niceties later.
CLI hints that point at missing sentence-transformers continue to name
`[embeddings-local]` directly — the most specific pointer for that case.
README documents both image variants with a comparison table and narrows
the Mac-on-Docker MPS note to only :full users (slim + LiteLLM is
unaffected).
Adds QEMU setup and the `platforms: linux/amd64,linux/arm64` arg to the
build-push-action. Apple Silicon Macs and arm64 Linux hosts get a native
image (pulled automatically via manifest selection) instead of running
under QEMU emulation. amd64 users are unaffected.
Tradeoff: arm64 is cross-compiled via QEMU on the x86_64 runner, so
release builds are noticeably longer (the torch install + model bake
stage both run emulated). Acceptable at current release cadence; can
upgrade to a native arm64 runner matrix if it becomes painful.
- Install cocoindex-code from the checked-out source tree (same build-arg
used by local E2E tests) instead of pulling from PyPI. Avoids a race
where the just-published wheel hadn't propagated to PyPI's CDN when
publish-docker started, and ensures the image matches the tagged
commit byte-for-byte.
- Add a `test_docker` workflow_dispatch input so registry credentials
(Docker Hub + GHCR) can be verified before the next release without
having to cut one. Dispatch pushes `:test` only; release pushes
`:latest` + `:<version>`.
- Drop the needs: publish-to-pypi dependency — with local-source install
we no longer need PyPI to be up-to-date first.
* feat: unified Docker workspace mount with supervised daemon
Reshape the Docker experience around a single bind mount and a single
named volume. Global settings live on the host under
$HOME/.cocoindex_code/ (visible and editable); index data and the model
cache persist in one cocoindex-data volume; daemon runtime state stays
on the container's native filesystem.
CLI and MCP output now show host-side paths via a bidirectional
COCOINDEX_CODE_HOST_PATH_MAPPING translator. A shell wrapper that
forwards $PWD (COCOINDEX_CODE_HOST_CWD) lets ccc work from any project
subdirectory on the host.
The daemon tolerates a missing global_settings.yml (starts in
no-settings mode) so ccc init's interactive picker works in Docker on
first run. A supervisor restart loop in the entrypoint, driven by a new
COCOINDEX_CODE_DAEMON_SUPERVISED contract, makes settings-change
auto-restart safe — editing global_settings.yml triggers an in-place
daemon respawn without taking the container down.
Linux ownership alignment via PUID/PGID, gosu privilege drop, and a
coco user baked into the image. Release workflow now publishes to both
Docker Hub (cocoindex/cocoindex-code) and GHCR
(ghcr.io/cocoindex-io/cocoindex-code).
Also:
- Merge cocoindex-db and cocoindex-model-cache into a single volume
- find_parent_with_marker requires .cocoindex_code/settings.yml, so a
workspace-root global-only dir doesn't trigger nested-init warnings
- New pytest marker `docker_e2e` gates the Docker-backed E2E suite
(excluded from default pytest runs)
* fix: mypy on Windows for POSIX-only os.getuid/getgid calls
Follow-up to #132: the skill's management.md still said `pipx install
cocoindex-code` and described `ccc init` as a purely non-interactive
command. Update to reflect:
- Two install styles — `[default]` (batteries included) vs bare
(slim, LiteLLM-only).
- First-run `ccc init` is interactive; prompts for provider/model and
runs a test embed via the daemon.
- `--litellm-model MODEL` flag for non-TTY / scripted use.
- Pointer to `ccc doctor` if the init model test fails.
`tokenizers` (transitive via `litellm`) ships only `abi3` wheels, with
no free-threaded variant. On macOS arm64 runners since the early-Apr
image update, the source-build fallback fails to link against CPython
3.14t. Excluding the cell cleans up CI signal — end users on standard
Python 3.14 remain unaffected (they pick up the `abi3` wheel).
Ubuntu + 3.14t stays enabled (it still passes, via source build that
Linux's ld accepts). Re-enable macOS once HuggingFace/tokenizers ships
free-threaded wheels or litellm drops the dep.
- Move `sentence-transformers` behind `[embeddings-local]` and `[default]`
extras (via `cocoindex[sentence-transformers]`), so `pip install
cocoindex-code` is LiteLLM-only. Closes#117.
- `ccc init` is now interactive when global settings don't exist: pick
provider (sentence-transformers / litellm) and model via a
questionary TUI. New `--litellm-model MODEL` flag skips prompts and
is the non-TTY escape hatch for LiteLLM. Closes#70.
- Change the default sentence-transformers model from
`all-MiniLM-L6-v2` to `Snowflake/snowflake-arctic-embed-xs`
(lighter, better quality for code).
- Generated `global_settings.yml` now includes a `ccc doctor` reminder
and commented-out env-var examples (OPENAI_API_KEY, GEMINI_API_KEY,
ANTHROPIC_API_KEY, VOYAGE_API_KEY).
- Model test during init runs in the daemon via the existing
`DoctorRequest` path; the daemon loads the model once and stays
running, so the user's next `ccc index` starts warm.
- Docker image now installs `cocoindex-code[default]` and pre-caches
the new default model. The `COCOINDEX_CODE_EMBEDDING_MODEL` env var
is no longer documented for Docker; users mount a
`global_settings.yml` or pass `--litellm-model`.
- Extract `check_embedding` + `EmbeddingCheckResult` into `shared.py`;
refactor daemon `_check_model` to delegate. Error messages in doctor
output now include the exception type name (strictly more
informative).
- Tests switch to a lighter `paraphrase-MiniLM-L3-v2` model via a new
`make_test_user_settings()` helper in `conftest.py`, leaving CI
cache costs unchanged.
Update mount_each call to match the new API where component
subpath is passed as a positional argument instead of using a
context manager.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: extract daemon path helpers to avoid CLI importing cocoindex
Move daemon_dir, daemon_socket_path, daemon_pid_path, daemon_log_path,
and connection_family from daemon.py into a new lightweight _daemon_paths.py
module. This prevents the CLI client from transitively importing cocoindex
and its heavy dependencies (numpy, torch, etc.) when it only needs path
utilities.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* ci: mark free-threaded Python CI jobs as continue-on-error
tokenizers lacks pre-built wheels for cp314t (free-threaded ABI),
so uv falls back to compiling from Rust source. This source build
is fragile across macOS runner image updates and broke after the
20260406 image bump. Mark 3.14t jobs as continue-on-error since
free-threaded wheel coverage across the ecosystem is still limited.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- docker/Dockerfile — multi-stage build (builder → model_cache →
runtime);
copies both `cocoindex-code` and `ccc` binaries; sets
COCOINDEX_CODE_DB_PATH_MAPPING=/workspace=/db so index databases live
in the container's native filesystem (avoids slow cross-OS volume I/O)
- docker/entrypoint.sh — creates user settings on first start via
`ccc init`, then runs `ccc run-daemon` in the foreground to keep the
container alive as a persistent daemon
- README — adds Docker section: persistent container as primary pattern
(`docker run -d` + `docker exec`), named volumes for DB and model cache,
Claude Code / Codex MCP configuration via `docker exec -i ... ccc mcp`
Add 19 file extensions from the supported languages table in README.md
that were missing from the default include patterns: Ruby, Swift, Kotlin,
Scala, R, HTML, CSS/SCSS, JSON, XML, YAML, TOML, Solidity, Pascal/Delphi,
DTD, and Fortran.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: enable mypy explicit_package_bases, remove stale type: ignore comments
explicit_package_bases = true resolves module paths from the repo root,
preventing double-discovery of files in tests/ under different module names.
Required for tests/example_toml_chunker.py to be importable as
example_toml_chunker rather than an ambiguous bare module.
Also sets asyncio_mode = auto so pytest-asyncio behaviour is explicit
(default in 1.3.0 is strict).
With explicit_package_bases active, mypy can fully resolve the Response
union in test_daemon.py — the 16 type: ignore[union-attr] and
type: ignore[attr-defined] comments that were suppressing false positives
under the old resolution are now unused and removed.
# Conflicts:
# tests/test_daemon.py
* feat: pluggable chunker registry with settings integration
Improves retrieval precision by letting users split specific file types at
semantic boundaries (e.g. TOML sections, SQL statements) instead of the
default line-window splitter.
## What
- cocoindex_code/chunking.py: public API module exporting ChunkerFn
(Callable alias), CHUNKER_REGISTRY context key, and re-exports of
Chunk/TextPosition from upstream. Single import path for chunker authors.
- tests/example_toml_chunker.py: demo chunker splitting at [section]
headers; excludes [[array_of_tables]] via negative lookahead. Lives in
tests/ to signal it belongs to a separate package, not the core library.
- ProjectSettings.chunkers: new list[ChunkerMapping] field, serialised as
YAML. Each entry maps a file extension to a 'module.path:callable' string.
Users activate chunkers by editing .cocoindex_code/settings.yml — no code
changes required.
- daemon.py: _resolve_chunker_registry resolves ChunkerMapping entries via
importlib at project load time and passes the result to Project.create().
callable() guard gives a clear error at startup rather than a TypeError
per file.
- Project.create(chunker_registry=...): new optional parameter. Injected as
a cocoindex context key (tracked=False) rather than exposed via env internals.
Empty registry by default — zero behavioural delta for existing users.
- indexer.py: process_file checks the registry per file suffix; falls through
to RecursiveSplitter unchanged when no chunker is registered.
## Design decisions
- ChunkerFn returns (language_override, chunks): language_override=None keeps
detect_code_language() result; non-None lets the chunker correct it (e.g.
.sls files starting with #!py).
- tracked=False is consistent with SQLITE_DB, CODEBASE_DIR, and other
non-serialisable context keys. Changing a chunker requires a daemon restart,
which triggers a full re-index anyway.
- _resolve_chunker_registry lives in daemon.py, its only call site, keeping
settings.py as pure schema/IO and chunking.py as pure type definitions.
# Conflicts:
# src/cocoindex_code/daemon.py
# src/cocoindex_code/indexer.py
# src/cocoindex_code/project.py
# tests/test_settings.py
Add target_sqlite_db_path() and cocoindex_db_path() to settings.py as
the single source of truth for database paths, replacing scattered
hardcoded "target_sqlite.db" and "cocoindex.db" strings across cli.py,
daemon.py, project.py, and config.py. Also use daemon_log_path() for
daemon log references and project_settings_path() for settings file
references.
Remove config.py (unused legacy module) and its tests — no production
code imported it.
Add settings/index-db location display to `ccc status`.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add COCOINDEX_CODE_DB_PATH_MAPPING for custom database locations
Allow remapping database file locations via environment variable, enabling
Docker deployments where databases live on the container's native filesystem
while source code is mounted from the host.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use = delimiter for DB path mapping (avoid Windows colon conflict)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: use platform-agnostic tmp_path in DB mapping tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>