[Bug]: schedule_task can't set model or reasoning effort, and silently ignores modelSelection#16833

openedOct 7, 2026byJjlipworth

Problem

An agent creating a scheduled task over MCP can't pick the model or its options (for example reasoning effort) for the runs.

  • schedule_task always copies the calling thread's selection (or the project default) when the task is created (apps/server/src/mcp/OrchestratorMcpService.ts:1528).
  • update_scheduled_task always keeps the stored selection (OrchestratorMcpService.ts:1623).
  • Neither input schema has a model field (packages/contracts/src/orchestratorMcp.ts:520-542, 587-594), and the input isn't strict, so an agent that passes modelSelection gets a success response while the field is dropped.
  • The returned summary (orchestratorMcp.ts:546-564) doesn't include the model, options or modes, so the agent can't see that its setting was dropped.

The server, the runner and the mobile editor already support a full selection per task (ScheduledTask.modelSelection, used at apps/server/src/scheduledTasks/ScheduledTaskService.ts:802,825), and #16592 adds the same controls to the web editor. Only the MCP tools are missing it.

Steps to reproduce

  1. In a thread running Claude Opus 5.5 at default effort, have the agent call schedule_task with a fixed_time schedule, bindToCurrentThread: false, and an extra modelSelection that sets effort to xhigh.
  2. The call succeeds, and neither the result nor list_scheduled_tasks shows a model or effort.
  3. scheduled_tasks.model_selection_json contains only {"instanceId":"claudeAgent","model":"claude-opus-5-5","options":[{"id":"fastMode","value":false}]}, so the run uses default effort.

Expected behavior

The agent can set the provider, model and options for a scheduled task, and can see what a task will run with.

Suggested fix

  • Add an optional target (reuse OrchestratorMcpTarget, orchestratorMcp.ts:100-128, the same field the other work-starting tools take) to schedule_task and update_scheduled_task. Resolve it the same way those tools do: validate it against orchestrator_capabilities, and inherit options only when the provider and model are unchanged.
  • Leaving target out keeps today's behaviour: copy from the calling thread on create, keep the stored selection on update.
  • Add providerInstanceId, model and options (and probably the runtime/interaction modes) to OrchestratorMcpScheduledTask so list/schedule/update show them.
  • Optionally, reject unknown input keys on these tools so mistakes surface as errors.
  • Fix the schedule_task description, which says settings "inherit from this thread" without saying it's a one-time copy.

Related: #15821 (follow the thread's model for thread-bound tasks), #16592 (web editor controls).

Note

Grok responding on behalf of Julius.

Triage: confirmed on current main.

Root cause

  • schedule_task always copies the calling thread's selection, or the project default when there is no calling thread: apps/server/src/mcp/OrchestratorMcpService.ts:1528-1529.
  • update_scheduled_task always writes back existing.modelSelection (and the stored runtime/interaction modes): OrchestratorMcpService.ts:1623-1625.
  • Neither OrchestratorMcpScheduleTaskInput (packages/contracts/src/orchestratorMcp.ts:520-542) nor OrchestratorMcpUpdateScheduledTaskInput (:587-594) has a model or target field. They are plain Schema.Structs, so an extra modelSelection key is dropped and the call still succeeds.
  • OrchestratorMcpScheduledTask (:546-564) has no model, options or modes, so neither the result nor list_scheduled_tasks shows what a task will run with.
  • The runner already uses the full stored selection (apps/server/src/scheduledTasks/ScheduledTaskService.ts:802,825). Only the MCP surface is missing it.

Proposed fix

  1. Add an optional target: OrchestratorMcpTarget (orchestratorMcp.ts:100-128) to both inputs. Resolve it with the same resolver the work-starting tools use (OrchestratorMcpService.ts ~1131-1213), which already validates against capabilities and inherits options only when provider and model are unchanged. If target is omitted, keep today's behaviour.
  2. Add providerInstanceId, model, options (and runtimeMode/interactionMode) to OrchestratorMcpScheduledTask.
  3. Optional: reject unknown keys on these inputs, and change the schedule_task description to say the settings are a one-time copy.

Workaround Until this ships, check or change the model and effort for the task from a scheduled-task editor in the app instead of over MCP. Controls for this in the web editor are in #16592, which is still open.

Related: #15821 (open feature request for thread-bound tasks to follow the thread's current model). It overlaps but is a separate request.

Synced from GitHub

I’m interested in this as well. Being able to choose the provider/model and reasoning effort per scheduled task would help me keep routine runs on an appropriately economical configuration, avoid burning through my limited subscription usage, and reduce the risk of unexpectedly high API bills. It would also help to have the saved selection visible in the task list/editor so I can confirm what each recurring task will use. Thanks for investigating this.

Reproduced on current main a50cd989ae with the isolated Linux dev server and real MCP requests. Disabled fixed-time tasks with bindToCurrentThread:false accepted both an extra modelSelection and a target requesting Claude Opus 5.5 with xhigh effort, but stored the project default (Codex gpt-6.1-sol). Both creation responses and list_scheduled_tasks omitted the selection. This reproduction used an external MCP client and a project default; it did not run a scheduled provider turn.