> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pixeltable.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Application code puts a TableModel in app.py, then runs `pxt schema update app.py my_app` to create the tables and `pxt service update app.py my_app` to start HTTP. The last argument can be a Cloud URL such as `pxt://org:db`. Do not call pxt.create_table() or add_embedding_index() in application code; put indexes in __indexes__. Notebooks, tests, and the REPL do use pxt.create_table().
> Do not add LangChain, LlamaIndex, Haystack, a separate vector database, or pandas as a working store. Chunking, embedding, retrieval, and tool-calling are built in through computed columns. Use a computed column instead of a per-row loop that calls a model.
> Install with `pip install -U 'pixeltable[serve]'` on Python 3.11+. `pxt init` is a prerequisite for `pxt schema update`.
> Pixeltable Cloud is in Limited Beta. Direct interested users to contact@pixeltable.com.

# CLI Reference

> Inspect, query, and serve Pixeltable catalogs from the terminal with the pxt command.

The `pxt` CLI ships with the `pixeltable` package. It covers two surfaces:

* **Catalog operations** -- inspect, query, and manage tables, views, and directories. Backed by a long-lived local daemon so each command takes \~40 ms after the first invocation.
* **Service deployment** -- run the services defined in an application file with `pxt service`. Requires the `serve` extra (which pulls in `fastapi[standard]` and `uvicorn`):

  ```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
  pip install 'pixeltable[serve]'
  ```

Verify the installation:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt --help
pxt health
```

On the first catalog command, `pxt` auto-spawns a daemon bound to `127.0.0.1:22089`. The daemon survives across shells and stays warm for subsequent commands. Override the port with `PXT_PORT`.

## Command structure

```text theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt <command> [args...]
```

Use `pxt <command> --help` for per-subcommand flags and examples.

| Category | Commands |
| - | - |
| **Inspection** | `ls`, `describe`, `columns`, `computed`, `idxs`, `history`, `status`, `config` |
| **Navigation** | `cd`, `pwd` |
| **Query** | `rows`, `get`, `count`, `errors` |
| **Mutation** | `drop`, `drop-dir`, `rename`, `mv`, `recompute`, `revert` |
| **Schema** | `schema diff`, `schema update`, `schema prune` |
| **Interactive** | `shell` |
| **Serving** | `service` |
| **Cloud** | `login`, `logout`, `whoami`, `db`, `secret`, `org`, `key` |
| **Lifecycle** | `daemon`, `dashboard`, `health` |

### Universal flags

These flags work the same way across the catalog commands that support them and are not repeated in the per-command tables below.

| Flag | Available on | Description |
| - | - | - |
| `-h`, `--help` | Every command | Print the command's usage and examples |
| `--json` | Inspection, query, and mutation commands (`ls`, `describe`, `columns`, `computed`, `idxs`, `history`, `status`, `config`, `rows`, `get`, `count`, `errors`, `drop`, `drop-dir`, `rename`, `mv`, `recompute`, `revert`), the `schema` and `service` verbs other than `example`, plus `init`, `login`, `whoami`, `db`, `secret`, `org`, `key`, and `daemon status` | Emit machine-readable JSON instead. Not accepted by `shell` (interactive REPL), `health` (always JSON), `dashboard` (URL launcher), the navigation commands (`cd`, `pwd`), `schema example` and `service example` (which print an example file), or the commands that print plain status lines (`logout`, `daemon start`/`stop`/`restart`). |
| `--json-schema` | `schema diff`, `service diff`, `db diff`, `db status`, `service list` | Print the JSON Schema of that command's `--json` output, with descriptions of every field and enum value, and exit. |
| `-n`, `--dry-run` | Every catalog mutation (`drop`, `drop-dir`, `rename`, `mv`, `recompute`, `revert`), plus `schema update`, `schema prune`, `service update` and `service prune` | Print the intended action; don't execute. |
| `-f`, `--force` | Mutations that prompt for confirmation (`drop`, `drop-dir`, `recompute`, `revert`, `schema update`, `schema prune`, `service update`, `service prune`, `db update`, `db delete`) | Skip the `[y/N]` prompt. Required in non-interactive contexts. `rename` and `mv` don't prompt and don't accept `-f`. |

### Working directory

`pxt cd` sets a working directory that is prepended to *relative* paths in later commands, and `pxt pwd` prints it -- the catalog analogue of a shell's `cd`/`pwd`.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt cd my_dir                      # relative paths now resolve under my_dir
pxt pwd                            # print the current working directory
pxt ls sub                         # lists my_dir/sub
pxt cd ..                          # up one level
pxt cd                             # clear it
```

Absolute paths ignore the working directory: a leading `/` (e.g. `pxt ls /other_dir`) resolves from the catalog root, and a `pxt://org:db/...` URI addresses a hosted catalog. `.` and `..` work in any path and resolve against the working directory; `..` at the catalog root keeps the root.

The working directory is scoped to the **invoking terminal**, not the daemon globally -- it is keyed by the shell's session, sent with every command. So separate terminals have independent working directories, and it does **not** leak into subprocesses or agents you launch: a spawned process runs under its own session with no working directory, so its `pxt` commands resolve relative paths from the catalog root regardless of what you set interactively.

Because of that isolation, scripts and agents should address the catalog with absolute paths (`/...` or `pxt://...`) and ignore the working directory; it is a convenience for interactive terminal use.

## Quick reference

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# inspect
pxt ls -l                          # everything under root, with metadata
pxt ls some_dir --counts           # row counts (parallelized)
pxt describe my_dir/my_table       # schema
pxt rows my_dir/my_table -n 5      # first 5 stored cells

# query
pxt get my_dir/my_table 42         # PK lookup
pxt count my_dir/my_table          # row count
pxt errors my_dir/my_table         # rows where a computed column failed

# ops
pxt drop my_dir/my_table -f
pxt mv my_dir/my_table other_dir
pxt recompute my_dir/my_table summary -f
pxt revert my_dir/my_table --steps 3 -f

# navigate
pxt cd my_dir                      # set the working directory (this terminal)
pxt pwd                            # print it

# projects
pxt init                             # mark the current directory as a project root

# declarative schemas
pxt schema check  app.py          # validate the file on its own, with no target
pxt schema diff   app.py my_app   # what 'update' would change (exit 2 = drift)
pxt schema diff   --json-schema   # JSON Schema for the --json output
pxt schema update app.py my_app   # create and migrate the declared tables
pxt schema prune  app.py my_app -f # drop the undeclared ones

# interactive
pxt shell

# services declared in an application file
pxt service check  app.py            # validate the file on its own, with no target
pxt service diff   app.py my_app     # what 'update' would change (exit 2 = drift)
pxt service diff   --json-schema     # JSON Schema for the --json output
pxt service update app.py my_app     # start them, restarting what changed
pxt service list                     # what is running, and where
pxt service logs my_app/ingest       # what a service logged; pxt://myorg:mydb/my_app/ingest for a hosted one

# cloud -- signing in
pxt new                          # a free trial database, no account needed
pxt login                        # approve a code in a browser; no API key needed
pxt whoami                       # who this machine is signed in as, and which credential it sends
pxt logout                       # forget this device's cached session, or its `pxt new` trial

# cloud -- databases
pxt db update pxt://myorg:mydb   # create the database, or bring it up to what the project declares
pxt db diff   pxt://myorg:mydb   # what 'update' would change
pxt db diff   --json-schema      # JSON Schema for the --json output
pxt db list                      # the databases in your org
pxt db logs   pxt://myorg:mydb   # what the database's pod logged

# cloud -- secrets
pxt secret set  pxt://myorg OPENAI_API_KEY=sk-...
pxt secret list                  # every secret in your org and its databases

# cloud -- keys
pxt key create ci                # a key that acts as you
pxt key create app --grant access:pxt://myorg:mydb/services/ingest
pxt key list                     # every key in the org, and who created it
```

## Inspection commands

### `pxt ls`

List entries under a directory.

| Flag | Description |
| - | - |
| `-l`, `--long` | Include column count, last version, and flags |
| `--counts` | Include row counts (runs `count()` per table, parallelized) |
| `--tree` | Tree view |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt ls                            # root
pxt ls some_dir                   # contents of some_dir
pxt ls -l some_dir                # with metadata
pxt ls --counts                   # with row counts
```

Output of `pxt ls -l`:

```text theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
path                kind   cols  version  flags
agent_demo          dir                       -
audio_chunks        view      9        3  ci
chess_vids          table     3        3  ci
chk                 table     2        1  i
```

Flag letters: `c` = has at least one computed column, `i` = has at least one index.

### `pxt describe`

Show a table's schema and metadata. The plain form is human-readable; `--json` returns the full `get_metadata()` dict.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt describe my_dir/my_table
pxt describe my_dir/my_table --json
```

### `pxt columns` / `pxt computed`

List columns for one or more tables. `pxt computed` is shorthand for `pxt columns --computed`. The path argument may be a single table or a directory; a directory path lists columns for every table beneath it, recursively. A directory path may be a local path or a hosted URI (`pxt://org:db/...`). With no path, every table in the in-process catalog is listed.

| Flag | Description |
| - | - |
| `--computed` | Restrict to computed columns (no effect for `pxt computed`, which always sets it) |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt columns                       # every column in the catalog
pxt columns my_dir/my_table       # one table
pxt columns my_dir                # every table under a directory, recursively
pxt columns pxt://org:db          # every table in a hosted database
pxt columns --computed            # computed columns across every table
pxt computed                      # same as above
```

### `pxt idxs`

List indexes. Shows both B-tree and embedding indexes by default; the `--embedding` flag restricts to embedding indexes. Like `pxt columns`, the path may be a single table or a directory (walked recursively), a hosted database root (`pxt://org:db`), or omitted for the whole in-process catalog.

| Flag | Description |
| - | - |
| `--embedding` | Restrict to embedding indexes |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt idxs                          # every index
pxt idxs my_dir/my_table          # indexes on one table
pxt idxs my_dir                   # every table under a directory, recursively
pxt idxs pxt://org:db             # every table in a hosted database
pxt idxs --embedding              # only embedding indexes
```

### `pxt history`

Show a table's version timeline.

| Flag | Description |
| - | - |
| `-n N` | Show at most N most recent versions |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt history my_dir/my_table
pxt history my_dir/my_table -n 5  # last 5 versions
```

### `pxt status`

Daemon and runtime state: pxt version, daemon PID, configured paths, total tables, total errors.

| Flag | Description |
| - | - |
| `--sizes` | Also report media and file-cache disk usage (slower; scans the directories) |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt status
pxt status --sizes --json
```

### `pxt config`

Every documented configuration setting with its current value and source (`env`, `file`, or `unset`). Credentials show `<redacted>` when set; the `source` column reveals presence even when the value is masked.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt config
pxt config --section openai
pxt config --source env
```

## Query commands

### `pxt rows`

Show the first N rows of a table. Unstored computed columns are skipped by default (selecting one forces evaluation, which can invoke LLMs or expensive compute); pass them explicitly via `--cols` to include them.

| Flag | Description |
| - | - |
| `-n N` | Number of rows (default 10) |
| `--cols a,b,c` | Comma-separated column subset. Default: all stored columns |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt rows my_dir/my_table -n 3
pxt rows my_dir/my_table --cols id,text,score
```

### `pxt get`

Look up a single row by primary key. An `Int`, `Float`, or `UUID` PK column parses its value and rejects one that does not parse. A `String` PK column keeps the value as typed, so `007` stays `007`. Lookup by a PK of any other type, such as `Date` or `Timestamp`, is not supported yet and finds no row. The table must declare a primary key. Unstored computed columns are skipped unless requested explicitly via `--cols` (consistent with `rows`).

| Flag | Description |
| - | - |
| `--cols a,b,c` | Comma-separated column subset. Default: all stored columns |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt get my_dir/my_table 42                    # single-column PK, int
pxt get my_dir/my_table some_string_id        # single-column PK, string
pxt get my_dir/my_table 42 abc                # composite PK, in declared order
pxt get my_dir/my_table 42 --cols id,text     # restrict to listed columns
```

### `pxt count`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt count my_dir/my_table         # prints the integer
pxt count my_dir/my_table --json
```

### `pxt errors`

List rows where a stored computed column failed. The table must have a primary key (so each failing row can be identified).

| Flag | Description |
| - | - |
| `--col NAME` | Filter to a single computed column |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt errors my_dir/my_table
pxt errors my_dir/my_table --col embedding
```

## Mutation commands

Every mutation accepts the universal `-n`/`--dry-run` and `--json` flags. The destructive ones (`drop`, `drop-dir`, `recompute`, `revert`) also prompt `[y/N]` with a TTY and accept `-f`/`--force` to skip the prompt; in non-interactive contexts they refuse to proceed without `-f`. `rename` and `mv` don't prompt: renaming or moving a catalog entry is reversible and doesn't lose data.

### `pxt drop`

Drop a table or view. Use `pxt drop-dir` for directories.

| Flag | Description |
| - | - |
| `--cascade` | Also drop dependent views |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt drop my_dir/my_table -f                 # drop a table
pxt drop my_dir/my_table --cascade -f       # also drop dependent views
pxt drop my_dir/my_table -n                 # dry-run
```

### `pxt drop-dir`

Remove a directory. Use `pxt drop` for tables/views.

| Flag | Description |
| - | - |
| `-r`, `--recursive` | Also remove contained tables/views/subdirectories |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt drop-dir my_dir -f            # remove an empty directory
pxt drop-dir my_dir -r -f         # recursive: also remove contained tables/subdirs
```

### `pxt rename`

Rename in place; the parent directory is preserved. `<new_name>` must be a single name component (no `/` or `.`). Takes only universal flags.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt rename my_dir/old_name new_name
```

### `pxt mv`

Move a table/view/dir under a different directory; the entry's own name is preserved. `<new_dir>` can be `''` or `/` for the root directory. Takes only universal flags.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt mv my_dir/my_table other_dir              # -> other_dir/my_table
pxt mv my_dir/my_table /                      # move to root
```

### `pxt recompute`

Recompute one or more computed columns of a table. Mirrors `Table.recompute_columns()`, without its `where`
predicate.

| Flag | Description |
| - | - |
| `--errors-only` | Only the rows whose value is an error. Takes a single column |
| `--no-cascade` | Do not recompute the computed columns and views that transitively depend on this one |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt recompute my_dir/my_table summary -f                  # the column and its dependents
pxt recompute my_dir/my_table summary embedding -f        # several columns in one pass
pxt recompute my_dir/my_table summary --errors-only -f    # only the rows that failed
pxt recompute my_dir/my_table summary -n                  # what it would recompute, and over how many rows
```

<Warning>
  Recomputing evaluates the target columns over every row, which can require substantial computing resources.
  `--errors-only` limits that recomputation to only the rows that failed.
  `-n` reports the target table's own row count.
</Warning>

### `pxt revert`

Undo recent ops on a table. Each revert undoes one op; `--steps` repeats.

| Flag | Description |
| - | - |
| `--steps N` | Number of consecutive reverts (default 1) |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt revert my_dir/my_table -f                 # undo the last op
pxt revert my_dir/my_table --steps 3 -f       # roll back 3 versions
```

<Warning>
  Revert is irreversible. Run `pxt history my_dir/my_table` first to see what would be undone.
</Warning>

## Project layout

`pxt schema` and `pxt service` read a Python file, and the tables they create refer back to the UDFs that file calls. A reference is a module path, so the file has to belong to a project. The **project root** is the directory with the project configuration, and every local module path is relative to it.

`pxt init` writes that configuration in the current directory:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
cd ~/proj
pxt init                             # writes pixeltable.toml, making ~/proj the project root
```

That file has one entry for each database in the project:

```toml theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
[[pixeltable.database]]
# the local database
vars.media_dest = 's3://bucket/prefix'      # binds a ConfigVar declared by a schema

[[pixeltable.database]]
name = 'pxt://myorg:prod'                   # a hosted database
system_dependencies = ['ffmpeg']            # what goes into its image
```

In a directory that already has a `pyproject.toml`, the same entry is appended there as `[[tool.pixeltable.database]]` instead, and that section marks the root.

Every directory from the root down to a file becomes one component of that file's module path, so each of those directory names has to be a Python identifier:

```
~/proj/pixeltable.toml               # the project configuration; its directory is the root
~/proj/ad_gen/app.py                 # a UDF here is recorded as 'ad_gen.app.<name>'
~/proj/ad_gen/functions.py           # imported as 'from ad_gen.functions import ...'
```

Imports resolve from the root down. This is where a single-file recipe and a larger application diverge: a file directly under the root imports its neighbors by their bare names, so `recipe.py` and `functions.py` side by side use `from functions import ...`. Once an application moves into a subdirectory, that subdirectory joins the path: `from ad_gen.functions import ...`.

A recorded path is how a later process -- the daemon, a serving worker, a hosted pod -- finds the UDF again, so a command given a file outside any project root is refused. `pxt schema check` and `pxt service check` validate a file on its own -- it imports without touching the catalog, it declares what the verb needs, and its columns refer to UDFs by paths another process can resolve:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt schema check app.py           # exit 0 valid, 1 invalid
pxt service check app.py --json
```

## Schema management

The commands above act on one object at a time. `pxt schema` works differently: you describe the tables you want in a Python file, and the CLI reconciles a catalog to that description. Provisioning an empty target and evolving an existing one are the same command, so there is no separate first-time step.

| Command | Description |
| - | - |
| `pxt schema diff FILE my_app` | Show what `update` would change. Read-only |
| `pxt schema update FILE my_app` | Create the tables the file declares under the last argument, and migrate existing ones |
| `pxt schema prune FILE my_app` | Drop the tables under the last argument that the file does not declare |
| `pxt schema check FILE` | Validate the file on its own. No catalog argument, and it reads no catalog |
| `pxt schema example` | Write a working file to start from |

`FILE` is a path to a Python file. The last argument is a catalog: a local directory such as `my_app`, or a `pxt://` URI. `update` creates it if it doesn't exist.

### The file

The file defines one or more models on a `pxt.model_base()`. Each model becomes one table, named by `name=`. `pxt schema example` writes a file covering every construct the schema DSL supports, so you never have to start from a blank page and never have to look up a construct:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt schema example --out app.py
```

`pxt schema example --brief` writes the minimal version instead:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
import pixeltable as pxt
import pixeltable.functions as pxtf

TableModel = pxt.model_base()

class Docs(TableModel, name='docs'):
    title: pxt.String
    body: pxt.String | None
    title_upper = pxtf.string.upper(title)

class Titled(TableModel, name='titled', base=Docs.where(Docs.title != '')):
    headline = Docs.title_upper + '!'         # a view of Docs, filtered by its base= query
```

An annotation (`name: type`) declares a stored column; an assignment (`name = expr`) declares a computed column. A model with `base=` becomes a view of that query's base model.

The daemon imports the file, so it must be readable there. Its own directory is added to `sys.path`, so it can import modules sitting next to it.

### Reviewing and updating

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt schema diff   app.py my_app     # review
pxt schema update app.py my_app     # create or migrate tables
```

`diff` prints one line per table, then one per operation:

```text theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
~ my_app/docs              update
    + column 'author' will be added  safe
    - column 'body' will be dropped  DESTRUCTIVE
= my_app/titled_docs       no change
! my_app/scratch           extra (not in schema)

Plan: 0 create, 1 update, 1 unchanged, 1 extra  |  1 destructive
```

| Marker | Meaning |
| - | - |
| `+` | The table will be created, or the column/index will be added |
| `~` | The table will be migrated |
| `=` | The table already matches its model |
| `-` | The column/index will be dropped |
| `!` | The table cannot be migrated in place, or is not declared by the schema |

### `pxt schema update`

`update` creates missing tables and migrates existing ones, adding and dropping columns and indexes. It takes the same flags as the other mutations, plus one of its own:

| Flag | Description |
| - | - |
| `-n`, `--dry-run` | Print the plan; do not run `update`. Exit `2` if changes are pending |
| `--allow-destructive` | Permit operations that drop a column or index |
| `-f`, `--force` | Skip the `[y/N]` prompt shown before destructive operations |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt schema update app.py my_app                          # safe changes
pxt schema update app.py my_app -n                       # the plan; does not run `update`
pxt schema update app.py my_app --allow-destructive -f   # including drops
```

If the plan contains a destructive operation and `--allow-destructive` is absent, `update` does not change the catalog and exits `3`.

<Warning>
  Dropping a column or an index destroys its data. Run `pxt schema diff` (or `update -n`) first: the plan marks every operation `safe`, `DESTRUCTIVE`, or `UNSUPPORTED`.
</Warning>

Some differences cannot be migrated in place: a table declared where a view exists, a changed iterator, or a column whose type or properties changed. Those are reported as `UNSUPPORTED`, `update` changes nothing, and it exits `1`. Adjust the application file or the table by hand.

### Exit codes

The schema commands report their outcome in the exit status, so a caller never has to parse the output:

| Code | Meaning |
| - | - |
| `0` | The target agrees with the schema (including when there was nothing to do) |
| `1` | Error: bad arguments, the file failed to import, or a table cannot be reconciled |
| `2` | Changes are pending (`diff`, or `update -n` / `prune -n`) |
| `3` | Refused: the plan is destructive and `--allow-destructive` was not given, or `-f` was needed to confirm without a terminal |

A drift check in CI is therefore one command:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt schema diff app.py pxt://acme:main/prod    # 0 = in sync, 2 = drift, 1 = error
```

### Machine-readable plans

`pxt schema diff --json` emits the whole plan as one object: `schema_file`, `catalog_dir`, `in_agreement`, `tables`, `extras`, and a `summary` with one count per resolution. Each entry in `tables` has a `path`, a `resolution`, a `destructive` flag, and its `ops`:

```json theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
{
  "path": "my_app/docs",
  "model_cls": "Docs",
  "kind": "table",
  "exists": true,
  "resolution": "update_destructive",
  "destructive": true,
  "ops": [
    {"target": "column", "name": "author", "op": "add", "severity": "additive", "destructive": false,
     "description": "column 'author' will be added", "details": {"type": "String"}},
    {"target": "column", "name": "body", "op": "drop", "severity": "destructive", "destructive": true,
     "description": "column 'body' will be dropped", "details": {}}
  ]
}
```

An op's `target` is `column`, `index`, or `table`, and its `op` is `add`, `drop`, or `alter`. `name` is what it acts on -- a column, an index, the differing attribute when the target is a table, or the table path for a drop -- and `details` contains that operation's operands, such as the `type` of an added column. `severity` is `additive`, `destructive`, or `unsupported`; `destructive` is the boolean form of the middle case. A table's `resolution` is `up_to_date`, `create`, `update_additive`, `update_destructive`, or `unsupported`, and a `create` has no ops, because the create subsumes them.

These field names and values are the catalog's own, as returned by `TableModel.get_model_diff()`, so a plan read from the CLI and a diff read from Python describe a change the same way.

`pxt schema diff --json-schema` prints the JSON Schema of that output.

`update` and `prune` return the same object with a `status` on every table and operation:

| Status | Meaning |
| - | - |
| `applied` | Carried out |
| `skipped` | Not carried out: a dry run, or nothing to do |
| `refused` | Not carried out because consent was missing (`--allow-destructive`, or `-f` with no terminal) |

Every path returns the plan, including the ones that refuse before reaching the daemon, so an `--allow-destructive` refusal is as machine-readable as a success: exit `3`, with the offending operations marked `refused` and the rest `skipped`. `prune` reports its drops in a top-level `ops` array, each with `target: "table"`, `op: "drop"`, and the dropped table's path in `name`.

### Pruning

`update` only ever touches tables declared by the schema, so tables it doesn't know about accumulate. `diff` lists them as extras; `prune` drops them. A full reconcile is `update` followed by `prune`.

| Flag | Description |
| - | - |
| `-n`, `--dry-run` | List what would be dropped; exit `2` if anything would be |
| `-f`, `--force` | Skip the `[y/N]` prompt |

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt schema prune app.py my_app -n     # list what would be dropped
pxt schema prune app.py my_app -f     # drop it
```

Only tables under the last argument are considered, so nothing elsewhere in the catalog is affected, and declared tables are never dropped. A view is dropped before its base. Prune never force-drops: a table with a dependent outside the pruned set is left in place, and the drop fails with an error reporting that dependent.

<Warning>
  Pruning is irreversible. Run it with `-n` first.
</Warning>

## Interactive shell

For agentic or scripted workloads that issue many commands in sequence, `pxt shell` amortizes Python startup over the session:

```text theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
$ pxt shell
pxt> ls
path                kind
agent_demo          dir
chess_vids          table
...
pxt> describe chess_vids
...
pxt> exit
```

Inside the shell, every `pxt` command is available unmodified. Errors from one command don't kill the session. Use `help`, `exit`, `quit`, or Ctrl-D to leave.

## Output and scripting

Most catalog commands accept `--json` for stable, machine-readable output; [Universal flags](#universal-flags) lists the commands that do not:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt ls --json | jq '.entries[] | select(.kind == "table")'
pxt get my_dir/my_table 42 --json | jq '.row'
pxt count my_dir/my_table --json | jq '.count'
```

Without `--json`, output is column-aligned text.

The `schema` commands additionally report drift in their exit status (`0` in sync, `2` pending, `3` refused, `1` error), so a CI gate needs no output parsing.

## Serving

`pxt service` runs the services in an application file. An application file is any Python source file containing
table/view models and either `FastAPIRouter` instances (which serve routes over them) or a `fastapi.FastAPI`
application of your own. It requires the `serve` extra
(`pip install 'pixeltable[serve]'`), which pulls in `fastapi[standard]` and `uvicorn`.

<Info>
  A service is a full FastAPI application with auto-generated [OpenAPI docs](https://fastapi.tiangolo.com/features/#automatic-docs)
  at `/docs`. For the API that defines the routes, see the [Python serving API](/howto/deployment/serving#mount-on-your-own-fastapi-app).
</Info>

One file contains both the schema and the services, so the same file drives both commands:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt service example --out app.py    # a working file to start from
pxt schema update app.py my_dir     # create the tables declared by the models
pxt service update app.py my_dir    # serve this file's services against them
```

The last argument is the catalog the models are bound to, so the same file can run against a development
directory and a production one.

### Serving your own application

A file may supply its own `fastapi.FastAPI` object instead of leaving Pixeltable to build one. Then the
file declares one service, named after its module, and `pxt service update` serves that application as it
is:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# notes_app.py
import fastapi
import pixeltable as pxt

TableModel = pxt.model_base()

class Notes(TableModel, name='notes'):
    note_id = pxt.Column(type=pxt.Int, primary_key=True)
    text: pxt.String

app = fastapi.FastAPI()

@app.post('/notes')
def add_note(note_id: int, text: str) -> dict[str, int]:
    return {'rows': Notes.insert([{'note_id': note_id, 'text': text}]).num_rows}
```

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt schema update notes_app.py my_dir     # create the tables for the models in notes_app.py
pxt service update notes_app.py my_dir    # serve the application, as service 'notes_app'
```

The models in the file are bound to the last argument before the application serves, so a handler reaches
them by name (`Notes.insert(...)`).

All `FastAPIRouter` instances in the same source file are expected to be included in the `FastAPI` application
(via `include_router()`), and the application file still produces a single service:

```python theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
app.include_router(ingest, prefix='/v1')   # ingest's routes are served under /v1
```

A router not included in `app` would never be served, and in that situation `pxt service` fails with an error.
The routes of an included `FastAPIRouter` are diffed by their declarations (i.e., they take the data types of path
parameters into account); the paths served by the application itself are diffed as path strings.

### Signing in

Hosted commands need a credential. `pxt login`, `pxt whoami`, and `pxt key` require Pixeltable 0.7.10 or later. There are three: a `pxt login` session, a `pxt new` trial ([Trial databases](#trial-databases)), and an API key. You need one of them.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt login
```

`pxt login` prints a code and opens a browser. Approve it there, signing in or signing up, and the
session lands on this machine. It uses the OAuth device grant, so nothing
listens on a port and the browser need not be on this machine: this works over SSH.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt whoami
you@example.com on https://internal-api.pixeltable.com
Organization: org_01H8XYZ
```

A sign-in lasts as long as Pixeltable Cloud honors it: when its token expires, the next command that
needs a token renews the session, and nothing on this machine expires it on a timer. `pxt whoami`
reports whether Pixeltable Cloud recognizes the credential, and exits nonzero when it does not; it
does not report whether the next command will succeed. A credential that is recognized but not
permitted to list organizations, such as a key whose grants do not cover that, still counts as
accepted: `pxt whoami` prints the refusal as a note and exits 0. `pxt whoami --offline` reports the
cached session without asking.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt logout
```

`pxt logout` forgets this machine's cached session, or its `pxt new` trial ([Trial databases](#trial-databases)). When the session has the sign-in service's
session id, `pxt logout` also opens that service's sign-out page for the session in your browser,
and prints the link when no browser opens. It signs out of both because a browser that is still
signed in confirms the next code without naming the account, so signing out of only one leaves you
signed in as someone you did not choose. Forgetting the session needs no network. When `pxt logout`
cannot work out the sign-out link, for example because the control plane cannot be reached, it
still signs this machine out and warns that the browser was not signed out. Whether the sign-out
page itself loads is something only the browser shows.

<Note>
  An **API key** takes precedence over a sign-in whenever both are present: it is the explicit
  choice, and what CI runs on. Set one with `PIXELTABLE_API_KEY`, or with `api_key` in the
  `[pixeltable]` section of your Pixeltable config file; the environment variable wins when both are
  set. Unlike a sign-in, it does not expire. `pxt whoami` says which one your commands will actually
  send.
</Note>

Signing in proves who you are. If you belong to exactly one organization, `pxt login` also selects
it. A brand-new account belongs to no organization, and every hosted command needs one, so `pxt login`
and `pxt whoami` print "No organization yet" with the command that creates one, `pxt org create NAME`,
rather than letting the next command fail as an authorization error.

### Trial databases

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt new
```

`pxt new` needs no account. It creates a trial organization with one database, `main`, and caches
the trial's API key on this machine, so later commands use it without `pxt login` or an exported
key. It prints the database's URI, the `[[pixeltable.database]]` entry for `pixeltable.toml`, the
next commands, and a claim link. It never prints the key, and neither does `pxt new --json`.

Until it is claimed, the organization has 1 database and at most 2 services, each on 1 worker with up
to 1 cpu, 2048 MB and 10 GB of disk, and 50 GB of media storage: past that, uploads stop. The server sets
its expiry, normally 48 hours after creation. Its pods reach the internet on ports 80, 443 and 5432 only, and one
network holds at most 10 unclaimed trials at once. Whoever opens the claim link signs in or signs up and
becomes the organization's admin, so keep the link out of shared logs.

Running `pxt new` again prints the same trial, without the claim link, and creates nothing.
`pxt whoami` shows the trial and its expiry. `pxt logout` removes the trial's key from this machine
and prints the claim link once more. It revokes nothing: the key works until the organization is
claimed or expires. An API key or a `pxt login` session outranks a trial, so with either one
configured, `pxt new` exits 1 and creates nothing. When the trial's key is rejected, the
organization may have been claimed, and its person signs in with `pxt login`.

`PIXELTABLE_SITE_URL` points `pxt new` at a site other than `https://www.pixeltable.com`. It must
use https, except on localhost.

### Organizations

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt org create acme --name "Acme Inc"
```

Creates the organization, its first database and its storage in one call. The name is the namespace
in `pxt://acme:main`, and it must be unique across Pixeltable. It works with a `pxt login` session or
with a personal API key, one created without grants; a key with grants belongs to its organization
and cannot create another.

Creating one also switches your `pxt login` session to it: Pixeltable Cloud takes the organization
from your session, not from the URI. If the switch fails, the organization exists anyway, and
`pxt org create` warns and says to run `pxt login`. An API key stays bound to its own organization
and outranks a `pxt login` session, so to work in the new one, use a key created there, or remove
the API key and then run `pxt login`. `pxt org list` shows the ones you can reach.

### Keys

A key is the credential that does not expire, for the places a browser sign-in cannot reach: CI, a
cron job, a deployed service. There is one command and two shapes, and the grants decide which.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt key create ci                                                 # acts as you
pxt key create app --grant access:pxt://acme:main/services/ingest # acts as nobody
```

Without grants, the key acts as whoever created it and reaches whatever they reach: the API key you
already know. With grants it belongs to the organization instead, and reaches only what it was
granted, so a service you deploy has no more authority than its job needs.

<Note>
  Keys with grants are a preview. Until they are enabled for your organization, Pixeltable Cloud
  refuses `pxt key create --grant` with "Keys with grants are not available yet".
</Note>

A grant is a verb on a resource, never a bare resource: a service on its own does not say whether
the holder may call it or reconfigure it, and those are not the same permission.

| Grant | What it allows |
| - | - |
| `access:pxt://org:db` | every service in the database, and its storage |
| `access:pxt://org:db/services` | call any service in the database |
| `access:pxt://org:db/services/name` | call that service, every route under it |
| `manage:pxt://org:db/services` | create, list and manage any service in the database |
| `manage:pxt://org:db/services/name` | start, stop, update, delete that service |

A service is addressed by its base path and name, as in `access:pxt://acme:main/services/my_dir/ingest`.
`manage` applies to services only, so `manage:pxt://org:db` is refused.

`access` and `manage` are independent: a key that can call a service cannot reconfigure it, and one
that can stop it cannot read what flows through it.

The secret is shown once, when the key is created, and is never retrievable afterwards. Deleting a
key revokes it. Every member of the organization sees every key, can change any runtime key's
grants, and can delete any key, and `pxt key list` shows who created each one.

### Hosted targets

The last argument may be a `pxt://org:db` URI, and the services then run in that database rather than on this
machine. The database needs this project and its tables first, so the order is:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db update pxt://acme:main               # create the database and put this project's code in it
pxt schema update app.py pxt://acme:main    # create the tables declared by the models
pxt service update app.py pxt://acme:main   # start the services there
```

`diff`, `update`, `prune`, `stop`, `restart` and `list` all accept a hosted target. `run` does not: it serves from the
calling process, so it is local by definition. Two verbs differ in meaning against a hosted database, where
a stopped service keeps its registration: `stop` stops it and leaves it there to be started again, while
`prune` forgets it.

`pxt service stop` accepts a service address in several forms. A bare name matches the services of the
current project, or every local service when the working directory is outside a project. `my_dir/NAME`
stops the service under `my_dir`, including one in another project, and `/NAME` stops the service at the
catalog root. A bare name that matches more than one service is refused, and the error lists the
qualified path of each match.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt service stop ingest                  # the service named ingest in the current project
pxt service stop my_dir/ingest           # the service of that name under my_dir
pxt service stop /ingest                 # the service of that name at the catalog root
pxt service stop pxt://acme:main/ingest  # the one in a hosted database
```

A name that matches no service, or matches one that is already stopped, is reported as `skipped` with
the reason (`not found` or `already stopped`), so stopping a set of services can be repeated safely.

`pxt service restart` cycles a service's pods onto the database's current image and project, keeping the
service's registration and endpoint, and accepts the same service addresses as `stop`, except that a
bare name matches every local service of that name, whatever its project. Use it after
`pxt db update` to move a running service onto the new project, and to pick up the current values of its
referenced secrets. Against a local target it stops the process and starts it again on the same
port, so callers keep their address.

`pxt service logs` reads a service's log and accepts the same service addresses as `restart`. `pxt db logs` reads
the log of a hosted database's pod:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt service logs ingest                          # a bare name, when only one target has a service of that name
pxt service logs my_dir/ingest                   # the service of that name under my_dir
pxt service logs pxt://acme:main/my_dir/ingest   # the one in a hosted database
pxt service logs pxt://acme:main/ingest --since 10m --tail 50
pxt db logs pxt://acme:main
```

A hosted log merges the serving process's log records, requests included, with its console output, ordered by
time. The console output contains the traceback of a service that failed to start. Health probes are left out unless
`--include-health` is given. The log outlives the pod, so the log of a failed deploy can be read after its pod is
gone. A line appears in the log a few seconds after it is written. A service running on this machine logs to a
local file instead, and `pxt service logs` reports the path of that file.

### `pxt service` verbs

| Command | Description |
| - | - |
| `pxt service diff APP my_app` | Report what `update` would change; exit `2` if anything is pending |
| `pxt service update APP my_app` | Start the services declared by `APP`, and restart the ones whose declaration changed |
| `pxt service run APP my_app [SERVICE]` | Serve one of them from this process instead, until interrupted |
| `pxt service prune APP my_app` | Stop and forget the services under the last argument that `APP` does not declare |
| `pxt service stop NAME...` | Stop the named services; a bare name matches within the current project |
| `pxt service list [my_app]` | What is running at a local or hosted catalog, and where |
| `pxt service logs NAME` | What the named service logged. Pass `my_app/NAME` or a `pxt://` path to disambiguate |
| `pxt service check APP` | Validate the application file on its own. No catalog argument, and it reads no catalog |
| `pxt service example` | Write a working application file to start from |

Like the `schema` verbs, `diff` reports drift in its exit status: `0` in agreement, `2` changes pending,
`3` refused, `1` error. So a CI gate needs no output parsing.

`pxt service diff --json-schema` prints the JSON Schema of that output.

### Flags

| Flag | Verbs | Description |
| - | - | - |
| `--json` | every verb except `example` | Emit machine-readable JSON |
| `--since`, `--tail`, `--include-health` | `logs` | How far back, how many lines, whether to keep health probes |
| `-f`, `--force` | `update`, `prune` | Skip the `[y/N]` prompt |
| `-n`, `--dry-run` | `update`, `prune` | Print the intended change; do not run `update` or `prune` |
| `--allow-destructive` | `update` | Permit changes that stop serving a route callers may be using |
| `--host`, `--port` | `run` | Bind address and port (default `127.0.0.1:8000`) |
| `--otel` | `run`, `update`, `diff` | Emit OpenTelemetry traces; see [Tracing](#tracing) |

### Tracing

`--otel` emits OpenTelemetry traces from the served application: Pixeltable's own spans, nested under the
request spans of the FastAPI app. It needs the instrumentation package (`pip install 'pixeltable[otel]'`),
and the endpoint and service name come from the `OTEL_*` environment variables or the `[otel]` config
section, as they do for any Pixeltable process.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt service run app.py my_dir --otel       # traced, in this process
pxt service update app.py my_dir --otel    # traced, in the background process update starts
```

Tracing is configured once per process, so it is a property of the deployment rather than of the file:
adding or dropping `--otel` restarts the service, and `pxt service diff app.py my_dir --otel` reports that
restart as a pending change before `update` performs it.

### Background and foreground

`update` starts **one background process per service**, each on its own port, and records it so `list` and
`stop` can find it again. A service that crashes disappears from `list` with no cleanup step, because a
record is only as live as the process it refers to.

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt service update app.py my_dir
pxt service list
# my_dir/ingest  http://127.0.0.1:41273  pid 51234  /home/me/app.py
pxt service stop ingest
```

`run` stays in the foreground until you interrupt it and does not register the service for `list` or `stop`,
so it is a separate command, not a flag on `update`. Use it as a container entrypoint or a development loop.
It serves one service per process, the same as `update`; name a specific service as a third argument when the file
declares more than one:

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt service run app.py my_dir --port 9000
# Pixeltable is running on http://localhost:9000
#   Routes: 4
#   API docs at http://localhost:9000/docs
```

### Restarts

A service binds its models once, when its process starts, so a changed declaration takes effect when `pxt service update` replaces
the process. `diff` reports which services that replacement would interrupt, and `update` reports them
before it proceeds. Adding a route is additive; changing or removing one stops serving a contract that
callers may be using, so it needs `--allow-destructive`.

## Cloud

`pxt db` and `pxt org` manage cloud-hosted databases and organizations. Cloud commands need a credential: a `pxt login` session, a `pxt new` trial ([Trial databases](#trial-databases)), or an API key ([Signing in](#signing-in)). To use an API key, create it in the Cloud dashboard ([Get an API key](/cloud#get-an-api-key)) or with `pxt key create`, then export it as `PIXELTABLE_API_KEY`. The CLI reads the process environment and does not load `.env` on its own ([Configuration](/platform/configuration)).

Every cloud command except `pxt logout` accepts `--json` for machine-readable output.

### Cloud configuration reference

`pxt db diff` and `pxt db update` read the entry of the target database from the project configuration (`pixeltable.toml`, or `pyproject.toml` under `[tool.pixeltable]`), searched for upward from the working directory.

#### `[[pixeltable.database]]` -- what a project declares about one database

Defines the attributes of a specific Pixeltable database (which may be either the local database, or a cloud-hosted database), including:

* Which project files to include
* Which dependencies to include
* Compute settings
* Media destinations
* Telemetry configuration

```toml theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
[[pixeltable.database]]
name = 'pxt://myorg:prod'           # matches the URI passed to pxt db update

# where media without an explicit destination goes (default: the database's home bucket)
db_input_media_dest = 's3://bucket/input/'
db_output_media_dest = 's3://bucket/output/'

# the OpenTelemetry exporter; set its auth headers with pxt secret set
db_exporter_otlp_endpoint = 'https://otlp.example.com'
db_exporter_otlp_protocol = 'http/protobuf'  # or 'grpc'

# which project files the database gets. Glob patterns relative to the project root; everything git
# would not ignore is uploaded by default, and the lockfile always is. Patterns use git wildmatch, so
# a bare `*.py` matches at every depth while a leading slash anchors it: `/*.py` is the root only.
include = ["app/**", "models/**"]
exclude = ["__pycache__", "*.pyc", ".git", ".env", "*.egg-info", ".venv"]

# what goes into the image
system_dependencies = ['ffmpeg']    # conda-forge packages
python_version = '3.11'

# what the database runs on
cpu = 2.0
memory_mb = 4096
disk_gb = 50
workers = 2

# fixed when the database is created
location = 'aws'
region = 'us-east-1'
```

An entry with no `name` configures the local database. A hosted database is configured by the entry whose `name` is its URI.

### `pxt db`

Manage cloud-hosted Pixeltable databases. A database is a hosted Pixeltable instance with its own compute, storage, and Python environment.

Database URIs use the form `pxt://org:db`. Valid states: `PROVISIONING`, `STARTING`, `AVAILABLE`, `UPDATING`, `STOPPING`, `STOPPED`, `FAILED`.

The URI argument is optional: when it is omitted, these commands use `db_uri` from the Pixeltable config file (see [Configuration](/platform/configuration)), so a project that sets it can run `pxt db status` and the other `db` commands with no argument.

#### `pxt db update`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db update pxt://myorg:mydb
pxt db update pxt://myorg:mydb -n      # print the plan and stop
pxt db update pxt://myorg:mydb --allow-destructive
```

| Flag | Description |
| - | - |
| `-n`, `--dry-run` | Print the plan; do not run `update` |
| `-f`, `--force` | Skip the confirmation |
| `--allow-destructive` | Permit taking capacity away |

`update` creates a hosted database and keeps it current afterwards. Put the database in a `[[pixeltable.database]]` entry, then run `update` against the URI in its `name`:

```toml theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
# pixeltable.toml
[[pixeltable.database]]
name = 'pxt://myorg:mydb'
```

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db update pxt://myorg:mydb
```

The URI on the command line selects the entry by its `name`: an entry for another database configures that one, and a target with no entry is an error. The first run creates the database, builds the image for its environment and uploads the project files that the pods run; every later run applies whatever has changed since. The [cloud configuration reference](#cloud-configuration-reference) lists everything an entry can declare.

`update` applies a new image if dependencies changed, then uploaded project files if sources changed, then one resize for any changed CPU, memory, disk, or worker counts so the pods restart only once. Secrets are set with [`pxt secret`](#pxt-secret) rather than from the project. The media destinations and the OTLP endpoint and protocol travel with the project files, which always include the project configuration.

#### `pxt db list`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db list
pxt db list --json
```

#### `pxt db status`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db status pxt://myorg:mydb
```

Prints the state, the resources, the project, and the pods, and marks what a pending update would change.

#### `pxt db start`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db start pxt://myorg:mydb
```

Wake a stopped database. Polls until `AVAILABLE`.

#### `pxt db stop`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db stop pxt://myorg:mydb
```

Stop a running database (releases compute; storage is preserved).

#### `pxt db restart`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db restart pxt://myorg:mydb
```

Cycle the pods onto their current image and project, without rebuilding or uploading anything. Use it
to pick up a secret set since they started. Polls until `AVAILABLE`; a stopped database is started instead.

#### `pxt db diff`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db diff pxt://myorg:mydb
pxt db diff pxt://myorg:mydb --json
```

`pxt db diff` compares the hosted database to that config entry (see the [cloud configuration reference](#cloud-configuration-reference)): capacity, the Python image, and the project file archive --

| Artifact | Contents | Replaced when |
| - | - | - |
| the image | the Python environment, and no project code | the lockfile, `python_version`, `system_dependencies` or the Pixeltable version changes |
| the project archive | every selected project file | any selected file changes |

so an edit to a source file is uploaded in seconds, and only a dependency change costs an image build. Exit status is 0 in agreement and 2 with changes pending; nothing is built, resized or set.

`pxt db diff --json-schema` prints the JSON Schema of that output.

#### `pxt db build-image`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db build-image pxt://myorg:mydb
```

Builds the image from the project environment without comparing anything first, which is how you force a rebuild after a failed one; `pxt db update` rebuilds only when that environment changed. The project files are uploaded with it, unless the database already has that exact archive. Polls until the build completes or fails; the pods restart on the new image and the new sources.

When a command reports an unsupported proxy protocol version and this Pixeltable is newer than the hosted database, run this rebuild against the database URI from the failed command. What that image installs is described in [What to run after a change](/cloud#what-to-run-after-a-change).

#### `pxt db delete`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt db delete pxt://myorg:mydb -f --json
```

Deletes the database, its storage, and all services. Irreversible.
Prompts for confirmation with `[y/N]` on a TTY; otherwise exits with code 3. Pass `-f` or `--force` to skip confirmation.

A database recreated under the same name is a different database: its workers are keyed by a new
internal id, so credentials for the old database no longer work. Treat a
delete followed by an `update` as a new deployment rather than a reset.

### `pxt org`

#### `pxt org list`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt org list
pxt org list --json
```

List all organizations accessible to the current credential.

#### `pxt org status`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt org status                   # only when your credential reaches exactly one org
pxt org status pxt://myorg       # name it when your credential reaches several
```

Show the organization's name, ID, and default database.

### `pxt key`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt key create NAME                       # a key that acts as you
pxt key create NAME --grant VERB:URI      # a scoped key that belongs to the org (preview); repeatable
pxt key list                              # every key in the org, and who created it
pxt key update NAME --grant VERB:URI      # add a grant
pxt key update NAME --revoke VERB:URI     # remove one
pxt key delete NAME                       # revoke the secret
```

`create` prints the secret once. `list` never does.

`update` is a delta, not a replacement, so widening a key does not depend on resending everything it
already had. Revoking a grant the key never had is an error rather than a no-op, since a typo would otherwise
read as a completed revocation. It applies only to a key that has grants: one that acts as
you has nothing to change.

Names are unique per organization across both shapes, so `pxt key delete NAME` never has to choose
between two keys. Any member of the organization can delete any key.

### `pxt secret`

```bash theme={"theme":{"light":"light-plus","dark":"dark-plus"}}
pxt secret list                    # every secret in your org and its databases
pxt secret list   pxt://myorg
pxt secret list   pxt://myorg:mydb
pxt secret set    pxt://myorg OPENAI_API_KEY=sk-...
pxt secret delete pxt://myorg:mydb OLD_KEY
```

An org secret applies to every database in the org. A database secret applies to that database and wins on a key collision. `list` prints names, never values.

`list` prints one table for the org and its databases. Without a URI it covers your credential's org; `pxt://myorg:mydb` narrows it to the org and that database. A database secret with the same name as an org secret is marked `overrides an organization secret`, and the org row stays in the table:

```
KEY                    SCOPE             NOTE
OPENAI_API_KEY         pxt://myorg
AWS_SECRET_ACCESS_KEY  pxt://myorg:mydb
OPENAI_API_KEY         pxt://myorg:mydb  overrides an organization secret
```

With `--json`, each row is an object with `key` and `scope`, plus `"overrides_org": true` on a database secret that overrides an org secret. With nothing set, `list` prints `No secrets for pxt://myorg.` (or the database's URI), and `list --json` prints `[]`.

`set` and `delete` print the keys they changed as the same `KEY` and `SCOPE` rows, without `NOTE`; with `--json`, as `key` and `scope` objects. Earlier releases printed bare key names, and `--json` printed an array of strings.

A running database or service uses the values from its startup. Run `pxt db restart` for the database's tables process and `pxt service restart` for each service. A database or service started afterwards reads the current value at startup.

<Warning>
  A `[[pixeltable.database]]` entry no longer accepts `secrets`. A project config that still has
  `secrets.openai_api_key = 'env:OPENAI_API_KEY'` fails to load:

  ```
  RequestError: Invalid `DatabaseConfig` in config file: pixeltable.toml
  secrets  Extra inputs are not permitted
  ```

  Delete the `secrets.*` lines and set each value with `pxt secret set` instead. The values were never
  stored in the file, so nothing is lost.
</Warning>

## What's next

* [Working with the Pixeltable CLI](/howto/cookbooks/core/working-with-cli): hands-on cookbook for inspect, query, debug, and serve workflows
* [HTTP Serving Guide](/howto/deployment/serving): TOML config reference, Python `FastAPIRouter` API, decorator routes
* [Configuration](/platform/configuration): API keys, storage paths, and environment settings


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.