Skip to content

CLI Reference

pizzapi [command] [options]

When called without a command, pizzapi starts an interactive coding session and streams it to the configured relay server.

Run pizzapi --help for a quick summary of all commands:

πŸ• PizzaPi v0.5.4
Commands:
pizza Start an interactive agent session
pizza local [flags] Start local relay + runner in one command
pizza web [flags] Manage the PizzaPi web hub (Docker)
pizza runner [args] Manage the background runner daemon
pizza runner stop Stop the runner daemon
pizza runner status [--json] Health check the runner daemon (exit 0 = healthy)
pizza runner pair [--force] Pair (or re-pair) the runner with a fresh API key
pizza setup Run first-time setup
pizza usage [provider] Show API usage stats
pizza models List available models
pizza plugins [cmd] Manage Claude Code plugins (list/trust/marketplace/install)
pizza install <source> Install a pi package (extensions, skills, prompts, themes)
pizza remove <source> Remove an installed pi package
pizza update [source|self] Update installed pi packages
pizza list List installed pi packages
pizza config Enable/disable package resources
Flags:
--cwd <path> Set working directory
--sandbox <mode> Set sandbox mode: enforce, audit, or off
--safe-mode Skip MCP, plugins, hooks, and relay
--no-mcp Skip MCP server connections
--no-plugins Skip Claude Code plugin loading
--no-hooks Skip hook execution
--no-relay Skip relay server connection
-v, --version Show version
-h, --help Show this help
Run pizza <command> --help for command-specific help.

Start an interactive pi coding session and relay it to the web UI.

Terminal window
pizzapi
pizzapi --cwd /path/to/project
pizzapi --safe-mode # Skip MCP, plugins, hooks, relay
pizzapi --no-mcp # Skip only MCP servers
FlagDescription
--cwd <path>Working directory for the session (default: current directory)
--safe-modeSkip all external dependencies (MCP, plugins, hooks, relay) for instant startup
--no-mcpSkip MCP server connections only
--no-pluginsSkip Claude Code plugin discovery and loading
--no-hooksSkip all hook execution
--no-relaySkip relay server connection
--sandbox <mode>Set sandbox mode: enforce, audit, or off. See Agent Sandbox.

Each --no-* flag also has a PIZZAPI_NO_*=1 environment-variable equivalent (PIZZAPI_NO_MCP, PIZZAPI_NO_PLUGINS, PIZZAPI_NO_HOOKS, PIZZAPI_NO_RELAY, and PIZZAPI_NO_SANDBOX for --sandbox=off).

The session ID is derived from the runner configuration and displayed on startup. Open the relay server’s web UI to watch the session live.

If no API key is configured and the relay is not disabled, the CLI will automatically launch the setup wizard before starting the session.

MCP servers are initialized in parallel with per-server timeouts (default: 30 seconds). If a server doesn’t respond in time, it’s skipped and an error is shown.

When startup takes longer than 5 seconds, a warning is displayed in both the TUI and web UI showing which servers were slow. You can disable this warning by setting "slowStartupWarning": false in your config.


Start the local relay, web UI, and runner in one command. This is the fastest way to get a self-hosted PizzaPi running on your own machine.

Terminal window
pizzapi local
pizzapi local --port 8080
pizzapi local --no-browser

What it does:

  1. Starts the local relay + web UI via pizza web (Docker Compose) if it is not already healthy.
  2. Runs the first-time setup wizard if no API key for the local relay is saved.
  3. Opens the browser to the local UI (unless --no-browser is passed).
  4. Starts the runner in the foreground.

Process ownership:

  • The relay is managed by Docker / pizza web. It keeps running after this command exits; stop it with pizza web stop.
  • The runner is owned by this command. Press Ctrl+C to stop the runner. No orphan daemon is left behind.

Re-running pizzapi local is safe and idempotent: an already-healthy relay is reused, an already-running runner is reported, and an existing local API key is preserved.

FlagDescription
--port <number>Relay port (default: 7492)
--no-browserPrint the UI URL instead of opening the browser
-h, --helpShow help

Run (or re-run) the first-time setup wizard. Prompts for the relay server URL, your name (optional), email, and password, then saves the API key to ~/.pizzapi/config.json.

Terminal window
pizzapi setup

Enroll a new PC by QR code instead of typing credentials. The CLI prompts for the relay URL, prints a terminal QR code, and polls for approval. Scan the QR code from an authenticated PizzaPi web browser (or open the printed URL) and tap Allow Camera & Scan to approve the device.

Terminal window
pizzapi setup --scan

The claim expires after 10 minutes. Once approved, the CLI receives an API key and writes ~/.pizzapi/config.json automatically.


Start the headless runner daemon. The daemon registers with the relay server and waits for session-spawn requests from the web UI or from agents using the spawn_session tool.

Terminal window
# Start the runner (foreground)
pizzapi runner
# Start the runner in the background
pizzapi runner &
# Stop a running daemon
pizzapi runner stop

See the Runner Daemon guide for detailed usage.


Send a stop signal to the currently running runner daemon.

Terminal window
pizzapi runner stop

Health check for the runner daemon β€” answers β€œis this runner alive and registered with the relay?” by combining a PID liveness check with the daemon’s last-known relay connection state. Fast and dependency-light: no relay round-trip, no config/model loading.

Terminal window
pizzapi runner status # human-readable summary
pizzapi runner status --json # machine-readable, for scripting/monitoring

Exit code: 0 if healthy (process running and connected: true), 1 otherwise.

--json prints:

{
"healthy": true,
"runnerId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"runnerName": "docker-runner",
"relayUrl": "https://pizza.example.com",
"connected": true,
"pid": 12345,
"startedAt": "2025-01-15T10:30:00.000Z",
"cliVersion": "0.5.61"
}
FieldPresent whenDescription
healthyalwaystrue only if the process is alive and connected is true
reasonunhealthy"no runner state file found", "pairing pending β€” approve at <url>" (auto-pairing is waiting on approval), "process not running", "relay rejected credentials β€” check PIZZAPI_API_KEY / re-pair" (the relay rejected the key β€” distinct from an ordinary connectivity problem), or "not registered with relay"
pairingUrlpairing pendingThe approval URL to open, when reason is a pending-pairing message
runnerId, runnerName, relayUrl, cliVersionstate file existsCopied from ~/.pizzapi/runner.json
connectedalwaysWhether the daemon’s last-known state is registered with the relay
pida pid was recordedThe daemon process’s own PID (not the supervisor’s)
startedAtstate file existsISO timestamp of the daemon’s last start

This is the command the runner container image’s Docker HEALTHCHECK runs.


Mint a fresh headless-paired API key on demand β€” the same device-claim flow the daemon runs automatically on a credential-less boot (Runner Container β†’ Credentials), but invokable any time. Useful after revoking a runner’s key in the web UI, instead of hand-editing the data volume.

Terminal window
pizzapi runner pair # refuses if a credential already resolves
pizzapi runner pair --force # pairs and overwrites any existing credential

Prints an approval URL + QR code (re-printed periodically while waiting), polls until approved or expired, then writes apiKey/relayUrl into config.json in the resolved agent dir, replacing only those two fields.

Exit code: 0 on a successful pair. Non-zero if refused, if the claim expires, or on any pairing failure.

Two guard rails, both bypassed only with --force:

  • Refuses to clobber an existing credential. If an API key already resolves (env var or config.json), it prints where it came from (never the key itself) and exits non-zero telling you to re-run with --force.
  • Refuses when an env var would shadow the result. The runtime resolution order is PIZZAPI_RUNNER_API_KEY β†’ PIZZAPI_API_KEY β†’ PIZZAPI_API_TOKEN β†’ config apiKey. If any of those three env vars is set, a freshly paired key written to config.json would be silently ignored at runtime β€” pairing would β€œsucceed” while nothing actually changes. This refuses outright by default (naming the offending variable and telling you to unset it) rather than just warning, because a warning line is easy to miss when the operator is scanning for a success message. Even with --force, the same warning still prints before proceeding, since forcing past the refusal doesn’t make the shadow go away.

If a runner daemon is already running when pairing succeeds, the daemon keeps using its old credential in memory β€” the command prints a reminder to restart it (pizzapi runner stop then start again, or docker restart <container>) rather than restarting anything itself.

If no relay URL is known (neither PIZZAPI_RELAY_URL nor a configured one), it fails immediately with an actionable message β€” it never prompts or guesses a default.


Start the PizzaPi web hub (relay server + web UI) using Docker Compose. This is the easiest way to self-host the relay β€” no need to clone the repo or configure Docker manually.

Run pizzapi web --help for the full usage:

pizza web β€” Manage the PizzaPi web hub (server + UI via Docker Compose)
Commands:
pizza web [flags] Start the web hub
pizza web stop Stop the web hub
pizza web logs Tail container logs
pizza web status Show container status
pizza web config Show current configuration
pizza web config set <k> <v> Update a config value
Flags:
--port <port> Set the host port (persisted to config.json)
--origins <list> Set extra allowed CORS origins (comma-separated, persisted)
--tag <tag> UI image tag from GHCR (default: CLI version, or latest)
--build Build UI locally (fallback mode)
--dev-ui Use the local dev UI (local repo only)
-f, --foreground Run in the foreground (don't detach)
--no-cache Rebuild Docker image without layer cache
-h, --help Show this help
Configuration (~/.pizzapi/web/config.json):
port Host port (default: 7492)
vapidSubject VAPID subject for push notifications
extraOrigins Extra CORS origins, comma-separated
Examples:
pizza web Start on default port 7492
pizza web --tag main Pull ghcr.io/pizzaface/pizzapi-ui:main
pizza web --build Build UI locally (fallback mode)
pizza web --dev-ui Use local dev UI (local repo only)
pizza web --port 8080 Start on port 8080 (remembered for next time)
pizza web config set port 9000 Change port without starting
pizza web config set extraOrigins "https://example.com"

--dev-ui runs the local dev UI stack from a repo checkout (the server plus dev:ui on port 5173). --build uses the local-build fallback mode. PREBUILT_UI is a Docker build arg that pizza web sets automatically based on the host prebuild state.

Terminal window
# Start on the default port (7492)
pizzapi web
# Start on a custom port (persisted for future runs)
pizzapi web --port 8080
# Set extra CORS origins (persisted)
pizzapi web --origins "https://example.com,https://other.com"
# Pull a specific GHCR UI tag
pizzapi web --tag main
# Build the UI locally (fallback mode)
pizzapi web --build
# Run the local dev UI stack (repo checkout only)
pizzapi web --dev-ui
# Run in the foreground (don't detach)
pizzapi web --foreground
# Management
pizzapi web stop
pizzapi web logs
pizzapi web status
SubcommandDescription
(none)Build and start the relay server + web UI
stopStop the running web hub
logsTail the container logs
statusShow running container status
configShow current configuration from config.json
config set <key> <value>Update a config value (see below)
FlagDescription
--port <number>HTTP port to expose (default: 7492). Persisted to config.json.
--origins <list>Extra CORS origins, comma-separated. Persisted to config.json.
--tag <tag>UI image tag to pull from ghcr.io/pizzaface/pizzapi-ui (default: CLI version, or latest).
--buildBuild UI locally instead of pulling GHCR image (fallback mode).
--dev-uiRun the local dev UI stack from a repo checkout.
--foreground, -fRun in the foreground instead of detaching
--no-cacheRebuild Docker image without layer cache
--help, -hShow help

View the current web hub configuration:

Terminal window
pizzapi web config

Update a configuration value. Changes are saved to ~/.pizzapi/web/config.json and take effect on the next pizza web start.

Terminal window
pizzapi web config set port 9000
pizzapi web config set extraOrigins "https://example.com"
pizzapi web config set vapidSubject "mailto:ops@example.com"
KeyDefaultDescription
port7492Host port to expose the web UI on
vapidSubjectmailto:admin@pizzapi.localVAPID subject for web push notifications
extraOrigins(none)Extra allowed CORS origins, comma-separated

All settings and persistent data are stored in ~/.pizzapi/web/:

FilePurpose
config.jsonAll web hub settings (port, VAPID keys, origins, etc.)
compose.ymlAuto-generated Docker Compose config (regenerated each run)
host-build.jsonHost UI pre-build cache state
compose.override.ymlOptional Docker Compose override (PizzaPi includes it automatically if present)

VAPID keys for push notifications are generated on first run and stored in config.json. They persist across restarts and config changes β€” push notification subscriptions won’t break.


Show API usage and quota information for your authenticated providers.

Terminal window
# Show usage for all providers
pizzapi usage
# Filter to a specific provider
pizzapi usage anthropic
pizzapi usage gemini
# Machine-readable JSON output
pizzapi usage --json

For Anthropic OAuth subscriptions, the command fetches quota utilization from the Anthropic API:

Claude usage (OAuth subscription)
──────────────────────────────────────────────────────
5-hour window 12.3% (resets 2/24/2026, 2:15:00 PM)
7-day window 8.1% (resets 3/1/2026, 9:00:00 AM)
7-day (OAuth apps) 4.2% (resets 3/1/2026, 9:00:00 AM)
7-day (Opus) 2.0% (resets 3/1/2026, 9:00:00 AM)
7-day (Sonnet) 6.5% (resets 3/1/2026, 9:00:00 AM)
7-day (co-work) 3.0% (resets 3/1/2026, 9:00:00 AM)
Extra usage enabled
Monthly limit: $100
Credits used: $12.34
Utilization: 12.3%

For Gemini OAuth credentials, the command fetches quota buckets from the Google Cloud Code Assist endpoint:

Gemini usage (Google Cloud Code Assist, OAuth)
Project: my-project-123
──────────────────────────────────────────────────────
INPUT / gemini-2.5-pro 85.0% remaining (850 left) resets 3/1/2026, 12:00:00 AM
OUTPUT / gemini-2.5-pro 92.3% remaining (923 left) resets 3/1/2026, 12:00:00 AM

List all AI models available through the configured providers.

Terminal window
# Human-readable table
pizzapi models
# Machine-readable JSON
pizzapi models --json

Example output:

anthropic
claude-opus-4-5 reasoning β€’ 200,000 ctx β€’ Claude Opus 4.5
claude-sonnet-4-20250514 200,000 ctx β€’ Claude Sonnet 4
google
gemini-2.5-pro reasoning β€’ 1,000,000 ctx β€’ Gemini 2.5 Pro
ollama-cloud
glm-5.1 reasoning β€’ 202,752 ctx β€’ GLM 5.1

Discover and manage Claude Code plugins. PizzaPi can load plugins designed for Claude Code β€” their commands become slash commands, hooks map to pi lifecycle events, and skills are shared via the Agent Skills standard.

Terminal window
# List all discovered plugins (global + project-local)
pizzapi plugins
# Trust all untrusted local plugins in the current project
pizzapi plugins trust
# Trust a specific plugin directory
pizzapi plugins trust /path/to/plugin
# Remove a plugin from the trust list
pizzapi plugins untrust /path/to/plugin
# Clear the entire trust list
pizzapi plugins untrust
# Show the current trust list
pizzapi plugins trusted
# Show help
pizzapi plugins --help
SubcommandDescription
(none) / listList all discovered plugins with trust status
trust [path]Trust project-local plugins. No path = trust all untrusted in cwd.
untrust [path]Remove from trust list. No path = clear entire list.
trustedShow the current trust list from ~/.pizzapi/config.json
marketplace add <source>Add a marketplace (owner/repo, git URL, or local path)
marketplace listList registered marketplaces
marketplace show <name>List a marketplace’s plugins
marketplace remove <name>Remove a marketplace and its clone
install <name[@marketplace]>Install and enable a plugin from a marketplace
uninstall <name[@marketplace]>Remove an installed plugin
enable / disable <name[@marketplace]>Toggle a plugin without uninstalling
installedList marketplace-installed plugins and their enabled state

Marketplace state is shared with Claude Code (~/.claude/plugins/). The same operations are available inside a session via the /plugin command, which also reloads session resources so a newly installed plugin is usable right away.

Trust model:

  • Global plugins in ~/.pizzapi/plugins/ and ~/.agents/plugins/ are always auto-trusted β€” same as global skills or extensions. Claude Code marketplace plugins installed via ~/.claude/plugins/installed_plugins.json are discovered through that manifest, not by scanning ~/.claude/plugins/ directly.
  • Project-local plugins in .pizzapi/plugins/, .agents/plugins/, or .claude/plugins/ under your project directory can execute shell commands via hooks. They require explicit trust before loading.

There are three ways to trust a local plugin:

  1. CLI: pizza plugins trust (pre-approve before starting a session)
  2. TUI: Interactive confirmation dialog at session start
  3. Web UI: Amber trust banner with Trust & Load / Skip buttons

Once approved by any method, the trust is persisted to ~/.pizzapi/config.json so future sessions auto-load without re-prompting.


pizzapi install, pizzapi remove, pizzapi update, pizzapi list, pizzapi config

Section titled β€œpizzapi install, pizzapi remove, pizzapi update, pizzapi list, pizzapi config”

Install, update, and manage pi packages β€” bundles of extensions, skills, prompt templates, and themes that extend the agent. These commands inherit the upstream pi package manager and store packages in ~/.pizzapi/settings.json (or .pizzapi/settings.json for project-local installs).

Terminal window
# Install a package from npm, git, or a local path
pizzapi install npm:@foo/pi-tools
pizzapi install git:github.com/user/repo
pizzapi install ./local/path
# Install into the current project only
pizzapi install npm:@foo/pi-tools -l
# Remove a package
pizzapi remove npm:@foo/pi-tools
pizzapi uninstall npm:@foo/pi-tools # alias for remove
# List installed packages
pizzapi list
# Update installed packages
pizzapi update --extensions
# Update everything (pi packages only; PizzaPi itself is updated via npm)
pizzapi update
# Interactively enable/disable package resources
pizzapi config
CommandDescription
install <source> [-l]Install a package and add it to settings
remove <source> [-l]Remove a package from settings
uninstall <source> [-l]Alias for remove
update [source|self|pi]Update installed packages (self forms print a note and exit; use npm install -g @pizzapi/pizza to update the wrapper)
update --extensionsUpdate installed packages only
update --selfPrint a note and exit; self-update is disabled
listList installed packages
configInteractively enable or disable package resources

All package commands accept -a/--approve, -na/--no-approve, and --cwd <path>. update additionally accepts --force and --extension <source>.

These commands accept --cwd <path> to target a different project directory and honor agentDir from ~/.pizzapi/config.json.


Print the installed version number and exit.

Terminal window
pizzapi --version
# pizzapi v1.2.3

PizzaPi registers several tools that are available in every agent session:

ToolDescription
spawn_sessionSpawn an independent linked child session on the runner
list_modelsList available models and providers
set_session_nameSet the session display name
update_todoUpdate the session’s todo list
subagentDelegate tasks to specialized subagents with isolated context

Delegate tasks to specialized agents in isolated in-process sessions. The tool returns immediately; each result is automatically delivered as a follow-up message when ready, so the parent can keep working without polling.

Modes:

  • Single: { agent: "name", task: "..." } β€” invoke one agent
  • Parallel: { tasks: [...] } β€” run up to 8 agents concurrently, with at most 4 at once
  • Chain: { chain: [...] } β€” sequential execution with {previous} output substitution

Agent definitions are loaded from ~/.pizzapi/agents/*.md (user scope), ~/.claude/agents/*.md (user backward-compat), .pizzapi/agents/*.md (project scope), and .claude/agents/*.md (project backward-compat). Use agentScope: "both" (or "project") to include project-local definitions.

See the Subagents guide for full documentation.


FlagDescription
--help, -hShow help and exit
--version, -vPrint version and exit
--cwd <path>Override working directory (applies to the default session command)

These commands are used internally by the daemon and should not be called directly:

CommandDescription
pizzapi _daemonInternal daemon entrypoint (spawned by the supervisor)
pizzapi _workerInternal worker entrypoint (spawned by the daemon for each session)
pizzapi _terminal-workerInternal terminal PTY worker (spawned by the daemon for terminal sessions)