9.7 KiB
🌙 Overnight / Long-Running Agent Runs — Cheat Sheet
What it is: how to run a multi-hour, unattended AI coding job (Devin / Claude Code / Codex / Copilot CLI) non-stop without it dying when the machine sleeps or the terminal closes — plus the ByteLyst best practices that make an unattended run safe. Best for: delegating a scoped roadmap (e.g. a 10-hour Phase build) and walking away overnight. Companion docs: the per-CLI sheets (
devin-cli.md,claude-code-cli.md,codex-cli.md) and the canonical../SKILLS/agent-behavior-guidelines.md.
🧠 The whole problem in one line: an unattended run has two enemies — the machine sleeping and the terminal/session dying.
caffeinatekills the first,tmuxthe second, and a checkpoint file saves you from everything else (reboot, crash, power loss).
The two failure modes (and what fixes each)
| Failure mode | What happens | Fix |
|---|---|---|
| Machine sleeps (idle timeout / lid closed) | CPU + network suspend → job freezes mid-step, connections drop | caffeinate (macOS) / systemd-inhibit (Linux) — keep it plugged in, lid open |
| Terminal/session dies (window closed, app crash/update, SSH drop, logout) | Job receives SIGHUP and is killed |
tmux / screen — the job is owned by the tmux server, not the window |
| Reboot / crash / power loss | Everything dies, including tmux | Checkpoint + resume — the job writes progress to a file; re-running resumes it |
caffeinate and tmux are complementary, not alternatives — use both for a real overnight run.
caffeinate (macOS) — stop the Mac from sleeping
caffeinate -dimsu <your-command> # stays awake only while <command> runs
| Flag | Prevents |
|---|---|
-d |
display sleep |
-i |
idle sleep |
-m |
disk sleep |
-s |
system sleep (on AC power) |
-u |
declares user active |
⚠️ Lid caveat:
caffeinatekeeps the Mac awake, but closing the lid still sleeps most Macs unless on AC power with an external display (clamshell) or the right pmset. For overnight: keep it plugged in and the lid open.
tmux — survive a closed terminal / disconnect
tmux new -s phase3 # start a named, detachable session
# ... launch your job inside it ...
# Ctrl-b then d # DETACH — job keeps running with no terminal attached
tmux attach -t phase3 # reattach later (after reconnect, or a new window)
tmux ls # list running sessions
- Local Mac: still useful — the job survives closing the terminal app, an app
crash/auto-update, or logout (a plain terminal job dies on all of these). It does
nothing for sleep — that's
caffeinate's job. - Over SSH: essential — the job survives the SSH connection dropping.
Linux equivalents: systemd-inhibit --what=idle:sleep <cmd> (sleep), screen or
tmux (session), or nohup <cmd> & + disown (cheapest detach, no reattach).
Putting it together
tmux new -s phase3
# inside the session:
caffeinate -dimsu <agent-cli> <all-allowed flag> "<the overnight prompt>" 2>&1 | tee ~/phase3.log
# Ctrl-b d to detach and walk away; tmux attach -t phase3 in the morning
| tee ~/phase3.log captures the full run to disk so you have the log even if the
scrollback is gone.
Shortcut: the longrun helper
The ByteLyst alias set (learning_ai_devops_tools/aliases/) ships a longrun helper that
does all of the above in one command — detached tmux + caffeinate (macOS) + a
timestamped log:
longrun phase3 <agent-cli> <all-allowed flag> "<the overnight prompt>"
# -> starts a detached, kept-awake, logged session named "phase3"
ta phase3 # reattach (alias for tmux attach -t)
tail -f ~/longrun-phase3-*.log # follow output
tmux kill-session -t phase3 # stop it
awake <cmd> # macOS: run any command keeping the machine awake
Install the aliases via learning_ai_devops_tools/aliases/install.sh (see that folder's
README).
Best practices for an unattended agent run
- Green baseline first. Run the verify gate (
pnpm build && pnpm test, browsers installed) before launching, so the agent starts from a known-clean state — never debug a pre-existing red suite at 2am. - Self-contained roadmap, slice-by-slice. Point the agent at a doc that encodes
scope, per-slice verify commands, and a done-definition (see
../PROMPTS/). One slice = one commit + push. - Checkpoint + resume. The job must write progress to a file (e.g.
docs/<phase>-progress.md: slice, status, commit SHA, gate result). If it dies for any reason, re-running the same prompt resumes from the first not-DONE slice. This is your safety net for the failurescaffeinate/tmuxcan't catch. - Failure protocol, not thrash. Tell it: max N honest attempts per slice, then commit
wip(...) BLOCKED:+ mark FAILED + move to the next independent slice. Order slices so the independent ones come first. - Never merge unattended. Push to a feature branch and open one PR — a human
reviews + merges in the morning. The agent must never touch
main. - Tests are sacred. Never weaken/skip a test to go green — fix the code (see the canonical guidelines). State this explicitly in the prompt.
- Scope + push-auth ready. Cache git credentials /
gh auth loginfirst so the overnightpushnever blocks on a prompt. Confirm push rights to the target remote. - All-allowed flag. Launch with the CLI's auto-approve flag so it never pauses for
permission (
--permission-mode dangerousfor Devin,--dangerously-skip-permissionsfor Claude Code,--dangerously-bypass-approvals-and-sandboxfor Codex — confirm with<cli> --help).
ByteLyst-specific gotchas (the ones that silently fail overnight)
- Corp proxy.
pnpm installand Playwright browser downloads will TLS-fail behind the intercepting proxy unlessNODE_EXTRA_CA_CERTS(proxy CA) is set. Prefer running off-corp for overnight jobs — simplest reliable path. (A proxy-blockedpnpm installis the classic cause of an overnight job that "did nothing".) - Playwright e2e. Slices with browser tests need
npx playwright install --with-depsbefore the run, or the e2e gate fails. - Workspace, not registry.
@bytelyst/*link viaworkspace:*from siblingpackages/*— run from the monorepo so they resolve locally; no registry needed for the build itself. - Side-by-side repos. If the prompt file lives in a sibling repo (e.g. the gigafactory
job lives in
learning_ai_devops_toolsbut runs inlearning_ai_common_plat), clone both under the same parent so the../relative path resolves.
Worked example — the gigafactory Phase 3 overnight run
# 1) bootstrap a clean baseline (once)
cd ~/code/mygh/learning_ai_common_plat && git pull && corepack enable \
&& pnpm install && pnpm build && pnpm test \
&& (cd dashboards/tracker-web && npx playwright install --with-deps)
cd ~/code/mygh/learning_ai_devops_tools && git pull # prompt + roadmap repo
# 2) launch non-stop
cd ~/code/mygh/learning_ai_common_plat
tmux new -s phase3
caffeinate -dimsu <agent-cli> <all-allowed flag> \
"Read ~/code/mygh/learning_ai_devops_tools/agent-queue/docs/jobs/phase3-overnight.md and execute it exactly: branch feat/gigafactory-phase3 off origin/main, implement Phase 3 slice-by-slice, verify each slice green before the next, checkpoint to docs/gigafactory-phase3-progress.md, commit+push per slice, open ONE PR and NEVER merge, never weaken tests (use the 3-attempt failure protocol), end with the consolidated report." \
2>&1 | tee ~/phase3.log
# Ctrl-b d to detach
In the morning: tmux attach -t phase3, read the consolidated report, then review +
merge the PR slice-by-slice.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Job froze partway, no error | Mac slept (idle or lid closed) | Use caffeinate -dimsu; plug in; lid open |
| Job vanished when I closed Terminal | No tmux — SIGHUP killed it |
Run inside tmux; reattach with tmux attach |
| "Did nothing" / 0 commits overnight | pnpm install TLS-failed on corp proxy |
Run off-corp, or set NODE_EXTRA_CA_CERTS |
| e2e slice failed immediately | Playwright browsers not installed | npx playwright install --with-deps before launch |
| Push at end blocked / hung | git/gh auth not cached | gh auth login / cache credentials first |
| Re-ran prompt, it redid finished work | No checkpoint file read | Ensure the job reads *-progress.md and resumes |
Quick-reference card
caffeinate -dimsu <cmd> # macOS: stay awake while <cmd> runs (lid open + on AC!)
systemd-inhibit --what=idle:sleep <cmd> # Linux equivalent
tmux new -s <name> # detachable session (Ctrl-b d = detach)
tmux attach -t <name> # reattach (tmux ls = list)
... | tee ~/run.log # capture full output to disk
# launch: tmux -> caffeinate -dimsu <cli> <auto-approve flag> "<prompt>" | tee log
# safety net: checkpoint file + re-run prompt to resume; push to branch, never merge
Related: devin-cli.md · claude-code-cli.md ·
codex-cli.md · ../PROMPTS/ ·
../SKILLS/agent-behavior-guidelines.md
Last updated: 2026-05-30 · confirm CLI auto-approve flags against your installed version (<cli> --help).