CLAUDE LABJP
FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as OctoberFORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October
Articles/Claude Code
Claude Code/2026-05-09Intermediate

Designing Claude Code Skills That Actually Run Unattended — Three Patterns to Avoid Permission-Dialog Stalls

I learned the hard way that Claude Code skills can silently freeze in scheduled runs because of permission dialogs. Here are three implementation patterns that keep file work, path detection, and recovery fully autonomous — distilled from a month of running content automation across four sites.

claude-code129skills10automation95scheduled-tasks4headless12

The first time I noticed something was wrong, the scheduled task log just said "triggered at 12:00" and then nothing. The status stayed on "running" for hours. No stack trace, no timeout, no error. When I ran the same skill manually, it finished in two minutes.

It took me about two weeks to figure out the culprit was a permission dialog. Tools like Read, Write, Edit, and folder-selection prompts such as request_cowork_directory quietly wait for a human to approve them — even when no human is watching. In an unattended schedule, that wait never ends.

I run daily content automation across four sites with Claude scheduled tasks, and over the past month I've settled on three implementation patterns that make permission-dialog stalls impossible by construction. They apply to Claude Code skills, but the same thinking carries over to Cowork mode and the Claude Agent SDK.

Why "stalls in unattended runs" is the worst kind of failure

Permission-dialog stalls leave no traces. There's no stack trace, no timeout, no error message — the task simply looks like it's still running. You usually notice days later when you wonder why a deliverable hasn't shown up.

Three things make this failure mode especially dangerous:

  • It never reproduces in manual runs, because you click "OK" on the dialog without thinking about it.
  • It generates no telemetry, so you can't bisect with logs.
  • Each individual tool call looks correct in isolation, so code review won't catch it.

In my case, a single SKILL.md that used the Read tool instead of cat $FILE froze the schedule for 24 hours. I spent half a month blaming the VM before realising the problem was the tool choice itself.

The design rule for unattended skills is simple: never call a tool that can ask a human anything. The three patterns below are concrete ways to enforce it.

Pattern 1: Route every file operation through bash cat / sed

Claude Code's file tools (Read, Write, Edit) are great in interactive sessions, but treacherous in unattended ones. They run permission checks under the hood, and any path that hasn't been pre-approved triggers a dialog the moment it's touched.

For unattended skills, push every file operation into bash. Here's the rewrite I do across all my SKILL.md files:

# Bad (can stall in scheduled runs)
Step 2: Use the Read tool to load content/config.json,
        check the value, then update with the Write tool.
 
# Good (everything stays in bash)
Step 2: Run the following in bash:
 
  cat content/config.json | jq '.version'
 
  # Use heredoc for full rewrites
  cat << 'EOF' > content/config.json
  {
    "version": "1.2.3",
    "updated_at": "2026-05-09"
  }
  EOF
 
  # Use sed -i for partial edits
  sed -i 's/"version": ".*"/"version": "1.2.4"/' content/config.json

The << 'EOF' heredoc with single-quoted delimiter suppresses shell expansion, which makes it safe even for files containing backticks or dollar signs. I use it for config files, MDX, and HTML templates.

For partial edits, sed -i covers most cases. When Claude Code generates skill examples, it tends to reach for the Edit tool — for unattended use, swap every one of those calls to sed or awk. If the substitution is too complex for sed, a short python3 -c "..." snippet works just as well.

A useful side benefit of bash-only file work is that the resulting skill becomes portable. Anything you write in cat, sed, or awk runs identically inside a Docker container, on a CI worker, or in a remote server you SSH into. The moment a skill depends on Claude Code's built-in tools, it stops being usable outside the Claude environment. Choosing the lower-level building blocks keeps your automation transferable.

If you've ever had a skill silently fail to fire, the diagnosis steps in Skills not triggering in Claude Code: a checklist are a good starting point — but unattended-mode failures need the additional discipline above.

Pattern 2: Detect paths dynamically on every run

The second landmine in unattended execution is hardcoded paths. Each scheduled run lives in a fresh session, and workspace mount points can change between runs. A path that worked yesterday may not exist today.

Every one of my SKILL.md files starts with a single line that detects the workspace dynamically:

# Detect workspace each run (mount path varies per session)
WS="$(ls -d /sessions/*/mnt/Workspace\ Name 2>/dev/null | head -1)"
 
if [ -z "$WS" ]; then
  echo "Workspace not mounted"
  exit 1
fi
 
# Now everything below can use $WS safely
cat "${WS}/_config/settings.json"

Calling request_cowork_directory (or any similar folder-picker tool) opens a selection dialog. In unattended mode, that dialog hangs forever. Switching to dynamic detection means: if the workspace is mounted, the script proceeds; if not, it fails loudly and immediately. You convert "silent freeze" into "explicit failure", which is dramatically easier to operate.

The single biggest lesson from six months of running this stuff is: a loud failure is always better than a quiet stall.

The dynamic-detection pattern also helps when you have multiple workspaces. I keep separate mount points for each of the four sites I run, and using a parameterised lookup (Workspace\ Name becomes a variable) means one SKILL.md can serve all of them. The only thing that changes per site is the workspace name string passed in. That single discipline saved me from cloning the same skill four times with subtly diverging copies.

The same idea applies to Git work. I clone with --depth 1 into a fixed path under /tmp each time, and check df for free space before writing. The general posture for running Claude Code in CI overlaps with what I covered in running Claude Code headless with --bare.

Pattern 3: Build recovery that never asks the human

The third pattern is error handling. The single worst thing an unattended skill can do is ask "should I proceed?" when something goes wrong. Tools like Cowork's AskUserQuestion are wonderful in interactive mode and forbidden in scheduled mode.

My SKILL.md files spell out the recovery contract explicitly:

## Auto-recovery rules
 
- Bash command failed → try a different bash command that
  reaches the same goal (e.g., `git push` fails → `git pull
  --rebase` then retry).
- Repository corrupted → `rm -rf $WORK_DIR` and re-clone.
- Disk full → drop caches in stages; if still insufficient,
  log the failure and exit.
- Never write "next steps" or "please run manually" — nobody
  is reading the output.
 
If recovery is impossible, log Status: FAILED and exit. Never
ask the user, request approval, or pause for confirmation.

When this contract is at the top of the SKILL.md, Claude consistently picks "no human in the loop" whenever it has to make a judgement call. Without it, you sometimes get "let me confirm before proceeding" — which is exactly the freeze you were trying to avoid.

I usually layer two recovery paths: try the primary fix, fall back to a more drastic one (like recreating the working directory), then write Status: FAILED to a log file and exit. For my content pipeline, git push failures cascade through three steps — rebase-and-retry, force re-clone, then give up — and after a month of operation only a handful of failures have ever made it to the third step.

One detail worth highlighting: log the recovery attempts as you go, not just the final outcome. When my pipeline fails, I want to know whether it failed on the first try and recovered cleanly, or whether it cycled through every fallback. A simple counter (RETRY=$((RETRY+1))) and a one-line log entry per attempt is enough. Without that visibility, you cannot tell whether your recovery layers are doing real work or quietly papering over a deeper problem.

If you want fine-grained control on top of this, the permissions block in .claude/settings.json lets you put Read, Write, and Edit on the deny list for unattended skills, so any accidental call fails loudly. I covered the full mechanism in Claude Code permission modes for production security.

Always validate with one real scheduled run

One last piece of advice. Whenever you ship a new SKILL.md change, do not declare it done after a successful manual run. Permission-dialog bugs cannot reproduce locally, so the only valid test is an actual scheduled invocation.

My validation flow is:

  • Update the SKILL.md and run once manually to verify basic behaviour.
  • Set the scheduled task's "next run" to five minutes from now.
  • Wait, then read the execution log to confirm no dialog-related stall.
  • If clean, restore the normal cadence.

Since I started doing this, "the task froze overnight" has dropped to almost zero. Local testing gives almost no signal about unattended behaviour.

Try rewriting one line in your SKILL.md today

If you already have a skill in production, open its SKILL.md and replace one mention of Read or Write with cat or cat << 'EOF' > file. That single change usually makes the difference you'll feel within a day. For skills you want to grow into bigger workflows, Claude Code Skill Composition goes deeper into the structural side.

Unattended automation is invisible work — nobody notices when it's running well. That's exactly why investing once in a stall-proof design pays back every quiet morning that follows. Thanks for reading.

Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Claude Code2026-04-30
Composing Claude Code Skills — Building Automation a Single Skill Can't Reach
A practical guide to going beyond one-skill-at-a-time and composing multiple Claude Code Skills into real workflows. Pipeline, branching, and meta-skill patterns with full implementation examples and the failure modes you should design against.
Claude Code2026-04-25
Automating CI/CD Pipelines with Claude Code's --print and --output-format json
A practical guide to using Claude Code's --print flag and --output-format json in CI/CD pipelines. Covers automated code review in GitHub Actions, PR comment generation, and test failure analysis — with working code throughout.
Claude Code2026-03-24
How to Automate Game Development with Claude Code × unity-mcp — A Complete Workflow from Concept to Release
Learn how to combine Claude Code with unity-mcp to automate Unity game development. The hcg-workflows skill set provides an 8-phase workflow from planning to deployment.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →