---
title: "08 · Session 与心跳：时间如何进入 Agent"
description: "解释 OpenClaw 的 Session、Heartbeat、Cron、Webhooks 与 Tasks：谁负责上下文，谁负责定时，谁只做台账。"
verifiedAt: "2026-05-06"
---

前面几章已经说明了 Agent 的空间结构：Workspace 放人格和工作文件，Gateway 接消息，Session 承载当前上下文。

这一章补上时间结构。

OpenClaw 不是一个永远摊开的聊天窗口。它把对话分成可重置的 Session，用 Heartbeat 周期性唤醒主会话，用 Cron 精确调度后台任务，用 Webhooks 接外部事件，再用 Tasks 记录那些脱离主对话运行的工作。理解这几层，你才知道什么时候让 Agent “记住”，什么时候让它“清空”，什么时候让它“到点办事”，什么时候只需要一条审计记录。

> [!TIP]
> 这一篇只解决一个判断：Session 管上下文，Heartbeat 管周期醒来，Cron 管精确调度，Webhook 管外部事件，Task 只做后台台账。

## 1. 先把五个词分清楚

这五个词容易混在一起：

| 概念 | 更像什么 | 负责什么 | 不负责什么 |
| --- | --- | --- | --- |
| `Session` | 对话桶 | 决定消息进入哪段上下文 | 不保存长期记忆 |
| `Heartbeat` | 周期巡检 | 定期唤醒主会话，让 Agent 自查 | 不保证精确到秒 |
| `Cron` | 闹钟 / 排班表 | 精确时间、一次性提醒、后台任务 | 不理解业务本身 |
| `Webhook` | 外部门铃 | 接收外部系统主动打来的事件 | 不主动轮询外部系统 |
| `Task` | 后台台账 | 记录 detached work 的状态 | 不负责定时触发 |

```mermaid
flowchart LR
    User["用户消息"] --> Session["Session<br/>上下文桶"]
    Heartbeat["Heartbeat<br/>周期醒来"] --> Session
    Cron["Cron<br/>精确调度"] --> Run["Agent run"]
    Webhook["Webhook<br/>外部事件"] --> Run
    Run --> Task["Task ledger<br/>后台台账"]
    Session --> Run

    style Session fill:#dbeafe,stroke:#3b82f6,stroke-width:2px
    style Heartbeat fill:#fef3c7,stroke:#f59e0b,stroke-width:2px
    style Cron fill:#dcfce7,stroke:#22c55e,stroke-width:2px
    style Webhook fill:#dcfce7,stroke:#22c55e,stroke-width:2px
    style Task fill:#f3f4f6,stroke:#6b7280,stroke-width:2px
```

一句话：

- 你问 Agent，它进入某个 `sessionKey`。
- 到了 Heartbeat 时间，Gateway 让主会话自己检查一次。
- 到了 Cron 时间，Gateway 按 job 运行任务。
- 外部系统有事件，就通过 Webhook 唤醒或启动 isolated run。
- 后台 run 发生后，Task ledger 记录它有没有成功。

## 2. Session 是路由结果，不是聊天窗口 UI

OpenClaw 官方把 conversations 组织成 sessions。每条消息会根据来源进入一个 session。

默认行为可以这样看：

- Direct messages 默认共享一个 DM session，多用户时要检查 `dmScope`。
- Group chats 按 group 隔离，群里谁能触发要看 group policy。
- Rooms / channels 按 room 或 channel 隔离，thread/topic 会影响 session key。
- Cron jobs 每次运行使用 fresh session，`main`、`isolated`、`current` 要分清。
- Webhooks 按 hook 隔离，除非配置覆盖；不要让外部随意选择 session。

这里有两个核心 ID：

- `sessionKey` 是路由桶，决定“这条消息属于哪段对话”。
- `sessionId` 是当前 transcript 文件，reset 后会换一个新的 `sessionId`。

常见 key 形态：

常见例子包括 `agent:main:main`、`agent:ops:whatsapp:group:120363403215116621`、`agent:ops:slack:channel:C1234567890`、`cron:morning-brief` 和 `hook:uuid`。

状态由 Gateway 持有。UI、TUI、Web 控制台都应该问 Gateway，不应该自己猜本地文件。

官方给出的磁盘位置是：

`~/.openclaw/agents/agentId/sessions/sessions.json` 和 `~/.openclaw/agents/agentId/sessions/sessionId.jsonl`。

`sessions.json` 是小型 mutable store，记录当前 `sessionKey -> SessionEntry`。`sessionId.jsonl` 是 append-only transcript，保存真实消息、工具调用、工具结果、compaction summary 等内容。

## 3. Reset 换的是当前 Session，不是记忆

Session 会复用，直到触发 reset。

官方生命周期规则：

- Daily reset 默认开启，在 Gateway host 的本地时间凌晨 4 点之后创建新 session。
- Idle reset 是可选项，通过 `session.reset.idleMinutes` 设置。
- 手动 reset 通过聊天里的 `/new` 或 `/reset` 触发。
- `/new model` 还可以顺带切换模型。
- Daily reset 和 idle reset 同时存在时，先到期的规则生效。
- 使用 provider-owned CLI session 的活跃会话，不会被 implicit daily default 直接切断；需要 `/reset` 或显式配置 `session.reset`。

这句话很关键：reset 创建新的 `sessionId`，不等于删除 memory，也不等于删除旧 transcript。

所以不要把 reset 理解成“失忆”。更准确地说，它是给同一个 `sessionKey` 换一份新的当前 transcript。长期偏好、人物设定、重要事实应该在 Workspace memory 或文件里，Session 只负责当前对话上下文。

> [!IMPORTANT]
> Reset 是“换当前稿纸”，不是“烧掉档案柜”。真正要长期保存的东西，应落到 memory 或 workspace 文件里。

## 4. DM isolation 是安全边界

OpenClaw 默认所有 DM 共享一个 session。这个设计适合单用户私人 Agent，因为连续性最好：你从不同时间点私信它，它都在同一段上下文里。

但只要多个人能私信同一个 Agent，默认 `main` 就有隐私风险。

官方建议多用户场景启用 DM isolation：

```jsonc
{
  "session": {
    "dmScope": "per-channel-peer"
  }
}
```

四种模式：

| `dmScope` | 隔离粒度 | 适合场景 |
| --- | --- | --- |
| `main` | 所有 DM 共享一个 session | 单用户私人 Agent |
| `per-peer` | 按发送者隔离 | 同一人跨渠道连续性重要 |
| `per-channel-peer` | 按渠道 + 发送者隔离 | 多用户 shared inbox 的默认选择 |
| `per-account-channel-peer` | 按账号 + 渠道 + 发送者隔离 | 多账号网关、多 bot 场景 |

如果同一个人会从多个渠道联系你，可以用 `session.identityLinks` 显式关联身份。改完之后用 `openclaw security audit` 检查配置。

判断标准很简单：

- 只有你一个人用，`main` 可以接受。
- 两个人以上能 DM，默认改 `per-channel-peer`。
- 多 bot、多账号、多租户，考虑 `per-account-channel-peer`。
- 跨渠道连续性是产品需求时，再显式配置 `identityLinks`。

## 5. Heartbeat 是周期性主会话 turn

Heartbeat 不是服务器健康探针。它是 Gateway 周期性发起的一次 Agent turn，让模型在主会话上下文里检查有没有事情需要提醒你。

官方默认值：

- 默认 interval 是 `30m`。
- Anthropic OAuth/token，包括 Claude CLI reuse，默认是 `1h`。
- 关闭 heartbeat 用 `every: "0m"`。
- 默认 delivery target 是 `none`。

最小配置示例：

```jsonc
{
  "agents": {
    "defaults": {
      "heartbeat": {
        "every": "30m",
        "target": "last",
        "lightContext": true,
        "isolatedSession": true
      }
    }
  }
}
```

字段含义：

- `every` 控制心跳间隔，先用默认值，不要为了“主动”盲目缩短。
- `target` 控制投递目标，默认 `none`；要通知最近渠道才用 `last`。
- `lightContext` 控制是否轻量上下文，常驻巡检建议开启。
- `isolatedSession` 控制是否 fresh session，避免心跳携带完整主对话历史。
- `activeHours` 控制运行时间窗口，防止半夜打扰和无意义调用。
- `model` 控制心跳专用模型，简单巡检可用便宜模型。
- `includeReasoning` 控制是否投递 Reasoning，群聊里要谨慎，避免泄漏思考内容。

这里要注意一个反直觉点：`isolatedSession: true` 并不改变投递路由。它只是让心跳运行时不要带完整主对话历史；结果仍然可以按主 session 的 last route 发送。

> [!NOTE]
> Heartbeat 的核心不是“服务器还活着吗”，而是“Agent 到点醒来，看有没有值得提醒你的事”。

## 6. HEARTBEAT.md 要短

如果 workspace 里有 `HEARTBEAT.md`，默认 heartbeat prompt 会要求 Agent 读取它。它适合放小而稳定的检查清单。

示例：

```markdown
# Heartbeat checklist

- Scan inbox for urgent follow-ups.
- Check calendar items in the next 2 hours.
- If nothing needs attention, reply HEARTBEAT_OK.
```

官方还有几个细节：

- `HEARTBEAT.md` 缺失时，heartbeat 仍然可以运行，由模型判断要做什么。
- 文件只有空行和 Markdown 标题时，会跳过本次心跳，原因是 `empty-heartbeat-file`。
- 不要把密钥、token、手机号、私密凭据写进 `HEARTBEAT.md`，它会进入 prompt context。
- 如果清单变长，优先拆成 `tasks:` block 或改用 Cron，不要把 heartbeat 变成万能脚本。

`tasks:` block 适合把多个周期检查放在同一个 heartbeat 文件里：

```yaml
tasks:
  - name: inbox-triage
    interval: 30m
    prompt: "Check for urgent unread emails."
  - name: calendar-scan
    interval: 2h
    prompt: "Check upcoming meetings."

# Additional instructions
- Keep alerts short.
- If nothing needs attention, reply HEARTBEAT_OK.
```

OpenClaw 会只把到期任务放进本次 heartbeat prompt。没有任务到期时，会跳过模型调用，原因是 `no-tasks-due`。任务上次运行时间写在 session state 的 `heartbeatTaskState` 里，正常重启后仍可延续。

## 7. HEARTBEAT_OK 是投递协议

Heartbeat 的回复有一个约定：

- 没有事情需要提醒时，回复 `HEARTBEAT_OK`。
- Heartbeat run 中，`HEARTBEAT_OK` 出现在开头或结尾会被当作 ack。
- 剩余内容不超过 `ackMaxChars` 时，OpenClaw 会丢弃这条回复，不打扰用户。
- 有告警时，不要带 `HEARTBEAT_OK`，只返回告警文本。
- 普通聊天里误发单独的 `HEARTBEAT_OK` 也会被丢弃。

这就是为什么 heartbeat 可以高频运行但不制造消息噪音。

配置可见性时，把三件事分开：

- `showOk` 控制是否显示 OK ack，多数情况下关闭。
- `showAlerts` 控制是否显示非 OK 告警，需要提醒时开启。
- `useIndicator` 控制是否给 UI 状态面板发 indicator，需要可见状态时开启。

如果三者都为 false，OpenClaw 会直接跳过 heartbeat run，不产生模型调用。

## 8. Cron 是 Gateway scheduler

Cron 是 OpenClaw 的精确调度机制。它运行在 Gateway 里，不运行在模型里。

官方关键事实：

- Job 存在 `~/.openclaw/cron/jobs.json`，Gateway 重启不会丢失已有 job。
- 所有 Cron execution 都会创建 background task 记录，Cron 跑过什么，可以回头查。
- 一次性 `at` job 默认成功后自动删除，它更像提醒，不是长期任务。
- Cron 可投递到 channel、webhook 或静默，调度和通知是两件事。
- Cron 可指定 Agent、模型、thinking、工具范围，所以调度任务可以有独立运行姿态。

三种 schedule：

- `at`：一次性时间点，例如 `20m`、ISO 8601 时间。
- `every`：固定间隔，例如每 2 小时跑一次。
- `cron`：日历式排班，例如每天 7 点、每周一 6 点。

时区规则要写准：

- `at` 无时区时按 UTC 处理；需要本地时间就显式写清。
- `cron` 无时区时使用 Gateway host timezone；关键任务建议带 `--tz`。
- top-of-hour recurring 默认最多 stagger 5 分钟；要整点用 `--exact` 或 `schedule.staggerMs = 0`。

旧稿里的时区判断过粗。`at` 和 `cron` 的无时区行为不同。

## 9. Cron 的四种 Session 目标

Cron 不只有 main 和 isolated。

| 目标 | 上下文边界 | 适合任务 |
| --- | --- | --- |
| `main` | 进入下一次 heartbeat turn | reminders、system events |
| `isolated` | 在 `cron:jobId` dedicated session 运行 | 报告、后台杂务、重分析 |
| `current` | 创建 job 时绑定当前 session | 需要当前上下文的重复工作 |
| `session:name` | 使用持久命名 session | 连续积累上下文的流程 |

示例：一次性提醒进入主会话。

```bash
openclaw cron add \
  --name "Calendar check" \
  --at "20m" \
  --session main \
  --system-event "Next heartbeat: check calendar." \
  --wake now
```

示例：每天早上固定时间跑 isolated 简报。

```bash
openclaw cron add \
  --name "Morning brief" \
  --cron "0 7 * * *" \
  --tz "America/Los_Angeles" \
  --session isolated \
  --message "Summarize overnight updates." \
  --announce \
  --channel slack \
  --to "channel:C1234567890"
```

示例：每周深度分析，指定模型和 thinking。

```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
```

`main` 的本质是 enqueue system event，并可选择 `wake now` 或 `next-heartbeat`。`isolated` 的本质是专门起一个 `cron:jobId` agent turn，每次 fresh session，不污染主对话历史。

## 10. Delivery 不是由 Agent 自己兜底

Cron 的 delivery mode 有三种：

- `announce` 把 summary 投递到目标 channel，isolated job 默认是 announce。
- `webhook` 把完成事件 POST 到 URL，由外部系统接收完成事件。
- `none` 内部保留，不投递；不等于交给 Agent 自己外发。

对于 cron-owned isolated jobs，runner 负责最终投递路径。Agent 应返回 plain-text summary，由 runner 决定投递、webhook 或静默。`--no-deliver` 只是保持内部，不代表把外发责任交还给 Agent。

如果 isolated run 返回 silent token，例如 `NO_REPLY` 或 `no_reply`，OpenClaw 会抑制 direct outbound delivery，也会抑制 fallback queued summary。结果就是：这次 Cron 不会往聊天里发消息。

排障顺序：

```bash
openclaw status
openclaw gateway status
openclaw cron status
openclaw cron list
openclaw cron runs --id job-id --limit 20
openclaw system heartbeat last
openclaw logs --follow
openclaw doctor
```

## 11. Webhook 是外部事件入口

Cron 是“到点触发”。Webhook 是“外部系统有事就通知 OpenClaw”。

Gateway 可以暴露 HTTP webhook endpoints：

```jsonc
{
  "hooks": {
    "enabled": true,
    "token": "shared-secret",
    "path": "/hooks"
  }
}
```

常见 endpoint：

- `POST /hooks/wake`：enqueue system event 到 main session。
- `POST /hooks/agent`：运行 isolated agent turn。
- `POST /hooks/name`：mapped hook，通过配置把自定义 payload 转成 wake 或 agent action。

安全规则必须硬记：

- 请求要带 `Authorization: Bearer token`，也支持 `x-openclaw-token`。
- Query-string token 会被拒绝。
- Hook endpoint 应放在 loopback、tailnet 或可信反向代理后面。
- 使用专用 hook token，不复用 Gateway auth token。
- `hooks.path` 不能用根路径 `/`。
- 用 `hooks.allowedAgentIds` 限制可显式路由的 Agent。
- 不要轻易开放 caller-selected session key；需要时配合 allowed prefix。

> [!WARNING]
> Webhook 是执行入口，不是普通网页回调。公网暴露前先确认 token、反向代理、allowed agents 和 session key 约束都已收紧。

## 12. Internal hooks 不是 Webhooks

OpenClaw 还有内部 Hooks。它们不是外部 HTTP endpoint，而是在 Gateway 内部事件发生时运行的小脚本。

典型事件：

- `command:new`：用户发出 `/new`。
- `command:reset`：用户发出 `/reset`。
- `command:stop`：用户发出 `/stop`。
- `session:compact:before`：compaction 前。
- `session:compact:after`：compaction 后。
- `session:patch`：session 属性修改。
- `agent:bootstrap`：workspace bootstrap 注入前。
- `gateway:startup`：channel 启动且 hooks 加载后。
- `message:received`：任意渠道收到入站消息。
- `message:transcribed`：音频转录后。
- `message:preprocessed`：媒体和链接理解后。
- `message:sent`：出站消息送达后。

常见用途：

- `/new` 或 `/reset` 时保存 session-memory。
- 记录命令审计日志。
- Gateway 启动时运行 `BOOT.md`。
- Bootstrap 前注入额外 workspace 文件。

如果你要拦截 tool call、reply dispatch、subagent delivery、plugin install 等更深的生命周期，应看 Plugin hooks，而不是内部 Hooks。

## 13. Tasks 是台账，不是调度器

Background Tasks 记录 detached work。它不决定什么时候运行；Cron、Sub-agent、ACP、CLI agent commands 才会产生运行。

会创建 Task 的来源：

- ACP background runs 会创建 Task；Heartbeat turns 不会。
- Subagent spawns 会创建 Task；normal interactive chat turns 不会。
- 所有 Cron executions，包括 main-session 和 isolated，都会创建 Task；direct slash command responses 不会。
- CLI operations that run through Gateway 会创建 Task。
- Agent media jobs 会创建 Task。

Task 生命周期：

Task 生命周期从 `queued` 到 `running`，最后进入 `succeeded`、`failed`、`timed_out`、`cancelled` 或 `lost`。

Completion 是 push-driven。Detached work 完成后，可以直接通知目标 channel，也可以 wake requester session 或 heartbeat。不要把它设计成 Agent 每隔几秒 polling 状态；那通常是错误形状。

检查命令：

```bash
openclaw tasks list
openclaw tasks show task-id
openclaw tasks cancel task-id
openclaw tasks audit
openclaw tasks maintenance --apply
```

Terminal task records 默认保留 7 天后自动清理。

## 14. 怎么选机制

按需求选，不按名字选：

| 需求 | 机制 | 为什么 |
| --- | --- | --- |
| 每天 9 点准时发报告 | Cron | 时间点明确 |
| 20 分钟后提醒我 | Cron `--at` | 一次性提醒 |
| 每 30 分钟顺手看 inbox、calendar、notifications | Heartbeat | 周期醒来，自查是否需要提醒 |
| 每次工具调用前做安全拦截 | Plugin hooks 或 tool policy | 拦截点在工具生命周期 |
| `/reset` 时保存一份摘要到 memory | internal hook | 事件来自 Gateway 内部 |
| GitHub PR 创建后立刻 review | Webhook | 外部系统主动通知 |
| 重分析很重，不想污染主对话 | Cron isolated 或 sub-agent | fresh session，隔离上下文 |
| 只想知道后台跑过什么 | Tasks | Task 是 ledger，不是 scheduler |

一个稳妥默认：

- 私人 Agent：`Session: main`，Heartbeat 可用 `30m` 或 `1h`，`target` 用 `none` 或 `last`，Cron 只放明确时间点的提醒。
- 多用户 Agent：`Session: per-channel-peer`，Heartbeat 配 `activeHours + target none`，Cron 用 `isolated + explicit delivery`。
- 运营 / 监控 Agent：`Session: per-account-channel-peer`，Heartbeat 用 task block + `lightContext`，Cron 做 precise jobs + model/tool restrictions，外部事件优先 Webhook。

## 15. 常见误解

误解一：Heartbeat 越频繁越好。

不对。Heartbeat 是 full agent turn，会消耗 token。官方建议控制成本：`isolatedSession: true`、`lightContext: true`、更便宜的 model、小型 `HEARTBEAT.md`、必要时 `target: "none"`。

误解二：Cron 和 Heartbeat 都是定时任务，所以随便选。

不对。Heartbeat 适合上下文相关的周期检查；Cron 适合精确时间、一次性提醒、独立后台任务。

误解三：Reset 会删记忆。

不对。Reset 换当前 session transcript；memory 和旧 transcript 仍在。长期事实要写进 memory 或 workspace 文件。

误解四：Webhook endpoint 放公网就行。

不对。Webhook 是执行入口，应该放在 loopback、tailnet 或可信反代后面，并使用专用 token 和 agent allowlist。

误解五：Task 可以当成任务调度器。

不对。Task 是 ledger。它记录 detached work 的状态，不负责定时。

## 16. 给 Agent 的实践任务

把这组要求发给 OpenClaw Agent，让它检查自己的时间系统：

1. 运行 `openclaw status` 和 `openclaw sessions --json`，说明当前 session store 路径、最近活动、`dmScope`。
2. 检查 `session.reset` 配置，说明 daily reset、idle reset、manual reset 的实际边界。
3. 读取 `HEARTBEAT.md`；如果不存在、为空、过长或含敏感信息，请指出。
4. 检查 `agents.defaults.heartbeat` 和 `agents.list[].heartbeat`，说明 `every`、`target`、`activeHours`、`lightContext`、`isolatedSession` 是否合理。
5. 运行 `openclaw cron status`、`openclaw cron list`、`openclaw cron runs`，列出所有 job 的 schedule、timezone、session target、delivery mode、`agentId`、model override。
6. 检查是否存在多用户 DM 但仍使用 `main` session 的风险。
7. 检查 `openclaw tasks list` 和 `openclaw tasks audit`，说明后台任务是否有 `failed`、`timed_out`、`lost`。
8. 给出最小修改建议，不要直接改配置。

## 17. 本章自检

读完这一章，你应该能回答：

1. `sessionKey` 和 `sessionId` 的区别是什么？
2. `main` DM scope 为什么只适合单用户？
3. `/new`、`/reset`、daily reset、idle reset 分别什么时候换 session？
4. Heartbeat 为什么不是服务器健康探针？
5. `HEARTBEAT_OK` 为什么能避免消息噪音？
6. Cron 的 `at` 和 `cron` 无时区时分别怎么处理？
7. Cron `main` 和 `isolated` 的上下文边界有什么不同？
8. Webhook 和 internal hook 的边界是什么？
9. 为什么 Tasks 是 ledger，不是 scheduler？

> [!IMPORTANT]
> 过关标准：能用一句话说清“OpenClaw 用 Session 管上下文，用 Heartbeat 做周期自查，用 Cron 做精确调度，用 Webhook 接外部事件，用 Tasks 留后台台账”。

## 18. 接下来去哪

<Cards>
  <Card href="/docs/openclaw/understanding/09-channel-security" title="09 · Channel 与安全" description="继续看外部入口、DM 配对、群组门控、工具策略、沙箱和 Gateway 暴露面。" />
  <Card href="/docs/openclaw/understanding/07-multi-agent" title="07 · 多 Agent 协作" description="回到上一篇，理解多个 Agent 如何拆任务、共享上下文和避免互相污染。" />
  <Card href="/docs/openclaw/official/01-gateway-runtime/automation" title="官方教程：自动化" description="对照官方配置继续看 heartbeat、cron、webhook、task 和 hooks。" />
</Cards>

## 19. 官方资料

- [Session management](https://docs.openclaw.ai/concepts/session)
- [Session Management Deep Dive](https://docs.openclaw.ai/reference/session-management-compaction)
- [Heartbeat](https://docs.openclaw.ai/gateway/heartbeat)
- [Automation & Tasks](https://docs.openclaw.ai/automation)
- [Scheduled Tasks](https://docs.openclaw.ai/automation/cron-jobs)
- [Background Tasks](https://docs.openclaw.ai/automation/tasks)
- [Hooks](https://docs.openclaw.ai/automation/hooks)
- [Plugin hooks](https://docs.openclaw.ai/plugins/hooks)
