14. Tasks、Automations 与后台工作
Craft 的并行能力有三个层次:单 turn 内的 background tool、多个 session 组成的 Task DAG、由事件/定时器触发的 Automation。它们没有另造一套“隐藏 Agent”,而是尽量复用 SessionManager 的 create/send/complete/persist 语义。
14.1 三者边界
Section titled “14.1 三者边界”| 能力 | 调度单位 | 生命周期 | 事实源 |
|---|---|---|---|
| Background task/shell | 一个 tool execution | 可跨 turn,通常属 session | backend + ManagedSession registry |
| Task | DAG node = child session | 一次 run,可暂停/恢复/验证 | task.yaml + run log + sessions |
| Automation | event matcher → action | 长期 workspace 规则 | automations config/history |
14.2 Task schema
Section titled “14.2 Task schema”单一来源:tasks/schema.ts。
id: release-audittitle: Release Auditgoal: Verify the release is safeacceptance_criteria: All critical checks passrunner: conductdefaults: model: claude-sonnet-4-6 permissionMode: allow-allmax_parallel: 3token_budget: 120000max_iterations: 2nodes: - id: inspect kind: session prompt: Inspect the diff - id: test kind: session prompt: Run relevant tests - id: review kind: session depends_on: [inspect, test] inputs: findings: ${nodes.inspect.output} prompt: Synthesize ${inputs.findings}主要字段:
- task:goal、acceptance、project/cwd、sources、skills、defaults、params;
- budgets:token、max parallel、max repair iterations;
- node:kind、prompt、model/connection/permission、labels/status;
- graph:depends_on、inputs、outputs;
- future/control:when、route、loop、for_each、aggregate、approval、retry、timeout、cache。
14.3 版本能力边界
Section titled “14.3 版本能力边界”0.11.2 的 schema 会解析 很多控制流 kind,但 Conductor v1 真正执行的是:
kind: session;depends_on;- params/inputs/node output 引用与可选 summarize;
max_parallel;- bounded retry;
- token budget;
- completion verification/repair frontier。
route/parallel/map/loop/approval/synthesize/... 等为前向兼容 round-trip,不能因 schema 接受就宣称 runner 已实现。源码在 tasks/schema.ts 明确标注。
14.4 验证 DAG
Section titled “14.4 验证 DAG”tasks/validate.ts 做:
- id/slug/重复 node;
- session node prompt 非空;
- depends_on/ref 目标存在;
- 将显式依赖与 input ref 依赖 materialize;
- cycle/self-cycle 检测并返回路径;
- 入口/出口与指标;
- unsupported execution kind 警告/错误。
一个隐藏依赖例子:node B 未写 depends_on: [a],但 input 引用 ${nodes.a.output},validator 必须把 A→B 加进图,否则 B 会过早 dispatch。
14.5 引用插值
Section titled “14.5 引用插值”tasks/refs.ts 支持:
${params.<name>}${inputs.<name>}${nodes.<id>.output}${nodes.<id>.output.<field>}Input 可写:
inputs: evidence: from: ${nodes.audit.output} summarize: true有 summarize callback 时先用 mini model 压缩上游大输出;没有则原样传递。引用既驱动 prompt 数据流,也驱动依赖图。
14.6 TaskRunner 架构
Section titled “14.6 TaskRunner 架构”TaskRunner.ts 依赖最小 ConductorSessionHost:
createSession()sendMessage()setSessionStatus()/setKanbanColumn()cancelProcessing()onSessionComplete()getSessionFinalText()getSessionWorkingDirectory()SessionManager 结构性满足这个接口;测试用 mock host,不必启动真实 SDK。
flowchart TD SPEC["task.yaml"] --> V["validate/materialize deps"] V --> R["ConductorRun"] R --> S["schedule ready <= max_parallel"] S --> CS["create child Session"] CS --> MSG["send interpolated prompt"] MSG --> DONE["onSessionComplete"] DONE --> OUT["save node output + run log"] OUT --> S OUT --> VERIFY["all done → orchestrator verify"] VERIFY -->|PASS| END["complete"] VERIFY -->|FAIL| REPAIR["reset repair frontier"] REPAIR --> S14.7 调度
Section titled “14.7 调度”scheduleReady():
- 只有 run status=running;
- 先检查 token budget;
- 计算 running count;
- 按 spec 顺序选
pending && all deps done; - 不超过
max_parallel,默认 4; - 异步 dispatch;
- 无 ready 时判断完成/失败/等待。
Node dispatch 创建普通 child session,带:
- parent/orchestrator id;
- task slug/run id/node id;
- cwd/project/source/skill;
- model/connection;
- kanban/status;
- node prompt + upstream inputs。
14.8 无人值守权限
Section titled “14.8 无人值守权限”Task child 没人守着弹窗。优先级:
node.permissionMode > task.defaults.permissionMode > AUTONOMOUS_DEFAULT_MODE = allow-all源码注释指出缺省不能是 ask(会挂),safe 又可能静默做不成工作。这是明确的产品取舍,不是普适安全答案。实际项目最好要求 task editor 总是持久化显式 default,并在高风险 cwd/source 上支持 sandbox/profile。
14.9 完成与输出
Section titled “14.9 完成与输出”SessionManager 统一发 SessionCompletionEvent。Runner:
- 找到 session 对应 node;
- 读取最终 assistant text 作为 node output;
- 写 output 文件;
- 将 child status/kanban 改 done 或 needs-review;
- 记录 token usage delta;
- append run log;
- 重新调度 dependent。
Token usage 是 session 累计值,所以 runner 记录上次观察值,只加 delta;否则重发 completion 会重复计费。
14.10 Retry
Section titled “14.10 Retry”Node retry 有 limit/backoff/when。dispatch error、timeout、agent error等映射为 failure class;在预算内将 node 重置 pending 并重发。超过 retry:
- node failed;
- 下游依赖不再 ready;
- run最终 failed,除非 trigger 语义允许(v1 受限)。
重试是同 node 新 child session或重新 dispatch,run log记录 attempt;不能覆盖旧失败证据。
14.11 Token budget
Section titled “14.11 Token budget”Run 累加各 child input+output token。检查发生:
- schedule 前:超预算不再派新 node;
- completion 时:刚完成 node 使预算突破,立即 pause;
- verification/repair 前:防继续消耗。
达到预算是 paused 而非强行把所有结果判 failed,用户可审查/调整。Run log写 budget-breach。
注意预算是软边界:一个已在运行的 turn 可能超过剩余额度;没有 provider token hard stop 就不能保证精确上限。
14.12 验证与修复
Section titled “14.12 验证与修复”全部 node done 后,不立即宣告 task 完成。若有 orchestrator 且 verifyOnComplete:
- run 进入
verifying; - 给 orchestrator发送 outputs + acceptance criteria;
- 监听 orchestrator completion;
- 解析最后一行
PASS或FAIL,可含nodes=a,b; - 无法解析时有限次数 re-ask,不消耗 repair budget;
- FAIL 且未超
max_iterations,计算 repair frontier; - 重置被点名 node及所有传递依赖的 done 状态;
- prompt 注入拒绝原因,重新执行;
- 达 cap/token budget 则 failed。
Repair frontier 而非全 DAG重跑,可复用仍有效的上游证据。
14.13 Pause、Resume 与重启恢复
Section titled “14.13 Pause、Resume 与重启恢复”Run log 是 append-only。重启后 hydrate():
- replay node started/completed/failed/retry/verification entries;
- done node只有 output 文件仍存在才复用;
- crash 时 running/cancelled node回 pending;
- 恢复 attempts/repairs/token;
- 继续 schedule。
这是 event sourcing 的轻量用法:task.yaml 是定义,run log 是执行事实,node output 是大 payload projection。
14.14 Automation 模型
Section titled “14.14 Automation 模型”AutomationMatcher event / cron / timezone optional conditions permissionMode / labels actions[] prompt webhook事件分两类:
- AppEvent:LabelAdd/Remove、PermissionModeChange、FlagChange、SessionStatusChange、SchedulerTick 等;
- AgentEvent:SessionStart、PreToolUse、PostToolUse 等 SDK bridge 事件。
当前 prompt handler 只处理 App events;Agent event 的旧 command execution 已移除,部分 matcher 只是匹配/记录 no-op。文档不能把所有 schema event都当成 prompt trigger 已完成。
14.15 AutomationSystem
Section titled “14.15 AutomationSystem”AutomationSystem 每 workspace 拥有:
- typed
EventBus; - config provider/watcher;
- PromptHandler;
- WebhookHandler;
- SchedulerService;
- event/history log;
- retry scheduler。
初始化订阅 handler、压缩旧 history、启动 cron。dispose 停 scheduler、handler 与 retry timers。
14.16 Metadata diff 产生事件
Section titled “14.16 Metadata diff 产生事件”Session metadata 更新前后 snapshot 比较:
- permission mode 变化;
- labels set diff;
- flag;
- status。
只有真实变化才 emit,避免保存同值触发自动化循环。setInitialMetadata() 初始化时不发事件,防启动加载所有 session 重新跑 automation。
14.17 Conditions
Section titled “14.17 Conditions”支持:
- time/day/timezone;
- state field from/to/equality;
- logical and/or/not。
Matcher 先匹配 event/cron,再评 conditions。条件求值必须纯且使用 event snapshot,而不是在 handler 执行很久后重新读已经变化的 session。
14.18 Prompt action
Section titled “14.18 Prompt action”PromptHandler:
- 对 AppEvent 找 matching matchers;
- 按 matcher 聚合 prompt actions;
- 用受限 event env 展开
$VAR/${VAR}; - 解析
@sourcementions; - 生成
PendingPrompt,携 automation name、session id、labels、permission、connection/model/thinking、Telegram topic等; - callback 给 SessionManager 执行。
SessionManager 可创建新 session或向指定 session发送,并写 triggeredBy 与 history。实际 send 仍走耐久主链。
14.19 Webhook action
Section titled “14.19 Webhook action”WebhookHandler:
- URL/method/header/body 展开;
- 使用 webhook-safe env,不暴露整个
process.env; - 安全校验目标;
- 多 action 并行;
- 立即最多 2 次 transient retry;
- 5xx/timeout 可入持久 deferred retry scheduler;
- URL日志 redaction;
- 每次结果写 history。
Webhook 是外发数据边界;配置验证要限制 header secrets、内网 URL/SSRF、body 大小和 event 字段泄漏。
14.20 History retention
Section titled “14.20 History retention”Automation history 使用 JSONL。启动时做两层保留/compaction,避免定时器长期运行后无限增长。History entry应包含 matcher/action、触发 event、started/completed、成功/失败和脱敏 endpoint,但不保存 secret header。
14.21 Background tasks/shells
Section titled “14.21 Background tasks/shells”Provider tool 可把长任务后台化,事件:
task_backgrounded(taskId, workflowId?)task_progress(elapsed)workflow_agent_completedtask_completed(status, outputFile, summary)
shell_backgrounded(shellId, command?)shell_killedSessionManager registry 把 toolUseId、task/shell id、turn关联;UI显示卡片/进度。keepBackgroundTasksAlive 决定 turn完成后是否保留 runtime;不保留时 cleanup 标 orphan/stopped。
后台完成发生在两 turn 之间时,backend background event sink唤醒 SessionManager;系统可发送 hidden nudge 让 Agent读取结果,而不伪装成用户 bubble。
14.22 三层编排如何组合
Section titled “14.22 三层编排如何组合”flowchart TD AUTO["Automation event"] --> ORCH["创建/唤醒 orchestrator session"] ORCH --> TASK["create_task / TaskRunner"] TASK --> C1["child session A"] TASK --> C2["child session B"] C1 --> BG1["background shell/tool"] C2 --> BG2["background workflow"] BG1 --> DONE["SessionCompletion seam"] BG2 --> DONE DONE --> TASK组合的关键是每层有明确 completion seam,不互相轮询 UI state。
14.23 风险
Section titled “14.23 风险”- Task schema 超前于 executor,用户可能误以为控制节点已工作;
- 默认 allow-all child 权限强,需要工作区级隔离;
- task token budget 是软上限;
- orchestrator verifying 时用户手动输入存在已知竞态;
- automation 自触发循环需 event diff/dedup/cycle guard;
- webhook SSRF/secret leakage 是高风险;
- background task在 agent/subprocess重启时的恢复语义不完全等同普通 session。
14.24 本章小结
Section titled “14.24 本章小结”TaskRunner 把 DAG node建成普通 session,从而免费获得模型、source、权限、消息和 UI;Automation 把长期事件变成 prompt/webhook,而 background task处理单 turn 内的长执行。三者的共同基座仍是 SessionManager 的生命周期和持久化。
下一章看另一个跨进程能力:内置浏览器如何在完整桌面中运行,又如何被远程 headless Agent 安全借用。