Protocol ideas become much easier to reason about once they are visible in code.
SAL, the Sovereign Agent Lifecycle Protocol, is still evolving, but the basic flow is straightforward enough to show in a small TypeScript sketch: an agent generates its own keypair, initializes into orphan state, proves possession through challenge-response, and later requests short-lived scoped access.
The public spec is at sal-protocol.dev, and the reference implementation is in Vibebase.
This is not production code. It is a minimal illustration of the shape.
1. Agent birth
At birth, the agent creates its own Ed25519 keypair locally.
import { generateKeyPairSync, sign } from "node:crypto";
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
That private key stays with the agent. No human has to provision a shared secret for this identity to exist.
2. Initialization into orphan state
The agent signs an initialization payload and submits it to the control plane.
const initRequest = {
public_key: "ed25519:example-public-key",
display_name: "planner-agent",
capabilities: ["plan", "read_docs"],
nonce: crypto.randomUUID(),
};
{
"success": true,
"data": {
"request": {
"public_key": "ed25519:example-public-key",
"display_name": "planner-agent",
"capabilities": ["plan", "read_docs"],
"nonce": "f0f4ecb4-e954-4c82-b7bc-bfd5829ab7cb",
"signature": "sig:agent-init"
}
}
}
And the response:
{
"success": true,
"data": {
"agent_id": "agt_01JZTS",
"state": "orphan",
"grants": [
{
"scope": "workspace:bootstrap",
"ttl_seconds": 300
}
]
}
}
That gives the agent a constrained starting point without requiring a human login flow.
3. Challenge-based token request
When the agent needs scoped service access, it first requests a challenge.
{
"success": true,
"data": {
"challenge": {
"id": "chl_01JZTT",
"nonce": "ec0ed404-c6d3-4cda-9cd2-8215ea3927ea",
"expires_at": "2026-07-28T09:05:00Z"
}
}
}
It signs that nonce with its private key and submits the proof:
const proof = sign(
null,
Buffer.from("ec0ed404-c6d3-4cda-9cd2-8215ea3927ea"),
privateKey
);
If policy allows the requested action, the gateway returns a short-lived scoped token:
{
"success": true,
"data": {
"token": {
"value": "eyJhbGciOiJFZERTQSJ9...",
"scope": ["task:append"],
"ttl_seconds": 300
}
}
}
4. Why this shape matters
Three things are happening here that are easy to miss if you are used to API key workflows.
First, the agent identity is self-generated rather than provisioned by a human.
Second, the proof of possession is fresh. The system is not trusting a copied static secret that might have been sitting in an environment variable for months.
Third, the service token is separate from the root agent identity and deliberately narrow in scope and lifetime.
That is the design center of SAL.
5. Where to go deeper
The minimal flow above leaves out claim handshake and lineage, which are where the protocol gets more interesting in real deployments. But even this small sketch shows the basic difference between SAL and conventional software auth patterns.
The goal is not just to authenticate software. The goal is to support an actual lifecycle for autonomous agents: birth, orphan state, claim, delegation, and scoped service access.
If you want the full model, the protocol is at sal-protocol.dev, and the running implementation is in Vibebase docs. If you have built a similar flow another way, I would love to compare notes, because this is exactly the kind of area where implementation pressure makes the protocol better.
Top comments (0)