Skip to content

clawdreyhepburn/ovid

Repository files navigation

🪪 OVID

Cryptographic identity for AI agents.

Ed25519 signed JWTs with delegation chains — tells you exactly who a sub-agent is, who created it, and when it expires.

The ProblemHow It WorksQuick StartAPIMandate EvaluationSecurity GuideFAQ


The Problem

When an AI agent spawns a sub-agent, the sub-agent inherits everything — API keys, credentials, tool access, filesystem. The code reviewer has a credit card. The browser worker can send tweets. The research agent can read every file on the machine.

This is ambient authority, and it's the same mistake we made with Unix root shells, shared browser cookies, and unsandboxed containers. The fix has always been the same: explicit, attenuated credentials.

OVID gives every sub-agent its own identity document — a signed JWT that says who it is, what mandate it carries, who created it, and when it expires. The spawning agent signs it. The chain is verifiable back to the human.

Read more: Your Sub-Agents Are Running With Scissors

How It Works

Human (root of trust)
  │
  │ delegates authority to
  ▼
Primary Agent (long-lived, has keypair)
  │
  │ issues OVID to
  ▼
Sub-Agent (ephemeral, carries OVID JWT with Cedar mandate)
  │
  │ can issue derived OVID to
  ▼
Sub-Sub-Agent (shorter lifetime, auditable chain)

Four principles:

  1. The spawner is the attestor. You trust a sub-agent because you trust the thing that created it — and that trust is cryptographically verifiable.
  2. Lifetime can only shorten. A child's OVID can't outlive its parent's. When the parent expires, everything downstream expires.
  3. Identity is self-contained. An OVID carries everything needed for verification. No database. No central server. No network calls.
  4. The chain is the proof. Each OVID embeds its full parent chain. Walk it back to the root and verify every signature.

Quick Start

Install

npm install @clawdreyhepburn/ovid

Issue an OVID

import { generateKeypair, createOvid } from '@clawdreyhepburn/ovid';

// Primary agent creates a keypair (do this once, persist it)
const primaryKeys = await generateKeypair();

// Spawn a sub-agent with a signed identity and Cedar mandate
const reviewer = await createOvid({
  issuerKeys: primaryKeys,
  issuer: 'clawdrey',
  mandate: {
    rarFormat: 'cedar',
    policySet: 'permit(principal, action == Ovid::Action::"read_file", resource);',
  },
  ttlSeconds: 1800, // 30 minutes
});

console.log(reviewer.jwt);                // standard JWT string
console.log(reviewer.claims.mandate);      // Cedar policy set
console.log(reviewer.claims.parent_chain); // []

Verify an OVID

import { verifyOvid } from '@clawdreyhepburn/ovid';

const result = await verifyOvid(reviewer.jwt, primaryKeys.publicKey);

if (result.valid) {
  console.log(result.principal);  // "clawdrey/agent-7f3a"
  console.log(result.mandate);    // { rarFormat: 'cedar', policySet: '...' }
  console.log(result.chain);      // []
  console.log(result.expiresIn);  // seconds until expiry
}

Delegation chains

Sub-agents can issue OVIDs to their own sub-agents:

const helper = await createOvid({
  issuerKeys: reviewer.keys,
  issuerOvid: reviewer,
  mandate: {
    rarFormat: 'cedar',
    policySet: 'permit(principal, action == Ovid::Action::"read_file", resource);',
  },
  ttlSeconds: 600, // shorter than parent ✅
});

console.log(helper.claims.parent_chain); // ["clawdrey/agent-7f3a"]

API

generateKeypair(): Promise<KeyPair>

Generates an Ed25519 keypair using the Web Crypto API.

exportPublicKeyBase64(key: CryptoKey): Promise<string>

Exports a public key as a base64url string.

createOvid(options: CreateOvidOptions): Promise<OvidToken>

Issues a new OVID JWT.

Option Type Required Default Description
issuerKeys KeyPair yes Issuing agent's keypair
issuerOvid OvidToken no Parent's OVID (omit for root)
mandate CedarMandate yes Cedar policy set
issuer string no Issuer ID
agentId string no auto Unique agent ID
ttlSeconds number no 1800 Time to live
kid string no Key ID for JWT header

verifyOvid(jwt, issuerPublicKey, options?): Promise<OvidResult>

Verifies an OVID JWT's signature and claims. Returns { valid, principal, mandate, chain, expiresIn }.


Mandate Evaluation

Looking for Cedar policy evaluation, enforcement, audit logging, and a forensics dashboard?

See @clawdreyhepburn/ovid-me (OVID Mandate Evaluation) — reads mandates from verified OVID tokens, evaluates tool calls against Cedar policies, provides three enforcement modes (enforce/dry-run/shadow), and includes a full audit + dashboard system.


OVID JWT Format

Header

{ "alg": "EdDSA", "typ": "ovid+jwt" }

Payload

{
  "jti": "clawdrey/agent-7f3a",
  "iss": "clawdrey",
  "sub": "clawdrey/agent-7f3a",
  "iat": 1711987200,
  "exp": 1711989000,
  "ovid_version": "0.2.0",
  "parent_chain": [],
  "agent_pub": "base64url-ed25519-public-key",
  "mandate": {
    "rarFormat": "cedar",
    "policySet": "permit(principal, action == Ovid::Action::\"read_file\", resource);"
  }
}

Development

git clone https://github.com/clawdreyhepburn/ovid.git
cd ovid
npm install
npm test        # 12 tests via vitest
npm run build   # TypeScript → dist/

Project structure

ovid/
├── src/
│   ├── index.ts       # Public API exports
│   ├── keys.ts        # Ed25519 keypair generation
│   ├── create.ts      # OVID issuance with lifetime attenuation
│   ├── verify.ts      # Signature verification and claims validation
│   └── types.ts       # TypeScript interfaces (including CedarMandate)
├── test/
│   ├── keys.test.ts
│   ├── create.test.ts
│   └── verify.test.ts
├── docs/
│   └── SECURITY.md
├── ARCHITECTURE.md
├── LICENSE
├── NOTICE
└── package.json

How OVID Fits the Stack

OVID provides identity and mandates — it tells you who a sub-agent is and what authority was delegated to it. But OVID itself doesn't enforce anything. Enforcement is handled by two complementary layers:

  1. Carapace — the deployment-level ceiling. The human defines what tools are allowed at all via Cedar policies, enforced on every before_tool_call hook. Binary allow/deny. This is the human's hard limit — no agent can exceed it regardless of what mandate it carries.

  2. OVID-ME — mandate evaluation. Reads the Cedar policy from a verified OVID token and evaluates whether the specific tool call is permitted by the parent's delegation. Three modes: enforce, dry-run, shadow.

Both must allow a tool call to proceed. Carapace gates what the human permits; OVID-ME gates what the parent delegated. A sub-agent with a broad mandate still can't exceed the deployment ceiling, and a sub-agent under a permissive deployment ceiling still can't exceed its parent's mandate.

Tool call arrives
  │
  ├─ Carapace: "Does the deployment policy allow this?" ── deny ──> blocked
  │                                                         │
  │                                                       allow
  │                                                         │
  ├─ OVID-ME: "Does the agent's mandate allow this?"  ── deny ──> blocked
  │                                                         │
  │                                                       allow
  │                                                         │
  └─ Tool executes

Related Projects

License

Copyright 2026 Clawdrey Hepburn LLC. Licensed under Apache-2.0.


OVID — OpenClaw Verifiable Identity Documents.

About

Lightweight agent identity documents. Ed25519-signed JWTs with attestation chains and scope attenuation.

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors