Agent Schedules
A schedule runs an agent with an instruction at a set time, with nobody in the chat. There are two kinds:
- Recurring: runs on a cron expression in a timezone, for example every weekday at 09:00 in
Europe/Warsaw. - One-time: runs once at a date and time. You create these in the Schedules tab, or the model creates them from a chat with the Scheduling tool.
Every run is recorded in the schedule’s run log with its status, output, tokens and any error.
Nothing fires unless a Celery beat scheduler is running. The Docker Compose files and docsgpt worker embed it (-B), and Kubernetes runs it in the worker. If you start workers with --no-beat, or on Windows, run docsgpt beat as well. See Background jobs and the worker step in the development environment.
Create a schedule in the web app
- Open the agent and select the Schedules tab. The tab appears once the agent is saved, and only for its owner and team editors.
- Select New schedule.
- Give it a name (optional) and pick a Frequency: Once, Daily, Weekly, Monthly or Yearly. Set the day or date and the time (At), and pick a Timezone.
- In Instructions, write what the agent should do on each run, as you would type it in a chat. Include any delivery step, such as “post the summary to Slack”.
- If the agent has tools with actions that need approval, they are listed under Tools that need approval, all unticked. Tick a tool only if the schedule should use its approval-gated actions without asking; see Tools in a scheduled run.
- Select Create task.
The tab lists Recurring schedules and One-time tasks separately, with each schedule’s next run, last run and status. What you can do depends on the schedule:
- An active recurring schedule has a Run now button and a menu with Edit, Pause and Delete.
- A paused recurring schedule has a Resume button and a menu with Edit, Run now and Delete.
- A pending one-time task has a menu with Edit and Cancel task.
Edit changes the instructions, time, timezone and tool approvals. Editing a one-time task’s date or time moves it to the new time, which must be in the future. A schedule can’t switch between one-time and recurring: the other kind’s frequencies are disabled while you edit, so create a new schedule instead. If the change is refused, the dialog stays open and says why.
Deleting a schedule also deletes its run history, and deleting the agent deletes all its schedules.
The builder covers daily, weekly, monthly and yearly times. For another cadence, such as every hour, set a custom cron expression through the API. The tab shows it as Custom: <expression>.
Tools in a scheduled run
Nobody is present to approve a tool call during a scheduled run, so:
- Actions that don’t need approval run as they would in a chat.
- An action that needs approval runs only if its tool is ticked under Tools that need approval in the schedule’s form. Ticking a tool pre-approves all of its approval-gated actions for every run of that schedule, so they run without asking. Nothing is ticked by default.
- The form lists a tool when any of its active actions is set to need approval, when it is a remote device (a device decides per command, from its approval mode), when it is a code executor set to require approval, and when it is a tool you can’t inspect, such as one the agent’s owner didn’t share with you.
- Commands that a remote device’s denylist forces to a prompt are refused even when the device is ticked.
- Tools that run in the browser, and connected tools whose account needs signing in, are refused.
- The Scheduling tool is never available in a scheduled run, so a run can’t create further schedules.
- A refused tool call is reported back to the model, which can still answer. The run fails with the
tool_not_allowederror type only when it ends without an answer.
If you later mark one of a tool’s actions as needing approval, schedules that don’t have that tool ticked refuse the action. Edit the schedule and tick the tool if it should run unattended.
Run now and the run log
Run now starts a run immediately. It is recorded with the trigger Manual; timed runs show Scheduled. Run now is refused while another run of the same schedule is still in progress.
For a recurring schedule, select Show runs to open the log, and select a run to see its details: status, scheduled, start and finish times, prompt and generated tokens, output and error. The output is capped at 24,000 characters and marked (truncated) beyond that.
A run ends in one of these statuses:
| Status | Meaning |
|---|---|
| Success | The run finished and produced an answer, tool calls or workflow steps, even if a tool call was refused along the way. |
| Failed | The run raised an error, was refused a tool and ended without an answer (tool_not_allowed), went over the owner’s usage quota or the schedule’s token budget (budget_exceeded), or produced nothing at all (empty_output). |
| Timeout | The run went past SCHEDULE_RUN_TIMEOUT. |
| Skipped | The run didn’t start: the previous run was still in progress (overlap), or the scheduler was down past the due time plus SCHEDULE_MISFIRE_GRACE (missed). |
The Schedules tab has no run log for one-time tasks. Their runs, like every scheduled run, appear in Settings → Logs with the type Scheduled, with their execution trace, and in the agent’s Logs tab; over the API, use GET /api/schedules/<id>/runs.
Where the output goes
- The output of a recurring schedule, or of a one-time task created in the Schedules tab, stays in the run log. It isn’t added to a conversation.
- A one-time task created from a chat adds its answer to that conversation as a new turn once it succeeds. The run sees the conversation’s earlier messages.
Auto-pause
After SCHEDULE_AUTOPAUSE_FAILURES (default 3) failed or timed-out runs in a row, a recurring schedule pauses itself. The schedule shows Paused and how many runs failed in a row. Fix the cause, then select Resume. Resuming resets the failure count and computes the next run from now. One-time tasks are never auto-paused.
Schedule from a chat
The Scheduling tool lets the model set a one-time task while you chat: “remind me tomorrow at 8 to check the deploy” or “in 2 hours, summarise the new tickets”. It can also list and cancel the pending tasks it set.
- In a regular chat without an agent, it is one of the default chat tools (
DEFAULT_CHAT_TOOLS). - In an agent’s chat, enable Scheduling in the agent’s tool picker.
The chat shows a card for each task with a Cancel task button. Tasks set in an agent’s chat also appear under One-time tasks in the agent’s Schedules tab. The tool sets one-time tasks only; for a recurring schedule, use the Schedules tab.
A task set from chat pre-approves only the tools whose actions never need approval. Tool calls that need approval are refused when it runs.
Who owns a schedule and whose quota it uses
- A run always executes as the agent’s owner, with the owner’s sources, tools and model, and is checked against the owner’s usage quota.
- Its tokens and trace are recorded under the schedule’s user: the agent’s owner for a schedule from the Schedules tab, and the person who set it for a task set from chat. So a teammate’s chat task on your agent is checked against your quota but shows up in their Analytics and Logs.
- A schedule created in the Schedules tab belongs to the agent’s owner, whoever creates it. Owners and team editors of the agent can manage it.
- A task someone sets from chat on a shared agent stays theirs. It stops running when they lose access to the agent.
- A task set through the agent’s API key, or by someone who reaches the agent only through its public link, keeps that caller’s limits: it writes to the owner’s connected accounts and saved credentials only for actions allowed under Letting API callers make changes.
REST API
Schedules have their own endpoints. Call them with a session token or a personal access token with the schedules:read or schedules:write scope. The REST API reference lists them all.
| Method and path | Purpose |
|---|---|
GET /api/agents/<agent_id>/schedules | List an agent’s schedules |
POST /api/agents/<agent_id>/schedules | Create a schedule |
GET /api/agents/<agent_id>/schedules/stats?days=30 | Runs, failures and tokens over a window |
GET, PUT, DELETE /api/schedules/<id> | Read, edit or delete a schedule |
PATCH /api/schedules/<id> | {"action": "pause"} or {"action": "resume"} |
POST /api/schedules/<id>/run | Run now |
GET /api/schedules/<id>/runs?limit=50&offset=0 | The run log |
GET /api/schedules/<id>/runs/<run_id> | One run’s output and error |
Fields for POST. PUT takes the same fields except trigger_type, which can’t change; send only the fields to change.
| Field | Description |
|---|---|
instruction | Required. What the agent does on each run. |
trigger_type | recurring (default) or once. |
cron | Five-field cron expression. Required for recurring. |
run_at | ISO 8601 time. Required for once. A time without an offset is read in timezone. On PUT it moves a pending or paused one-time task, with the same checks as a create; a recurring schedule answers 400, and a finished or already started task 409. |
timezone | IANA name such as America/New_York. Default UTC. |
name | Display name. |
end_at | ISO 8601 time after which a recurring schedule stops and shows Completed. |
tool_allowlist | Tool ids whose approval-gated actions may run without approval. Actions that don’t need approval run whether or not their tool is listed. The web app sends the tools ticked under Tools that need approval. Default: none. On PUT, leaving it out keeps the saved list. |
model_id | Model to run with instead of the agent’s default. |
token_budget | Tokens one run may use. A run that goes over is recorded as failed with budget_exceeded. |
curl -X POST "$API/api/agents/$AGENT_ID/schedules" \
-H "Authorization: Bearer $DOCSGPT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Hourly ticket triage",
"instruction": "Summarise the new support tickets and flag anything urgent.",
"cron": "0 * * * *",
"timezone": "Europe/Berlin",
"token_budget": 20000
}'To resume a one-time task whose time has passed, send a new future run_at with the resume action.
Schedule changes are also published on the realtime events stream: schedule.run.completed, schedule.run.failed, schedule.autopaused, schedule.completed (a one-time task closed after its stuck run was marked failed), schedule.resumed, schedule.cancelled, and schedule.message.appended when a one-time task adds its answer to a conversation.
Limits
Operators set these in .env. See the settings reference for the full list.
| Setting | Default | Effect |
|---|---|---|
SCHEDULE_MIN_INTERVAL | 900 | Shortest gap between recurring runs, in seconds. A cron expression that fires more often is rejected. 0 removes the limit. |
SCHEDULE_MAX_PER_USER | 50 | Active and paused schedules one user can have. 0 removes the limit. |
SCHEDULE_RUN_TIMEOUT | 600 | Seconds one run may take before it stops with Timeout. |
SCHEDULE_MISFIRE_GRACE | 60 | Seconds past its due time that a recurring run may still start, for example after the scheduler was down. Later ones are skipped as missed. |
SCHEDULE_AUTOPAUSE_FAILURES | 3 | Failures in a row that pause a recurring schedule. 0 turns auto-pause off. |
SCHEDULE_ONCE_MAX_HORIZON | 31536000 | How far ahead a one-time task can be set, in seconds (one year). |
SCHEDULE_DISPATCHER_INTERVAL | 30 | Seconds between checks for due schedules (at least 15). |
SCHEDULE_RUN_OUTPUT_RETENTION_DAYS | 90 | Run log entries older than this are deleted, except the latest 50 of each schedule. |