# Schedule agent runs > Publish exact run configuration and review schedule activation separately. Section: Synapse and Locus. Web page: https://docs.katara.com/products/schedules/ A schedule version binds a name, calendar, overlap policy and the exact request used to admit an agent run. Publication creates an immutable version. It does not enable execution. Schedule reads report `execution_ready`; enabling is refused while the execution service is unavailable. Availability does not establish that an installed worker has completed a scheduled run. ## Publish the reviewed configuration Prepare a [run request](https://docs.katara.com/products/runs.txt) with its exact agent version, input reference, output target, workload grants, budget and usage class. Test simulation, paid Test Compute and Live retain their normal authority and funding requirements. A calendar does not extend a grant, consent or content lifetime. A scheduled run pays the way its budget pays: credits, or the wallet a budget is [paid from](https://docs.katara.com/products/wallet-budgets.txt). Each occurrence is admitted against the wallet like a run started by hand, so an occurrence is refused while the wallet owes its unpaid limit or has a failed collection. A schedule cannot pay its runs with x402, and cannot use a budget [paid per run](https://docs.katara.com/developers/x402.txt#pay-for-an-agent-run). Each scheduled run reads the input as the person who enabled the schedule, so the agent needs no share or grant for it. Enabling checks that the person can read the input, and every occurrence checks it again. If they lose access to the input or leave the organization, a run already started stops reading it and later occurrences are refused. Read the current environment before publication and include its `expected_environment_epoch` and `expected_reset_generation`. Choose a schedule UUID. Use `expected_revision: 0` for its first version, or the current head revision when publishing a replacement. A replacement does not silently replace an enabled version. The calendar requires both `calendars` and `intervals` arrays. Use `[]` for an unused family; `null` is invalid. Supply an exact IANA timezone name and canonical UTC `start_at` and `end_at` timestamps ending in `Z`. The bounds are inclusive. Local times are evaluated in the named timezone, including its daylight-saving transitions; your computer's timezone does not determine occurrences. Each calendar rule requires `second`, `minute`, `hour`, `day_of_month`, `month` and `day_of_week` ranges. `year` is optional and otherwise permits every year. A range has explicit integer `start`, `end` and `step`. Bounds are inclusive: seconds `0..59` with step `15` select 0, 15, 30 and 45. Weekdays use Sunday 0 through Saturday 6. Fields within a rule must all match; matching any rule selects an occurrence. Ranges must be ordered, disjoint and within their field bounds. Each field allows at most 64 ranges. Calendar and interval rules together allow 1–32 entries. Interval rules specify `every_seconds` from 1 through 316,224,000 and `offset_seconds` from zero to less than the interval. They select UTC instants at epoch plus offset plus whole intervals, within the explicit time bounds. Duplicate rules are refused. The policy selects `skip`, `buffer_one`, `buffer_all` or `allow` for overlapping occurrences. `catchup_window_seconds` must be 10–86,400; older missed occurrences are outside that window. Set `pause_on_failure` explicitly. Buffered work still needs valid authority when execution is attempted. ```typescript const scope = { org_id, environment_id }; const published = await client.schedules.publish(scope, { schedule_id, expected_revision: 0, expected_environment_epoch: environment.authority_epoch, expected_reset_generation: environment.reset_generation, configuration: { name: "Daily review", calendar, policy, run }, }, publicationKey); const record = await client.schedules.getVersion(scope, published.resource_id); ``` Python provides `client.schedules.publish`, `get_version`, `get`, `list`, `set_enabled` and `retire`. TypeScript uses `getVersion` and `setEnabled` for the corresponding operations. SDKs snapshot requests before asynchronous authentication and never retry these mutations automatically. ## Enable, pause or retire Schedule operations require `synapse:schedules:write`. Publication and reads accept an appropriately scoped key or human session. Enable, pause and retire require a human session. Enabling also requires `execution_ready: true`. Review the exact version reference and activation generation before changing activation. Submit `version`, `expected_generation`, both environment preconditions and the explicit `enabled` boolean. Use generation zero when no activation exists. An enabled version can differ from the publication head: inspect `activation.version` before pausing it. Retirement submits the same exact reference and generation preconditions without `enabled`. It permanently retires that schedule identity; it does not erase historical versions or receipts. Publishing another version cannot revive a retired schedule. ```typescript await client.schedules.setEnabled(scope, { version: record.reference, expected_generation: record.activation?.generation ?? 0, expected_environment_epoch: environment.authority_epoch, expected_reset_generation: environment.reset_generation, enabled: true, }, activationKey); ``` ## Inspect and recover an uncertain request `list` accepts `limit` from 1–50, an optional `after` schedule UUID and `include_retired`. The default limit is 25. Continue with the returned `next_cursor`. `get` reads the current publication head; `getVersion` reads an exact immutable version. Keep the reviewed request, selected account and environment, and caller-generated idempotency key until the outcome is known. If a response is lost, inspect current state and explicitly retry the same body and key only after confirming the same account and scope. Do not replace the key, rebuild the request from a newer head, or automatically enable after a recovered publication. A reset or revoked authority can refuse recovery; retain the uncertain request for investigation. A completed receipt confirms that operation, while current activation may have changed afterward. ## Read runtime observations Every record and directory entry includes `runtime.state`, `runtime.generation`, and an optional `runtime.observed_at`. The generation is the canonical activation generation, or zero without an activation. It can refer to an older version than the publication head. `execution_ready` reports whether both runtime workers started; it does not establish that this schedule is active. | Runtime state | Meaning | | --- | --- | | `unconfigured` | No runtime profile is enrolled for the environment mode, even if activation metadata exists. | | `pending` | The controller has not established active execution for the requested generation. | | `active` | The controller reports the generation active; each occurrence still needs current admission authority. | | `paused` | The runtime is stopped, including a never-activated schedule at generation zero. | | `review` | An enabled native schedule stopped or needs review. A new explicit activation generation is required; it does not resume automatically. | | `stopping` | Pause or retirement is recorded, but native cleanup remains pending. | | `error` | The controller could not establish the requested runtime state. | The optional observation time is the last controller check, including a failed attempt. It is not proof of successful execution. Inspect fresh metadata before a new explicit activation review. No occurrence preview is implied by these fields.