Here's a scenario you've probably lived through:
You ask Claude Code to refactor a module. Halfway through, you leave for a meeting. When you come back, the session is gone, the context is cleared, and it has no idea what it was doing. You re-explain the requirements, it re-reads the codebase, and fifteen minutes later you're back where you started — just in time for your next interruption.
The real problem isn't "how to keep Claude Code running." It's three distinct problems:
- Don't stop — it keeps working after you leave
- Don't reset — if it stops, it picks up where it left off
- Don't go rogue — without supervision, it doesn't break things
Each layer requires different techniques. Combined, they form a complete unattended architecture.
Layer 1: Don't Stop
Keep Claude Code executing after you walk away.
tmux (The Basics)
The simplest approach — keep the terminal session alive:
tmux new -s work
claude
# Time to leave
# Ctrl+B then D (detach)
# Session keeps running. Close your laptop lid if you want.
# When you're back
tmux attach -t work
Claude Code doesn't know you left. It continues whatever it was doing. Good for "grabbing coffee" absences.
Limitation: Your machine can't shut down or lose network. Laptop sleep will kill it.
/loop — Scheduled Execution Within a Session
Claude Code's built-in /loop runs a prompt at fixed intervals:
/loop 10m Check CI status. If anything failed, fix it.
This is more than a timer. With the right prompt, it becomes an autonomous worker:
/loop 15m Read TODO.md. Pick the next incomplete item and work on it. Mark it done when finished. Update the progress marker.
Critical design point: The loop prompt can't just say "keep going." It must specify where to find progress and how to decide what's next. More on this below.
System crontab + claude -p (Cross-Session)
For "shut down and come back tomorrow while it works overnight":
# crontab -e
0 */4 * * * cd ~/project && claude -p "Read TODO.md. Execute the next pending item." --bare >> /tmp/claude-auto.log 2>&1
--bare skips full context loading (CLAUDE.md, MCP servers) — 10x faster startup. Good for scheduled tasks, not for complex development requiring full context.
Advanced: Combine with --resume to continue a previous session:
# Save the session ID
claude -p "Start refactoring auth module" --output-format json | jq -r '.session_id' > /tmp/session-id.txt
# Four hours later, pick up where it left off
claude --resume $(cat /tmp/session-id.txt) -p "Continue"
GitHub Actions (True 24/7)
If you don't want to keep any machine running:
name: Claude Auto Work
on:
schedule:
- cron: '0 */6 * * *' # Every 6 hours
workflow_dispatch: # Manual trigger too
jobs:
work:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Claude
run: |
npx @anthropic-ai/claude-code -p "
Read TODO.md. Pick the highest priority incomplete item.
Complete it, update TODO.md, commit and push.
" --bare
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GitHub's machines are always awake. You sleep, it works. But this layer is the most dangerous without proper guardrails — Layer 3 matters here.
Layer 2: Don't Reset
This is the layer most people miss. Running persistently is useless if Claude Code doesn't know what it was doing. Every new session starts blank by default.
The core principle: write progress to the filesystem, not just the conversation.
TODO.md — The Simplest Progress File
The loop prompt references this directly:
Read TODO.md. Find the item marked "CURRENT" and work on it.
When done, check it off and move "CURRENT" to the next incomplete item.
If everything is complete, stop the loop.
Even if the session dies and restarts, it reads TODO.md and knows exactly where to pick up.
/checkpoint — Structured State Snapshots
Claude Code has built-in checkpointing that captures:
- Current git state
- Decisions made so far
- Remaining work
/checkpoint Save: auth refactor in progress, imports updated for 8/20 files
Resume later with:
/catchup
It reads the last checkpoint, gives you a briefing, and you say "continue."
Memory System — Long-Term Cross-Session Persistence
Claude Code's memory system writes persistent files that are automatically loaded in future sessions:
---
name: auth-refactor-progress
description: Tracks auth module refactoring progress
type: project
---
Auth refactor Phase 1 (file splitting) complete. Phase 2 (import updates) at file 8 of 20.
**Why:** Original auth.ts was 1200 lines, needs splitting into three modules.
**How to apply:** When auth refactor is mentioned, start from Phase 2, file 9.
Memory files are loaded automatically — no need to tell Claude Code to check them.
Plan Mode — Progress Tracking for Large Tasks
For tasks touching more than three files, start with Plan Mode:
/plan Refactor auth module
Claude Code outlines the steps. You approve. The plan itself is the progress record — which steps are done, which aren't.
Loop + Plan is powerful:
/loop 10m Check the current plan's progress. Execute the next incomplete step. Update the plan status after each step.
Git Commits as Checkpoints
Commit after every meaningful unit of progress. Make the message explicit:
feat: auth refactor phase 2 - updated imports (8/20 files)
If every other mechanism fails, git log is your progress ledger. Claude Code reads it and can infer where things stand.
Layer 3: Don't Go Rogue
The real fear with unattended AI isn't downtime — it's unsupervised action.
Hooks — Hard Guardrails
Claude Code hooks are deterministic controls that don't rely on model judgment:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hook": "echo 'No destructive commands' && [[ ! \"$TOOL_INPUT\" =~ (rm -rf|--force|--hard) ]]",
"description": "Block dangerous operations"
}
]
}
}
For unattended operation, add strict hooks:
- Block
git push --force - Block deletion of more than 5 files
- Block modification of
.envand credentials - Restrict edits to specific directories (
/freeze)
/freeze — Scope-Limited Editing
/freeze src/auth/
Claude Code can only modify files under src/auth/. Even if the loop drifts, it can't touch anything else.
Commit, Don't Push
For unattended tasks, default to "commit but don't push." Let it work locally, you review and push when you're back:
After completing each item, git commit. Do NOT push. Wait for my review.
Worst case: git reset. Nothing touches the remote.
Explicit Stop Conditions
Build failure conditions into the loop prompt:
/loop 10m Execute the next TODO.md item.
If any of the following happen, stop the loop and write a report to REPORT.md:
- Tests fail twice in a row
- A design decision requires my input
- You encounter an unfamiliar error
Do not guess. Do not work around it. Stop and wait for me.
Practical Configurations
Day-to-Day Development (At Computer, Stepping Away)
tmux + /loop 15m + TODO.md + /freeze
tmux keeps the session alive. /loop pushes progress forward every fifteen minutes. TODO.md tracks state. /freeze limits the blast radius. You leave for a meeting, come back to two or three more TODOs checked off.
Multi-Day Tasks (Can't Finish Today)
Plan Mode + /checkpoint + Memory + git commit
Plan Mode defines the steps. /checkpoint saves state. Memory persists across sessions. Git commits are your audit trail. Tomorrow: /catchup → "continue."
Unattended Monitoring (CI, Sync, Status)
crontab + claude -p --bare + hooks
System crontab triggers Claude Code every few hours. --bare for fast startup. Hooks block anything dangerous. It runs, reports, exits.
The Full Architecture
Common Pitfalls
Vague loop prompts
# Bad
/loop 10m Keep going
# Good
/loop 10m Read TODO.md. Find the "CURRENT" marker. Execute that item. Check it off and move the marker. Stop if all items complete.
Each loop iteration is a near-fresh state. Your prompt must include "where to find progress" and "how to decide what to do." Don't assume it remembers the last iteration.
No stop conditions
A loop without explicit stop conditions runs until tokens are exhausted or something breaks. Always define when it should stop.
Progress only in context
Claude Code's conversation context gets compacted or cleared. Anything important must be written to the filesystem — TODO.md, plans, memory, git commits. Context-only state is ephemeral by default.
Unattended + push = risk
Unless your CI/CD is robust (high test coverage, staging environment, review gates), don't let unattended Claude Code push to remote. Local commits only. You push after review.
The One-Liner
Persistent Claude Code isn't about keeping it running — it's about making sure every time it wakes up, it knows exactly what to do.
tmux keeps it alive. TODO.md keeps its memory. Hooks keep it safe. /loop ties them together. Set this up, and you have an AI engineer that picks up where it left off — it just needs you to check in occasionally and confirm the direction.
