{
  "access": "public",
  "type": "reference",
  "format": "markdown",
  "title": "Scheduler Tools Reference",
  "chunked": true,
  "url": "https://library.datagrout.ai/scheduler-tools",
  "summary": "Defer and repeat tool calls or workflows on a time-based or event-driven schedule.",
  "content_markdown": "# Scheduler Tools\n\nDefer and repeat tool calls or workflows on a time-based or event-driven schedule.\n\nScheduler tools let agents create, inspect, and cancel scheduled tasks powered by the Governor system. You describe the schedule in natural language and provide the tool or workflow to run — the system parses the schedule, installs the appropriate triggers, and fires the task at the right time. All Scheduler tools are available at `data-grout@1/scheduler.*@1`.\n\n**Important**: Scheduled tasks require an active Governor session to fire. The scheduler auto-provisions a lightweight Governor session (5 credits/hour) when creating a task, so you do not need to call `governor.enable` manually. However, if the Governor session is explicitly ended via `governor.disable`, scheduled tasks will be paused until the session is restarted. Calling `governor.enable` before scheduling gives you a full-featured Governor with percepts and enrichment on top of the scheduler.\n\nYou can also pass a `schedule` parameter directly to `discovery.perform` or `flow.into` to schedule any single tool call or workflow without calling `scheduler.create` explicitly.\n\n---\n\n## `scheduler.create@1`\n\nSchedule a tool call or multi-step workflow for deferred or recurring execution. Accepts a natural language schedule description alongside either a `tool` name (single call) or a `plan` array (multi-step workflow).\n\nTwo execution models are supported:\n\n- **Time-based** (e.g. `\"daily at 9am\"`, `\"in 30 minutes\"`): scheduled directly at the computed time\n- **Event-driven** (e.g. `\"whenever 10 new leads arrive\"`): trigger-based execution powered by the Governor system\n\n### Parameters\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `schedule` | string | yes | -- | Natural language schedule description (e.g. `\"every 5 minutes\"`, `\"daily at 9am UTC\"`, `\"every Monday at 8:30am\"`) |\n| `tool` | string | conditionally | -- | Full tool name to execute on each trigger. Provide either `tool` or `plan` |\n| `args` | object | no | `{}` | Arguments to pass to the tool on each execution |\n| `plan` | array | conditionally | -- | A `flow.into`-style plan array for multi-step workflows. Provide either `tool` or `plan` |\n| `refract` | string | no | -- | Optional `prism.refract` goal to apply to the tool output on each execution |\n| `chart` | string | no | -- | Optional `prism.chart` goal to apply to the tool output on each execution |\n| `max_fires` | integer | no | unlimited | Maximum number of times to fire. Omit for unlimited recurring execution |\n\n### Example: recurring tool call\n\n```json\n{\n  \"name\": \"data-grout@1/scheduler.create@1\",\n  \"arguments\": {\n    \"schedule\": \"every weekday at 8am UTC\",\n    \"tool\": \"quickbooks@1/get-all-overdue-invoices@1\",\n    \"args\": { \"days_overdue\": 30 },\n    \"refract\": \"list customers with total overdue > $1000 sorted by amount descending\"\n  }\n}\n```\n\nResponse:\n\n```json\n{\n  \"success\": true,\n  \"scheduled_task_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"schedule_type\": \"time_based\",\n  \"schedule\": {\n    \"cron\": \"0 8 * * 1-5\",\n    \"description\": \"Every weekday at 08:00 UTC\"\n  },\n  \"next_fire_at\": \"2026-03-03T08:00:00Z\",\n  \"recurs\": true,\n  \"message\": \"Scheduled: every weekday at 8am UTC\"\n}\n```\n\n### Example: one-time deferred workflow\n\n```json\n{\n  \"name\": \"data-grout@1/scheduler.create@1\",\n  \"arguments\": {\n    \"schedule\": \"in 2 hours\",\n    \"plan\": [\n      {\n        \"id\": \"sync_leads\",\n        \"tool\": \"salesforce@1/get-all-leads@1\",\n        \"args\": { \"status\": \"New\" }\n      },\n      {\n        \"id\": \"notify\",\n        \"tool\": \"data-grout@1/flow.request-approval@1\",\n        \"args\": {\n          \"action\": \"Import new leads\",\n          \"details\": \"$sync_leads.count leads ready to import\"\n        }\n      }\n    ],\n    \"max_fires\": 1\n  }\n}\n```\n\n### Example: inline scheduling on discovery.perform\n\n`schedule` must be a **top-level** `discovery.perform` parameter, **not** nested inside `args`. Nesting it inside `args` will cause immediate execution with no scheduling.\n\n```json\n{\n  \"name\": \"data-grout@1/discovery.perform@1\",\n  \"arguments\": {\n    \"tool\": \"quickbooks@1/get-all-invoices@1\",\n    \"args\": { \"status\": \"open\" },\n    \"schedule\": \"every day at 6pm\"\n  }\n}\n```\n\nThis is equivalent to calling `scheduler.create` with the same `tool`, `args`, and `schedule`.\n\n---\n\n## `scheduler.list@1`\n\nList active, pending, paused, and completed scheduled tasks for the current user.\n\n### Parameters\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `agent_id` | string | no | -- | Filter by a specific agent ID. Omit to list all tasks for the user |\n| `status` | string | no | `\"all\"` | Filter by status: `\"active\"`, `\"pending\"`, `\"paused\"`, `\"completed\"`, `\"cancelled\"`, `\"all\"` |\n\n### Example\n\n```json\n{\n  \"name\": \"data-grout@1/scheduler.list@1\",\n  \"arguments\": {\n    \"status\": \"active\"\n  }\n}\n```\n\nResponse:\n\n```json\n{\n  \"success\": true,\n  \"tasks\": [\n    {\n      \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n      \"schedule_goal\": \"every weekday at 8am UTC\",\n      \"tool_name\": \"quickbooks@1/get-all-overdue-invoices@1\",\n      \"status\": \"active\",\n      \"recurs\": true,\n      \"next_fire_at\": \"2026-03-03T08:00:00Z\",\n      \"last_fired_at\": \"2026-03-02T08:00:01Z\",\n      \"fire_count\": 12,\n      \"max_fires\": null,\n      \"cron_expression\": \"0 8 * * 1-5\",\n      \"description\": \"Every weekday at 08:00 UTC\",\n      \"created_at\": \"2026-02-17T14:22:00Z\"\n    }\n  ],\n  \"total\": 1\n}\n```\n\n---\n\n## `scheduler.cancel@1`\n\nCancel an active or pending scheduled task by its ID. Use `scheduler.list` to find task IDs.\n\n### Parameters\n\n| Parameter | Type | Required | Default | Description |\n|-----------|------|----------|---------|-------------|\n| `task_id` | string | yes | -- | The scheduled task UUID to cancel |\n\n### Example\n\n```json\n{\n  \"name\": \"data-grout@1/scheduler.cancel@1\",\n  \"arguments\": {\n    \"task_id\": \"550e8400-e29b-41d4-a716-446655440000\"\n  }\n}\n```\n\nResponse:\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Scheduled task cancelled: every weekday at 8am UTC\",\n  \"task_id\": \"550e8400-e29b-41d4-a716-446655440000\"\n}\n```\n\n---\n\n## Typical usage patterns\n\n**Recurring data sync with post-processing:**\n\n```json\n{\n  \"schedule\": \"every hour\",\n  \"tool\": \"salesforce@1/get-all-leads@1\",\n  \"args\": { \"status\": \"New\", \"limit\": 500 },\n  \"refract\": \"count by owner and flag owners with more than 20 new leads\"\n}\n```\n\n**Deferred one-shot task:**\n\n```json\n{\n  \"schedule\": \"in 30 minutes\",\n  \"tool\": \"quickbooks@1/send-invoice@1\",\n  \"args\": { \"invoice_id\": \"INV-1042\" },\n  \"max_fires\": 1\n}\n```\n\n**Scheduled workflow that needs human approval:**\n\nCombine `scheduler.create` with a `plan` that includes `flow.request-approval` as a step. The approval gate fires mid-workflow each time the schedule triggers.\n\n---\n\n## Event-Driven Scheduling\n\nEvent-driven schedules use the Governor system's Reflex layer to fire tasks based on conditions rather than fixed times. When you create an event-driven schedule, the system:\n\n1. **Parses the trigger** using the Governor Reflection LLM to extract the condition\n2. **Installs percepts** — lightweight sensors that watch for relevant events\n3. **Asserts Prolog facts** — `scheduled_task/5` and `schedule_trigger/4` facts into the Governor's fact space\n4. **Evaluates triggers** via Reflex — the symbolic Prolog layer checks conditions on each percept event (zero LLM tokens per check)\n5. **Fires the task** when conditions are met, recording `schedule_fired/4` facts\n\n### Percept Types\n\nThe Governor supports several percept types that can trigger event-driven schedules:\n\n| Percept | Description | Example trigger |\n|---------|-------------|-----------------|\n| `cron` | Time-based conditions evaluated as Prolog facts | `\"every hour between 9am and 5pm\"` |\n| `file_watch` | File system change notifications | `\"whenever the sales report is updated\"` |\n| `webhook` | External webhook events | `\"when a new Stripe payment arrives\"` |\n| `process` | System process status changes | `\"when the ETL job finishes\"` |\n\n### How Reflex evaluation works\n\nEvent-driven schedules are evaluated symbolically (no LLM):\n\n1. A percept fires (e.g., a file changes)\n2. The percept handler asserts a fact into the Prolog fact space (e.g., `file_changed(Path, Timestamp)`)\n3. Reflex queries the trigger's Prolog rule against the current fact space\n4. If the rule succeeds, the `GovernorScheduleExecutor` Oban worker runs the scheduled tool/plan\n5. The fact `schedule_fired(TaskId, Agent, Timestamp, Result)` is asserted for audit\n\nThis means that after initial setup, recurring trigger evaluation costs zero LLM tokens — all the logic runs in SWI-Prolog.\n\n### Example: event-driven schedule\n\n```json\n{\n  \"name\": \"data-grout@1/scheduler.create@1\",\n  \"arguments\": {\n    \"schedule\": \"whenever 10 new leads arrive in Salesforce\",\n    \"tool\": \"salesforce@1/get-all-leads@1\",\n    \"args\": { \"status\": \"New\", \"limit\": 10 },\n    \"refract\": \"summarize lead sources and flag any from enterprise companies\"\n  }\n}\n```\n\nResponse:\n\n```json\n{\n  \"success\": true,\n  \"scheduled_task_id\": \"7f1a2b3c-...\",\n  \"schedule_type\": \"event_driven\",\n  \"schedule\": {\n    \"trigger\": \"lead_count_threshold\",\n    \"condition\": \"10 new leads\",\n    \"percept_type\": \"webhook\"\n  },\n  \"recurs\": true,\n  \"message\": \"Scheduled: fires whenever 10 new leads arrive\"\n}\n```\n\n### Governor billing\n\nEvent-driven schedules require an active Governor session. Billing:\n\n- **Full Governor session** (active monitoring): 50 credits/hour\n- **Schedule-only mode** (just firing on percepts): 5 credits/hour\n- The schedule executor itself charges normal tool costs when it fires\n\n### Reflection loop\n\nFor complex event-driven schedules, the Governor's Reflection loop can learn new patterns:\n\n1. If a simple percept isn't sufficient, Reflection (LLM, up to 5 iterations) analyzes the schedule goal\n2. It may synthesize new Prolog rules and install new percepts automatically\n3. The `GovernorScheduleReflector` Oban worker reviews active schedules every 6 hours\n4. Schedules whose Governor sessions have gone inactive are automatically paused\n"
}