Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
11
docs/automation/auth-monitoring.md
Normal file
11
docs/automation/auth-monitoring.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
summary: "Redirect to /gateway/authentication"
|
||||
title: "Auth monitoring"
|
||||
---
|
||||
|
||||
This page moved. Model provider authentication lives under [Authentication](/gateway/authentication); ops scripts for monitoring auth state live at [Auth monitoring scripts](/help/scripts#auth-monitoring-scripts).
|
||||
|
||||
## Related
|
||||
|
||||
- [Automation troubleshooting](/automation/cron-jobs#troubleshooting)
|
||||
- [Hooks](/automation/hooks)
|
||||
12
docs/automation/clawflow.md
Normal file
12
docs/automation/clawflow.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
summary: "Redirect to Task Flow"
|
||||
title: "ClawFlow"
|
||||
---
|
||||
|
||||
ClawFlow was renamed to [Task Flow](/automation/taskflow). Use that page for durable multi-step flow orchestration.
|
||||
|
||||
## Related
|
||||
|
||||
- [Task Flow](/automation/taskflow)
|
||||
- [Standing orders](/automation/standing-orders)
|
||||
- [Hooks](/automation/hooks)
|
||||
586
docs/automation/cron-jobs.md
Normal file
586
docs/automation/cron-jobs.md
Normal file
@@ -0,0 +1,586 @@
|
||||
---
|
||||
summary: "Scheduled jobs, webhooks, and Gmail PubSub triggers for the Gateway scheduler"
|
||||
read_when:
|
||||
- Scheduling background jobs or wakeups
|
||||
- Wiring external triggers (webhooks, Gmail) into OpenClaw
|
||||
- Deciding between heartbeat and cron for scheduled tasks
|
||||
title: "Scheduled tasks"
|
||||
sidebarTitle: "Scheduled tasks"
|
||||
---
|
||||
|
||||
Cron is the Gateway's built-in scheduler. It persists jobs, wakes the agent at the right time, and can deliver output to a chat channel, a webhook, or nowhere.
|
||||
|
||||
## Quick start
|
||||
|
||||
<Steps>
|
||||
<Step title="Add a one-shot reminder">
|
||||
```bash
|
||||
openclaw cron create "2027-02-01T16:00:00Z" \
|
||||
--name "Reminder" \
|
||||
--session main \
|
||||
--system-event "Reminder: check the cron docs draft" \
|
||||
--wake now \
|
||||
--delete-after-run
|
||||
```
|
||||
</Step>
|
||||
<Step title="Check your jobs">
|
||||
```bash
|
||||
openclaw cron list
|
||||
openclaw cron get <job-id>
|
||||
openclaw cron show <job-id>
|
||||
```
|
||||
</Step>
|
||||
<Step title="See run history">
|
||||
```bash
|
||||
openclaw cron runs --id <job-id>
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## How cron works
|
||||
|
||||
- Cron runs **inside the Gateway process**, not inside the model. The Gateway must be running for schedules to fire.
|
||||
- Job definitions, runtime state, and run history persist in OpenClaw's shared SQLite state database, so restarts do not lose schedules.
|
||||
- Every cron execution creates a [background task](/automation/tasks) record.
|
||||
- One-shot jobs (`--at`) auto-delete after success by default; pass `--keep-after-run` to keep them.
|
||||
- Per-run wall-clock budget: `--timeout-seconds` when set. Otherwise, isolated/detached agent-turn jobs are bounded by cron's own 60-minute watchdog before the underlying agent-turn timeout (`agents.defaults.timeoutSeconds`, default 48 hours) would ever apply; command jobs default to 10 minutes.
|
||||
- On Gateway startup, overdue isolated agent-turn jobs are rescheduled instead of replayed immediately, keeping model/tool bootstrap work out of the channel-connect window.
|
||||
- If you drive `openclaw agent` from system cron or another external scheduler, wrap it with a hard-kill escalation even though the CLI already handles `SIGTERM`/`SIGINT`. Gateway-backed runs ask the Gateway to abort accepted runs; local and embedded fallback runs get the same abort signal. For GNU `timeout`, prefer `timeout -k 60 600 openclaw agent ...` over plain `timeout 600 ...` — the `-k` value is the backstop if the process cannot drain in time. For systemd units, use a `SIGTERM` stop signal with a grace window (`TimeoutStopSec`) before the final kill. Reusing a `--run-id` while the original Gateway run is still active reports the duplicate as in-flight instead of starting a second run.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Isolated run hardening">
|
||||
- Isolated runs best-effort close tracked browser tabs/processes for their `cron:<jobId>` session on completion, and dispose any bundled MCP runtime instances created for the job through the same shared teardown path used by main-session and custom-session runs. Cleanup failures are ignored so the cron result still wins.
|
||||
- Isolated runs with the narrow cron self-cleanup grant can read scheduler status, a self-filtered list containing only their own job, and that job's run history, and may remove only their own job.
|
||||
- Isolated runs guard against stale acknowledgement replies: if the first result is only an interim status update (`on it`, `pulling everything together`, and similar hints) and no descendant subagent is still responsible for the final answer, OpenClaw re-prompts once for the actual result before delivery.
|
||||
- Structured execution-denial metadata (including node-host `UNAVAILABLE` wrappers whose nested error starts with `SYSTEM_RUN_DENIED` or `INVALID_REQUEST`) is recognized so a blocked command is not reported as a green run, while ordinary assistant prose is not mistaken for a denial.
|
||||
- Run-level agent failures count as job errors even with no reply payload, so model/provider failures increment error counters and trigger failure notifications instead of clearing the job as successful.
|
||||
- When a job hits `timeoutSeconds`, cron aborts the run and gives it a short cleanup window. If it does not drain, Gateway-owned cleanup force-clears that run's session ownership before cron records the timeout, so queued chat work is not stuck behind a stale processing session.
|
||||
- Setup/startup stalls get a phase-specific timeout (for example `cron: isolated agent setup timed out before runner start` or `cron: isolated agent run stalled before execution start (last phase: context-engine)`). These watchdogs cover embedded and CLI-backed providers even before their external CLI process starts, and are capped independently of long `timeoutSeconds` values so cold-start/auth/context failures surface quickly.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Task reconciliation">
|
||||
Cron task reconciliation is runtime-owned first, durable-history-backed second: an active cron task stays live while the cron runtime still tracks that job as running, even if an old child session row still exists. Once the runtime stops owning the job and a 5-minute grace window expires, maintenance checks persisted run logs and job state for the matching `cron:<jobId>:<startedAt>` run. A terminal result there finalizes the task ledger; otherwise Gateway-owned maintenance can mark the task `lost`. Offline CLI audit can recover from durable history, but its own empty in-process active-job set is not proof a Gateway-owned run is gone.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Schedule types
|
||||
|
||||
| Kind | CLI flag | Description |
|
||||
| --------- | ----------- | -------------------------------------------------------------------------------------------------------- |
|
||||
| `at` | `--at` | One-shot timestamp (ISO 8601 or relative like `20m`) |
|
||||
| `every` | `--every` | Fixed interval (`10m`, `1h`, `1d`) |
|
||||
| `cron` | `--cron` | 5-field or 6-field cron expression with optional `--tz` |
|
||||
| `on-exit` | `--on-exit` | Fire once when a watched command exits (event trigger; survives turn teardown; optional `--on-exit-cwd`) |
|
||||
|
||||
Timestamps without a timezone are treated as UTC. Add `--tz America/New_York` to interpret an offset-less `--at` datetime, or to evaluate a cron expression, in that IANA timezone. Cron expressions without `--tz` use the Gateway host timezone. `--tz` is not valid with `--every` or `--on-exit`.
|
||||
|
||||
Recurring top-of-hour expressions (minute `0` with a wildcard hour field) are automatically staggered by up to 5 minutes to reduce load spikes. Use `--exact` to force precise timing, or `--stagger 30s` for an explicit window (cron schedules only).
|
||||
|
||||
### Day-of-month and day-of-week use OR logic
|
||||
|
||||
Cron expressions are parsed by [croner](https://github.com/Hexagon/croner). When both the day-of-month and day-of-week fields are non-wildcard, croner matches when **either** field matches, not both. This is standard Vixie cron behavior.
|
||||
|
||||
```bash
|
||||
# Intended: "9 AM on the 15th, only if it's a Monday"
|
||||
# Actual: "9 AM on every 15th, AND 9 AM on every Monday"
|
||||
0 9 15 * 1
|
||||
```
|
||||
|
||||
This fires roughly 5-6 times a month instead of 0-1 times a month. To require both conditions, use croner's `+` day-of-week modifier (`0 9 15 * +1`), or schedule on one field and guard the other in your job's prompt or command.
|
||||
|
||||
## Payloads
|
||||
|
||||
Every job carries exactly one payload kind, chosen by flag:
|
||||
|
||||
| Payload | Flag | Runs |
|
||||
| ------------- | ---------------------------------------------- | ------------------------------------------------------- |
|
||||
| System event | `--system-event <text>` | Enqueued into the main session, no model call by itself |
|
||||
| Agent message | `--message <text>` | A model-backed agent turn |
|
||||
| Command | `--command <shell>` or `--command-argv <json>` | A shell/process on the Gateway host, no model call |
|
||||
|
||||
### Agent-turn options
|
||||
|
||||
<ParamField path="--message" type="string" required>
|
||||
Prompt text (required for isolated/current/custom-session jobs).
|
||||
</ParamField>
|
||||
<ParamField path="--model" type="string">
|
||||
Model override; must resolve to an allowed model or the run fails with a validation error.
|
||||
</ParamField>
|
||||
<ParamField path="--fallbacks" type="string">
|
||||
Per-job fallback model list, for example `--fallbacks openai/gpt-5.5,openrouter/meta-llama/llama-3.3-70b-instruct:free`. Pass `--fallbacks ""` for a strict run with no fallbacks.
|
||||
</ParamField>
|
||||
<ParamField path="--clear-fallbacks" type="boolean">
|
||||
On `cron edit`, removes the per-job fallback override so the job follows configured fallback precedence. Cannot combine with `--fallbacks`.
|
||||
</ParamField>
|
||||
<ParamField path="--clear-model" type="boolean">
|
||||
On `cron edit`, removes the per-job model override so the job follows normal cron model precedence (stored cron-session override, else agent/default model). Cannot combine with `--model`.
|
||||
</ParamField>
|
||||
<ParamField path="--thinking" type="string">
|
||||
Thinking level override (`off|minimal|low|medium|high|xhigh|adaptive|max`).
|
||||
</ParamField>
|
||||
<ParamField path="--clear-thinking" type="boolean">
|
||||
On `cron edit`, removes the per-job thinking override. Cannot combine with `--thinking`.
|
||||
</ParamField>
|
||||
<ParamField path="--light-context" type="boolean">
|
||||
Skip workspace bootstrap file injection.
|
||||
</ParamField>
|
||||
<ParamField path="--tools" type="string">
|
||||
Restrict which tools the job can use, for example `--tools exec,read`.
|
||||
</ParamField>
|
||||
|
||||
`--model` sets the job's primary model; it does not replace a session `/model` override, so configured fallback chains still apply on top of it. An unresolved or disallowed model fails the run with an explicit validation error rather than silently falling back to the default. If a job has `--model` but no explicit or configured fallback list, OpenClaw passes an empty fallback override instead of silently appending the agent primary as a hidden retry target.
|
||||
|
||||
Model-selection precedence for isolated jobs, highest first:
|
||||
|
||||
1. Per-job payload `model` (explicit config; a disallowed model fails the run)
|
||||
2. Gmail hook model override (only when the run came from Gmail and that override is allowed)
|
||||
3. User-selected stored cron-session model override
|
||||
4. Agent/default model selection
|
||||
|
||||
Fast mode follows the resolved live selection. If the selected model config has `params.fastMode`, isolated cron uses it by default; a stored session `fastMode` override (then an agent `fastModeDefault`) still wins over model config either direction. Auto mode uses the model's `params.fastAutoOnSeconds` cutoff, defaulting to 60 seconds.
|
||||
|
||||
If a run hits a live model-switch handoff, cron retries with the switched provider/model and persists that selection (and any new auth profile) for the active run. Retries are bounded: after the initial attempt plus 2 switch retries, cron aborts instead of looping.
|
||||
|
||||
Before an isolated run starts, OpenClaw checks reachable local endpoints for configured `api: "ollama"` and `api: "openai-completions"` providers whose `baseUrl` is loopback, private-network, or `.local`. This preflight walks the job's configured fallback chain and only marks the run `skipped` once every candidate is unreachable; `--fallbacks ""` keeps that walk strict to just the primary model. A down endpoint records the run as `skipped` with a clear error instead of starting a model call. The result is cached for 5 minutes per endpoint (not per job or model), so many due jobs sharing a dead local Ollama/vLLM/SGLang/LM Studio server cost one probe instead of a request storm. Skipped preflight runs do not increment execution-error backoff; set `failureAlert.includeSkipped` to opt into repeated skip alerts.
|
||||
|
||||
### Command payloads
|
||||
|
||||
Command payloads run deterministic scripts inside the Gateway scheduler without starting a model-backed turn. They execute on the Gateway host, capture stdout/stderr, record the run in cron history, and reuse the same `announce`, `webhook`, and `none` delivery modes as agent-turn jobs.
|
||||
|
||||
<Note>
|
||||
Command cron is an operator-admin Gateway automation surface, not an agent `tools.exec` call. Creating, updating, removing, or manually running cron jobs requires `operator.admin`; scheduled command runs later execute inside the Gateway process as that admin-authored automation. Agent exec policy (`tools.exec.mode`, approval prompts, per-agent tool allowlists) governs model-visible exec tools, not command cron payloads.
|
||||
</Note>
|
||||
|
||||
```bash
|
||||
openclaw cron create "*/15 * * * *" \
|
||||
--name "Queue depth probe" \
|
||||
--command "scripts/check-queue.sh" \
|
||||
--command-cwd "/srv/app" \
|
||||
--announce \
|
||||
--channel telegram \
|
||||
--to "-1001234567890"
|
||||
```
|
||||
|
||||
`--command <shell>` stores `argv: ["sh", "-lc", <shell>]`. Use `--command-argv '["node","scripts/report.mjs"]'` for exact argv execution without shell parsing. Optional `--command-env KEY=VALUE` (repeatable), `--command-input`, `--timeout-seconds` (default 10 minutes), `--no-output-timeout-seconds`, and `--output-max-bytes` control the process environment, stdin, and output bounds.
|
||||
|
||||
Delivered text is derived from process output: non-empty stdout wins; if stdout is empty and stderr is non-empty, stderr is delivered; if both are present, cron sends a small `stdout:` / `stderr:` block. Exit code `0` records the run `ok`; non-zero exit, signal, timeout, or no-output timeout records `error` and can trigger failure alerts. A command that prints only `NO_REPLY` uses the normal cron silent-token suppression and posts nothing back to chat.
|
||||
|
||||
## Execution styles
|
||||
|
||||
| Style | `--session` value | Runs in | Best for |
|
||||
| --------------- | ------------------- | ------------------------ | ------------------------------- |
|
||||
| Main session | `main` | Dedicated cron wake lane | Reminders, system events |
|
||||
| Isolated | `isolated` | Dedicated `cron:<jobId>` | Reports, background chores |
|
||||
| Current session | `current` | Bound at creation time | Context-aware recurring work |
|
||||
| Custom session | `session:custom-id` | Persistent named session | Workflows that build on history |
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Main session vs isolated vs custom">
|
||||
**Main session** jobs enqueue a system event into a cron-owned run lane and optionally wake the heartbeat (`--wake now` or `--wake next-heartbeat`). They can use the target main session's last delivery context for replies, but do not append routine cron turns to the human chat lane and do not extend daily/idle reset freshness for the target session. **Isolated** jobs run a dedicated agent turn with a fresh session. **Custom sessions** (`session:xxx`) persist context across runs, enabling workflows like daily standups that build on previous summaries.
|
||||
|
||||
Main-session cron events are self-contained system-event reminders. They do not automatically include the default heartbeat prompt's "Read HEARTBEAT.md" instruction; say that explicitly in the cron event text if a reminder should consult `HEARTBEAT.md`.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="What 'fresh session' means for isolated jobs">
|
||||
A new transcript/session id per run. OpenClaw carries safe preferences (thinking/fast/verbose settings, labels, explicit user-selected model/auth overrides), but does not inherit ambient conversation context from an older cron row: channel/group routing, send or queue policy, elevation, origin, or ACP runtime binding. Use `current` or `session:<id>` when a recurring job should deliberately build on the same conversation context.
|
||||
</Accordion>
|
||||
<Accordion title="Subagent and Discord delivery">
|
||||
When isolated cron runs orchestrate subagents, delivery prefers the final descendant output over stale parent interim text. If descendants are still running, OpenClaw suppresses that partial parent update instead of announcing it.
|
||||
|
||||
For text-only Discord announce targets, OpenClaw sends the canonical final assistant text once instead of replaying both streamed/intermediate text and the final answer. Media and structured Discord payloads are still delivered separately so attachments and components are not dropped.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Delivery and output
|
||||
|
||||
| Mode | What happens |
|
||||
| ---------- | ------------------------------------------------------------------- |
|
||||
| `announce` | Fallback-deliver final text to the target if the agent did not send |
|
||||
| `webhook` | POST finished event payload to a URL |
|
||||
| `none` | No runner fallback delivery |
|
||||
|
||||
Use `--announce --channel telegram --to "-1001234567890"` for channel delivery. For Telegram forum topics, use `-1001234567890:topic:123`; OpenClaw also accepts the Telegram-owned `-1001234567890:123` shorthand. Direct RPC/config callers may pass `delivery.threadId` as a string or number. Slack/Discord/Mattermost targets use explicit prefixes (`channel:<id>`, `user:<id>`). Matrix room IDs are case-sensitive; use the exact room ID or `room:!room:server` form from Matrix.
|
||||
|
||||
When announce delivery uses `channel: "last"` or omits `channel`, a provider-prefixed target such as `telegram:123` can select the channel before cron falls back to session history or a single configured channel. Only prefixes advertised by the loaded plugin are provider selectors. If `delivery.channel` is explicit, the target prefix must name the same provider; `channel: "whatsapp"` with `to: "telegram:123"` is rejected instead of letting WhatsApp interpret the Telegram ID as a phone number. Target-kind and service prefixes (`channel:<id>`, `user:<id>`, `imessage:<handle>`, `sms:<number>`) stay channel-owned target syntax, not provider selectors.
|
||||
|
||||
For isolated jobs, chat delivery is shared: if a chat route is available, the agent can use the `message` tool even with `--no-deliver`. If the agent sends to the configured/current target, OpenClaw skips the fallback announce. Otherwise `announce`, `webhook`, and `none` only control what the runner does with the final reply after the agent turn.
|
||||
|
||||
When an agent creates an isolated reminder from an active chat, OpenClaw stores the preserved live delivery target for the fallback announce route. Internal session keys may be lowercase; provider delivery targets are not reconstructed from those keys when current chat context is available.
|
||||
|
||||
Implicit announce delivery uses configured channel allowlists to validate and reroute stale targets. DM pairing-store approvals are not fallback automation recipients; set `delivery.to` or configure the channel `allowFrom` entry when a scheduled job should proactively send to a DM.
|
||||
|
||||
### Failure notifications
|
||||
|
||||
Failure notifications follow a separate destination path:
|
||||
|
||||
- `cron.failureDestination` sets a global default for failure notifications.
|
||||
- `job.delivery.failureDestination` overrides that per job.
|
||||
- If neither is set and the job already delivers via `announce`, failure notifications fall back to that primary announce target.
|
||||
- `delivery.failureDestination` is only supported on `sessionTarget="isolated"` jobs unless the primary delivery mode is `webhook`.
|
||||
- `failureAlert.includeSkipped: true` opts a job or global cron alert policy into repeated skipped-run alerts. Skipped runs keep a separate consecutive-skip counter, so they do not affect execution-error backoff.
|
||||
- `openclaw cron edit` exposes per-job alert tuning: `--failure-alert`/`--no-failure-alert`, `--failure-alert-after <n>`, `--failure-alert-channel`, `--failure-alert-to`, `--failure-alert-cooldown`, `--failure-alert-include-skipped`/`--failure-alert-exclude-skipped`, `--failure-alert-mode`, and `--failure-alert-account-id`.
|
||||
|
||||
### Output language
|
||||
|
||||
Cron jobs do not infer a reply language from channel, locale, or previous messages. Put the language rule in the scheduled message or template:
|
||||
|
||||
```bash
|
||||
openclaw cron edit <jobId> \
|
||||
--message "Summarize the updates. Respond in Chinese; keep URLs, code, and product names unchanged."
|
||||
```
|
||||
|
||||
For template files, keep the language instruction in the rendered prompt and verify placeholders such as `{{language}}` are filled before the job runs. If the output mixes languages, make the rule explicit, for example: "Use Chinese for narrative text and keep technical terms in English."
|
||||
|
||||
## CLI examples
|
||||
|
||||
<Tabs>
|
||||
<Tab title="One-shot reminder">
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Calendar check" \
|
||||
--at "20m" \
|
||||
--session main \
|
||||
--system-event "Next heartbeat: check calendar." \
|
||||
--wake now
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Recurring isolated job">
|
||||
```bash
|
||||
openclaw cron create "0 7 * * *" \
|
||||
"Summarize overnight updates." \
|
||||
--name "Morning brief" \
|
||||
--tz "America/Los_Angeles" \
|
||||
--session isolated \
|
||||
--announce \
|
||||
--channel slack \
|
||||
--to "channel:C1234567890"
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Model and thinking override">
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Deep analysis" \
|
||||
--cron "0 6 * * 1" \
|
||||
--tz "America/Los_Angeles" \
|
||||
--session isolated \
|
||||
--message "Weekly deep analysis of project progress." \
|
||||
--model "opus" \
|
||||
--thinking high \
|
||||
--announce
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Webhook output">
|
||||
```bash
|
||||
openclaw cron create "0 18 * * 1-5" \
|
||||
"Summarize today's deploys as JSON." \
|
||||
--name "Deploy digest" \
|
||||
--webhook "https://example.invalid/openclaw/cron"
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Command output">
|
||||
```bash
|
||||
openclaw cron create "*/15 * * * *" \
|
||||
--name "Queue depth probe" \
|
||||
--command "scripts/check-queue.sh" \
|
||||
--command-cwd "/srv/app" \
|
||||
--announce \
|
||||
--channel telegram \
|
||||
--to "-1001234567890"
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Managing jobs
|
||||
|
||||
```bash
|
||||
# List all jobs
|
||||
openclaw cron list
|
||||
|
||||
# Get one stored job as JSON
|
||||
openclaw cron get <jobId>
|
||||
|
||||
# Show one job, including resolved delivery route
|
||||
openclaw cron show <jobId>
|
||||
|
||||
# Enable/disable without deleting
|
||||
openclaw cron enable <jobId>
|
||||
openclaw cron disable <jobId>
|
||||
|
||||
# Edit a job
|
||||
openclaw cron edit <jobId> --message "Updated prompt" --model "opus"
|
||||
|
||||
# Force run a job now
|
||||
openclaw cron run <jobId>
|
||||
|
||||
# Force run a job now and wait for its terminal status
|
||||
openclaw cron run <jobId> --wait --wait-timeout 10m --poll-interval 2s
|
||||
|
||||
# Run only if due
|
||||
openclaw cron run <jobId> --due
|
||||
|
||||
# View run history
|
||||
openclaw cron runs --id <jobId> --limit 50
|
||||
|
||||
# View one exact run
|
||||
openclaw cron runs --id <jobId> --run-id <runId>
|
||||
|
||||
# Delete a job
|
||||
openclaw cron remove <jobId>
|
||||
|
||||
# Agent selection (multi-agent setups)
|
||||
openclaw cron create "0 6 * * *" "Check ops queue" --name "Ops sweep" --session isolated --agent ops
|
||||
openclaw cron edit <jobId> --clear-agent
|
||||
```
|
||||
|
||||
`openclaw cron run <jobId>` returns after enqueueing the manual run. Use `--wait` for shutdown hooks, maintenance scripts, or other automation that must block until the queued run finishes; it polls the returned `runId` (default timeout `10m`, poll interval `2s`) and exits `0` for status `ok`, non-zero for `error`, `skipped`, or a wait timeout.
|
||||
|
||||
The agent `cron` tool returns compact job summaries (`id`, `name`, `enabled`, `nextRunAtMs`, `scheduleKind`, `lastRunStatus`) from `cron(action: "list")`; use `cron(action: "get", jobId: "...")` for one full job definition. Direct Gateway callers can pass `compact: true` to `cron.list`; omitting it preserves the full response with delivery previews.
|
||||
|
||||
`openclaw cron create` is an alias for `openclaw cron add`. New jobs can use a positional schedule (`"0 9 * * 1"`, `"every 1h"`, `"20m"`, or an ISO timestamp) followed by a positional agent prompt. Use `--webhook <url>` on `cron add|create` or `cron edit` to POST the finished run payload to an HTTP endpoint; webhook delivery cannot combine with chat delivery flags (`--announce`, `--channel`, `--to`, `--thread-id`, `--account`). On `cron edit`, `--clear-channel`, `--clear-to`, `--clear-thread-id`, and `--clear-account` unset those routing fields individually (each rejected alongside its matching set flag) — distinct from `--no-deliver`, which only disables runner fallback delivery.
|
||||
|
||||
<Note>
|
||||
Model override note:
|
||||
|
||||
- `openclaw cron add|edit --model ...` changes the job's selected model.
|
||||
- If the model is allowed, that exact provider/model reaches the isolated agent run.
|
||||
- If it is not allowed or cannot be resolved, cron fails the run with an explicit validation error.
|
||||
- API `cron.update` payload patches can set `model: null` to clear a stored job model override.
|
||||
- `openclaw cron edit <job-id> --clear-model` clears that override from the CLI (same effect as the `model: null` patch) and cannot combine with `--model`.
|
||||
- Configured fallback chains still apply because cron `--model` is a job primary, not a session `/model` override.
|
||||
- `openclaw cron add|edit --fallbacks ...` sets payload `fallbacks`, replacing configured fallbacks for that job; `--fallbacks ""` disables fallback and makes the run strict. `openclaw cron edit <job-id> --clear-fallbacks` clears the per-job override.
|
||||
- A plain `--model` with no explicit or configured fallback list does not fall through to the agent primary as a silent extra retry target.
|
||||
|
||||
</Note>
|
||||
|
||||
## Webhooks
|
||||
|
||||
Gateway can expose HTTP webhook endpoints for external triggers. Enable in config:
|
||||
|
||||
```json5
|
||||
{
|
||||
hooks: {
|
||||
enabled: true,
|
||||
token: "shared-secret",
|
||||
path: "/hooks",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
Every request must include the hook token via header:
|
||||
|
||||
- `Authorization: Bearer <token>` (recommended)
|
||||
- `x-openclaw-token: <token>`
|
||||
|
||||
Query-string tokens are rejected.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="POST /hooks/wake">
|
||||
Enqueue a system event for the main session:
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:18789/hooks/wake \
|
||||
-H 'Authorization: Bearer SECRET' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"text":"New email received","mode":"now"}'
|
||||
```
|
||||
|
||||
<ParamField path="text" type="string" required>
|
||||
Event description.
|
||||
</ParamField>
|
||||
<ParamField path="mode" type="string" default="now">
|
||||
`now` or `next-heartbeat`.
|
||||
</ParamField>
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="POST /hooks/agent">
|
||||
Run an isolated agent turn:
|
||||
|
||||
```bash
|
||||
curl -X POST http://127.0.0.1:18789/hooks/agent \
|
||||
-H 'Authorization: Bearer SECRET' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"message":"Summarize inbox","name":"Email","model":"openai/gpt-5.5"}'
|
||||
```
|
||||
|
||||
Fields: `message` (required), `name`, `agentId`, `sessionKey` (requires `hooks.allowRequestSessionKey=true`), `idempotencyKey`, `wakeMode`, `deliver`, `channel`, `to`, `model`, `thinking`, `timeoutSeconds`.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Mapped hooks (POST /hooks/<name>)">
|
||||
Custom hook names resolve via `hooks.mappings` in config. Mappings can transform arbitrary payloads into `wake` or `agent` actions with templates or code transforms.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
<Warning>
|
||||
Keep hook endpoints behind loopback, tailnet, or a trusted reverse proxy.
|
||||
|
||||
- Use a dedicated hook token; do not reuse gateway auth tokens.
|
||||
- Keep `hooks.path` on a dedicated subpath; `/` is rejected.
|
||||
- Set `hooks.allowedAgentIds` to limit which effective agent a hook can target, including the default agent when `agentId` is omitted.
|
||||
- Keep `hooks.allowRequestSessionKey=false` unless you require caller-selected sessions.
|
||||
- If you enable `hooks.allowRequestSessionKey`, also set `hooks.allowedSessionKeyPrefixes` to constrain allowed session key shapes.
|
||||
- Hook payloads are wrapped with safety boundaries by default.
|
||||
|
||||
</Warning>
|
||||
|
||||
## Gmail PubSub integration
|
||||
|
||||
Wire Gmail inbox triggers to OpenClaw via Google PubSub.
|
||||
|
||||
<Note>
|
||||
**Prerequisites:** `gcloud` CLI, `gog` (gogcli), OpenClaw hooks enabled, Tailscale for the public HTTPS endpoint.
|
||||
</Note>
|
||||
|
||||
### Wizard setup (recommended)
|
||||
|
||||
```bash
|
||||
openclaw webhooks gmail setup --account openclaw@gmail.com
|
||||
```
|
||||
|
||||
This writes `hooks.gmail` config, enables the Gmail preset, and defaults to Tailscale Funnel for the push endpoint (`--tailscale funnel|serve|off`).
|
||||
|
||||
### Gateway auto-start
|
||||
|
||||
When `hooks.enabled=true` and `hooks.gmail.account` is set, the Gateway starts `gog gmail watch serve` on boot and auto-renews the watch. Set `OPENCLAW_SKIP_GMAIL_WATCHER=1` to opt out.
|
||||
|
||||
### Manual one-time setup
|
||||
|
||||
<Steps>
|
||||
<Step title="Select the GCP project">
|
||||
Select the GCP project that owns the OAuth client used by `gog`:
|
||||
|
||||
```bash
|
||||
gcloud auth login
|
||||
gcloud config set project <project-id>
|
||||
gcloud services enable gmail.googleapis.com pubsub.googleapis.com
|
||||
```
|
||||
|
||||
</Step>
|
||||
<Step title="Create topic and grant Gmail push access">
|
||||
```bash
|
||||
gcloud pubsub topics create gog-gmail-watch
|
||||
gcloud pubsub topics add-iam-policy-binding gog-gmail-watch \
|
||||
--member=serviceAccount:gmail-api-push@system.gserviceaccount.com \
|
||||
--role=roles/pubsub.publisher
|
||||
```
|
||||
</Step>
|
||||
<Step title="Start the watch">
|
||||
```bash
|
||||
gog gmail watch start \
|
||||
--account openclaw@gmail.com \
|
||||
--label INBOX \
|
||||
--topic projects/<project-id>/topics/gog-gmail-watch
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### Gmail model override
|
||||
|
||||
```json5
|
||||
{
|
||||
hooks: {
|
||||
gmail: {
|
||||
model: "openrouter/meta-llama/llama-3.3-70b-instruct:free",
|
||||
thinking: "off",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
```json5
|
||||
{
|
||||
cron: {
|
||||
enabled: true,
|
||||
store: "~/.openclaw/cron/jobs.json",
|
||||
maxConcurrentRuns: 8,
|
||||
retry: {
|
||||
maxAttempts: 3,
|
||||
backoffMs: [30000, 60000, 300000],
|
||||
retryOn: ["rate_limit", "overloaded", "network", "timeout", "server_error"],
|
||||
},
|
||||
webhookToken: "replace-with-dedicated-webhook-token",
|
||||
sessionRetention: "24h",
|
||||
runLog: { maxBytes: "2mb", keepLines: 2000 },
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The `retry` values above are the defaults: up to 3 retries with `30s/60s/5m` backoff, retrying all five transient categories. `webhookToken` is sent as `Authorization: Bearer <token>` on cron webhook POSTs.
|
||||
|
||||
`maxConcurrentRuns` limits both scheduled cron dispatch and isolated agent-turn execution, and defaults to 8. Isolated cron agent turns use the queue's dedicated `cron-nested` execution lane internally, so raising this value lets independent cron LLM runs progress in parallel instead of only starting their outer cron wrappers. The shared non-cron `nested` lane is not widened by this setting.
|
||||
|
||||
`cron.store` is a logical store key and doctor migration path, not a live JSON file to hand-edit. Job data lives in SQLite; use the CLI or Gateway API for changes.
|
||||
|
||||
Disable cron: `cron.enabled: false` or `OPENCLAW_SKIP_CRON=1`.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Retry behavior">
|
||||
**One-shot retry**: transient errors (rate limit, overload, network, timeout, server error) retry up to `retry.maxAttempts` times (default 3) using `retry.backoffMs` (default 30s, 60s, 5m). Permanent errors disable the job immediately.
|
||||
|
||||
**Recurring retry**: consecutive execution errors back off on an extended schedule (30s, 60s, 5m, 15m, 60m). Backoff resets after the next successful run.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Maintenance">
|
||||
`cron.sessionRetention` (default `24h`, `false` disables) prunes isolated run-session entries. `cron.runLog.keepLines` limits retained SQLite run-history rows per job; `maxBytes` is retained for config compatibility with older file-backed run logs.
|
||||
</Accordion>
|
||||
<Accordion title="Legacy store migration">
|
||||
On upgrade, run `openclaw doctor --fix` to import legacy `~/.openclaw/cron/jobs.json`, `jobs-state.json`, and `runs/*.jsonl` files into SQLite and rename them with a `.migrated` suffix. Malformed job rows are skipped from runtime and copied to `jobs-quarantine.json` for later repair or review.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Command ladder
|
||||
|
||||
```bash
|
||||
openclaw status
|
||||
openclaw gateway status
|
||||
openclaw cron status
|
||||
openclaw cron list
|
||||
openclaw cron runs --id <jobId> --limit 20
|
||||
openclaw system heartbeat last
|
||||
openclaw logs --follow
|
||||
openclaw doctor
|
||||
```
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Cron not firing">
|
||||
- Check `cron.enabled` and the `OPENCLAW_SKIP_CRON` env var.
|
||||
- Confirm the Gateway is running continuously.
|
||||
- For `cron` schedules, verify timezone (`--tz`) vs the host timezone.
|
||||
- `reason: not-due` in run output means the manual run was checked with `openclaw cron run <jobId> --due` and the job was not due yet.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Cron fired but no delivery">
|
||||
- Delivery mode `none` means no runner fallback send is expected. The agent can still send directly with the `message` tool when a chat route is available.
|
||||
- Delivery target missing/invalid (`channel`/`to`) means outbound was skipped.
|
||||
- For Matrix, copied or legacy jobs with lowercased `delivery.to` room IDs can fail because Matrix room IDs are case-sensitive. Edit the job to the exact `!room:server` or `room:!room:server` value from Matrix.
|
||||
- Channel auth errors (`unauthorized`, `Forbidden`) mean delivery was blocked by credentials.
|
||||
- If the isolated run returns only the silent token (`NO_REPLY` / `no_reply`), OpenClaw suppresses direct outbound delivery and the fallback queued-summary path, so nothing is posted back to chat.
|
||||
- If the agent should message the user itself, check that the job has a usable route (`channel: "last"` with a previous chat, or an explicit channel/target).
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Cron or heartbeat appears to prevent /new-style rollover">
|
||||
- Daily and idle reset freshness is not based on `updatedAt`; see [Session management](/concepts/session#session-lifecycle).
|
||||
- Cron wakeups, heartbeat runs, exec notifications, and gateway bookkeeping may update the session row for routing/status, but they do not extend `sessionStartedAt` or `lastInteractionAt`.
|
||||
- For legacy rows created before those fields existed, OpenClaw can recover `sessionStartedAt` from the transcript JSONL session header when the file is still available. Legacy idle rows without `lastInteractionAt` use that recovered start time as their idle baseline.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Timezone gotchas">
|
||||
- Cron without `--tz` uses the gateway host timezone.
|
||||
- `at` schedules without timezone are treated as UTC.
|
||||
- Heartbeat `activeHours` uses configured timezone resolution.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Related
|
||||
|
||||
- [Automation](/automation) — all automation mechanisms at a glance
|
||||
- [Background Tasks](/automation/tasks) — task ledger for cron executions
|
||||
- [Heartbeat](/gateway/heartbeat) — periodic main-session turns
|
||||
- [Timezone](/concepts/timezone) — timezone configuration
|
||||
12
docs/automation/cron-vs-heartbeat.md
Normal file
12
docs/automation/cron-vs-heartbeat.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
summary: "Redirect to /automation"
|
||||
title: "Cron vs heartbeat"
|
||||
---
|
||||
|
||||
This page moved. See [Scheduled Tasks (Cron) vs Heartbeat](/automation#scheduled-tasks-cron-vs-heartbeat) for the decision table.
|
||||
|
||||
## Related
|
||||
|
||||
- [Scheduled tasks](/automation/cron-jobs)
|
||||
- [Heartbeat](/gateway/heartbeat)
|
||||
- [Background tasks](/automation/tasks)
|
||||
11
docs/automation/gmail-pubsub.md
Normal file
11
docs/automation/gmail-pubsub.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
summary: "Redirect to /automation/cron-jobs"
|
||||
title: "Gmail PubSub"
|
||||
---
|
||||
|
||||
This page moved to [Gmail PubSub integration](/automation/cron-jobs#gmail-pubsub-integration) on the Scheduled Tasks page.
|
||||
|
||||
## Related
|
||||
|
||||
- [Webhooks](/automation/cron-jobs#webhooks)
|
||||
- [Troubleshooting](/automation/cron-jobs#troubleshooting)
|
||||
395
docs/automation/hooks.md
Normal file
395
docs/automation/hooks.md
Normal file
@@ -0,0 +1,395 @@
|
||||
---
|
||||
summary: "Hooks: event-driven automation for commands and lifecycle events"
|
||||
read_when:
|
||||
- You want event-driven automation for /new, /reset, /stop, and agent lifecycle events
|
||||
- You want to build, install, or debug hooks
|
||||
title: "Hooks"
|
||||
---
|
||||
|
||||
Hooks are small scripts that run inside the Gateway when agent events fire: commands like `/new`, `/reset`, `/stop`, session compaction, gateway lifecycle, and message flow. They are discovered from directories and managed with `openclaw hooks`. The Gateway loads internal hooks only after you enable hooks or configure at least one hook entry, hook pack, legacy handler, or extra hook directory.
|
||||
|
||||
There are two kinds of hooks in OpenClaw:
|
||||
|
||||
- **Internal hooks** (this page): run inside the Gateway when agent events fire.
|
||||
- **Webhooks**: external HTTP endpoints that let other systems trigger work in OpenClaw. See [Webhooks](/automation/cron-jobs#webhooks).
|
||||
|
||||
Hooks can also be bundled inside plugins. `openclaw hooks list` shows both standalone hooks and plugin-managed hooks (displayed as `plugin:<id>`).
|
||||
|
||||
## Choose the right surface
|
||||
|
||||
OpenClaw has several extension surfaces that look similar but solve different problems:
|
||||
|
||||
| If you want to... | Use... | Why |
|
||||
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| Save a snapshot on `/new`, log `/reset`, call an external API after `message:sent`, or add coarse operator automation | Internal hooks (`HOOK.md`, this page) | File-based hooks are meant for operator-managed side effects and command/lifecycle automation |
|
||||
| Rewrite prompts, block tools, cancel outbound messages, or add ordered middleware/policy | Typed plugin hooks via `api.on(...)` | Typed hooks have explicit contracts, priorities, merge rules, and block/cancel semantics |
|
||||
| Add telemetry-only export or observability | Diagnostic events | Observability is a separate event bus, not a policy hook surface |
|
||||
|
||||
Use internal hooks when you want automation that behaves like a small installed integration. Use typed plugin hooks when you need runtime lifecycle control.
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
# List available hooks
|
||||
openclaw hooks list
|
||||
|
||||
# Enable a hook
|
||||
openclaw hooks enable session-memory
|
||||
|
||||
# Check hook status
|
||||
openclaw hooks check
|
||||
|
||||
# Get detailed information
|
||||
openclaw hooks info session-memory
|
||||
```
|
||||
|
||||
## Event types
|
||||
|
||||
| Event | When it fires |
|
||||
| ------------------------ | ---------------------------------------------------------- |
|
||||
| `command:new` | `/new` command issued |
|
||||
| `command:reset` | `/reset` command issued |
|
||||
| `command:stop` | `/stop` command issued |
|
||||
| `command` | Any command event (general listener) |
|
||||
| `session:compact:before` | Before compaction summarizes history |
|
||||
| `session:compact:after` | After compaction completes |
|
||||
| `session:patch` | When session properties are modified |
|
||||
| `agent:bootstrap` | Before workspace bootstrap files are injected |
|
||||
| `gateway:startup` | After channels start and hooks are loaded |
|
||||
| `gateway:shutdown` | When gateway shutdown begins |
|
||||
| `gateway:pre-restart` | Before an expected gateway restart |
|
||||
| `message:received` | Inbound message from any channel |
|
||||
| `message:transcribed` | After audio transcription completes |
|
||||
| `message:preprocessed` | After media and link preprocessing completes or is skipped |
|
||||
| `message:sent` | Outbound send attempted (`context.success` has the result) |
|
||||
|
||||
## Writing hooks
|
||||
|
||||
### Hook structure
|
||||
|
||||
Each hook is a directory containing two files:
|
||||
|
||||
```text
|
||||
my-hook/
|
||||
├── HOOK.md # Metadata + documentation
|
||||
└── handler.ts # Handler implementation
|
||||
```
|
||||
|
||||
The handler file can be `handler.ts`, `handler.js`, `index.ts`, or `index.js`.
|
||||
|
||||
### HOOK.md format
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-hook
|
||||
description: "Short description of what this hook does"
|
||||
metadata:
|
||||
{ "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } }
|
||||
---
|
||||
|
||||
# My Hook
|
||||
|
||||
Detailed documentation goes here.
|
||||
```
|
||||
|
||||
**Metadata fields** (`metadata.openclaw`):
|
||||
|
||||
| Field | Description |
|
||||
| ---------- | ---------------------------------------------------- |
|
||||
| `emoji` | Display emoji for CLI |
|
||||
| `events` | Array of events to listen for |
|
||||
| `export` | Named export to use (defaults to `"default"`) |
|
||||
| `os` | Required platforms (e.g., `["darwin", "linux"]`) |
|
||||
| `requires` | Required `bins`, `anyBins`, `env`, or `config` paths |
|
||||
| `always` | Bypass eligibility checks (boolean) |
|
||||
| `hookKey` | Config key override (defaults to the hook name) |
|
||||
| `homepage` | Docs URL shown by `openclaw hooks info` |
|
||||
| `install` | Installation methods |
|
||||
|
||||
### Handler implementation
|
||||
|
||||
```typescript
|
||||
const handler = async (event) => {
|
||||
if (event.type !== "command" || event.action !== "new") {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`[my-hook] New command triggered`);
|
||||
// Your logic here
|
||||
|
||||
// Optionally send a reply on replyable surfaces
|
||||
event.messages.push("Hook executed!");
|
||||
};
|
||||
|
||||
export default handler;
|
||||
```
|
||||
|
||||
Each event includes: `type`, `action`, `sessionKey`, `timestamp`, `messages`, and `context` (event-specific data). Typed plugin hook contexts for agent and tool hooks can also include `trace`, a read-only W3C-compatible diagnostic trace context that plugins may pass into structured logs for OTEL correlation.
|
||||
|
||||
Strings pushed to `event.messages` are delivered back to the chat only for
|
||||
`command:new` and `command:reset` (routed as a reply to the originating
|
||||
conversation) and for `session:compact:before` / `session:compact:after`
|
||||
(sent as compaction status notices). All other events, including
|
||||
`command:stop`, `message:*`, `agent:bootstrap`, `session:patch`, and
|
||||
`gateway:*`, ignore pushed messages.
|
||||
|
||||
### Event context highlights
|
||||
|
||||
**Command events** (`command:new`, `command:reset`): `context.sessionEntry`, `context.previousSessionEntry`, `context.commandSource`, `context.senderId`, `context.workspaceDir`, `context.cfg`.
|
||||
|
||||
**Command events** (`command:stop`): `context.sessionEntry`, `context.sessionId`, `context.commandSource`, `context.senderId`.
|
||||
|
||||
**Message events** (`message:received`): `context.from`, `context.content`, `context.channelId`, `context.metadata` (provider-specific data including `senderId`, `senderName`, `guildId`). `context.content` prefers a nonblank command body for command-like messages, then falls back to the raw inbound body and generic body; it does not include agent-only enrichment such as thread history or link summaries.
|
||||
|
||||
**Message events** (`message:sent`): `context.to`, `context.content`, `context.success`, `context.channelId`, plus `context.error` when sending failed.
|
||||
|
||||
**Message events** (`message:transcribed`): `context.transcript`, `context.from`, `context.channelId`, `context.mediaPath`.
|
||||
|
||||
**Message events** (`message:preprocessed`): `context.bodyForAgent` (final enriched body), `context.from`, `context.channelId`.
|
||||
|
||||
**Bootstrap events** (`agent:bootstrap`): `context.bootstrapFiles` (mutable array), `context.agentId`.
|
||||
|
||||
**Session patch events** (`session:patch`): `context.sessionEntry`, `context.patch` (only changed fields), `context.cfg`. Only privileged clients can trigger patch events; the context is a clone, so handlers cannot mutate the live session entry.
|
||||
|
||||
**Compaction events**: `session:compact:before` includes `messageCount`, `tokenCount`. `session:compact:after` adds `compactedCount`, `summaryLength`, `tokensBefore`, `tokensAfter`.
|
||||
|
||||
`command:stop` observes the user issuing `/stop`; it is cancellation/command
|
||||
lifecycle, not an agent-finalization gate. Plugins that need to inspect a
|
||||
natural final answer and ask the agent for one more pass should use the typed
|
||||
plugin hook `before_agent_finalize` instead. See [Plugin hooks](/plugins/hooks).
|
||||
|
||||
**Gateway lifecycle events**: `gateway:shutdown` includes `reason` and `restartExpectedMs` and fires when gateway shutdown begins. `gateway:pre-restart` includes the same context but only fires when shutdown is part of an expected restart and a finite `restartExpectedMs` value is supplied. During shutdown, each lifecycle hook wait is best-effort and bounded so shutdown continues if a handler stalls. The default wait budget is 5 seconds for `gateway:shutdown` and 10 seconds for `gateway:pre-restart`.
|
||||
|
||||
Use `gateway:pre-restart` for short restart notices while channels are still available:
|
||||
|
||||
```typescript
|
||||
import { execFile } from "node:child_process";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
export default async function handler(event) {
|
||||
if (event.type !== "gateway" || event.action !== "pre-restart") {
|
||||
return;
|
||||
}
|
||||
|
||||
const restartInSeconds = Math.ceil(event.context.restartExpectedMs / 1000);
|
||||
await execFileAsync("openclaw", [
|
||||
"system",
|
||||
"event",
|
||||
"--mode",
|
||||
"now",
|
||||
"--text",
|
||||
`Gateway restarting in ~${restartInSeconds}s (${event.context.reason}). Checkpoint now.`,
|
||||
]);
|
||||
}
|
||||
```
|
||||
|
||||
Between the `gateway:shutdown` (or `gateway:pre-restart`) event and the rest of the shutdown sequence, the gateway also fires a typed `session_end` plugin hook for every session that was still active when the process stopped. The event's `reason` is `shutdown` for a plain SIGTERM/SIGINT stop and `restart` when the close was scheduled as part of an expected restart. This drain is bounded so a slow `session_end` handler cannot block process exit, and sessions that have already been finalized through replace / reset / delete / compaction are skipped to avoid double-firing.
|
||||
|
||||
## Hook discovery
|
||||
|
||||
Hooks are discovered from four sources:
|
||||
|
||||
1. **Bundled hooks**: shipped with OpenClaw
|
||||
2. **Plugin hooks**: bundled inside installed plugins; can override bundled hooks with the same name
|
||||
3. **Managed hooks**: `~/.openclaw/hooks/` (user-installed, shared across workspaces); can override bundled and plugin hooks. Extra directories from `hooks.internal.load.extraDirs` share this precedence.
|
||||
4. **Workspace hooks**: `<workspace>/hooks/` (per-agent, disabled by default until explicitly enabled)
|
||||
|
||||
Workspace hooks can add new hook names but cannot override bundled, managed, or plugin-provided hooks with the same name.
|
||||
|
||||
The Gateway skips internal hook discovery on startup until internal hooks are configured. Enable a bundled or managed hook with `openclaw hooks enable <name>`, install a hook pack, or set `hooks.internal.enabled=true` to opt in. When you enable one named hook, the Gateway loads only that hook's handler; `hooks.internal.enabled=true`, extra hook directories, and legacy handlers opt into broad discovery.
|
||||
|
||||
### Hook packs
|
||||
|
||||
Hook packs are npm packages that export hooks via `openclaw.hooks` in `package.json`. Install with:
|
||||
|
||||
```bash
|
||||
openclaw plugins install <path-or-spec>
|
||||
```
|
||||
|
||||
Npm specs are registry-only (package name + optional exact version or dist-tag). Git/URL/file specs and semver ranges are rejected. The older `openclaw hooks install` and `openclaw hooks update` commands are deprecated aliases for `openclaw plugins install` / `openclaw plugins update`.
|
||||
|
||||
## Bundled hooks
|
||||
|
||||
| Hook | Events | What it does |
|
||||
| --------------------- | ------------------------------------------------- | -------------------------------------------------------------- |
|
||||
| session-memory | `command:new`, `command:reset` | Saves session context to `<workspace>/memory/` |
|
||||
| bootstrap-extra-files | `agent:bootstrap` | Injects additional bootstrap files from glob patterns |
|
||||
| command-logger | `command` | Logs all commands to `~/.openclaw/logs/commands.log` |
|
||||
| compaction-notifier | `session:compact:before`, `session:compact:after` | Sends visible chat notices when session compaction starts/ends |
|
||||
| boot-md | `gateway:startup` | Runs `BOOT.md` when the gateway starts |
|
||||
|
||||
Enable any bundled hook:
|
||||
|
||||
```bash
|
||||
openclaw hooks enable <hook-name>
|
||||
```
|
||||
|
||||
<a id="session-memory"></a>
|
||||
|
||||
### session-memory details
|
||||
|
||||
Extracts the last user/assistant messages (default 15, configurable with `hooks.internal.entries.session-memory.messages`) and saves them to `<workspace>/memory/YYYY-MM-DD-HHMM.md` using the host local date. Memory capture runs in the background so `/new` and `/reset` acknowledgements are not delayed by transcript reads or optional slug generation. Set `hooks.internal.entries.session-memory.llmSlug: true` to generate descriptive filename slugs with the configured model (falls back to timestamp slugs when unavailable). Requires `workspace.dir` to be configured.
|
||||
|
||||
<a id="bootstrap-extra-files"></a>
|
||||
|
||||
### bootstrap-extra-files config
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"entries": {
|
||||
"bootstrap-extra-files": {
|
||||
"enabled": true,
|
||||
"paths": ["packages/*/AGENTS.md", "packages/*/TOOLS.md"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`patterns` and `files` are accepted as aliases of `paths`. Paths resolve relative to the workspace and must stay inside it. Only recognized bootstrap basenames are loaded (`AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, `MEMORY.md`).
|
||||
|
||||
<a id="command-logger"></a>
|
||||
|
||||
### command-logger details
|
||||
|
||||
Logs every slash command as a JSON line (timestamp, action, session key, sender ID, source) to `~/.openclaw/logs/commands.log`.
|
||||
|
||||
<a id="compaction-notifier"></a>
|
||||
|
||||
### compaction-notifier details
|
||||
|
||||
Sends short status messages into the current conversation when OpenClaw starts and finishes compacting the session transcript. This makes long turns less confusing on chat surfaces because the user can see that the assistant is summarizing context and will continue after compaction.
|
||||
|
||||
<a id="boot-md"></a>
|
||||
|
||||
### boot-md details
|
||||
|
||||
Runs `BOOT.md` at gateway startup for each configured agent scope, if the file exists in that agent's resolved workspace.
|
||||
|
||||
## Plugin hooks
|
||||
|
||||
Plugins can register typed hooks through the Plugin SDK for deeper integration:
|
||||
intercepting tool calls, modifying prompts, controlling message flow, and more.
|
||||
Use plugin hooks when you need `before_tool_call`, `before_agent_reply`,
|
||||
`before_install`, or other in-process lifecycle hooks.
|
||||
|
||||
Plugin-managed internal hooks are different: they participate in this page's
|
||||
coarse command/lifecycle event system and show up in `openclaw hooks list` as
|
||||
`plugin:<id>`. Use those for side effects and compatibility with hook packs, not
|
||||
for ordered middleware or policy gates.
|
||||
|
||||
For the complete plugin hook reference, see [Plugin hooks](/plugins/hooks).
|
||||
|
||||
## Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"enabled": true,
|
||||
"entries": {
|
||||
"session-memory": { "enabled": true },
|
||||
"command-logger": { "enabled": false }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Per-hook environment values satisfy a hook's `requires.env` eligibility checks (alongside the process environment), and handlers can read them from their hook config entry:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"entries": {
|
||||
"my-hook": {
|
||||
"enabled": true,
|
||||
"env": { "MY_CUSTOM_VAR": "value" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Extra hook directories:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"internal": {
|
||||
"load": {
|
||||
"extraDirs": ["/path/to/more/hooks"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
The legacy `hooks.internal.handlers` array config format is still supported for backwards compatibility, but new hooks should use the discovery-based system.
|
||||
</Note>
|
||||
|
||||
## CLI reference
|
||||
|
||||
```bash
|
||||
# List all hooks (add --eligible, --verbose, or --json)
|
||||
openclaw hooks list
|
||||
|
||||
# Show detailed info about a hook
|
||||
openclaw hooks info <hook-name>
|
||||
|
||||
# Show eligibility summary
|
||||
openclaw hooks check
|
||||
|
||||
# Enable/disable
|
||||
openclaw hooks enable <hook-name>
|
||||
openclaw hooks disable <hook-name>
|
||||
```
|
||||
|
||||
## Best practices
|
||||
|
||||
- **Keep handlers fast.** Hooks run during command processing. Fire-and-forget heavy work with `void processInBackground(event)`.
|
||||
- **Handle errors gracefully.** Wrap risky operations in try/catch; do not throw so other handlers can run.
|
||||
- **Filter events early.** Return immediately if the event type/action is not relevant.
|
||||
- **Use specific event keys.** Prefer `"events": ["command:new"]` over `"events": ["command"]` to reduce overhead.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook not discovered
|
||||
|
||||
```bash
|
||||
# Verify directory structure
|
||||
ls -la ~/.openclaw/hooks/my-hook/
|
||||
# Should show: HOOK.md, handler.ts
|
||||
|
||||
# List all discovered hooks
|
||||
openclaw hooks list
|
||||
```
|
||||
|
||||
### Hook not eligible
|
||||
|
||||
```bash
|
||||
openclaw hooks info my-hook
|
||||
```
|
||||
|
||||
Check for missing binaries (PATH), environment variables, config values, or OS compatibility.
|
||||
|
||||
### Hook not executing
|
||||
|
||||
1. Verify the hook is enabled: `openclaw hooks list`
|
||||
2. Restart your gateway process so hooks reload.
|
||||
3. Check gateway logs: `openclaw logs --follow | grep -i hook`
|
||||
|
||||
## Related
|
||||
|
||||
- [CLI Reference: hooks](/cli/hooks)
|
||||
- [Webhooks](/automation/cron-jobs#webhooks)
|
||||
- [Plugin hooks](/plugins/hooks) — in-process plugin lifecycle hooks
|
||||
- [Configuration](/gateway/configuration-reference#hooks)
|
||||
135
docs/automation/index.md
Normal file
135
docs/automation/index.md
Normal file
@@ -0,0 +1,135 @@
|
||||
---
|
||||
doc-schema-version: 1
|
||||
summary: "Overview of automation mechanisms: tasks, cron, hooks, standing orders, and Task Flow"
|
||||
read_when:
|
||||
- Deciding how to automate work with OpenClaw
|
||||
- Choosing between heartbeat, cron, commitments, hooks, and standing orders
|
||||
- Looking for the right automation entry point
|
||||
title: "Automation"
|
||||
---
|
||||
|
||||
OpenClaw runs work in the background through tasks, scheduled jobs, inferred
|
||||
commitments, event hooks, and standing instructions. Use this page to pick the
|
||||
right mechanism.
|
||||
|
||||
## Quick decision guide
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
START([What do you need?]) --> Q1{Schedule work?}
|
||||
START --> Q2{Track detached work?}
|
||||
START --> Q3{Orchestrate multi-step flows?}
|
||||
START --> Q4{React to lifecycle events?}
|
||||
START --> Q5{Give the agent persistent instructions?}
|
||||
START --> Q6{Remember a natural follow-up?}
|
||||
|
||||
Q1 -->|Yes| Q1a{Exact timing or flexible?}
|
||||
Q1a -->|Exact| CRON["Scheduled Tasks (Cron)"]
|
||||
Q1a -->|Flexible| HEARTBEAT[Heartbeat]
|
||||
|
||||
Q2 -->|Yes| TASKS[Background Tasks]
|
||||
Q3 -->|Yes| FLOW[Task Flow]
|
||||
Q4 -->|Yes| HOOKS[Hooks]
|
||||
Q5 -->|Yes| SO[Standing Orders]
|
||||
Q6 -->|Yes| COMMITMENTS[Inferred Commitments]
|
||||
```
|
||||
|
||||
| Use case | Recommended | Why |
|
||||
| --------------------------------------- | ---------------------- | ------------------------------------------------ |
|
||||
| Send daily report at 9 AM sharp | Scheduled Tasks (Cron) | Exact timing, isolated execution |
|
||||
| Remind me in 20 minutes | Scheduled Tasks (Cron) | One-shot with precise timing (`--at`) |
|
||||
| Run weekly deep analysis | Scheduled Tasks (Cron) | Standalone task, can use different model |
|
||||
| Check inbox every 30 min | Heartbeat | Batches with other checks, context-aware |
|
||||
| Monitor calendar for upcoming events | Heartbeat | Natural fit for periodic awareness |
|
||||
| Check in after a mentioned interview | Inferred Commitments | Memory-like follow-up, no exact reminder request |
|
||||
| Gentle care check-in after user context | Inferred Commitments | Scoped to the same agent and channel |
|
||||
| Inspect status of a subagent or ACP run | Background Tasks | Tasks ledger tracks all detached work |
|
||||
| Audit what ran and when | Background Tasks | `openclaw tasks list` and `openclaw tasks audit` |
|
||||
| Multi-step research then summarize | Task Flow | Durable orchestration with revision tracking |
|
||||
| Run a script on session reset | Hooks | Event-driven, fires on lifecycle events |
|
||||
| Execute code on every tool call | Plugin hooks | In-process hooks can intercept tool calls |
|
||||
| Always check compliance before replying | Standing Orders | Injected into every session automatically |
|
||||
|
||||
### Scheduled Tasks (Cron) vs Heartbeat
|
||||
|
||||
| Dimension | Scheduled Tasks (Cron) | Heartbeat |
|
||||
| --------------- | ----------------------------------- | ------------------------------------- |
|
||||
| Timing | Exact (cron expressions, one-shot) | Approximate (default every 30 min) |
|
||||
| Session context | Fresh (isolated) or shared | Full main-session context |
|
||||
| Task records | Always created | Never created |
|
||||
| Delivery | Channel, webhook, or silent | Inline in main session |
|
||||
| Best for | Reports, reminders, background jobs | Inbox checks, calendar, notifications |
|
||||
|
||||
Use Scheduled Tasks (Cron) when you need precise timing or isolated execution. Use Heartbeat when the work benefits from full session context and approximate timing is fine.
|
||||
|
||||
## Core concepts
|
||||
|
||||
### Scheduled tasks (cron)
|
||||
|
||||
Cron is the Gateway's built-in scheduler for precise timing. It persists jobs, wakes the agent at the right time, and can deliver output to a chat channel or webhook endpoint. Supports one-shot reminders, recurring expressions, and inbound webhook triggers.
|
||||
|
||||
See [Scheduled Tasks](/automation/cron-jobs).
|
||||
|
||||
### Tasks
|
||||
|
||||
The background task ledger tracks all detached work: ACP runs, subagent spawns, isolated cron executions, and CLI operations. Tasks are records, not schedulers. Use `openclaw tasks list` and `openclaw tasks audit` to inspect them.
|
||||
|
||||
See [Background Tasks](/automation/tasks).
|
||||
|
||||
### Inferred commitments
|
||||
|
||||
Commitments are opt-in, short-lived follow-up memories. OpenClaw infers them
|
||||
from normal conversations, scopes them to the same agent and channel, and
|
||||
delivers due check-ins through heartbeat. Exact user-requested reminders still
|
||||
belong to cron.
|
||||
|
||||
See [Inferred Commitments](/concepts/commitments).
|
||||
|
||||
### Task Flow
|
||||
|
||||
Task Flow is the flow orchestration substrate above background tasks. It manages durable multi-step flows with managed and mirrored sync modes, revision tracking, and `openclaw tasks flow list|show|cancel` for inspection.
|
||||
|
||||
See [Task Flow](/automation/taskflow).
|
||||
|
||||
### Standing orders
|
||||
|
||||
Standing orders grant the agent permanent operating authority for defined programs. They live in workspace files (typically `AGENTS.md`) and are injected into every session. Combine with cron for time-based enforcement.
|
||||
|
||||
See [Standing Orders](/automation/standing-orders).
|
||||
|
||||
### Hooks
|
||||
|
||||
Internal hooks are event-driven scripts triggered by agent lifecycle events
|
||||
(`/new`, `/reset`, `/stop`), session compaction, gateway startup, and message
|
||||
flow. They are discovered from hook directories and managed with
|
||||
`openclaw hooks`. For in-process tool-call interception, use
|
||||
[Plugin hooks](/plugins/hooks).
|
||||
|
||||
See [Hooks](/automation/hooks).
|
||||
|
||||
### Heartbeat
|
||||
|
||||
Heartbeat is a periodic main-session turn (default every 30 minutes). It batches multiple checks (inbox, calendar, notifications) in one agent turn with full session context. Heartbeat turns do not create task records and do not extend daily/idle session reset freshness. Use `HEARTBEAT.md` for a small checklist, or a `tasks:` block when you want due-only periodic checks inside heartbeat itself. Empty heartbeat files skip as `empty-heartbeat-file`; due-only task mode skips as `no-tasks-due`. Heartbeats defer while cron work is active or queued, and `heartbeat.skipWhenBusy` can also defer an agent while that same agent's session-keyed subagent or nested lanes are busy.
|
||||
|
||||
See [Heartbeat](/gateway/heartbeat).
|
||||
|
||||
## How they work together
|
||||
|
||||
- **Cron** handles precise schedules (daily reports, weekly reviews) and one-shot reminders. All cron executions create task records.
|
||||
- **Heartbeat** handles routine monitoring (inbox, calendar, notifications) in one batched turn every 30 minutes.
|
||||
- **Hooks** react to specific events (session resets, compaction, message flow) with custom scripts. Plugin hooks cover tool calls.
|
||||
- **Standing orders** give the agent persistent context and authority boundaries.
|
||||
- **Task Flow** coordinates multi-step flows above individual tasks.
|
||||
- **Tasks** automatically track all detached work so you can inspect and audit it.
|
||||
|
||||
## Related
|
||||
|
||||
- [Scheduled Tasks](/automation/cron-jobs) — precise scheduling and one-shot reminders
|
||||
- [Inferred Commitments](/concepts/commitments) — memory-like follow-up check-ins
|
||||
- [Background Tasks](/automation/tasks) — task ledger for all detached work
|
||||
- [Task Flow](/automation/taskflow) — durable multi-step flow orchestration
|
||||
- [Hooks](/automation/hooks) — event-driven lifecycle scripts
|
||||
- [Plugin hooks](/plugins/hooks) — in-process tool, prompt, message, and lifecycle hooks
|
||||
- [Standing Orders](/automation/standing-orders) — persistent agent instructions
|
||||
- [Heartbeat](/gateway/heartbeat) — periodic main-session turns
|
||||
- [Configuration Reference](/gateway/configuration-reference) — all config keys
|
||||
12
docs/automation/poll.md
Normal file
12
docs/automation/poll.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
summary: "Redirect to /cli/message"
|
||||
title: "Polls"
|
||||
---
|
||||
|
||||
This page moved. Poll documentation, including `openclaw message poll` flags and per-channel limits, lives in [Message tool](/cli/message).
|
||||
|
||||
## Related
|
||||
|
||||
- [Webhooks](/automation/cron-jobs#webhooks)
|
||||
- [Scheduled tasks](/automation/cron-jobs)
|
||||
- [Background tasks](/automation/tasks)
|
||||
238
docs/automation/standing-orders.md
Normal file
238
docs/automation/standing-orders.md
Normal file
@@ -0,0 +1,238 @@
|
||||
---
|
||||
summary: "Define permanent operating authority for autonomous agent programs"
|
||||
read_when:
|
||||
- Setting up autonomous agent workflows that run without per-task prompting
|
||||
- Defining what the agent can do independently vs. what needs human approval
|
||||
- Structuring multi-program agents with clear boundaries and escalation rules
|
||||
title: "Standing orders"
|
||||
---
|
||||
|
||||
Standing orders grant your agent **permanent operating authority** for defined programs. Instead of prompting the agent for each task, you define programs with clear scope, triggers, and escalation rules, and the agent executes autonomously within those boundaries: "You own the weekly report. Compile it every Friday, send it, and only escalate if something looks wrong."
|
||||
|
||||
## Why standing orders
|
||||
|
||||
**Without standing orders:** you prompt the agent for every task, routine work gets forgotten or delayed, and you become the bottleneck.
|
||||
|
||||
**With standing orders:** the agent executes autonomously within defined boundaries, routine work happens on schedule, and you only get involved for exceptions and approvals.
|
||||
|
||||
## How they work
|
||||
|
||||
Standing orders are defined in your [agent workspace](/concepts/agent-workspace) files. The recommended approach is to include them directly in `AGENTS.md` (which is auto-injected every session) so the agent always has them in context. For larger configurations, you can also place them in a dedicated file like `standing-orders.md` and reference it from `AGENTS.md`.
|
||||
|
||||
Each program specifies:
|
||||
|
||||
1. **Scope** - what the agent is authorized to do
|
||||
2. **Triggers** - when to execute (schedule, event, or condition)
|
||||
3. **Approval gates** - what requires human sign-off before acting
|
||||
4. **Escalation rules** - when to stop and ask for help
|
||||
|
||||
The agent loads these instructions every session via the workspace bootstrap files (see [Agent Workspace](/concepts/agent-workspace) for the full list of auto-injected files) and executes against them, combined with [cron jobs](/automation/cron-jobs) for time-based enforcement.
|
||||
|
||||
<Tip>
|
||||
Put standing orders in `AGENTS.md` to guarantee they're loaded every session. The workspace bootstrap automatically injects `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, and `MEMORY.md` - but not arbitrary files in subdirectories.
|
||||
</Tip>
|
||||
|
||||
## Anatomy of a standing order
|
||||
|
||||
```markdown
|
||||
## Program: Weekly Status Report
|
||||
|
||||
**Authority:** Compile data, generate report, deliver to stakeholders
|
||||
**Trigger:** Every Friday at 4 PM (enforced via cron job)
|
||||
**Approval gate:** None for standard reports. Flag anomalies for human review.
|
||||
**Escalation:** If data source is unavailable or metrics look unusual (>2σ from norm)
|
||||
|
||||
### Execution steps
|
||||
|
||||
1. Pull metrics from configured sources
|
||||
2. Compare to prior week and targets
|
||||
3. Generate report in Reports/weekly/YYYY-MM-DD.md
|
||||
4. Deliver summary via configured channel
|
||||
5. Log completion to Agent/Logs/
|
||||
|
||||
### What NOT to do
|
||||
|
||||
- Do not send reports to external parties
|
||||
- Do not modify source data
|
||||
- Do not skip delivery if metrics look bad - report accurately
|
||||
```
|
||||
|
||||
## Standing orders plus cron jobs
|
||||
|
||||
Standing orders define **what** the agent is authorized to do. [Cron jobs](/automation/cron-jobs) define **when** it happens. They work together:
|
||||
|
||||
```text
|
||||
Standing Order: "You own the daily inbox triage"
|
||||
↓
|
||||
Cron Job (8 AM daily): "Execute inbox triage per standing orders"
|
||||
↓
|
||||
Agent: Reads standing orders → executes steps → reports results
|
||||
```
|
||||
|
||||
The cron job prompt should reference the standing order rather than duplicating it:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name daily-inbox-triage \
|
||||
--cron "0 8 * * 1-5" \
|
||||
--tz America/New_York \
|
||||
--timeout-seconds 300 \
|
||||
--announce \
|
||||
--channel imessage \
|
||||
--to "+1XXXXXXXXXX" \
|
||||
--message "Execute daily inbox triage per standing orders. Check mail for new alerts. Parse, categorize, and persist each item. Report summary to owner. Escalate unknowns."
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: content and social media (weekly cycle)
|
||||
|
||||
```markdown
|
||||
## Program: Content & Social Media
|
||||
|
||||
**Authority:** Draft content, schedule posts, compile engagement reports
|
||||
**Approval gate:** All posts require owner review for first 30 days, then standing approval
|
||||
**Trigger:** Weekly cycle (Monday review → mid-week drafts → Friday brief)
|
||||
|
||||
### Weekly cycle
|
||||
|
||||
- **Monday:** Review platform metrics and audience engagement
|
||||
- **Tuesday-Thursday:** Draft social posts, create blog content
|
||||
- **Friday:** Compile weekly marketing brief → deliver to owner
|
||||
|
||||
### Content rules
|
||||
|
||||
- Voice must match the brand (see SOUL.md or brand voice guide)
|
||||
- Never identify as AI in public-facing content
|
||||
- Include metrics when available
|
||||
- Focus on value to audience, not self-promotion
|
||||
```
|
||||
|
||||
### Example 2: finance operations (event-triggered)
|
||||
|
||||
```markdown
|
||||
## Program: Financial Processing
|
||||
|
||||
**Authority:** Process transaction data, generate reports, send summaries
|
||||
**Approval gate:** None for analysis. Recommendations require owner approval.
|
||||
**Trigger:** New data file detected OR scheduled monthly cycle
|
||||
|
||||
### When new data arrives
|
||||
|
||||
1. Detect new file in designated input directory
|
||||
2. Parse and categorize all transactions
|
||||
3. Compare against budget targets
|
||||
4. Flag: unusual items, threshold breaches, new recurring charges
|
||||
5. Generate report in designated output directory
|
||||
6. Deliver summary to owner via configured channel
|
||||
|
||||
### Escalation rules
|
||||
|
||||
- Single item > $500: immediate alert
|
||||
- Category > budget by 20%: flag in report
|
||||
- Unrecognizable transaction: ask owner for categorization
|
||||
- Failed processing after 2 retries: report failure, do not guess
|
||||
```
|
||||
|
||||
### Example 3: monitoring and alerts (continuous)
|
||||
|
||||
```markdown
|
||||
## Program: System Monitoring
|
||||
|
||||
**Authority:** Check system health, restart services, send alerts
|
||||
**Approval gate:** Restart services automatically. Escalate if restart fails twice.
|
||||
**Trigger:** Every heartbeat cycle
|
||||
|
||||
### Checks
|
||||
|
||||
- Service health endpoints responding
|
||||
- Disk space above threshold
|
||||
- Pending tasks not stale (>24 hours)
|
||||
- Delivery channels operational
|
||||
|
||||
### Response matrix
|
||||
|
||||
| Condition | Action | Escalate? |
|
||||
| ---------------- | ------------------------ | ------------------------ |
|
||||
| Service down | Restart automatically | Only if restart fails 2x |
|
||||
| Disk space < 10% | Alert owner | Yes |
|
||||
| Stale task > 24h | Remind owner | No |
|
||||
| Channel offline | Log and retry next cycle | If offline > 2 hours |
|
||||
```
|
||||
|
||||
## Execute-verify-report pattern
|
||||
|
||||
Standing orders work best when combined with strict execution discipline. Every task in a standing order should follow this loop:
|
||||
|
||||
1. **Execute** - Do the actual work (don't just acknowledge the instruction)
|
||||
2. **Verify** - Confirm the result is correct (file exists, message delivered, data parsed)
|
||||
3. **Report** - Tell the owner what was done and what was verified
|
||||
|
||||
```markdown
|
||||
### Execution rules
|
||||
|
||||
- Every task follows Execute-Verify-Report. No exceptions.
|
||||
- "I'll do that" is not execution. Do it, then report.
|
||||
- "Done" without verification is not acceptable. Prove it.
|
||||
- If execution fails: retry once with adjusted approach.
|
||||
- If still fails: report failure with diagnosis. Never silently fail.
|
||||
- Never retry indefinitely - 3 attempts max, then escalate.
|
||||
```
|
||||
|
||||
This pattern prevents the most common agent failure mode: acknowledging a task without completing it.
|
||||
|
||||
## Multi-program architecture
|
||||
|
||||
For agents managing multiple concerns, organize standing orders as separate programs with clear boundaries:
|
||||
|
||||
```markdown
|
||||
## Program 1: [Domain A] (Weekly)
|
||||
|
||||
...
|
||||
|
||||
## Program 2: [Domain B] (Monthly + On-Demand)
|
||||
|
||||
...
|
||||
|
||||
## Program 3: [Domain C] (As-Needed)
|
||||
|
||||
...
|
||||
|
||||
## Escalation Rules (All Programs)
|
||||
|
||||
- [Common escalation criteria]
|
||||
- [Approval gates that apply across programs]
|
||||
```
|
||||
|
||||
Each program should have:
|
||||
|
||||
- Its own **trigger cadence** (weekly, monthly, event-driven, continuous)
|
||||
- Its own **approval gates** (some programs need more oversight than others)
|
||||
- Clear **boundaries** (the agent should know where one program ends and another begins)
|
||||
|
||||
## Best practices
|
||||
|
||||
### Do
|
||||
|
||||
- Start with narrow authority and expand as trust builds
|
||||
- Define explicit approval gates for high-risk actions
|
||||
- Include "What NOT to do" sections - boundaries matter as much as permissions
|
||||
- Combine with cron jobs for reliable time-based execution
|
||||
- Review agent logs weekly to verify standing orders are being followed
|
||||
- Update standing orders as your needs evolve - they're living documents
|
||||
|
||||
### Avoid
|
||||
|
||||
- Grant broad authority on day one ("do whatever you think is best")
|
||||
- Skip escalation rules - every program needs a "when to stop and ask" clause
|
||||
- Assume the agent will remember verbal instructions - put everything in the file
|
||||
- Mix concerns in a single program - separate programs for separate domains
|
||||
- Forget to enforce with cron jobs - standing orders without triggers become suggestions
|
||||
|
||||
## Related
|
||||
|
||||
- [Automation](/automation): all automation mechanisms at a glance.
|
||||
- [Cron jobs](/automation/cron-jobs): schedule enforcement for standing orders.
|
||||
- [Hooks](/automation/hooks): event-driven scripts for agent lifecycle events.
|
||||
- [Webhooks](/automation/cron-jobs#webhooks): inbound HTTP event triggers.
|
||||
- [Agent workspace](/concepts/agent-workspace): where standing orders live, including the full list of auto-injected bootstrap files (`AGENTS.md`, `SOUL.md`, etc.).
|
||||
168
docs/automation/taskflow.md
Normal file
168
docs/automation/taskflow.md
Normal file
@@ -0,0 +1,168 @@
|
||||
---
|
||||
summary: "Task Flow orchestration layer above background tasks"
|
||||
read_when:
|
||||
- You want to understand how Task Flow relates to background tasks
|
||||
- You encounter Task Flow or openclaw tasks flow in release notes or docs
|
||||
- You want to inspect or manage durable flow state
|
||||
title: "Task flow"
|
||||
---
|
||||
|
||||
Task Flow is the orchestration layer above [background tasks](/automation/tasks). A flow is a durable record of multi-step work with its own status, JSON state, revision counter, and linked task records. Flows survive gateway restarts; individual tasks remain the unit of detached work.
|
||||
|
||||
## When to use Task Flow
|
||||
|
||||
| Scenario | Use |
|
||||
| ----------------------------------------- | ------------------------------------------- |
|
||||
| Single background job | Plain task |
|
||||
| Multi-step pipeline driven by plugin code | Task Flow (managed) |
|
||||
| Detached ACP or subagent spawn | Task Flow (mirrored, created automatically) |
|
||||
| One-shot reminder | Cron job |
|
||||
|
||||
## Sync modes
|
||||
|
||||
### Managed mode
|
||||
|
||||
A managed flow has a controller: plugin code that creates the flow through the plugin runtime Task Flow API with a goal and a required controller id, then drives it explicitly.
|
||||
|
||||
- Each step runs as a background task created under the flow; the flow's owner key and requester origin carry over to child tasks.
|
||||
- The controller advances the flow between `running`, `waiting`, and terminal states, and stores arbitrary JSON step state on the flow record.
|
||||
- Every mutation passes the flow's expected revision. A stale write is rejected as a revision conflict instead of clobbering newer state.
|
||||
- Once cancellation is requested, new child tasks are refused, and the flow finalizes as `cancelled` when no child task remains active.
|
||||
|
||||
Example: a weekly report flow that (1) gathers data, (2) generates the report, and (3) delivers it, one background task per step:
|
||||
|
||||
```
|
||||
Flow: weekly-report
|
||||
Step 1: gather-data → task created → succeeded
|
||||
Step 2: generate-report → task created → succeeded
|
||||
Step 3: deliver → task created → running
|
||||
```
|
||||
|
||||
### Mirrored mode
|
||||
|
||||
OpenClaw creates a mirrored one-task flow automatically when a detached ACP or subagent run starts (session-scoped tasks with deliverable completion). The flow record mirrors its single backing task - status, goal, and timing - so detached spawns get a stable flow handle for status and retry surfaces without a controller. Mirrored flows show sync mode `task_mirrored` in the CLI.
|
||||
|
||||
## Flow statuses
|
||||
|
||||
| Status | Meaning |
|
||||
| ----------- | -------------------------------------------------------------------------- |
|
||||
| `queued` | Created, not yet progressing |
|
||||
| `running` | Flow is actively progressing |
|
||||
| `waiting` | Managed flow is parked on wait metadata (timer, external event) |
|
||||
| `blocked` | A step finished without a usable result; `blockedTaskId`/summary say which |
|
||||
| `succeeded` | Completed successfully |
|
||||
| `failed` | Completed with an error |
|
||||
| `cancelled` | Cancel requested and all child tasks settled |
|
||||
| `lost` | Flow lost its authoritative backing state |
|
||||
|
||||
## Durable state and revision tracking
|
||||
|
||||
Flow records persist in the shared SQLite state database (`~/.openclaw/state/openclaw.sqlite`, `flow_runs` table) alongside task records, so progress survives gateway restarts. Each write bumps the flow's `revision`; concurrent writers that pass a stale expected revision get a conflict and must re-read. WAL growth is bounded by SQLite autocheckpointing plus periodic passive checkpoints, with truncate checkpoints on shutdown. The legacy `flows/registry.sqlite` sidecar from older installs is imported by `openclaw doctor`.
|
||||
|
||||
## Cancel behavior
|
||||
|
||||
`openclaw tasks flow cancel` sets a sticky cancel intent on the flow, cancels its active child tasks, and refuses new managed child tasks. Once no child task remains active, the flow finalizes as `cancelled` - immediately, or via the maintenance sweep if children take longer to settle. The intent is persisted, so a cancelled flow stays cancelled even if the gateway restarts before all child tasks have terminated.
|
||||
|
||||
## CLI commands
|
||||
|
||||
```bash
|
||||
# List active and recent flows
|
||||
openclaw tasks flow list [--status <status>] [--json]
|
||||
|
||||
# Show details for a specific flow
|
||||
openclaw tasks flow show <lookup> [--json]
|
||||
|
||||
# Cancel a running flow and its active tasks
|
||||
openclaw tasks flow cancel <lookup>
|
||||
```
|
||||
|
||||
| Command | Description |
|
||||
| --------------------------------- | ----------------------------------------------------------------------- |
|
||||
| `openclaw tasks flow list` | Tracked flows with sync mode, status, revision, controller, task counts |
|
||||
| `openclaw tasks flow show <id>` | Inspect one flow by flow id or owner key, including linked tasks |
|
||||
| `openclaw tasks flow cancel <id>` | Cancel a running flow and its active tasks |
|
||||
|
||||
Flows are also covered by `openclaw tasks audit` (stale or broken flow findings) and `openclaw tasks maintenance` (finalizes stuck cancels, prunes terminal flows after 7 days).
|
||||
|
||||
## Reliable scheduled workflow pattern
|
||||
|
||||
For recurring workflows such as market intelligence briefings, treat the schedule, orchestration, and reliability checks as separate layers:
|
||||
|
||||
1. Use [Scheduled Tasks](/automation/cron-jobs) for timing.
|
||||
2. Use a persistent cron session when the workflow should build on prior context.
|
||||
3. Use [Lobster](/tools/lobster) for deterministic steps, approval gates, and resume tokens.
|
||||
4. Use Task Flow to track the multi-step run across child tasks, waits, retries, and gateway restarts.
|
||||
|
||||
Example cron shape:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Market intelligence brief" \
|
||||
--cron "0 7 * * 1-5" \
|
||||
--tz "America/New_York" \
|
||||
--session session:market-intel \
|
||||
--message "Run the market-intel Lobster workflow. Verify source freshness before summarizing." \
|
||||
--announce \
|
||||
--channel slack \
|
||||
--to "channel:C1234567890"
|
||||
```
|
||||
|
||||
Use `--session session:<id>` instead of `isolated` when the recurring workflow needs deliberate history, previous run summaries, or standing context. Use `isolated` when each run should start fresh and all required state is explicit in the workflow.
|
||||
|
||||
Inside the workflow, put reliability checks before the LLM summary step:
|
||||
|
||||
```yaml
|
||||
name: market-intel-brief
|
||||
steps:
|
||||
- id: preflight
|
||||
command: market-intel check --json
|
||||
- id: collect
|
||||
command: market-intel collect --json
|
||||
stdin: $preflight.json
|
||||
- id: summarize
|
||||
command: market-intel summarize --json
|
||||
stdin: $collect.json
|
||||
- id: approve
|
||||
command: market-intel deliver --preview
|
||||
stdin: $summarize.json
|
||||
approval: required
|
||||
- id: deliver
|
||||
command: market-intel deliver --execute
|
||||
stdin: $summarize.json
|
||||
condition: $approve.approved
|
||||
```
|
||||
|
||||
Recommended preflight checks:
|
||||
|
||||
- Browser availability and profile choice, for example `openclaw` for managed state or `user` when a signed-in Chrome session is required. See [Browser](/tools/browser).
|
||||
- API credentials and quota for each source.
|
||||
- Network reachability for required endpoints.
|
||||
- Required tools enabled for the agent, such as `lobster`, `browser`, and `llm-task`.
|
||||
- Failure destination configured for cron so preflight failures are visible. See [Scheduled Tasks](/automation/cron-jobs#delivery-and-output).
|
||||
|
||||
Recommended data provenance fields for every collected item:
|
||||
|
||||
```json
|
||||
{
|
||||
"sourceUrl": "https://example.com/report",
|
||||
"retrievedAt": "2026-04-24T12:00:00Z",
|
||||
"asOf": "2026-04-24",
|
||||
"title": "Example report",
|
||||
"content": "..."
|
||||
}
|
||||
```
|
||||
|
||||
Have the workflow reject or mark stale items before summarization. The LLM step should receive only structured JSON and should be asked to preserve `sourceUrl`, `retrievedAt`, and `asOf` in its output. Use [LLM Task](/tools/llm-task) when you need a schema-validated model step inside the workflow.
|
||||
|
||||
For reusable team or community workflows, package the CLI, `.lobster` files, and any setup notes as a skill or plugin and publish it through [ClawHub](/clawhub). Keep workflow-specific guardrails in that package unless the plugin API is missing a needed generic capability.
|
||||
|
||||
## How flows relate to tasks
|
||||
|
||||
Flows coordinate tasks, not replace them. A single flow may drive multiple background tasks over its lifetime. Use `openclaw tasks` to inspect individual task records and `openclaw tasks flow` to inspect the orchestrating flow.
|
||||
|
||||
## Related
|
||||
|
||||
- [Background Tasks](/automation/tasks) - the detached work ledger that flows coordinate
|
||||
- [CLI: tasks](/cli/tasks) - CLI command reference for `openclaw tasks flow`
|
||||
- [Automation Overview](/automation) - all automation mechanisms at a glance
|
||||
- [Cron Jobs](/automation/cron-jobs) - scheduled jobs that may feed into flows
|
||||
374
docs/automation/tasks.md
Normal file
374
docs/automation/tasks.md
Normal file
@@ -0,0 +1,374 @@
|
||||
---
|
||||
summary: "Background task tracking for ACP runs, subagents, cron executions, and CLI operations"
|
||||
read_when:
|
||||
- Inspecting background work in progress or recently completed
|
||||
- Debugging delivery failures for detached agent runs
|
||||
- Understanding how background runs relate to sessions, cron, and heartbeat
|
||||
title: "Background tasks"
|
||||
sidebarTitle: "Background tasks"
|
||||
---
|
||||
|
||||
<Note>
|
||||
Looking for scheduling? See [Automation](/automation) for choosing the right mechanism. This page is the activity ledger for background work, not the scheduler.
|
||||
</Note>
|
||||
|
||||
Background tasks track work that runs **outside your main conversation session**: ACP runs, subagent spawns, cron job executions, and CLI-initiated operations.
|
||||
|
||||
Tasks do **not** replace sessions, cron jobs, or heartbeats - they are the **activity ledger** that records what detached work happened, when, and whether it succeeded.
|
||||
|
||||
<Note>
|
||||
Not every agent run creates a task. Heartbeat turns and normal interactive chat do not. All cron executions, ACP spawns, subagent spawns, and gateway-dispatched CLI agent commands do.
|
||||
</Note>
|
||||
|
||||
## TL;DR
|
||||
|
||||
- Tasks are **records**, not schedulers - cron and heartbeat decide _when_ work runs, tasks track _what happened_.
|
||||
- ACP, subagents, all cron jobs, and CLI operations create tasks. Heartbeat turns do not.
|
||||
- Each task moves through `queued → running → terminal` (succeeded, failed, timed_out, cancelled, or lost).
|
||||
- Cron tasks stay live while the cron runtime still owns the job; if the in-memory runtime state is gone, task maintenance first checks durable cron run history before marking a task lost.
|
||||
- Completion is push-driven: detached work can notify directly or wake the requester session/heartbeat when it finishes, so status polling loops are usually the wrong shape.
|
||||
- Isolated cron runs and subagent completions best-effort clean up tracked browser tabs/processes for their child session before final cleanup bookkeeping.
|
||||
- Isolated cron delivery suppresses stale interim parent replies while descendant subagent work is still draining, and it prefers final descendant output when that arrives before delivery.
|
||||
- Completion notifications are delivered directly to a channel or queued for the next heartbeat.
|
||||
- `openclaw tasks list` shows all tasks; `openclaw tasks audit` surfaces issues.
|
||||
- Terminal records are kept for 7 days (`lost` records for 24 hours), then automatically pruned.
|
||||
|
||||
## Quick start
|
||||
|
||||
<Tabs>
|
||||
<Tab title="List and filter">
|
||||
```bash
|
||||
# List all tasks (newest first)
|
||||
openclaw tasks list
|
||||
|
||||
# Filter by runtime or status
|
||||
openclaw tasks list --runtime acp
|
||||
openclaw tasks list --status running
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Inspect">
|
||||
```bash
|
||||
# Show details for a specific task (by task ID, run ID, or session key)
|
||||
openclaw tasks show <lookup>
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Cancel and notify">
|
||||
```bash
|
||||
# Cancel a running task (kills the child session)
|
||||
openclaw tasks cancel <lookup>
|
||||
|
||||
# Change notification policy for a task
|
||||
openclaw tasks notify <lookup> state_changes
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Audit and maintenance">
|
||||
```bash
|
||||
# Run a health audit
|
||||
openclaw tasks audit
|
||||
|
||||
# Preview or apply maintenance
|
||||
openclaw tasks maintenance
|
||||
openclaw tasks maintenance --apply
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Task flow">
|
||||
```bash
|
||||
# Inspect TaskFlow state
|
||||
openclaw tasks flow list
|
||||
openclaw tasks flow show <lookup>
|
||||
openclaw tasks flow cancel <lookup>
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## What creates a task
|
||||
|
||||
| Source | Runtime type | When a task record is created | Default notify policy |
|
||||
| ---------------------- | ------------ | ---------------------------------------------------------------------- | --------------------- |
|
||||
| ACP background runs | `acp` | Spawning a child ACP session | `done_only` |
|
||||
| Subagent orchestration | `subagent` | Spawning a subagent via `sessions_spawn` | `done_only` |
|
||||
| Cron jobs (all types) | `cron` | Every cron execution (main-session and isolated) | `silent` |
|
||||
| CLI operations | `cli` | `openclaw agent` commands that run through the gateway | `silent` |
|
||||
| Agent media jobs | `cli` | Session-backed `image_generate`/`music_generate`/`video_generate` runs | `silent` |
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Notify defaults for cron and media">
|
||||
Cron tasks (main-session and isolated) use `silent` notify policy - they create records for tracking but do not generate task notifications of their own; cron owns its delivery path.
|
||||
|
||||
Session-backed `image_generate`, `music_generate`, and `video_generate` runs also use `silent` notify policy. They still create task records, but completion is handed back to the original agent session as an internal wake so the agent can write the follow-up message and attach the finished media itself. The requester agent follows its normal visible-reply contract: automatic final reply when configured, or `message(action="send")` plus `NO_REPLY` when the session requires message-tool replies. If the requester session is no longer active or its active wake fails, and the completion agent misses some or all generated media, OpenClaw sends an idempotent direct fallback with only the missing media to the original channel target.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Concurrent media-generation guardrail">
|
||||
While a session-backed media-generation task is still active, `image_generate`, `music_generate`, and `video_generate` guard against accidental retries: repeating the call for the same prompt/request returns the matching active task status instead of starting a duplicate, while a distinct prompt can start its own task. Use `action: "status"` when you want an explicit progress/status lookup from the agent side.
|
||||
</Accordion>
|
||||
<Accordion title="What does not create tasks">
|
||||
- Heartbeat turns - main-session; see [Heartbeat](/gateway/heartbeat)
|
||||
- Normal interactive chat turns
|
||||
- Direct `/command` responses
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Task lifecycle
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> queued
|
||||
queued --> running : agent starts
|
||||
running --> succeeded : completes ok
|
||||
running --> failed : error
|
||||
running --> timed_out : timeout exceeded
|
||||
queued --> cancelled : operator cancels
|
||||
running --> cancelled : operator cancels
|
||||
queued --> lost : backing state gone > 5 min
|
||||
running --> lost : backing state gone > 5 min
|
||||
```
|
||||
|
||||
| Status | What it means |
|
||||
| ----------- | --------------------------------------------------------------------------- |
|
||||
| `queued` | Created, waiting for the agent to start |
|
||||
| `running` | Agent turn is actively executing |
|
||||
| `succeeded` | Completed successfully |
|
||||
| `failed` | Completed with an error |
|
||||
| `timed_out` | Exceeded the configured timeout |
|
||||
| `cancelled` | Stopped by the operator via `openclaw tasks cancel`, or the run was aborted |
|
||||
| `lost` | The runtime lost authoritative backing state after a 5-minute grace period |
|
||||
|
||||
Transitions happen automatically - agent run lifecycle events (start, end, error) update the task status; you do not manage it manually.
|
||||
|
||||
Agent run completion is authoritative for active task records. A successful detached run finalizes as `succeeded`, ordinary run errors finalize as `failed`, timeouts finalize as `timed_out`, and cancel/abort outcomes finalize as `cancelled`. Once a task is terminal, later lifecycle signals do not downgrade it - an operator-cancelled or already-`failed`/`timed_out`/`lost` task stays that way even if a success signal arrives afterwards.
|
||||
|
||||
`lost` is runtime-aware:
|
||||
|
||||
- ACP tasks: only a live in-process ACP turn in the Gateway proves the run is alive; persisted session metadata alone does not. Offline CLI audit stays conservative and never reclaims ACP tasks.
|
||||
- Subagent tasks: backing child session disappeared from the target agent store (or carries a restart-recovery tombstone).
|
||||
- Cron tasks: the cron runtime no longer tracks the job as active and durable cron run history does not show a terminal result for that run. Offline CLI audit does not treat its own empty in-process cron runtime state as authority.
|
||||
- CLI tasks: tasks with a run id/source id use the live run context, so lingering child-session or chat-session rows do not keep them alive after the gateway-owned run disappears. Legacy CLI tasks without run identity still fall back to the child session. Gateway-backed `openclaw agent` runs also finalize from their run result, so completed runs do not sit active until the sweeper marks them `lost`.
|
||||
|
||||
## Delivery and notifications
|
||||
|
||||
When a task reaches a terminal state, OpenClaw notifies you. There are two delivery paths:
|
||||
|
||||
**Direct delivery** - if the task has a channel target (the `requesterOrigin`), the completion message goes straight to that channel (Discord, Slack, Telegram, etc.). Group and channel task completions are instead routed through the requester session so the parent agent can write the visible reply. For subagent completions, OpenClaw also preserves bound thread/topic routing when available and can fill a missing `to` / account from the requester session's stored route (`lastChannel` / `lastTo` / `lastAccountId`) before giving up on direct delivery.
|
||||
|
||||
**Session-queued delivery** - if direct delivery fails or no origin is set, the update is queued as a system event in the requester's session and surfaces on the next heartbeat.
|
||||
|
||||
<Tip>
|
||||
Session-queued task completions trigger an immediate heartbeat wake, so you see the result quickly - you do not have to wait for the next scheduled heartbeat tick.
|
||||
</Tip>
|
||||
|
||||
That means the usual workflow is push-based: start detached work once, then let the runtime wake or notify you on completion. Poll task state only when you need debugging, intervention, or an explicit audit.
|
||||
|
||||
### Notification policies
|
||||
|
||||
Control how much you hear about each task:
|
||||
|
||||
| Policy | What is delivered |
|
||||
| --------------------- | ------------------------------------------------------- |
|
||||
| `done_only` (default) | Only terminal state (succeeded, failed, etc.) |
|
||||
| `state_changes` | Every state transition and progress update |
|
||||
| `silent` | Nothing at all (default for cron, CLI, and media tasks) |
|
||||
|
||||
Change the policy while a task is running:
|
||||
|
||||
```bash
|
||||
openclaw tasks notify <lookup> state_changes
|
||||
```
|
||||
|
||||
## CLI reference
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="tasks list">
|
||||
```bash
|
||||
openclaw tasks list [--runtime <acp|subagent|cron|cli>] [--status <status>] [--json]
|
||||
```
|
||||
|
||||
Output columns: Task, Kind, Status, Delivery, Run, Child Session, Summary. Bare `openclaw tasks` behaves like `openclaw tasks list`.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="tasks show">
|
||||
```bash
|
||||
openclaw tasks show <lookup> [--json]
|
||||
```
|
||||
|
||||
The lookup token accepts a task ID, run ID, or session key. Shows the full record including timing, delivery state, error, and terminal summary.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="tasks cancel">
|
||||
```bash
|
||||
openclaw tasks cancel <lookup>
|
||||
```
|
||||
|
||||
For ACP and subagent tasks, this kills the child session; ACP and cron cancellations route through the running Gateway (`tasks.cancel`). For CLI-tracked tasks, cancellation is recorded in the task registry (there is no separate child runtime handle). Status transitions to `cancelled` and a delivery notification is sent when applicable.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="tasks notify">
|
||||
```bash
|
||||
openclaw tasks notify <lookup> <done_only|state_changes|silent>
|
||||
```
|
||||
</Accordion>
|
||||
<Accordion title="tasks audit">
|
||||
```bash
|
||||
openclaw tasks audit [--severity <warn|error>] [--code <name>] [--limit <n>] [--json]
|
||||
```
|
||||
|
||||
Surfaces operational issues for tasks **and** TaskFlows in one report. Findings also appear in `openclaw status` when issues are detected.
|
||||
|
||||
Task findings:
|
||||
|
||||
| Finding | Severity | Trigger |
|
||||
| ------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| `stale_queued` | warn | Queued for more than 10 minutes |
|
||||
| `stale_running` | error | Running for more than 30 minutes |
|
||||
| `lost` | warn/error | Runtime-backed task ownership disappeared; retained lost tasks warn until `cleanupAfter`, then become errors |
|
||||
| `delivery_failed` | warn | Delivery failed and notify policy is not `silent` |
|
||||
| `missing_cleanup` | warn | Terminal task with no cleanup timestamp |
|
||||
| `inconsistent_timestamps` | warn | Timeline violation (for example ended before started) |
|
||||
|
||||
TaskFlow findings:
|
||||
|
||||
| Finding | Severity | Trigger |
|
||||
| ---------------------- | ---------- | --------------------------------------------------------------------------- |
|
||||
| `restore_failed` | error | Flow registry restore from SQLite failed |
|
||||
| `stale_running` | error | Running flow has not advanced for more than 30 minutes |
|
||||
| `stale_waiting` | warn | Waiting flow has not advanced for more than 30 minutes |
|
||||
| `stale_blocked` | warn | Blocked flow has not advanced for more than 30 minutes |
|
||||
| `cancel_stuck` | warn | Cancel requested over 5 minutes ago, no active child tasks, still nonterminal |
|
||||
| `missing_linked_tasks` | warn/error | Stale managed flow with no linked tasks or wait state |
|
||||
| `blocked_task_missing` | warn | Blocked flow points at a task id that no longer exists |
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="tasks maintenance">
|
||||
```bash
|
||||
openclaw tasks maintenance [--json]
|
||||
openclaw tasks maintenance --apply [--json]
|
||||
```
|
||||
|
||||
Use this to preview or apply reconciliation, cleanup stamping, and pruning for tasks, TaskFlow state, and stale cron run session registry rows.
|
||||
|
||||
Reconciliation is runtime-aware:
|
||||
|
||||
- ACP tasks require a live in-process turn in the Gateway; subagent tasks check their backing child session.
|
||||
- Subagent tasks whose child session has a restart-recovery tombstone are marked lost instead of being treated as recoverable backing sessions.
|
||||
- Cron tasks check whether the cron runtime still owns the job, then recover terminal status from persisted cron run logs/job state before falling back to `lost`. Only the Gateway process is authoritative for the in-memory cron active-job set; offline CLI audit uses durable history but does not mark a cron task lost solely because that local set is empty.
|
||||
- CLI tasks with run identity check the owning live run context, not just child-session or chat-session rows.
|
||||
|
||||
Completion cleanup is also runtime-aware:
|
||||
|
||||
- Subagent completion best-effort closes tracked browser tabs/processes for the child session before announce cleanup continues.
|
||||
- Isolated cron completion best-effort closes tracked browser tabs/processes for the cron session before the run fully tears down.
|
||||
- Isolated cron delivery waits out descendant subagent follow-up when needed and suppresses stale parent acknowledgement text instead of announcing it.
|
||||
- Subagent completion delivery uses the child's latest visible assistant text only. Tool/toolResult output is not promoted into child result text. Terminal failed runs announce failure status without replaying captured reply text.
|
||||
- Cleanup failures do not mask the real task outcome.
|
||||
|
||||
When applying maintenance, OpenClaw also removes stale `cron:<jobId>:run:<runId>` session registry rows older than 7 days, while preserving rows for currently running cron jobs and leaving non-cron session rows untouched.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="tasks flow list | show | cancel">
|
||||
```bash
|
||||
openclaw tasks flow list [--status <status>] [--json]
|
||||
openclaw tasks flow show <lookup> [--json]
|
||||
openclaw tasks flow cancel <lookup>
|
||||
```
|
||||
|
||||
The flow lookup token accepts a flow id or owner key. Use these when the orchestrating [Task Flow](/automation/taskflow) is the thing you care about rather than one individual background task record.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Chat task board (`/tasks`)
|
||||
|
||||
Use `/tasks` in any chat session to see background tasks linked to that session. The board shows up to five active and recently completed tasks with runtime, status, timing, and progress or error detail.
|
||||
|
||||
When the current session has no visible linked tasks, `/tasks` falls back to agent-local task counts so you still get an overview without leaking other-session details.
|
||||
|
||||
For the full operator ledger, use the CLI: `openclaw tasks list`.
|
||||
|
||||
## Status integration (task pressure)
|
||||
|
||||
`openclaw status` includes an at-a-glance task line:
|
||||
|
||||
```
|
||||
Tasks 2 active · 1 queued · 1 running · 1 issue · audit clean · 6 tracked
|
||||
```
|
||||
|
||||
The summary counts active work (`queued` + `running`), failures (`failed` + `timed_out` + `lost`), audit findings, and total tracked records; the JSON payload also breaks counts down by runtime (`acp`, `subagent`, `cron`, `cli`).
|
||||
|
||||
Both `/status` and the `session_status` tool use a cleanup-aware task snapshot: active tasks are preferred, expired rows are hidden, and terminal tasks only appear for a short recent window (5 minutes), with failures focused when no active work remains. This keeps the status card on what matters right now.
|
||||
|
||||
## Storage and maintenance
|
||||
|
||||
### Where tasks live
|
||||
|
||||
Task records and delivery state persist in the shared OpenClaw SQLite state database:
|
||||
|
||||
```
|
||||
~/.openclaw/state/openclaw.sqlite (tables: task_runs, task_delivery_state, flow_runs)
|
||||
```
|
||||
|
||||
Set `OPENCLAW_STATE_DIR` to move the whole state root (default `~/.openclaw`) elsewhere; the shared database path moves with it.
|
||||
|
||||
The registry loads into memory on first use and persists every write back to SQLite, so records survive gateway restarts. WAL growth stays bounded through SQLite's default autocheckpoint threshold plus periodic `PASSIVE` checkpoints; shutdown and explicit maintenance checkpoints use `TRUNCATE` so normal closes reclaim WAL space without making the background sweeper wait on active readers.
|
||||
|
||||
Legacy sidecar stores from older installs (`tasks/runs.sqlite`, `flows/registry.sqlite`) are imported into the shared database by `openclaw doctor`.
|
||||
|
||||
### Automatic maintenance
|
||||
|
||||
A sweeper runs every **60 seconds** (first pass about 5 seconds after gateway start) and handles four things:
|
||||
|
||||
<Steps>
|
||||
<Step title="Reconciliation">
|
||||
Checks whether active tasks still have authoritative runtime backing. ACP tasks require a live in-process turn, subagent tasks use child-session state, cron tasks use active-job ownership plus durable run history, and CLI tasks with run identity use the owning run context. If backing state is gone for more than 5 minutes (30 minutes for childless native subagent tasks), the task is marked `lost`.
|
||||
</Step>
|
||||
<Step title="ACP session repair">
|
||||
Closes terminal or orphaned parent-owned one-shot ACP sessions, and closes stale terminal or orphaned persistent ACP sessions only when no active conversation binding remains.
|
||||
</Step>
|
||||
<Step title="Cleanup stamping">
|
||||
Sets a `cleanupAfter` timestamp on terminal tasks (terminal time + retention window). During retention, lost tasks still appear in audit as warnings; after `cleanupAfter` expires or when cleanup metadata is missing, they become errors.
|
||||
</Step>
|
||||
<Step title="Pruning">
|
||||
Deletes records past their `cleanupAfter` date.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Note>
|
||||
**Retention:** terminal task records are kept for **7 days** (`lost` records for **24 hours**), then automatically pruned. No configuration needed.
|
||||
</Note>
|
||||
|
||||
## How tasks relate to other systems
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Tasks and Task Flow">
|
||||
[Task Flow](/automation/taskflow) is the flow orchestration layer above background tasks. A single flow may coordinate multiple tasks over its lifetime using managed or mirrored sync modes. Use `openclaw tasks` to inspect individual task records and `openclaw tasks flow` to inspect the orchestrating flow.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Tasks and cron">
|
||||
Cron job definitions, runtime execution state, and run history live in OpenClaw's shared SQLite state database. **Every** cron execution creates a task record - both main-session and isolated - with `silent` notify policy, so cron runs are tracked without generating task notifications of their own.
|
||||
|
||||
See [Cron Jobs](/automation/cron-jobs).
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Tasks and heartbeat">
|
||||
Heartbeat runs are main-session turns - they do not create task records. When a task completes, it can trigger a heartbeat wake so you see the result promptly.
|
||||
|
||||
See [Heartbeat](/gateway/heartbeat).
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Tasks and sessions">
|
||||
A task may reference a `childSessionKey` (where work runs) and a `requesterSessionKey` (who started it). Its `agentId` identifies the agent executing the work, while the requester and owner fields preserve launch and control context. Sessions are conversation context; tasks are activity tracking on top of that.
|
||||
</Accordion>
|
||||
<Accordion title="Tasks and agent runs">
|
||||
A task's `runId` links to the agent run doing the work. Agent lifecycle events (start, end, error) automatically update the task status - you do not need to manage the lifecycle manually.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Related
|
||||
|
||||
- [Automation](/automation) - all automation mechanisms at a glance
|
||||
- [CLI: Tasks](/cli/tasks) - CLI command reference
|
||||
- [Heartbeat](/gateway/heartbeat) - periodic main-session turns
|
||||
- [Scheduled Tasks](/automation/cron-jobs) - scheduling background work
|
||||
- [Task Flow](/automation/taskflow) - flow orchestration above tasks
|
||||
12
docs/automation/troubleshooting.md
Normal file
12
docs/automation/troubleshooting.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
summary: "Redirect to /automation/cron-jobs"
|
||||
title: "Automation troubleshooting"
|
||||
---
|
||||
|
||||
This page moved. Automation troubleshooting now lives at [Scheduled Tasks](/automation/cron-jobs#troubleshooting).
|
||||
|
||||
## Related
|
||||
|
||||
- [Hooks](/automation/hooks)
|
||||
- [Background tasks](/automation/tasks)
|
||||
- [Gateway troubleshooting](/gateway/troubleshooting)
|
||||
12
docs/automation/webhook.md
Normal file
12
docs/automation/webhook.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
summary: "Redirect to /automation/cron-jobs"
|
||||
title: "Webhooks"
|
||||
---
|
||||
|
||||
This page moved. Webhook documentation now lives at [Scheduled Tasks](/automation/cron-jobs#webhooks).
|
||||
|
||||
## Related
|
||||
|
||||
- [Poll](/automation/poll)
|
||||
- [Gmail PubSub](/automation/gmail-pubsub)
|
||||
- [Hooks](/automation/hooks)
|
||||
Reference in New Issue
Block a user