Writing / 23 SEP 2026

A job queue where a restart loses nothing

I run local models and rent coding agents like Claude Code and Codex. eki is the one queue in front of all of them. These are the design rules that made it survive restarts.

by xz4 min read

My Mac does a lot of AI work now: a local 27B model for everyday prompts, and hosted coding agents for the jobs a local model can't do. For a while that meant a handful of terminals, each running something, and a vague memory of which one was doing what. When the Mac restarted, or I closed the wrong window, work vanished.

eki is my answer: one queue on the Mac. I ask once — eki ask "fix the failing test" — and eki decides where it goes, runs it, and keeps it running. It's still in progress and not public yet, but the design has settled enough to write about.

Rule one: a restart at any moment loses nothing

This is the rule every other decision is checked against, and it shapes the whole architecture.

A rule like this is only real if it's tested, so there's a test for it — the drill — that kills things at awkward moments and checks nothing was lost. It runs on every change.

Rule two: everything is a run

Every request becomes a row in the database before it starts: queued, running, done, failed, cancelled, handed off, or interrupted. Everything that happens during it is an event. That makes the whole system inspectable from the command line — eki runs, eki follow <run>, eki show <run> — and it means the question "what is my Mac doing right now?" always has an answer.

Rule three: routing explains itself

The most useful feature turned out to be a small one. Every run stores why it went where it went, as a readable chain:

rule: names a path → code → claude (codex last: five_hour 82%)

A request passes through five layers in order. First, a thread stays with the provider that's been answering it, unless that provider can't take the new request. Second, constraints: pure code that compares what the request needs (text, tools, web, vision) against what each provider can do, plus whether it's available or cooling down after hitting a limit. Third, intent: simple rules catch the obvious cases — a folder path means code work, an attached picture means vision — and only when no rule fires does a small model classify the request. Fourth, preference: each kind of work has an order of targets, and one near its usage limit moves to the back. Fifth, failover down that list.

When nothing else decides, the default is cheapest first: the local model, then subscriptions, then pay-per-token APIs. eki route "…" prints the chain without running anything, which is how I tune the rules.

Rule four: background work waits for room

A run has a priority: now (I'm waiting for it) or background. Background runs are gated by the machine itself — memory pressure, load, and whether the Mac is plugged in. A 27B model uses around 14 GB of memory, so this matters: a background job shouldn't make the Mac crawl while I'm using it,.

Rule five: integrate, don't rebuild

eki doesn't build its own agent harness or tools. Models come from providers, harnesses from their makers, tools from MCP servers, instructions from skills. eki's job is to hand each run the same set of skills and tools in whatever form each program expects. And credentials stay mine: subscriptions are reached only by running the official command-line tools as me. eki never reads or copies a token.

Small files, on purpose

One last rule sounds cosmetic but isn't: no module over 400 lines, enforced by a test. The previous version of eki had a few very large files, and when several agents worked on it in parallel, they constantly collided in the same file. Small files with one job each make parallel changes merge cleanly — which matters, because more and more of eki's changes are proposed by agents working on eki itself.

I'll write more about that part — eki planning and building changes to itself, with me as the reviewer — once it's further along.