CLI reference

Every launchsafe-firewall command and option

Edit on GitHub

Every command parses its arguments against a declared spec before anything runs:

  • --help or -h anywhere (before --) prints that command's help and exits 0 without side effects.
  • An unknown flag, a missing value, a bad choice or a surplus argument exits 64 with one line on stderr and changes nothing.
  • hook never exits 64: a malformed hook command exits 2, which blocks the tool (fail closed).
  • Commands marked changes state are refused when an agent runs them (FW-TAMPER) and, under the test marker, refuse to write under the real home directory.

Commands that need the approval passphrase ask for it in your own terminal. Never type it into an agent.

install

Register the firewall's hooks in an agent's settings (Claude Code, Codex, Gemini CLI, Cursor). Changes state.

launchsafe-firewall install [--agent claude|codex|gemini|cursor] [--scope user|project|local] [--project DIR] [--no-approver]
launchsafe-firewall install --agent gemini --seatbelt PROFILE [--gemini-package DIR] [--scope user|project] [--project DIR] [--no-approver]
launchsafe-firewall install --managed [--agent claude|codex|gemini|cursor] [--lock-other-hooks] [--print]
  • --agent claude|codex|gemini|cursor: which agent's settings (default claude).
  • --scope user|project|local: which settings file (Codex, Gemini CLI and Cursor: user or project).
  • --project DIR: the project directory (default: the current directory).
  • --managed: print managed settings for an administrator to deploy.
  • --lock-other-hooks: with --managed, also set allowManagedHooksOnly.
  • --print: with --managed, print the JSON only.
  • --no-approver: do not offer to set an approval passphrase.
  • --seatbelt permissive-open|permissive-proxied|restrictive-open|restrictive-proxied|strict-open|strict-proxied: with --agent gemini, macOS: also write ~/.gemini/sandbox-macos-launchsafe.sb, Gemini CLI's own profile plus write access to the hook's state directories only, for gemini -s with SEATBELT_PROFILE=launchsafe (permissive-open is Gemini CLI's default).
  • --gemini-package DIR: with --seatbelt, Gemini CLI's package (or its bundle directory) to copy the profile from (default: found from the gemini command on PATH).

uninstall

Remove the firewall's hooks (needs the approval passphrase). Changes state.

launchsafe-firewall uninstall [--agent claude|codex|gemini|cursor] [--scope user|project|local] [--project DIR] [--restore-backup [--force]] [--remove-sandbox] [--purge]
  • --agent, --scope, --project: as for install.
  • --restore-backup: put each settings file back exactly as it was before the first install (a file install created is removed; the current file is saved as FILE.before-restore.TIMESTAMP first; settings you changed since install are listed and need a yes or --force; this also removes a sandbox profile doctor --fix added).
  • --force: with --restore-backup, discard settings you changed since install without asking (the file as it is now is still saved beside it first).
  • --remove-sandbox: also remove the sandbox profile doctor --fix installed (it is kept otherwise).
  • --purge: also delete the firewall's state directory.

doctor

Check that the firewall is actually protecting this machine. Does not change state on its own.

launchsafe-firewall doctor [--json] [--project DIR]
launchsafe-firewall doctor --fix [--scope user|project|local] [--dry-run] [--project DIR]
launchsafe-firewall doctor --repair-state [--project DIR]
  • --json: print JSON.
  • --project DIR: the project directory (default: the current directory).
  • --fix: offer fixes after showing each change: Claude Code's sandbox profile from your policy (needs the approval passphrase), pinning the approval key in the hook, a package cooldown in your user config, downloading malicious-package data.
  • --scope user|project|local: with --fix, which Claude Code settings file gets the sandbox profile (default: user).
  • --repair-state: rebuild a damaged install.json from the agent settings files that hold the firewall's hooks (the damaged file is kept beside it; person-run, needs the approval passphrase).
  • --dry-run: with --fix, print the changes and exit without writing anything or asking for the passphrase.

update

Download the malicious-package data (OSV MAL- entries) used to check installs. This is the only network use. Changes state.

launchsafe-firewall update [--source URL|DIR] [--ecosystem LIST]
  • --source URL|DIR: where to fetch <Ecosystem>/all.zip from (default: OSV's public bulk exports).
  • --ecosystem LIST: comma-separated ecosystems (default: npm, PyPI, crates.io, RubyGems, Go, Maven, NuGet, Packagist).

status

Sessions, held actions and recent decisions.

launchsafe-firewall status [--json]

queue

Actions held for a person.

launchsafe-firewall queue [--json]             # same as queue list
launchsafe-firewall queue list [--json]
launchsafe-firewall queue show <id> [--json]   # one held action, with the diff for a proposed change
launchsafe-firewall queue review               # go through every held action (needs the approval passphrase); changes state
launchsafe-firewall queue approve <id>...      # allow held actions once (needs the approval passphrase); changes state
launchsafe-firewall queue reject <id>...       # reject held actions; changes state

pins

MCP servers' pinned configuration, tools and descriptions, and changes waiting for review.

launchsafe-firewall pins [--json]              # same as pins list
launchsafe-firewall pins list [--json]
launchsafe-firewall pins accept <server>...    # accept pending changes after review (needs the approval passphrase); changes state

vault

Secrets the agent can use by reference but never sees. See Vault.

launchsafe-firewall vault [--json]             # same as vault list
launchsafe-firewall vault list [--json]        # names, kinds, fields, bindings; never a value
launchsafe-firewall vault add <name> [--kind credential|oauth|card|iban|national_id|personal] [--fields a,b] [--confirm always|never]
launchsafe-firewall vault allow <name> --host HOST [--allow-in-url] [--allow-http] | --mcp SERVER[:TOOL[:ARG]] | --process "PROGRAM ARGS..."
launchsafe-firewall vault revoke <name> <n>
launchsafe-firewall vault remove <name>
launchsafe-firewall vault rotate <name>

add, allow, revoke, remove and rotate need the approval passphrase and change state.

  • vault add --kind: what it is (default credential); card, iban, national_id and personal have several fields.
  • vault add --fields a,b: the field names (default per kind: value; card number,expiry,cvc,name; iban iban,bic,holder).
  • vault add --confirm always|never: macOS, ask in a keychain dialog on every read (default: always for card, iban, national_id, personal; never for credential, oauth).
  • vault allow --host HOST: an exact host name, or *.example.com for its subdomains. --allow-in-url lets the value also appear in the URL itself (server logs keep URLs); --allow-http lets it also go over plain http (the default is https only).
  • vault allow --mcp SERVER[:TOOL[:ARG]]: an MCP server, optionally a tool pattern and the one argument path it may appear in.
  • vault allow --process ARGV: a command line it may be given to by run (a trailing * allows further arguments).
  • vault revoke <name> <n>: remove one binding of a secret, by its number in vault list.

mcp

The MCP gateway. See MCP gateway. All of these change state.

launchsafe-firewall mcp wrap --client CLIENT --server NAME [--mode auto|full|hook] [--phones PIN] -- COMMAND [ARGS...]
launchsafe-firewall mcp serve [--port N]
launchsafe-firewall mcp wrap-config --client CLIENT [--server NAME,...] [--port N] [--dry-run]
launchsafe-firewall mcp unwrap-config --client CLIENT [--dry-run]
launchsafe-firewall mcp login <server>
  • mcp wrap: the stdio gateway for one server (an MCP client starts this from its configuration).
  • --client claude-desktop|claude-code|cursor|codex|gemini|vscode: which MCP client.
  • --server NAME: the server's name in the client's configuration.
  • --mode auto|full|hook: full, the gateway decides every call; hook, the client's firewall hook does (default auto).
  • --phones sha256:HEX: the paired phones' pin (written by mcp wrap-config; phone approvals verify against it).
  • mcp serve: the local Streamable HTTP gateway (127.0.0.1 only; person-run). --port N sets the port (default 8473).
  • mcp wrap-config: put the gateway in front of a client's MCP servers; shows the diff, backs up, needs the approval passphrase. --server NAME,... limits it to these servers, --port N is the local gateway's port for HTTP servers (default 8473), --dry-run prints the changes and exits.
  • mcp unwrap-config: put a client's MCP servers back as they were before wrap-config (needs the approval passphrase).
  • mcp login: sign the gateway in to a wrapped HTTP server's authorization server (OAuth, person-run).

gateway

launchsafe-firewall gateway [--json]                    # same as gateway status
launchsafe-firewall gateway status [--json]             # servers wrapped, not wrapped, and withheld results
launchsafe-firewall gateway reset <client>              # start a new gateway session for a client now; changes state
launchsafe-firewall gateway quarantine [--json]         # MCP results the gateway withheld (never their text)
launchsafe-firewall gateway quarantine show <id>        # the text of one withheld result, for you in your own terminal; changes state

mail

The email guard. See Email guard.

launchsafe-firewall mail [--json]                        # same as mail quarantine list
launchsafe-firewall mail quarantine [--all] [--json]
launchsafe-firewall mail quarantine list [--all] [--json]
launchsafe-firewall mail quarantine show <id> [--json]   # one record, with its hidden text escaped
launchsafe-firewall mail quarantine release <id>         # deliver next time, hidden parts stripped (needs the approval passphrase); changes state
launchsafe-firewall mail quarantine discard <id>         # close the record; it stays withheld; changes state
launchsafe-firewall mail audit --path FILE|DIR [--limit N] [--json]
  • --all: also list released and discarded records.
  • mail audit: a dry run of the email guard over saved mail (.eml files, mbox files or folders of them): counts only, nothing changes or leaves the machine. --path FILE|DIR is an .eml file, an mbox file, or a folder of them (searched recursively); --limit N scans at most N messages (default 5000); --json prints the counts as JSON (no addresses, no subjects).

phone and relay

Phone approvals are not available yet. See Phone approvals.

launchsafe-firewall phone [--json]                        # same as phone list
launchsafe-firewall phone list [--json]
launchsafe-firewall phone pair [--label NAME] [--no-login-item]   # needs the approval passphrase and a LaunchSafe account; changes state
launchsafe-firewall phone remove <label|id>               # needs the approval passphrase; changes state
launchsafe-firewall phone unpair <label|id>               # same as phone remove
launchsafe-firewall relay [--json]                        # same as relay status
launchsafe-firewall relay status [--json]
launchsafe-firewall relay run [--once]                    # the relay daemon; changes state
  • --label NAME: this machine's name on the phone (default: the host name).
  • --no-login-item: do not install the relay daemon as a login item (run relay run yourself).
  • --once: one upload and one decision check, then exit.

approver

The approval passphrase.

launchsafe-firewall approver                  # same as approver status
launchsafe-firewall approver status           # whether an approval passphrase is set
launchsafe-firewall approver init             # set the approval passphrase; changes state
launchsafe-firewall approver rotate           # change the approval passphrase; changes state

log

The signed decision log.

launchsafe-firewall log                       # same as log tail
launchsafe-firewall log tail [N]              # the last N decisions
launchsafe-firewall log verify                # check the log's hash chain and signatures
launchsafe-firewall log rotate                # start a new log file now; changes state

policy

See Policy.

launchsafe-firewall policy                    # same as policy show
launchsafe-firewall policy show               # print the merged policy
launchsafe-firewall policy validate           # check every policy file and list ignored project settings
launchsafe-firewall policy init               # write a starter user policy file; changes state
launchsafe-firewall policy migrate            # rewrite the user policy in the current schema version, keeping a backup; changes state

canary

Decoy files.

launchsafe-firewall canary [--json]                       # same as canary list
launchsafe-firewall canary list [--json]                  # the decoys planted, and whether each is still there
launchsafe-firewall canary plant [--workspace DIR] [--home] [--kinds env,aws,ssh,gh,notes,npmrc,kube]
launchsafe-firewall canary remove <id>
launchsafe-firewall canary remove --all

plant and remove change state.

  • --workspace DIR: the project to plant in (default: the current directory).
  • --home: also plant decoys in your home directory (~/.aws, ~/.ssh, ~/.config/gh); off by default.
  • --kinds LIST: comma-separated kinds (default: env,aws in the workspace; aws,ssh,gh with --home).
  • remove --all: remove every decoy (also resets a damaged registry).

scope

The task scope a session's prompt set.

launchsafe-firewall scope [<session>] [--json]            # same as scope show
launchsafe-firewall scope show [<session>] [--json]       # the scope and your widenings (default: the most recent session)
launchsafe-firewall scope widen <session> --path P | --repo OWNER/REPO | --host HOST | --intent push|pr|publish|deploy|message|delete|install|migrate

scope widen needs the approval passphrase and changes state. --path P is a file or directory (relative to the current directory), --repo OWNER/REPO a GitHub repository, --host HOST a host name, --intent a publish-type action the task may take.

check and explain

launchsafe-firewall check   < action.json
launchsafe-firewall explain <id> [--json]
launchsafe-firewall explain   < action.json
  • check judges one action without changing anything. It reads {"tool": "...", "input": {...}, "untrusted": false, "unattended": false, "prompt": "..."} on stdin.
  • explain explains a rule (FW-...), a queue item, a log entry or an agent-safety rule. With no id, it is the same as check.

ui

A read-only dashboard in your browser (127.0.0.1 only, a private address printed once). Approvals stay in the terminal. Only you can start it, from your own terminal. Changes state. See Dashboard.

launchsafe-firewall ui [--project DIR] [--no-open]
  • --project DIR: the project doctor's checks look at (default: the current directory).
  • --no-open: print the address without opening the browser.

run

Start an agent (or any command) inside the OS sandbox: writes only to the workspace and a private temporary directory, network only to your policy's hosts through a local proxy, decisions in the signed log (macOS sandbox-exec, Linux bubblewrap). Changes state. See Run and sandbox.

launchsafe-firewall run [--workspace DIR] [--allow-write LIST] [--send-host LIST] [--allow-localhost] [--allow-keychain] [--git-init] [--env NAME=vault://REF]... [--dry-run] [--verbose] -- <command> [args...]
  • --env NAME=vault://REF: put a vaulted secret into the command's environment as NAME (repeatable); the secret must be bound to this exact command (vault allow <name> --process "<command>").
  • --ticket T: a single-use ticket the firewall's hook issued for exactly this --env list and command (Claude Code's rewrite of a shell command with references); runs without the sandbox, output filtered.
  • --workspace DIR: the directory the command may write to (default: the current directory).
  • --allow-write LIST: comma-separated extra directories it may write to (never the home directory, credential stores, agent settings or system directories).
  • --send-host LIST: comma-separated hosts it may send to for this run, without byte budgets (for example the agent's model API).
  • --allow-localhost: macOS, let it connect to any port on 127.0.0.1 (local test servers; every local service becomes reachable). Linux has its own loopback.
  • --allow-keychain: macOS, let it use the keychain (denied by default, so vault items stay out of reach).
  • --git-init: when the workspace has no .git, run git init in it before the run starts (inside the run .git cannot be created).
  • --dry-run: print the sandbox profile and the hosts, start nothing.
  • --verbose: also print each refused connection as it happens (a full-screen agent may draw over it).

demo, version and help

launchsafe-firewall demo                  # replay the public incidents through the policy
launchsafe-firewall version               # print the version
launchsafe-firewall help [command...]     # help for a command

hook

The agent hook. It reads the event on stdin and is what the agents' hook registrations run. Changes state.

launchsafe-firewall hook [--agent claude|codex|gemini|cursor] [--record DIR]
  • --agent claude|codex|gemini|cursor: which agent sends the event (default claude).
  • --record DIR: also save each raw event to DIR (only with LAUNCHSAFE_FIREWALL_RECORD=1).

On this page