Whisper · Docs
SDKs & CLI

CLI & one-command setup

Wiring a project into a new identity system usually means an SDK, a bespoke config file, and an afternoon of docs — whisper collapses all of it into one binary and one line.

whisper init claude, and your project has a real, routable, DNSSEC-anchored identity before you've finished reading this sentence.

The pain this removes

Every coding agent, every automation runner, every CI job that needs a network identity has historically faced the same bad menu: install a Python package with native deps for one stack, an npm package for another, hand-roll a WireGuard config for a third, and hope the proxy environment variables you set actually get inherited by the child process. None of that is hard, exactly — it's just friction, repeated once per tool, per language, per environment. And friction is where identity systems die: an agent that's "supposed to" carry its address ends up talking out from whatever IP the host happened to have, and the whole point of a verifiable identity — that the network layer is the proof — quietly evaporates.

The whisper CLI is the fix: one MIT-licensed, cross-platform Go binary that does registration, connection, and verification without asking you to touch a config file, and a whisper init <tool> family that wires that identity into the specific tool you're already using — Claude Code, Gemini, aider, Zed, browser-use, and eight more — with zero manual setup. It is also, deliberately, not the only way in: everything it does is one HTTP call or one dig away (see the mappings below), so nothing about it is a black box.

Install

curl -fsSL https://get.whisper.online | sh      # reads before it runs; one binary, no daemon required

Prefer a package manager? The same signed binary ships on all of them — pick the one your platform already trusts:

brew install whisper-sec/tap/whisper                                  # Homebrew (macOS/Linux)
scoop bucket add whisper https://github.com/whisper-sec/scoop-bucket && scoop install whisper  # Windows
go install github.com/whisper-sec/whisper-cli/cmd/whisper@latest      # straight from source
mise use -g "github:whisper-sec/whisper-cli[exe=whisper]"             # mise
sudo apt install whisper   # after adding get.whisper.online/deb — see /docs/integrations

Source, issues, and the release signatures live at github.com/whisper-sec/whisper-cli. Every artifact is signed; whisper --version prints the build's commit and the key fingerprint it was signed with.

Sign in

whisper login                 # opens the console in a browser, drops a scoped key in your keychain
whisper login --token whisper_live_...   # or paste one directly (CI, containers, no browser)

A key is only needed for the control-plane half. Everything under whisper verify works with no login at all — that's the keyless tier, by design (see Verify an agent).

The commands, and what each one actually calls

Nothing the CLI does is proprietary to the CLI. Every command is a thin, honest wrapper over either a public DNS/HTTP check or the one control-plane verb, whisper.agents. Here's the mapping, so you can reimplement any of it yourself or debug it when something looks wrong:

Command What it does Underlying call
whisper login store a scoped API key none — local only
whisper create --label my-agent mint an identity: address, forward name, PTR, DANE pin CALL whisper.agents({op:'register', args:{label:'my-agent'}})
whisper list your agents, their addresses and status CALL whisper.agents({op:'list', args:{}})
whisper connect my-agent [--tier socks5\|wireguard] bring up egress sourced from the agent's /128 CALL whisper.agents({op:'connect', args:{agent:'my-agent', tier:'socks5'}})
whisper run -- <cmd> connect (if needed), verify egress, exec <cmd> under it connect, then the keyless echo check, then execve
whisper ip my-agent prove the current egress source address curl through the proxy to https://rdap.whisper.online/egress-ip
whisper verify <addr> keyless identity check GET https://rdap.whisper.online/verify-identity/<addr>
whisper verify --trustless <addr> the same check, re-derived locally from the DNSSEC root — Whisper's own API is never trusted local DNSSEC chain-of-trust validation, see Trustless verification
whisper revoke my-agent tear down address, DNS, DANE pin, and egress in one step CALL whisper.agents({op:'revoke', args:{agent:'my-agent'}})

Every one of the right-hand-column calls is documented on its own in Control plane and Connect & egress. The CLI adds nothing to the protocol — it only removes the typing.

The same thing, with stock tools only

The table isn't aspirational — every call really is one curl or one dig. Provisioning an agent and proving an identity, with no Whisper software installed anywhere:

# mint an agent — POST the one control-plane verb; the key travels in the header, never the body
curl -s https://graph.whisper.security/api/query \
  -H "X-API-Key: whisper_live_..." \
  -d '{"query":"CALL whisper.agents({op:'"'"'register'"'"', args:{label:'"'"'my-agent'"'"'}})"}' | jq .

# verify any agent's identity — keyless, no header at all
curl -s https://rdap.whisper.online/verify-identity/2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 | jq .

The CLI equivalents — whisper create --label my-agent and whisper verify 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4 — send the same bytes to the same endpoints. Nothing is hidden behind the binary; it only saves the typing. Full request and response shapes: Control plane.

whisper run — what actually changes in the child process

whisper run -- python agent.py does exactly three things, in order, and fails loudly rather than falling back silently if any of them don't hold:

  1. Connects, if the named (or default) agent isn't already connected — whisper.agents({op:'connect', tier:'socks5'}) by default, since Tier 1.5 needs no root and no kernel interface.
  2. Verifies the egress before handing off control: it fetches https://rdap.whisper.online/egress-ip through the new proxy and checks the answer equals the agent's own /128 — the same check whisper ip exposes standalone. A mismatch is a hard error, never a quiet fallback to your host's own address.
  3. Execs your command with ALL_PROXY and HTTPS_PROXY pointed at a local loopback SOCKS5 endpoint the CLI holds open for the life of the command — source-bound to the agent's /128, so no egress credential ever lands in the child's environment (or, for --tier wireguard, nothing at all — the interface itself carries the address, so no env var is needed):
whisper run -- python my_agent.py
# child process env now includes:
#   ALL_PROXY=socks5h://127.0.0.1:1080
#   HTTPS_PROXY=socks5h://127.0.0.1:1080

Because ALL_PROXY/HTTPS_PROXY are a decades-old Unix convention, this needs no cooperation from your code: curl, git, Python requests/httpx, Node's fetch, and Claude Code's own tool-use network layer all already honor them. There is no SDK to import.

whisper init <tool> — wiring an identity into what you already run

whisper connect and whisper run are generic; whisper init <tool> goes one step further and speaks each target's own configuration surface, so the identity is there before the tool's first network call — no wrapper script, no env var to remember:

whisper init claude          # writes the proxy/network entry into ./.claude/settings.local.json
whisper init gemini          # same egress, Gemini CLI's own config surface
whisper init aider           # aider's local config, same proxy underneath
whisper init zed             # Zed's context-server settings
whisper init browser-use     # a browser-context proxy config for headless/agentic browsing

Twelve targets ship today — claude, python, zed, gemini, aider, ai-sdk, browser-use, discord, telegram, notebook, compose, k8s — each writing into that tool's native format rather than a Whisper-specific one. Run it with no argument and it detects the project (a .claude/ directory, a pyproject.toml, a docker-compose.yml) and picks the right target itself. Every target is provisioned against the same control-plane register + connect pair above; init only differs in where it writes the result. Before starting the target process, init confirms the local egress endpoint is already listening — so the tool's very first outbound call never races an unready proxy.

whisper init claude && claude    # the project now has an identity; Claude Code's traffic carries it

For everything that isn't a first-class init target — n8n, Zapier, Cloudflare Workers, Kubernetes — see the full connector catalog at Integrations; they use the same two calls, just via a platform-native connector instead of a CLI wrapper.

Uninstalling, cleanly

whisper revoke my-agent   # first: kill the identity — address, DNS, DANE pin, and status-list entry, provably
rm $(command -v whisper)  # then: remove the binary, no other state left behind

whisper keeps no daemon running between invocations and no local database beyond the key in your OS keychain — revoking an agent and deleting the binary leaves nothing behind on either side.

Next

Connect & egress — the three tiers whisper connect and whisper run choose between, and how source-binding actually works · Integrations — every non-CLI way to wire in the same identity, from MCP to Kubernetes.