[FEATURE] Programmatic workflow start for SDK hosts — Workflow can be observed and stopped, but only a model can start it
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
There is no way for an SDK host to _start_ a workflow. The Workflow tool is the only entry point, and tools are invoked by the model — so every workflow run costs a full agent turn, even when the workflow to run and its args are already known.
Dynamic workflows are pitched for unattended work — the harness blog post pairs them with /loop and /goal for "continuous triage" and scheduled research. But an SDK host that wants to run a saved workflow on a cron has no way to dispatch it directly. It has to ask a model to press the button.
We run a scheduler on top of @anthropic-ai/claude-agent-sdk (0.3.220 / Claude Code 2.1.220, Bedrock). To fire a saved workflow nightly, the only available mechanism is to submit a prompt and hope the model calls the tool. Even in the most degenerate case — a scheduled job whose entire prompt is the bare slash command /context-probe — a full agent turn runs:
| | |
|---|---|
| prompt | /context-probe (nothing else) |
| non-cached input tokens | 24 |
| cache read | 832,902 |
| cache write | 167,611 |
| output tokens | 1,400 |
| cost | $0.90 |
| tools called | PostMessage (12:27:09) → Workflow (12:27:11) → Bash |
Note the ordering: the model emitted a conversational message before calling Workflow. The workflow itself was trivial (2 agents, one echo each). Essentially the entire cost is the dispatcher turn — mounting the tool/MCP surface and running a model turn purely to translate /context-probe into Workflow({name: "context-probe"}).
At nightly cadence that is ~$27/month per scheduled workflow of pure dispatch overhead, plus latency, plus non-determinism: the model may add commentary, may pass args wrong, or may decline to call the tool at all.
What I verified is missing (SDK 0.3.220)
Checked the entire client-accessible surface:
- Exported functions (
sdk.d.ts):query,startup,tool,createSdkMcpServer, session management (listSessions,forkSession,getSubagentMessages, …). Nothing starts a workflow. - Control-request subtypes: the task lifecycle is well covered inbound —
task_started,task_progress,task_updated,task_notification— andstop_taskexists. There is nostart_task/run_workflowcounterpart. A host can observe and terminate a workflow it cannot start. - Options / Settings:
disableWorkflows,enableWorkflows,workflowSizeGuideline,workflowKeywordTriggerEnabled,ultracode. All of these gate whether and how the model may reach for the tool; none invoke it. - No forced tool use: no
tool_choice, noforcedTool, no assistant-message seeding.canUseTool/permissionModegate approval of a call, never its initiation. - Docs: the Agent SDK TypeScript reference has no
Workflowentry at all, despite the workflows page pointing readers to it ("see the Workflow tool entry in the Agent SDK reference for the full set of options").
Proposed Solution
A programmatic start, mirroring the stop_task control request that already exists. Either shape works:
A. Control request
// symmetric with the existing stop_task
{ subtype: "start_workflow",
name?: string, // saved workflow (same resolution as Workflow({name}))
scriptPath?: string,
args?: unknown,
resumeFromRunId?: string }
// → { runId, taskId }, then the normal task_started / task_notification stream
B. Query method
const run = await q.startWorkflow({ name: "nightly-triage", args: { since: "2026-08-06" } });
// run.runId; results arrive on the existing task_* events
Either way the run should emit the same task_* lifecycle events as a model-initiated one, so existing observability keeps working unchanged.
A CLI equivalent (claude workflow run <name> --args '{...}', non-interactive, no agent turn) would serve the same need for cron-style users who aren't embedding the SDK.
Alternative Solutions
Things I tried or considered, and why they don't close the gap:
- Bare slash-command prompt (
/context-probe) — measured above. Still a full agent turn; the model can still editorialise or deviate. This is the current best workaround and it is the thing being priced at $0.90/run. - Prompt engineering to suppress the preamble ("call the workflow and say nothing") — reduces chatter, not cost. The spend is context boot, not output.
- Trimming the mounted tool surface for dispatch sessions — genuinely helps the cache-read figure, but it's a workaround for having to boot a model turn at all, and it degrades the session for anything else.
ultracode: true— makes the model more willing to orchestrate, but it is still the model deciding, and it forcesxhigheffort on every request.- Reusing the workflow runtime out-of-process — not exposed; the runtime is reachable only through the tool.
Priority
Medium - Would be very helpful
Feature Category
Developer tools/SDK
Use Case Example
A nightly scheduled sweep in an SDK-hosted agent platform:
- A saved workflow
nightly-triagelives inCLAUDE_CONFIG_DIR/workflows/— reviewed, versioned, deterministic. - At 02:00 the scheduler wants to run exactly that script with
args: { since: <yesterday> }. - Today: it submits a prompt, a model turn boots (~830K cached tokens, ~$0.90), the model usually calls
Workflow({name}), and the run starts. The orchestration is deterministic but the dispatch is not — and it is billed like a conversation. - With this feature: the scheduler calls
startWorkflow({ name: "nightly-triage", args }), gets arunId, and consumes the sametask_*events it already handles. Zero dispatcher tokens, no model discretion, and the cost of the run is exactly the agents that do the work.
This also makes workflows composable with existing job infrastructure (retries, alerting, cost attribution) in a way that "submit a prompt and hope" cannot.