diff --git a/.github/workflows/tutorials.yml b/.github/workflows/tutorials.yml new file mode 100644 index 0000000..8c3476c --- /dev/null +++ b/.github/workflows/tutorials.yml @@ -0,0 +1,70 @@ +name: Tutorial tests + +# Runs the beginner path's commands for real against the pinned OpenClaw +# (scripts/openclaw-version.txt): onboarding, a Gateway on loopback with token +# auth, automations, skills, backups, audits. One script per page in +# scripts/tutorial-tests/. Steps that need a model key or a channel account are +# listed as skipped, with the reason. See scripts/README.md. +# +# Report only for now: the job passes even when a page fails, and the summary +# and tutorial-report.json say which steps failed. To make it blocking, set the +# repository variable TUTORIALS_STRICT=1 (Settings > Secrets and variables > +# Actions > Variables), or run it manually with "strict" ticked. + +on: + push: + branches: [gh-pages] + paths: + - 'docs/**' + - 'scripts/tutorial-tests/**' + - 'scripts/openclaw-version.txt' + - '.github/workflows/tutorials.yml' + pull_request: + paths: + - 'docs/**' + - 'scripts/tutorial-tests/**' + - 'scripts/openclaw-version.txt' + - '.github/workflows/tutorials.yml' + schedule: + - cron: '17 5 * * 1' # Mondays 05:17 UTC + workflow_dispatch: + inputs: + strict: + description: Fail the job when a page fails + type: boolean + default: false + +permissions: + contents: read + +concurrency: + group: tutorials-${{ github.ref }} + cancel-in-progress: true + +jobs: + tutorials: + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + TUTORIALS_STRICT: ${{ (github.event_name == 'workflow_dispatch' && inputs.strict) && '1' || vars.TUTORIALS_STRICT || '0' }} + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-node@v6 + with: + node-version: 24 # openclaw needs >=24.16 + - name: Install pinned OpenClaw + run: | + npm i --prefix tools/openclaw --no-save --ignore-scripts --no-audit --no-fund \ + "openclaw@$(tr -d '[:space:]' < scripts/openclaw-version.txt)" + tools/openclaw/node_modules/.bin/openclaw --version + node --version; npm --version + - name: Run tutorial tests + run: node scripts/tutorial-tests/run.mjs --json tutorial-report.json + - uses: actions/upload-artifact@v7 + if: always() + with: + name: tutorial-report + path: | + tutorial-report.json + tutorial-report/ + if-no-files-found: ignore diff --git a/.gitignore b/.gitignore index c90cb90..bf2e203 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,7 @@ yarn-error.log* # Snippet gates /tools/openclaw snippet-report.json + +# Tutorial tests +tutorial-report.json +/tutorial-report diff --git a/docs/getting-started/quick-start.md b/docs/getting-started/quick-start.md index c01e567..f7e758f 100644 --- a/docs/getting-started/quick-start.md +++ b/docs/getting-started/quick-start.md @@ -2,6 +2,10 @@ last_update: date: 2026-10-18 verified_with: 2026.10.4 +ci_verified: + version: 2026.10.4 + date: 2026-10-18 + steps: 24 title: Quick Start description: Get OpenClaw running and talking to you in about 5 minutes, from install to first conversation keywords: [openclaw, openclaw getting started, openclaw tutorial, openclaw quick start, openclaw first steps, how to use openclaw, openclaw beginner guide] @@ -168,7 +172,7 @@ openclaw channels add discord Each command opens guided setup for that channel. By default, unknown senders who DM your bot get a pairing code instead of the agent. Approve them with: ```bash -openclaw pairing list +openclaw pairing list telegram openclaw pairing approve telegram ``` @@ -206,7 +210,7 @@ openclaw cron add --name "Morning brief" --cron "0 9 * * *" --session isolated \ `openclaw automations` is the same command under its new name. To give the heartbeat a short standing checklist, store it in its monitor scratch: find the job with `openclaw cron list --all` (it is listed as `Heartbeat (main)`), then `openclaw cron scratch --set "..."`. :::note Coming from an older version? -`HEARTBEAT.md` is retired and no longer read. `openclaw doctor --fix` imports an existing file into the heartbeat's monitor scratch and converts its `tasks:` entries into automations. +`HEARTBEAT.md` is retired and no longer read. `openclaw doctor --fix`, run with the Gateway stopped, imports an existing file into the heartbeat's monitor scratch and converts its `tasks:` entries into automations. ::: See the [Heartbeat Guide](/guides/heartbeat), [Automation](/guides/automation) and the official [heartbeat docs](https://docs.openclaw.ai/gateway/heartbeat). diff --git a/docs/guides/first-7-days/day-1-make-it-yours.md b/docs/guides/first-7-days/day-1-make-it-yours.md index 3ea8d72..8589ad9 100644 --- a/docs/guides/first-7-days/day-1-make-it-yours.md +++ b/docs/guides/first-7-days/day-1-make-it-yours.md @@ -2,6 +2,10 @@ last_update: date: 2026-10-18 verified_with: 2026.10.4 +ci_verified: + version: 2026.10.4 + date: 2026-10-18 + steps: 17 title: "Day 1: Make It Yours" description: "Personalize your OpenClaw bot — name, personality, boundaries, and your first real conversation" keywords: [openclaw, setup, personalize, soul.md, agents.md, user.md, first day, customize agent, bot personality] @@ -53,7 +57,7 @@ The workspace holds a handful of Markdown files that load at the start of every | `MEMORY.md` | Curated long-term facts and decisions (optional). | | `memory/YYYY-MM-DD.md` | Daily notes the agent writes as it goes. | -You can edit them with any text editor, or in the Control UI under **Settings → Agents → Files**. If you delete one by accident, `openclaw setup` recreates missing defaults without overwriting the files you kept. +You can edit them with any text editor, or in the Control UI under **Settings → Agents → Files**. If you delete one by accident, `openclaw setup --baseline` recreates missing defaults without overwriting the files you kept. (Bare `openclaw setup` on a configured install opens a chat instead.) --- @@ -127,7 +131,7 @@ Edit `~/.openclaw/workspace/IDENTITY.md`: - **Avatar:** avatars/nova.png ``` -Replace `(pick one)` with a single emoji. Placeholder text in parentheses is ignored, not saved. The avatar is a workspace-relative path, an `http(s)` URL, or a data URI; drop the line if you don't have one. +Replace `(pick one)` with a single emoji, or delete the line. Only the template's own placeholder text is ignored; anything else you leave there, including `(pick one)`, is saved as the value. The avatar is a workspace-relative path, an `http(s)` URL, or a data URI; drop the line if you don't have one. To push the file into the agent's config (used by the Control UI and other surfaces), run: diff --git a/docs/guides/first-7-days/day-3-automation.md b/docs/guides/first-7-days/day-3-automation.md index d14781c..ce055dd 100644 --- a/docs/guides/first-7-days/day-3-automation.md +++ b/docs/guides/first-7-days/day-3-automation.md @@ -2,6 +2,10 @@ last_update: date: 2026-10-18 verified_with: 2026.10.4 +ci_verified: + version: 2026.10.4 + date: 2026-10-18 + steps: 30 title: "Day 3: Set It Free" description: "Schedule automations for morning briefings and checks, and tune the heartbeat monitor so your bot reaches out on its own" keywords: [openclaw, automation, automations, cron, heartbeat setup, scheduled tasks, morning briefing, proactive alerts] @@ -28,7 +32,7 @@ OpenClaw has two kinds of scheduled work, and both are run by the Gateway's auto Rule of thumb: if the task has a time or interval in its name, it's an automation. :::info Coming from an older guide? -Older OpenClaw versions read heartbeat tasks from a `HEARTBEAT.md` file in the workspace. That file was retired in 2026.8.1: OpenClaw no longer creates or reads it. If you still have one, run `openclaw doctor --fix`. Doctor imports its instructions into the heartbeat's monitor scratch, turns valid `tasks:` entries into automations, and archives the original ([retired HEARTBEAT.md](https://docs.openclaw.ai/reference/templates/HEARTBEAT)). +Older OpenClaw versions read heartbeat tasks from a `HEARTBEAT.md` file in the workspace. That file was retired in 2026.8.1: OpenClaw no longer creates or reads it. If you still have one, stop the Gateway (`openclaw gateway stop`) and run `openclaw doctor --fix`. Doctor imports its instructions into the heartbeat's monitor scratch, turns valid `tasks:` entries into automations, and archives the original ([retired HEARTBEAT.md](https://docs.openclaw.ai/reference/templates/HEARTBEAT)). ::: ## Before You Start: Where Messages Go diff --git a/docs/guides/first-7-days/day-4-skills.md b/docs/guides/first-7-days/day-4-skills.md index dd91a68..523f107 100644 --- a/docs/guides/first-7-days/day-4-skills.md +++ b/docs/guides/first-7-days/day-4-skills.md @@ -2,6 +2,10 @@ last_update: date: 2026-10-18 verified_with: 2026.10.4 +ci_verified: + version: 2026.10.4 + date: 2026-10-18 + steps: 20 title: "Day 4: Supercharge It" description: "Use the skills that ship with OpenClaw, find more on ClawHub, and check them before you install" keywords: [openclaw, skills, install skills, clawhub, skill tutorial, community skills, extend bot] diff --git a/docs/guides/first-7-days/day-7-production.md b/docs/guides/first-7-days/day-7-production.md index f7bee0b..d31cd11 100644 --- a/docs/guides/first-7-days/day-7-production.md +++ b/docs/guides/first-7-days/day-7-production.md @@ -2,6 +2,10 @@ last_update: date: 2026-10-18 verified_with: 2026.10.4 +ci_verified: + version: 2026.10.4 + date: 2026-10-18 + steps: 30 title: "Day 7: Lock It Down" description: "A validated security baseline, cost checks, monitoring, backups and safe upgrades for a long-running OpenClaw setup" keywords: [openclaw, production, hardening, monitoring, security, backup, upgrade, cost] @@ -207,10 +211,12 @@ Use `openclaw update`, not `npm update -g openclaw`. The updater validates the t **4. Check:** ```bash -openclaw doctor --fix +openclaw doctor openclaw status --deep ``` +The updater already ran the required Doctor migrations; `openclaw doctor` reports anything left. If it suggests repairs, stop the Gateway first (`openclaw gateway stop`), run `openclaw doctor --fix`, then `openclaw gateway start`: with the Gateway running, `doctor --fix` cannot lock the state database and exits with `GatewayStateOwnerContentionError`. + Confirm every channel reconnects and your automations are listed in `openclaw cron list`. **5. If something breaks:** don't just reinstall an older version. Downgrading the package does **not** reverse config or database migrations. Upstream's supported recovery is to restore a verified pre-update backup together with the OpenClaw release that made it ([rollback and recovery](https://docs.openclaw.ai/install/updating/rollback-and-recovery)): diff --git a/docs/guides/heartbeat.md b/docs/guides/heartbeat.md index 6b1d1e0..f3b78c9 100644 --- a/docs/guides/heartbeat.md +++ b/docs/guides/heartbeat.md @@ -2,6 +2,10 @@ last_update: date: 2026-10-18 verified_with: 2026.10.4 +ci_verified: + version: 2026.10.4 + date: 2026-10-18 + steps: 39 title: Heartbeat Guide description: How OpenClaw's heartbeat works in v2026.10 — agents.defaults.heartbeat, monitor scratch, automation jobs for recurring checks, cost control, and migrating from HEARTBEAT.md keywords: [openclaw, openclaw heartbeat, monitor scratch, automations, activeHours, HEARTBEAT.md migration] @@ -118,12 +122,18 @@ Scratch becomes part of the prompt. Do not put API keys, tokens or phone numbers ### Migrating from HEARTBEAT.md {#migrating-from-heartbeatmd} -If you used `~/.openclaw/workspace/HEARTBEAT.md` (or a per-agent workspace copy) before v2026.8.1, run: +If you used `~/.openclaw/workspace/HEARTBEAT.md` (or a per-agent workspace copy) before v2026.8.1, stop the Gateway and run Doctor: ```bash +openclaw gateway stop openclaw doctor --fix +openclaw gateway start ``` +Doctor needs exclusive access to the state database. With the Gateway running, `doctor --fix` exits with `GatewayStateOwnerContentionError` and changes nothing. + +Doctor only imports into an empty scratch. If the heartbeat already has different scratch, or you cleared it with `--unset`, Doctor warns and leaves `HEARTBEAT.md` where it is; copy what you need with `openclaw cron scratch --file ~/.openclaw/workspace/HEARTBEAT.md`. + Doctor creates the monitor rows from `agents.*.heartbeat`, imports each workspace `HEARTBEAT.md` into that agent's monitor scratch, converts a structured `tasks:` block into separate automation jobs, archives the original under the state directory (`backups/heartbeat-migration/`), and deletes the file. After that the runtime reads scratch only. :::warning Bare `interval` numbers are read as minutes @@ -305,7 +315,7 @@ Common skip reasons: Checklist when nothing happens: 1. `openclaw config validate` passes, and the config has no top-level `heartbeat` key. -2. `openclaw cron list --all` shows an enabled `Heartbeat ()` job. If not, run `openclaw doctor --fix`. +2. `openclaw cron list --all` shows an enabled `Heartbeat ()` job. If not, stop the Gateway and run `openclaw doctor --fix`. 3. `cron.enabled` is not `false` and `OPENCLAW_SKIP_CRON` is not set. 4. `every` is not `"0m"`, and the current time is inside `activeHours`. 5. An owner route resolves (no `no-route` skips in `openclaw cron runs`). diff --git a/scripts/README.md b/scripts/README.md index 4826715..400f0bb 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -109,6 +109,101 @@ check whether the page's prose (batch sections, the latest release passed to `GITHUB_TOKEN` don't trigger other workflows; re-run the snippet check by hand or push a commit to the branch if needed. +## Tutorial tests (`tutorial-tests/`) + +The snippet gates check that commands *exist*. The tutorial tests check that +the beginner path *works*: each `*.test.sh` walks one page in order and runs its +commands for real against the pinned OpenClaw, with a Gateway running on the +GitHub Actions runner (`.github/workflows/tutorials.yml`: pushes and PRs that +touch `docs/` or the tests, weekly, and on demand). + +| Test | Page | +|---|---| +| `quick-start.test.sh` | `getting-started/quick-start.md` | +| `day-1-make-it-yours.test.sh` | `guides/first-7-days/day-1-make-it-yours.md` | +| `day-3-automation.test.sh` | `guides/first-7-days/day-3-automation.md` | +| `day-4-skills.test.sh` | `guides/first-7-days/day-4-skills.md` | +| `day-7-production.test.sh` | `guides/first-7-days/day-7-production.md` | +| `heartbeat.test.sh` | `guides/heartbeat.md` | + +Each test gets a fresh sandbox `HOME` (so `~/.openclaw/...` on the page is the +sandbox), a non-interactive onboarding with no model credentials, and its own +Gateway (`openclaw gateway run`, loopback, token auth), which is stopped at the +end. Tests re-run themselves under `env -i`, so no API key or token from the +calling shell reaches OpenClaw. + +**The page is the source.** A test names commands by their text on the page; +`lib.sh` finds them in the page's shell blocks (or inline code) and runs the +page's own text, so a test cannot drift from its page silently: + +```bash +source "$(dirname "$0")/lib.sh" +page docs/guides/heartbeat.md +onboard # CI stand-in for interactive onboarding +gateway_start +run -e 'Heartbeat \(main\)' "openclaw cron list --all" # -e: output must match +run "openclaw automations add \"every 30m\"..." # "...": the one command with this prefix +capture jobId "openclaw cron list --all --json" '(j.jobs).find(x=>x.displayName==="Heartbeat (main)").id' +run "openclaw cron scratch " # come from capture/ph +config_block 1 # Nth openclaw.json block: config patch + validate +config_block 4 --dry-run # reference block: validate the merge, don't apply +file_block "~/.openclaw/workspace/SOUL.md" # write a titled block to its path +skip "openclaw tui" "interactive terminal UI" +finish +``` + +Other helpers: `run_as "" ""` for steps that need a +non-interactive form or the pinned version, `setup "