Skip to main content
Open in Kaggle  Open in Colab  Download Notebook
This documentation page is also available as an interactive notebook. You can launch the notebook in Kaggle or Colab, or download it for use with an IDE or local Jupyter installation, by clicking one of the above links.

Problem

You defined a multimodal pipeline in Python and now need to inspect tables, debug computed columns, roll back changes, and expose HTTP endpoints without writing more application code. Jumping into a REPL or building a custom admin UI for every project does not scale, especially when AI agents need stable, machine-readable output.

Solution

What’s in this recipe:
  • Inspect catalogs with pxt ls, describe, columns, and idxs
  • Query and debug rows with pxt rows, count, get, and errors
  • Manage versions with pxt history and pxt revert
  • Script and automate with --json, -f, and pxt shell
  • Validate declarative HTTP serving with pxt serve --dry-run
The pxt CLI ships with Pixeltable (v0.6.5+). Catalog commands talk to a local daemon (~40 ms per call after the first invocation). Use Python to define schema once, then operate the catalog from the terminal. See the CLI reference for every flag.

Setup

%pip install -qU 'pixeltable[serve]'
Note: you may need to restart the kernel to use updated packages.
import json
import pixeltable as pxt
import subprocess
from pixeltable.functions.video import frame_iterator


def pxt_json(*args: str) -> object:
    """Run pxt with --json and parse stdout."""
    return json.loads(subprocess.check_output(['pxt', *args], text=True))
SAMPLE_VIDEO = 'https://raw.githubusercontent.com/pixeltable/pixeltable/release/docs/resources/bangkok.mp4'

pxt.drop_dir('cli_demo', force=True)
pxt.create_dir('cli_demo')

videos = pxt.create_table(
    'cli_demo/videos', {'video': pxt.Video, 'title': pxt.String}
)
frames = pxt.create_view(
    'cli_demo/frames',
    videos,
    iterator=frame_iterator(videos.video, fps=1),
)
frames.add_computed_column(thumb=frames.frame.thumbnail((320, 180)))

videos.insert([{'video': SAMPLE_VIDEO, 'title': 'Bangkok'}])
Connected to Pixeltable database at: postgresql+psycopg://postgres:@/pixeltable?host=/private/var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home/pgdata
Created directory ‘cli_demo’.
Created table ‘videos’.
Added 0 column values with 0 errors in 0.00 s
Inserted 20 rows with 0 errors in 0.89 s (22.39 rows/s)
20 rows inserted.

  1. Inspect the catalog

List directories and tables, then drill into schema and computed columns. Flag letters in pxt ls -l: c = computed column, i = index.
!pxt ls -l cli_demo
!pxt describe cli_demo/videos
!pxt columns cli_demo/frames --computed
!pxt idxs cli_demo/frames
path             kind   cols  version  flags
cli_demo/frames  view      6        2  c
cli_demo/videos  table     2        1  i
table ‘cli_demo/videos’

 Column Name    Type  Source Computed With Comment

       video   Video  videos                              title  String  videos                       cli_demo/frames thumb   Required[Image] computed    frame.thumbnail([320, 180])

  1. Query rows

Peek at stored data from the terminal. Pass computed columns explicitly with --cols; unstored computed columns are skipped by default. Thumbnails may take a moment to compute after insert.
!pxt count cli_demo/frames
!pxt rows cli_demo/frames -n 1 --cols pos,thumb
19
pos thumb
0   <Image 320x180 RGB>

  1. Debug computed-column failures

When a stored computed column fails, pxt errors lists the failing rows by primary key.
@pxt.udf
def boom_if_zero(x: int) -> int:
    if x == 0:
        raise ValueError('boom')
    return x


failures = pxt.create_table(
    'cli_demo/failures', {'k': pxt.Required[pxt.Int]}, primary_key='k'
)
failures.add_computed_column(
    result=boom_if_zero(failures.k), on_error='ignore'
)
failures.insert([{'k': 0}, {'k': 1}], on_error='ignore')

!pxt errors cli_demo/failures
Created table ‘failures’.
Added 0 column values with 0 errors in 0.01 s
Inserted 2 rows with 2 errors across 2 columns (failures.result, failures.None) in 0.00 s (400.31 rows/s)
{k: 0}  result  ValueError  boom

  1. Version control

Every insert and schema change creates a new table version. Inspect the timeline, then roll back if needed. See Track changes and revert for the Python API.
videos.add_computed_column(label=videos.title.upper())

!pxt history cli_demo/videos -n 5
!pxt revert cli_demo/videos -f
!pxt history cli_demo/videos -n 3
Added 1 column value with 0 errors in 0.02 s (51.20 rows/s)
version created_at  change_type inserts updates deletes errors  schema_change
2   2026-06-12T23:39:11.848683Z schema  0   1   0   0   Added: label
1   2026-06-12T23:39:08.810158Z data    20  0   0   0   
0   2026-06-12T23:39:08.490587Z schema  0   0   0   0   Initial Version
reverted cli_demo/videos: v2 -> v1
version created_at  change_type inserts updates deletes errors  schema_change
1   2026-06-12T23:39:08.810158Z data    20  0   0   0   
0   2026-06-12T23:39:08.490587Z schema  0   0   0   0   Initial Version

  1. Agent-friendly scripting

Most catalog commands accept --json for stable, machine-readable output. Use -f to skip confirmation prompts in non-interactive contexts. For many commands in one session, pxt shell keeps the daemon warm:
pxt shell
pxt> ls cli_demo
pxt> count cli_demo/frames
pxt> exit
tables = [
    e['path']
    for e in pxt_json('ls', 'cli_demo', '--json')['entries']
    if e['kind'] == 'table'
]
print('tables:', tables)
print(
    'frame count:',
    pxt_json('count', 'cli_demo/frames', '--json')['count'],
)
tables: [‘cli_demo/failures’, ‘cli_demo/videos’]
frame count: 0

  1. Config and health

Check daemon health, runtime status, and resolved configuration (API keys show as <redacted> when set). See Configure API keys for credential setup.
!pxt health
!pxt status
!pxt config --section openai
{
  “ok”: true,
  “service”: “pxt”,
  “pxt_version”: “0.6.5”,
  “pid”: 52061,
  “started_at”: “2026-06-12T23:09:23.075920+00:00”,
  “pxt_install_dir”: “/opt/miniconda3/envs/pxt/lib/python3.10/site-packages/pixeltable”,
  “python_executable”: “/opt/miniconda3/envs/pxt/bin/python”,
  “pixeltable_home”: “/private/var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home”,
  “pixeltable_pgdata”: “/private/var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home/pgdata”,
  “pixeltable_config_file”: “/private/var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home/config.toml”,
  “pixeltable_env”: {
    “PIXELTABLE_HOME”: “/var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home”
  }
}
pxt_version     0.6.5.dev24+8a39208c
daemon_pid      52061
daemon_started  2026-06-12T23:09:23.075920+00:00
home            /var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home
db_url          postgresql+psycopg://postgres:***@/pixeltable?host=%2Fprivate%2Fvar%2Ffolders%2Fs4%2F0zdx499s6sv3_0jll6ccdbh00000gn%2FT%2Ftmp.8rYgq6oxHN%2F.pxt-home%2Fpgdata
media_dir       /var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home/media
file_cache_dir  /var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home/file_cache
total_tables    7
total_errors    2
config_file  /var/folders/s4/0zdx499s6sv3_0jll6ccdbh00000gn/T/tmp.8rYgq6oxHN/.pxt-home/config.toml
not set: openai.api_key, openai.base_url, openai.api_version, openai.rate_limits, openai.max_connections, openai.max_keepalive_connections, openai.read_timeout, openai.write_timeout

  1. Serve without application code

Validate an insert endpoint with --dry-run --json (no server started). For production, declare routes in pyproject.toml — see HTTP Serving. Full live flow:
pxt serve insert --table cli_demo/videos --path /videos --inputs video title --outputs title
curl -X POST localhost:8000/videos -H 'Content-Type: application/json' \
  -d '{"video": "https://raw.githubusercontent.com/pixeltable/pixeltable/release/docs/resources/bangkok.mp4", "title": "Bangkok"}'
pxt rows cli_demo/frames -n 1 --cols pos,thumb
!pxt serve insert --table cli_demo/videos --path /videos --inputs video title --outputs title --dry-run --json
{
  “name”: “pxt-serve”,
  “prefix”: "",
  “host”: “0.0.0.0”,
  “port”: 8000,
  “routes”: [
    {
      “path”: “/videos”,
      “background”: false,
      “type”: “insert”,
      “table”: “cli_demo/videos”,
      “inputs”: [
        “video”,
        “title”
      ],
      “uploadfile_inputs”: null,
      “outputs”: [
        “title”
      ],
      “return_fileresponse”: false,
      “export_sql”: null
    }
  ]
}

Next steps

Last modified on June 23, 2026