lerp Docs Why lerp GitHub latest

The board

Lerp has five concepts and no sixth: a ticket, a queue, a runner, a lane, and the loop. Everything the board does is those five arranged by where tickets sit. This page is them as an adopter meets them; SCOPE.md is the same five as a fence, with the nine invariants and the litmus tests every change to lerp runs through, and it is the canonical text where the two ever seem to disagree.

Tickets, and where state lives

A ticket is a Linear issue, and Linear is the database. All durable state — what work exists, what stage it is in, who has claimed it, what was decided — lives there, and lerp keeps no store of its own. SCOPE.md invariant 1 is what holds that.

Locally lerp keeps exactly two things: lerp.toml (config, checked in) and an evidence store, .lerp/ at the repo root (gitignored, by init) — one record per run under .lerp/runs (pid, log file, ticket, workspace path, and the exit status the run records for itself as it ends), workspaces under .lerp/workspaces, an advisory lock at .lerp/lock that keeps it to one loop per clone, and the loop’s diagnostics in .lerp/loop.log. Local state is evidence, never truth: losing all of it may cost compute, never correctness.

Queues, and why there is no workflow syntax

A queue is a Linear status with instructions attached: tickets sitting in status are picked up, run through runner with prompt, and moved to on_success on a clean exit — or to on_failure, if the queue names one, when the agent exits non-zero.

That is the whole of the workflow language. There is deliberately no conditional, template, or DAG syntax, because the topology is not in the config at all: it is in where tickets sit and where each on_success points. A stage whose on_success names a status some queue watches chains into that stage; one that names a status no queue watches is a gate, where the pipeline waits on a human. Branching is a person or an agent moving a ticket. Rewriting the pipeline into a different shape needs no code change and no new syntax — see lerp.toml for the fields and the stock arrangement of them.

Runners

A runner is an adapter to a coding-agent CLI, and the contract is the lowest common denominator: it takes a prompt and a working directory, runs to exit, and its exit code means done or failed. Lerp does not parse an agent’s output to decide anything — it reads it only to draw it on the screen. What the agent writes into Linear, it writes itself, with its own credentials.

Lanes

A lane is the concurrency unit: lerp runs at most N agents at once, one per lane. Each lane is a whole disposable workspace, built by the provision command before a run starts and torn down by dispose when the lane is reaped — the stock config uses a git worktree, and environment isolation (ports, databases, containers) is the repo’s own problem, solved in those two commands. The default N is 10 and -concurrency changes it; a repo with a heavy provision command wants it lower.

The loop

Lerp is a reconciler. Desired state is the board; actual state is the agent processes running on this machine; and each pass starts, adopts, or reaps agents until the two match. A crash is not an error case — it is drift, and the loop repairs drift.

That is why an agent is not lerp’s child in any sense that matters. Each one is its own process group with its run evidence on disk, so it outlives the lerp that started it, and the pass that finds it belongs to whichever lerp is open — what a crash or a kill actually costs is a question that page answers.

The claim

Assignment is the claim: lerp claims a ticket by assigning it to your Linear user, and a claimed ticket is somebody else’s work as far as lerp is concerned, even when the somebody is you. So a ticket is eligible for pickup when three things are true at once — it sits in a queue’s status, it has no assignee, and it is not blocked by an unfinished ticket (Linear’s blockedBy).

The claim is also what makes multiplayer work without a server: each developer runs their own lerp against their own clone, and the claim arbitrates between them, with no lerp server and no coordination service anywhere. The protocol that does it, and what it is allowed to cost when two lerps collide, is SCOPE.md invariant 4 — read it there rather than here, because it is the kind of rule that is worth having in one place.

What falls out for an adopter is that colleagues see claims and stage artifacts, the same visibility they have into each other’s human work.

Where a run comes to rest

Where a finished run leaves the ticket is the whole of the topology. A finished run releases the claim wherever it comes to rest. Coming to rest in a status some queue serves means the next pass picks the ticket up for that stage on its own. Coming to rest in a status no queue serves is the pipeline waiting on a human — the status is the gate, so nothing needs to hold the ticket there. Promote it, or move it in Linear; either way the loop carries it on from there.

Two things call the whole rule off. A ticket an agent or a human moved out of the queue’s status during the run keeps that move — the hop it skipped is reported rather than forced. And a ticket assigned to somebody else by the time the run ends is theirs entirely, hop and claim both, since taking over a run mid-flight is exactly the way to say so.