Release May 25, 2026 · 10 min read

ElsiumAI 0.15.0: Cryptographic Receipts, Capability Tokens, and Time-Travel Replay

An agent runtime needs more than tool calls. It needs provenance — cryptographic evidence of what happened, scoped permissions that can be revoked, and the ability to rewind a failed run. ElsiumAI 0.15.0 ships all three as first-class primitives.

This release is the biggest single jump in the framework’s surface area: a complete Ed25519 cryptographic foundation, OAuth-style capability tokens with delegation and revocation, typed tool call streams, cost-aware cascade routing, tool contracts, durable human-in-the-loop, and time-travel replay. Eight orthogonal primitives, each independently useful, that compose into a runtime you can trust in production.


What shipped

CapabilityWhat it gives you
Ed25519 crypto foundationSigner / Verifier / KeyRegistry / WriteOnceStore in @elsium-ai/core. Substrate for everything else.
Capability TokensEd25519-signed, scoped, time-bound tokens that gate tools, LLMs, MCP servers, RAG stores, and data classes. Delegation + revocation built in.
withToolTypes streamsWraps any stream and emits per-tool-typed tool_call_complete events with Zod-validated arguments.
Thinking / reasoning eventsTyped thinking_start / delta / end stream events. Anthropic extended thinking + OpenAI reasoning effort.
CARG cascade routerStart cheap, escalate only when validator fails, confidence drops, or a classifier predicts the tier won’t handle it.
Tool contractssideEffectLevel + idempotencyKey + preconditions + dryRunHandler. Safety properties the framework can reason about.
askHumanDurable human-in-the-loop. Responder mode for synchronous flows; store-backed mode that survives process restarts.
replayFromRecord every step of an agent run, then re-execute from any midpoint with selective overrides.

1. Ed25519 Crypto Foundation

The release starts with primitives, not features. @elsium-ai/core/crypto ships an Ed25519 signer/verifier backed by node:crypto, a KeyRegistry with validity windows, and a WriteOnceStore port whose file adapter uses O_EXCL for atomic write-once semantics:

import {
  createEd25519Signer,
  createKeyRegistry,
  createFileWriteOnceStore,
  generateEd25519KeyPair,
} from '@elsium-ai/core'

const pair = generateEd25519KeyPair()
const signer = createEd25519Signer({ privateKey: pair.privateKey, keyId: 'org-k1' })

const registry = createKeyRegistry({
  trustRoots: [{ keyId: 'org-k1', publicKey: pair.publicKey }],
})

const store = createFileWriteOnceStore({ dir: './proofs' })

This isn’t a feature you call directly very often. It’s the substrate that makes everything else in the release possible — signed execution proofs, capability tokens, signed replay logs, audit trail signing. By giving the framework a single, vetted crypto module, the higher-level primitives stay small and focused.


2. Capability Tokens — OAuth for AI Agents

Capability tokens are the headline feature of 0.15.0. Mint an Ed25519-signed token that declares exactly what an agent run is allowed to touch: which tools (with field-level constraints), which LLM providers (with cost/token budgets), which MCP servers, which RAG stores, which data classes. Every guarded execution point verifies the token before doing work — signature, validity window, scope, optional revocation.

import {
  createCapabilityIssuer,
  createCapabilityVerifier,
  createEd25519Signer,
  createKeyRegistry,
  createInMemoryRevocationStore,
} from '@elsium-ai/core'

const issuer = createCapabilityIssuer({ signer, orgId: 'aperion' })

const token = issuer.mint({
  subject: { agent: 'support-bot', runId: 'run_xyz' },
  capabilities: [
    { kind: 'tool', name: 'customer.read', constraints: { allowedFields: ['name', 'email'] } },
    { kind: 'llm',  provider: 'anthropic', maxCost: 0.5, maxTokens: 50_000 },
    { kind: 'mcp',  server: 'github', tools: ['issues.list'] },
    { kind: 'rag',  stores: ['kb-public'], maxResults: 10 },
  ],
  dataClasses: { allowed: ['public', 'internal'], denied: ['pii', 'financial'] },
  ttlMs: 60 * 60 * 1000,
})

All four guards (tool / LLM / MCP / RAG) accept the same shape { token, verifier?, onDeny? }. Denials fire onDeny for audit and either throw ElsiumError(AUTH_ERROR) or return { success: false }:

import { withCapability } from '@elsium-ai/tools'
import { capabilityMiddleware } from '@elsium-ai/gateway'
import { createCapabilityGuardedMCPClient } from '@elsium-ai/mcp'
import { withRagCapability } from '@elsium-ai/rag'

const guardedTool = withCapability(myTool, { token, verifier })
const llm = gateway({ provider: 'anthropic', apiKey: '...', middleware: [capabilityMiddleware({ token, verifier })] })
const guardedMcp = createCapabilityGuardedMCPClient(mcpClient, { token, server: 'github', verifier })
const guardedRag = withRagCapability(ragPipeline, { token, verifier, store: 'kb-public' })

Delegation creates strict-subset child tokens for sub-agents (tool deniedFields inherited, LLM maxCost/maxTokens ≤ parent, MCP allowlists ⊆ parent, child expiresAt ≤ parent). Revocation uses a pluggable RevocationStore — pass it to the verifier and call verifyTokenAsync to consult it. Revocation is eventually consistent: in-flight calls that already passed verification continue, so document it in your runbook.

The full surface is in Capability Tokens.


3. Typed Streams: withToolTypes + Thinking Events

Two stream improvements that pair well together. withToolTypes(stream, schemas) wraps any stream, accumulates the raw tool_call_delta JSON fragments per toolCallId, validates against your Zod schemas on tool_call_end, and emits a typed tool_call_complete event whose toolCall.arguments is narrowed by tool name:

import { withToolTypes } from '@elsium-ai/core'

const schemas = {
  get_weather: z.object({ city: z.string(), unit: z.enum(['C', 'F']).optional() }),
  search: z.object({ query: z.string(), limit: z.number().int().positive() }),
}

for await (const event of withToolTypes(llm.stream({ ... }), schemas)) {
  if (event.type === 'tool_call_complete' && event.toolCall.name === 'get_weather') {
    const { city, unit } = event.toolCall.arguments // fully typed from Zod
  }
}

The thinking event support is symmetrical — StreamEvent now includes thinking_start / thinking_delta / thinking_end variants. Opt in via thinking on the CompletionRequest; the gateway translates it into Anthropic’s thinking: { type: 'enabled', budget_tokens } or OpenAI’s reasoning_effort. Render reasoning in a side panel without polluting the main text stream.


4. CARG — Cost-Aware Cascade Routing

CARG is the third leg of the operational triad — VAG says wrong, CAG says uncertain, CARG says expensive. createCascadeRouter routes to the cheapest tier first and escalates on provider error, validator failure, low confidence, or a classifier-decided difficulty cap:

import { createCascadeRouter, createHeuristicClassifier } from '@elsium-ai/gateway'

const router = createCascadeRouter(
  {
    tiers: [
      { name: 'haiku',  provider: 'anthropic', model: 'claude-haiku-4-5-20251001', maxDifficulty: 0.4 },
      { name: 'sonnet', provider: 'anthropic', model: 'claude-sonnet-4-6',         maxDifficulty: 0.8 },
      { name: 'opus',   provider: 'anthropic', model: 'claude-opus-4-7' },
    ],
    classifier: createHeuristicClassifier(),
    escalateOnFailure: { onProviderError: true, maxEscalations: 2 },
  },
  { apiKeys: { anthropic: process.env.ANTHROPIC_API_KEY! } },
)

const result = await router.complete({ messages: [...] })
// result.tier — which tier served. result.attempts — per-tier audit.

Two built-in classifiers ship: createHeuristicClassifier() (zero-cost, keyword + size scoring) and createLLMClassifier({ complete }) (asks a cheap model). Implement the LLMClassifier interface for custom logic.


5. Tool Contracts — Run Handler, Hope Becomes Reason

Four new fields on ToolConfig turn a tool from “run handler, hope” into something the framework can reason about for safety:

import { defineTool, createInMemoryIdempotencyStore } from '@elsium-ai/tools'

const transferTool = defineTool({
  name: 'transferFunds',
  input: z.object({ txId: z.string(), amount: z.number().positive(), to: z.string() }),
  sideEffectLevel: 'destructive',
  idempotencyKey: (i) => i.txId,
  idempotencyStore: createInMemoryIdempotencyStore(),
  preconditions: [
    { name: 'hasBalance', check: async (i) => ({ ok: balanceOf(i.from) >= i.amount, reason: 'insufficient' }) },
  ],
  dryRunHandler: (i) => ({ ok: true, ref: `PREVIEW:${i.txId}` }),
  handler: async (i) => bank.transfer(i),
})

await transferTool.execute(input, { dryRun: true })  // skips handler, returns preview
await transferTool.execute(input)                    // first call runs
await transferTool.execute(input)                    // second call: idempotent cache hit, no double-charge

The framework can now answer questions a plain handler can’t: is this safe to dry-run? has this already executed? are the preconditions met? All declared per-tool, all enforced before the handler runs.


6. askHuman — Durable Human-in-the-Loop

Most agent demos don’t survive a deploy. askHuman ships two modes — a synchronous responder for in-process flows, and a store-backed durable mode that survives process restarts. Paired with the existing async task store, the agent state itself can pause for hours or days while waiting for a human:

import { askHuman, createInMemoryAskHumanStore, resolveAskHuman } from '@elsium-ai/agents'

const store = createInMemoryAskHumanStore()

const decision = await askHuman({
  requestId: 'req-42',
  question: 'Approve $1,200 refund?',
  options: ['approve', 'deny'] as const,
  store,
  timeoutMs: '7d',
})

// Elsewhere — webhook / dashboard / CLI — once a human responds:
await resolveAskHuman(store, 'req-42', {
  status: 'approved',
  option: 'approve',
  decidedBy: 'reviewer@example.com',
})

timeoutMs accepts a number or a duration string ('5s', '2m', '1h', '7d'). Bad suffix throws CONFIG_ERROR. onTimeout: 'reject' | 'timeout' controls the resulting status when the deadline passes.


7. replayFrom — Time-Travel Replay

An agent fails in production. You have a recording. You want to swap one prompt halfway through the run and see the downstream change — without re-paying for the upstream LLM calls. That’s replayFrom:

import { createTraceRecorder, replayFrom } from '@elsium-ai/testing'

const recorder = createTraceRecorder({ agentId: 'news-bot' })
// ... wrap your pipeline so each step recorder.recordStep({ key, input, output, durationMs })
const trace = recorder.finish()

const result = await replayFrom(trace, {
  fromStep: 'summarize',
  executor: async ({ key, input }) => runStep(key, input),
  overrides: {
    research:  { kind: 'transform', input: (i) => ({ ...i, query: 'tweaked query' }) },
    summarize: { kind: 'replace', output: { bullets: ['pinned'] } },
  },
})

Steps before fromStep are served from the recording; from fromStep onwards, your executor runs live with overrides applied. Each ReplayedStep reports source: 'replay' | 'live' and overridden: boolean so the Dev Studio can render a diff.

In 0.16.0, this primitive becomes an agent method so every agent.run() auto-records and every agent gets replayFrom() for free. More on that in the next post.


Putting it together

The point of shipping eight primitives in one release isn’t to dump features — it’s that they compose. A single invoice-extraction agent can now:

  1. Receive a capability token scoped to one tool, one LLM provider, $0.50 of spend, and a 1-hour TTL.
  2. Pass through CARG: classifier predicts low difficulty → route to Haiku tier. If VAG fails, escalate to Sonnet.
  3. Stream typed tool calls + reasoning events to the UI.
  4. Hit a destructive tool that requires idempotency, preconditions, and dry-run preview.
  5. Pause on askHuman({ timeoutMs: '7d' }) when a human approval is needed — the task survives restarts.
  6. Emit a signed execution proof anyone can verify offline with just the public key.
  7. Record every step. If the run fails, replayFrom rewinds to the failing iteration with a swapped prompt.

None of these are libraries you have to choose between. They share types, share semantics ({ token, verifier?, onDeny? } is the same shape everywhere), and share the same audit pipeline.


Getting Started

npm install elsium-ai@0.15.0

Or scaffold a new project:

npx elsium init my-agent
cd my-agent
npx elsium dev

Full documentation: Capability Tokens · Tool Contracts · CARG · Thinking events · Verifiable Execution


ElsiumAI is MIT licensed and open source. Created by Eric Utrera (@ebutrera9103).

E

Eric Utrera

Creator of ElsiumAI. Building production AI infrastructure.