Skip to main content
Glama

polyflow

智能体已经可以恢复已暂停的运行。但它无法告诉你恢复后的运行被允许做什么。

polyflow 是一个面向 AI 智能体的工作流引擎。智能体推理的是工作流,而不是下一个工具调用;polyflow 仅在该工作流通过模型检查后才予以接纳,然后持久地运行它,并一次向智能体下发一个工作指令。

它以 MCP 服务器形式发布,因此任何支持 MCP 的智能体——OpenWorker、Claude Code、Cursor——都可以使用它,而无需修改该智能体的核心。

实验性、未经证实、未经同行评审。该检查是一致性检查,而非证明,并且“穷尽”始终意味着在契约声明的有限域内穷尽。每个发现都是线索,而非结论。

循环

tools → observe → reason → WORKFLOW ──▶ polyflow admits it (or refuses)
                                            │
                        ┌───────────────────┘
                        ▼
        one work order  →  the agent runs the tool, through its own
                           permission gates, with its own credentials
                        →  workflow_report
                        →  next work order … until terminal

智能体从不决定接下来发生什么。它只推理如何完成一个指令——而这正是模型真正擅长的——并报告结果。排序、重试、定时器、重复抑制和终止条件都属于机器。

Related MCP server: nano-vm-mcp

为什么这样做,而不是常驻授权

如今,无人值守的自动化按动词获得批准:“允许 slack_send 到 #cs”,永远有效,无论模型决定用它做什么。当计划是每次运行都重新规划的散文式指令字符串时,这就是上限。

polyflow 批准的是计划。workflows/customer-brief/effect-invariants.mjs 保存了用户实际可以同意的句子:

{ name: 'no-post-without-prior-approval',
  pred: (path) => path.emitted.every((e, i) =>
    e.kind !== 'post_brief' || path.actionBefore('APPROVED', i)) }

启动时枚举契约声明域内每条可达的发射路径并检查它们。未通过的工作流不会被注册——不是被标记,而是不可运行:

[polyflow] admitted: customer-brief — paths explored: 5 · states seen: 10 · exhaustive within declared domains
[polyflow] REFUSED: unsafe-brief
[polyflow]   no-post-without-prior-approval

test/fixtures/unsafe-brief 是刻意制造的损坏孪生:它在进入审核时、在人类回答之前就发帖。它仍然调用 ask_user,仍然针对同一频道,仍然满足常驻授权。阅读 diff 的审查者很容易漏掉它。而门禁不会。

快速开始

npm install                    # pulls polygraph (polyrun) as a dependency
npm test                       # 14 tests, no API key, deterministic
node bin/polyflow-mcp.mjs      # MCP stdio server

与 OpenWorker 一起运行

先决条件: Node 22+(polyflow 使用 node:sqlite),并且已安装 OpenWorker。polyflow 本身不需要 API 密钥——它从不调用模型。

1. 注册它。 从 polyflow 目录:

node bin/polyflow-install.mjs --agent openworker/cowork --workspace acme
# --print shows the entry and the target path without writing anything

这会将 polyflow 条目合并到 OpenWorker 的全局 mcpServers 文件中——与 Connectors 页面编辑的是同一个文件(Windows 上为 %APPDATA%\coworker\mcp.json,其他系统为 ~/.config/coworker/mcp.json,$COWORKER_STATE_DIR 可覆盖两者)。它是合并而非替换,并且拒绝触碰无法解析的文件。

2. 重启 OpenWorker。 没有需要启动或监督的 polyflow 守护进程:OpenWorker 在会话打开时通过 stdio 生成 bin/polyflow-mcp.mjs,并在会话结束时将其拆除。运行状态保存在 POLYFLOW_DB 处的 SQLite 文件中,因此两者都能存活。

3. 检查它是否启动。 六个工具以 mcp__polyflow__* 形式出现。让智能体*“列出你可以运行的工作流”*——它应该返回 customer-brief、其 admitted: true,以及它被接纳时附带的五项保证。如果没有,Connectors 页面会显示持续错误,服务器的启动行(admitted: / REFUSED:)会输出到 stderr。

4. 使用它。 无需特殊操作:给智能体一个工作流覆盖的任务,它会自行拾取该工作流——这正是 FINDINGS-phase3.md 所衡量的。要为其安排定期任务,请创建一个普通的 OpenWorker 自动化,其指令描述该任务;工作流会在每次触发时按派生键重新附加,而不是重新开始。

区域。 --agent 是智能体类区域(这类智能体使用哪个工作流库),--workspace 是实例区域(这些运行属于谁)。一个 polyflow 安装可以服务多个工作区——为每个工作区注册一次,使用不同的 --workspace,指向相同的 POLYFLOW_DB 以共享存储,或使用不同文件以保持隔离。

添加你自己的工作流。 复制 workflows/customer-brief/ 并编辑六个文件(见下文 工作流)。重启服务器:未通过发射检查的工作流会在启动时被拒绝,并且根本无法启动,因此错误的编辑会响亮地失败,而不是在凌晨 3 点失败。

权限。 安装的条目有意设置 requires_approval: false——polyflow 工具不会触及机器之外的任何东西,运行的真实副作用是智能体自己的工具,这些工具保留自己的门禁。每次 workflow_report 都弹出提示会在智能体与其自身记账之间放置一个对话框。该条目还为只读工具声明了 tool_risk,在应用 upstream/0001-mcp-per-tool-risk-level.patch 时会被尊重,没有它则被无害地忽略。

polyrun 从何而来。 polyflow 在进程中嵌入 polyrun,从 node_modules/polygraph 解析,然后是同级检出;POLYFLOW_POLYRUN 可覆盖两者。

其他智能体宿主

polyflow 是一个普通的 MCP stdio 服务器,因此任何支持 MCP 的东西都可以使用它。安装程序为每个宿主写入正确的文件:

node bin/polyflow-install.mjs --host kiro          # ~/.kiro/settings/mcp.json
node bin/polyflow-install.mjs --host kiro --scope workspace   # ./.kiro/settings/mcp.json
node bin/polyflow-install.mjs --host claude-code   # ./.mcp.json
node bin/polyflow-install.mjs --host generic       # prints the entry, writes nothing

两个宿主形状不同,会打印而不是写入:

node bin/polyflow-install.mjs --host nemo      # YAML for a NeMo Agent Toolkit workflow
node bin/polyflow-install.mjs --host registry  # AWS CLI call to publish an Agent Registry record
  • Kiro / Kiro Crew 从 ~/.kiro/settings/mcp.json(用户)或 .kiro/settings/mcp.json(工作区,名称冲突时工作区优先)读取 mcpServers。Kiro Crew 的定期无人值守任务与 OpenWorker 的定时任务形状相同,这正是 FINDINGS-phase3.md 中结果所涉及的情况。

  • NVIDIA NeMo Agent Toolkit 通过其 mcp_client 函数组连接(需要 nvidia-nat-mcp)。打印的块声明了该组并将其添加到工作流的 tool_names 中。NeMo 本身也可以作为 MCP 服务器运行,因此 NeMo 工作流可以成为 polyflow 工作指令命名的工具之一。

  • AWS Agent Registry 是目录而非运行时:发布记录可让组织中的其他人和其他智能体发现 polyflow。记录可以从 HTTPS 端点同步,而 stdio 服务器无法提供该端点,因此打印的命令会创建手动 MCP 记录。

只有 OpenWorker 路径经过了端到端测试(见 FINDINGS-phase2.md)。其他路径是根据每个宿主的文档化配置格式构建的,尚未运行。

无论使用哪个宿主,环境变量如下:

env

含义

默认值

POLYFLOW_WORKFLOWS

工作流库目录

./workflows

POLYFLOW_DB

sqlite 路径

.polyflow/polyflow.sqlite

POLYFLOW_AGENT

智能体类区域

default

POLYFLOW_INSTANCE

实例区域(工作区)

cwd 基名

POLYFLOW_POLYRUN

polygraph 检出

../polygraph

工具

工具

作用

workflow_list

该智能体知道如何做什么,以及每个工作流被接纳时附带的保证

workflow_start

启动或重新附加——运行的标识从已验证的输入派生,因此夜间任务会恢复而不是重启,智能体也无法通过重命名来获得第二次运行

workflow_report

报告工具结果,接收下一个指令

workflow_state

状态 + 未完成指令,不改变任何内容

workflow_signal

带外事件;不适用的操作是可观察的拒绝

workflow_journal

每一步,接受或拒绝,附原因——也是有效的 Polygraph 轨迹语料库

区域

两个层级,不需要在 OpenWorker 中添加新字段:

  • 智能体区域 — 每个智能体类一个(openworker/cowork)。拥有工作流库:这类智能体知道如何做什么。映射到 ScheduledTask.agent。

  • 实例区域 — 每个正在运行的副本一个(workspace)。拥有活动运行及其日志。映射到 workspace,它已经是 coworker.memory.Scope.WORKSPACE。

实例 id 从 agent | instance | workflow | key 派生,这就是为什么启动和附加是同一个调用。

工作流

目录中的六个文件:

polyflow.workflow.json   name, area, tools{effect kind -> agent tool},
                         key{template,fields} — the run's identity, derived
contract.json            states, actions, finite data domain
machine.cjs              SAM v2 strict-profile module
effects.cjs              pure mapper: transition -> work orders
effects.manifest.json    completion actions + retry policy per kind
effect-invariants.mjs    what may be EMITTED, on every reachable path

使这对智能体有效的反转:在 polyrun 中,运行时执行效果。polyflow 没有凭据、没有连接器、没有权限引擎——智能体三者都有。因此,效果是交回的工作指令。处理器暂停;智能体认领指令,在其自己的门禁下运行工具,并报告。只有在那之后,完成动作才会分发。

持久性来自租约机制。待处理映射在内存中,因此崩溃会丢失 promise,租约过期,效果被重新认领,指令被重新提供——相同的意图 id,至少一次,由机器吸收。

测试证明了什么

✔ the admission gate certifies the demo workflow exhaustively
✔ workflow_list reports the guarantees the run was admitted under
✔ happy path: one order at a time, ending posted
✔ the run key is derived from input, not chosen by the caller
✔ an invalid key field is refused with an instruction, not honoured
✔ a finished run says so, and says not to start another
✔ start is idempotent: re-attaching returns the run in progress
✔ a denial is a result, not a fault — and no post is ever ordered
✔ zero tickets ends the run rather than posting an empty brief
✔ a duplicate report is refused, not double-executed
✔ an out-of-band action that does not apply is an observable reject
✔ a workflow that can post before approval is REFUSED and cannot be started
✔ a run outlives the process: restart re-offers the open work order
✔ initialize, tools/list, tools/call over stdio

重启测试才是关键:会话 1 将运行驱动到审批步骤然后死亡;会话 2 是另一个进程,没有对话、没有转录、没有重放——因为状态从一开始就不在消息中。它从原处精确地拾取运行,并且两个会话中恰好发生一次发帖。

尚未构建

  • 提升。 工作流在这里是手工编写的。计划是从日志中挖掘重复的运行形状,并提出一个机器供审查——从历史归纳,而非预见。除非被重用,否则为每个任务编写机器的成本高于它所替代的工具调用。

  • 版本控制。 polyvers 将更改后的工作流与进行中的运行进行门控;尚未接入。

  • 审计。 日志已经是轨迹语料库;针对它的 polyrun audit 尚未接入。

  • 需要核心更改的 OpenWorker 接缝: 将暂停的指令路由到收件箱,以及 ScheduledTask 上的 workflow_ref。见 FINDINGS-phase0.md。

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers