Skip to content

CLI reference

Every command that reads configuration takes -c / --config FILE, which defaults to PRIVYX_CONFIG and then to the built-in defaults. See Configuration. privyx --version prints the version.

privyx proxy

Start the privacy proxy.

privyx proxy [-c FILE] [--host HOST] [--port PORT] [-u URL] [--transparent | --gateway] [--reload]
Option Description
--host Bind address. Default 127.0.0.1.
--port Bind port. Default 8000.
-u, --upstream Upstream provider URL. Wins over the config file.
--transparent / --gateway Forward every path to the upstream origin, or serve the chat-only gateway. Default: proxy.mode, which is transparent.
--reload Restart the server when the config file changes. For development; an in-memory vault starts empty after each restart.
--ssl-certfile, --ssl-keyfile Serve HTTPS with this certificate and key (PEM). Both are required.
--ssl-keyfile-password Password for an encrypted key.
--ssl-ca-certs CA bundle (PEM).

Besides the proxied paths, the server answers GET /health and GET /metrics (Prometheus text), neither of which needs a key.

On SIGTERM or Ctrl-C, and on a --reload restart, requests still running get 5 s to finish. Longer ones, such as a long streamed reply, are then cut off: the client sees the connection close, and their ephemeral sessions are deleted.

privyx run

Start a proxy on a local port, run a tool against it, and stop the proxy when the tool exits. The exit code is the tool's. The proxy follows proxy.mode, like privyx proxy. The transparent proxy (the default) relays the tool's own key or login unless Privyx has a key of its own (Configuration). It masks the chat paths in proxy.routes and forwards any other path unmasked, embeddings for instance; proxy.passthrough_unknown: false answers those with 403 instead. With proxy.mode: gateway in the config file, Privyx sends only its own key and posts to the upstream URL as written, which an upstream behind a base path needs. The tool owns the terminal, so Privyx writes no log lines to it; they go to log_file when one is set, which is where to look when a request fails with a 503. The tool usually runs in your project, so the audit trail goes to $XDG_STATE_HOME/privyx/audit.log (~/.local/state/privyx/audit.log) instead of the working directory, unless audit.path or PRIVYX_AUDIT_PATH sets it.

privyx run [OPTIONS] TARGET [ARGS]...
privyx run claude
privyx run claude -- --continue      # arguments after -- go to the tool
privyx run -u https://api.example.com --env-var MY_TOOL_BASE_URL -- my-tool --flag
Option Description
-p, --provider Provider type upstream (openai, anthropic, generic). Known targets set it for you.
-u, --upstream Upstream URL. The transparent proxy uses only its origin and appends the tool's own paths; the gateway posts to it as written. Default: the provider type's default.
--port Proxy port. 0 (default) picks a free one.
--env-var Also set this environment variable to the proxy URL. Repeatable.
--session-strategy ephemeral, client, or conversation (default). Overrides the config.
--no-anchor Do not create an anchor secret in ~/.config/privyx/anchor.key.
--list List the known targets and exit.

Known targets, and where each gets the proxy's URL:

Target Provider Proxy URL passed as
claude anthropic ANTHROPIC_BASE_URL, and the same variable in --settings, which outranks a base URL in Claude Code's own settings.json
codex openai -c openai_base_url=…/v1 (codex does not read OPENAI_BASE_URL), said again after your arguments when they hold a -c of their own, and OPENAI_BASE_URL
openai openai OPENAI_BASE_URL, ending in /v1 as the OpenAI SDK expects
aider openai OPENAI_API_BASE, OPENAI_BASE_URL, ending in /v1

Claude Code keeps only the last --settings: one of your own, after --, replaces Privyx's. Codex drops every -c given before a subcommand once one follows it (exec -c …), which is why Privyx repeats its own after your arguments. openai_base_url applies to codex's built-in openai provider: with a model_provider of your own in codex's config, codex does not reach Privyx. If your Claude Code settings point ANTHROPIC_BASE_URL at a router or another proxy, give that URL to privyx run as --upstream: Privyx now takes that place and forwards to its own upstream. If the tool exits without having sent Privyx a single request, privyx run warns: a tool that calls its provider directly is not masked.

Any other command runs too, given --env-var so Privyx knows how to point it at the proxy. The variable gets the proxy's URL with no path.

privyx detect

Show what the configured detector and policy find in a text.

privyx detect [-c FILE] [--transform] [--no-policy] TEXT...
echo "mail alice@example.com" | privyx detect --stdin
Option Description
--transform Also print the masked text.
--policy / --no-policy Apply the configured policy (default) or show every detection.
--stdin Read the text from standard input.

privyx mask

Replace sensitive values with tokens, reversibly. The output is what the proxy would send upstream.

privyx mask --map map.json "mail alice@example.com"
privyx mask --map map.json -i request.json --path '$.messages'
cat events.jsonl | privyx mask --map map.json -f jsonl -i - -o masked.jsonl
Option Description
--map FILE Read and write the mapping in this file. An existing file is extended, so tokens stay the same across documents.
--session ID Keep the mapping in this vault session instead. Needs a persistent vault.
-i, --input FILE Input file; - for standard input.
--stdin Read from standard input.
-o, --output FILE Output file. Default: standard output.
-f, --format auto (default, from the file extension), text, json, or jsonl.
--path Only mask under this JSON path, e.g. $.messages. Repeatable.

privyx unmask

Put the original values back, from a --map file or a --session. Tokens the mapping does not know are left as they are. Takes the same options as privyx mask.

privyx unmask --map map.json -i masked.txt

privyx session

List, show, and delete vault sessions. These need a sqlite or redis vault; see Sessions and vault.

privyx session list
privyx session show SESSION_ID [--reveal]
privyx session prune --older-than 7d [--dry-run]
Command Option Description
list Sessions, most recently active first, with mapping counts. Never shows values.
show --reveal Print original values in full. Without it they are masked.
prune --older-than Required. Delete sessions idle at least this long: 30m, 12h, 7d, 2w.
prune --dry-run List what would be deleted and delete nothing.

privyx inspect session SESSION_ID is an older name for privyx session show.

privyx audit

Read the audit trail. FILE defaults to audit.path; the trail of privyx run is in ~/.local/state/privyx/audit.log unless you set one.

privyx audit stats [FILE] [--since 24h]
privyx audit tail [FILE] [-n 20] [--no-follow]
Command Option Description
stats --since Only count events from the last 30m, 12h, 7d, 2w.
tail -n, --lines Recent events to show first. Default 10.
tail --follow / --no-follow Keep printing new events (default) or stop.

See Audit events for what each event holds.

privyx config

Show the configuration.

privyx config            # a summary
privyx config --show     # every setting as JSON, credentials masked
privyx config --path     # the config file in use, or "defaults"

privyx doctor

Build every configured component and push a request through it: plugins, detector, vault (a real write and read), provider, proxy, and streaming restore. Exits with a non-zero status if any check fails.

$ privyx doctor
Privyx Doctor
=============
  ✓ plugins: no plugin paths configured
  ✓ detector: regex: 1 span(s) ['EMAIL']
  ✓ vault: memory: round-trip ok
  ✓ provider: generic → http://localhost:20128
  ✓ proxy: request transformed, 1 mapping(s) vaulted
  ✓ streaming: pseudonym restored across a split chunk
  ✓ configuration: valid: detector=regex policy=default operator=pseudonym vault=memory anchor=off