Changelog
User-facing changes to the Clockwork platform API, @clockwork/sdk and @clockwork/mcp. Every entry says where the change stands, because "merged" and "available to you" are not the same thing.
Status of planning v2
As of 2026-10-12. All times UTC. "Merged" means on main; "deployed" means a Vercel production deployment of the platform (platform.clockwork-co.com) reached READY. Merging to main triggers a production deployment automatically.
| Change | Merged | Deployed to production |
|---|---|---|
| Planning v2 core: F1 to F7 and F9 to F11 (batch graphs, requirements, anchors, leveling, max lag, simulation, events, shared state, availability windows, guest tokens) | PR #268, 2026-10-07 01:25 (df6384e). Build fix PR #271, 2026-10-08 16:31 (95c8e75). Docs PR #270, 2026-10-09 17:28 (e14fe9e) | Yes, 2026-10-09. First READY deployment dpl_J6GQT4sQ… (commit 95c8e751), migrations 0072 to 0078 applied; dpl_44ERFeiu… (commit e14fe9e1, the docs PR) followed |
| F12: pool assignment | PR #273, 2026-10-12 01:26 (a6397a2) | Yes, 2026-10-12 (commit a6397a25, READY), migration 0079 applied |
| Security and correctness fixes | PR #274, 2026-10-12 09:46 (a98d121) | Yes, 2026-10-12 (commit a98d1218, READY). Production serves this build |
| F8: template overrides, excludes, role bindings | PR #275, 2026-10-12 13:42 (3329a9e) | Yes, 2026-10-12. The first production deployment (dpl_7VmaPm…) failed with Vercel's git_info_fail (no build log); the retry dpl_5tFFsmnW… reached READY. The F8 fields have not been exercised against production by us |
| Flag | CLOCKWORK_PLANNING_V2=1 is set on the Production and Preview environments of the platform (set 2026-10-08/09) and is therefore on for every organization. In code the default is still off: with it off, each new endpoint answers 404 NOT_FOUND, the new fields are inert, guest tokens do not authenticate and webhooks and the event log behave exactly as before. |
| Access control today | That single global flag. Per-organization gating is planned (an allow-list so the flag can be limited to chosen organizations); it is not built, and nothing on this page describes it as available. |
| What has been checked in production | The served OpenAPI document is version 1.1.0 with 107 paths, and a request with a spoofed x-user-id header answers 401 (both checked 2026-10-12). One authenticated smoke test ran once with a throwaway key (job created, scheduled and cancelled; tasks deleted; resources retired). The features have not otherwise been verified in production; they were verified on a preview deployment and by local tests. |
Package versions did not change for these features (@clockwork/sdk 1.0.0, @clockwork/mcp 0.1.0): identify what you have by the commit SHAs above.
The documentation pages describe the code on main. Their code samples are run against a local platform built from it with the flag on (docs-examples/), not against production.
2026-10-12 — Security and correctness fixes (merged #274, deployed)
Merged 2026-10-12 09:46 UTC, deployed to production the same day (a98d1218). Some of these change behavior for callers that relied on the old, wrong behavior.
- Spoofable identity headers (critical). The platform trusted
x-user-id/x-org-id/x-actor-id/x-actor-role/x-org-slugrequest headers as session context, but nothing in the platform sets them, so any caller who knew a platform-user id could act as that user without credentials. The middleware now drops these headers from every/api/v1/*request. Authenticate with an API key or a Supabase session JWT. POST /tasks/{id}/assign-resourceandPOST /tasks/{id}/completenow apply the same task-visibility rule as delay, update and assign (403for a task you cannot see,404unknown task). Guest tokens stay refused onassign-resource.- Webhook URL validation.
POST /webhooksandPOST /events/subscriptionsreturn400 INVALID_WEBHOOK_URLfor non-http(s)URLs and URLs with embedded credentials, and, on the production platform, forlocalhost,*.localhost,*.local,*.internal, single-label hosts and IP literals in loopback, private, link-local, metadata or reserved ranges. The check also runs at delivery time and deliveries no longer follow redirects. A hostname that resolves to a private address (DNS rebinding) is not covered. GET /conflicts?resolved=false,GET /opportunities?dismissed=falseandGET /workflow-instances?withSummary=falsenow honourfalse/0(they were read astrue). Accepted values:true,false,1,0; anything else is400 VALIDATION_ERROR.@clockwork/sdk:ConflictTypenow includesanchor_infeasibleandmax_lag_exceeded. Code with an exhaustiveswitchover the old union needs the two new cases.- Guest tokens. An open event stream ends within one poll of the token being revoked or expiring; guest event payloads no longer carry the assignee's platform-user id; a guest
delaycannot move a task earlier (422) and truncatesreasonto 500 characters; guest conversation titles are cut to 200; guests are rate limited by an in-process counter when Redis is not configured;lastUsedAtis updated at most once a minute; adelaywith an unrepresentable date is400(was500). A project-bound API key can only mint, list and revoke tokens in its own project, and revoking a token you did not mint needs organizationadmin.
2026-10-12 — Template overrides and scheduling fields on create (F8: merged, NOT deployed)
Merged by PR #275 on 2026-10-12 13:42 UTC. Deployed to production on 2026-10-12 (the first deployment failed with git_info_fail; the retry dpl_5tFFsmnW… reached READY; not exercised against production by us). Additive, needs CLOCKWORK_PLANNING_V2. No migration. With the flag off nothing changes, byte for byte.
Added
- Template instantiation with overrides, excludes and role bindings.
workflowInstances.create({ templateId, ... })takesoverrides(per manifest node key:title/name,description,durationMinutes,bufferAfterMinutes,isFixed,offsetFromAnchorMin; per"from->to":lagMinutes),excludewithexcludeMode: 'bridge' | 'drop'(bridge connects an excluded node's predecessors to its successors with the lags summed; drop removes its dependencies) androleBindings(role slot -> resource id, bound with the existing role machinery). The job is built through the same atomic path ascreateWithGraph(one transaction, one schedule computation) and the response addsappliedandschedule. Unknown keys or slots, excluding every node, and a mixed-type bridge are422s that write nothing. MCP: thecreate_workflow_instancetool takes the same fields. Workflow Instances
Fixed
POST /workflow-instancessilently droppedanchor,schedulingDirectionandresourceLeveling. With the flag on they are now validated (same rules ascreateWithGraph;backwardwithoutanchoris a422 ANCHOR_REQUIRED) and stored. With the flag off they are still dropped without an error, as before. The schema remains non-strict, so other unknown fields are still ignored. The SDK'sCreateWorkflowInstanceInputnow declares the fields.
2026-10-12 — Pool assignment (F12: merged, deployed)
Written 2026-10-10; merged by PR #273 on 2026-10-12 01:26 UTC; deployed to production 2026-10-12 (a6397a25) with migration 0079 (two nullable columns, reversible). Needs CLOCKWORK_PLANNING_V2 and is inert unless you set the new field.
Added
- Automatic assignment from a pool.
instance.assignmentPolicy('balance_load'or'earliest_finish', needsresourceLeveling: 'delay') oncreateWithGraphmakes the planner pick one member of acapability:<id>pool for each pool requirement. The choice is returned inschedule.assignments, stored on the requirement (assignedResourceIdfromtasks.listRequirements) and is sticky: a started or finished task never changes member, an unstarted task keeps its member while it stays in the pool. Deterministic and idempotent. Without the field nothing changes. MCP:assignmentPolicyoncreate_workflow_graph. Resource Requirements
2026-10-07 — Planning v2 (merged 2026-10-07, deployed to production 2026-10-09)
The features below were authored on 2026-10-06 and merged together by PR #268 on 2026-10-07 (F8 and F12 followed, above). They are additive: nothing changes for an existing integration until the flag is on and you use a new field or endpoint. Migrations 0072–0078 shipped with them (all nullable or defaulted columns, each with a reversible down script) and were applied by the production deployment on 2026-10-09. The flag is now on in production, so the endpoints below exist there.
Added
- Atomic batch graph creation (
ca2c08d).POST /workflow-instances/graph(workflowInstances.createWithGraph) creates a job with its resources, tasks and dependencies in one transaction with one schedule computation, and returns the instance, aref -> idmap and the computed schedule. Unknown refs, duplicate refs and dependency cycles are rejected with a422naming the offending refs, and nothing is written. Limits per request: 500 tasks, 2,000 dependencies, 100 resources. AlsoPOST /tasks/batch(tasks.createBatch) andPOST /dependencies/batch(dependencies.createBatch). MCP:create_workflow_graph. Counts as one request toward rate limits. Migration0072(planned start/end and latest start on tasks; required start and makespan on jobs). Batch Graphs - Multi-unit and partial resource requirements (
9321836). A task can claimunitsof a resource or pool with anoccupancyoffull,bookends(first and last minutes only) ornone.GET/PUT /tasks/{id}/requirements(tasks.listRequirements/setRequirements;PUTreplaces the list). Units above capacity are a422 REQUIREMENT_EXCEEDS_CAPACITY; over-allocation is reported as aresource_capacity_breachconflict. MCP:get_task_requirements,set_task_requirements. Migration0073. Resource Requirements - Anchored backward scheduling (
350e7cc). Jobs takeanchor: { type: 'finish', at }andschedulingDirection: 'forward' | 'backward'(default forward). Backward places every unstarted task at its latest start that still meets the anchor. New constraint typesanchor_windowanddeadlinewithrelativeTo, a per-taskanchorWindowshorthand, and ananchor_infeasibleconflict (withshortfallMinutes) when the anchor cannot be met. Tasks gainplannedStart,plannedEnd,latestStart; jobs gainrequiredStartandmakespanMinutes. Migration0074. Anchored Scheduling - Maximum lag on dependencies (
9cef3d2).maxLagMinutes(at leastlagMinutes;nullclears it) on dependency create/update, batch graphs and batch dependencies. Planner-managed jobs keep the gap within the limit; other jobs get amax_lag_exceededconflict. Migration0075. Dependencies - Resource leveling (
4249291).resourceLeveling: 'off' | 'delay'on jobs (defaultoff, which only reports over-allocation).delayresolves it by delaying unstarted tasks, lowest slack first, without moving started or completed tasks. Migration0076. Resource Leveling - Dry-run simulation (
2652544).POST /schedule/simulate(scheduling.simulate; MCPsimulate_schedule): a hypothetical graph, or{ baseInstanceId, mutations }against a live job withdelay,complete,add_resourceandremove_resource. Persists nothing and emits no events. Has its own rate-limit bucket at 5× the key's budget. Schedule Simulation - Schedule-change events and one event vocabulary (
a3d4c70).schedule.changedis emitted once per recompute, listing every task whose planned window moved. Canonical dot-notation event names everywhere, with the original underscore names and the names earlier releases delivered under still accepted. A shared envelope that is byte-identical on webhooks and on the new server routeGET /events/stream(Server-Sent Events: polling-backed, about one second of lag, heartbeat, resume withLast-Event-ID). The SDK'sevents.stream()existed before, but the server route it called did not. Events, Webhooks, Event-Driven Patterns - Shared state and setup time on resources (
47a9db1). Resources declarestateKey,stateToleranceandstateSetupMinutes; requirements take astate. Claims overlap only within the tolerance and a larger change inserts the setup time.422 STATE_NOT_SUPPORTEDfor a state on a pool or on a resource that declares none. Migration0077. Resources - Resource availability windows (
4c4919e).resources.availabilityentries shaped{ from, to }or{ start, end }(ISO 8601) are absolute windows the planner keeps occupied time inside. No migration. With the flag on, unusable window entries are rejected with400. Resources - Scoped guest tokens and filtered streams (
01b6fa8).POST /tokens,GET /tokens,DELETE /tokens/{id}(tokens.create/list/revoke; MCPcreate_guest_token,list_guest_tokens,revoke_guest_token) mint short-lived, revocablecg_live_…tokens for a person with no account, bound to one job and to either one resource's tasks or a task list, with a fixed action list, a per-token rate limit and a lifetime of at most 30 days. Webhook subscriptions takeworkflowInstanceIdandresourceIddelivery filters. New management scopestokens:readandtokens:write. Migration0078. A security review of this feature is recommended before enabling it in production. Guest Access
Changed
- With the flag on, the webhook body is the shared event envelope.
eventcarries the canonical name (task.delayed, nottask.updated;conflict.detected, notconstraint.violated;task.ready, nottask.created) andlegacy_eventkeeps the earlier name. A handler that switched on the earlier name should switch ontype.X-Clockwork-Eventcarries the canonical name. A subscription registered under an earlier name keeps receiving the event. Webhooks criticalPathin plan output is now a single driving chain through tight dependencies, not every zero-slack task.- Ids generated for a batch request are handed out in
reforder, so the same request body produces the same schedule. ClockworkError.detailsin the SDK now carries structured error fields such asrefson a422.
Documentation
- Rate limits are documented: 1,000 requests per 60-second window per API key by default, 5× for simulation, 120 per guest token by default;
RateLimit-Resetis the seconds until the window ends, not a Unix timestamp as the page previously said. Authentication - The Webhooks guide and the Events page now use one set of event names (the guide used to subscribe to
task_delayedbut switch ontask.updated), with a table of how each event appears on SSE and on webhooks, a handler that works with the payload shape from before and after the flag is on, and an account of what delivery guarantees exist and do not exist (see Webhooks). - The OpenAPI document (
/api/v1/openapi.json) is now version1.2.0(1.1.0 added the planning-v2 surface; 1.2.0 corrects thePOST /dependencies/batchresponse shape and the task/job response unions): it documents the paths the SDK calls (/api/v1/<resource>, with the older/runtime/...forms noted as equivalent), has request and response schemas for each operation, the error envelope, rate-limit headers, and the scope each operation requires. Removed the/templatespath, which does not exist.
2026-10-07 — Scheduled jobs in the web app (merged)
- Vercel cron schedules in
apps/webare daily (b116328, PR #269 merged 2026-10-07 03:36 UTC, merge2275046; the web app's deployment is not tracked on this page)./api/cron/auto-triage-sweepruns at 06:00 UTC and/api/cron/email-scan-sweepat 07:00 UTC (previously every 30 and 15 minutes) so the project deploys on Vercel's Hobby plan. This affects the Clockwork web app only, not the platform API.
Known issues
Found while checking this documentation against the code; each was reproduced on a local platform built from main with a fresh database, not on production. They are listed so that you do not meet them by surprise; none is fixed by the documentation change.
- Attaching a constraint to a job fails.
constraints.attachwithtargetType: 'instance'is accepted by the API and SDK but answers500 INTERNAL_ERROR: the table has a check allowing onlyexecution,taskandworkflow_definition(migration0042). Attach to the job's tasks. Constraints - On forward jobs with leveling off,
plannedStart,plannedEnd,latestStart,requiredStartandmakespanMinuteskeep their creation values after a delay;earliestStartis the live start there. Tasks conflicts.snoozerecordssnoozedUntiland does nothing else: snoozed conflicts still appear inlist(). Conflicts- Webhooks are one attempt with no retries and no ordering guarantee, and whether a delivery always completes after the request that caused it has answered is not verified on the hosted runtime. Webhooks
- Editing a resource or a capability pool's membership does not re-plan jobs; the next task change in the job does. Resources, Capability Pools
Earlier
Changes before 2026-10-07 are not itemised here. The last production build of the platform before planning v2 was 117b998 (2026-08-02).
Related
- Authentication — keys, scopes, rate limits
- Batch Graphs — the first planning v2 feature
- Capability Pools — group interchangeable resources and let the planner pick
- Webhooks and Events — the event vocabulary
- OpenAPI spec — version 1.1.0 on production (checked 2026-10-12)