关于 wiff
wiff 是用普通 JavaScript 编写的多 Agent 工作流系统,适用于跨不同编码工具编排任务。持久化守护进程记录执行状态,支持中断后恢复已完成步骤。
主要功能
- 01以 JavaScript 编写工作流
- 02并行执行或按阶段串联 Agent
- 03持久化日志并恢复中断运行
- 04使用 Git worktree 隔离写入任务
- 05跨 Codex、Claude、Cursor 和 Kimi 调度
适用场景
- 01并行审查多个文件并修复问题
- 02在进程退出后继续未完成工作流
- 03从不同 MCP 客户端查看或取消运行
MCP 相关
wiff 通过 stdio MCP 桥接提供工作流启动、状态查询、等待、取消和模型查询工具。桥接连接到持久化的本地守护进程,运行可由不同 MCP 客户端管理。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
5收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| cwd | string | 否 | 工作流 Agent 继承的绝对工作目录。 |
| args | any | 否 | 作为全局 args 值提供给工作流的 JSON 输入。 |
| script | string | 否 | 内联工作流 JavaScript。不能与 scriptPath 同时使用。 |
| scriptPath | string | 否 | 工作流 JavaScript 的绝对路径或相对于 cwd 的路径。 |
| resumeFromRunId | string | 否 | 要恢复的现有运行 ID。Script 和 args 默认使用已存储的值。 |
详细介绍
wiff
与执行环境无关、确定性、可恢复的多 Agent 工作流——用纯 JavaScript 编写。就像 wf,但叫 wiff。
用一段简短脚本,将任务分发给一组 Agent,而不是寄希望于奇迹。你可以使用 agent()、/goal 阶段、parallel() 和 pipeline() 编写普通 JavaScript;运行时会在后台执行脚本,记录每一步,并且当一次运行中途终止时,可从断点恢复,无需为任何已完成的 Agent 重复付费。一次性 MCP 桥接程序会与持久运行的本地守护进程通信,因此,正在运行的工作流不会因启动它的 Codex、Claude Code、Cursor 或 cron 进程结束而中断;每个子任务则运行在 Codex、Claude、Cursor 或 Kimi 上。
export const meta = {
name: "audit",
description: "Audit files in parallel, fix confirmed issues in isolation",
phases: [{ title: "Audit" }, { title: "Fix" }],
};
phase("Audit");
const findings = await parallel(
args.files.map((file) => () =>
agent(`Audit ${file} for auth bugs`, {
key: `audit:${file}`, // stable key → free replay on resume
sandbox: "read-only",
schema: findingSchema, // structured JSON output
}),
),
);
phase("Fix");
return await parallel(
findings.filter((f) => f.real).map((f) => () =>
agent(`Fix: ${f.summary}`, {
key: `fix:${f.file}`,
agentType: "surgeon", // persona from .codex/agents/surgeon.md
isolation: "worktree", // own git worktree — parallel writes can't collide
sandbox: "workspace-write",
}),
),
);
当某个阶段必须持续工作,直到真正满足某个条件时,可以将其设为原生 Codex 目标:
phase("Verify and repair");
await agent("/goal Make the unit tests pass and verify the final run.", {
key: "tests-green",
sandbox: "workspace-write",
timeoutMs: 30 * 60 * 1_000,
});
wiff 会在该语句处暂停工作流,并在目标生效期间继续使用同一个 Codex 对话线程。只有工作线程将目标标记为完成后,才会启动下一阶段;目标受阻、暂停或受限时,任务会明确失败。
将持久偏好设置放入 ~/.wiff/config.json,并可选择在
<cwd>/.wiff/config.json 中设置项目级覆盖项:
{
"version": 1,
"instructions": "Verify before reporting success.",
"defaults": {
"model": "claude-sonnet-5",
"fallbackModels": ["gpt-5.6-sol"]
},
"rules": [
{
"name": "fix-until-green",
"when": { "phase": ["Fix", "Repair"] },
"goal": "Relevant tests must pass.",
"options": {
"model": "gpt-5.6-sol",
"effort": "high"
}
}
]
}
默认值会填充缺失的 Agent 选项;匹配规则属于明确的用户策略,会覆盖生成的工作流选项。指令会与任务一同注入;按顺序排列的备用模型可以跨后端使用;恢复运行时,适用的偏好变更会使缓存结果失效。
原因
目前没有与 harness 无关的工作流编排系统。 每种编码 harness 都有自己的多 Agent 方案——Claude Code 有 Workflow 工具,Codex 有子 Agent,Cursor 有自己的 Agent——但每种方案都与其 harness 绑定:运行会随应用关闭而终止,状态对其他工具不可见,而且只能在各自的聊天窗口中驱动。wiff 将编排从 harness 中抽离出来:由持久运行的本地守护进程负责执行和持久化磁盘状态,而每种 harness 都使用一个可丢弃的 stdio MCP 桥接。任何 MCP 客户端——Codex、Claude Code、Cursor、cron 任务——都可以启动、断开连接、监视、恢复或取消同一运行,而编排本身是脚本,不是对话。
临时的多 Agent 编排(“为此启动几个子 Agent”)也很实用,直到运行深入到 40 个 Agent,而某个环节出了问题。代码化工作流能带来:
-
确定性——编排是脚本,不是凭感觉。工作流代码中不包含时间、随机性、文件系统或网络;外部工作由 Agent 完成。
-
超越父进程的生命周期——关闭或终止启动工作流的 MCP 桥接不会中断运行。脱离终端运行的守护进程会继续执行,其他 harness 可以通过运行 ID 重新连接。
-
恢复,而非重试——每次 Agent 调用都会使用稳定的键和输入哈希记录到日志中。守护进程正常重启时,会自动恢复持久化的活动运行。守护进程或机器意外崩溃后,需显式恢复被安全中断的运行:输入未变的已完成 Agent 会立即从缓存重放,且不产生费用。在轮次中途被中断的 Agent 会使用此前尝试的对话记录摘要重新运行(“这是你之前完成的工作——请继续”),而工作树 Agent 会继承部分检出内容,不必从头开始。
这张截图展示的正是该功能:主进程在 synthesis 过程中被终止,恢复时,四个已完成的 Agent 在 0ms 内从日志中恢复——只有被中断的 Agent 重新运行。
-
失败即失败——Agent 被拒绝时,工作流会明确失败(
parallelSettled()可显式选择忽略)。不会有伪装成成功的静默null。 -
调度过程可见——Agent 在获得运行时槽位前会记录为排队状态,只有后端开始执行时才会记录为运行状态。排队时长和执行时长分别统计,而所有者心跳会让正在运行但已停滞的工作流显现出来。
-
在关键处隔离——
isolation: "worktree"会为每个执行写入操作的 Agent 创建一个全新的分离式 Git 工作树。干净的工作树会被删除;有未提交更改的工作树会保留,并列在运行记录中,供你检查或合并。 -
角色设定——
agentType: "reviewer"会将 Markdown 角色设定作为子 Agent 的开发者指令注入,并通过 frontmatter 设置模型、effort 和沙盒的默认值。
安装
Codex(插件:MCP 工具 + $workflow 工作流编写技能):
codex plugin marketplace add https://github.com/xxxoooxoxo/wiff.git
codex plugin add wiff@wiff
Claude Code(插件:MCP 工具 + 技能):
claude plugin marketplace add xxxoooxoxo/wiff
claude plugin install wiff@wiff
其他任何环境——该服务已发布到 npm(@xxxoooxoxo/wiff)和 官方 MCP 注册表(io.github.xxxoooxoxo/wiff),因此支持注册表的客户端可以按名称安装,其他客户端则通过 npx 运行:
npx -y @xxxoooxoxo/wiff # stdio MCP server
也可以从本地检出目录运行:
git clone https://github.com/xxxoooxoxo/wiff.git
codex plugin marketplace add ./wiff
codex plugin add wiff@wiff
然后启动一个新的 Codex 会话,调用随附的技能 $workflow,或直接提出请求:“将此任务作为可恢复的工作流运行。”
安装插件后,其五个工作流控制器工具会自动获批,因此无头运行和桌面运行不会停在 MCP 审批提示处。Agent 的文件系统访问权限仍由每次调用的 sandbox 控制。
在其他 harness 中使用(Claude Code、Cursor、任何 MCP 客户端)
Codex 插件只是打包形式。底层引擎是一个普通的 stdio MCP 服务,因此任何支持 MCP 的运行环境都可以编排 wiff 工作流。可以这样理解:编排器和工作器都可插拔——无论由谁驱动,每个 agent() 子进程都会根据其模型名称选择后端:gpt-*/o* 模型通过本地 codex app-server 作为原生 Codex 线程运行(gpt-6-astra 需要 Codex CLI >= 0.153.4);当前的 claude-fable-5-1、claude-fable-5、claude-opus-5、claude-sonnet-5 和 claude-haiku-4-5 模型,或不断变化的 fable/opus/sonnet/haiku 别名,会作为无头 claude Agent 运行;composer-* 和 grok-* 模型(包括 cursor-grok-* 名称)通过官方 Cursor SDK(@cursor/sdk)在进程内运行;kimi-code/* 模型则作为无头 kimi 进程运行。工作流可以自由混用这些模型(provider: "codex" | "claude" | "cursor" | "kimi" 可覆盖推断结果,WIFF_BACKEND 用于指定无法识别模型的备用后端)。在 Claude、Cursor 和 Kimi 后端上,workspace-write 需要 isolation: "worktree";Kimi 的 read-only 模式仅为建议,因为打印模式会自动批准工具,且没有 OS 沙箱。
无论使用哪种运行环境,机器都必须满足以下要求:Node >= 22;如果使用 isolation: "worktree",则需要 git;还需要安装 Agent 所用后端的运行时——Codex CLI
= 0.144.6 和/或已安装并完成身份验证的
claudeCLI、用于 Cursor Agent 的CURSOR_API_KEY,或已配置所需完整模型别名(例如kimi-code/k3)的kimiCLI。
Claude Code——上方的插件安装方式最简单。若要手动仅连接服务:
claude mcp add wiff -- npx -y @xxxoooxoxo/wiff
工具调用会经过 Claude Code 自身的权限系统;若要跳过每次调用时的提示,请在 .claude/settings.json 中允许这五个工具:
{ "permissions": { "allow": [
"mcp__wiff__workflow_start", "mcp__wiff__workflow_status",
"mcp__wiff__workflow_wait", "mcp__wiff__workflow_cancel",
"mcp__wiff__workflow_models"
] } }
Cursor / Windsurf / Claude Desktop——将服务添加到客户端的 mcp.json 中:
{
"mcpServers": {
"wiff": { "command": "npx", "args": ["-y", "@xxxoooxoxo/wiff"] }
}
}
非 Codex 宿主的说明:
- 状态是共享的。 每个执行环境都会读取和写入同一个
~/.wiff/runs/,因此,从 Codex 启动的运行可以通过 Claude Code 监视、取消或恢复(反之亦然),实时查看器也能看到所有内容。 - 执行由守护进程负责。 首次控制器调用会为每个 Wiff 状态根目录启动一个分离的守护进程。MCP 桥接程序可以退出,而不会影响正在进行的工作。默认情况下,守护进程在空闲 15 分钟后退出(可通过
WIFF_DAEMON_IDLE_MS覆盖此设置),并将其 pid、socket 和日志写入~/.wiff/daemon.json和~/.wiff/daemon.log。 - 控制器在发送工作前进行身份验证。
~/.wiff/control/下的一个权限为 0600 的密钥用于执行质询-响应握手。桥接程序会在传输工作流脚本或参数前证明守护进程的身份;守护进程也会对每个控制器请求进行身份验证。 - 所有权由操作系统租约保障,而非陈旧文件。 一个由密钥派生的环回端口会在守护进程的整个生命周期内保持占用。操作系统会将其授予唯一所有者,并在崩溃时自动释放;只有该所有者可以替换控制 socket 或锁元数据。如果派生出的端口与无关的本地软件冲突,请将
WIFF_DAEMON_OWNERSHIP_PORT设为一个可用的环回端口;Wiff 会报告确切的冲突,而不会将其误判为活动所有者。 - 首个控制器会提供守护进程环境。
PATH、后端凭据、CODEX_HOME、角色路径和 Wiff 默认值都会沿用启动守护进程的桥接程序环境。如果这些设置发生变化,请正常终止~/.wiff/daemon.json中记录的 pid(下次桥接程序启动时会恢复活动的持久化运行),或等待空闲 15 分钟后自动关闭。 - 将脚本约定纳入上下文。
$workflow技能仅会在 Codex 内自动加载。在其他执行环境中,请让模型参考plugins/wiff/skills/workflow/references/api.md(或将该技能复制到执行环境的技能/规则目录,例如.claude/skills/或 Cursor 规则),以便编写有效脚本。 - 角色会在每个执行环境中依次从
<cwd>/.codex/agents/和~/.codex/agents/解析;如需使用其他位置(例如共享的~/.claude/agents),请在服务端环境中设置CODEX_WORKFLOW_AGENTS_DIR。 workflow_start要求显式指定绝对路径cwd,因此服务端自身的工作目录不会影响结果。
面向 Agent
如果你是编码 Agent——通过 MCP 驱动 wiff,或参与此代码库开发——请阅读 AGENTS.md。其中介绍了五种工作流工具、容易让 Agent 出错的脚本编写规则(稳定的 key、使用 thunk 而非 promise、工作流代码中不得执行 I/O、并发写入时进行 worktree 隔离)、运行状态在磁盘上的存储位置,以及如何验证运行时变更。完整的脚本约定见API 参考。
工作原理
该插件通过 stdio MCP 桥接器提供五个工具:workflow_start、workflow_status、workflow_wait、workflow_cancel 和 workflow_models。桥接器通过经过身份验证的本地套接字连接到按需启动的分离守护进程。守护进程负责工作流管理器、后端、心跳和日志,因此关闭桥接器不会终止正在执行的工作。由密钥派生的环回租约会在进程的整个生命周期内,确保只有一个进程拥有 OS 级所有权;只有该所有者可以替换套接字和锁元数据。质询-响应握手会在脚本或参数通过连接传输前验证守护进程的身份。启动的工作流会在受限的 Node vm 中运行脚本(不允许导入、文件系统、Shell、网络、时间或随机数——所有这些操作都会抛出异常)。每次 agent() 调用都会根据模型名称或显式指定的 provider 路由到 Codex、Claude、Cursor 或 Kimi 后端;子级中会禁用递归编排。
运行的所有内容都会持久化在 ~/.wiff/runs/<runId>/ 下:
run.json status, phase, counters, failures, kept worktrees
script.js the exact source (reread on resume)
journal.jsonl every phase/log/agent event, with input hashes and token usage
agents/*.jsonl full per-child transcripts
worktrees/ isolated checkouts for agents that asked for them
即使启动它的主机已关闭,状态查询、等待和取消操作仍可正常使用。守护进程优雅重启时,会自动恢复正在运行的持久化工作流。守护进程意外崩溃时,后续启动的守护进程会采取保守策略,将运行标记为 interrupted,以避免产生重复副作用;任何客户端都可以从日志中恢复该运行。
完整的脚本约定请参阅API 参考,分阶段示例请参阅examples/verify-and-fix.js。
实时查看器
在本地 Web UI 中查看每次运行及其中的每个 Agent:
npx -p @xxxoooxoxo/wiff wiff-viewer # http://127.0.0.1:4979 (--port / --root to override)
# or from a checkout: cd plugins/wiff && npm run viewer
零依赖,只读访问运行文件,因此可以查看由任何进程拥有的运行。顶部的实时状态栏会显示每次运行中所有排队或正在运行的 Agent,包括排队时间,以及正在执行的 Agent 当前在做什么(从记录中截取其最新命令、文件编辑或思考内容)。所有者心跳会标记停滞的主机。下方显示按阶段划分的 Agent 卡片及其实时状态行、甘特时间线、令牌计数、保留的工作树,以及可点击打开并实时跟随内容的记录抽屉。目标节点会标记为排队中、活跃、已达成、失败或已重放。支持浅色和深色主题。
相关项目
- robzilla1738/Codex-Workflows — 面向 Codex 的工作流即代码运行时,专注于分发式评审。设计理念趋同,实现彼此独立。
- scasella/claude-dynamic-workflows-codex — 将 Claude Code 的动态工作流 DSL 重新托管到 GPT Agent 上,提供有会话状态的工作器和浏览器运行查看器。
- Codex 原生子 Agent — 非常适合交互式、由人工监督的任务分发;此插件面向自动化、可恢复且带日志的任务。
开发
cd plugins/wiff
npm test # unit tests (fake backend, no tokens spent)
npm run check # syntax check
npm run smoke # one real Codex child, end to end
传入已完成的冒烟测试运行 ID,即可验证跨进程恢复,而无需再次调用模型:
npm run smoke -- wf_<run-id>
Codex 会从带版本号的缓存中运行已安装的插件——编辑源代码后,请更新 .codex-plugin/plugin.json 中的版本号,并重新运行 codex plugin add wiff@wiff 以获取更改。
发布
将版本更新合并到 main 后,会自动将软件包发布到 npm,然后在 MCP Registry 中注册相同版本。请确保以下文件中的版本一致:
plugins/wiff/package.jsonplugins/wiff/.codex-plugin/plugin.jsonplugins/wiff/.claude-plugin/plugin.jsonserver.json及其 npm 软件包条目
如果这些版本或 npm/MCP 软件包名称不一致,发布工作流会在发布前失败。可以安全地重新运行:已存在于任一注册表中的版本会被跳过。
npm 发布使用可信的 GitHub Actions 发布器,而不是长期有效的令牌。@xxxoooxoxo/wiff 的一次性 npm 配置为:仓库 xxxoooxoxo/wiff、工作流 release.yml,并允许执行 npm publish。MCP Registry 也使用 GitHub OIDC 进行身份验证,无需仓库密钥。
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。