- 桌面应用
- 开发工具
【免费下载链接】EcoPaste
🎉跨平台的剪贴板管理工具 | Cross-platform clipboard management tool
本指南以 Trellis 多智能体协作运行时的核心参考文档 references/workers.md 为骨架,系统讲解"Worker 派生(spawn)"这一机制:如何把 peer agent 以独立子进程挂到 channel 上、如何用 Agent Card 定义角色、如何注入任务上下文、如何软/硬中断、以及 OOM 守护和收件箱调度。读完本文,你将能够写出可靠的 dispatcher(调度方)工作流——从唤醒 Worker、等待结果到排查"卡死"Worker,全部用事件日志而非进程状态作为事实依据。
什么是 Worker:channel 里的注册子进程
Trellis 的trellis channel是一个本地多智能体协作运行时,其完整定位与使用路由见技能索引 SKILL.md。在这套模型里:
- channel是一个持久的共享事件日志(
events.jsonl),所有协作都是向日志追加事件; - worker是一个注册的 child process(
claude或codex适配器),被附加到某个 channel 上; - supervisor(
channel __supervisor内部子命令 fork 出的进程)负责把 inbox 消息转发给 Worker,并把 Worker 的输出翻译回 channel 事件。
因此,Worker 的典型特征可以概括为三点:独立执行(peer agent 作为独立进程跑)、通过 channel 事件日志汇报(不是直接改你的终端)、收件箱驱动(inbox-idle,直到收到定向消息才被唤醒)。这与"一次性问答"的channel run(见 references/workflows.md 的 Pattern D)形成对比:需要多轮、可审计、可中途改道的协作,优先用持久 channel + spawn 的 Worker。
最小工作流:create → spawn → send → wait
文档开篇给出的标准四步流程,是理解一切后续命令的基石:
trellis channel create impl-task --by dispatcher --cwd /path/to/repo trellis channel spawn impl-task --provider codex --as codex-impl --timeout 30m echo "Implement the schema for table X per .trellis/.../prd.md" \ | trellis channel send impl-task --as dispatcher --to codex-impl --stdin trellis channel wait impl-task --as dispatcher --from codex-impl --kind done --timeout 30m各步职责:
create创建 channel(append 一个create事件),--by记录创建者身份,--cwd会被记录在 create 事件中;spawnfork 出 supervisor worker:它先发spawned,运行期间流式发progress,最终应以done、error或killed结束;send --to <worker>把任务指令投递进 Worker 的收件箱,唤醒这个此前一直 inbox-idle 的进程;wait阻塞监听事件流,直到匹配--from codex-impl --kind done的事件出现(默认--timeout 30m内)。
需要特别提醒的是完成信号的选择:技能索引与 command-reference.md 中 "tag vs kind" 一节强调——完成信号应该用--kind done/--kind turn_finished这类系统事件,不要依赖 Worker 里 LLM 手工打的自定义 tag。原因很实际:LLM Worker 经常把 tag 字符串写进正文而不是真的执行 CLI 命令,导致wait永远等不到。send命令本身没有--tag标志,每次send写入的都是message事件。
spawn核心参数详解
spawn是 Worker 生命周期里参数最密集的命令,文档列出的关键 flags 及其语义如下:
| 参数 | 作用 | 默认值/说明 |
|---|---|---|
--agent <name> | 加载.trellis/agents/<name>.md卡片 | 提供 provider/model/as/system prompt 默认值 |
--provider <claude\|codex> | 覆盖 agent 卡片中的 provider | 会对照 adapter 注册表校验;当前仅claude、codex两种(见 command-reference.md) |
--as <name> | channel 内的 Worker 句柄 | 默认取 agent 名称 |
--cwd <path> | Worker 工作目录 | 同时也是--file/--jsonl的 jail 根目录 |
--model <id> | 模型覆盖 | — |
--resume <id> | 续接已有 claude session / codex thread | — |
--timeout <duration> | 到期自动 kill | 形如30s/2m/1h |
--warn-before <duration> | supervisor_warning提前量 | 默认5m;0ms关闭 |
--file <path> | 把文件内容注入 system prompt(可重复,支持 glob) | 由context-loader组装 |
--jsonl <path> | Trellis jsonl manifest(每行{file, reason},可重复) | — |
--by <agent> | spawned事件的作者 | 默认$TRELLIS_CHANNEL_AS或main |
--inbox-policy <explicitOnly\|broadcastAndExplicit> | 收件箱唤醒策略 | 默认explicitOnly |
--idle-timeout <duration> | OOM 守护的空闲 TTL | 默认5m;0关闭 |
--max-live-workers <n> | spawn 时的存活 Worker 预算 | 默认6;0关闭 |
成功事件spawned会记录pid、provider、agent、注入的files以及展开后的manifests——这样后续任何观察者(spectator)都能审计当时这个 Worker 到底"看过什么上下文",这是 channel 事件模型天然的可审计性来源。
Agent Cards:用 Markdown 定义 Worker 角色
--agent <name>会解析到.trellis/agents/<name>.md。卡片文件名必须匹配[A-Za-z0-9._-]+。默认的 Trellis 安装自带两张卡片:
.trellis/agents/check.md—— 代码质量审查者(code-quality reviewer);.trellis/agents/implement.md—— 实现任务编码 Worker(coding worker)。
卡片是典型的 frontmatter + Markdown 正文结构:
--- name: check description: Code quality check expert. provider: claude ---- frontmatter 字段用于填充
spawn的默认值:provider、model、as; - Markdown 正文成为 Worker 的 system-prompt 角色描述;
- 卡片不会自动附加任务文件——上下文必须每次 spawn 显式注入(见下文)。
文档同时给出了一个重要的操作习惯:spawn 具名 agent 前,先检查项目卡片是否存在:
ls .trellis/agents sed -n '1,100p' .trellis/agents/check.md本仓库虽然没有.trellis/agents/目录,但.cursor/agents/下实际放着三个遵循同一套 frontmatter 约定的项目级 agent 卡片:trellis-check.md(质量检查)、trellis-implement.md(实现)、trellis-research.md(研究)。从中可以看到卡片不只是"角色提示词":trellis-check.md还在正文里声明了递归守卫(recursion guard)、hook 注入标记协议(<!-- trellis-hook-injected -->)、上下文加载顺序以及自修复(self-fix)职责;trellis-implement.md则明确禁止git commit/push/merge。这说明 agent 卡片是把"安全边界 + 角色 + 工作流"打包成一页文件的实践——spawn 前务必读一遍。
上下文注入:--file与--jsonl
Worker 是独立进程,看不到你终端的对话上下文,所以任务材料必须显式注入到它的 system prompt 里。两个 flags 在# CONTEXT FILES块下由context-loader组装:
--file <path>:可重复、支持 glob(*、**)。每个匹配到的文件都被读取并拼接进 system prompt;--jsonl <path>:可重复的 Trellis manifest,每行是{"file":"<path>","reason":"<why>"}。reason会以注释头(header comment)形式保留在对应文件内容上方——这是把"为什么引入这个文件"的意图也喂给 Worker 的手段。
loader 强制执行的限制(这是配置自动化时最容易踩的坑):
- 单文件 1 MB 硬上限,超限直接报错;
- 单文件 200 KB警告写入 stderr;
- 总组装上下文 500 KB警告写入 stderr;
- 路径穿越 jail:所有解析后的路径必须落在
--cwd之下。
完整示例——把 check agent 指向一个任务目录:
TASK=.trellis/tasks/05-13-example trellis channel spawn cr-example --agent check --provider codex --as check-cx \ --file "$TASK/prd.md" \ --file "$TASK/design.md" \ --file "$TASK/implement.md" \ --jsonl "$TASK/check.jsonl" \ --cwd "$PWD" --timeout 30mspawned事件会同时记录字面意义的files数组和由--jsonl展开的manifests,审计线索完整覆盖"Worker 实际看到了什么"。项目实践中,check.jsonl的用途可以在 trellis-check.md 里看到印证——检查代理被要求先读取<task-path>/check.jsonl及其中列出的每个文件再开始审查。
命名与路由:--as的双重含义与--all语义
--as在不同子命令里含义不同:
- 在
send/wait/interrupt中:说话人身份(产生事件的作者); - 在
spawn中:Worker 句柄——其他 agent 用--to寻址它。
当一个 channel 里有多个 Worker 或多个 provider 参与时,必须使用显式、稳定的名字,否则wait --from无法区分谁是谁:
trellis channel spawn cr-feature --agent check --as check-claude trellis channel spawn cr-feature --agent check --provider codex --as check-cx trellis channel wait cr-feature --as main \ --from check-claude,check-cx --kind done --all --timeout 15m这里--all有两个约束:
- 必须搭配
--from——语义是"阻塞直到列出的每一个 Worker 都产出了匹配事件"; - 超时退出码是 124,并向 stderr 打印
timeout: still waiting on ...(指名还有哪些 Worker 没到)。
这一模式在 workflows.md 的 Pattern C(并行审查)中是被完整使用的:同一 channel 里派生两个 check Worker(claude 一个、codex 一个),各自拿到同一批任务文件,最后--all等待两份结果。
软中断:channel interrupt
interrupt是协作式改道(cooperative redirect):它向事件日志追加一个kind: "interrupt"(reason 为"user")的事件,并且在适配器支持的情况下,向 provider 发起一次带替换指令的回合级中断(Claude 的/interrupt、Codex 的 turn cancel,见 command-reference.md)。
适用场景:希望 Worker丢掉当前回合、立刻按新输入行动,但保留会话(不丢失 session、上下文和线程)。
echo "Stop refactoring the parser — switch to fixing the failing test in src/foo.ts" \ | trellis channel interrupt impl-task --as dispatcher --to codex-impl --stdinFlags:
--as <agent>(必填)—— 调用者身份;--to <agent>(必填)—— 目标 Worker;--scope <project|global>—— channel 作用域(默认 project,解析当前 cwd 的项目 bucket);--stdin/--text-file <path>/[text]—— 替换指令正文来源(正文优先级:positional → stdin → text-file)。
追加的interrupt事件可以被下游wait/messages用--kind interrupt订阅——例如用于记录改道路径,或用它把其他 Worker 门控在一个协调者的纠偏之后。这里要再次强调"kind vs tag"的纪律:中断不是 tag,是专用命令产生的事件对(interrupt_requested/interrupted)。
如果只是低优先级提示、希望 Worker 下一个回合再处理,不要用 interrupt,发一条普通带 tag 的消息即可:
echo "Check this when you reach the next turn." \ | trellis channel send impl-task --as dispatcher --to codex-impl \ --stdin --tag question硬中断:kill+--resume
当 Worker 必须立刻停(跑飞循环、坏指令已在飞行途中、或适配器不理会interrupt)时使用kill。supervisor 的升级路径是SIGTERM → 8 秒宽限 → SIGKILL;只有在真的动用了 SIGKILL 时,CLI 才会写killed事件——保证事件日志如实反映发生了什么。
trellis channel kill impl-task --as codex-impl trellis channel spawn impl-task --as codex-impl --provider codex \ --resume "$(cat ~/.trellis/channels/<bucket>/impl-task/worker.session-id)" echo "STOP — new instructions: ..." \ | trellis channel send impl-task --as dispatcher --to codex-impl --stdinkillflags:
--as <agent>(必填)—— 指定要杀的 Worker 名(位置参数<name>是 channel 名,别搞混);--scope <project|global>;--force—— 立刻 SIGKILL(同时杀死内层 worker pid)。
副作用(side effects)是有意设计的分工:
- 清理:
pid、worker-pid、config、spawnlock这些 sidecar 文件; - 保留:
log、session-id、thread-id,用于取证和续接。
结论就是文档那句话:当interrupt无法收敛时,kill+--resume是保证能改道的路径——杀掉进程,用保存的 session-id 重新 spawn,再用send --stdin灌入新指令。这正好补上软中断不支持的"硬"场景。顺带一提,channel rm(在 command-reference.md 中)会先杀掉存活 Worker 再删除整个 channel 目录。
Worker OOM 守护:防止孤儿进程堆积
OOM 守护的目的是防止孤儿/空闲 Worker 越积越多、耗尽宿主机资源。它在每次spawn时运行,按"项目 bucket"维度执行两条策略:
- Idle TTL:清扫最后活动时间超过阈值的 Worker,默认
5m,0关闭; - Live-worker budget:若同一项目 bucket 里已存活的 Worker 超过 N 个,拒绝新的 spawn,默认
6,0关闭。
配置优先级(高 → 低):
- CLI flags:
spawn --idle-timeout、--max-live-workers; - 环境变量:
TRELLIS_CHANNEL_WORKER_IDLE_TIMEOUT、TRELLIS_CHANNEL_MAX_LIVE_WORKERS; .trellis/config.yaml中的channel.worker_guard配置节;- 内置默认值(
5m、6)。
操作面细节:
- 清扫/拒绝的通知写到 stderr(spawn 时就能看到"哪个空闲 Worker 被扫掉了""为什么新 spawn 被拒");
- 守护对临时 worker(ephemeral、
channel run的 Worker)一视同仁——同样受 idle TTL 和 budget 约束; - 审计当前状态:
channel list的WORKERS列 + 检查~/.trellis/channels/<bucket>/<channel>/下每个 Worker 的pid/worker-pidsidecar 文件。
诊断"幽灵 Worker"(列表里显示存活但 supervisor 已死)的标准动作见 progress-debugging.md:先cat "$CHAN/<worker>.pid"确认 supervisor PID,再ps -p验证,若确实死了就用trellis channel kill <name> --as <worker> --force清掉残留。
Worker 收件箱 API:唤醒、投递与消费
收件箱(inbox)是 Worker 赖以唤醒的 channel 表面,路由由两个旋钮控制:
旋钮一:收件箱策略(spawn --inbox-policy)
explicitOnly(默认):Worker 只在收到send --to <worker>或interrupt --to <worker>时被唤醒;broadcastAndExplicit:广播(不带--to的send)也能唤醒它。
旋钮二:投递模式(send --delivery-mode)
appendOnly:无论 Worker 状态如何,直接追加事件;requireKnownWorker:若--to指定的名字从未被 spawn 过,命令失败;requireRunningWorker:若指定 Worker 当前不在存活状态,命令失败。
更严格的投递模式能避免"调用方以为对方在跑,消息却悄悄丢失"的静默失败——这正是 dispatcher 自动化里的防呆设计。
收件箱相关的子命令(均以 command-reference.md 为准):
send <channel> [text]—— 追加message事件:--as <agent>(必填)作者;--to <agents>CSV,单个 → 字符串、多个 → 数组;省略即广播;--stdin/--text-file <path>/[text]正文来源;--delivery-mode <appendOnly|requireKnownWorker|requireRunningWorker>。
interrupt <channel> [text]—— 软中断改道(见上文)。wait <channel>—— 阻塞直到匹配事件到达:--as <agent>(必填),self作为过滤上下文;--from <agents>CSV 作者过滤;--kind <kind[,kind...]>CSV、OR 语义,支持interrupt、done、progress等(校验对照CHANNEL_EVENT_KINDS白名单,非法值会抛Invalid --kind '<x>'. Must be one of: …);--to <target>默认指向自身 agent(广播 + 显式给我的事件都算);--include-progress也监听 progress 事件;--all要求每个--fromagent 都匹配(超时退出 124);--timeout <duration>,如30s/2m/1h/1000ms。
messages <channel>—— 查看/过滤/跟踪事件流:--follow跟踪,--kind/--from/--to过滤,--raw每行一个 JSON,--no-progress隐藏进度噪声。
一个典型的 dispatcher 主循环:
# 1. 唤醒 Worker(严格投递:名字必须真实存活) echo "Run the failing test and report." \ | trellis channel send impl-task --as dispatcher --to codex-impl --stdin \ --delivery-mode requireRunningWorker # 2. 阻塞直到完成或失败 trellis channel wait impl-task --as dispatcher \ --from codex-impl --kind done,error --timeout 30m # 3. 读取最终答复 trellis channel messages impl-task --from codex-impl --last 1 --raw关于wait的底层语义,progress-debugging.md 补充了关键细节:wait从events.jsonl的 EOF 开始观察,唤醒条件是message/done/error/killed,progress仅在--include-progress时才参与;退出码约定为0匹配、124超时、1/2错误。另外注意一个脚本化红利:所有产生事件的子命令(send、interrupt、post、context add/delete、title set/clear、thread rename)都会把追加的事件以单行 JSON 打到 stdout——收件箱层完全可以用 shell/脚本做结构化对接。
结合项目的进阶阅读
如果你要在自己的项目里落地这套 Worker 编排,建议按以下顺序在仓库中对照阅读:
- references/workflows.md —— 六种官方协作模式:多轮头脑风暴(Pattern A)、implement/check 派发(Pattern B)、并行审查(Pattern C)、一次性 Worker(Pattern D)、forum 频道(Pattern E)、接管既有 thread(Pattern F);
- references/command-reference.md —— 全部子命令与 flag 的权威参考,含
CHANNEL_EVENT_KINDS白名单(spawned、killed、progress、done、error、interrupt_requested、turn_started、turn_finished、supervisor_warning等 21 种)与输出约定; - references/progress-debugging.md —— Worker 卡死的分步诊断(PID 检查 → tail worker log → 查 raw 事件)、
events.jsonl存储布局(~/.trellis/channels/<bucket>/<channel>/下的 sidecar 文件)、以及"永远用子命令而不是 grep 裸文件"的审计纪律; - trellis-check.md、trellis-implement.md —— 本项目里遵循同一 frontmatter 约定的项目级 agent 卡片实例,展示了卡片如何承载递归守卫、上下文加载协议与"自修复/禁止 commit"等约束。
把上面这些合起来,你就能构建出"事件日志驱动、可审计、可改道、有资源守护"的本地多智能体流水线:spawn 具名 Worker → 注入任务文件 → 定向唤醒 → 系统事件完成信号 → 必要时软/硬中断并用--resume续接 → 用messages --raw审计每一行真相。
- 桌面应用
- 开发工具
【免费下载链接】EcoPaste
🎉跨平台的剪贴板管理工具 | Cross-platform clipboard management tool
相关推荐
EcoPaste 中的 Trellis Channel Worker 深度指南:Spawn、Agent Cards、上下文注入与中断恢复
EcoPaste 中的 Trellis Channel Worker 深度指南:Spawn、Agent Cards、上下文注入与中断恢复 Trellis 的多智
桌面应用Trellis Channel Workers 完整实战指南:spawn 派生、Agent Cards、上下文注入与中断控制
Trellis Channel Workers 完整实战指南:spawn 派生、Agent Cards、上下文注入与中断控制 Trellis 的 channel
桌面应用Trellis Channel Workers 权威指南:spawn、Agent Cards、上下文注入与中断恢复机制(EcoPaste 实战)
Trellis Channel Workers 权威指南:spawn、Agent Cards、上下文注入与中断恢复机制(EcoPaste 实战) 导读 本文是
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考