[BUG] v2.1.206 silently broke unattended scheduled tasks: runs no longer inherit permissions.defaultMode, fall back to Manual, and per-task mode has no programmatic or bulk control

Status Open
Reported on v2.1.205
Maintainer reply None cached
Activity 6 comments · opened Jul 15, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Environment

  • Claude Code Desktop (Windows 11 Pro, 10.0.26200)
  • Worked through v2.1.205; broken from v2.1.206 (observed on v2.1.209, auto-updated 2026-07-14/15)

Summary

v2.1.206 changed how scheduled tasks determine their permission mode. Before, scheduled-task runs inherited permissions.defaultMode from the project's .claude/settings.local.jsonbypassPermissions there made every routine run unattended, which is the entire point of a scheduled task. From v2.1.206, each task has its own permission mode, settable only in the desktop app's Edit form, and every existing task silently fell back to Manual.

Result: the desktop app auto-updated overnight and the next morning every scheduled run started stalling on permission prompts with nobody there to answer them. I run 11 production routines on this machine (daily reporting, budget pacing, Slack posts, a scheduled approvals sweep that executes ad-platform changes). Three of them poll every 10 minutes during one hour of the morning — every tick now throws an approval prompt. The user is having to sit and click "bypass" on every single run, which defeats the feature's purpose.

Verified by diffing session transcripts across versions: runs launched by <=2.1.205 have "permissionMode":"bypassPermissions"; runs launched by 2.1.209 have "permissionMode":"default" — with zero settings changes on my side (settings file mtime predates the update by a month).

What makes this worse than an ordinary behavior change

  1. No migration. Tasks that had run in bypass daily for months were silently downgraded. If defaultMode inheritance was being removed, the migration should have stamped each existing task with the mode it was actually running under — or at least surfaced a one-time notice listing affected tasks.
  1. No changelog warning. The v2.1.206 entry only says the "default" mode was renamed to "Manual". It never mentions scheduled tasks or that runs would stop inheriting defaultMode. This converts working unattended automation into interactive automation — that's a breaking change and deserves a loud callout.
  1. No programmatic remedy.
  • create_scheduled_task / update_scheduled_task (the app's own MCP tools) expose no permission-mode parameter.
  • The mode is not stored in the task's SKILL.md or any user-editable file — it lives in the app's internal DB.
  • There is no bulk "set all tasks to X" control.
  • Computer-use automation can't help either, since the app (correctly) refuses to control its own window.

So a user with 11 routines must fix an update-induced regression by hand, in a UI, 11 times — and again for every future task, since new tasks default to Manual.

  1. The failure mode is silent. A Manual-mode scheduled run doesn't error or notify — it sits on a prompt until someone looks. For time-sensitive automation (scheduled ad-platform budget changes), a silent stall is the worst possible failure mode.
  1. Allowlists don't fully mitigate. Even after building a 57-rule allowlist in ~/.claude/settings.json covering every command and MCP tool the routines use (derived from scanning 274 scheduled-run transcripts), runs still prompt on every launch. Whatever run-level gate Manual mode applies to scheduled sessions is not suppressible by permission rules at all.

Steps to reproduce

  1. On <=2.1.205, set "permissions": { "defaultMode": "bypassPermissions" } in the project's .claude/settings.local.json and create a recurring scheduled task. Observe runs launch in bypass and complete unattended.
  2. Update to >=2.1.206 (or 2.1.209).
  3. Observe the next scheduled run launches with "permissionMode":"default" and stalls on permission prompts. Nothing in the UI or logs announces the change.

Expected behavior

Existing tasks keep their effective permission mode across the update, or the user is explicitly told which tasks changed and given a one-click way to restore them.

Requests

  1. Restore a global control — honor permissions.defaultMode (or add scheduledTasks.defaultPermissionMode) as the default for tasks with no explicit per-task mode. Per-task override is fine; per-task-only is not.
  2. Expose the permission mode programmatically — in create_scheduled_task / update_scheduled_task and/or the task's on-disk definition.
  3. Migrate on breaking changes — preserve prior effective mode, or block the first post-update launch with a list of affected tasks.
  4. Call out automation-breaking changes in the changelog in plain terms.
  5. Alert on stalled runs — if a scheduled run waits on a permission prompt more than a few minutes, notify instead of failing silently.

Related (not duplicates)

  • #76141 — "Always allow" decisions don't persist across scheduled runs (same symptom cluster)
  • #76469 — routine permission-mode edit doesn't save (Windows) — if this affects the Edit-form fix too, there is currently no working path back to unattended runs on Windows
  • #33027 — "Always allow" option missing from scheduled-task prompts
  • #76340 (closed) — scheduled tasks stall silently on permission prompts

I understand the security motivation for tightening unattended permissions, and I'm not asking for bypass-by-default. I'm asking that a deliberate configuration users already made not be silently discarded by an auto-update, and that the replacement mechanism be automatable by the same users the feature exists for.

Happy to provide session transcripts, timestamps, and task definitions on request.

What Should Happen?

Scheduled tasks created under the old behavior should keep running unattended after the update — either by preserving each task's prior effective permission mode during migration, or by continuing to honor permissions.defaultMode for tasks with no explicit per-task mode. At minimum, the update should have surfaced a one-time notice listing the affected tasks with a one-click way to restore their previous mode. Additionally, the per-task permission mode should be settable programmatically (via create_scheduled_task / update_scheduled_task or the task's on-disk definition), not only by hand in the desktop Edit form, and a scheduled run stalled on a permission prompt should raise a notification instead of failing silently.

Error Messages/Logs

Session transcript evidence (first permissionMode entry per scheduled-run session, morning of 2026-07-15, ET; session IDs truncated, task names redacted):

f3e5be23  v2.1.205  task-A (daily, 10-min poll)   "permissionMode":"bypassPermissions"   (08:58, before app update)
e516f431  v2.1.209  task-A (same task)            "permissionMode":"default"             (09:07)
2fef171a  v2.1.209  task-B                        "permissionMode":"default"             (09:06)
5444b4ab  v2.1.209  task-C                        "permissionMode":"default"             (09:12)
a0345b0a  v2.1.209  task-D                        "permissionMode":"default"             (09:09)
0da7cfd9  v2.1.209  task-E                        "permissionMode":"default"             (09:02)
35cec9b1  v2.1.209  task-F                        "permissionMode":"default"             (08:58)

Project .claude/settings.local.json contains "defaultMode": "bypassPermissions"; file mtime 2026-06-15 (a month before the update). No user-level or managed settings override exists.

Steps to Reproduce

  1. On Claude Code Desktop <= 2.1.205, set the following in the project's .claude/settings.local.json:

``json
{ "permissions": { "defaultMode": "bypassPermissions" } }
``

  1. Create a recurring scheduled task in the desktop app (any prompt that runs a shell command, e.g. a daily script run).
  2. Observe runs launch with "permissionMode":"bypassPermissions" in the session transcript and complete unattended. (This was our steady state for ~2 months across 11 tasks.)
  3. Let the app auto-update to >= 2.1.206 (observed on 2.1.209).
  4. Observe the next scheduled run launches with "permissionMode":"default" (Manual) and stalls on permission prompts. No settings were changed; nothing in the UI, logs, or changelog announces that existing tasks changed behavior.
  5. Note there is no way to restore the old behavior except opening each task's Edit form in the desktop UI and setting its permission mode by hand, one task at a time — the mode is not exposed in create_scheduled_task / update_scheduled_task, not stored in the task's SKILL.md, and has no bulk control.

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.205

Claude Code Version

2.1.209 (Claude Code Desktop, Windows)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Non-interactive/CI environment

Additional Information

Context: this is the Claude Code Desktop app on Windows (scheduled tasks / routines feature), so "Terminal/Shell" doesn't strictly apply — runs are headless/non-interactive, which is exactly why Manual mode is unworkable for them.

View original on GitHub ↗

5 Comments

Knuckles92 · 1 month ago

I am having this same issue.

I properly receive the "Allow for all Schedules runs" prompt, but it never persisits. If it choose that option, i am hit with the same permissions/approval prompt every time. I am happy to provide screenshots or debugging steps if needed.

jakedmochowski-ww · 1 month ago

Thanks @Knuckles92 — screenshots would be great, especially of the "Allow for all scheduled runs" prompt not persisting; that matches #76141 and suggests the persistence layer for scheduled-run permission decisions is broken generally, not just the defaultMode migration.

Two updates from my side:

  1. Still reproducible on 2.1.215 — runs continue to launch in Manual ("permissionMode":"default" in session transcripts) with no settings changes on my side.
  2. Per #76469, the Edit-form permission-mode change silently fails to save specifically for routines created via natural language (create_scheduled_task), while form-created routines save correctly. All 11 of my affected routines are NL-created, which may be a useful triage clue for where the per-task mode read/write diverges.
dannybyrnes · 1 month ago

Confirming this on macOS — this issue and #76469 are both labeled platform:windows, but the same failure occurs here. The failure mode on this machine is intermittent, which matches neither the one-time migration downgrade described here nor the "edit never saves" in #76469.

Environment: Claude Desktop 1.24012.9, macOS 26.5.2 (25F84); claude --version on the same machine reports 2.1.143. Two routines, both created via create_scheduled_task (NL/MCP), not the New routine form.

77 routine-spawned sessions on this machine:

| permissionMode | sessions | 0-turn runs | % dead |
|---|---|---|---|
| bypassPermissions | 71 | 4 | 6% |
| default | 6 | 6 | 100% |

Every run that spawned in default did zero turns — blocked on the first permission prompt, wrote nothing to its run log, and sat silently in the sidebar. n=6 is small, but the split is clean.

The mode reverts intermittently rather than staying downgraded. Per task: one routine 54 bypassPermissions / 3 default; the other 16 / 3. The default runs, with the per-task mode set to Bypass permissions in the Routines UI throughout:

2026-07-16 12:01  turns=0
2026-07-17 18:50  turns=0
2026-07-20 08:27  turns=0
2026-07-22 09:32  turns=0
2026-07-24 16:22  turns=0
2026-07-29 08:18  turns=0

So the setting persists and takes effect 71 of 77 times, then silently drops to default every few days — and when it does, the run is guaranteed dead and silent. For unattended automation that is arguably worse than a permanent downgrade: it works often enough that you stop checking.

This may refine the triage clue above. @jakedmochowski-ww suggested NL-created routines (#76469) as the divergence point. Both of mine are NL/create_scheduled_task-created, and their mode does save and take effect the large majority of the time — so NL-creation alone doesn't look sufficient to explain it. At least on macOS the read/write path works, and something resets it intermittently at spawn.

One weak correlation I can't turn into a reliable repro: one revert (07-17) landed in the same minute both tasks were edited via update_scheduled_task. The 07-29 revert had no such call anywhere near it.

Reproducing the measurement (macOS): session metadata lives at ~/Library/Application Support/Claude/claude-code-sessions/<a>/<b>/local_<sessionId>.json, with scheduledTaskId, permissionMode, completedTurns, and createdAt. Runs having a scheduledTaskId and completedTurns: 0 are the dead ones.

Re: "Alert on stalled runs" in your Requests list — strongly seconding it. Because the failure is silent, I ended up writing a SessionStart hook that scans those session JSONs and flags any routine run with 0 turns (with a 30-minute idle threshold so in-flight runs aren't caught). It converts a silent failure into a visible one but doesn't prevent it. Needing it at all is the argument for that request.

jakedmochowski-ww · 1 month ago

Windows data point, and a measurement caveat.

Spawn-mode measurement (Windows 11, Claude Code Desktop 2.1.215+): across all 133 routine-spawned sessions on this machine since 7/22, 100% spawned with permissionMode: "default" — zero in bypass. That includes routines recreated from scratch via New routine → Local form with Bypass permissions set at creation (the path #76469 reports as working). On this machine the per-task mode appears to be ignored at spawn entirely; the only reason runs complete is that I manually flip each session to bypass — daily, per run.

Measurement caveat for @dannybyrnes' method: permissionMode in local_<sessionId>.json is the session's final mode, not its spawn mode — on an attended machine, manual mid-session flips overwrite it (this initially made my form-recreated routines look like they were "holding bypass"; they weren't). Spawn mode is the first permissionMode entry in the CLI session transcript, mappable via the cliSessionId field in the same JSON. Your unattended 0-turn data is probably unaffected, but re-measuring spawn-time values might sharpen the picture.

Net: Windows looks deterministically broken at spawn (100% Manual across 133 runs), macOS intermittently (your 6/77) — possibly two layered bugs in per-task mode resolution.

dannybyrnes · 1 month ago

@jakedmochowski-ww — you were right about the method, and re-measuring changes my numbers substantially. Three corrections to my comment above.

1. Spawn mode vs final mode. I was reading permissionMode straight from local_<sessionId>.json, which as you say is the final mode. Re-measured spawn mode as the first permissionMode entry in the CLI transcript, joined via cliSessionId. Resolved for all 77 sessions:

| spawn → final | sessions |
|---|---|
| bypassPermissionsbypassPermissions | 54 |
| defaultbypassPermissions | 17 |
| defaultdefault | 6 |

So 23 of 77 (30%) actually spawned in default — not the 6 (8%) I reported. The missing 17 are exactly the contamination you described: runs that spawned Manual and were flipped to bypass mid-session, which my method scored as healthy.

2. Dead runs, by spawn mode:

| spawn mode | sessions | 0-turn | % dead |
|---|---|---|---|
| bypassPermissions | 54 | 2 | 4% |
| default | 23 | 8 | 35% |

Eight rather than six because two sessions spawned Manual, got flipped, and still completed no turns.

3. Version, my error. I quoted claude --version as 2.1.143 — that's a stale CLI install on the PATH, not what runs the routines. The Desktop app here runs claude-code 2.1.219, i.e. after 2.1.206, so my data sits inside the affected range rather than before it as my number implied.

Revised read: macOS is much closer to your Windows result than my first pass implied — 30% spawning Manual, not 8% — but it still isn't deterministic here; 54 of 77 genuinely do spawn in bypass. So either one bug with a far higher hit rate on Windows, or your two-layered-bugs reading. Either way the per-task mode is not reliably honored at spawn on macOS either, and the difference looks like degree rather than kind.

For anyone reproducing on macOS: take cliSessionId from local_<sessionId>.json, find ~/.claude/projects/<sanitized-cwd>/<cliSessionId>.jsonl, and read the first permissionMode value appearing anywhere in it. Diffing that against the JSON's own permissionMode is what surfaces the mid-session flips — and without that diff, an attended machine will systematically under-count the failure.

Showing cached comments. Read the full discussion on GitHub ↗