The scheduler is vendored from
@amaster.ai/pi-task-scheduler (Apache-2.0). A few
things were changed locally, one of which affects behaviour: the scheduler lifecycle
is owned by the sidecar itself, and the scheduler tools’ scope was widened from
“the current session” to app level — automations are an app-level asset, visible
across sessions.Execution shape
A few deliberate decisions, all serving “do not interrupt what I am doing”:Each trigger gets its own session
Results stay in that session, reviewable later, never disturbing the conversation you
are in. Materialised sessions appear in the sidebar automatically with a ⚡ badge.
Missed triggers catch up merged
When the app reopens, missed triggers run once, merged — not once per miss. A
daily report skipped for three days does not run three times.
Notifications land in the session
Clicking a completion notification drops you directly into that run’s session, with an
automatic fallback to the JS plugin path if the native call fails.
Guardrails
At most 2 concurrent runs and 30 tasks; queued triggers show up in the run history.
What “its own session” means concretely
Each run is a brand-new session identified asautomation:<taskId>:<historyEntryId>. Consequently:
- It takes the create-session branch rather than the resume branch (an explicit id would be validated as an existing stream session and fail with “session not found”)
- The session is persisted with its transcript JSONL, so it is fully reviewable later
- The real session id is recorded on the task’s history entry, used for notification deep links
The prompt delivered is exactly the text you wrote — no prefix, no suffix.
Unattended constraints are enforced by the permission tier, not by wrapping the prompt.
Wrapping would instead make the model work inside a frame it should not have to care
about.
Three ways to create one
- The form — sidebar “Automations” → a full management view: task cards, a creation dialog, run history;
- Ask the agent in conversation — the sidecar registers scheduler tools, so the agent can create tasks for you;
- Task templates — pick one from the template picker and adjust it.
Built-in templates
The unattended permission tier
When there is nobody to ask, “ask” is not an option — approval has to be a hard decision. Scheduled tasks use their own permission axis (toolPolicyProfile), three tiers,
defaulting to the tightest:
An explicit grant is not overridden by the tier:
allowCommands (command word
prefixes) and allowMcpTools (exact tool names) are standing authorizations, evaluated
before the tiers — the same allow-list must not mean opposite things on the “I run it
myself” path and the “it runs on a schedule” path.
What happens when a tool is denied
A denial does not deadlock the task or trigger endless retries. The scheduler tells the model:Do not retry this tool; finish the task with allowed read-only operations.So a
read-only daily report that hits bash will assemble the report by reading
files instead, rather than retrying until it times out.
Webhooks and notifications
Task events (fired, completed, failed) can be pushed to any service — theautomation.* entries in the event registry show up automatically in the webhook
settings dropdown.
Completion can also go out as a system notification; clicking it lands in that run’s
session.
maxConcurrentRuns (default 2) and maxTasks (default 30) are locally added
guardrails so the scheduler cannot run away.
Run history
The “Run history” tab aggregates across tasks, groups by day, and is searchable. Queued triggers appear here too — so when a task “didn’t run”, the first place to look is the run history, not the task card.Management UI
Task cards
Header row: run now / edit / history; ⋯ holds only delete
Two tabs
”Tasks | Run history”; history aggregates across tasks, grouped by day, searchable
Bulk management
Card checkbox / select-all, bulk enable / pause / delete (two-step delete confirmation)
Next
Modes overview
The difference between the two “tier” axes and what each means.
Remote access & mobile
Check on these jobs while you are away.
