STOP
If you find yourself importing any of these, you are off-path:
- Do not use LangChain / LlamaIndex / Haystack / LangGraph. Chunking is
document_splitter. Search is.similarity(). Tools arepxt.tools()+invoke_tools(). - Do not use pandas as a working store. Tables are the store.
.collect().to_pandas()is export only. - Do not write
for row in ...:loops calling models. Wrap the call in a computed column. - Do not install a separate vector database. In an app,
__indexes__ = [pxt.EmbeddingIndex(...)]on the model. In a notebook,t.add_embedding_index(col, embedding=fn). Search with.similarity(string=query). - Do not write
while not done:agent loops. Insert a row. The computed-column chain runs.
See anti-patterns.md [blocked] (6 macros).
What is Pixeltable?
One application file (app.py) is the backend.
pxt schema update: creates tables fromTableModelclasses. Does not start HTTP.- Insert a sample,
.select(),pxt dashboard, orpxt schema diff. Compute runs on insert. Afterpxt service update, curl POST. pxt service update: starts HTTP (local orpxt://).pxt service listprints the URL. This is the serving command; do not reach forpxt service run.
pxt db update uploads the project files and sets the hosted image and workers. It does not set secrets (pxt secret does), insert rows, or start app HTTP.
First run: Quickstart. Why: Why Pixeltable.
Starting a new project
pxt service example writes models plus a FastAPIRouter. Schema only (no HTTP): pxt schema example --brief --out app.py. Then edit app.py and run pxt schema update again. After a schema change, run pxt service update again if routes exist. Do not python app.py. Full flags: cli.md [blocked].
The last argument (my_app, or pxt://org:db on Cloud) is a catalog directory, not a folder on disk. pxt init marks the project root. Schema does not start HTTP. Service does not create tables. Non-interactive: pxt service update ... -f. Local handle: pxt.get_table('my_app.docs'), or bind the models: import app; app.TableModel.bind_all('my_app'), then app.Docs.insert(...) / app.Docs.select(...).collect().
Same file on Cloud: set PIXELTABLE_API_KEY, add [[pixeltable.database]] with name = 'pxt://org:db', then pxt db update pxt://org:db -f, then pxt schema update app.py pxt://org:db -f, then pxt service update app.py pxt://org:db -f. Cloud handle: pxt.get_table('pxt://org:db/docs'). Cloud databases store media in their managed home bucket by default; set a column destination= only to override it. On Cloud, try the app with dashboard insert plus pxt schema diff, and inspect failures with pxt service logs / pxt db logs. Cloud.
The application file
pxt service example --out app.py writes this shape. Edit it. Then pxt schema update app.py my_app.
Annotation is a stored column. Assignment is a computed column. Optional is T | None. Primary key is pxt.Column(..., primary_key=True); add_update_route matches rows by it, so the request body carries id even though inputs does not list it. Indexes on the model: __indexes__ = [pxt.EmbeddingIndex(...)]. from pixeltable.serving import FastAPIRouter.
Already have FastAPI: after schema update, ingest.bind('my_app') then app.include_router(ingest). Or define the fastapi.FastAPI object in app.py and include_router() each router there; pxt service update then serves that one application. Call pxt.get_table() inside custom handlers. workflows.md [blocked].
RAG, views, and search: workflows.md [blocked]. Do not add Hugging Face or spaCy unless the user asked.
Apps vs notebooks
- Apps:
app.py+pxt schema update+pxt service update. Indexes on the model. - Notebooks / REPL:
pxt.create_table(),add_computed_column(),add_embedding_index(). The appendix below uses that form.
Where to look
Add video, audio, agents, or a UI by editing app.py. A view is either a filter (base=Docs.where(...)) or an iterator (frame_iterator, audio_splitter, document_splitter, video_splitter, string_splitter, list_iterator, tile_iterator). Check pixeltable.functions before writing a UDF. Start from pxt service example or pxt schema example. Do not invent a second pxt schema update path.
API traps
Extract the field (.text, .choices[0].message.content). Cast Json with .astype(pxt.String) only before embedding or concatenating.
Notebook / REPL appendix
Types are non-nullable by default. Optional is T | None. Do not use pxt.Required.
Insert: t.insert([{...}]). Computed column:
Views: document_splitter, frame_iterator (from pixeltable.functions.video), string_splitter, audio_splitter. Notebook indexes: t.add_embedding_index('content', embedding=embed_fn, if_exists='ignore').
Query: t.where(...).select(...).collect(). Similarity: t.content.similarity(string=query). In @pxt.query, alias as score=sim.
UDFs are recorded as a module path relative to the project root (app.excerpt).
Always if_exists='ignore' on notebook create_* / add_*. Failed cells: t.recompute_columns('summary', errors_only=True). string_splitter / document_splitter(..., separators='sentence') need spaCy. Embedding indexes need .using(...).
pxt CLI
cli.md [blocked].