pydantic-ai-pixeltable
Pydantic AI Harness integration for Pixeltable. Two independent layers:
PixeltableMemoryStore: persist HarnessMemoryin a Pixeltable table (sameMemory(store)slot asFileStore)Pixeltable: read-only catalog tools (list_tables,describe_table,query_table,similarity_search) over tables you already have
Neither requires the other. Requires Pixeltable >= 0.7.8 and pydantic-ai-harness >= 0.29.0.
This is an interoperability bridge. Native Pixeltable agents still use a TableModel and computed columns.
How it fits together
Native backend (FileStore) This package (Pixeltable)
Memory(FileStore) Memory(PixeltableMemoryStore)
└ .agent-memory/ └ pxt table 'harness.memory'
├ main/MEMORY.md ├ kind='file' rows path, content, version
├ ... (one .md per memory path) └ kind='op' rows '__op__/<id>' receipts
└ .memory-store.sqlite3 same catalog as your data; inspect via store.table
(versions + operation journal)
Pixeltable(tables=[...]) (optional, independent)
└ your existing tables/views, incl. pxt.Document and
embedding indexes -> query_table, similarity_search
Unique to this backend: memory rows are ordinary catalog rows. store.search stays lexical (the Harness contract), but through store.table you can add an embedding index on content and run Pixeltable similarity queries over memory, or join it with the rest of the catalog.
Installation
pip install pydantic-ai-pixeltable
Quick Start
Memory in the catalog, plus read-only tools over the tables you already have:
from pydantic_ai import Agent
from pydantic_ai_harness import Memory, ToolOutputLimits
from pydantic_ai_pixeltable import Pixeltable, PixeltableMemoryStore
agent = Agent(
"anthropic:claude-sonnet-4-6",
capabilities=[
Memory(PixeltableMemoryStore(table_name="harness.memory")),
Pixeltable(tables=["my_app.doc_chunks"]),
ToolOutputLimits(),
],
)
Prefer FileStore (or PostgresMemoryStore) when the notebook does not need to live in the catalog; the choice is per project.
tables is a required allowlist of table paths or directory prefixes. Pass tables=["*"] to allow the whole catalog, including the memory table and its __op__ receipt payloads.
Two Pixeltable(...) instances share id="pixeltable" and merge by narrowing: an entry survives only when every capability covers it, and a disjoint merge raises. pydantic-ai-chdb also registers list_tables and describe_table; wrap one side in PrefixTools when you pair them.
Catalog tools
Pixeltable does not create tables or insert rows. Point it at a table or view that already has data, plus an embedding index for similarity_search.
query_tablefilters with equality only ({"status": "open"}); media, array, and binary columns reject non-null filters.similarity_searchcallscolumn.similarity(string=query)and needs an embedding index on that column.- Output is bounded by
max_rowsandmax_chars; the minimal{"table", "rows", "truncated"}envelope is always returned, even whenmax_charsis set below its size. Default columns skip media, array, binary, and computed columns that are not stored (they would recompute per query); a named media column returns a file URL, not a blob.
Declare the tables and index on a TableModel in app.py; pxt schema update creates them:
import pixeltable as pxt
import pixeltable.functions as pxtf
from pixeltable.functions.huggingface import sentence_transformer
TableModel = pxt.model_base()
embed_fn = sentence_transformer.using(model_id="intfloat/multilingual-e5-large-instruct")
class Docs(TableModel, name="docs"):
document: pxt.Document
class Chunks(
TableModel,
name="doc_chunks",
base=Docs,
iterator=pxtf.document.document_splitter(Docs.document, separators="paragraph"),
):
__indexes__ = [pxt.EmbeddingIndex(text, embedding=embed_fn, name="chunks_embed")] # type: ignore[name-defined]
pxt schema update app.py my_app
A notebook or REPL can still call create_table, create_view, and add_embedding_index. Do not put those calls in app.py.
YAML spec
agent = Agent.from_spec(
{
"model": "anthropic:claude-sonnet-4-6",
"capabilities": [{"Pixeltable": {"tables": ["my_app.doc_chunks"]}}],
},
custom_capability_types=[Pixeltable],
)
Without custom_capability_types=[Pixeltable], Agent.from_spec does not know the class.
Memory store
- The table is created on first use; you do not run
pxt schema updatefor it. - Each path is one row (
kind == "file"); operation receipts are rows under__op__/. Path roots__meta__and__op__are reserved. - Compare-and-set:
expected_versionmust equal the row's version. Versions are unique UUID strings, not monotonic. A stale version raisesMemoryConflictError. - Operation receipts are journaled
__op__rows: the intended mutation is recorded before it is applied, so a mid-write crash rolls forward or replays cleanly instead of double-applying. store.compact()rebuilds the table from live rows. Pixeltable keeps old row versions for updates and deletes, so compaction is the only way to reclaim storage. Run it with writers paused; it refuses tables with user-added columns or indexes.Memory(PixeltableMemoryStore)is Python-only. Harness YAML backends arememory,file, andsqlite.- This package emits no telemetry of its own; the
memory.*spans come from the HarnessMemorycapability.
Escape hatch: .table
store = PixeltableMemoryStore(table_name="harness.memory")
t = store.table
t.where(t.kind == "file").select(t.path, t.content, t.version).collect()
Use .table to query. A raw t.update of content is not a Memory write: the version does not change, and the next compare-and-set can overwrite it.
Measured results
Pixeltable 0.7.8 on embedded PostgreSQL, ~20k rows per test, laptop hardware (pytest tests/test_stress.py -v -m expensive):
| Operation | Time |
|---|---|
list_paths, limit 50 over 20k files |
~12 ms |
search (lexical), 100-file scan bound |
~8 ms |
| CAS write under contention (200 tasks, 4 paths) | ~5 ms per attempt, exactly 4 winners |
query_table equality filter, limit 20 over 20k rows |
~10 ms |
similarity_search top-3 over 20k indexed rows |
~8 ms |
| Embedding index build over 20k rows | ~2.3 s |
Development
pip install -e ".[dev]"
pytest tests/ -v
pytest tests/test_stress.py -v -m expensive
ruff check . && ruff format --check .
pytest tests/ -v skips @pytest.mark.expensive (~20k-row Memory and catalog volume).
License
Apache 2.0
Metadata
Release files for pydantic-ai-pixeltable 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pydantic_ai_pixeltable-0.2.0.tar.gz | 37.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pydantic_ai_pixeltable-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 60.9 kB
Release files / pydantic_ai_pixeltable-0.2.0.tar.gz
| Download URL | pydantic_ai_pixeltable-0.2.0.tar.gz |
|---|---|
| Size | 37.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7ae2d1874b1b347a25fb9dfffc144107489ab72bed33aeb271659d7d41338405
|
|
BLAKE2b-256 checksum How to use checksums |
0d257809d4500ed01a979ed1caf9f6cc1f492a68ea2283efd5aafc6742da6c66
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency logRelease files / pydantic_ai_pixeltable-0.2.0-py3-none-any.whl
| Download URL | pydantic_ai_pixeltable-0.2.0-py3-none-any.whl |
|---|---|
| Size | 23.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c8f4d344e552c4b361668d70150aed5a35897bef345282deeaec9933ae769ad5
|
|
BLAKE2b-256 checksum How to use checksums |
7b32d00fe690fcaefd75426f62dc12e7ac85cd6d4635a762130f10fa4e3f27da
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 23, 2026.
Transparency log