| name | scheduled-tasks |
| description | Use when creating, inspecting, validating, running, or troubleshooting daemon-backed scheduled automations and conversation callbacks. |
| metadata | {"id":"scheduled-tasks","title":"Scheduled Tasks","summary":"Built-in guidance for daemon-backed scheduled automations and conversation callbacks.","status":"active"} |
| tools | ["scheduled_task"] |
Scheduled Tasks
Scheduled tasks are the durable automation system behind saved scheduled prompts.
Use them when something should happen:
- later
- on a recurring schedule
- as either a background job or a conversation-thread wakeup
- without an active conversation open
CLI
For Neon Pilot administration from shell, prefer the CLI:
neon-pilot tasks list --json
neon-pilot tasks get <task-id> --json
neon-pilot tasks save --title "Daily check" --cron "0 9 * * *" --prompt "Summarize status" --json
neon-pilot tasks validate --title "One shot" --at "2026-06-10T09:00:00Z" --prompt "Follow up" --json
neon-pilot tasks run <task-id> --json
neon-pilot tasks delete <task-id> --json
neon-pilot heartbeats start <heartbeat-id> --interval-minutes 5 --conversation-id <conversation-id> --prompt "Wake up, check whether work remains, and stop this heartbeat when done." --json
neon-pilot heartbeats list --json
neon-pilot heartbeats stop <heartbeat-id> --json
Use the unified neon_pilot internal tool from inside a model turn when direct tool execution is more appropriate than shell administration. scheduled_task remains available for low-level scheduled task management, but recurring self-admin heartbeats should go through the Neon Pilot admin surface.
When to use scheduled tasks
Good fits:
- morning reports
- recurring reviews
- unattended background prompts
- durable conversation jobs that should resume a thread later
- automation that should surface attention on its owning thread
- task-style work that may optionally callback into a conversation later
Do not confuse scheduled tasks with:
- project tasks in
state.yaml — those are planning/checklist items
- follow-up queue entries — those are conversation-bound wakeups
- durable background runs — those are detached jobs launched on demand with
background_bash or subagent
Where automations live
Canonical storage:
~/.local/state/neon-pilot/daemon/runtime.db
Automation definitions and scheduler runtime state now live in the daemon SQLite database.
For the current automation UI and storage model, see the Automations extension README.
Required schedule fields
A task must define exactly one of:
cron — recurring schedule
at — one-time timestamp
Web UI automation fields
The Automations page exposes the same core fields as Codex-style scheduled prompts:
- title
- prompt
- target (
background-agent or conversation)
- working directory (
cwd)
- schedule (
cron or one-time at)
Model and timeout still exist internally for background-agent targets, but the default UI flow is intentionally narrow.
Frontmatter reference
| Key | Required | Notes |
|---|
id | no | defaults from filename |
enabled | no | defaults to true |
cron | yes* | recurring 5-field cron |
at | yes* | one-time timestamp parseable by Date.parse |
provider | no | optional if paired with model |
model | no | full model ref, or combined with provider |
cwd | no | working directory for the run |
timeoutSeconds | no | per-run timeout |
* Exactly one of cron or at is required.
Cron vs one-time tasks
Cron
Use cron when the task should run repeatedly.
Examples:
- every weekday morning
- every hour
- every Sunday evening
at
Use at when the task should run once.
If the daemon is offline when the scheduled time passes, the run is marked skipped.
Runtime behavior
Important behavior to understand:
- tasks are daemon-managed
- cron tasks run at most once per matching minute
- overlap is prevented; if one run is still active, the next due run is skipped/coalesced
- retries happen up to the configured retry limit
- each run writes a log
- every automation defaults to a dedicated thread unless you explicitly bind it to an existing thread or disable thread ownership
- successful and failed runs stay on the automation and its owning thread by default
- background-agent tasks are passive by default; conversation-target tasks write directly into their bound thread when due
One-time tasks resolve once and do not run again.
Run model
Background-agent automations run as direct daemon-managed subprocesses.
Conversation-target automations create a durable automation execution record and run Pi directly against the bound thread session, so they continue even when that thread is archived or not open in the UI.
Each execution still writes a durable run record under the daemon state root.
Conversation callbacks
A scheduled task can optionally callback into the conversation that created it.
That callback path is intentionally separate from the automation definition because conversation ids and session files are local runtime state.
When enabled, a task completion or failure can create:
- a conversation wakeup
- an alert
- the usual run/log trail on the owning thread
This is the right fit for:
- "run this later and tell me what happened"
- "watch for deployment gates and bring this thread back when it matters"
It is not the same as a same-thread follow-up. For direct human tell-me-later requests, prefer the unified conversation deferred-resume admin command.
Managing tasks from the web UI
The Automations page lets you:
- inspect discovered automations
- create a new automation from a centered modal launched from the page toolbar
- choose a dedicated thread, an existing thread, or no thread for each automation
- enable or disable an automation
- edit an automation from the detail view with a focused form
- delete an automation from the detail view with confirmation
- adjust common recurring schedules with an interactive schedule builder or fall back to raw cron
- run an automation immediately
- open the automation-owned thread directly from the detail view
- inspect automation status visually
See Neon Pilot Taste for UI control and layout guidance.
Managing tasks with tools
Use the scheduled_task tool for create/update/get/validate/run flows.
Common actions:
save — create or update a task definition
get — inspect one task
validate — validate stored task definitions or a proposed payload
run — trigger a task immediately
Useful save fields beyond the schedule itself:
targetType: "background-agent" | "conversation"
threadMode: "dedicated" | "existing" | "none"
threadConversationId when you want threadMode: "existing"
deliverAs: "steer" | "followUp" for conversation-target automations
deliverResultToConversation only for background-agent automations that should callback later
Use the web UI when you want to inspect automation detail, status, and owned run history visually.
Scheduled heartbeats
A scheduled heartbeat is a Neon Pilot admin primitive backed by scheduled conversation automations. It is managed through the unified admin surface, not as a separate model tool:
neon-pilot heartbeats start <heartbeat-id> --interval-minutes 5 --conversation-id <conversation-id> --prompt "Wake up, check whether work remains, and stop this heartbeat when done." --json
neon-pilot heartbeats list --json
neon-pilot heartbeats stop <heartbeat-id> --json
Internal agents use neon_pilot with action: "heartbeat_start" | "heartbeat_list" | "heartbeat_stop". intervalMinutes is stored as the cron wrapper */N * * * *; use normal scheduled task cron automation for other cadences. Heartbeats target a conversation and set skip/coalesce behavior so a due tick is skipped when the previous callback is still running.
Logs and runtime state
Default daemon state root:
~/.local/state/neon-pilot/daemon
Useful storage:
- automation definitions + scheduler state:
runtime.db
- durable run logs/results:
runs/<run-id>/{output.log,result.json}
Useful status command:
pa daemon status
Common validation failures
Typical problems:
- both
cron and at set
- neither
cron nor at set
- empty prompt
Quick check:
Use the scheduled_task tool with action: "validate".
Recommended workflow
- create or edit automations in the web UI when possible
- use the
scheduled_task tool to inspect, validate, or trigger automations programmatically
- check daemon status with
pa daemon status
- look for the resulting run/status on the automation and its owning thread if the automation is meant to surface attention
Related docs