系统性拆解 Claude Code 跨工具后台能力:Agent/Bash/Cron/TaskStop 等如何协同形成后台监听模式,理解其设计而非仅会用单一工具。
Claude Code 中并没有一个叫 "Background" 的工具。这是设计上的选择,不是疏漏。Background 行为分散在整个工具生态系统中:
仅看其中之一,你只能看到碎片。合在一起,才构成一个完整的系统。
每个普通工具都有一个核心行为:Read 读取文件、Bash 执行命令、Agent 委托给另一个 Claude。Background 不是另一种行为,而是一种执行模式。
同一个 Bash 或 Agent 操作可以以两种模式运行:
同步(默认):调用 → 阻塞 → 接收结果 → 继续对话。
后台(run_in_background: true):调用 → 立即返回 task ID → 主 Claude 继续运行 → 任务完成时 harness 发送通知。
如果把 Background 做成一组独立工具(BackgroundBash、BackgroundAgent 等),工具数量和决策负担都会翻倍。Claude Code 选择将现有行为参数化。这与 Grep 的 output_mode 和 Edit 的 replace_all 采用的是同一种正交设计:保持行为不变,通过字段切换模式。
与 Unix 的类比很有用。fork() 创建子进程,task ID 充当 PID 的角色,<task-notification> 类似 SIGCHLD。Claude Code 在 harness 层构建了一套进程管理系统,区别在于子进程可能是 shell 进程、另一个 Claude 或 WebSocket 连接。
Background Bash、background Agent、Cron 任务和 Monitor 实例都会获得一个 handle,供 harness 追踪:
Bash(command: "long-training.py", run_in_background: true) → task_id
Agent(prompt: "...", run_in_background: true) → task_id
CronCreate(cron: "*/5 * * * *", recurring: true, prompt: "...") → job_id
Monitor(command: "tail -f log | grep ERROR", persistent: true) → monitor_id
所有这些都可以通过同一个 TaskStop 接口停止。通知内容因类型不同而有所差异:
Bash 完成时包含输出文件路径。
Agent 完成时包含 agent 的结果。
Cron 使用其 prompt 启动新的一轮对话。
Monitor 将每行 stdout 或 WebSocket 事件转换为消息。
接口是统一的,而语义则保持专用性。这是好的 API 设计。
示例:background Bash 和 background Agent。
任务现在开始,稍后结束,harness 在完成时发送一个 <task-notification>。典型用途包括长时间测试、构建、训练运行、研究 subagent 或依赖安装。
Bash(command: "...", run_in_background: true) → task_id
(对话继续)
[task-notification: completed, output: /tmp/.../out.log]
Read("/tmp/.../out.log")
任务尚未启动。CronCreate 记录一个 prompt 和一个调度时间表;当时刻到来时,运行时用那个 prompt 启动新的一轮对话。这适用于提醒、五分钟后检查或明天早上的自我回顾。
关键区别在于:Type A 是一个已经在运行、等待结束的任务;Type B 是一个尚未启动、等待触发器到来的任务。
示例:Monitor,特别是 persistent: true。
监听器现在开始,没有固定终点(或在超时、流关闭或显式停止时结束),并为每个事件发送通知。典型用途包括跟踪日志中的错误、监视文件系统变化、订阅 WebSocket 或跟踪一个 PR 直到合并。
Background 应该建立一个简单的直觉:
当 harness 可以通知你时,不要 sleep。当任务已经在后台时,不要同步等待。
不要启动一个后台任务、sleep 一分钟,然后再读取其输出。harness 会通知你;继续工作,在通知后再读取输出。
不要反复 curl CI 端点然后接 sleep 60。选择与语义匹配的原语:
最终会退出的命令 → 带 until 循环的 Bash run_in_background;
事件流 → Monitor;
已知时刻的一次性检查 → CronCreate。
Claude Code 还会警告:开头的大段 sleep 命令会被阻塞。这是一个硬性系统约束,不仅仅是建议。工具层会主动推动 Claude 采用异步思维。
"task" 这个词被重载了:
Task 系列中的 task 可能尚未启动。Background task 是具体正在运行的进程或监听器。TaskStop 和之前的 TaskOutput 控制的是后者,而非待办事项。一个有用的记忆方法是:TaskCreate/TaskList/TaskGet/TaskUpdate 像是 CRUD 操作,而 TaskStop 是运行时控制。
想象用户想同时启动三件事:运行一个 15 分钟的测试套件、让一个 subagent 研究 auth 架构,以及启动开发服务器同时监视其日志。
Bash(command: "pnpm test:all", run_in_background: true) → task_test
Agent(prompt: "research auth architecture", run_in_background: true) → task_auth
Bash(command: "pnpm dev", run_in_background: true) → task_dev
Monitor(
command: "tail -f /tmp/dev.log | grep -E --line-buffered 'error|warn'",
description: "dev server errors"
) → monitor_dev
一条消息中的多个工具调用会并发启动。主 Claude 保持可对话状态。测试完成会产生一个 task notification;研究完成会产生另一个;dev 日志中的错误通过 Monitor 立即送达;TaskStop(task_dev) 停止服务器。传统的 REPL 执行会将这些任务串行化。Background 将它们转变为并行工作,由最长任务决定总耗时。
仅限会话:任务在会话结束时消亡。多日工作请使用系统 cron、launchd、GitHub Actions 或云调度器。
通知等待空闲:task notification 不会在 Claude 处理用户回合时中断它;会排队直到 REPL 空闲。
速率限制:高频 Monitor 流和累积的输出可以被停止或截断。强过滤器是必不可少的。
并发限制:Bash 和 Agent 任务在超过运行时主机相关限制(通常为 min(16, cpu-2))时会排队。
沙箱仍然有效:后台执行不会绕过沙箱。需要一个单独的、明确的 dangerous-sandbox 选项来改变这个边界。
最重要的命名决策是没有 BackgroundBash 或 BackgroundAgent。一个布尔值 run_in_background 表明 Background 是一种执行模式,而非新行为。
TaskStop 也是刻意设计成通用的。停止一个后台 Bash 任务不是 BashStop;停止一个 Agent 也不是 AgentStop。这个单一动词类似于 kill <pid>:无论 fork 了什么,相同的控制操作都会停止它。
旧的 TaskOutput 已被弱化,取而代之的是用 Read 读取输出文件。如果现有原语已经覆盖了某个能力,API 就不会再添加另一个动词。Cron 和 Monitor 在外部保持专用名称,而在内部共享任务基础设施。
描述承载了大部分规范性指导:
"Long leading sleep commands are blocked" 将一条建议升级为强制约束。Monitor 关于缓冲、速率限制和原始日志的警告对事件流做了同样的事情。这些描述是编码在各个工具中的跨工具契约。
最显著的设计信号是 Bash 和 Agent 使用同一个字段,但默认值相反:
Bash 的字段描述说仅在不需要立即获取结果时使用 background,承诺稍后通知,并警告不要追加 &。Agent 的描述解释了何时选择退出并在前台运行。同一个字段是一面镜子:默认值反映了每个工具的典型生命周期。
<task-notification> 中的输出路径自然地引导 Claude 用 Read 读取结果。Monitor 的 persistent 布尔值区分了有界监听器和会话级监听器。
Background 的 schema 层很薄,因为它修改的是现有同步行为而非替换它。重要的安全措施都在运行时级别:Monitor 的一小时超时、persistent 语义、cron 表达式验证、统一的 task ID、并发限制和沙箱执行。
这个"薄"本身就是核心设计选择的证据。如果 Background 是一种新能力,它就需要一个独立的 schema。因为它只是一种模式,现有的 command、prompt 和 cron schema 基本上够用;Background 添加的是一个标志或触发策略。
反轮询原则连接了 Bash、Agent 和 Monitor:不要轮询会通知你的任务,不要为已经在运行的 Agent 安排检查,也不要对一次性事件使用持续的 tail -f。
前十三篇文章介绍的工具大多都是同步的:Read、Edit、Write、Grep、Glob、WebFetch、WebSearch、交互工具等。Background 是隐藏的实现层,让这些空间原语能够扩展到异步协作。
Background 的优雅之处并不仅仅在于它让 AI 异步化。而是在于每一层都在强化参数化而非工具扩散:
命名:没有独立工具,只有 run_in_background 和统一的 TaskStop。
工具描述:反轮询、过滤器优先、仅会话级、通知契约都分布在相关工具中。
字段:Bash 和 Agent 有相反的默认值,因为它们的正常生命周期不同。
Schema:刻意保持轻薄,超时、持久化、并发和沙箱安全措施作为后盾。
缺失的 schema 本身就是证据。Background 不是一个新的 action;而是附加在现有 action 上的一个模式。没有它,Claude Code 只能是一个一次执行一个 action 的助手。有了它,Claude 成为一个多线程协作者,可以运行长时间任务、保持对话、响应事件并安排未来工作。
这个系列现在以一张完整地图收尾:用户对齐 → 定位 → 感知 → 执行 → 回退 → 通过 subagent、时间、事件流和后台执行扩展。目标从来不是枚举工具,而是将同样的四层解剖术应用于每一个工具。可复用的经验是克制:每个工具只做一件小事,组合起来就构成了协作系统。