Sharing and Accepting Capabilities (CapTP)
The Capability Transport Protocol (CapTP) is how capabilities move between agents. Whether you are delegating access to a sub-agent, accepting a capability from a colleague, or sending a message to an offline recipient, CapTP handles the transport, persistence, and verification.
Key Concepts
Live References vs. Sturdy References
A live reference exists only within an active session between two agents. It is fast (no lookup required) but ephemeral -- if either party disconnects, the reference is gone.
A sturdy reference survives disconnection, serialization, and restart. It encodes the target cell, a Swiss number (unforgeable designator), and a routing hint. You can save a sturdy ref to disk, email it, or seal it in a box for later delivery.
Store-and-Forward
If your target is offline, CapTP queues the message in their MerkleQueue inbox. You pay a small deposit (refunded when the recipient processes the message). Messages persist until the recipient comes online or the TTL expires.
Sharing a Capability
Via the Cipherclerk (Browser Extension)
- Open the cipherclerk and navigate to "Tokens".
- Select the token you want to share.
- Click "Delegate" and enter the recipient's public key (or scan a QR code).
- Choose restrictions: which actions, what TTL, what budget limit.
- Click "Send". The cipherclerk attenuates the token and transmits via CapTP.
Via the CLI
# Delegate a capability with restrictions
dregg cap delegate \
--token $TOKEN_ID \
--to $RECIPIENT_PUBKEY \
--restrict service=storage,action=read,budget=1000 \
--ttl 24h
# The recipient can accept with:
dregg cap accept --from $YOUR_PUBKEY
Via the SDK (Programmatic)
use dregg_sdk::{AgentCipherclerk, Attenuation};
let mut alice = AgentCipherclerk::new();
let mut bob = AgentCipherclerk::new();
let root = alice.mint_token(b"secret-key-here-32-bytes!!!!!!!!", "compute");
// Alice delegates to Bob with restrictions
let delegated = alice.delegate(&root, &bob.public_key(), &Attenuation {
services: vec![("compute".into(), "inference".into())],
max_budget: Some(5000),
max_ttl: Some(std::time::Duration::from_secs(3600)),
..Default::default()
}).unwrap();
// Bob receives the signed delegation envelope. He passes the authority policy
// (here: "I trust envelopes signed by Alice's pubkey") so the SDK can verify
// the envelope binding before accepting.
bob.receive_signed_delegation(
delegated,
&DelegationAuthority::TrustedKey(alice.public_key()),
).unwrap();
Accepting a Capability
When someone delegates a capability to you, it arrives in your inbox. The cipherclerk (or CLI) validates:
- The delegation chain is cryptographically valid (HMAC chain intact).
- The capability was not revoked (non-membership in revocation set).
- The restrictions are consistent (each step only narrows).
You can inspect the capability before accepting -- see what service it grants, what restrictions apply, when it expires, and who delegated it.
Offline Delivery (Sealed Boxes)
To send a capability to someone who is offline, CapTP uses sealed boxes (X25519 + ChaCha20-Poly1305 encryption):
- The sender seals the capability under the recipient's public key.
- The sealed box is deposited in the recipient's MerkleQueue inbox (federation stores it).
- When the recipient comes online, they unseal using their private key.
The sealed box reveals nothing to the federation or any observer -- only that a message of a certain size was deposited at a certain time.
Four sealed capabilities sit in the recipient’s MerkleQueue. The federation can see counts and ciphertext lengths; it cannot see senders, capability contents, or which messages link to which prior interactions.
Three-Party Introduction
If Alice holds capabilities to both Bob and Carol, she can introduce them:
- Alice invokes
Effect::Introducein a turn, granting Bob a (possibly attenuated) capability to Carol. - Bob receives a routing directive telling him how to reach Carol.
- Bob can now communicate directly with Carol -- no further involvement from Alice.
This is how new communication paths form in dregg. There is no global directory;
all paths are introduced.
Promise Pipelining
You can send messages to the result of a pending operation without waiting for it to complete. If you request a service and the result will be a new capability, you can start using that capability immediately -- the messages queue and deliver once the promise resolves. This eliminates round-trip latency in multi-step workflows.
Revoking Shared Capabilities
After sharing a capability, you may need to revoke it:
- Epoch bump: Increment your delegation epoch. All children become stale within
max_staleness. - RevocationChannel: For instant revocation, enroll the capability in a channel. Trip the channel to revoke in real-time.
- CDT revocation: Revoke an entire subtree of delegations at once.
# Revoke a specific delegation
dregg cap revoke --token $TOKEN_ID --delegation $DELEGATION_HASH
# Trip a revocation channel (instant, all subscribers affected)
dregg cap trip-channel --channel $CHANNEL_ID
Next Steps
- CLI Reference -- Full command reference for
dregg cap - SDK Quickstart -- Programmatic CapTP usage
- Capability Architecture -- How CapTP works internally