CLAUDE.md · diff
git:20260912.398e9ef to git:20260915.8355403
4 added, 381 removed. Audit A to A.
> **Audience: Pixeltable contributors.** If you're building an *application* with Pixeltable, use the [Agent Skill](https://github.com/pixeltable/pixeltable-skill) instead (`npx skills add pixeltable/pixeltable-skill`).
# CLAUDE.md
- Instructions for AI coding agents working with the Pixeltable codebase.
-
- ## Protected Configuration
-
- Never change `integrations.telemetry.enabled` in `docs/release/docs.json`. It must remain set to `true` in every pull request.
-
- ## Project Overview
-
- Pixeltable is an open-source Python library providing declarative data infrastructure for building multimodal AI applications. It enables incremental storage, transformation, indexing, retrieval, and orchestration of data across images, video, audio, and documents.
-
- **Key concepts:**
- - **Tables**: Store structured and unstructured data with native multimodal column types (`pxt.Image`, `pxt.Video`, `pxt.Audio`, `pxt.Document`)
- - **Computed Columns**: Declaratively define transformations that run automatically on new/updated data
- - **Views**: Virtual tables with iterators for efficient data processing (e.g., document chunking, video frame extraction)
- - **Embedding Indexes**: Built-in vector search with automatic index maintenance
- - **UDFs**: User-defined functions with `@pxt.udf` and `@pxt.query` decorators
- - **AI Integrations**: Built-in functions for OpenAI, Anthropic, Hugging Face, and many more
-
- **Documentation**: https://docs.pixeltable.com/
- **SDK Reference**: https://docs.pixeltable.com/sdk/latest/pixeltable
-
- ## Repository Structure
-
- ```
- pixeltable/
- ├── pixeltable/ # Main library source code
- │ ├── catalog/ # Table, View, Column metadata and operations
- │ ├── exec/ # Query execution engine
- │ ├── exprs/ # Expression types and operators
- │ ├── func/ # UDF/query function infrastructure
- │ ├── functions/ # Built-in AI provider integrations (openai, anthropic, etc.)
- │ ├── index/ # Embedding index implementations
- │ ├── io/ # Import/export (CSV, Parquet, Hugging Face, etc.)
- │ ├── iterators/ # View iterators (DocumentSplitter, FrameIterator, etc.)
- │ ├── metadata/ # Schema migration and persistence
- │ ├── share/ # Data sharing (publish/replicate)
- │ └── utils/ # Utilities
- ├── tests/ # Test suite
- │ ├── functions/ # Tests for AI integrations
- │ ├── io/ # Tests for import/export
- │ └── data/ # Test fixtures (images, videos, documents)
- ├── docs/
- │ ├── release/ # Mintlify documentation source (notebooks, MDX)
- │ ├── _guidelines/ # Documentation style guides
- │ └── sample-apps/ # Older showcases; examples live in pixeltable-starter-kit
- └── tool/ # Development utilities
- ```
-
- ## Setup Commands
-
- **Prerequisites:** Miniforge with a dedicated environment (not `base`)
-
- ```bash
- # Create and activate conda environment
- mamba create --name pxt python=3.11
- conda activate pxt
-
- # Install development dependencies
- make install
-
- # Run tests (excludes expensive/remote API tests by default)
- make test
-
- # Run full test suite including notebooks
- make fulltest
-
- # Run minimal test suite for quick checks
- make slimtest
- ```
-
- ## Development Workflow
-
- ### Code Style
-
- - **Line length**: 120 characters
- - **Quotes**: Single quotes (`'`) preferred
- - **Formatter**: ruff (`make format`)
- - **Type hints**: Required for all functions (mypy strict mode)
- - **Imports**: Group by standard library → third-party → pixeltable
-
- ```bash
- # Format code
- make format
-
- # Run static checks (mypy + ruff)
- make check
-
- # Individual checks
- make typecheck # mypy
- make lint # ruff check
- make formatcheck # ruff format --check
- ```
-
- ### Testing
-
- ```bash
- # Run pytest (excludes expensive/remote_api tests)
- make pytest
-
- # Run full pytest including expensive tests
- make fullpytest
-
- # Run specific test file
- pytest tests/test_table.py -v
-
- # Run tests matching a pattern
- pytest -k "test_insert" -v
-
- # Run with remote API tests (requires credentials)
- pytest -m "remote_api" tests/functions/test_openai.py
- ```
-
- **Test markers:**
- - `@pytest.mark.expensive` - Long-running tests
- - `@pytest.mark.remote_api` - Tests calling external APIs
-
- ### Required After Every Code Change
-
- After every code change, before reporting it done:
-
- 1. `make format`: auto-formats code.
- 2. `make check`: mypy + ruff static checks; both must pass.
- 3. `git add` any new source file, then review the whole change with `git diff HEAD` (no pathspec: source
- and tests), reading every comment, docstring, and string you added. A diff narrowed to one file does not
- count, and an unstaged new file does not appear in it. A comment must describe only the code at hand
- (never a caller's intent or a called function's internals) and must not state behavior you have not
- verified.
- 4. Delete before rewording: cover each comment and read only the identifier, the signature, and the code
- below it. If those carry the same fact, delete the comment rather than improving it. A docstring that
- paraphrases the name, an "or None if ..." for a `| None` annotation, and a fact already stated elsewhere
- all go. Keep what the reader cannot recover: a constraint a callee imposes, the reason for a surprising
- choice, an invariant that would silently break.
- 5. Check the prose that survived for straight word order, per `feedback_simple_direct_prose.md`: no
- preposition stranded at the end of a clause, no noun-phrase pileup ("the X a Y is Z to"), no fused
- emphatic ("X is what makes Y work" -> "X makes Y work"). Where a plainer phrase says the same thing, use
- it. Fix every violation from steps 3 to 5 before proceeding.
-
- Skip only if explicitly directed or if the environment makes it impossible.
-
- ### Creating a Pull Request
-
- 1. Create a branch from `main`
- 2. Make changes and add tests in `tests/`
- 3. Run `make format` and `make check` (see above)
- 4. Run `make test` to run the test suite
- 5. Push and create PR via GitHub
-
- ## Code Conventions
-
- ### Adding a New UDF
-
- UDFs go in `pixeltable/functions/`. Each provider has its own module (e.g., `openai.py`, `anthropic.py`).
-
- ```python
- # pixeltable/functions/my_provider.py
- import pixeltable as pxt
-
- @pxt.udf
- def my_function(input_text: str, model: str = 'default-model') -> str:
- """
- Brief description of what this function does.
-
- Args:
- input_text: The input text to process.
- model: The model to use for processing.
-
- Returns:
- The processed output text.
-
- Example:
-
- >>> t.add_computed_column(result=my_function(t.text, model='advanced'))
- """
- # Implementation
- pass
- ```
-
- **Important patterns:**
- - Use `@pxt.udf` for scalar functions, `@pxt.uda` for aggregates
- - Use `.using()` for model parameterization in embedding functions
- - Add tests in `tests/functions/test_my_provider.py`
-
- ### Adding a New Iterator
-
- Iterators go in `pixeltable/iterators/`. They split rows into multiple output rows.
-
- ```python
- # pixeltable/iterators/my_iterator.py
- from pixeltable.iterators import ComponentIterator
- import pixeltable.type_system as ts
-
- class MyIterator(ComponentIterator):
- """Iterator that splits X into multiple rows."""
-
- def __init__(self, input_data: SomeType):
- # Initialize iteration state
- pass
-
- def __next__(self) -> dict[str, Any]:
- # Return next row as dict
- pass
-
- def close(self) -> None:
- pass
-
- @classmethod
- def input_schema(cls) -> dict[str, ts.ColumnType]:
- return {'input_data': ts.SomeType()}
-
- @classmethod
- def output_schema(cls, *args, **kwargs) -> tuple[dict[str, ts.ColumnType], list[str]]:
- return {'output_field': ts.SomeType()}, []
- ```
-
- ### Working with Tables
-
- Application schema is a `TableModel` class in `app.py`. `pxt schema update app.py my_app` creates those tables. Put `FastAPIRouter` routes in that same `app.py`. In tests, notebooks, and a REPL, keep using `pxt.create_table()`; do not require a project file there.
-
- ```python
- import pixeltable as pxt
- import pixeltable.functions as pxtf
- from pixeltable.serving import FastAPIRouter
-
- TableModel = pxt.model_base()
-
-
- class Docs(TableModel, name='docs'):
- doc_id = pxt.Column(value=pxtf.uuid.uuid7(), primary_key=True)
- title: pxt.String
- body: pxt.String | None
- title_upper = pxtf.string.upper(title)
-
-
- ingest = FastAPIRouter(name='ingest')
- ingest.add_insert_route(
- Docs, path='/docs', inputs=[Docs.title, Docs.body], outputs=[Docs.doc_id, Docs.title, Docs.title_upper]
- )
- ```
-
- ```bash
- pxt schema update app.py my_app
- pxt service update app.py my_app
- ```
-
- After `pxt schema update`, open the table with `t = pxt.get_table('my_app.docs')`, then `t.insert()` / `.select()` / `.collect()`. On a `TableModel`, put indexes in `__indexes__`. Do not call `add_embedding_index()` in application code that you later create with `pxt schema update`.
-
- Tests and notebooks (not app files):
-
- ```python
- import pixeltable as pxt
-
- t = pxt.create_table('my_dir.my_table', {
- 'text': pxt.String,
- 'image': pxt.Image,
- 'metadata': pxt.Json,
- })
- t.add_computed_column(embedding=some_embedding_fn(t.text))
- t.add_embedding_index('text', embedding=embed_fn)
- t.insert([{'text': 'hello', 'image': 'path/to/image.jpg'}])
- ```
-
- ### Error Handling
-
- - Use `pixeltable.exceptions` for custom exceptions
- - Validate inputs early and provide clear error messages
- - Use `exn.Error` for user-facing errors
-
- ## Documentation
-
- ### Notebooks
-
- Documentation notebooks are in `docs/release/`. Follow `docs/_guidelines/GUIDELINES_FOR_NOTEBOOKS.md`:
-
- - Start with YAML frontmatter in a **Raw cell** (not Markdown)
- - No H1 headers in markdown (title comes from frontmatter)
- - Use `##` for main sections, `###` for subsections
- - Clear outputs before committing unless output is instructive
- - Use `raw.githubusercontent.com` for GitHub raw links
-
- ### Docstrings
-
- Follow `docs/_guidelines/GUIDELINES_FOR_DOCSTRINGS.md`:
-
- - Code examples must use `>>>` prompts, not fenced code blocks
- - Backticks must be properly paired
- - HTML tags must be self-closing
- - When describing what a function does, focus on the behavior of the function itself, not its callers
-
- ### Code Comments
-
- - Keep code comments succinct; avoid unnecessarily verbose comments.
- - Always use parens to denote functions: in code comments, it's `my_func()`, not `my_func`.
-
- ### Building Docs
-
- ```bash
- # Build documentation
- make docs
-
- # Serve locally for development
- make docs-serve
-
- # Deploy to staging
- make docs-deploy TARGET=stage
- ```
-
- ### Local Dashboard UI
-
- Before changing `dashboard/` or dashboard-facing APIs in `pixeltable_cli/server/`, read [`dashboard/DESIGN.md`](dashboard/DESIGN.md) (required) and [`dashboard/ARCHITECTURE.md`](dashboard/ARCHITECTURE.md). Follow DESIGN.md; justify any visual departure explicitly.
-
- ## Testing Against Remote APIs
-
- For tests that call external APIs (OpenAI, Anthropic, etc.):
-
- 1. Set appropriate environment variables (e.g., `OPENAI_API_KEY`)
- 2. Run with the `remote_api` marker: `pytest -m "remote_api" tests/functions/test_openai.py`
- 3. These tests are excluded from CI by default
-
- ## Database and Storage
-
- - Pixeltable uses embedded PostgreSQL at `~/.pixeltable/pgdata`
- - Generated media stored at `~/.pixeltable/media`
- - File cache at `~/.pixeltable/file_cache`
- - **Never directly modify** files in `~/.pixeltable`; use the SDK
-
- To reset the database for testing:
- ```bash
- scripts/drop-pxt-db.sh
- ```
-
- ## Common Patterns
-
- ### Idempotent Operations
-
- Use `if_exists='ignore'` or `if_not_exists=True` for idempotent schema operations:
-
- ```python
- pxt.create_dir('my_dir', if_exists='ignore')
- pxt.create_table('my_dir.table', schema, if_exists='ignore')
- t.add_computed_column(col=expr, if_exists='ignore')
- t.add_embedding_index('col', embedding=fn, if_not_exists=True)
- ```
-
- ### Query Functions
-
- Encapsulate complex queries as reusable functions:
-
- ```python
- @pxt.query
- def search_documents(query_text: str, limit: int = 10):
- sim = docs.text.similarity(string=query_text)
- return docs.order_by(sim, asc=False).limit(limit).select(docs.text, sim)
- ```
-
- ### Handling Nullable Columns
-
- Check for null values when processing data:
-
- ```python
- @pxt.udf
- def safe_process(value: Optional[str]) -> str:
- if value is None:
- return ''
- return process(value)
- ```
-
- ## Key Files Reference
+ Pixeltable keeps one developer guide for every coding agent. It lives in `AGENTS.md`, and the line below
+ imports it, so Claude Code reads the same instructions Codex and the other agents do. Edit `AGENTS.md`;
+ do not add rules here.
- | File | Purpose |
- |------|---------|
- | `pixeltable/__init__.py` | Public API exports |
- | `pixeltable/catalog/table.py` | Table class implementation |
- | `pixeltable/catalog/view.py` | View class implementation |
- | `pixeltable/func/udf.py` | UDF decorator implementation |
- | `pixeltable/functions/` | AI provider integrations |
- | `pixeltable/io/` | Import/export functionality |
- | `pixeltable_cli/` | CLI + daemon (serves dashboard API and static SPA) |
- | `dashboard/` | Local web UI frontend (React/Vite); see `dashboard/DESIGN.md` |
- | `dashboard/DESIGN.md` | Dashboard visual/UX source of truth (required for UI changes) |
- | `dashboard/ARCHITECTURE.md` | Dashboard stack and API map |
- | `pyproject.toml` | Dependencies and tool config |
- | `Makefile` | Build and test commands |
+ @AGENTS.md