Nested identity
An agent behind another agent. A PC that is a Whisper agent runs a browser that is also a Whisper agent and egresses through it - so the browser is nested behind the PC. Whisper detects that hierarchy, at any depth, across any mix of SOCKS5 and WireGuard, and makes it a checkable, governable fact.
Agents nest in the real world. A device holds an identity; something running on it holds its own; its traffic transits the outer one. Whisper records the parent to child relationship, shows you the live tree and its full history, documents same-owner edges publicly in RDAP and WHOIS, and - the part that matters for security - binds a child by every ancestor's egress policy. Nothing here is a new port or a new key: nesting rides the same whisper.agents control verb and the same /128 identities you already have.
How an edge is detected
Two signals, reconciled. Both are opaque to the graph proxy, so neither needs a new op.
| Signal | What it is | Where it comes from |
|---|---|---|
| Declared | intent | a parent arg on op:connect - "I run behind this identity" |
| Measured | attestation | the egress tap: a nested child's connection arrives from the parent's /128 (CLIENT_SRC) while the child authenticates as its own (SRC) |
Measured is ground truth: it is the observed transit, and it is what governs (below). A parent you merely declare is shown, but it never gates another identity's traffic - so no one can name a /128 they do not control to borrow, or escape, its policy.
Declare an edge when you provision the child:
CALL whisper.agents({op:'connect', args:{tier:'socks5', address:'<child /128>', parent:'<parent /128>'}})
A Tier-1.5 child (SOCKS5/HTTP egress source-bound to its /128) is measured automatically the first time it egresses through the parent. A Tier-1 (WireGuard) child is kernel-routed through its parent, so the parent governs it by routing; declare it to see it in the tree.
See the tree
op:agent returns each identity's current parent, its children, and its depth, joined live with per-connection liveness - never from the zone, so a busy nest never churns the record:
CALL whisper.agents({op:'agent', args:{address:'<child /128>'}})
# columns include: parent, children, children_total, depth,
# owner_agents_raw, owner_agents_nested_deducted, roam
#
# parent = { "parent": "2a04:2a01:92b1:49e2:8487:9d44:64d6:cb51",
# "parent_handle": "t6b3a5f3...", // the parent's OPAQUE tenant handle
# "source": "declared", "active": false, "orphaned": false }
# depth = 1
parent_handle is an opaque t<sha256> handle, never a raw account id - so a child always sees the identity it is behind, even across owners, without deanonymizing it. owner_agents_raw counts every /128; owner_agents_nested_deducted counts only root endpoints, so a fleet's true footprint is visible both ways. A child that stops egressing goes stale and then leaves the live tree while its history is kept; re-nest it under a different parent and both the current pointer and the timeline stay correct.
Documented in RDAP and WHOIS
A same-owner edge is public by default, the same way an identity's /128 is: the child's RDAP record carries a related link to its parent plus a "Nested identity" remark, and WHOIS shows a nested-behind: line. It is synthesized from the DNSSEC-signed zone, so it is byte-identical on every node via AXFR.
curl -H 'accept: application/rdap+json' https://ns1.whisper.online/ip/<child /128>
# -> links[]: ... { "rel":"related", "title":"nested behind (transit parent identity)", "href":".../ip/<parent>" }
# remarks[]: "Nested identity - this /128 egresses behind another Whisper identity."
A cross-owner edge is suppressed from the public surface by default (your agent transiting someone else's network is not published without consent). Either endpoint of a same-owner edge can opt out and the public link disappears while the owner still sees it:
CALL whisper.agents({op:'policy', args:{address:'<child /128>', nesting_opt_out:true}})
# -> policy rows include ['nesting_opt_out', 'true']
Opt-out is publish-before-commit: the public zone is rewritten first, so the flag can never report success while the AXFR'd record still exposes the edge.
Bound by every ancestor's policy
This is the security guarantee. A nested child's effective egress policy is its own firewall intersected with every live ancestor's - most-restrictive-wins. A DENY at any layer wins; a kill-switched or revoked ancestor cuts every descendant behind it. Because the child's final hop is Whisper-mediated (it sources from its own /128), that composition is enforced in software over the measured chain, evaluated once per connection:
- A category or host an ancestor blocks is blocked for the child, even if the child's own firewall would allow it.
- A child can never declare a laxer parent to slip an ancestor's block - only the measured transit chain governs.
- A chain too deep to fully evaluate fails closed (denied), never open.
So governance flows down the tree by construction: restrict the PC and the browser behind it inherits the restriction; kill the PC and the browser's egress stops with it.
Roaming (for partners)
The parent an agent egresses behind is a network. op:agent {roam:true} returns the ordered history of parent networks a device has roamed through - each as its opaque parent_handle, with first-seen, last-seen and connection counts - folded from the warm activity store:
CALL whisper.agents({op:'agent', args:{address:'<child /128>', roam:true}})
# -> roam: [ { "parent_handle":"t89a2...", "first_seen":..., "last_seen":..., "connections":42 }, ... ]
An MSSP that governs several client tenants recomputes each managed tenant's handle and matches it against these - so it can tell when a managed device has landed behind another managed client's network versus a foreign one. The handles are opaque, so a foreign network stays anonymous; only a network the partner already governs de-opaques.
What it is, and isn't
- Measured governs, declared informs. A declared parent appears in the tree and in same-owner RDAP; it never gates another identity's egress. Only observed transit composes policy.
- Same-owner public, cross-owner private. Same-owner edges are documented by default (opt-out per identity); cross-owner edges are suppressed from the public surface by default.
- Fails closed. Egress composition denies a chain it cannot fully evaluate. This is the opposite of resolution, which fails open so DNS never goes dark.
Next
See /docs/identity for the /128 an agent nests behind, /docs/connect for the SOCKS5/WireGuard tiers that produce a measured edge, and /docs/egress-governance for the per-agent firewall that composes down the chain.