Skip to content
Guides · Coding agents

Can You Run a Coding Agent Overnight and Wake Up to Finished Work?

Updated November 12, 2026 .md

Short answer: It works when the run can finish without you. Give each sandbox one well-specified task, make passing tests the finish line, commit after every step, and cap time and attempts. Vague goals, missing credentials and loops with no stop condition still fail. In the morning you review a log, commits and test results.

"Overnight" doesn't mean the agent works better at night. It means nobody watches it. So the question is what a run needs in order to end in a useful state with no one there to answer questions, approve commands or notice it's stuck. This page sets up such a run on prod and shows the morning review.

We didn't spend on a model. A short shell script stands in for the agent's loop, and its "agent" step applies prepared patches, one of them buggy on purpose. Every sbx command below ran on prod on 2026-11-12, with the night shortened to about 2.5 minutes. Output is real, trimmed with …. Nothing here says what any particular model can get done in eight hours. That depends on the model, the task and the repo.

Other guides cover the parts in more depth, and this page doesn't repeat them:

What works unattended, and what doesn't#

Works overnight Fails overnight Why
"Make tests/test_word_count.py pass" "Make the code better" With no test, nothing tells the loop it's done. It stops early or never stops.
One task per sandbox Five unrelated tasks in one checkout One task can't break another's work, and you can review or discard each one on its own.
A commit after each passing step One big diff at the end A crash at 4 a.m. loses one step, not the night. git log is the progress report.
Every key the task needs, set before you leave A key it finds missing at 1 a.m. Nobody is there to paste it in. The loop should record "blocked" and move on.
Caps on attempts per task and on total time "Keep going until it works" A loop with no stop condition retries the same failure all night.
The agent allowed to run commands in a throwaway VM Permission prompts nobody answers A prompt at midnight waits until morning. See running Claude Code without prompts, safely.

Expect a mixed result. In our test, two tasks finished, one was blocked on a missing key and one was skipped as too vague. That is a normal morning.

1. Set up the night#

The task list puts the finish line next to each task. That is a test command, or - when there isn't one. It also lists the env var each task needs:

1|Implement slugify|python3 -m unittest -q tests.test_slugify|-
2|Implement word_count|python3 -m unittest -q tests.test_word_count|-
3|Add live exchange rates|-|RATES_API_KEY
4|Make the code better|-|-

The loop around the agent is what makes a run safe to leave alone. It caps total time and attempts per task, and it commits only when the task's tests pass. It writes each step to progress.log. It also holds ~/.sandboxer/keep-awake while it runs and removes it on exit:

#!/bin/bash
# Stand-in for an agent loop: one task at a time, tests as the finish line, a commit per finished task.
# A real agent replaces apply_attempt with a model call; everything around it stays the same.
cd ~/app
DEADLINE=$(( $(date +%s) + ${MAX_SECONDS:-600} ))   # hard stop for the whole run
MAX_ATTEMPTS=3                                     # per task
mkdir -p ~/.sandboxer && touch ~/.sandboxer/keep-awake
trap 'rm -f ~/.sandboxer/keep-awake' EXIT
log() { echo "$(date -u +%T) $*" | tee -a progress.log; }
apply_attempt() {   # the "agent": attempt 1 of task 2 has a bug on purpose
  sleep ${THINK_SECONDS:-30}
  … # applies .agent/patches/task<id>[-try<n>].py to textkit.py
}
blocked=0
while IFS='|' read -r id desc check needs; do
  if [ "$(date +%s)" -ge "$DEADLINE" ]; then log "STOP deadline reached before task $id"; blocked=1; break; fi
  if [ "$check" = "-" ] && [ "$needs" = "-" ]; then log "SKIP task $id ($desc): no test to finish against"; blocked=1; continue; fi
  if [ "$needs" != "-" ] && [ -z "${!needs}" ]; then log "BLOCKED task $id ($desc): $needs is not set"; blocked=1; continue; fi
  for try in $(seq 1 $MAX_ATTEMPTS); do
    log "task $id attempt $try: $desc"
    git checkout -q textkit.py
    apply_attempt "$id" "$try"
    if out=$($check 2>&1); then
      git commit -qam "task $id: $desc (tests pass)"
      log "DONE task $id: $(git log -1 --format=%h)"
      break
    fi
    log "tests failed: $(echo "$out" | grep -m1 -E 'Error|FAIL')"
    [ "$try" = "$MAX_ATTEMPTS" ] && { log "GAVE UP task $id after $MAX_ATTEMPTS attempts"; blocked=1; git checkout -q textkit.py; }
  done
done < TASKS.txt
log "finished: $(git rev-list --count main..HEAD) commits on $(git branch --show-current)"
exit $(( blocked ? 2 : 0 ))

The exit code is the summary: 0 means all done, 2 means something needs you. The agent works on a branch, agent/overnight, and never on main.

Create the sandbox with an auto-stop deadline that covers the night. The default is one hour and the maximum is 30 days (long-running tasks). We used 8 hours and a 2-minute idle pause, short enough to watch the pause happen:

id=$(sbx new --type small --ttl 28800 --idle 2 --name aeo-overnight-1 --json | jq -r 'select(.event == "ready") | .id')
sbx scp -r seed.sh overnight.sh patches $id:/home/user/
sbx exec $id "bash ~/seed.sh && mkdir -p ~/app/.agent && cp ~/patches/* ~/app/.agent/patches/ && cp ~/overnight.sh ~/app/.agent/"
{"event":"ready","id":"sb_g9cbwgnufm","state":"ready", … "archiveAfter":"2026-11-12T19:03:08.464736Z", … "idleStopMinutes":2, … "ttlSeconds":28800,"type":"small", …}

It was ready 0.27 s after the call in our test. archiveAfter is 8 hours after creation. Then start the run detached and close the laptop:

sbx exec $id --detach "cd ~/app && THINK_SECONDS=50 MAX_SECONDS=1800 .agent/overnight.sh"
{"ok":true,"type":"command.started", … "commandId":"cmd_azhk1az1rbd3", … "pid":687,"processId":687,"startedAt":"2026-11-12T11:03:19.682811117Z","success":true}

Keeping it awake. A detached command already holds off idle pause while it runs (what counts as activity). The keep-awake file matters when the agent runs some other way, such as a systemd service or a tmux session, and sits waiting on a model API with little CPU load. Use the file, not sbx idle $id 0. The file goes away when the loop exits, so the sandbox can still pause after the work ends.

Already working with a local agent? sbx handoff moves a local Claude Code or Codex session and its repo into a sandbox and resumes it there, headless. sbx handoff --back brings the work home (CLI docs). It runs the agent with the API key saved on your Agents page, not a subscription login. We didn't run it here, because it needs a model key. For a fresh start in a VM, see run Claude Code in a cloud VM.

2. What happened while nobody watched#

The run ended at 11:05:50, and nothing touched the sandbox after that. At 11:08:13, sbx info showed it stopped by the idle pause, with memory kept:

{"state":"archived","stoppedAt":"2026-11-12T11:08:13.287679Z","lastActivityAt":"2026-11-12T11:05:57.009077Z","stop":{ … "reason":"idle", … "status":"completed"}, …}

On a real night, this is what keeps an early finish cheap. If the agent is done at 3 a.m., billing stops after your idle timeout (30 minutes on the $20 plan), not at 8 a.m. when the TTL runs out.

3. The morning review#

Did it finish, and how? The first command woke the sandbox. Afterwards sbx info showed "state":"ready","memoryRestored":true.

sbx exec $id --status 687
Process:   687
Status:    exited (exit 2)
Command:   cd ~/app && THINK_SECONDS=50 MAX_SECONDS=1800 .agent/overnight.sh
Started:   2026-11-12T11:03:19.682811117Z
Finished:  2026-11-12T11:05:50.0635615Z
Log:       /home/user/.sandboxer/processes/687.log
--- stdout (tail) ---
11:03:19 task 1 attempt 1: Implement slugify
11:04:09 DONE task 1: 1d54a88
11:04:09 task 2 attempt 1: Implement word_count
11:04:59 tests failed: FAIL: test_empty (tests.test_word_count.T.test_empty)
11:04:59 task 2 attempt 2: Implement word_count
11:05:50 DONE task 2: 2406532
11:05:50 BLOCKED task 3 (Add live exchange rates): RATES_API_KEY is not set
11:05:50 SKIP task 4 (Make the code better): no test to finish against
11:05:50 finished: 2 commits on agent/overnight

exit 2 tells you before you read a line that something needs you. sbx exec $id --attach 687 prints the whole log and exits with the same code, so a morning script can branch on it. In our test it ended with the finished line and exited 2.

What else ran? sbx history lists every command sent through the API, including ones the agent's tools ran with sbx exec. It works while the sandbox is stopped, too:

sbx history $id
COMMAND-ID        STATUS  MODE      STARTED              COMMAND
…
cmd_rrgqtypzia2c  exit 0  sync      2026-11-12 11:03:24  ls -la ~/.sandboxer/keep-awake
cmd_azhk1az1rbd3  exit 2  detached  2026-11-12 11:03:19  cd ~/app && THINK_SECONDS=50 MAX_SECONDS=1800 .agent/overnight.sh
cmd_dgjcb6ihnuet  exit 0  sync      2026-11-12 11:03:16  bash ~/seed.sh && mkdir -p ~/app/.agent && cp ~/patches/* ~/app/.agen…

What changed, and do the tests pass? Don't take the log's word for it. Run the full suite yourself:

sbx exec $id "cd ~/app && git status --short --branch && git log --oneline --stat main..agent/overnight && python3 -m unittest 2>&1 | tail -3"
## agent/overnight
2406532 task 2: Implement word_count (tests pass)
 textkit.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
1d54a88 task 1: Implement slugify (tests pass)
 textkit.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
Ran 5 tests in 0.000s

OK

The worktree is clean, so nothing is half-done. There are two commits, one per finished task. The failed first attempt at task 2 left no commit, only a line in the log.

Take the branch home. Bundle it in the sandbox, copy it out and read the diff on your machine. Your git credentials never enter the sandbox:

sbx exec $id "cd ~/app && git bundle create -q ~/overnight.bundle main agent/overnight"
sbx scp $id:/home/user/overnight.bundle .
git clone -q -b agent/overnight overnight.bundle app && cd app
git diff --stat origin/main
 textkit.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

From here it's a normal code review. The morning checklist:

  1. Exit code and last log lines. Done, blocked or gave up?
  2. Blocked and skipped tasks. Add the missing key or write the missing test, then queue them for tonight.
  3. git log on the agent's branch. Is there one commit per step, with messages that match the log?
  4. The tests, run by you. Is anything uncommitted or failing?
  5. sbx history. Did it run anything you didn't expect, like installs, network calls or deletes?
  6. The diff, on your machine, before anything merges.
  7. Delete the sandbox, or resume it for another night. A stopped sandbox created after October 29, 2026 is kept for 14 days after its last stop, then its data is deleted.

What a night costs#

From the live pricing, billed per second. This is machine time only. Your model provider's tokens are billed separately:

Size Per hour 8 hours Nights in the $20 plan's included time
small (2 vCPU, 4 GB) $0.018 $0.144 138
default (4 vCPU, 8 GB) $0.036 $0.288 69

The arithmetic: 8 × $0.018 = $0.144, and $20 ÷ $0.144 = 138.9. Also 8 × $0.036 = $0.288, and $20 ÷ $0.288 = 69.4. A night that ends early costs less, because the idle pause stops billing. Our whole test came to 2m41s of machine time, small counting at half rate, which sbx usage priced at $0.0016.

What stops a runaway#

An agent loop with a bug can retry all night. Several limits bound that without you awake:

  • The TTL. --ttl 28800 stops the sandbox 8 hours after it starts, whatever is running. A running job doesn't hold it off. It's a stop with memory, so sbx resume picks up where it was. The agent inside can't move its own deadline: the in-sandbox SANDBOXER_TOKEN can't create, resume, fork or delete sandboxes (API keys). How long a sandbox can run shows the 403 when it tries to extend.
  • Idle pause. When the loop exits and its keep-awake file goes with it, the sandbox pauses after idleStopMinutes. Don't set it to 0 for an unattended run.
  • Your own caps in the loop. Total seconds and attempts per task, as in the script above. Only these stop a loop that is busy but going nowhere before the TTL does.
  • A scoped, expiring key for whatever starts the run. If a script or scheduler creates the night's sandboxes, give it a key with only the actions it needs and a short --ttl, like sbx api-key create night-runner --preset ci --ttl 1d. It stops working on its own (API keys). We didn't run this one, because creating keys changes the shared test account.
  • Machine-time caps. An organization owner can cap a member's machine time per plan period with usageCapSeconds. After that, that member's creates, resumes and forks get 402 team_member_cap_reached. Running sandboxes keep running, so the TTL still ends the night. A prepaid balance with auto-refill off is the account-wide ceiling. Both are in cap what agent sandboxes can cost.

FAQ#

Do people really wake up to finished apps?#

Sometimes they wake up to finished tasks. In our test the tasks that finished were the ones with a test to pass and everything they needed. The vague task and the one missing a key did not finish. Plan for a review in the morning, not a merge.

Does my laptop need to stay on?#

No. sbx exec --detach returns at once, and the job runs inside the VM, not in your terminal. Closing the terminal or the laptop doesn't touch it.

What happens if the agent is still working when the TTL runs out?#

The sandbox stops with memory and disk kept, and sbx resume brings the job back where it was. Pick a TTL longer than the night, and commit as you go anyway.

Should one sandbox run several tasks overnight?#

Give each task its own sandbox and branch, so a bad task can't break the others and each can be reviewed or thrown away alone. Run coding agents in parallel shows several at once.

Can the agent push to GitHub itself overnight?#

It can if you give it a token, but you don't have to. In this page's test the branch left the sandbox as a git bundle, so no git credential went in. Build a background coding agent has a service do the push.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide