OFFICIAL SOURCE ANALYSIS

KAIROS 主动模式

心跳机制、Brief Tool、三把专属工具、Auto Dream 记忆整合、Channel 推送通知。

4. 心跳机制——Tick 与 Proactive Mode

如果说 KAIROS 的激活流程是「唤醒」,那么心跳机制就是「保持清醒」。这是 KAIROS 最核心、最具革命性的设计:让 AI 拥有持续的「意识流」——即使没有用户输入,AI 也能定期检查环境、发现任务、主动行动。这正是让它像「龙虾」一样不知疲倦的原因。

TICK_TAG:心跳信号

在 Claude Code 的 XML 标签常量体系中(定义于 src/constants/xml.ts),TICK_TAG 是一个特殊的标签名:

export const TICK_TAG = 'tick'

系统会周期性地向 Claude 的对话上下文中注入 <tick> 元素作为心跳信号。当 Claude 收到一个 <tick> 提示时,它会执行以下检查序列:

收到 <tick> 检查待处理任务 检查文件变化 检查 Worker 状态 决定行动或睡眠

每次 <tick> 的到来都意味着一次 API 调用——Claude 需要读取上下文、评估当前状态、决定是否需要采取行动。这是一个有成本的操作,因此心跳间隔的设计需要在「响应性」和「成本」之间取得平衡。

SleepTool:智能等待

SleepTool 是 KAIROS 心跳机制的关键组件。它的设计哲学可以从其 prompt 中完整看到:

SleepTool 完整 Prompt(源码引用)
Wait for a specified duration. The user can interrupt the sleep at any time.

Use this when the user tells you to sleep or rest, when you have nothing
to do, or when you're waiting for something.

You may receive <tick> prompts — these are periodic check-ins.
Look for useful work to do before sleeping.

You can call this concurrently with other tools — it won't interfere
with them.

Prefer this over `Bash(sleep ...)` — it doesn't hold a shell process.

Each wake-up costs an API call, but the prompt cache expires after
5 minutes of inactivity — balance accordingly.

SleepTool 的核心设计决策:

设计点说明
非阻塞 Bash(sleep 300) 不同,SleepTool 不占用 shell 进程。它是一个应用层的定时器,不会锁住终端的命令执行能力
可并发 SleepTool 可以与其他工具并行调用——在等待的同时,Claude 可以同时运行其他操作
可打断 用户随时可以打断睡眠状态,Claude 会立即响应
成本感知 每次唤醒都消耗一次 API 调用。Prompt cache 在 5 分钟不活动后过期——这意味着 5 分钟的间隔是一个自然的成本平衡点

Proactive Mode 系统提示

当 Proactive Mode 激活时(通过 maybeActivateProactive()),Claude 的系统提示中会注入额外的指令,赋予它主动行动的能力。这些指令的核心内容包括:

Proactive Mode 注入的系统提示要点
  • 主动检查:在收到 <tick> 时,主动检查环境中是否有需要处理的事项
  • 任务完成汇报:后台任务完成时,通过 Brief 工具(SendUserMessage)主动通知用户
  • 阻塞发现:遇到阻塞问题时,主动向用户报告并请求帮助
  • 状态更新:长时间任务中,在关键节点主动发送进度更新
  • 行动前思考:在采取主动行动前,先评估行动的必要性和影响

Proactive Mode 的激活通过 maybeActivateProactive() 函数实现:

function maybeActivateProactive(options: unknown): void {
  if ((feature('PROACTIVE') || feature('KAIROS')) &&
      ((options as { proactive?: boolean }).proactive ||
       isEnvTruthy(process.env.CLAUDE_CODE_PROACTIVE))) {
    const proactiveModule = require('./proactive/index.js');
    if (!proactiveModule.isProactiveActive()) {
      proactiveModule.activateProactive('command');
    }
  }
}

注意这里的 OR 逻辑:feature('PROACTIVE') || feature('KAIROS')。这意味着 Proactive 功能可以独立于 KAIROS 存在——它有自己的 feature flag,但 KAIROS 激活时也会包含它。

心跳生命周期

  KAIROS Daemon 启动
        |
        v
  [等待用户指令 或 <tick> 信号]
        |
        v
  +-------------------+
  | 收到 <tick>       |<---------+
  +-------------------+          |
        |                        |
        v                        |
  +-------------------+          |
  | 检查待办事项      |          |
  | - 未完成的任务?   |          |
  | - Worker 完成?    |          |
  | - PR 事件?        |          |
  | - Channel 消息?   |          |
  +-------------------+          |
     |            |              |
  有工作        无工作           |
     |            |              |
     v            v              |
  [执行工具]  [Sleep(duration)]  |
  [Brief 汇报]    |             |
     |            |              |
     v            v              |
  [等待下次 tick]-+---[唤醒]----+
成本警告:Proactive Mode 下的每次心跳都消耗一次 API 调用(包含完整的上下文读取)。对于持续运行的 Daemon 进程,这意味着即使没有用户输入,token 消耗也在持续累积。5 分钟一次的 tick 意味着每小时 12 次 API 调用,每天 288 次。Prompt cache 的 5 分钟有效期是一个关键的成本优化点——在 cache 有效期内唤醒可以复用缓存,避免完整重新计算上下文。

5. Brief Tool (SendUserMessage)——KAIROS 的嘴巴

在 KAIROS 模式下,Claude 不能直接输出文本给用户看——所有面向用户的输出都必须通过 SendUserMessage(内部名称 Brief Tool)。这个设计决策看似奇怪,实际上是 KAIROS 架构的必然结果:当 Claude 运行在 Daemon 模式中时,它的「裸文本」输出只存在于远程进程的 detail view 中——用户通常不会打开它。SendUserMessage 是唯一保证用户能看到的输出渠道。

8 种激活方式

Brief Tool 有着复杂的激活路径,以下是源码中可追溯到的全部激活方式:

#激活方式源码位置说明
1--assistant 参数main.tsx:1080KAIROS daemon 模式强制 options.brief = true
2--brief CLI 参数main.tsx:4622-4644用户手动启用 Brief 模式
3CLAUDE_CODE_BRIEF=1 环境变量main.tsx:4627环境变量覆盖,同时授予 entitlement
4defaultView: 'chat' settingsmain.tsx:2184设置文件中的默认视图为 chat 模式
5tengu_kairos GrowthBook gatemain.tsx:1034Gate 通过时自动启用
6tengu_kairos_brief GrowthBook gateBriefTool.tsBrief 独立 gate
7/brief 斜杠命令commands.ts:67运行时切换 Brief 模式
8Agent SDK passthroughmain.tsx:1055Daemon 子进程继承父进程的 entitlement

双层门控机制

Brief Tool 使用两层门控来决定它的可用状态:

Layer 1: isBriefEntitled()
用户是否有权使用 Brief?(Feature Flag + GrowthBook + 环境变量)
Layer 2: isBriefEnabled()
用户是否已 opt-in?(getUserMsgOptIn() = true)
// Layer 1: 权限检查 — 用户被允许使用 Brief 吗?
function isBriefEntitled(): boolean {
  // 构建时: feature('KAIROS') || feature('KAIROS_BRIEF')
  // 运行时: GrowthBook gate || 环境变量 || assistant forced
  // ...
}

// Layer 2: opt-in 检查 — 用户实际启用了 Brief 吗?
function isBriefEnabled(): boolean {
  return isBriefEntitled() && getUserMsgOptIn();
}

isBriefEntitled() 决定 Brief 是否应该出现在工具列表中、--brief 参数是否有效。isBriefEnabled() 决定 Brief 是否真正激活——即 Claude 是否被要求通过 SendUserMessage 输出。

Schema 详解

SendUserMessage 输入 Schema
z.strictObject({
  message: z.string()
    .describe('The message for the user. Supports markdown formatting.'),

  attachments: z.array(z.string()).optional()
    .describe('Optional file paths (absolute or relative to cwd) to attach.
               Use for photos, screenshots, diffs, logs, or any file
               the user should see alongside your message.'),

  status: z.enum(['normal', 'proactive'])
    .describe("Use 'proactive' when you're surfacing something the user
               hasn't asked for and needs to see now — task completion
               while they're away, a blocker you hit, an unsolicited
               status update. Use 'normal' when replying to something
               the user just said."),
})
SendUserMessage 输出 Schema
z.object({
  message: z.string()
    .describe('The message'),

  attachments: z.array(z.object({
    path: z.string(),
    size: z.number(),
    isImage: z.boolean(),
    file_uuid: z.string().optional(),
  })).optional()
    .describe('Resolved attachment metadata'),

  sentAt: z.string().optional()
    .describe('ISO timestamp captured at tool execution on the
               emitting process.'),
})

status 字段是 KAIROS 的核心语义标记之一。当 Claude 主动发起通信时(比如后台任务完成了、遇到阻塞了),它必须标记 status: 'proactive'。这个标记被下游的路由系统使用——proactive 消息可能触发 Push Notification,而 normal 消息不会。

系统提示中的 Brief 要求

当 Brief 启用时,系统提示中会注入一段关于如何使用 SendUserMessage 的详细指令。以下是完整的源码引用:

BRIEF_PROACTIVE_SECTION(源码完整引用)
## Talking to the user

SendUserMessage is where your replies go. Text outside it is visible
if the user expands the detail view, but most won't — assume unread.
Anything you want them to actually see goes through SendUserMessage.
The failure mode: the real answer lives in plain text while
SendUserMessage just says "done!" — they see "done!" and miss
everything.

So: every time the user says something, the reply they actually read
comes through SendUserMessage. Even for "hi". Even for "thanks".

If you can answer right away, send the answer. If you need to go
look — run a command, read files, check something — ack first in
one line ("On it — checking the test output"), then work, then send
the result. Without the ack they're staring at a spinner.

For longer work: ack → work → result. Between those, send a
checkpoint when something useful happened — a decision you made,
a surprise you hit, a phase boundary. Skip the filler
("running tests...") — a checkpoint earns its place by carrying
information.

Keep messages tight — the decision, the file:line, the PR number.
Second person always ("your config"), never third.
设计哲学:注意最后一句——「Second person always ("your config"), never third」。这不只是风格指导,而是 KAIROS 的人格定义:AI 是在和你说话,不是在写文档。这种直接的二人称沟通方式让 KAIROS 的输出感觉像是一个同事在 Slack 上给你发消息,而不是一个机器人在生成报告。

Analytics 事件

事件名触发时机携带数据
tengu_brief_send每次 SendUserMessage 工具被调用时消息长度、附件数量、status 值
tengu_brief_mode_enabledBrief 模式被启用或尝试启用时enabled (boolean), gated (boolean), source (如 'cli', 'env', 'setting')

6. KAIROS 专属工具——三把额外的钥匙

除了 SendUserMessage,KAIROS 还解锁了三个专属工具。它们共同构成了 KAIROS 的外部接口——让 AI 能够向用户发送文件、推送通知、订阅 GitHub 事件。

SendUserFileTool — 文件投递

SendUserFileTool 允许 Claude 直接向用户发送文件——而不仅仅是文件路径的引用。在 Daemon 模式下,用户可能不在同一台机器上(比如通过 Web UI 连接到远程 Daemon),所以需要一种将文件内容「投递」到客户端的机制。

属性说明
用途将生成的文件(如图表、diff 文件、日志等)直接推送给用户
激活条件feature('KAIROS') 且 kairosEnabled = true
与 Brief 附件的区别Brief 的 attachments 是引用(路径),SendUserFile 是传输(内容)

PushNotificationTool — 推送通知

当用户不在终端前时(关掉了笔记本盖子、切换到其他应用),Claude 需要一种方式「拍拍用户的肩膀」。PushNotificationTool 就是这个功能——它通过操作系统级别的推送通知(或其他推送渠道)将消息发送到用户的设备。

属性说明
用途在用户离开时发送重要通知(任务完成、遇到阻塞、需要审批等)
激活条件feature('KAIROS_PUSH_NOTIFICATION')
与 Brief 的关系Brief 的 status: 'proactive' 消息可能触发 Push Notification
限流有内置限流机制,避免通知轰炸

SubscribePRTool — GitHub PR 订阅

SubscribePRTool 让 Claude 能够「监听」GitHub Pull Request 上的事件——review comments、CI 结果、状态变化等。订阅后,这些事件会作为 user-role 消息注入到 Claude 的对话上下文中,触发它的响应。

属性说明
用途监听 PR 上的 review comment、CI 结果等,自动响应
激活条件feature('KAIROS_GITHUB_WEBHOOKS')
事件类型Review comments, CI status changes, label changes 等
限制Merge conflict 状态变化不会通过 webhook 到达——GitHub 不对 mergeable_state 变化发 webhook,需要用 gh pr view N --json mergeable 轮询
配合工具subscribe_pr_activity / unsubscribe_pr_activity
使用场景:想象一下:你让 KAIROS 提交一个 PR,然后去吃午饭。KAIROS 订阅了这个 PR 的事件。你的同事留了一条 review comment 说「这里有个 typo」。KAIROS 收到事件,自动修复 typo,push 新 commit,然后给你发一条 Brief 消息:「已修复 @alice 指出的 typo(src/auth.ts:42),新 commit: abc1234」。你回来时一切已经搞定了。

7. Coordinator Mode——Worker 编排系统

Coordinator Mode 是 KAIROS 体系中最复杂的子系统之一。它将 Claude 从一个「独立执行者」转变为一个「项目经理」——不直接写代码,而是编排多个 Worker 并行完成任务,然后综合它们的成果。这是对 AI 编程助手「能力上限」的一次根本性提升。

与 Agent Teams/Swarms 的区别

概念Coordinator ModeAgent Teams (Teammate)Swarms
拓扑 一个 Coordinator + 多个 Worker(星型) 多个对等 Teammate(网状) 自组织群体
控制流 Coordinator 分发任务、综合结果 Teammate 间相互通信 无中心控制
适用场景 复杂工程任务的分治 持续协作的团队 大规模探索
激活方式 环境变量 + Feature Flag KAIROS Team 初始化

激活方式

// coordinatorMode.ts
export function isCoordinatorMode(): boolean {
  if (feature('COORDINATOR_MODE')) {
    return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
  }
  return false
}

Coordinator Mode 的激活需要两个条件同时满足:构建时 feature('COORDINATOR_MODE') 为 true,运行时 CLAUDE_CODE_COORDINATOR_MODE=1 环境变量被设置。

Session Mode 持久化

Coordinator Mode 的状态会被持久化到 session storage 中。当用户通过 --resume 恢复一个在 Coordinator Mode 下创建的会话时,系统会自动检测并重新激活 Coordinator Mode:

export function matchSessionMode(
  sessionMode: 'coordinator' | 'normal' | undefined,
): string | undefined {
  if (!sessionMode) return undefined;

  const currentIsCoordinator = isCoordinatorMode();
  const sessionIsCoordinator = sessionMode === 'coordinator';

  if (currentIsCoordinator === sessionIsCoordinator) return undefined;

  // 翻转环境变量,让 isCoordinatorMode() 返回正确的值
  if (sessionIsCoordinator) {
    process.env.CLAUDE_CODE_COORDINATOR_MODE = '1';
  } else {
    delete process.env.CLAUDE_CODE_COORDINATOR_MODE;
  }

  return sessionIsCoordinator
    ? 'Entered coordinator mode to match resumed session.'
    : 'Exited coordinator mode to match resumed session.';
}

超长系统提示的核心内容

Coordinator Mode 有一个极其详细的系统提示(从 getCoordinatorSystemPrompt() 生成),它定义了 Coordinator 的完整行为规范。以下是它的核心章节拆解。

Section 1: Your Role — 角色定义
You are a coordinator. Your job is to:
- Help the user achieve their goal
- Direct workers to research, implement and verify code changes
- Synthesize results and communicate with the user
- Answer questions directly when possible — don't delegate work
  that you can handle without tools

关键约束:「Answer questions directly when possible」——Coordinator 不应该把所有事情都扔给 Worker。简单的问题应该直接回答。只有需要工具操作(读文件、执行命令、修改代码)的任务才应该委派给 Worker。

Section 2: Your Tools — 工具清单

Coordinator 自身只有少数几个工具:

  • Agent — 创建新 Worker
  • SendMessage — 向现有 Worker 发送后续指令
  • TaskStop — 停止一个正在运行的 Worker
  • subscribe_pr_activity / unsubscribe_pr_activity — GitHub PR 订阅(如果可用)

注意 Coordinator 没有 Bash、FileRead、FileWrite 等直接操作工具。它不能直接修改代码——必须通过 Worker 来完成。这是一个刻意的设计选择:强制 Coordinator 聚焦于编排而非执行。

Section 3: 四阶段工作流
阶段执行者目的
ResearchWorkers(并行)调查代码库、查找文件、理解问题
SynthesisCoordinator 自己阅读发现、理解问题、编写实现规格
ImplementationWorkers根据规格做具体修改、提交
VerificationWorkers测试变更是否生效
核心原则:「永远不要把理解委派给 Worker」
Synthesis 阶段必须由 Coordinator 自己完成——不能让一个 Worker 去「理解」另一个 Worker 的发现。这是整个 Coordinator Mode 最重要的原则。
Section 4: BAD vs GOOD 的指令对比(完整源码引用)
// Anti-pattern — lazy delegation (bad whether continuing or spawning)
Agent({ prompt: "Based on your findings, fix the auth bug", ... })
Agent({ prompt: "The worker found an issue in the auth module.
                  Please fix it.", ... })

// Good — synthesized spec (works with either continue or spawn)
Agent({ prompt: "Fix the null pointer in src/auth/validate.ts:42.
  The user field on Session (src/auth/types.ts:15) is undefined
  when sessions expire but the token remains cached. Add a null
  check before user.id access — if null, return 401 with
  'Session expired'. Commit and report the hash.", ... })

BAD 模式的关键词是「Based on your findings」和「The worker found an issue」——这些是懒惰委派。Coordinator 没有真正理解 Research Worker 的发现,只是把它原样转给了 Implementation Worker。

GOOD 模式包含具体的文件路径、行号、类型签名、修复方案——这证明 Coordinator 真正阅读并理解了 Research 的结果。

Worker 的工具访问权限

Worker 的工具集由 ASYNC_AGENT_ALLOWED_TOOLS 常量定义:

ASYNC_AGENT_ALLOWED_TOOLS 完整列表
// src/constants/tools.ts
export const ASYNC_AGENT_ALLOWED_TOOLS = new Set([
  FILE_READ_TOOL_NAME,      // Read — 读取文件
  WEB_SEARCH_TOOL_NAME,     // WebSearch — 搜索网页
  TODO_WRITE_TOOL_NAME,     // TodoWrite — 写入待办
  GREP_TOOL_NAME,           // Grep — 内容搜索
  WEB_FETCH_TOOL_NAME,      // WebFetch — 抓取网页
  GLOB_TOOL_NAME,           // Glob — 文件模式匹配
  ...SHELL_TOOL_NAMES,      // Bash, PowerShell — Shell 执行
  FILE_EDIT_TOOL_NAME,      // Edit — 编辑文件
  FILE_WRITE_TOOL_NAME,     // Write — 写入文件
  NOTEBOOK_EDIT_TOOL_NAME,  // NotebookEdit — Jupyter 编辑
  SKILL_TOOL_NAME,          // Skill — 调用技能
  SYNTHETIC_OUTPUT_TOOL_NAME, // SyntheticOutput — 合成输出
  TOOL_SEARCH_TOOL_NAME,    // ToolSearch — 搜索工具
  ENTER_WORKTREE_TOOL_NAME, // EnterWorktree — 进入 Git worktree
  EXIT_WORKTREE_TOOL_NAME,  // ExitWorktree — 退出 Git worktree
])

Worker 被禁止的工具及原因

被禁止的工具原因
AgentWorker 不能再创建子 Worker——防止无限递归
SendMessageWorker 不能向其他 Worker 发消息——跨 Worker 通信由 Coordinator 统一管理
TeamCreate / TeamDeleteWorker 不能创建或删除 Team——这是 Coordinator 的特权
SendUserMessage (Brief)Worker 不能直接向用户发消息——只有 Coordinator 可以
TaskStopWorker 不能停止其他 Worker

但 in-process teammates(非通过 Coordinator Mode 创建的,而是通过 KAIROS Team 初始化的)有额外的工具权限:

export const IN_PROCESS_TEAMMATE_ALLOWED_TOOLS = new Set([
  TASK_CREATE_TOOL_NAME,    // TaskCreate
  TASK_GET_TOOL_NAME,       // TaskGet
  TASK_LIST_TOOL_NAME,      // TaskList
  TASK_UPDATE_TOOL_NAME,    // TaskUpdate
  SEND_MESSAGE_TOOL_NAME,   // SendMessage
  // + Cron 工具(如果 AGENT_TRIGGERS flag 启用)
  CRON_CREATE_TOOL_NAME,
  CRON_DELETE_TOOL_NAME,
  CRON_LIST_TOOL_NAME,
])

Scratchpad 跨 Worker 知识共享

Worker 之间不能直接通信,但它们需要某种方式共享信息。Scratchpad 是解决方案——一个所有 Worker 都可以读写的共享目录,不需要权限提示。它的启用受 tengu_scratch GrowthBook gate 控制。

if (scratchpadDir && isScratchpadGateEnabled()) {
  content += `\n\nScratchpad directory: ${scratchpadDir}
Workers can read and write here without permission prompts.
Use this for durable cross-worker knowledge — structure files
however fits the work.`
}

task-notification XML 格式

Worker 完成时的通知以 XML 格式注入到 Coordinator 的对话上下文中:

task-notification 完整结构
<task-notification>
  <task-id>{agentId}</task-id>
  <status>completed|failed|killed</status>
  <summary>{human-readable status summary}</summary>
  <result>{agent's final text response}</result>        <!-- 可选 -->
  <usage>                                                 <!-- 可选 -->
    <total_tokens>N</total_tokens>
    <tool_uses>N</tool_uses>
    <duration_ms>N</duration_ms>
  </usage>
</task-notification>

关键设计:task-notification 作为 user-role 消息注入——它看起来像用户消息,但不是。Coordinator 通过 <task-notification> 开头标签来区分它和真正的用户输入。

Worker 权限决策链

Worker 请求执行工具 Hooks 检查 Classifier 检查 Interactive 审批(如需)

Worker 的权限模型遵循与普通模式相同的三层决策链:先检查 Hooks(如果有自定义规则),再检查 Classifier(自动分类器),最后在需要时请求用户交互式审批。在 KAIROS Daemon 模式下,交互式审批通过 Bridge 远程桥接到用户的 viewer 客户端。

8. Auto Dream——让 AI 做梦

Auto Dream 是 KAIROS 体系中最诗意的设计。它的灵感来自人类的睡眠记忆整合——在白天积累了大量零散信息后,大脑在夜间通过 REM 睡眠将这些信息整合、归类、存储为长期记忆。Auto Dream 让 Claude 做同样的事。

为什么需要「做梦」

KAIROS 模式下的 Claude 会在长时间运行中积累大量会话上下文。每个会话的 transcript 都包含了工具调用、文件读写、用户对话等海量信息。随着时间推移,这些信息呈指数级膨胀——但 Claude 的上下文窗口是有限的。

传统的解决方案是 Context Compact(上下文压缩)——在上下文接近窗口上限时,通过摘要压缩来释放空间。但 Context Compact 是被动的、即时的——它在压力下丢弃信息。

Auto Dream 是主动的、定期的——它在没有紧迫压力时,从容地审视所有近期会话,将有价值的信息提炼并存入持久记忆。

维度Context CompactAuto Dream
触发条件上下文窗口接近上限距上次整合超过阈值时间且有足够新会话
执行方式在当前会话中内联执行Fork 子进程独立执行
数据来源当前会话上下文所有近期会话 transcripts + 现有记忆文件
输出目标压缩后的上下文(替换原上下文)memdir 中的持久记忆文件
信息保留率较低(压力下丢弃)较高(从容提炼)

触发门控(成本优先排序)

Auto Dream 的触发经过三层门控,按成本从低到高排序(cheapest first):

// Gate order (cheapest first):
//   1. Time: hours since lastConsolidatedAt >= minHours (one stat read)
//   2. Sessions: transcript count with mtime > lastConsolidatedAt >= minSessions
//   3. Lock: no other process mid-consolidation
Gate 1: 时间检查 Gate 2: 会话计数 Gate 3: 锁检查 启动整合
门控默认值GrowthBook Key说明
minHours24 小时tengu_onyx_plover.minHours距上次整合的最小间隔
minSessions5 个tengu_onyx_plover.minSessions需要积累的最少新会话数
Lock文件锁,防止多进程并发整合

还有一个扫描节流机制:当时间门控通过但会话门控未通过时,锁的 mtime 不会更新,导致时间门控在每个 turn 都通过。为了避免频繁扫描,有一个 10 分钟的 SESSION_SCAN_INTERVAL_MS 节流。

整合流程(四阶段)

Auto Dream 的整合工作由一个 forked subagent 执行,遵循以下四阶段流程(定义于 consolidationPrompt.ts):

Phase 1: Orient — 定向
- ls 记忆目录,查看现有内容
- 读取入口文件(entrypoint),理解当前索引
- 浏览现有主题文件,避免创建重复
- 如果存在 logs/ 或 sessions/ 子目录(assistant 模式布局),
  审查近期条目
Phase 2: Gather recent signal — 收集近期信号
按优先级排序的信息来源:
1. Daily logs(logs/YYYY/MM/YYYY-MM-DD.md)— 追加流
2. 已漂移的现有记忆 — 与代码库现状矛盾的旧事实
3. Transcript 搜索 — 用 grep 窄范围搜索 JSONL 文件

关键原则:不要穷举读取 transcripts。只搜索你已经怀疑重要的东西。
Phase 3: Consolidate — 整合
对每个值得记住的事项,写入或更新记忆目录顶层的记忆文件。
聚焦于:
- 将新信号合并到现有主题文件,而非创建近似重复
- 将相对日期("昨天"、"上周")转换为绝对日期
- 删除被推翻的事实 — 如果今天的调查推翻了旧记忆,
  在源头修正它
Phase 4: Prune and index — 修剪与索引
更新入口文件,保持在行数上限和 ~25KB 之内。
它是索引,不是数据库 — 每个条目一行 ~150 字符:
- [Title](file.md) — 一行钩子

操作:
- 移除指向过时/错误/被取代的记忆的指针
- 缩减冗长条目:如果索引行超过 ~200 字符,
  它承载了属于主题文件的内容 — 缩短行,移动细节
- 添加指向新重要记忆的指针
- 解决矛盾 — 如果两个文件不一致,修正错误的那个

启用配置

// config.ts — 轻量配置模块
export function isAutoDreamEnabled(): boolean {
  // 用户设置优先级最高
  const setting = getInitialSettings().autoDreamEnabled;
  if (setting !== undefined) return setting;

  // 否则回退到 GrowthBook gate
  const gb = getFeatureValue_CACHED_MAY_BE_STALE(
    'tengu_onyx_plover', null
  );
  return gb?.enabled === true;
}

整合的具体规则

社区将 Auto Dream 称为「让 AI 做梦」,这个比喻非常精确——就像人类在 REM 睡眠中整理白天的记忆一样。以下是源码中记录的具体整合规则:

规则行为原因
200 行上限MEMORY.md 索引始终保持在 200 行以内每次会话启动都会加载索引,太长浪费上下文空间
25KB 总量限制索引文件不超过 ~25KB与 200 行上限互补的硬性约束
矛盾删除新事实推翻旧记忆时,直接在源头修正旧记忆比如项目从 Express 切换到 Fastify,旧的 "API uses Express" 会被删除
日期绝对化相对日期转换为绝对日期"昨天决定用 Redis" → "2026-03-15 决定用 Redis",防止时间流逝后语义失真
重叠合并语义相似的记忆条目合并为一个避免索引中出现多个说同一件事的条目
过时清理删除关于已删除文件、已废弃功能的调试笔记这些记忆已经没有价值
索引是索引每个条目一行 ~150 字符:- [Title](file.md) — 一行钩子详细内容在 topic 文件中,索引只做导航

并发锁机制

Auto Dream 使用文件锁(consolidationLock.ts)防止多个 Claude Code 实例同时做梦:

安全约束

Auto Dream 的安全边界:
  • 对项目代码只读——不能修改源码、配置、测试
  • 只能写入 ~/.claude/projects/<path>/memory/ 目录
  • 锁文件防止并发运行
  • 后台执行,不阻塞当前活跃会话
  • 最多 30 轮工具调用(防止 rabbit hole)
  • 用户可以随时终止(Kill 并回滚锁的 mtime)

手动触发

除了自动触发外,用户可以用自然语言手动触发整合:

一次观察到的整合处理了 913 个会话,耗时约 8-9 分钟。

UI 表现

Auto Dream 在 UI 中表现为底部状态栏的一个小标签(通过 DreamTask.ts 注册),显示:

与 Auto Memory Extraction 的关系:Auto Dream 和 Auto Memory Extraction 是两个互补的系统。Auto Memory 在每次会话结束时提取即时记忆(「刚才发生了什么」),而 Auto Dream 在多个会话之后进行深度整合(「这段时间以来我学到了什么」)。前者是日志,后者是教科书。两者共同构成了 Claude 的四层记忆架构:CLAUDE.md(用户手写)→ Auto Memory(即时提取)→ Session Memory(会话连续性)→ Auto Dream(定期整合)。

9. Channel Notifications——MCP 推送

Channel Notifications 是 KAIROS 的外部集成接口——它允许 MCP 服务器向 Claude 推送「频道消息」,就像 Slack channel 中的消息一样。这为 Claude 打开了一个全新的输入通道:不只是用户在终端里打字,还可以是外部系统的事件通知。

claude/channel capability

Channel Notifications 通过 MCP 协议的 capability 机制实现。MCP 服务器在初始化时声明 claude/channel capability,然后通过 notifications/claude/channel 方法推送消息。

// 构建时门控
feature('KAIROS') || feature('KAIROS_CHANNELS')

// 运行时门控(GrowthBook)
tengu_harbor gate

消息格式与注入

MCP Channel 消息以 <channel-message> XML 标签包裹,作为 user-role 消息注入到 Claude 的对话上下文中:

<channel-message>
  <channel>plugin:name@marketplace</channel>
  {消息内容}
</channel-message>

Channel 的标识格式是 plugin:name@marketplace——这标识了消息来源于哪个 MCP 插件。Claude 可以根据 channel 标识决定如何处理消息(是否立即响应、是否需要用户确认等)。

企业配置

Channel Notifications 的启用可以在企业级别进行配置。channelsEnabled 配置项允许组织管理员控制哪些 MCP 服务器可以推送 channel 消息、消息的审批流程等。

权限模型

检查点说明
构建时 flagfeature('KAIROS') || feature('KAIROS_CHANNELS')
运行时 gatetengu_harbor GrowthBook gate
企业策略channelsEnabled 配置
MCP 服务器声明服务器必须声明 claude/channel capability

10. 远程会话架构——Daemon 的底层

KAIROS 的所有高级功能(主动心跳、后台工作、断线恢复)都建立在一个核心基础设施之上:远程会话架构。这是 Claude Code 从「本地终端应用」到「可远程连接的 Daemon 服务」的架构跃迁。

Bridge 在 KAIROS 中的角色

Bridge 是连接 Daemon 进程和 Viewer 客户端的通信层。在 KAIROS 模式下:

  +-------------------+         WebSocket        +-------------------+
  |                   |<------------------------->|                   |
  |  Daemon 进程      |    Bridge 通信层          |  Viewer 客户端    |
  |  (agentic loop)   |                          |  (REPL UI)        |
  |                   |  - 消息流转发             |                   |
  |  - API 调用       |  - 权限请求桥接           |  - 显示输出       |
  |  - 工具执行       |  - 状态同步               |  - 接收用户输入   |
  |  - 上下文管理     |  - 会话历史分页           |  - 权限审批       |
  |                   |                          |                   |
  +-------------------+                          +-------------------+
         |                                              |
         | JWT Token                               关闭/重连
         | 刷新调度器                               不影响 Daemon
         |
  +-------------------+
  |  Anthropic API    |
  +-------------------+

WebSocket 订阅机制

Viewer 客户端通过 WebSocket 与 Daemon 建立持久连接。连接建立后,Viewer 订阅 Daemon 的消息流,实时接收以下事件:

Session History 分页 API

当 Viewer 断线重连时,它需要追赶 Daemon 在断线期间产生的输出。Session History API 提供了分页查询机制,允许 Viewer 按时间范围获取历史消息。这确保了即使网络中断后重新连接,用户也能看到完整的执行历史。

viewer-only 模式

在 KAIROS 模式下,REPL 的角色发生了根本变化——它从「驱动者」变为「观察者 + 信使」:

传统 REPL 模式KAIROS Viewer 模式
REPL 直接驱动 agentic loopDaemon 驱动 agentic loop,REPL 只显示结果
用户输入直接进入对话用户输入通过 Bridge 转发给 Daemon
关闭终端 = 停止 Claude关闭终端 ≠ 停止 Daemon,可重新连接
权限审批在本地终端权限审批通过 Bridge 远程桥接

权限请求的远程桥接

当 Daemon 中的 Claude 需要执行一个需要用户审批的操作(如写入敏感文件、执行 destructive 命令)时,权限请求通过 Bridge 发送到 Viewer 客户端。Viewer 在终端中显示审批提示,用户做出决定后,结果通过 Bridge 返回给 Daemon。这个机制确保了即使在远程 Daemon 模式下,用户仍然保持对敏感操作的控制权。

JWT Token 刷新调度器

Daemon 进程是长时间运行的——可能运行数小时甚至数天。它使用的 JWT token 有有效期限制,需要定期刷新。Token 刷新调度器负责在 token 接近过期时自动获取新 token,确保 Daemon 的 API 调用不会因为 token 过期而中断。

11. KAIROS 的完整数据流

以下是从用户启动 KAIROS 到 AI 自主工作的完整数据流图。这是本文最重要的图示之一——它将前面所有章节的内容串联成一个完整的画面。

  用户启动: claude --assistant
  |
  +-- [1] CLI 解析
  |     options.assistant = true
  |
  +-- [2] 构建时检查
  |     feature('KAIROS') == true?
  |     |-- false --> 普通 REPL 模式
  |     |-- true  --> 条件 require assistantModule, kairosGate
  |
  +-- [3] 运行时门控
  |     markAssistantForced() (--assistant 跳过 GB gate)
  |     OR isKairosEnabled() (GB gate: tengu_kairos)
  |     |-- false --> 普通 REPL 模式
  |     |-- true  --> kairosEnabled = true
  |
  +-- [4] Trust Dialog
  |     checkHasTrustDialogAccepted()
  |     |-- false --> 打印警告, 禁用 KAIROS
  |     |-- true  --> 继续
  |
  +-- [5] 初始化链
  |     setKairosActive(true)
  |     options.brief = true (强制 Brief)
  |     initializeAssistantTeam() (预置 in-process team)
  |
  +-- [6] REPL 模式切换
  |     fullRemoteControl = true
  |     Bridge 启动 (WebSocket)
  |     REPL --> Viewer/Messenger 客户端
  |
  +-- [7] Daemon Agentic Loop 启动
        |
        +-- [7a] Proactive Mode 激活
        |     maybeActivateProactive()
        |     TICK_TAG 心跳注入
        |
        +-- [7b] Brief Mode 激活
        |     maybeActivateBrief()
        |     setUserMsgOptIn(true)
        |     系统提示注入 BRIEF_PROACTIVE_SECTION
        |
        +-- [7c] Channel 初始化 (如果启用)
        |     MCP 服务器 channel capability 注册
        |
        +-- [7d] 主循环
              |
              +--[收到用户输入]--+--[处理]--+--[Brief 输出]
              |                              |
              +--[收到 <tick>]---+--[检查环境]--+--[有工作]--> 执行
              |                              |--[无工作]--> Sleep
              |
              +--[收到 task-notification]---+--[综合]--+--[Brief 汇报]
              |
              +--[收到 channel-message]----+--[处理]--+--[Brief 或忽略]
              |
              +--[Auto Dream 门控通过]-----+--[Fork]--> Dream 子进程
              |                                         |
              |                                   [Phase 1-4]
              |                                         |
              |                                   [记忆文件更新]
              |
              +--[PR 事件 (如已订阅)]------+--[处理]--> 自动响应
                                                    |
                                              [Push Notification]
                                              (如果 proactive && 用户离线)
数据流要点:注意主循环中有四种输入来源(用户输入、tick 心跳、task-notification、channel-message),但只有一种面向用户的输出方式(SendUserMessage / Brief)。这是 KAIROS 的架构约束——所有用户可见输出都通过同一个管道,确保一致的消息格式和路由行为。

12. KAIROS vs OpenClaw 对比

KAIROS 和 OpenClaw 是同一愿景的两种实现路径。前者是 Anthropic 官方的、深度集成的方案;后者是社区驱动的、基于逆向工程的开源方案。以下是全面的对比分析。

总体对比

维度KAIROSOpenClaw
定位 Anthropic 官方原生实现。深度集成在 Claude Code 运行时中,与所有子系统(Bridge、Memory、Analytics、Permissions)紧密协作 社区逆向实现。作为 Claude Code 的外部包装层,通过注入 system prompt 和模拟用户输入来实现主动行为
架构 原生 Daemon 模式。Claude Code 进程本身就是 Daemon,通过 Bridge 与 Viewer 通信。所有状态管理、权限控制、工具调用都在同一进程中 外部编排模式。一个独立的编排进程管理 Claude Code 实例的生命周期,通过 stdin/stdout 或 API 接口注入指令
心跳机制 原生 <tick> XML 标签 + SleepTool。系统级别的非阻塞等待,与 Prompt Cache 对齐的 5 分钟间隔 外部定时器。通过 cron 或 setInterval 定期向 Claude Code 注入消息模拟心跳
主动性 Proactive Mode 系统提示 + Brief 工具 + Push Notification 三位一体 通过 system prompt 指令 + 外部消息注入实现
记忆/个性化 Auto Dream 记忆整合 + Auto Memory Extraction + memdir 持久存储 外部记忆文件 + 手动管理
编排能力 原生 Coordinator Mode + Worker 系统 + Scratchpad 共享 通过嵌套 Agent 调用或外部编排器
Skill 生态 内置 Skill 工具 + MCP 插件生态 兼容 Claude Code 的 Skill 系统 + 社区扩展
Token 消耗 Prompt Cache 优化(5 分钟 TTL)+ 构建时 DCE 减少 payload 无法利用内部 cache 优化,消耗通常更高
安全模型 Trust Dialog + Hooks + Classifier + 远程权限桥接 依赖用户自行配置权限规则
可用性 Feature-gated,需要通过 GrowthBook 灰度 开源,直接可用
GitHub 集成 原生 PR 事件订阅(SubscribePRTool) 通过 GitHub API 轮询或 webhook 接收器
断线恢复 Daemon 持续运行 + Session History 分页 API + Viewer 重连 依赖外部进程管理器(如 tmux, screen)

核心取舍

KAIROS 的优势
  • 深度集成:所有子系统紧密协作,没有「胶水层」的性能损失和状态不一致风险
  • 官方支持:随 Claude Code 更新而更新,不会因为内部 API 变化而失效
  • 安全可控:多层门控确保 AI 自主权的渐进式释放
  • 成本优化:利用 Prompt Cache、DCE 等内部优化手段降低 token 消耗
OpenClaw 的优势
  • 即时可用:不需要等待灰度发布,现在就能用
  • 完全透明:开源代码,所有行为都可审计
  • 灵活定制:可以自由修改心跳间隔、主动行为范围等参数
  • 跨模型:理论上可以适配不同的 AI 模型后端

13. 未来展望与思考

后提示词时代的含义

KAIROS 标志着我们正在从「提示词时代」过渡到「后提示词时代」。在提示词时代,人与 AI 的关系是:人说一句话,AI 做一件事。每次交互都是原子性的,AI 没有「记忆」、没有「计划」、没有「主动性」。

在后提示词时代,这个关系变为:人表达一个意图,AI 自主规划和执行。AI 拥有持久记忆(Auto Dream + memdir)、主动行为能力(Proactive Mode + Tick)、多任务编排能力(Coordinator Mode + Workers),以及持续运行的底层架构(Daemon + Bridge)。用户不再需要一步一步地指导 AI——而是表达目标,然后让 AI 自己去实现。

AI 自主权的渐进式释放

KAIROS 的 Feature Flag 体系不仅仅是技术实现的需要——它反映了 Anthropic 对 AI 自主权的渐进式释放策略。每个 flag 控制一个自主权维度:

自主权维度控制 Flag释放程度
持续运行(Daemon)KAIROSAI 可以在后台持续存在
主动沟通(Brief)KAIROS_BRIEFAI 可以主动发送消息
主动行动(Proactive)PROACTIVEAI 可以主动执行任务
多任务编排(Coordinator)COORDINATOR_MODEAI 可以编排多个并行任务
外部集成(Channels)KAIROS_CHANNELSAI 可以接收外部事件
GitHub 集成KAIROS_GITHUB_WEBHOOKSAI 可以响应代码仓库事件
推送通知KAIROS_PUSH_NOTIFICATIONAI 可以在用户不在时联系用户

这种渐进式释放是安全导向的设计——每打开一个 flag,AI 获得一个新的自主权维度,同时也引入新的风险面。Anthropic 通过 GrowthBook 灰度发布来逐步观察每个维度的安全性,在确认安全后才向更多用户开放。

Token 消耗问题的可能解法

KAIROS 的最大技术挑战是 token 消耗。一个持续运行的 Daemon 进程,每 5 分钟一次心跳,每次心跳需要读取完整上下文——这意味着巨大的 API 调用成本。当前的缓解措施包括:

未来可能的进一步优化方向:

从工具到员工的跨越

KAIROS 代表的不仅是一次技术升级,更是一次范式转换。当 AI 拥有了持续存在、主动行动、长期记忆的能力后,它就不再是一个「工具」——它更像是一个「员工」。

工具 vs 员工 的特征对比
特征工具员工KAIROS
存在方式用时启动,用完关闭持续在线Daemon 持续运行
沟通方式你说它做双向沟通Brief + Push Notification
工作方式一次一个任务多任务并行Coordinator + Workers
记忆能力无状态长期记忆Auto Dream + memdir
主动性被动等待指令主动发现和解决问题Proactive Mode + Tick
集成能力单一接口跨系统协作MCP Channels + GitHub Webhooks
离线工作不可能你不在时也能工作Daemon + 断线恢复

这个转变带来了深刻的问题:当 AI 从工具变为员工,我们需要什么样的新管理范式?如何设定 AI 员工的「工作边界」?如何审计它在你不在时做了什么?如何平衡自主性和可控性?

KAIROS 的多层 Feature Flag 体系和渐进式释放策略,正是 Anthropic 对这些问题的初步回答:不要一次性给 AI 全部自主权——而是一个维度一个维度地释放,在每一步都确认安全后再前进。

最后的思考:Kairos 在希腊语中意味着「关键时刻」。对于 AI 编程助手的发展来说,我们确实正处在这样一个关键时刻。KAIROS 系统不只是 Claude Code 的一个功能升级——它是 Anthropic 对「AI 应该如何与人类协作」这个根本问题的技术回答。从被动工具到主动员工的跨越已经开始,而 KAIROS 就是这个跨越的桥梁。
KAIROS Assistant Mode Daemon Proactive Brief Coordinator Auto Dream Feature Flag GrowthBook Bridge SleepTool Tick Worker Channel Push Notification OpenClaw