agent to Claude Code in its own sandbox and opens a pull request
with the result. And a nightly eval that runs the agent on five small tasks in
parallel sandboxes and posts the pass rate and spend.
How it fits together
The
coding-agents map holds the snapshot record and a claim per issue in
progress. Each secret reaches only the workloads that use it;
GITHUB_WEBHOOK_SECRET reaches only the webhook. With no labeled issues and
no SSH session, only the map and the devbox disk cost anything, plus one eval
a night, and AGENT_MAX_BUDGET_USD caps each run’s model spend at $5.
Run it
1
Download
The CLI installs once with
uv tool install lazycloud-client. The commands
below download a standalone project and install its dependencies; no
repository checkout is needed. The guide then runs from that directory through
uv run, which uses the project’s pinned SDK.2
Configure
Set
REPOSITORY in coding_agents/settings.py; SETUP_COMMAND and
TEST_COMMAND default to a uv project with pytest. The script asks for an
Anthropic API key, a GitHub
token with read and write access to contents, issues and pull requests,
and a webhook secret such as openssl rand -hex 32.3
Deploy
/github, content type
application/json, the secret you stored, and Issues events only.4
Use
Create an
agent label, open an issue, and apply the label. A pull
request from agent/issue-<number> follows, with the agent’s summary,
the test verdict, the turns and the spend.uv run lazycloud devbox agent-box ssh connects to the devbox; inside,
clone the repository, start tmux and run claude or codex.
uv run lazycloud run coding_agents.app:nightly_eval runs the eval now
instead of waiting for 06:00 UTC.A devbox with a disk
A devbox is a container you SSH into; the secrets arrive as environment variables, soclaude and gh work on the first
connection, and the idle window counts from your last SSH connection.
coding_agents/app.py
Sandboxes that reach only the model API
A sandbox runs the agent’s commands;allow_list
holds address ranges, DNS included, so the function pins api.anthropic.com
in the sandbox’s /etc/hosts, and the agent runs as an unprivileged user
that cannot change it. The issue sandbox is the same with
image=Image.from_id(snapshot.image_id), declared at run time.
coding_agents/app.py
A filesystem image as the snapshot
A sandbox’s filesystem can become an image, which is how the repository and its dependencies reach offline sandboxes.coding_agents/snapshot.py
A claim in a map, then spawn
A map entry with a two-hour TTL claims the issue before.spawn(), so a relabel or a redelivery keeps the run already going.
The webhook is authorized=False, since GitHub cannot send a LazyCloud token;
every delivery carries the secret’s signature instead.
coding_agents/app.py
A schedule that fans out
A schedule is a function withcron; spawn_map
starts one eval-task call per task, and call.result(wait=True) collects
each outcome, with a failed call counted as a failed task.
coding_agents/app.py
Adapt it
- Another stack needs its tools in
agent_imageand its commands inSETUP_COMMANDandTEST_COMMAND, for examplenpm ciandnpm test. AGENT_MODELtakesopusor a full model name; the eval is the place to compare models on cost and pass rate before switching.- A CI job that runs
uv run python -m coding_agents.snapshotafter each merge keeps pull requests close to the default branch.
Clean up
agent/issue-* branches you no longer need. Snapshot images stay in the
workspace, since the CLI has no command to delete an image.
deployment stop nightly-eval pauses only the eval.