| 1 | import { PRODUCT_TERMS } from "@/lib/content/vocabulary"; |
| 2 | import { buildPageMetadata } from "@/lib/page-meta"; |
| 3 | |
| 4 | export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }) { |
| 5 | const { locale } = await params; |
| 6 | const isZh = locale === "zh"; |
| 7 | return buildPageMetadata({ |
| 8 | path: "/docs/fleet", |
| 9 | locale, |
| 10 | title: isZh ? "Fleet 与 Workflow · Codewhale 文档" : "Fleet & Workflow · Codewhale Docs", |
| 11 | description: isZh |
| 12 | ? "持久多 worker 运行的本地控制平面,以及可选的 Workflow 编排层。" |
| 13 | : "The local-first control plane for durable multi-worker runs, plus the optional Workflow orchestration overlay.", |
| 14 | }); |
| 15 | } |
| 16 | |
| 17 | export default async function FleetPage({ params }: { params: Promise<{ locale: string }> }) { |
| 18 | const { locale } = await params; |
| 19 | const isZh = locale === "zh"; |
| 20 | const bodyClass = isZh |
| 21 | ? "text-ink-soft leading-[1.9] tracking-wide" |
| 22 | : "text-ink-soft leading-relaxed"; |
| 23 | const vocabulary = PRODUCT_TERMS.map((row) => ({ |
| 24 | term: row.term, |
| 25 | definition: isZh ? row.long.zh : row.long.en, |
| 26 | })); |
| 27 | |
| 28 | return ( |
| 29 | <section className="space-y-10"> |
| 30 | <section id="overview" className="scroll-mt-32"> |
| 31 | <h2 className="font-display text-3xl mb-1">{isZh ? "Fleet 与 Workflow" : "Fleet & Workflow"}</h2> |
| 32 | <p className={`${bodyClass} mt-3`}> |
| 33 | {isZh |
| 34 | ? "Fleet 是面向持久多 worker 运行的本地优先控制平面。它不是独立的执行引擎:一个 Fleet worker 就是一次由 Fleet 启动并持久跟踪的 codewhale exec 无头运行。当工作需要重试、睡眠/重启后存活、远程执行、收据或可审计的台账时,使用 Fleet 而不是短寿命的 agent 扇出。" |
| 35 | : "Fleet is the local-first control plane for durable multi-worker runs. It is not a separate execution engine: a fleet worker is a headless codewhale exec run that the fleet launches and tracks durably. Reach for Fleet instead of short-lived agent fan-out whenever the work needs retry, sleep/restart survival, remote execution, receipts, or a ledgered audit trail."} |
| 36 | </p> |
| 37 | <div className="hairline-t mt-6"> |
| 38 | {vocabulary.map((row) => ( |
| 39 | <section key={row.term} className="py-4 hairline-b"> |
| 40 | <h3 className="font-display text-xl">{row.term}</h3> |
| 41 | <p className={`${bodyClass} mt-1 text-sm`}>{row.definition}</p> |
| 42 | </section> |
| 43 | ))} |
| 44 | </div> |
| 45 | </section> |
| 46 | |
| 47 | <section id="cli" className="scroll-mt-32"> |
| 48 | <h2 className="font-display text-2xl mb-1">{isZh ? "运行一次 Fleet" : "Run a fleet"}</h2> |
| 49 | <p className={`${bodyClass} mt-3`}> |
| 50 | {isZh |
| 51 | ? "Fleet 状态存放在工作区的 .codewhale/fleet.jsonl 台账中,worker 日志在 .codewhale/fleet/ 下。codewhale fleet resume <run-id> 是重启恢复命令:它重放台账、调和停止心跳的在途租约,且幂等——在管理进程退出、笔记本睡眠或运行时重启后都可以安全运行。" |
| 52 | : "Fleet state lives in the workspace's .codewhale/fleet.jsonl ledger, with worker logs under .codewhale/fleet/. codewhale fleet resume <run-id> is the restart-recovery verb: it replays the ledger, reconciles in-flight leases whose workers stopped heartbeating, and is idempotent — safe after a manager exit, laptop sleep, or runtime restart."} |
| 53 | </p> |
| 54 | <pre className="code-block mt-4">{`codewhale fleet init |
| 55 | codewhale fleet run tasks.json --max-workers 4 |
| 56 | codewhale fleet status |
| 57 | codewhale fleet inspect <worker-id> |
| 58 | codewhale fleet logs <worker-id> |
| 59 | codewhale fleet interrupt <worker-id> |
| 60 | codewhale fleet resume <run-id> |
| 61 | codewhale fleet stop --all`}</pre> |
| 62 | <p className={`${bodyClass} mt-3`}> |
| 63 | {isZh ? ( |
| 64 | <> |
| 65 | 注意两个同名状态面:TUI 里的 <code className="inline">/fleet status</code>(或{" "} |
| 66 | <code className="inline">/subagents</code>)只显示当前交互会话的子 Agent;shell 里的{" "} |
| 67 | <code className="inline">codewhale fleet status</code> 才读取持久 Fleet 台账。 |
| 68 | </> |
| 69 | ) : ( |
| 70 | <> |
| 71 | Two similarly named status surfaces exist: in the TUI,{" "} |
| 72 | <code className="inline">/fleet status</code> (or <code className="inline">/subagents</code>) |
| 73 | shows the sub-agents attached to the current interactive session; in a shell,{" "} |
| 74 | <code className="inline">codewhale fleet status</code> reads the durable Fleet ledger. |
| 75 | </> |
| 76 | )} |
| 77 | </p> |
| 78 | </section> |
| 79 | |
| 80 | <section id="profiles" className="scroll-mt-32"> |
| 81 | <h2 className="font-display text-2xl mb-1">{isZh ? "角色与 /fleet setup" : "Roles and /fleet setup"}</h2> |
| 82 | <p className={`${bodyClass} mt-3`}> |
| 83 | {isZh |
| 84 | ? "/fleet setup 打开一个渐进式向导,编写可复用的 agent 团队档案:一次只做一个选择——角色,然后是模型(可继承,或任何已配置提供商的具体模型),再是思考档位(inherit、off、low、medium、high、max 或 auto)——最后在审查页确认完整姿态(路由、思考、权限、工具、范围与审查策略)。档案可以写在项目级(.codewhale/agents/<role>.toml,随仓库走)或个人级($CODEWHALE_HOME/agents/<role>.toml,本机所有仓库可用);同名项目档案优先。档案的存储范围不会扩大运行操作的权限。" |
| 85 | : "/fleet setup opens a progressive wizard for authoring a reusable agent-team profile: one focused choice at a time — a role, then a model (inherit, or a concrete model from any configured provider), then a thinking tier (inherit, off, low, medium, high, max, or auto) — and a review of the full posture (route, thinking, permissions, tools, scope, and review policy) before anything is saved. Profiles live in project scope (.codewhale/agents/<role>.toml, travels with the repo) or personal scope ($CODEWHALE_HOME/agents/<role>.toml, available in every repo on the machine); a same-id project profile wins. Profile storage scope never widens the authority of a running operation."} |
| 86 | </p> |
| 87 | </section> |
| 88 | |
| 89 | <section id="workflow" className="scroll-mt-32"> |
| 90 | <h2 className="font-display text-2xl mb-1">{isZh ? "Workflow 编排" : "Workflow orchestration"}</h2> |
| 91 | <p className={`${bodyClass} mt-3`}> |
| 92 | {isZh |
| 93 | ? "普通多 Agent 工作不需要 Workflow:在 Operate 里直接发消息,需要并行、隔离或长时间工作时让 Codewhale 优先委派后台 worker 即可。只有当工作需要有序阶段、门禁、共享预算、回放或确定性汇总时才用 Workflow。Workflow 脚本是纯协调者:没有自己的文件系统和 shell,真正的工作由它启动的子 Agent 完成。脚本以编译专用的声明式 JS 子集编写,降低到类型化的 WorkflowSpec 后由 Rust 校验与执行;import、fetch、process、eval、async/await 等会产生副作用的写法会被编译器拒绝。" |
| 94 | : "Ordinary multi-agent work does not need Workflow: send normal messages in Operate and let Codewhale prefer background workers when parallelism, isolation, or duration makes delegation useful. Use Workflow when ordered phases, gates, shared budgets, replay, or deterministic fan-in matter. A Workflow script is a coordinator only: it has no filesystem or shell of its own; real work happens in the sub-agents it launches. Scripts are written in a declarative compile-only JS subset that lowers to a typed WorkflowSpec validated and executed by Rust; effectful constructs such as import, fetch, process, eval, and async/await are rejected by the compiler."} |
| 95 | </p> |
| 96 | <p className={`${bodyClass} mt-3`}> |
| 97 | {isZh |
| 98 | ? "默认校验边界:每次 Workflow 运行最多 100 个 worker Agent、最多 5 层递归 Fleet 环、循环必须声明 max_iterations、动态 expand 节点必须声明 max_children 和模板。这些是数量上限而非并发要求——一个合法的 100 Agent Workflow 仍会按配置好的 Fleet worker 池排水执行。Workflow JS 沙箱内单 run 最多 16 个并发存活 Agent、整个 VM 生命周期最多 1,000 次启动。" |
| 99 | : "Default validation bounds: up to 100 worker agents per workflow run, up to 5 recursive Fleet rings, loops must declare max_iterations, and dynamic expand nodes must declare max_children plus a template. These are population limits, not launch concurrency — a valid 100-agent workflow still drains through the configured Fleet worker pool. Inside the Workflow JS sandbox, one run keeps at most 16 concurrent live agents and at most 1,000 spawns over the VM lifetime."} |
| 100 | </p> |
| 101 | </section> |
| 102 | |
| 103 | <section id="source" className="hairline-t pt-8"> |
| 104 | <p className="text-sm text-ink-mute"> |
| 105 | {isZh |
| 106 | ? "来源文档:docs/FLEET.md, docs/WORKFLOW_AUTHORING.md · 更新时请同步修改 docs-map.ts。" |
| 107 | : "Source documents: docs/FLEET.md, docs/WORKFLOW_AUTHORING.md · Update docs-map.ts when changing."} |
| 108 | </p> |
| 109 | </section> |
| 110 | </section> |
| 111 | ); |
| 112 | } |
| 113 |