Desktop scheduled tasks: model selection broken end-to-end (spawns ignore user settings; documented picker absent; MCP tool lacks model param)

Status Open
Reported on v2.1.219
Maintainer reply None cached
Activity 7 comments · opened Sep 3, 2026

Bug report: Desktop scheduled tasks — model selection broken end-to-end

Environment: Claude Desktop (macOS) 1.24012.9, claude-code CLI 2.1.219+, macOS Darwin 25.5.0.
Two desktop profiles under one account, each with its own scheduled-task registry.

Summary

There is currently no working way to control which model a desktop scheduled task runs on, and scheduled-task spawns only sometimes honor user settings.
Three independent defects compound:

1. Scheduled-task spawns ignore user settings on most runs (primary bug)

User settings: "model": "best", "effortLevel": "xhigh", "fallbackModel": ["claude-opus-5"], no env overrides, no managed settings.
Across 148 scheduler-spawned sessions (Jun 3 – Sep 3) the session records show exactly two spawn profiles:

  • Profile A (116 sessions): stamps the newest Opus [1m] model, no effort key, no sessionSettings. Ignores user settings entirely. Never once produced Fable 5 (consistent with no fable[1m] variant existing).
  • Profile B (32 sessions): inherits user settings and the app's live ultracode state (sessionSettings: {"ultracode": true}, effort: "xhigh", model resolving per the best alias → claude-fable-5). Every observed Fable run is Profile B.

Which profile a run gets flips per run, not per task — e.g. on 2026-09-03 the 07:53 task spawned Profile B (claude-fable-5, ultracode) and the 08:24 task spawned Profile A (claude-opus-5[1m]), same build, same profile, 31 minutes apart.
Selection is recorded nowhere (task store, session records, settings) and matches no documented behavior.

2. The documented Edit-form model picker is absent

desktop-scheduled-tasks docs: "The instructions input includes pickers for the permission mode and model."
In build 1.24012.9 the Edit form shows no model picker. No changelog entry indicates when this feature shipped or its gating.

3. The documented "ask Claude" fallback cannot work

Same docs say the task model can be changed "through the Edit form or ask Claude."
The update_scheduled_task / create_scheduled_task MCP tools accept only
taskId, prompt, description, cronExpression, fireAt, enabled, notifyOnCompletion — no model parameter (schema re-fetched 2026-08-03, 2026-08-21, 2026-09-03; unchanged).
The task store (claude-code-sessions/<account>/<profile>/scheduled-tasks.json) carries no model-like key on any of 20 task entries across both profiles.

Impact

Users who need a specific model on unattended scheduled runs (e.g. Fable 5 with Opus fallback) cannot get it deterministically:
~78% of runs draw Profile A and silently execute on a model the user did not choose, at default effort, with ultracode orchestration silently absent.
Headless runs surface no notice of any of this.

Requests

  1. Make all scheduled-task spawns resolve model/effort from user settings (or document why Profile A exists and how to disable it).
  2. Ship the per-task model picker the docs already describe, or correct the docs.
  3. Add model (and ideally effort) parameters to update_scheduled_task / create_scheduled_task so the documented "ask Claude" path works.

Evidence available on request

Full session-record analysis (148 spawns with timestamps/models/effort/sessionSettings), task-store dumps from both profiles, settings history with backups.

View original on GitHub ↗

3 Comments

Suchspezi · 1 month ago

Root cause located in the desktop bundle + a working workaround (Windows, Desktop 1.46388.1 / CLI 2.1.260)

I can confirm all three defects on Windows 11 and add two findings that may help triage:

1. Why the picked model is never persisted. In resources/app.asar the model resolver has an early return for exactly the two scheduled-task actions:

tje = new Set(["scheduled_task_create","scheduled_task_update"]);
function Cl(e,t,n){ if (tje.has(n)) return; /* … */ return r.model ?? t }

The create/update paths assign model: i ? i(t.model, "scheduled_task_create") : t.model, so the value becomes undefined and the store never gets a model field (0 of 36 tasks here). The same code is present in the staged 1.46388.2.

2. Why runs ignore user settings ("Profile A"). Observed process command line of a scheduled-task session (Get-CimInstance Win32_Process):

claude.exe --output-format stream-json --input-format stream-json --model default --permission-prompt-tool stdio --setting-sources=user,project,local …

The app passes the literal alias default. The CLI resolves default by account type (Max → Opus) and --model overrides the model setting, so "model": "sonnet" in settings.json can never apply. The warm-session path normalizes "default" to "no flag" (d = l.push === "default" ? void 0 : l.push), which is when settings.json does apply — that matches the per-run flip between Profile A and B.

3. Workaround that works (measured). Because default is documented as overridable by ANTHROPIC_DEFAULT_MODEL, putting it into the settings env block redirects every --model default launch:

| launch | modelUsage |
|---|---|
| claude -p … --model default | claude-opus-5[1m] |
| same, settings {"env":{"ANTHROPIC_DEFAULT_MODEL":"claude-sonnet-5"}} | claude-sonnet-5 |
| ANTHROPIC_MODEL=claude-sonnet-5 + --model default | claude-opus-5[1m] (flag wins, as documented) |

Over 48 scheduled runs (02–04 Sep) before the workaround, 100 % had Opus in the top-level session despite "model": "sonnet". Verified on a real scheduled run today (04 Sep, "Run now" on a task): the app still spawned --model default, and the first assistant message ran on claude-sonnet-5.

A fix on the app side would be to stop discarding the model for scheduled_task_create/update and to pass the resolved model (or nothing) instead of the literal default when a task has no model. Happy to share the full measurement scripts.

Suchspezi · 1 month ago

Repro/measurement scripts (as promised above): https://gist.github.com/Suchspezi/52aa1a2a3e53aed4265b96086846ac36

Both are read-only, scan ~/.claude/projects/*/*.jsonl, no dependencies. modell-audit.js gives the per-day model/switch breakdown; cron-subagent-audit.js gives the top-level-vs-subagent token split used in the numbers above.

tobitheking07 · 1 month ago

Confirming on macOS 26.5.1 (arm64), Claude Code CLI 2.1.92, Desktop app, consistent with the early-return finding above.

Symptom: the per-routine model picker shows Sonnet 5. Setting it to Opus 5 does not stick — it is back on Sonnet 5 on the next look, matching Cl() returning early for scheduled_task_create / scheduled_task_update.

User settings are ignored too:

{ "model": "opus[1m]", "effortLevel": "max" }

Both scheduled tasks still run on Sonnet 5.

Supporting detail: neither task's SKILL.md frontmatter contains a model: key at all — only name: and description:. Consistent with the selection never being written anywhere, rather than being written and then overridden at spawn time.

Why this matters beyond model choice: these two routines perform unattended production server maintenance (security updates, service restarts, reboot decisions on a live e-commerce VPS). Silently running them on a different model than the one deliberately configured is a correctness concern, not just a cost or preference one — and there is currently no way to tell from the UI that the selection was discarded.

Workaround for anyone hitting this: write the task prompt so it does not depend on model strength — spell out every non-obvious decision explicitly rather than leaving it to judgement.

Showing cached comments. Read the full discussion on GitHub ↗