Skip to content
ElectricElectric
PricingBlog
Main Navigation
Go to Cloud
Cloud
Go to Cloud
On this page

← Blog

Electric Agents 0.5

By Sam Willis

Are you an LLM? You can read better optimized documentation at /blog/2026/06/11/electric-agents-0-5-from-runtime-to-app.md for this page in Markdown format

Electric Agents 0.5 is out today. It rounds out the platform we launched in April, where agents are durable, addressable streams, with a broader SDK and runtime surface for building agentic systems.

The release gives you the runtime and SDK primitives: long-lived entities, StreamDB state, local and remote runners, spawning and forking, wakes, signals, schedules, self-sends, app APIs, and multi-agent coordination patterns. We are also building the first Electric Agents desktop and mobile apps: in-development devtools and demo surfaces for inspecting, controlling, and dogfooding agent systems. You can download canary builds from GitHub releases or build them yourself from source. Managed Agents servers in Electric Cloud are coming soon.

Get started with Electric Agents

Run the Quickstart, read the docs, watch the demos in this post, or revisit the original Electric Agents launch post.

What changed since April ​

The April launch introduced the model: agents as durable, addressable streams of state. This release fills out the surface area around that model:

  • Core APIs. Define agents, run them on runners, wake them from events, spawn children, fork history, signal active work, schedule future work, and build app surfaces on top.
  • Apps in development. The new desktop and mobile apps show what those surfaces look like: devtools for inspecting and operating agent systems built on the SDK.
  • Cloud next. Managed Agents servers in Electric Cloud are coming soon, with hosted coordination and user-owned compute.
  • Background. For the deeper context, read the April launch post, agents as data primitives, StreamDB, forking durable streams, and durable sessions for collaborative AI.

The Electric Agents stack ​

The stack starts with durable data and builds up to agents, runners, and application surfaces. 0.5 expands the runtime and SDK surface on top of that stack. The new in-development desktop and mobile apps show how the same state model can be used for devtools and product workflows.

Electric Agents stack: Durable Streams, StreamDB, TanStack DB, Agents runtime, and Agents apps.

At the base are Durable Streams: append-only logs that store what happened. StreamDB projects those events into typed, live state. TanStack DB gives those projections a query layer for filtering, joins, aggregation, and materialized client state.

The Agents runtime sits on top of that data layer. It provides the control plane for entities: messaging, scheduling, wakes, retry, permissions, signals, child coordination, and runner dispatch. Agents servers coordinate work; runners do the compute. A runner can live on your laptop, in your infrastructure, in CI, or in another worker environment you control.

The Agents apps are the top layer we are now starting to show: desktop and mobile surfaces for devtools, coding-agent workflows, remote control, and our own dogfooding. Because coordination and compute are separate, you can start a coding session on your machine, leave the runner there, then open the same session from your phone to send a follow-up, stop it, or ask it to fix something.

Managed Agents servers in Electric Cloud are coming soon. The 0.5 runtime is built around the same local/remote runner model: hosted coordination, user-owned compute.

Every entity is a StreamDB ​

In Electric Agents, the agent is the durable entity, not the process currently handling it.

  • An Electric Agents entity is a long-lived, addressable thing: an assistant, worker, coding session, support ticket, lead researcher, orchestrator, monitor, or any agent type you define.
  • Every entity has a durable stream, which is the log of what happened.
  • Every entity also has a typed StreamDB projection. That projection gives you live state: timeline, inbox, runs, tool calls, context, errors, children, signals, and custom collections.
  • The process that handles a wake can come and go. The entity persists. It can sleep, wake, replay, fork, spawn children, and be observed by apps or other agents.
Entity: /assistant/helper
handler.ts
1registry.define("assistant", {
2 async handler(ctx) {
3 ctx.useAgent({
4 systemPrompt: "You are a helpful assistant.",
5 model: "claude-sonnet-4-5-20250929",
6 tools: [calculatorTool, ...ctx.darixTools],
7 })
8 await ctx.agent.run()
9 },
10})
Stream
sleeping — zero compute

Every agent is fully introspectable. The stream is a complete audit trail — what you see above is the actual data model.

Demos and videos ​

Forking and spawning ​

Show the difference between spawning a fresh child and forking an entity with parent history.

Every agent is a StreamDB ​

Show the inspector or timeline/state view: the same entity as messages, runs, tool calls, state, children, and stream rows.

Multiple layers of spawning ​

Use James' demo or another nested agent tree to show parent -> child -> grandchild coordination.

Local vs remote runners ​

Show a local runner doing the work while another client observes or controls the same session.

Signals quick tour ​

Show SIGINT, pause/resume, kill, and handler-level signals from CLI or app.

PG sync triggers ​

Show a Postgres change triggering an agent through sync/event plumbing.

Send to self and cron ​

Show an agent scheduling its own future work or waking itself to continue.

Multi-agent patterns ​

Show blackboard/shared state, orchestrator/worker, reactive observers, or map-reduce.

Core APIs ​

Define ​

Define entity types with schemas, handlers, permissions, and tools. This is where you decide what kind of long-lived thing exists in the system, what state it owns, and what code runs when it wakes. SDK

ts
const registry = createEntityRegistry()

registry.define("assistant", {
  description: "A project-aware assistant",
  state: {
    notes: {
      schema: z.object({ id: z.string(), text: z.string() }),
      primaryKey: "id",
    },
  },
  async handler(ctx) {
    // ...
  },
})

Run ​

Run an agent loop that persists runs, text, reasoning, tool calls, and errors to the entity stream. The handler can do normal application work before or after the LLM loop; ctx.useAgent() and ctx.agent.run() record the agent trace. See writing handlers and configuring the agent loop. Runtime

ts
async handler(ctx) {
  ctx.useAgent({
    systemPrompt: "You are a helpful assistant.",
    model: "claude-sonnet-4-6",
    tools: [...ctx.electricTools, searchDocsTool],
  })

  await ctx.agent.run()
}

Spawn ​

Spawn a fresh child entity without parent history. Use this for workers, fan-out, and multi-layer agent trees where the parent wants another entity to own a separate stream of work. See spawning and coordinating. SDK

ts
const worker = await ctx.spawn(
  "worker",
  "audit-docs",
  { tools: ["read", "search"] },
  {
    initialMessage: "Audit the docs for missing release notes.",
    wake: { on: "runFinished", includeResponse: true },
  }
)

Fork ​

Fork an entity with history. Use this when you want a second path through the same session. The fork keeps the useful context and branches the durable stream, so you can try another approach without overwriting the original. See spawning and coordinating. Runtime App

ts
const fork = await ctx.forkSelf("variant-a", {
  initialMessage: { text: "Try the shorter implementation path." },
  tags: { branch: "variant-a" },
})

Send ​

Send messages to any entity. Because messages are durable inbox entries, the same API works for user input, parent-to-child steering, and send-to-self continuation after a delay. SDK

ts
await ctx.send(
  "/worker/audit-docs",
  { files: ["website/docs/agents/index.md"] },
  { type: "review_request" }
)

await ctx.send(
  ctx.entityUrl,
  { step: "continue-after-indexing" },
  { type: "self", afterMs: 60_000 }
)

Wake ​

Wake entities from inbox messages, child completion, state changes, cron, future sends, event sources, and Postgres sync triggers. Wakes are how agents scale to zero: no process has to stay alive just to notice that something changed. See waking entities. Runtime

ts
await ctx.observe(entity("/worker/audit-docs"), {
  wake: { on: "runFinished", includeResponse: true },
})

await client.registerWake({
  subscriberUrl: "/monitor/docs",
  sourceUrl: "/worker/audit-docs/main",
  condition: { on: "change", collections: ["runs", "texts"] },
})

Observe ​

Observe entities, shared state, entity lists, timelines, and child state in real time from handlers or apps. Observing loads the target stream into a typed local DB. Those collections can drive UI, coordination logic, or debugging tools. Use the runtime client and React client APIs. SDK App APIs

ts
const client = createAgentsClient({ baseUrl: "http://localhost:4437" })
const db = await client.observe(entity("/assistant/release-post"))

console.log(db.collections.texts.toArray)

Schedule ​

Schedule work with cron and future sends. Agents can sleep until the next scheduled wake. Recurring jobs and delayed follow-ups live in the entity's durable manifest, not in an external timer you have to reconcile. Runtime

ts
await client.upsertCronSchedule({
  entityUrl: "/assistant/release-post",
  id: "daily-checkin",
  expression: "0 9 * * *",
  timezone: "Europe/London",
  payload: "Review open launch tasks.",
})

await client.upsertFutureSendSchedule({
  entityUrl: "/assistant/release-post",
  id: "follow-up",
  fireAt: new Date(Date.now() + 60_000).toISOString(),
  payload: "Continue after the preview build finishes.",
})

Signal ​

Signal running agents: interrupt, pause, resume, kill, or deliver handler-level lifecycle signals. Signals give apps and operators a control plane for active work without treating the agent as an opaque process. See the signals guide and CLI reference. Runtime CLI App

ts
await client.signalEntity({
  entityUrl: "/horton/release-post",
  signal: "SIGINT",
  reason: "User wants to redirect the current run.",
})

Coordinate ​

Coordinate with shared state and multi-agent patterns such as orchestrator/worker, blackboard, reactive observers, map-reduce, and pipelines. Coordination is explicit state and explicit streams, so parent agents, child agents, and UI clients can inspect the work. SDK

ts
const board = ctx.mkdb("release-board", {
  tasks: {
    schema: z.object({ id: z.string(), status: z.string() }),
    type: "shared:task",
    primaryKey: "id",
  },
})

board.tasks.insert({ id: "screenshots", status: "needed" })

const reviewer = await ctx.spawn("worker", "reviewer", {})
await ctx.observe(entity(reviewer.entityUrl), {
  wake: { on: "change", collections: ["texts"] },
})

Connect ​

Connect external tools and systems with MCP servers, event-source subscriptions, webhooks, and PG sync-driven triggers. Agents can subscribe to operational systems and wake when those systems change. Runtime

ts
await client.subscribeToEventSource({
  entityUrl: "/horton/release-post",
  id: "github-pr",
  sourceKey: "github",
  bucketKey: "repo",
  params: { repo: "electric-sql/electric" },
  lifetime: { kind: "until_entity_stopped" },
})

const todos = await client.observe(
  pgSync({ table: "todos", where: "project_id = $1", params: ["agents"] })
)

Inspect ​

Inspect every entity as a StreamDB: timeline, inbox, runs, tool calls, child status, errors, signals, attachments, and custom collections. The runtime exposes these as TanStack DB collections, so app code can query the agent's state instead of scraping logs. See the built-in collections reference and the TanStack DB query docs. App APIs App

ts
import { eq, queryOnce } from "@durable-streams/state/db"

const db = await client.observe(entity("/horton/release-post"))

const runs = await queryOnce((q) => q.from({ run: db.collections.runs }))

const toolCalls = await queryOnce((q) =>
  q.from({ toolCall: db.collections.toolCalls })
)

const attachments = await queryOnce((q) =>
  q
    .from({ manifest: db.collections.manifests })
    .where(({ manifest }) => eq(manifest.kind, "attachment"))
)

Apps in development ​

The desktop and mobile apps are in development. We are using them to dogfood the SDK and runtime, and to build toward our own software factory: agents that shepherd PRs and issues, keep work moving, and let everyone connect to the same durable session.

  • Custom agent types: build entities with @electric-ax/agents-runtime and inspect them in the desktop app.
  • State explorer: see each entity's runs, inbox, manifests, and custom state in one view.
  • Entity timeline: replay a run event by event, then fork from a point in the timeline to try another path.
  • Cloud or self-hosted: use Electric Cloud when available, or point the app at an agents-server you run yourself.
  • Remote sessions: open sessions started by CI, webhooks, issues, cron, or another machine.
  • MCP servers: add MCP servers with native OAuth. Workspace mcp.json files are respected.
  • Model providers: use an API key from your keychain, or sign in to Codex. Anthropic, OpenAI, DeepSeek, and Moonshot are supported.
  • Skills and slash commands: use /quickstart to get started, then save commands for your workflows.
  • Phone handoff: open a run on iOS or Android to steer it, send a message, or check progress.
  • Desktop workflow extras: pick a working directory, split the tile workspace, attach files and screenshots to chat, discover local dev servers, and install the electric CLI system-wide.

You can download app canaries from GitHub releases, or build the apps yourself from the repo.

How to try it ​

Run the quickstart from the CLI:

sh
npx electric-ax agents quickstart

Open the UI, spawn Horton, send a message, and watch the timeline update as the agent thinks, calls tools, and responds.

Then define your own entity type and connect it to the same runtime and apps:

ts
import {
  createEntityRegistry,
  createRuntimeHandler,
} from "@electric-ax/agents-runtime"

const registry = createEntityRegistry()

registry.define("assistant", {
  description: "A general-purpose AI assistant",
  async handler(ctx) {
    ctx.useAgent({
      systemPrompt: "You are a helpful assistant.",
      model: "claude-sonnet-4-6",
      tools: [...ctx.electricTools],
    })

    await ctx.agent.run()
  },
})

export const runtime = createRuntimeHandler({
  baseUrl: process.env.ELECTRIC_AGENTS_URL ?? "http://localhost:4437",
  serveEndpoint: "http://localhost:3000/webhook",
  registry,
})

Once registered, assistant appears as an entity type in the app. Spawn /assistant/my-agent, send it a message, and use the same timeline, state, and devtools surfaces that Horton uses.

Coming next ​

  • Managed Agents servers in Electric Cloud.
  • More examples and docs for app builders: PG sync triggers, event sources, MCP, attachments, sandbox profiles, and multi-agent patterns.
  • More app development polish: desktop builds, smoother downloads and updates, and richer mobile distribution.

Next steps ​

  • Run npx electric-ax agents quickstart.
  • Read the Electric Agents docs.
  • Watch the demos in this post.
  • Download app canaries from GitHub releases, or build them from source.
  • Join the Electric Discord and tell us what you build.

ElectricElectric

AboutContactLegalDocsDemosBlogSign up
TanStack DBPGliteXBlueskyDiscordGitHub

© 2026 Electric DB Inc. Released under the Apache 2.0 License.

✨ Markdown