Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
This is built on top of [CocoIndex v1](https://cocoindex.io/docs-v1/llms.txt).


## Build and Test Commands

This project uses [uv](https://docs.astral.sh/uv/) for project management.

```bash
uv run mypy . # Type check Python code
uv run pytest tests/ # Run Python tests
```

## Code Conventions

### Internal vs External Modules

We distinguish between **internal modules** (under packages with `_` prefix, e.g. `_internal.*` or `connectors.*._source`) and **external modules** (which users can directly import).

**External modules** (user-facing, e.g. `cocoindex/ops/sentence_transformers.py`):

* Be strict about not leaking implementation details
* Use `__all__` to explicitly list public exports
* Prefix ALL non-public symbols with `_`, including:
* Standard library imports: `import threading as _threading`, `import typing as _typing`
* Third-party imports: `import numpy as _np`, `from numpy.typing import NDArray as _NDArray`
* Internal package imports: `from cocoindex.resources import schema as _schema`
* Exception: `TYPE_CHECKING` imports for type hints don't need prefixing

**Internal modules** (e.g. `cocoindex/_internal/component_ctx.py`):

* Less strict since users shouldn't import these directly
* Standard library and internal imports don't need underscore prefix
* Only prefix symbols that are truly private to the module itself (e.g. `_context_var` for a module-private ContextVar)

### General principles (also covered by `/review-changes`)

- **Top-level imports.** Defer to in-function only for a real circular dependency or a heavy import that isn't always needed.
- **Specific types over `Any`.** When a value enters as a weaker form (`str`, `Any`), convert to the strong type at the earliest point. Don't propagate the weak form.
- **`NamedTuple`/small dataclass for multi-value returns.** Access fields by name at call sites.
- **Single source of truth.** When the same value or logic appears in multiple places, consolidate it.
- **Delete dead code and dead config.** When a change makes something unreachable, the code, the tests, and the knobs all go.
- **Honest names.** The name describes what the code does today.

### Testing Guidelines

We prefer end-to-end tests on user-facing APIs, over unit tests on smaller internal functions. With this said, there're cases where unit tests are necessary, e.g. for internal logic with various situations and edge cases, in which case it's usually easier to cover various scenarios with unit tests.

When tests fail, fix the underlying issue. Don't skip, ignore, or exclude to get a green result.
61 changes: 61 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
IMAGE ?= cocoindex-code:local-layered
COMPOSE ?= docker compose -f docker/docker-compose.yml
CCC_VARIANT ?= slim
CCC_WRAPPER ?= bin/ccc
DAEMON_CONTAINER ?= cocoindex-code-local-daemon
STATE_VOLUME ?= cocoindex-code-local-state
RUNTIME_VOLUME ?= cocoindex-code-local-runtime

.PHONY: build build-local build-pypi up restart ps logs down reset install-ccc-wrapper

build: build-local

build-local:
docker build \
-t "$(IMAGE)" \
-f docker/Dockerfile \
--build-arg CCC_VARIANT="$(CCC_VARIANT)" \
--build-arg CCC_INSTALL_SPEC=/ccc-src \
.

build-pypi:
docker build \
-t "$(IMAGE)" \
-f docker/Dockerfile \
--build-arg CCC_VARIANT="$(CCC_VARIANT)" \
.

ps:
docker ps --filter 'name=cocoindex-code-local-daemon'

up:
docker volume inspect "$(STATE_VOLUME)" >/dev/null 2>&1 || docker volume create "$(STATE_VOLUME)" >/dev/null
docker volume inspect "$(RUNTIME_VOLUME)" >/dev/null 2>&1 || docker volume create "$(RUNTIME_VOLUME)" >/dev/null
@if docker inspect "$(DAEMON_CONTAINER)" >/dev/null 2>&1 && \
[ -z "$$(docker inspect -f '{{ index .Config.Labels "com.docker.compose.project" }}' "$(DAEMON_CONTAINER)" 2>/dev/null)" ]; then \
echo "Removing non-Compose daemon container $(DAEMON_CONTAINER) before compose up"; \
docker rm -f "$(DAEMON_CONTAINER)" >/dev/null; \
fi
COCOINDEX_CODE_IMAGE="$(IMAGE)" $(COMPOSE) up -d

restart:
COCOINDEX_CODE_IMAGE="$(IMAGE)" $(COMPOSE) down
COCOINDEX_CODE_IMAGE="$(IMAGE)" $(COMPOSE) up -d

logs:
$(COMPOSE) logs -f cocoindex-code-daemon

down:
$(COMPOSE) down || docker rm -f "$${COCOINDEX_CODE_DAEMON_CONTAINER:-cocoindex-code-local-daemon}" || true

reset: down
docker volume rm \
"$${COCOINDEX_CODE_STATE_VOLUME:-cocoindex-code-local-state}" \
"$${COCOINDEX_CODE_RUNTIME_VOLUME:-cocoindex-code-local-runtime}" \
2>/dev/null || true
docker network rm "$${COCOINDEX_CODE_DOCKER_NETWORK:-cocoindex-code-local}" 2>/dev/null || true

install-ccc-wrapper:
mkdir -p "$(HOME)/.local/bin"
cp "$(CCC_WRAPPER)" "$(HOME)/.local/bin/ccc"
chmod +x "$(HOME)/.local/bin/ccc"
Loading