explaingit

tonbo-io/ursula

85RustAudience · ops devopsComplexity · 5/5ActiveLicenseSetup · hard

TLDR

Self-hostable Rust server for append-only event streams with sub-50ms writes, Raft quorum replication, and S3 as the cold tier, served over plain HTTP.

Mindmap

mindmap
  root((ursula))
    Inputs
      Event bytes
      Bucket name
      Stream name
      Read offset
    Outputs
      Append ack
      SSE live tail
      S3 chunk
    Use Cases
      Log AI agent steps
      Tail editor keystrokes
      Replay workflow state
      Self-host event log
    Tech Stack
      Rust
      axum
      Raft
      S3
      SSE

Things people build with this

USE CASE 1

Self-host an event log for AI agent reasoning steps with live SSE tails

USE CASE 2

Run a three-node Ursula cluster on EC2 and offload cold chunks to S3

USE CASE 3

Store every keystroke of a collaborative editor in a per-document stream

USE CASE 4

Replay long-running workflow state from any offset for debugging

Tech stack

RustaxumRaftS3

Getting it running

Difficulty · hard Time to first run · 1h+

Single binary boots in-memory on localhost, but a real deployment needs a 3 or 5 node cluster with S3 access and Raft quorum tuning.

Apache 2.0 lets you use, modify, and redistribute the code commercially as long as you preserve attribution and the license notice.

In plain English

Ursula is an open-source server, written in Rust, for storing append-only event streams and serving them over plain HTTP. An event stream here means a continuous log of small records, the kind of thing produced when a document editor wants to keep every keystroke, an AI agent wants to keep every step of its reasoning, or a long-running workflow wants to keep every state change. Apps can write new events to the end of a stream and others can read the stream back from any point, including tailing it live as new events arrive. The pitch in the README is that there are already protocols for this shape of data, specifically the Durable Streams Protocol developed by ElectricSQL, but most existing servers force a tradeoff. Either you cannot self-host them, write latency is slow because they batch, they need expensive S3 Express storage, or a single node failure loses data. Ursula tries to keep all four properties: self-hostable, sub-50 ms writes, plain S3 as the cold storage tier, and quorum replication so an acknowledged write survives losing one node. A typical deployment is three or five Ursula processes acting as one cluster. Each stream hashes to one Raft group, and one CPU core per node owns that group, so cores work on different streams without sharing mutable state on the hot path. Writes go into an in-memory ring and a Raft log, get acknowledged once a majority of the replicas persist them, and a background flusher later writes older chunks out to S3. The HTTP layer is built with axum and is stateless. To try it, you build from Rust source with cargo run and the binary listens on 127.0.0.1:4437 in an in-memory mode. The HTTP API is bucket-and-stream shaped: PUT /demo creates a bucket, PUT /demo/hello creates a stream, POST appends bytes, GET reads from an offset, and adding live=sse turns the request into a live tail. On three c7g.4xlarge EC2 machines the README reports about 35,200 appends per second across 500 streams and SSE fan-out to 1000 subscribers at 6.1 ms at the 99th percentile. The 0.1 series is a working prototype. Planned next are conditional appends with an if-match header for optimistic concurrency, a WASM compute extension that lets server-side modules summarise stream state, online membership changes, backup and restore tooling, and Rust and TypeScript client libraries. License is Apache 2.0, built by a team called Tonbo.

Copy-paste prompts

Prompt 1
Cargo run Ursula locally, create a bucket and stream, then append and tail events with curl
Prompt 2
Deploy a three-node Ursula cluster on c7g.4xlarge EC2 boxes with S3 as the cold tier
Prompt 3
Hash 500 streams across Raft groups in Ursula and benchmark appends per second
Prompt 4
Subscribe to an Ursula stream via live=sse and fan out updates to a browser client
Prompt 5
Add a Rust client library wrapper around Ursula's bucket-and-stream HTTP API
Open on GitHub → Explain another repo

Generated 2026-05-22 · Model: sonnet-4-6 · Verify against the repo before relying on details.