back to home

Rivet

Open-source coding agent that turns a GitHub issue into a tested pull request.

Solo engineer · Open source (MIT) · Aug – Oct 2026

TypeScriptNext.jsPostgreSQLDrizzleRedisBullMQDockerOpenTelemetry
7 wk
first commit to release
13
documented milestones
29/30
eval runs passed hidden tests
3
reconciliation loops
7
fault-injection modes
188
test files

♦ the problem

Coding agents are good at writing a patch. The hard part is everything around it: where untrusted repository code runs, what happens when the process dies halfway through, how you tell a new test failure from one that was already there, and whether a pull request it opens can be trusted.

Rivet is that surrounding system, built properly. Give it a GitHub issue and it plans the change, edits code in a disposable Docker sandbox, validates against the repository's own checks, passes the patch through an independent reviewer, and opens an ordinary pull request. Every step is durable and visible in a live timeline.

♦ the hard parts

Crash-safe runs with leases and fencing

Queue locks describe a message, not a job: a worker killed with kill -9 never tells Redis how far it got. So each job row in Postgres carries a lease owner that doubles as a fencing token. Claims are one compare-and-swap, so two racing workers produce exactly one winner. One heartbeat UPDATE every ten seconds both extends the lease and fences out a worker whose job was reclaimed: zero rows back means stop.

Recovery that keeps the work

After every phase and every implementation turn, the working tree is captured as a binary git patch against the job's immutable base commit, through a temporary git index so the agent's own staging is untouched. A replacement worker applies it in a fresh container and re-derives the patch's SHA-256 before calling it restored. A corrupt checkpoint fails loudly instead of quietly restarting from zero.

A sandbox the model key never enters

Repository code runs in a resource-limited container as a non-root user with every Linux capability dropped. The agent runs on the trusted worker and reaches the repository only through four tools routed into the container. Rivet asserts that exact tool set at startup and passes no worker environment through, so the provider key and database credentials never reach repository code. The worker refuses to start if a sandbox can reach the control plane.

Validation that knows what was already broken

Tests, typecheck, and lint run before any change to record a baseline, then again after. Each check is classified as verified, fixed, regressed, unresolved, or unverified, and any newly failing named test counts as a regression even in a suite that was already red. Pre-existing debt doesn't fail unrelated work, and new breakage can't hide behind it.

Publishing without duplicates

A GitHub App mints short-lived installation tokens on the worker. Branch, push, and pull request creation go through a receipt ledger, so a job retried after a crash does not open a second pull request.

♦ seven weeks, thirteen milestones

I built Rivet alone in thirteen milestones, each with a written plan, and kept an architecture document in the repo current as each one landed, including where the design is a deliberate shortcut.

Failure handling is tested on purpose, not hoped for. Seven fault-injection modes, including killing the worker mid-phase, out-of-memory, and a missing Docker daemon, exercise recovery on demand. Tests are split into four suites by what they need: unit tests run with no database, Redis, or Docker, and separate integration, streaming, and real-container suites run against local infrastructure. A written security review walks the threat model control by control and names the risks accepted rather than mitigated.

♦ architecture

The Next.js web app and the long-running worker call one shared domain library directly, with no HTTP hop between them. Postgres is authoritative: the job state machine, an append-only event log, checkpoints, and artifacts. Redis carries only job IDs and can be rebuilt from Postgres. A sweeper runs three reconciliation loops: expired leases against workers, orphaned jobs against Redis, and leftover containers against Docker.

The queue, sandbox, coding agent, and telemetry sit behind ports, each with a fake, which is why unit tests and production builds need no infrastructure. The live UI tails the event log over server-sent events and resumes from the last event ID, so a dropped browser connection picks up where it left off. OpenTelemetry traces, metrics, and correlated logs cover every job.

♦ outcome

Rivet is open source and runs today as a local, single-operator app. To measure it, I built an evaluation harness where a benchmark run is an ordinary job, graded afterwards by hidden tests in a separate container the agent never sees. Across five lock-pinned tasks (two bug fixes, a feature, a refactor, and an API change), each run three times with and without independent review, 29 of 30 runs passed: 15 of 15 with review, 14 of 15 without.

The honest reading: the tasks are small fixtures I wrote alongside the harness, and 30 runs can't separate a small effect from noise. The write-up in the repo says so. What it shows is that the full loop works end to end and can be measured, which is the part most agent demos skip.