VAID
A VAID is a portable identity bound to an action an agent takes. It says who acted, with what authority, and who issued that authority – and every action it signs carries a proof-of-possession any party holding the signer's public key can check on sight, with no shared trust domain and no service in between.
The outcome
Every agent action that needs trust across a system boundary takes a bespoke integration or a shared secret. Verifying who did what means being inside the same trust domain, or negotiating a federation agreement first.
Any party holding the signer's public key can verify who acted and on what exact request, by checking one signature – with no shared trust domain, no prior relationship, and no service to call.
That single, portable, independently-checkable proof is the primitive the whole category is missing – and the unit SYNTHERA and every tenant is built on.
How it works
Think of it like a passport, bound to an action.
A passport says who you are and who vouches for you, and a border officer can check it without calling your home country. A VAID does the same for an agent action: it states the acting identity, the authority it carries, and its lineage – and every action it signs carries a proof-of-possession, so a verifier checks that signature against the acting key rather than taking the sender's word for who called.
This isn't a diagram of verification. It's the real thing, running in your browser: the actual VAID proof-of-possession path against the standard's frozen conformance vector.
A VAID binds an action to a signature. The reference request below carries a proof-of-possession that verifies against a real, frozen Ed25519 signature – public-key-only, in your browser. Type one character into the body and the proof breaks – that is the point.
- JCS canonicalize–
- SHA-256 digest–
- Ed25519 verify–
Real Ed25519 + SHA-256 + RFC 8785 canonicalization over the request payload, checked against the frozen conformance vector – a live demonstration of the proof-of-possession path, not itself a conforming implementation.
Mint on your machine. Send one line. They check it in a browser.
You mint a VAID locally — no account, no call to us. It comes out as a single
vaid1: line you can paste into a chat message or an email. Whoever receives it
opens the verify page, pastes it in, and gets a verdict. They install nothing.
The page is fully client-side: it holds the published kernel key, makes no request when it
verifies, and works with the network switched off. That is the point of the credential —
checking it requires no cooperation from the party who issued it.
The verdict establishes authenticity and expiry. It does not consult revocation and cannot — there is no published revocation list. The page says so on every result.
Interop, made concrete
On the signing and conformance-vector path, the Rust, Python and TypeScript reference SDKs reproduce the same SHA-256 digest and the same Ed25519 signature from the same fixed inputs, with no shared runtime between them. That frozen vector – the one this demo just checked – is the interoperability guarantee, proven rather than claimed.
Scope is a statement
The open standard now includes the signing and verification contract and an open reference mint – issuance, delegation and attenuation. What stays commercial is the hosted authority that would run a mint in production: durable revocation, KMS-backed keys and the durable, hash-chained audit-of-record, plus the policy language for what a VAID may do and the mesh and federation control plane. A control plane routes, enforces and mediates between organisations at runtime. Verifying a chain across them needs nothing operated at all. The reference mint proves the shape; it is not that authority. "Hosted authority" names the aggregate of those durable pieces – it is not a separate component that exists today, and the audit and revocation seams are already open in the mint.
In detail
Here's precisely what that signature covers – the exact payload, canonicalization and headers the demo just verified, and the guarantees they buy.
Cryptographically signed
The action's proof is checked, not asserted. A verifier checks one Ed25519 signature over the canonical request – no trust in the sender required, only the signer's public key.
Capability-scoped
The payload binds the exact method, path and body of the action. A signature for one request is useless on any other.
Lineage-tracked
At mint time, identity and tenant are bound from the authenticated parent VAID, never from a body-asserted field – so a caller can only ever act as itself.
A holder signs a small, exact payload – seven fields, no more, no less – then attaches four headers. The signature covers the canonical bytes of that payload.
payload = { vaidId, method, path,
bodySha256, tenantId,
timestamp, clientNonce }
canonical = RFC 8785 JCS(payload)
digest = SHA-256(canonical)
signature = Ed25519(digest) # over the 32-byte digest x-synthera-vaid: base64(VAID) x-synthera-timestamp: 2026-06-04T12:00:00Z x-synthera-nonce: 0123…cdef x-synthera-signature: base64(Ed25519 sig)
vaid-mint 0.4.0, a third party holding an
issuer's kernel public key, plus the ancestor documents a presenter supplies, can walk a full
delegation chain and confirm that every child's authority falls inside its parent's: scope,
capabilities, and the qualified trust-domain and tenant pair, at every hop
– ✓ Shipped. Containment reuses the same matchers the
mint applies at issuance, so verify time cannot drift from the check that gated issuance.
It works across organisations – ✓ Shipped. A chain that crosses kernel keys additionally requires a detached consent attestation from the issuer that minted the parent, because nothing inside a VAID document otherwise proves that issuer agreed. A cross-key hop without valid consent never verifies. None of this changed the VAID document: no new field, no signature-version bump, and the frozen mint vector did not move.
What it does not do, stated because these are load-bearing. The presenter must retain and present the ancestors, so a leaf whose ancestor documents were discarded has unverifiable attenuation, and it fails closed as unverifiable rather than passing as satisfied. Full chain verification requires full chain disclosure, which is a real privacy cost and not a footnote. The walk does not consult revocation or expiry; those stay separate questions, and the reference mint's revocation is still in memory only. And consent is time-bounded rather than revocable: an issuer that changes its mind inside an attestation's window has no mechanism to withdraw it, because retraction needs durable revocation, which this implementation does not provide.
RevocationCheck seam, three-state and lineage-aware, revoking a
parent revokes its children, and it fails closed when a store is unreachable – so injecting a durable
backend replaces the in-memory default without touching anything else. Durable revocation is one of
the commercial pieces named above. Revocation also sits outside the conformance surface, so no frozen
vector polices it.
Get VAID
The reference implementation is open source under Apache-2.0. Source: github.com/solara-associates/vaid
In a coding agent — one command
vaid-skill (0.1.3) is an Agent Skill
wrapping the same published SDKs. It installs into whichever of
Claude Code, Codex, Cursor,
Gemini CLI and GitHub Copilot it finds, and gives the agent
four verbs and no more: mint issues a VAID (or, with --parent, an
attenuated child whose authority is a strict subset of yours), present packages one
into the line you send, verify checks one offline, and revoke marks one
revoked on that machine only — which is all anything can do while no revocation list is published.
npx vaid-skill
No skill, just the CLI: npx -p vaid-skill vaid --help.
More in the quickstart →
Or the SDKs directly
cargo add vaid-pop cargo add vaid-client cargo add vaid-mint
pip install vaid-pop pip install vaid-mint pip install vaid-langchain
npm install vaid-pop npm install vaid-client npm install vaid-mint
The three implementations version independently, and a fix lands only in the language that had
the defect, so installing by name gives you different
numbers – vaid-pop is 0.2.1 on crates.io,
0.2.0 on PyPI and 0.3.0 on npm today.
Byte-for-byte agreement is asserted at the frozen conformance vector, never at the version number,
and each package ships the check so you can confirm that on the artifact you actually received
rather than take it from this page. Step 03 of the quickstart →
Mint, sign, verify: the whole loop
Mint a VAID, sign a request with the key it binds, then verify both the VAID and the request against public keys alone. Nothing here calls a service. Copy either column and run it.
use base64::Engine;
use ring::rand::SystemRandom;
use ring::signature::{Ed25519KeyPair, KeyPair};
use sha2::{Digest, Sha256};
use vaid_client::RequestSigner;
use vaid_mint::{verify_vaid_authenticity, AgentClass, ReferenceIssuer, TenantId, VaidIssuer};
use vaid_pop::{request_auth::RequestAuthPayload, vaid_pop::verify_signed_payload};
fn main() {
let pkcs8 = Ed25519KeyPair::generate_pkcs8(&SystemRandom::new()).unwrap();
let agent_key = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref()).unwrap(); // the agent holds this
let issuer = ReferenceIssuer::ephemeral(24, "vaid.example").unwrap(); // your own mint
let vaid = issuer.issue_vaid_with_key(
AgentClass::new("orchestrator"), "1.0.0".into(), TenantId::new("acme"), None,
vec!["data.acme".into()], vec!["read".into()],
agent_key.public_key().as_ref().to_vec()).unwrap();
let body = br#"{"query": "select 1"}"#;
let signer = RequestSigner::from_vaid_json(&serde_json::to_vec(&vaid).unwrap(), agent_key).unwrap();
let headers = signer.sign_headers("POST", "/query", body).unwrap();
// Verifier side: public keys and the request. No call to the mint.
let payload = RequestAuthPayload {
vaid_id: vaid.vaid_id(), method: "POST".into(), path: "/query".into(),
body_sha256: hex::encode(Sha256::digest(body)), tenant_id: vaid.tenant_id().as_str().into(),
timestamp: headers.timestamp.parse().unwrap(), client_nonce: headers.nonce.clone(),
};
let sig = base64::engine::general_purpose::STANDARD.decode(&headers.signature).unwrap();
println!("vaid authentic: {}", verify_vaid_authenticity(issuer.kernel_public_key(), &vaid));
println!("request signed by holder: {}", verify_signed_payload(&payload, vaid.public_key_der(), &sig));
} import base64, hashlib from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey from vaid_mint import ReferenceIssuer, verify_vaid_authenticity from vaid_pop import RequestSigner, build_request_auth_payload, verify_signed_payload agent_key = Ed25519PrivateKey.generate() # the agent holds this issuer = ReferenceIssuer.ephemeral(24, "vaid.example") # your own mint vaid = issuer.issue_vaid_with_key( agent_class="orchestrator", version="1.0.0", tenant_id="acme", parent_vaid=None, scope_boundary=["data.acme"], capability_set=["read"], public_key_der=agent_key.public_key().public_bytes_raw()) body = b'{"query": "select 1"}' headers = RequestSigner(vaid=vaid, private_key=agent_key).sign_headers("POST", "/query", body) # Verifier side: public keys and the request. No call to the mint. payload = build_request_auth_payload( vaid_id=vaid["vaid_id"], method="POST", path="/query", body_sha256=hashlib.sha256(body).hexdigest(), tenant_id=vaid["tenant_id"], timestamp=headers["x-synthera-timestamp"], client_nonce=headers["x-synthera-nonce"]) signature = base64.b64decode(headers["x-synthera-signature"]) print("vaid authentic:", verify_vaid_authenticity(issuer.kernel_public_key(), vaid)) print("request signed by holder:", verify_signed_payload(payload, vaid["public_key_der"], signature))
Both print vaid authentic and request signed by holder as true, in each language's own casing. Run the full quickstart →
SYNTHERA is the trust layer for multi-agent systems: every agent gets a verifiable identity, scoped authority and a tamper-evident record, so software from different teams, vendors and frameworks can act on each other’s behalf without custom glue between every pair.
Join the first cohort shaping the VAID spec.
VAID is an interoperability contract. If you're building on agent identity, help shape the standard as it evolves.