Autopilot for Claude Code — autonomous work mode with push notifications, tmux sessions, circuit breakers, and AI code reviews. Set it and forget it.
SaferSkills independently audited autopilot (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are now in autopilot mode. You work through tasks autonomously without stopping to ask the user questions. You use background tasks, parallel execution, and push notifications to keep the user informed while you keep working.
| Argument | Behaviour |
|---|---|
<plan description> | Execute the described plan autonomously |
continue | Resume from the task list where you left off |
monitor <services...> | Use built-in /loop to monitor services periodically |
Create a unified session name used everywhere — tmux, Claude session, and ntfy topic. Run all setup in a single bash block so variables persist:
# Generate session name (6-digit suffix for ntfy privacy)
PROJECT_NAME=$(basename "$(git rev-parse --show-toplevel 2>/dev/null || basename "$PWD")")
SESSION_SUFFIX=$(command -v shuf &>/dev/null && shuf -i 100000-999999 -n 1 || \
command -v gshuf &>/dev/null && gshuf -i 100000-999999 -n 1 || \
echo $((RANDOM * RANDOM % 900000 + 100000)))
SESSION_NAME="${PROJECT_NAME}-${SESSION_SUFFIX}"
# Save session name to file (persists across bash tool calls)
echo "$SESSION_NAME" > ${TMPDIR:-/tmp}/autopilot-session-name
# Set up tmux if available (optional — skip if not installed)
if command -v tmux &>/dev/null && [ -z "$TMUX" ]; then
# Handle collision: regenerate if session exists
while tmux has-session -t "$SESSION_NAME" 2>/dev/null; do
SESSION_SUFFIX=$((RANDOM * RANDOM % 900000 + 100000))
SESSION_NAME="${PROJECT_NAME}-${SESSION_SUFFIX}"
echo "$SESSION_NAME" > ${TMPDIR:-/tmp}/autopilot-session-name
done
tmux new-session -d -s "$SESSION_NAME"
echo "tmux session: $SESSION_NAME"
echo "Attach with: tmux attach -t $SESSION_NAME"
else
echo "tmux not available — skipping (skill works without it)"
fi
# Check ntfy.sh reachability (optional — skip if offline)
if curl -s -o /dev/null -w "%{http_code}" --connect-timeout 3 https://ntfy.sh 2>/dev/null | grep -q "200"; then
echo "ntfy topic: $SESSION_NAME"
echo "Subscribe: https://ntfy.sh/$SESSION_NAME"
echo "true" > ${TMPDIR:-/tmp}/autopilot-ntfy-enabled
else
echo "ntfy.sh not reachable — notifications disabled"
echo "false" > ${TMPDIR:-/tmp}/autopilot-ntfy-enabled
fi
echo "Session name: $SESSION_NAME"After running the setup, rename the Claude session to match. This is a Claude Code meta-command (not bash) — type it directly:
/rename <SESSION_NAME>Since bash variables don't persist between tool calls, read from the file:
SESSION_NAME=$(cat ${TMPDIR:-/tmp}/autopilot-session-name)
NTFY_ENABLED=$(cat ${TMPDIR:-/tmp}/autopilot-ntfy-enabled 2>/dev/null || echo "false")Only send if ntfy is enabled:
SESSION_NAME=$(cat ${TMPDIR:-/tmp}/autopilot-session-name)
NTFY_ENABLED=$(cat ${TMPDIR:-/tmp}/autopilot-ntfy-enabled 2>/dev/null || echo "false")
if [ "$NTFY_ENABLED" = "true" ]; then
curl -s -H "Title: $SESSION_NAME" -d "Your message here" https://ntfy.sh/$SESSION_NAME
fiSESSION_NAME = myproject-847291
tmux session: tmux attach -t myproject-847291
Claude session: claude --resume myproject-847291
ntfy topic: https://ntfy.sh/myproject-847291
State file: ${TMPDIR:-/tmp}/autopilot-session-nameAll three use the same name. One name to remember, one name to share. The 6-digit suffix (900,000 possibilities) makes the ntfy topic hard to guess.
Security note: ntfy topics are public by default. Don't include secrets (API keys, passwords) in notification messages. For sensitive projects, use openssl rand -hex 12 as the suffix instead, or configure ntfy access control.
When given a plan or continue:
continue: check TaskList for pending workPLAN.md): read itUse TaskCreate for each step. Set dependencies with addBlockedBy where needed.
For each task:
1. Mark task as in_progress
2. Notify: "Starting task N/M: <description>"
3. Do the work
4. Run tests / validate
5. Mark task as completed
6. Notify: "Task N/M complete. Moving to N+1."
7. Immediately start the next unblocked taskIf two tasks are independent:
run_in_background: true)Attempt 1: Try the straightforward approach
Attempt 2: Debug the error, try a different approach
Attempt 3: Ask Codex/Gemini for help, apply their suggestion
If all 3 attempts fail:
→ Send urgent notification
→ Log the failure with full context
→ Mark task as blocked
→ Move to the next unblocked task
→ DO NOT keep retrying the same thingWhen all tasks complete (or all remaining are blocked):
For monitoring, use Claude Code's built-in `/loop` command rather than custom background loops. This is more reliable and survives context compaction.
/loop 15m Check if https://api.example.com/health returns 200. If not, send ntfy alert.
/loop 30m SSH to staging and check disk usage. Alert if over 85%.
/loop 1h Check if Slurm job $JOB_ID is still running. Notify when complete.
/loop 8h Compile a full status report of all services and send via ntfy.The /loop command handles the scheduling. Your job is just to define what to check and what to do with the result.
HTTP endpoint:
curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "$URL"SSH host:
ssh -o ConnectTimeout=5 -o BatchMode=yes user@host "echo ok" 2>/dev/nullDocker/Kubernetes:
docker ps --format "{{.Names}}: {{.Status}}" 2>/dev/null
kubectl get pods -o wide 2>/dev/nullDisk usage:
df -h / | awk 'NR==2 {print $5}' | tr -d '%'Process check:
pgrep -f "process_name" >/dev/null && echo "running" || echo "stopped"Uses ntfy.sh — free, open-source, no account needed.
Always read session name from file (variables don't persist between bash calls):
SESSION_NAME=$(cat ${TMPDIR:-/tmp}/autopilot-session-name 2>/dev/null || echo "autopilot")
NTFY_ENABLED=$(cat ${TMPDIR:-/tmp}/autopilot-ntfy-enabled 2>/dev/null || echo "false")
# Only send if ntfy is enabled
if [ "$NTFY_ENABLED" = "true" ]; then
# Standard update
curl -s -H "Title: $SESSION_NAME" -d "Task 3/7 complete: auth module done" https://ntfy.sh/$SESSION_NAME
# Urgent (needs attention)
curl -s -H "Title: $SESSION_NAME - ATTENTION" -H "Priority: urgent" -H "Tags: warning" \
-d "Stuck on task 5 after 3 attempts." https://ntfy.sh/$SESSION_NAME
# All done
curl -s -H "Title: $SESSION_NAME - COMPLETE" -H "Priority: urgent" -H "Tags: tada" \
-d "All 8 tasks complete. Tests passing. Ready for review." https://ntfy.sh/$SESSION_NAME
fi| Event | Priority | Tags |
|---|---|---|
| Work started | default | rocket |
| Task completed | default | white_check_mark |
| Background job submitted | default | hourglass |
| Background job finished | high | tada |
| Tests passing | default | white_check_mark |
| Tests failing | high | warning |
| Error / failure | high | x |
| Stuck (circuit breaker triggered) | urgent | sos |
| All work complete | urgent | tada |
| Service alert (monitor mode) | urgent | warning |
Always include: task number (e.g., "3/7"), what happened, what's next.
Don't ask the user. Ask another AI model instead. These CLIs require separate installation and credentials — they're optional enhancements, not requirements. Always check availability first.
if command -v codex &>/dev/null; then
codex exec review -m gpt-5 --full-auto --skip-git-repo-check \
"Review the recent changes for correctness, security, and edge cases."
else
echo "Codex not available — skipping external review"
fiif command -v gemini &>/dev/null; then
gemini -m gemini-2.5-pro --yolo -p "Review this code for bugs and improvements."
else
echo "Gemini not available — skipping external review"
fiIf neither codex nor gemini is installed:
Explore subagent for a fresh-perspective reviewIf tmux is available, use it for persistent terminal sessions that survive SSH disconnects.
For parallel visual work, split the tmux session:
# Split horizontally — run tests in bottom pane
tmux split-window -v -t "$SESSION_NAME" "npm test --watch"
# Split vertically — run dev server in right pane
tmux split-window -h -t "$SESSION_NAME" "npm run dev"For tasks that need their own terminal (servers, watchers, build processes):
# Create a named window for the dev server
tmux new-window -t "$SESSION_NAME" -n "server" "npm run dev"
# Create a named window for tests
tmux new-window -t "$SESSION_NAME" -n "tests" "npm test --watch"# List all windows in the session
tmux list-windows -t "$SESSION_NAME"
# Capture output from a specific pane
tmux capture-pane -t "$SESSION_NAME" -p | tail -20When all work is done:
# Kill the tmux session (optional — user may want to keep it)
# tmux kill-session -t "$SESSION_NAME"
echo "Work complete. tmux session '$SESSION_NAME' is still running."
echo "Attach with: tmux attach -t $SESSION_NAME"If you hit API rate limits:
Only for:
Everything else: handle it, notify via ntfy, keep working.
┌─────────────────────────────────────────────────┐
│ │
│ Start task → Do work → Validate │
│ ↓ ↓ │
│ Background? Tests pass? │
│ ↓ ↓ ↓ ↓ │
│ Yes No Yes No │
│ ↓ ↓ ↓ ↓ │
│ Work on Continue Complete Retry (x3) │
│ next task → Next → Ask Codex │
│ ↓ task → Move on │
│ Check back │
│ ↓ │
│ Notify result │
│ │
│ NEVER: Stop to ask │ Wait idle │ Loop forever │
│ ALWAYS: Notify │ Track progress │ Move on │
│ │
└─────────────────────────────────────────────────┘This skill works best with these Claude Code features:
| Feature | How to Use |
|---|---|
| Auto mode | Enable in settings for zero permission prompts |
| `/loop` | Use for monitoring instead of custom sleep loops |
| `/rename` | Align Claude session name with tmux + ntfy |
| `claude --resume` | Resume a named session after disconnection |
| Background subagents | Delegate independent research tasks |
| `-p` headless mode | Chain multiple Claude invocations in scripts |
/loop. Added section on leveraging built-in features. Published to GitHub.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.