Why Event-Sourced Agent Harnesses
Most agent harnesses keep a log of every event that passes through them. The problem is that log isn’t the source of truth, it’s a side effect. Side effects end up visible only in telemetry traces, making debugging slow and extension fragile.
Templestein’s design flips this: make the event stream the only interface. Every input, every error, every model response is appended to a named path. Pause a stream by appending a pause event. Extend by writing a processor that reacts to new event types, in any language, on any server.
The events.iterate.com Stream API
events.iterate.com gives every agent a named path. Post JSON to that path and the service appends it with an auto-incrementing offset. Read with ?live=true and the connection stays open, streaming events via SSE. Post malformed JSON and the service appends a validation-error event rather than dropping the request.
Circuit-breaking works the same way. Push more than 100 events per second and the stream pauses automatically by appending a pause event to its own log. Idempotency keys prevent duplicate appends from webhooks. Scheduled events let a processor set a recurring heartbeat or fire a delayed action, all in the same log.
Writing a Stream Processor
A stream processor has two parts: a reduce function and an after-append hook. The reducer is pure and synchronous. It takes a state and an event and returns the new state. The after-append hook is where side effects go, such as appending to another stream or making an OpenAI request.
“you can build a super expressive state of the art coding agent by just implementing uh like a stream processor that reduces over the event stream and occasionally an X side effects” — Jonas Templestein
The split matters when a processor restarts after downtime. It replays the full event log through the reducer to rebuild state, then only calls after-append for events that arrived after it came back. Catching up 100 missed events never fires 100 LLM requests.
Deploying Processors as Events
Append an event of type dynamic-worker-configured to any stream. The payload is a JavaScript string with a reducer and an after-append hook. The service spins up a Cloudflare Worker and runs it. No separate deployment. He walked through the ping-pong dynamic worker live demo (51:34): after appending the event, the stream responded “pong” to every “ping” immediately.
Templestein had a 40-line OpenAI agent bundled this way before the workshop. npm dependencies must be bundled into the string, since the worker has no package registry access, but a planned unbundled variant would ship a package.json field for a separate processor to resolve.
Distributed Plugins and the No-Before-Hook Rule
Any processor can subscribe to an agent’s stream from a different server. A safety checker can sit on a separate machine, append a warning event, and the agent loop waits up to 200 milliseconds before firing the next LLM request. Templestein argues MCP offers no way to proactively hook into the loop the same way.
Before-hooks are deliberately excluded. Synchronous middleware caused performance regressions and broke context caching in systems like Open Code. Here, the system is eventually consistent: a RAG processor that misses its 200-millisecond window is simply late. The agent runs. The context just skips that retrieval.
Q&A
What does Iterate actually do as a company? Templestein described it as a ‘hacker hobby club’ with no launched product, but said the product would be built on this architecture. ▶ 15:54
Where do the reducers actually run, and who consumes the event stream? Reducers run wherever the processor is hosted, whether locally, on Cloudflare Workers, or inside the events service itself, and the circuit-breaker processor running in production was cited as a concrete example. ▶ 47:15
Notable Quotes
you can build a super expressive state of the art coding agent by just implementing uh like a stream processor that reduces over the event stream and occasionally an X side effects Jonas Templestein · ▶ 17:33
the moment an agent exists, it should have a URL Jonas Templestein · ▶ 3:54
everything that happens results in an event and then you can react to those events however you see fit Jonas Templestein · ▶ 55:25
Key Takeaways
- Treat every agent as an append-only event log; errors, pauses, and completions are all events.
- Split agent code into a pure reduce function and a side-effect hook so replay never double-fires LLM calls.
- Deploy processor logic as an event payload to any stream, skipping traditional server deployments entirely.