Audience: KRL developers and engine operators
Engine version: 1.6+
Parent: Identity System
What this page covers
Every pico in pico-engine 1.6+ has a cryptographic identity expressed as a DID (Decentralized Identifier). This page explains what those DIDs are, how to find them, and how to use them in KRL.
It does not cover subscription formation, lifecycle, or routing — that belongs on Subscriptions.
Why DIDs?
Picos need a stable answer to “which pico is this?” that survives beyond a single channel ECI or engine instance. DIDs provide that for pico-to-pico work: introductions, encrypted traffic, and (eventually) verifiable credentials.
DIDs are a separate plane from the other identity mechanisms:
Mechanism | Identifies | You use it when… |
|---|
Mechanism | Identifies | You use it when… |
|---|---|---|
Passkey | A human at the browser | Using the developer UI or session-gated |
DID | A pico as an actor | Picos talk to each other (queries, events, intros) |
OAuth Bearer | An external integrator | Webhooks, Home Assistant, third-party apps on |
Humans sign in with a passkey; your root pico is your agent and holds a DID. Picos use DIDs outward; external apps use OAuth.
Two DIDs, two jobs
Pico-engine uses two DID methods. They are complementary, not redundant.
DID | Role | Cardinality | Think of it as… |
|---|
DID | Role | Cardinality | Think of it as… |
|---|---|---|---|
did:webvh | Portable pico identity — who the actor is | One per pico | The pico’s passport |
did:peer | Private relationship identity for one subscription pair | One per established subscription | A phone number for that relationship only |
did:webvh is provisioned automatically when a pico is created. Share it when someone needs to introduce themselves to your pico (for example as target_did when forming a subscription).
did:peer is minted during the SKY intro handshake when a subscription is approved. Use it for ongoing query and event traffic on that subscription. Do not share a peer DID to start a new subscription — always use the recipient’s did:webvh at create time.
ECIs (channel ids) are still the local policy gate on each engine. DIDs identify picos and relationships; ECIs enforce what a caller may do on this engine.
did:webvh — portable pico identity
Provisioning
Every pico receives a did:webvh at creation — root picos, child picos, and picos created before 1.6 (provisioned on first load after upgrade).
The DID document log is served at:
GET /picos/{picoId}/did.jsonl
The engine embeds PICO_ENGINE_BASE_URL in the document. For cross-engine use, that URL must be stable and peer-reachable (not just what you type in a local browser tab).
Finding a pico’s did:webvh
Where | How |
|---|
Where | How |
|---|---|
Developer UI | Open the pico → Subscriptions tab → Identity panel → did:webvh (myDid) |
KRL |
|
HTTP | Fetch |
Give partners your did:webvh when they need to subscribe to you or resolve who you are. Do not give them a did:peer for that purpose.
did:peer — subscription relationship identity
After two picos complete a DID-based subscription intro, each side stores the remote party’s did:peer on the established subscription (Tx_did, Rx_did).
Peer DIDs are private to that relationship. They are used for encrypted SKY traffic (DIDComm) when picos are on different meshes or engines, and for routing queries and events once the subscription exists.
→ How peer DIDs are created and used: Subscriptions
Public intro
Public intro controls whether a pico accepts unsolicited SKY intro messages addressed to its did:webvh.
Pico | Default |
|---|
Pico | Default |
|---|---|
Root pico | On ( |
Child pico | Off |
Any pico may enable public intro — for example a community or registry pico that should accept subscriptions from strangers.
Where | How |
|---|
Where | How |
|---|---|
Developer UI | Subscriptions tab → Identity → Public intro checkbox |
KRL query |
|
KRL event |
|
Cross-engine subscriptions usually require the recipient to have public intro enabled (or an existing relationship path).
Using DIDs in KRL
Query a remote pico by DID
wrangler:picoQuery(<did_webvh_or_peer>, "io.picolabs.wrangler", "id", {})
The engine routes over an established subscription when one exists for that DID. Otherwise it may resolve a did:webvh directly (cold query) if the peer is reachable.
picoQuery accepts did:webvh or did:peer. It does not accept an ECI — use picoQuery with an ECI for classic (non-DID) remote calls.
Send an event by DID
event:send({
"did": "<did_webvh_or_peer>",
"domain": "wrangler",
"type": "ping",
"attrs": {}
})
For traffic on an established subscription, you can also pass the full subscription map:
event:send({
"sub": subscription,
"domain": "wrangler",
"type": "ping",
"attrs": {}
})
See the event library docs in the developer UI for details. Subscription formation and the layer2: true attribute are documented on Subscriptions.
Know who sent a cross-pico event
When the engine delivers an inbound cross-pico event, rules may read the sender’s portable identity:
wrangler:callerDid()
Returns the sender’s did:webvh when the engine provides it; otherwise null.
Wrangler identity API
Query / action | Returns / effect |
|---|
Query / action | Returns / effect |
|---|---|
| This pico’s did:webvh |
| Whether unsolicited SKY intro is accepted |
| Toggle public intro |
| Sender’s did:webvh on inbound cross-pico events |
| Query a remote pico by did:webvh or did:peer |
Identity primitives are implemented in the engine dido module and exposed through wrangler queries and events.
DIDs are not…
Not passkeys. Passkeys authenticate you to your mesh. DIDs identify picos to each other.
Not OAuth. OAuth authorizes external HTTP callers on /sky/*. Pico-to-pico traffic uses SKY and DIDComm (or verified local dispatch on the same engine), not Bearer tokens.
Not ECIs. An ECI is a channel address and policy gate on one engine. A DID is a portable cryptographic identity. Established subscriptions still have an Rx ECI where policy is enforced locally.
Not a replacement for family channels. Parent and child picos communicate through family channels, not subscriptions or DIDs.
Configuration
Variable | Relevance to DIDs |
|---|
Variable | Relevance to DIDs |
|---|---|
| Embedded in every did:webvh; must be stable and peer-reachable for portable identity and cross-engine resolution. Defaults to |
See the Environment variables page for the full list (passkey and OAuth variables are on the sibling identity pages).
Related pages
Identity System — three-plane overview
Subscriptions — formation, lifecycle, routing, cross-engine
Passkey Authentication and UI access — human → root pico (link to your Passkey child page)
Deprecated: io.picolabs.did-o ruleset — use wrangler:picoQuery and event:send with DIDs instead.