scheduled-tasks dispatcher stopped honoring SKILL.md `model:` frontmatter on/around 2026-04-27 ~01-02 UTC
Bug: scheduled-tasks dispatcher stopped honoring SKILL.md model: frontmatter on/around 2026-04-27 ~01–02 UTC
Summary
As of approximately 2026-04-27 01:00–02:30 UTC, the Claude Code scheduled-tasks dispatcher stopped reading the model: frontmatter field in ~/.claude/scheduled-tasks/{id}/SKILL.md. Every scheduled task now runs on Opus regardless of what its frontmatter says — including tasks set to sonnet and tasks set to haiku. Pre-04-27 sessions for the same tasks ran on Sonnet/Haiku as the frontmatter specified.
This is a global behaviour change, not a per-task regression. Editing or re-saving SKILL.md after the change has no effect.
For Pro users this is invisibly costly (quota burn). For API users it's ~3× cost.
Environment
- Claude Code desktop app, Windows 11
~/.claude/scheduled-tasks/{id}/SKILL.mdstorage layoutmcp__scheduled-tasks__create_scheduled_task/update_scheduled_task/list_scheduled_tasks- Session metadata at
%APPDATA%/Claude/claude-code-sessions/<root>/<group>/local_*.json
Evidence: coordinated transition across 12 tasks within a 2-hour window
For each task with model: sonnet (or model: haiku) in frontmatter, I extracted the timestamp of the last Sonnet/Haiku session and the first Opus session that followed:
| Task | Frontmatter | Last non-Opus session (UTC) | First Opus session after (UTC) |
|---|---|---|---|
| meeting-digest-sweeper | sonnet | 2026-04-27 00:51 | 2026-04-27 01:06 |
| vbe-workflow-sync | sonnet | 2026-04-26 23:45 | 2026-04-27 02:08 |
| vbe-cache-refresh | haiku | 2026-04-26 23:45 | 2026-04-27 02:15 |
| learn-system-sync | sonnet | 2026-04-26 23:45 | 2026-04-27 02:18 |
| vbe-comment-staleness | sonnet | 2026-04-26 23:47 | 2026-04-27 02:19 |
| migration-matrix-refresh | (no model: line) | 2026-04-26 23:52 | 2026-04-27 02:28 |
| learn-daily-digest | sonnet | 2026-04-26 23:53 | 2026-04-27 16:10 |
| verify-scheduled-jobs | sonnet | 2026-04-26 23:53 | 2026-04-27 16:10 |
| onb-sync | sonnet | 2026-04-26 23:58 | 2026-04-27 16:13 |
| standup-digest | sonnet | 2026-04-27 00:51 | 2026-04-27 23:08 |
| learn-pending-processor | sonnet | 2026-04-28 18:06 | 2026-04-28 19:06 |
| learn-weekly-audit | sonnet | 2026-04-26 23:48 | 2026-05-03 22:29 (next dispatch — weekly) |
The "first Opus after" times trail by however long it took each task's cron to fire next. The earliest Opus session is 2026-04-27 01:06 UTC. Every task's very next dispatch after that boundary returned Opus, regardless of frontmatter.
Tasks that legitimately have model: opus (e.g. learn-monthly-audit, standup-digest-audit) and tasks with no model: line still run Opus — these are matching by accident or by default, not by the dispatcher reading frontmatter.
Why this isn't "the SKILL.md edits broke things"
A task's prior verification report attributed the regression to SKILL.md frontmatter edits made on 2026-04-29 to five specific tasks. That framing is wrong:
- The transition happened ~2 days earlier (04-27 ~01 UTC) and affected every task with non-Opus frontmatter, not just the 5 that were later edited.
- The 04-29 edits to those 5 SKILL.md files had no effect either way — the dispatcher had already stopped reading frontmatter.
Reproduction
- Pick any active scheduled task whose SKILL.md frontmatter has
model: sonnet. Confirm vialocal_*.jsonthat recent runs useclaude-opus-4-7[1m]. - Compare against earlier runs (pre-2026-04-27) — they used
claude-sonnet-4-6. - Edit the file: re-save with the same
model: sonnetline, or remove and re-add it. Wait for the next dispatch. Model is stillclaude-opus-4-7[1m]. - Try
update_scheduled_taskmutations:
update_scheduled_task(taskId, description=<same value>)→ next dispatch still Opus.update_scheduled_task(taskId, enabled=false)thenupdate_scheduled_task(taskId, enabled=true, fireAt=<near future>)→ next dispatch still Opus. (Verified 2026-05-05 00:03 UTC onmigration-matrix-refresh.)update_scheduled_task(taskId, fireAt=<near future>)on an active task → next dispatch still Opus. (Verified 2026-05-04 21:52 UTC onmigration-matrix-refresh.)
Why we can't work around it
mcp__scheduled-tasks__create_scheduled_taskschema has nomodelparameter.- There's no
delete_scheduled_tasktool — can't delete and recreate within the MCP. - Filesystem-level deletion of
~/.claude/scheduled-tasks/{id}/would orphan whatever scheduler state the runner keeps elsewhere. - Setting the global default via
~/.claude/settings.json"model": "sonnet"does NOT help, even after a full Claude Code app restart. Verified 2026-05-05: after adding"model": "sonnet"to user-level settings.json, restarting the desktop app, and letting cron-driven dispatches fire naturally, every scheduled-task session still launched on Opus. Sample (post-restart cron firings, 2026-05-05 02:46–02:47 UTC): vbe-workflow-sync(frontmatter: sonnet) → Opusvbe-cache-refresh(frontmatter: haiku) → Opuslearn-system-sync(frontmatter: sonnet) → Opus
Neither the frontmatter nor the global default is read at dispatch time. The dispatcher appears to have its own hardcoded or per-task-cached model selection that no user-facing config affects.
Asks
- Restore frontmatter-honoring behaviour at dispatch time, OR expose
modelas an explicit parameter oncreate_scheduled_taskandupdate_scheduled_task. - Add a
delete_scheduled_tasktool to themcp__scheduled-tasks__*surface. - Document the current behaviour in the meantime so users on Pro plans know their
model: sonnetconfigurations are silently being ignored.
Workaround currently in use
Disabled the most expensive scheduled tasks (enabled: false) until a fix lands.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗