DEV Community

Steve Emmerich
Steve Emmerich Subscriber

Posted on

A minimal TypeScript implementation of SAL flows

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");
Enter fullscreen mode Exit fullscreen mode

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(),
};
Enter fullscreen mode Exit fullscreen mode
{
  "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"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

And the response:

{
  "success": true,
  "data": {
    "agent_id": "agt_01JZTS",
    "state": "orphan",
    "grants": [
      {
        "scope": "workspace:bootstrap",
        "ttl_seconds": 300
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

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"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

It signs that nonce with its private key and submits the proof:

const proof = sign(
  null,
  Buffer.from("ec0ed404-c6d3-4cda-9cd2-8215ea3927ea"),
  privateKey
);
Enter fullscreen mode Exit fullscreen mode

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
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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)