Full reference for the paperctl CLI.
paperctl start
Launch a supported agent through the local proxy. paperctl start claude sets ANTHROPIC_BASE_URL; paperctl start codex configures Codex model providers for the local Paper proxy.
paperctl start [agent]
Supported agents are claude, codex, and pi:
paperctl start claude
paperctl start codex
paperctl start pi
Anything after -- is passed straight through to the agent, so paper’s own flags never collide with the agent’s:
paperctl start claude -- --dangerously-skip-permissions
| Flag | Description |
|---|---|
--gateway <name> |
Route only this launch through this gateway — never changes paperd’s primary gateway or daemon.toml |
--backend <name> |
Backend on the selected gateway; requires --gateway, and is required when the selection is ambiguous |
--label <name> |
Attach labels to the captured session (repeatable; give the flag before the agent name). Unknown names prompt on a TTY and otherwise require --create |
--create |
With --label, create any label that doesn’t exist yet |
paperctl start --label incident-2026-09 claude
paperctl start --gateway default --backend openai-managed codex
paperctl shell
Print Paper’s shell init script for bash, zsh, or fish. The script installs a claude function that wraps invocations through paperctl start claude, so plain claude always routes through the proxy.
eval "$(paperctl shell zsh)" # add to .zshrc
eval "$(paperctl shell bash)" # add to .bashrc
paperctl shell fish | source # add to config.fish
The installer offers to add this to your rc file on first install.
paperctl plugin
Install or remove a harness’s capture plugin — the setup that captures an app nobody launches from a terminal, outside a paperctl start launch.
paperctl plugin install codex-app [--dry-run] [--auth <chat-gpt|api-key-login|api-key>] [--config-path <path>]
paperctl plugin uninstall codex-app [--dry-run] [--config-path <path>]
paperctl plugin install codex-app points the ChatGPT desktop app, the IDE extension, and plain codex launches at paperd by reconciling Codex’s shared config — $CODEX_HOME/config.toml, or ~/.codex/config.toml when CODEX_HOME is unset — and delivering the Paper plugin the app loads. It updates only the values paper owns, preserves the rest of the file, and is safe to run repeatedly. Restart the ChatGPT app after it reports changes.
--dry-runprints what would be written without changing anything.--auth chat-gpt(default) keeps Codex’s own ChatGPT sign-in and writes no API key.--auth api-key-loginuses an API key Codex has saved (viacodex login --with-api-key).--auth api-keyroutes withOPENAI_API_KEYfrom the Codex process environment instead. The flag is also spelled--codex-auth, which is howtapesctl plugin installnames the same choice.--backendselects the backend segment in the API-key modes (defaultopenai-transparent).--config-pathinspects or repairs a specific config file, for standalone use or testing.
paperctl plugin uninstall codex-app reverses the install: the Paper provider declaration goes first, then the Paper-owned handoff files, then the extracted marketplace. Codex’s own cached copy of the plugin is left registered and the command to remove it is printed, since removing it by spec would also remove a copy you installed by hand. Unlike install, it runs even when daemon.toml is unparseable — a broken config is exactly when you reach for teardown.
The harness is an argument, not a verb, and its name resolves through the same registry tapesctl uses: codex-app and codex-desktop both work. Harnesses captured by redirection alone need no plugin and say so — for the terminal Codex CLI, use paperctl start codex.
See Capture the ChatGPT app for the walkthrough, including the two steps Codex gates on you inside the app.
paperctl init
Install paperd as a launchd agent (macOS) or systemd user unit and bring it up. Auto-discovers the default gateway and backend, and keeps a short-lived JWT warm so agents skip long-lived API keys.
paperctl init
paperctl init --dry-run
paperctl init --gateway my-gateway --backend my-backend
| Flag | Description |
|---|---|
--dry-run |
Print the install plan without writing to disk or shelling out to launchctl/systemctl |
--gateway <slug> |
Gateway slug paperd should route through, pre-selected as the primary in daemon.toml |
--backend <slug> |
Backend slug paperd should route through, scoped to the --gateway above |
--environment <env> |
Environment defaults bundle to bootstrap: production (default) or staging. Ignored when daemon.toml already exists |
paperctl status
Show the proxy address, auth health, current user, and org.
paperctl status
paperd: running (pid 2330)
proxy: 127.0.0.1:51539
auth: healthy (expires in 14m59s)
user: [email protected]
org: your-org
gateway: default
backend: ant-default
upstream: https://your-org.papercompute.run/
paperctl logs
Print recent paperd logs.
paperctl logs
paperctl logs -n 500
paperctl logs --follow
-n / --lines sets how many recent lines to show (default 100). -f / --follow streams new log lines as they arrive, like tail -f.
paperctl login
Open a browser for WorkOS auth. Re-run to switch accounts.
paperctl login
paperctl login --no-browser
--no-browser prints the verification URL instead of opening it — for SSH sessions and machines without a browser, open the URL from any device.
paperctl whoami
Show the currently logged-in identity.
paperctl whoami
paperctl whoami --json
--json emits JSON instead of a human summary — handy for scripts.
paperctl logout
Clear daemon-owned credentials. Run paperctl login to sign back in.
paperctl logout
paperctl org
Manage organization context.
To add a teammate, invite them by email from Settings → Team in paper console. They accept, run paperctl login, and land in the org with the default gateway already discovered — that’s the whole flow, it works whether or not they have a paper account yet, and all you need to know about them is their email address.
paperctl org membership add also exists, but it is not a shortcut to that flow — today it takes a WorkOS user id (the internal user_01ABC… identifier behind a paper account), not an email. If you need one: the teammate can send you theirs by running paperctl whoami — or skip the id entirely by adding them via email in the console. Two more requirements before you reach for the command:
- You must be an admin of the target org. Members get a bare
HTTP 403— that’s the permission error, not a syntax problem. - Pass
--org-slugexplicitly. The command does not use your active org, so without the flag it fails withno org slug configured— and the error’s suggestion to runpaperctl org selectdoesn’t currently help. Find the slug withpaperctl org list.
New members join as member; --role admin grants admin:
paperctl org membership add <workos-user-id> --org-slug <org-slug>
paperctl org membership add <workos-user-id> --org-slug <org-slug> --role admin
List your orgs with paperctl org list, and create one from the CLI with paperctl org create (prompts for a display name if --name is omitted):
paperctl org list
paperctl org create --name "Acme Robotics"
Use paperctl org select when you belong to more than one org and need to choose which gateway paper routes through. Bare org select lists your orgs and prompts; pass an org id, slug, or display name to skip the prompt:
paperctl org select
paperctl org select <org-slug>
The new selection takes effect the next time paperctl starts. If it’s already running, restart it:
paperctl init
paperctl show
Show the active organization, or a specific org by slug.
paperctl show
paperctl show your-org
paperctl search
Semantic search over your recorded sessions. Embeds the query and returns the matched turns, most-relevant first, matched by meaning, not exact keywords.
paperctl search "why did the deploy fail"
paperctl search "auth error" -k 20 # up to 20 matches (default 8)
paperctl search "auth error" --label incident-2026-09
paperctl search "auth error" --json # raw JSON for scripts
-k / --top caps how many matched turns come back (default 8). --label <name> (repeatable) restricts results to sessions carrying that label — note that the deployed search service does not yet apply this filter consistently, so results can include sessions outside the label; when the label boundary matters, cross-check with paperctl sessions list --label, which filters reliably. --json emits the raw result list instead of the styled output.
paperctl sessions
List, inspect, and export the sessions captured for the active org.
paperctl sessions list # most recent first
paperctl sessions get <session-id>
paperctl sessions export <session-id> --out session.ndjson
List
paperctl sessions list --limit 50 --sort total_cost_usd --direction desc
paperctl sessions list --since 2026-07-01T00:00:00Z --auth-subject <user-id>
paperctl sessions list --json
| Flag | Description |
|---|---|
--limit <n> |
Max rows to return (server default 50, max 200) |
--sort <col> |
last_active, started_at, turn_count, total_cost_usd, total_tokens, duration_ns, derived_status, or auth_subject |
--direction <dir> |
asc or desc |
--since / --until |
Bound to sessions active in an RFC3339 time window |
--auth-subject <id> |
Scope to a single user, by WorkOS user id (your own is the user_… line in paperctl whoami) |
--label <name> |
Only sessions carrying this label; repeatable, and repeated labels are ANDed |
--harness-session-id <id> + --harness-id <harness> |
Find the session captured from a specific harness session (the id start prints); the two flags are a pair |
--cursor <cursor> |
Opaque pagination cursor from a previous response |
--json |
Emit the raw JSON response instead of formatted rows |
Get
paperctl sessions get <session-id>
paperctl sessions get <session-id> --json
Export
Export sessions as NDJSON to a file (--out) or stdout.
paperctl sessions export <session-id> --out session.ndjson
paperctl sessions export --since 2026-07-01T00:00:00Z --until 2026-07-15T00:00:00Z
paperctl sessions export --all --out all.ndjson
Export scope is required: pass a session ID, a --since/--until window, or --all. A bare export is rejected so it never dumps everything by accident. --all exports every session, which the server clamps to a trailing 30 days. Use --detail traces for full trace/span granularity (the default is spans, one span-level record per turn).
paperctl skill
Browse, generate, and sync your organization’s skills.
paperctl skill list
paperctl skill generate <session-id> --name 'Release Runbook'
paperctl skill status <generation-id>
paperctl skill sync <slug>
List
paperctl skill list # every skill in your org's library, with slugs
paperctl skill list --query release # only skills matching "release"
| Flag | Description |
|---|---|
--query <text> |
Filter to skills matching the text |
--limit <n> |
Max skills to return (default 24) |
--json |
Emit the raw list instead of the styled output |
Generate
Queue a skill generation from one or more recorded sessions. Generation runs server-side (LLM-backed); the result lands as a new private revision of the skill named by --name — nothing is published by generating.
paperctl skill generate <session-id> --name 'Release Runbook'
paperctl skill generate <session-id> <session-id> --name 'Release Runbook' --wait
| Flag | Description |
|---|---|
--name <name> |
Required. The skill the generation targets — its slug names the stable skill, created on first use |
--type <type> |
workflow (default), domain-knowledge, or prompt-template |
--base-revision <id> |
Build on an existing revision of the same skill instead of starting from nothing |
--wait |
Poll until the generation settles (completed, failed, or canceled) |
--json |
Emit the raw summary instead of the styled output |
Without --wait, the command prints a generation id you can check later:
Status
paperctl skill status <generation-id>
Sync
Write a skill’s rendered SKILL.md to a local skills directory as <skills-dir>/<slug>/SKILL.md. Re-running the same command overwrites with the skill’s current content — sync is also the update path. See Install a Skill for the workflow.
paperctl skill sync <slug>
paperctl skill sync <slug> --claude --dry-run
The argument is a skill slug (exact match) or a skill id (prefix match).
| Flag | Description |
|---|---|
--claude |
Write to .claude/skills (for Claude Code) instead of .agents/skills |
--local |
Write under ./ instead of the home directory |
--dry-run |
Print the resolved target directory; write nothing |
paperctl label
Manage labels and attach them to sessions. Labels are shared, org-wide names you use to group sessions — see Organize sessions with labels for the workflow.
paperctl label list
paperctl label create <name> [--color '#RRGGBB'] [--description <text>]
paperctl label rename <name> <new-name>
paperctl label delete <name> [--force]
paperctl label add <session-id> <name>... [--create]
paperctl label rm <session-id> <name>...
createstores the display name verbatim (emoji included); the server enforces uniqueness on a case-folded key and assigns a color when none is given.addattaches labels by name and never creates one implicitly — unknown names prompt on a TTY, and otherwise require--create.renamekeeps every attachment;rmdetaches from one session without deleting the label;deleteremoves the label and every attachment it has, and asks for confirmation unless--force.
paperctl tapes
Create, inspect, and manage tapes AI gateway instances and their LLM backends.
paperctl tapes create
paperctl tapes gateway
paperctl tapes backend
Bootstrap interactively
Use paperctl tapes create when an org has no default gateway, or when you want to provision a second one:
paperctl tapes create
Manage gateways
| Subcommand | Description |
|---|---|
paperctl tapes gateway create |
Create a new gateway |
paperctl tapes gateway list |
List gateways |
paperctl tapes gateway get |
Get gateway details |
paperctl tapes gateway delete |
Delete a gateway |
paperctl tapes gateway use |
Mark a gateway as the primary one paperd routes through |
Manage backends
Backends are scoped to a gateway — every command takes --gateway [name].
| Subcommand | Description |
|---|---|
paperctl tapes backend create |
Create a backend |
paperctl tapes backend list |
List backends |
paperctl tapes backend get |
Get backend details |
paperctl tapes backend delete |
Delete a backend |
paperctl tapes backend use |
Mark a backend (and its gateway) as primary |
For Codex routing and custom backend shapes, see Backends and providers.
paperctl cassettes
Call cassette methods served by your tapes deployment. Cassettes are API extensions your deployment serves under /v1/cassettes — search, labels, export, skills, and others already have first-class commands above, which is what you want day to day. paperctl cassettes is the direct surface: it discovers whatever your deployment actually serves at runtime and exposes each method as a subcommand. paperd must be running for discovery and calls.
paperctl cassettes --help # lists what your deployment serves
paperctl doctor
Check and repair the Paper installation: daemon, login, organization, and route. Prompts only where a choice is needed.
paperctl doctor
It also checks the install itself: if the directory containing the running binary is missing from PATH, or a stale pre-rename paper binary earlier in PATH shadows the new one, doctor names the problem and prints the exact command to fix it.
paperctl configure
Review and change Paper settings interactively. Runs the paperctl doctor checks first, then opens a settings menu.
paperctl configure
paperctl menu
Manage the menu-bar / system-tray app. Bare paperctl menu runs it in the foreground (same as paperctl menu run).
paperctl menu install
paperctl menu run
paperctl menu uninstall
paperctl menu install is the recommended setup — it installs a launchd agent (macOS) so the menu auto-starts on login and survives reboots. Picking Quit from the menu keeps it quit until the next login. paperctl menu uninstall stops the agent and removes it.
paperctl upgrade
Upgrade paperctl in place: download the requested build, verify its published checksum, atomically replace the binary, and restart paperd. With no flags it installs the newest release, and exits successfully without downloading when you’re already up to date.
paperctl upgrade
paperctl upgrade --version v0.33.0
paperctl upgrade --nightly
--version pins an exact release — older versions are allowed, so a bad release has an escape hatch. --nightly installs the rolling nightly build instead of a release.
The command is upgrade, not update, on purpose: upgrade means “replace the binary with another build”, and update is reserved for possible future semantics.
paperctl version
Print version information.
paperctl version
paperctl uninstall
Completely remove paperd and all local Paper state — the supervisor unit, control socket, credentials, daemon config, and logs — as if Paper was never installed.
paperctl uninstall
The command prompts for confirmation before removing anything; -y / --yes skips the prompt for scripted removal.
To start again, run paperctl init and paperctl login.
Configuration
org context
Which organization paper routes through. Auto-selected on paperctl login if you belong to one; choose with paperctl org select if you belong to multiple. View with paperctl status.
gateway context
Which tapes AI gateway paper routes inference through. Auto-discovered from the org default on paperctl init; manage with paperctl tapes gateway.
backend context
A backend is one route from a gateway to a single upstream model provider, defined by a schema (Anthropic, OpenAI, AzureOpenAI, ChatGPTCodex), the upstream host, an auth mode, and a model allowlist. The active gateway routes to its primary backend; one is provisioned alongside the gateway by default. Manage backends with paperctl tapes backend.
Codex backend routes
Codex uses explicit Paper route prefixes instead of the primary backend route:
- ChatGPT passthrough auth routes through
/v1/openai-chatgpt/chatgpt-codex. - OpenAI API-key auth routes through
/v1/openai-responses/<backend>/v1.
These routes are provisioned by default, so paperctl start codex works with no setup; see Backends and providers to customize them or set a shared team key.
ANTHROPIC_BASE_URL
Environment variable Claude Code reads to find an alternate API endpoint. paperctl start claude sets it automatically for the launched process. To wire it up yourself, copy the proxy address from paperctl status and export it:
export ANTHROPIC_BASE_URL=http://127.0.0.1:51539
The proxy address comes from daemon configuration and stays the same across restarts (127.0.0.1:51539 by default). Still prefer paperctl start claude — or add eval "$(paperctl shell zsh)" (or the bash/fish equivalent) to your shell rc — so the address is resolved for you instead of hand-managed.
config location
Credentials and local state live in ~/.config/paper/. Removing this directory wipes your login — running paperctl login again recreates it.
Global flags and environment variables
Every command accepts a small set of per-invocation overrides; each also reads a matching environment variable. None of them persist anything — they scope a single command.
| Flag | Env var | Description |
|---|---|---|
--org-slug <slug> |
PAPER_ORG_SLUG |
Act against this org without re-running paperctl org select |
--gateway-id <id> |
PAPER_GATEWAY_ID |
Scope a tapes subcommand to a non-primary gateway |
--environment <env> |
PAPER_ENVIRONMENT |
Defaults bundle: production (default) or staging |
--disable-telemetry |
PAPER_DISABLE_TELEMETRY |
Disable telemetry events for this invocation |