slow software Β· grown overnight

Some things can happen slowly.

lazycode is an open-source coding agent that plans with a realtime model, then does the actual work on batch APIs β€” overnight, at half the price. Hand over the backlog, make tea, go to bed. Branches are waiting by morning.

lamplight β€” realtime, for the plan overnight β€” batch, it grows while you sleep
pip install lazycode-agent Read the source pre-alpha Β· M0 Β· Apache-2.0
23:47 Β· wave 1 in flight Β· nothing left to do but sleep

We rush the wrong things.

Refactors don't need you hovering. Tests don't care if they finish at three in the morning. Migrations were never urgent β€” only postponed.

A garden doesn't grow faster because you watch it. Some work just needs time β€” and time, it turns out, is half price.

β€” the case for lazy code

an evening with lazycode

Ask once. Approve. Go live your evening.

how it works

It thinks fast, then works slow.

Chat agents burn tokens round-tripping one message at a time, because you're sitting there waiting. Remove the waiting and a better shape appears: lazycode treats your goal like a database treats a query β€” plan, optimize, execute in parallel waves, verify.

δΈ€plan Β· realtime

A short, bright moment of thought

A realtime model reads your repo map and decomposes the goal into a DAG of typed operators β€” Explore, Generate, Edit, Verify, Judge, Reduce. You see the whole plan and approve it before a cent is spent on execution.

二optimize

The plan gets quietly better

Rule-based rewrites, straight out of a query optimizer: push mechanical work to local tools, prune each node's context, factor shared prompt prefixes for cache hits, widen independent fan-out. Breadth is free β€” only depth costs time.

δΈ‰execute Β· batch

Waves roll through the night

Every node whose dependencies are met ships in one batch submission β€” one wave can carry fifty file edits at half price. The daemon persists everything and waits without impatience; most waves finish within the hour.

ε››verify Β· land

Morning finds it finished

Results are harvested into git worktree sandboxes, diffs applied with three-way merge, your test command run per group. You wake to branches, a report, and an assumption ledger β€” not a wall of chat.

physical plan Β· job jb_7f3a Β· goal: "add type hints to services/"

wave 0 Β· realtime wave 1 Β· batch Β· 4 nodes wave 2 Β· batch wave 3 Β· local Decomposerepo map β†’ DAGlamplight Β· $$ Generateservices/auth.py Generateservices/billing.py Generateservices/quota.py Generateservices/events.py Verifymypy Β· group A Verifymypy Β· group B Reducebranch + reportβœ“ by 06:12

independent nodes ride the same wave β€” one batch call, fifty files

the pipeline

Watch one goal become a batch.

This is Figure 2 of the paper, running. A single realtime call plans; the plan decomposes into self-sufficient batch requests; the night does the work; results land as verified diffs β€” and the frontier forms the next wave. Every transition is written to the event log before its side effect, which is why a crash anywhere resumes instead of re-paying.

compile β€” one online-priced call
plan β†’ decompose β†’ harvest
$ lazycode "add type hints to services/"
plannerrealtime Β· typed plan
Explorelocal Β· $0 Β· finds 3 files
Generateauth.pyrepo mapfilerules
Generatebilling.pyrepo mapfilerules
Generateorders.pyrepo mapfilerules
Verifylocal Β· pytest Β· free
Reducereport Β· wave-2
the night β€” batch lane, half price
23:00
wave-1 Β· 3 items Β· one batch requestshared prefix hoisted Β· byte-identical across items
W1 formed β€” key logged before money moves W2 submitted β€” re-poll, never re-submit
auth.py
billing.py
orders.py
W3 completed β€” replay is idempotent
barrier β€” next frontier only when every item is terminal
wave-2 Β· 1 item Β· Reducethe frontier re-formed; deps satisfied
auth.pydiff β†’ allow-list β†’ 3-way apply
billing.pydiff β†’ allow-list β†’ 3-way apply
orders.pydiff β†’ allow-list β†’ 3-way apply
pytest services/
morning reportAssumptions: 1 β€” "treated Optional[str] as str | None"
event log Β· append-only Β· the source of truth

Dashed nodes run locally and cost nothing. W1–W3 are the crash windows: formed-not-submitted adopts its own paid batch by key; submitted re-polls, never re-submits; completed replays idempotently. The receipt at the end is real.

economics

Patience is a discount.

Batch APIs are 50% off list price. Most tools would stop there. We don't β€” because realtime agents get prompt-cache discounts on input that batch mostly gives up. Here is where the savings actually come from, measured honestly.

Output tokens: a flat 50% win

Every token the model writes overnight costs half. No caveats. For generation-heavy work β€” new tests, migrations, mass refactors β€” this is the bulk of the bill.

Input tokens: won by depth collapse

A chat agent re-reads the conversation every turn; caching makes that cheap (0.1Γ— on hits). lazycode wins on input differently β€” it collapses thirty hurried turns into a few wide waves, so the context is simply read far fewer times. Fewer rounds beats cheaper re-reads.

Scheduling: breadth is free

Batch providers don't care whether a wave carries one request or a thousand. The optimizer widens fan-out aggressively, because only depth costs wall-clock time β€” and the night is long anyway.

We benchmark against Claude Code with caching on β€” the real alternative β€” not an uncached strawman. Typical result: 30–70% cheaper, task-shape dependent. The benchmark harness ships in the repo; run it yourself.

The patience dial

lazycode's Ξ» slider β€” every plan node can run realtime or batch

Ξ»=0 Β· all nowall overnight Β· Ξ»=1
RELATIVE COST
44%
DELIVERY
by morning

Illustrative, using list prices and a generation-heavy task shape. Urgent nodes stay realtime; everything that can wait, waits β€” and gets cheaper.

durability

Built to sleep through anything.

An agent that works while you sleep has one non-negotiable job: never lose work, never pay twice. Every guarantee below is enforced by the test suite β€” including a kill -9 β†’ resume end-to-end test.

events.sqlite Β· append-only

Event-sourced core

Every state change is an event; job state is a replayable projection. Crash at any instant β€” plan approved, wave in flight, results half-processed β€” and lazycode resume reconstructs exactly where it was.

sha256(items) Β· idempotency

Never pay for a batch twice

Submissions carry content-derived idempotency keys, stamped into the provider's batch metadata. If the process dies between paying and recording, reconciliation finds the orphaned batch and adopts it instead of re-submitting.

lease Β· single writer

One writer, ever

A daemon holds a heartbeated per-job lease as the sole database writer; CLI and UI are read-only clients. No second process can double-submit your job β€” not even you, accidentally, from another terminal.

caffeinate -i Β· with consent

Stays awake so you don't have to

The daemon keeps your machine from sleeping (it asks first). Results land in git worktree sandboxes, diffs apply with three-way merge and an applied-diff ledger β€” your working tree is never touched.

quickstart

Start this evening.

Python 3.12+, a git repo with at least one commit, and an Anthropic API key. Or try the built-in mock provider first β€” zero network, zero spend.

shell
# install
pip install lazycode-agent

# hand over the backlog
cd /path/to/your-repo
export ANTHROPIC_API_KEY=sk-ant-...
lazycode run "add type hints to services/" --verify "pytest -q"

# approve the plan, close the laptop. in the morning:
lazycode review jb_7f3a
lazycode runPlan with a realtime model, approve, execute in batch waves
lazycode statusPer-node progress: what's queued, in flight, landed, failed
lazycode explainLogical and physical plan trees β€” Spark-style, for your code
lazycode reviewBranches, verification results, and the assumption ledger
lazycode resumePick an interrupted job back up after a crash or reboot
lazycode daemonSingle-writer orchestrator that owns jobs and stays awake

M0 β€” shipped

Plan β†’ waves β†’ verified branches. Crash-safe resume, idempotent submits, daemon, benchmark harness.

M1 β€” next

Repair loop: failed verify feeds back into a fix wave instead of stopping. Typed contracts, merge/cancel.

M2

Cost estimates in the plan preview, explain analyze, hedging and deadline-aware realtime fallback.

M3+

Web UI for plan DAGs, rolling wave flush, OpenAI & Gemini batch adapters, webhook-first completion.