# Schedules without a cron run only when you trigger them

> Agno AgentOS schedules can leave cron_expr empty and wait for POST /schedules/{schedule_id}/trigger, with ScheduleResponse reporting the cron as null. Changing a schedule's endpoint over PATCH or ScheduleManager now also updates the agent, team or workflow it records as its target.

- Published: 2026-10-19
- Author: Ashpreet Bedi
- Categories: Changelog
- Canonical: https://www.agno.com/blog/schedules-without-a-cron-run-only-when-you-trigger-them
- Markdown: https://www.agno.com/blog/schedules-without-a-cron-run-only-when-you-trigger-them.md

Agno's `POST /schedules` now accepts a body with no `cron_expr`, and `ScheduleManager.create()` accepts `cron=""`. Either way the schedule is stored with `next_run_at` set to `null`, so the poller never claims it, and `POST /schedules/{schedule_id}/trigger` runs it and records the run in its history.

Think of a report someone asks for on request, or a job a button in your app should start. Earlier releases required a valid cron on every schedule.

```python
from agno.scheduler import ScheduleManager

manager = ScheduleManager(db)
report = manager.create(name="adhoc-report", cron="", endpoint="/agents/reporter/runs")
```

`ScheduleResponse.cron_expr` is now optional. To make an existing schedule on demand, send `"cron_expr": ""` in a `PATCH`; leaving the field out of a `PATCH` keeps the current cron.

This release also fixes endpoint edits. A schedule can record the component it runs in `target_type` and `target_id`, and archiving that component disables every schedule whose target or endpoint matches it. When you repointed a schedule over `PATCH /schedules/{schedule_id}` or `ScheduleManager.update()`, earlier releases kept the old target, so archiving the agent you had moved away from would still switch the schedule off. Both paths now rewrite the target from the new endpoint.

We ran both on AgentOS with SQLite and FastAPI's `TestClient`, a stub model standing in for the agent's real one:

```text
# earlier releases
POST /schedules (no cron_expr) -> 422 "cron_expr": Field required
ScheduleManager.create(cron='') -> ValueError Invalid cron expression:
PATCH /schedules/{id} -> 200: {"endpoint": "/agents/new-agent/runs", "target_type": "agent", "target_id": "old-agent"}
disable_schedules_for_target('agent', 'old-agent') -> 1 disabled
ScheduleManager.update(endpoint=...) -> endpoint=/agents/new-agent/runs target_id=old-agent

# this release
POST /schedules (no cron_expr) -> 201 {"cron_expr": null, "next_run_at": null}
POST /schedules/{id}/trigger -> 200 status=success
ScheduleManager.create(cron='') -> next_run_at=None
PATCH /schedules/{id} -> 200: {"endpoint": "/agents/new-agent/runs", "target_type": "agent", "target_id": "new-agent"}
disable_schedules_for_target('agent', 'old-agent') -> 0 disabled
ScheduleManager.update(endpoint=...) -> endpoint=/agents/new-agent/runs target_id=new-agent
```

Schedules that Studio or another control plane manages keep their targets fixed, so repoint those by replacing the schedule.

See the [cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/05_agent_os/12_scheduler/03_manage_with_python.py), and learn more about the [AgentOS scheduler](https://docs.agno.com/agent-os/scheduler/overview) in the documentation.
