Back to Podcast Digest
AI Engineer1h 4m

Make your own event-sourced agent harness using stream processors — Jonas Templestein, Iterate

TL;DR

  • Jonas wants agent harnesses to be fully event-sourced, because that makes them debuggable by default — his core complaint is that most agent systems are “almost” event-sourced until some side effect disappears into traces, whereas a single append-only log with offsets makes every message, error, and tool action inspectable.

  • The whole workshop revolves around one primitive: raw events on hierarchical agent paths like a filesystem — using events.iterate.com, each stream is just YAML/JSON events with a type, payload, streamPath, and incrementing offset, and Jonas argues you can build a serious coding agent from that alone.

  • He splits agent logic into a reducer and an after-append hook to avoid replaying old side effects — reducers synchronously derive state from events, while effects like LLM calls happen later, so if your laptop sleeps and 100 events pile up, you can catch up state first instead of accidentally firing 100 stale OpenAI requests.

  • Distribution is the feature and the danger — Jonas wants plugins running on different machines, in different languages, even on the edge with public URLs, but he repeatedly notes this invites race conditions, loops, and safety issues, which is why the service already has a circuit breaker that pauses streams after bursts like 100 events/sec.

  • His most ambitious demo was also the weirdest: turning a stream into an agent by appending JavaScript as an event — the dynamic worker configured event contains a script string with a reducer and afterAppend, so a blank stream can become a ping-pong bot, or in theory a 40-line OpenAI agent, just by appending code.

  • The live workshop mostly broke, but the architectural idea still came through — Jonas and Misha fought Cursor lag, repo drift, and non-runnable examples, then openly called it a “shitty experience” and promised a follow-up video, which oddly reinforced the talk’s hacker-club vibe more than a polished product pitch would have.

The Breakdown

A workshop held together with duct tape

Jonas opens by warning everyone this will be “pure chaos”: the idea was only committed to the week before, kids were sick, the SDK got pushed “literally one minute ago,” and the session format itself kept changing because of a fire issue. That tone never really leaves — he frames the whole thing as an improvised test of whether this event-sourced agent idea is “dumb or cool.”

Why agent harnesses should be event logs all the way down

The thesis is simple: Jonas wants to build agent harnesses “purely event sourced,” which to him mostly means actually debuggable. His gripe is that current systems already behave like logs of events, but then sneak in hidden side effects you can only recover later from traces, which makes them harder to inspect and extend.

The primitive: one stream, one path, raw events

He introduces events.iterate.com, a lightweight service built that week around hierarchical agent paths, where each path just stores raw events. With curl, he posts a hello world event, shows the server-generated envelope (type, payload, streamPath, offset, timestamp), and then tails the stream over SSE with live=true, basically saying: if another process answered those events, you'd already have an agent.

Errors, idempotency, schedules, and pause buttons are all just more events

A lot of the charm comes from how stubbornly consistent the model is. Invalid payloads don't throw hidden exceptions — they append error events; pausing a stream happens by appending a pause event; scheduling a heartbeat every 5 seconds is also just an event; even loop protection is modeled this way, with a circuit breaker that pauses streams if they start spewing too fast.

Reducers first, side effects second

Once the live coding starts, Jonas shifts into the programming model he actually cares about: stream processors. The important split is between a reducer that derives state from events and an afterAppend phase that does side effects, because he doesn't want reopening your laptop to cause a backlog of historical events to replay into fresh LLM calls.

The almost-demo: a tiny OpenAI agent from event state

He sketches what the OpenAI processor would look like even as the code keeps misbehaving. The state would hold a model string, system prompt, and history; agent input added events would update history; OpenAI streaming responses would come back as more events — his recurring point being that everything, even partial chunks, should become facts in the same log.

A stream can become an agent by appending code to it

The most striking section comes late, when he gives up on the broken examples and shows the UI-based dynamic worker configured event. That event contains JavaScript as a string — reducer plus afterAppend — and once appended, the previously inert stream starts responding pong to ping, which Jonas clearly finds delightfully absurd.

Why he still thinks the distributed version matters

In the wrap-up, he argues this architecture enables something current MCP-style integrations don't: just-in-time external processors that can proactively add context, safety checks, or business logic to an agent's event stream without living inside the agent loop. He's especially against heavy “before hooks,” saying they wreck performance and context caching, and prefers eventual consistency plus small bounded waits, like pausing up to 200ms for a safety checker before sending the LLM request anyway.

Share