Docs navigation

Agent identity

Every ProofLedger agent has a registered identity — name, owner, framework, model, version — and an Ed25519 keypair. The agent signs each event with its private key; the server verifies against the registered public key. A forged or altered event fails verification and is blocked by default policy.

Registering an agent

Node.js — registerAgent()
const result = await ProofLedger.registerAgent({
  agentId: "support-agent",       // stable id used everywhere
  name: "Support Agent",
  owner: "customer-success",
  framework: "langchain",
  model: "gpt-4.1",
  version: "1.0.0",
});

// The keypair is generated IN THIS PROCESS; only the public key is sent.
// result.privateKey is returned once so you can persist it in your secret
// manager. The SDK holds it in memory and signs events automatically.

Registration is idempotent when you pass the saved key back (registerAgent({ privateKey }) / register_agent(private_key=…)): metadata updates and the identity stays the same. Once an agent has a key, ProofLedger refuses to replace it from a project API key alone. Registering with a different key returns 409 key_rotation_requires_proof, and PATCH /api/agents/:id cannot change publicKey or status. Otherwise anyone holding the API key could impersonate the agent.

Security

Private keys are never stored or logged server-side. To rotate, call rotateAgentKey() while holding the current key (the rotation is signed by it). If the key is lost, an operator can use Reset signing key on the agent's dashboard page. That clears the key, revokes outstanding authorizations, and lets the agent register a new one.

Identity across restarts

// First boot: register and persist the private key.
const { privateKey } = await ProofLedger.registerAgent();
await secrets.put("support-agent-key", privateKey);

// Every boot after: re-register with the SAME key (idempotent)...
await ProofLedger.registerAgent({ privateKey: await secrets.get("support-agent-key") });
// ...or just re-attach the identity without a network call:
ProofLedger.identifyAgent("support-agent", await secrets.get("support-agent-key"));

How signing works

For each event, the SDK signs the canonical JSON of { eventId, agentId, eventType, action, timestamp } with the agent's Ed25519 private key. The server recomputes the same canonical body and verifies. The result is stored on the event (signatureValid) and shown as a ✓ signed badge on the timeline. Signatures are byte-compatible between the TypeScript and Python SDKs.

// Verify a signature yourself — offline, no API call:
import { verifyEvent } from "@proofledger/sdk";

const ok = verifyEvent(publicKey, {
  eventId: "evt_…",
  agentId: "support-agent",
  eventType: "decision",
  action: "Refund approved under policy",
  timestamp: "2026-07-02T18:00:00.000Z",
}, signature);

Lifecycle & statuses

Agents move through active · warning · blocked · inactive · pending_approval. Unknown agents that send events are quarantined as pending_approval and raise an unknown_agent security event. Scores below 50 escalate to warning; below 30, blocked — and blocked agents fail policy for every privileged action. Operators manage status from the agent detail page or POST /api/agents/:id/block.

Agent-to-agent messages

// Signed messages between agents, verified server-side:
const { verified } = await ProofLedger.sendAgentMessage({
  fromAgent: "support-agent",
  toAgent: "billing-agent",
  content: { task: "refund ORD-123", amount: 49 },
  privateKey: supportAgentKey,
});
// verified === true only if the signature matches the sender's registered key