Skip to main content

whisper-id

A real, routable IPv6 identity, safe egress, and the full control plane for any Python agent, in two calls.

pip install whisper-id            # add [socks] for requests+SOCKS: pip install "whisper-id[socks]"
from whisper_id import register, egress
import requests

agent = register("my-bot")                       # a routable Whisper /128 identity
with egress():                                   # route this block through your /128
    requests.get("https://api64.ipify.org").text # ← leaves from your Whisper IPv6

That's it. Inside the with block the standard proxy env vars point at your local Whisper proxy, so requests, httpx, urllib, and most libraries "just work"; on exit they're restored.

API

Call Does
register(name, *, new_key=False) Create a named agent: a routable /128. new_key=True mints a new agent and its own API key. → Agent(address, id, name)
egress(agent=None, *, tier="socks5", set_env=True) Context manager: bring up egress bound to your /128. Yields Egress (.port, .proxy_url, .socks_url, .proxies). tier="wireguard" for a routed /128.
verify(address) Keyless: is address a real Whisper agent? (DANE + DNSSEC + reverse-DNS + JWS) → bool
verify_details(address) Keyless: the full verdict (is_whisper_agent, fqdn, operator, tenant, dane_ok, jws_ok, ...) or None
rdap(address) Keyless: the public RDAP record for a /128, or None
egress_ip() Keyless: the IP this process leaves from (a /128 when routed, else the platform's) → str
ip() Your current egress IP via the CLI, proving it's your /128. → str

Control plane: pure-HTTP (no CLI), one HTTPS call each; needs your key (arg key=... or WHISPER_API_KEY):

Call Does
list_agents(kind="agents") Your fleet (kind = agents | identities | records). → list[dict]
policy(default=..., allow=..., block=...) Set your DNS resolver policy, or read it with no args. → dict
logs(agent=..., kind=..., from_=..., to=..., limit=...) Recent DNS/conn/alloc activity (kind = dns | conn | alloc). → list[dict]
identity(label, contact_email=...) Allocate your own /128; release with identity(release=True, address=...). → dict
agent(agent_or_address) One agent's detail + counters (id, or a /128, anything with : is an address). → dict
revoke(agent) Fully revoke an agent (irreversible). → dict

Pass the proxy explicitly instead of via env if you prefer:

with egress(set_env=False) as e:
    requests.get(url, proxies=e.proxies)

Keyless / serverless (no CLI)

verify, verify_details, rdap, and egress_ip are keyless: pure HTTPS, no whisper CLI and no key, so they run anywhere, including serverless/edge functions:

from whisper_id import verify, rdap
if verify(addr):                       # one HTTPS call; works in AWS Lambda, Cloudflare, etc.
    print(rdap(addr)["name"])

register, egress, and ip need the CLI (egress needs the local proxy; register needs your key).

Control plane: govern your fleet (no CLI)

With your key set, provision and govern agents over pure HTTPS, no whisper binary, so this works in serverless/edge functions too:

import os
from whisper_id import identity, list_agents, policy, logs, agent, revoke

os.environ["WHISPER_API_KEY"] = "whisper_live_..."   # or pass key=... to any call

a = identity("scout")                              # allocate a routable /128
print(a["address"], a["fqdn"])

policy(default="deny", allow=["api.github.com"])   # deny-by-default DNS policy
print(policy())                                    # read it back → {'default': 'deny', ...}

for it in list_agents():                            # your fleet
    print(it["label"], it["address"])

print(agent(a["address"])["dns_queries"])          # per-agent counters
logs(agent=a["address"], kind="dns", from_="-1h")  # recent activity
revoke(a["address"])                               # irreversible

Every call is one HTTPS POST of CALL whisper.agents({op, args}) to the control plane; it raises WhisperError with the server's message on failure, and accepts both response shapes. Set WHISPER_CONTROL_URL / WHISPER_RDAP_URL to point at a self-hosted deployment.

Security graph (keyed)

The Whisper security graph (3.6B nodes, 30B relationships) is one typed namespace. It is Cypher, and Cypher needs an API key, so the whole namespace is keyed on the same transport as the control plane above (one HTTPS POST to graph.whisper.security/api/query, the key only in the X-API-Key header). This is the keyed tier; the genuinely keyless half of Whisper stays verify / rdap (no Cypher).

from whisper_id import graph

g = graph()                                  # key from WHISPER_API_KEY (or graph("whisper-..."))

g.identify("api.openai.com")                 # vendor + operator role behind a host or IP
g.assess("8.8.8.8")                          # labelled threat posture
g.origins("cloudflare.com")                  # real origin IPs behind a CDN
g.explain("paypal.com")                      # threat-feed score + why
g.typosquat("paypal.com")                    # multi-step flow (look-alike sweep), streamed
g.run_flow("typosquat", {"domain": "paypal.com"})   # any flow by its catalog slug
g.query("CALL db.schema()")                  # raw escape hatch for any read Cypher

Fourteen direct verbs run their Cypher against the graph and return a list of column-keyed dicts ([{col: val, ...}]). The fifteen multi-step flow verbs (attackSurface, typosquat, infrastructureMapping, ...) run keyed via the gallery flow runner (console.whisper.security/api/gallery/run, a Server-Sent-Events stream): they return {slug, steps, context, output, totalLatencyMs} and stream per-step progress through an optional on_event(name, data) callback. g.run_flow(slug, inputs, params) runs any flow by its catalog slug. Every method's docstring links its docs page under whisper.security/docs.

Requirements

For register / egress / ip, the whisper CLI on your PATH (this package is a thin, dependency-free wrapper over it). The keyless calls above need nothing.

curl get.whisper.online | sh

Set WHISPER_API_KEY in the environment (or run whisper login) for the CLI-backed calls (register, egress, ip) and the pure-HTTP control plane (identity, policy, logs, agent, revoke, list_agents: these take the key directly, no CLI). verify / rdap are keyless. ($WHISPER_BIN overrides the CLI path.)

Links

MIT licensed.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

whisper_id-0.5.1.tar.gz (31.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

whisper_id-0.5.1-py3-none-any.whl (21.5 kB view details)

Uploaded Python 3

File details

Details for the file whisper_id-0.5.1.tar.gz.

File metadata

  • Download URL: whisper_id-0.5.1.tar.gz
  • Upload date:
  • Size: 31.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for whisper_id-0.5.1.tar.gz
Algorithm Hash digest
SHA256 16621b60349e70af1b375261b6041ae156d57c6caaae25a3bad204d36db31b99
MD5 5348d68717aad00f1764e7996d884160
BLAKE2b-256 343e14c1eb8102027e101ba4b8d90b2cb22e6ca74d5da69f36111ece3488f843

See more details on using hashes here.

Provenance

The following attestation bundles were made for whisper_id-0.5.1.tar.gz:

Publisher: publish.yml on whisper-sec/whisper-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file whisper_id-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: whisper_id-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 21.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for whisper_id-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3a7e414d57ab26061d380fd1a07178e7a882c45b256a76f8ed4ee7d0cf031a07
MD5 52f4434cd5619aeff329593b6ce79b99
BLAKE2b-256 d3c8ef908b455afbc3081f9c1eb63e35a39a44d959f89da0fd884cee618ac607

See more details on using hashes here.

Provenance

The following attestation bundles were made for whisper_id-0.5.1-py3-none-any.whl:

Publisher: publish.yml on whisper-sec/whisper-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.6.1

2 files

0.6.0

2 files

This release

0.5.1 This release

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page