🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

智能体编排图 Epsirom/braid

DeepSeek Harnessv0.5.2
Epsirom0 天前有提交已提供中文文档扫描:含敏感能力

Braid 用图来协调多个 LLM 智能体。你定义每个智能体的任务,以及它需要哪些结果;Braid…

37.1/100
综合分
7
GitHub 星标
313
npm 周下载
—/5
用户评分

数据截至 2026/10/31 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add @chrok/braid
npm 源 · @chrok/braid 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · dev
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 0 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包@chrok/braid @ 0.5.2
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/26 17:43:59

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件
查看扫描证据(共 16 处,展示前 14 条)
  • 读取本地文件
    dist/workspaces.js:120
    await access(join(ancestor, ".git"));
  • 读取本地文件
    dist/workspaces.js:142
    return realpath(sourceRoot);
  • 读取本地文件
    dist/workspaces.js:148
    const commonDirectory = await realpath(resolve(sourceRoot, await git(sourceRoot, ["rev-parse", "--git-common-dir"])));
  • 读取本地文件
    dist/workspaces.js:149
    const cwdSuffix = relative(sourceRoot, await realpath(this.cwd));
  • 读取本地文件
    dist/workspaces.js:152
    const directory = await realpath(await mkdtemp(join(tmpdir(), "braid-workspaces-")));
  • 写入本地文件
    dist/workspaces.js:154
    await mkdir(hooksDirectory);
  • 写入本地文件
    dist/workspaces.js:173
    await copyFile(sourceIndex, index);
  • 读取本地文件
    dist/workspaces.js:188
    await access(join(sourceRoot, file));
  • 删除本地文件递归
    dist/workspaces.js:214
    await rm(directory, { recursive: true, force: true });
  • 删除本地文件
    dist/workspaces.js:218
    await rm(index, { force: true });
  • 删除本地文件
    dist/workspaces.js:219
    await rm(`${index}.lock`, { force: true });
  • 写入本地文件
    dist/workspaces.js:288
    await mkdir(workspace.workingDirectory, { recursive: true });
  • 删除本地文件递归
    dist/workspaces.js:438
    await rm(snapshot.directory, { recursive: true, force: true });
  • 执行外部命令固定命令
    dist/workspaces.js:476
    const child = execFile("git", [
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 协调多个智能体成图
  • 定义任务与依赖结果
  • 支持有界循环

TypeScript 运行时,跑 LLM 智能体图,支持有界循环、实时更新、隔离 Git 工作树和显式集成。核心不绑框架,带 OpenAI 兼容 runner,还有 Pi 和 DeepSeek Harness 插件。

v0.5.22026-10-25
· 变更内容 · 新功能 · 图里没有进行中的任务、但还有暂停的任务时,唤醒父级 完整变更日志:
v0.5.12026-10-20
· 变更内容 · 新功能 · 引导智能体不要设置 Braid 的时间预算和工具预算 · 让运行中的节点请求父智能体重新规划 · 重新规划请求改为报告发现,不再报告计划 · 修复 · Pi 和 DSH 中核心版本不匹配时快速失败 完整变更日志:
v0.5.02026-10-20
· 升级说明 · startBraid 现在遇到超过 nodeTimeoutMs 的可中断执行会暂停,不再判为失败,OpenAI 兼容适配器和核心默认的 60 秒节点超时也一样。想保留旧行为,传 onNodeTimeout: "fail"。 · 移除 Pi 阻塞模式:去掉 --braid-blocking 和 /braid:blocking。print 和 JSON 运行本来就会等后台任务结束。 · 见 0.4 → 0.5 迁移指南,含 TypeScript 接口变更。 · 变更内容 · 破坏性变更 · 移除废弃的 Pi /braid:blocking 命令 · 执行超过节点超时时暂停,不再判为失败 · 移除 Pi 阻塞模式 · 新功能 · 在运行中的执行内重试 Pi 模型瞬时错误 · 暂停和恢复运行中的执行 · 暂存已在运行执行的结果 · 修复 · 区分 Pi 循环交接与重试边 · 维护 · 将 0.4.0 标记为已发布;放宽 Pi 命令行测试超时 · 挂起测试的等待改为按时间而非按 tick 设上限 完整变更日志:
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
Braid Braid 用图来协调多个 LLM 智能体。你定义每个智能体的任务,以及它需要哪些结果;Braid 并行运行彼此独立的任务,再把它们的输出传给下一步。 你可以把它当作 TypeScript/JavaScript 库使用,也可以作为 Pi 或 DeepSeek Harness 的插件使用。 为什么用 Braid? 做代码审查时,可以让一个智能体检查正确性,另一个检查测试覆盖率。第三个智能体等这两个结果都出来,再写最终审查意见: flowchart LR correctness[Check correctness] --> review[Write final review] tests[Check test coverage] --> review 每个方框是一个任务(节点);每条箭头把一个结果传给依赖它的任务(边)。Braid 负责管理任务何时运行,并给每个智能体独立的上下文。对于会改代码的智能体,它还提供独立的 Git worktree;一个显式的 integrate 任务会把选中的改动应用到你的 checkout。 图还可以根据智能体的决策分支,在循环里重复工作直到某个决策结束循环,也能在运行时编辑、重跑或暂停。需要这些功能时,看可运行示例和执行控制。
展开完整文档(README 剩余 1 节)
Braid

Braid 用图来协调多个 LLM 智能体。你定义每个智能体的任务,以及它需要哪些结果;Braid 并行运行彼此独立的任务,再把它们的输出传给下一步。

你可以把它当作 TypeScript/JavaScript 库使用,也可以作为 Pi 或 DeepSeek Harness 的插件使用。

为什么用 Braid?

做代码审查时,可以让一个智能体检查正确性,另一个检查测试覆盖率。第三个智能体等这两个结果都出来,再写最终审查意见:

flowchart LR
correctness[Check correctness] --> review[Write final review]
tests[Check test coverage] --> review

每个方框是一个任务(节点);每条箭头把一个结果传给依赖它的任务(边)。Braid 负责管理任务何时运行,并给每个智能体独立的上下文。对于会改代码的智能体,它还提供独立的 Git worktree;一个显式的 integrate 任务会把选中的改动应用到你的 checkout。

图还可以根据智能体的决策分支,在循环里重复工作直到某个决策结束循环,也能在运行时编辑、重跑或暂停。需要这些功能时,看可运行示例和执行控制。

快速上手

| 你想在哪里用 Braid | 从这里开始 |
| 在自己的应用里 | 安装 @chrok/braid,并提供一个模型 runner |
| 在 Pi 里 | 安装 @chrok/pi-braid,获得后台智能体和实时面板;在 CI 里 pi -p "task" 会等待后台任务 |
| 在 DeepSeek Harness 里 | 安装 @chrok/dsh-braid,获得后台智能体和原生 Web 图面板 |

在你的应用里安装

需要 Node.js 22+,并使用 ESM 导入。核心包没有运行时依赖。

npm install @chrok/braid

把下面内容存成 example.mjs,然后运行 node example.mjs(不需要 API key):

import { braid } from "@chrok/braid";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

// A non-Git directory keeps this text-only example outside workspace management.
const cwd = await mkdtemp(join(tmpdir(), "braid-hello-"));
try {
const result = await braid({
goal: "Try one isolated invocation.",
nodes: [{ type: "execute", id: "answer", prompt: "Say hello." }],
edges: [],
}, {
cwd,
runner: async () => ({ output: "Hello from Braid." }),
});
console.log(result.terminalOutputs.answer.output);
// Hello from Braid.
} finally {
await rm(cwd, { recursive: true, force: true });
}

要接入真实服务商,请使用下面 API 示例中的适配器。安装并运行上面的示例不会发起模型请求。在 Git 检出目录中,Braid 会为每次执行新建一个工作树。只有显式的 integrate 节点才会把结果写回源检出目录。在针对仓库运行自定义适配器之前,请先阅读工作区行为。

在 Pi 中安装

需要 Pi 1.2.0 和 Node.js 22.19+:

pi install npm:@chrok/pi-braid

运行 /reload,然后让 Pi 用 Braid 分析任务。后台进度会自动显示在输入编辑器上方;打开 /braid 可查看完整的实时面板。用 /braid:review [target or focus] 启动有边界的并行审查/修复循环(最多三轮审查),用 /braid:clear 清除进度组件(再运行一次即可恢复)。npm 会安装精确匹配的核心依赖;已发布的版本无需检出。想试用当前源码检出,请按本地 Pi 安装指南操作。

Braid Pi 流程面板,含离线示例

这张截图使用真实的面板渲染器和模拟响应。后台任务、取消和本地安装请见 Pi 指南,已测试的版本请见兼容性。

在 DeepSeek Harness 中安装

需要 Node.js 22.19+ 和 DeepSeek Harness 0.2.0-rc.2,即固定的开发者预览宿主版本。DSH 支持从 Braid 0.3.1 开始;npm 徽章显示可用性。

dsh plugin --profile web add @chrok/dsh-braid

重启配置档,让 DSH 用 Braid 运行任务,然后在会话标题栏或右侧边栏打开 Braid。请把 web 换成你自己的配置档名称。npm 会自动安装匹配的核心依赖。工具、实时控制、Web 面板以及从本地检出安装,请见 DSH 指南。

API

安装包之后,用一次调用提交图;配置和可信服务商适配器与图数据分开:

import { braid } from "@chrok/braid";
import { createOpenAICompatibleRunner } from "@chrok/braid/adapters/openai";

const apiKey = process.env.OPENAI_API_KEY;
const model = process.env.BRAID_MODEL;
if (!apiKey || !model) throw new Error("Set OPENAI_API_KEY and BRAID_MODEL");

const result = await braid({
goal: "Assess a proposed change and give a recommendation.",
nodes: [
{
type: "decision", id: "route", prompt: "Choose a brief answer or a detailed assessment.",
choices: ["brief", "detailed"], model: process.env.BRAID_ROUTER_MODEL ?? model,
},
{ type: "execute", id: "benefits", prompt: "Assess the potential benefits." },
{ type: "execute", id: "risks", prompt: "评估风险与未知项。" }, { type: "execute", id: "answer", prompt: "结合已有上下文给出建议。" }, ],
edges: [
{ from: "route", to: "answer", choice: "brief" },
{ from: "route", to: "benefits", choice: "detailed" },
{ from: "route", to: "risks", choice: "detailed" },
{ from: "benefits", to: "answer" },
{ from: "risks", to: "answer" },
],
}, {
runner: createOpenAICompatibleRunner({ apiKey }),
defaultModel: model,
maxConcurrency: 4,
nodeTimeoutMs: 60_000,
graphTimeoutMs: 300_000,
onEvent: event => console.log([${event.type}], event),
});

console.log(result.status, result.terminalOutputs);

detailed 路线会并发启动 benefits 和 risks。brief 路线跳过这两个节点,把它们的未激活状态向下传播,只带 route 的输出运行 answer。整张图没有专门的分叉、分支或汇合节点。

图 schema

type NodePrompt = string | {
template: string;
variables: Readonly<Record<string, string>>;
};
type BraidInputNode =
| { type: "execute"; id: string; prompt: NodePrompt; model?: string;
workspace?: "read-only" | "worktree"; notifyOnCompletion?: boolean;
requireSuccess?: boolean; pauseAfter?: boolean; maxRuns?: number }
| { type: "decision"; id: string; prompt: NodePrompt;
choices: readonly string[]; model?: string; workspace?: "read-only" | "worktree"; notifyOnCompletion?: boolean;
requireSuccess?: boolean; pauseAfter?: boolean; maxRuns?: number }
| { type: "merge" | "integrate"; id: string; prompt?: NodePrompt; model?: string;
notifyOnCompletion?: boolean;
requireSuccess?: boolean; pauseAfter?: boolean; maxRuns?: number };

type Edge = { from: string; to: string; choice?: string };
type BraidInput = {
goal: string;
nodes: readonly BraidInputNode[];
edges: readonly Edge[];
promptTemplates?: Readonly<Record<string, string>>;
};

ID 唯一、非空,且不含 @。goal、model、choice、纯字符串提示词以及渲染后的提示词,只要出现就必须是非空字符串。decision 的 choice 必须非空且互不重复。
workspace 在 execute/decision 节点上可选,在 merge/integrate 节点上禁止使用。只读和可写两种 Git 执行都会拿到隔离的前驱快照;只读会禁用写能力。在 Git 之外,所有文件系统访问都是只读。notifyOnCompletion 请求宿主发提醒,pauseAfter 暂缓向外调度,requireSuccess 让失败中止整轮运行。
这三个布尔值默认都是 false。BraidRun.holdAfter 对已在运行的执行添加或移除同样的暂缓。maxRuns 限制一个节点最多能启动多少次执行,计入循环轮次和下游重跑(被跳过的执行不计);省略或设为 Infinity 表示不限,而所有者替换已启动的节点时总会启动。超出上限的重跑会等待 waitReason: "limit"(见 limits)。

未知字段、缺失引用和重复边(相同的 from、to 和 choice)都会被拒绝。环就是循环,任何边都可能闭合一个环:无条件环、嵌套环和重叠环都允许。决策节点的 choice 边可以结束一个环,环中节点上的 maxRuns 限定它的轮数;两者都没有时,它会一直重复,直到它的所有者停止它。Braid 选择闭合每个环的边,这决定了每一轮从哪里开始;边上的 closesCycle: true 会改为选中这条边(见 cycles)。每次创建环的提交或更新都会用 cycles_created 事件报告它,newCycles(graph, previous) 会列出新环、是否有东西能停止它们,以及环内任何在首次运行前等待 choice 的节点。允许存在不连通的组件;每个根都会运行。
只有决策节点可以有 choice 边,choice 也不必都有出口。

validateGraph(input) 只做校验,不执行。无效的图会抛出 GraphValidationError;无效的选项会抛出 TypeError。可选调用失败会留在执行历史里;必需失败或基础设施失败会让本次运行失败。完整的循环、实时更新、暂停/恢复和失败约定见 execution control。

可复用的提示词模板

在 promptTemplates 里定义一次共享指令,然后给每个节点一个模板名和显式的字符串变量。核心 API 和 Pi 的 braid 工具接受同一种表示:

{
"goal": "Review the runtime and validation code",
"promptTemplates": {
"review": "Review {{target}} for {{focus}}. Inspect source and tests, then report findings with file references and supporting evidence."
},
"nodes": [
{
"type": "execute", "id": "runtime", "workspace": "read-only",
"prompt": {
"template": "review",
"variables": { "target": "src/runtime.ts", "focus": "scheduling and cancellation" }
}
},
{
"type": "execute", "id": "validation", "workspace": "read-only",
"prompt": {
"template": "review",
"variables": { "target": "src/validate.ts", "focus": "input validation" }
}
}
],
"edges": []
}

- 占位符用 {{name}},花括号内两侧可以有空白。名称匹配 [A-Za-z_][A-Za-z0-9_];重复的占位符复用同一个值。模板名可以是任何非空字符串。
- variables 是必需的,常量模板也要传 {}。值必须是字符串,并且必须与模板的变量完全匹配。只要渲染后的完整提示词仍然非空,就允许空值。
- 值只按字面插入一次:不解析表达式,不做递归展开,不转义,不查环境变量,也不访问其他节点的输出。要把字面双花括号插入模板,就把它作为变量值传入。
- 未知模板、缺失或未使用的变量、无效的模板语法,以及渲染后为空的提示词,都会在调用任何模型之前抛出 GraphValidationError。所有声明的模板都会做语法检查,包括未使用的模板。报错会指出是哪个模板;涉及节点引用或渲染时,还会指出受影响的节点。
- 模板作用于 execute、decision、merge 和 integrate 提示词。省略 merge/integrate 提示词时保留默认值。纯字符串提示词永远不会渲染,即使其中含有 {{...}}。

模板能减少 graph/tool-call 参数里的重复文本;每个 worker 仍然会收到完整渲染后的提示词。渲染和输入快照都在异步执行之前完成。模板只属于单次提交,没有保存的注册表,也不引入新的运行时依赖。

BraidInputNode、NodePrompt 和 PromptTemplateReference 描述精简输入。BraidNode、ExecuteNode、DecisionNode、MergeNode、IntegrateNode 和 ModelRequest.node 为 runner 保留各自的字符串提示词类型。核心在渲染之后施加同样的非空提示词校验;它不限制提示词长度或 token 上限(见 resource limits)。

选项

| 选项 | 默认值 | 含义 |
| runner | 必填 | 每次调用都使用全新、隔离的调用 |
| defaultModel | 适配器默认值 | 由各节点的 model 覆盖 |
| cwd | process.cwd() | 核心托管 worktree 的源码检出目录;非 Git 目录只授予只读能力 |
| maxExecutions | 不限 | 所有轮次和更新中已启动与已跳过的执行总数;待执行的执行不计入;须为正的安全整数 |
| maxTokens | 不限 | 所有执行上报的输入与输出 token 总数,在执行结算时检查;须为正的安全整数 |
| maxConcurrency | 4 | 运行时托管的节点调用同时进行的最大数量;须为正整数 |
| nodeTimeoutMs | 不限 | 每个节点单独的截止时间,从节点开始运行时计时(排队或挂起期间不计) |
| graphTimeoutMs | 不限 | 整个执行的截止时间,包括节点排队、暂停的 gate 和挂起;校验之后开始计时 |
| onNodeTimeout | "pause"(braid() 中为 "fail") | "pause" 会挂起超时的执行及其工作,直到恢复或取消(需要可中断的 runner);"fail" 会以 NODE_TIMEOUT 使其失败 |
| onLimit | "pause"(braid() 中为 "fail") | 触达节点的 maxRuns、maxExecutions、graphTimeoutMs 或 maxTokens 时的行为:"pause" 让重跑保持待执行,或暂停运行,直到所有者提高上限;"fail" 以 RUN_LIMIT、EXECUTION_LIMIT、GRAPH_TIMEOUT 或 TOKEN_LIMIT 使运行失败 |
| signal | 无 | 调用方的取消信号;中止正在运行的节点,并把排队中的节点标记为已取消 |
| onEvent | 无 | 实时观察者,监听 graph 与执行的创建、开始、交接、完成、跳过、失败以及 graph 完成 |
所有限制默认都不限,因此一次运行可以一直跑到图结束,或者由所有者停止。超时必须为正的有限毫秒数,最大 2_147_483_647,或者 Infinity;maxExecutions 和 maxTokens 接受正的安全整数或 Infinity。startBraid 返回 setLimits,用来在运行活跃期间修改 maxExecutions、graphTimeoutMs 和 maxTokens;见 limits。

调度与路由语义

每个节点都是一条执行实例的血统,形式为 <nodeId>@<generation>;最新的那个是它的头部。实例状态是显式的:

pending -> running -> completed | failed
pending -> skipped

边的状态由源节点头部的状态解析:

| 源结果 | 出边状态 |
| 尚未结束 | 未解析 |
| 已完成,无标签边 | 活跃 |
| 已完成的决策,匹配所选分支 | 活跃 |
| 已完成的决策,不匹配所选分支 | 不活跃 |
| 因所有输入都不活跃而跳过 | 不活跃 |
| 失败,无标签边 | 活跃(传递错误和可用的输出/工作区) |
| 失败的决策,带分支标签的边 | 阻塞 |
| 因依赖失败而跳过 | 阻塞 |

只有决策节点才能有带分支标签的出边。无标签边是无条件的,包括来自决策的边。单个分支可以激活任意多条边。分支路由要求决策成功完成。决策必须恰好调用一次 decide,并且恰好声明一个分支;缺失、无效或重复调用都会让它失败。在适配器内部捕获工具校验错误,并不会把那次调用变成成功。

待定实例会一直等待,直到所有入边都已解析,并且没有任何输入是过期的,也就是即将被更新的实例替换。然后:

1. 任何阻塞的入边都会让它变成 skipped: upstream_failed。
2. 如果它有入边但没有任何一条活跃,它就变成 skipped: inactive。
3. 否则它开始 running(包括没有输入的根节点)。

当源节点以新结果落定,已落定的下游头部会被克隆成新实例,于是变更会级联:循环一轮一轮地展开,重跑某个节点会重跑依赖它的东西。

失败会作为上下文沿无条件边传播,让后继节点和合并智能体能够检查错误并恢复部分工作。失败的决策无法激活带分支标签的边;它们的无条件后继仍可运行。没有自动重试。失败默认是可选的;requireSuccess: true 的执行失败会中止整个运行,取消兄弟节点,并排空写入和清理。策略属于实例。
暂停期间,图的截止时间和执行限制仍然有效;触达其中一项会暂停运行,除非 onLimit 为 "fail"。

待定实例就地编辑;已启动的实例永不改变,而是被替换。startBraid 暴露带修订检查的 update、resume、snapshot 和 cancel,外加 pause/pauseRun/resumeRun,用来在运行中的执行下一次发起模型请求时挂起它,同时不丢失已有工作;holdAfter 用来在运行中的执行结束后扣住它的结果;setLimits 用来提高运行上限。执行节点和决策节点可以调用 request.requestReplan,请图的属主修改计划;它会扣住这些节点的结果,绝不自行编辑图。更新可以在最终确定之前的任意时刻添加、编辑、替换和删除节点与边:对已启动的节点做 upsert 会替换它,并重跑它的下游谱系。schema 和示例见执行控制。

执行事件

运行时会在每个执行结果上保留一份不可变的 events 日志,并可通过 options.onEvent 流式输出同样的事件。事件带编号和时间戳。日志是诊断数据,不改变调度;观察者抛出的异常和被拒绝的 promise 一律忽略。事件负载在留存和投递之前会先冻结。

事件序列包括初始的 graph_created、execution_created 和 edge_created;带修订号的 graph_updated;以及按实例记录的 execution_created、node_started、workspace_updated、handoff、node_completed、node_failed 或 node_skipped,另外还有适配器向运行中的 worker 投递人类消息时的 human_input。execution_created 给出每个新实例的 generation 和 cause(submitted、added、cloned 或 replaced);execution_superseded 和 execution_removed 报告被替换和被删除的实例。实例事件携带 executionId 和该实例的 revision。交接事件还会标明确切的 fromExecutionId。

execution_paused 和 execution_resumed 报告闸门,execution_hold_added/execution_hold_removed 报告运行中执行的扣留状态变化;replan_requested 报告某个节点请求图的属主重新规划;execution_suspending/execution_suspended 报告运行中执行的暂停,graph_paused/graph_resumed 报告整个运行的暂停。graph_waiting 报告最后一个活跃执行已结束、被扣住或已挂起,只剩被扣住、已挂起或已暂停的工作。graph_completed 或 graph_failed 终止日志。完成/失败在检查点写入之后发布。同一份定义再次运行时,节点事件会以不同的执行 ID 重复出现。

用 startBraid 的方法控制运行。事件回调是观察者;抛出异常或被拒绝都不会改变调度器行为。Pi 面板显示当前拓扑、迭代次数、暂停闸门和有界的事件预览;完整历史仍可从结果中获取。

实时执行活动

生命周期事件只说明一次调用何时开始、何时结束,不说明中间在做什么。ExecutionActivityTracker 是一个可选的、与宿主无关的辅助工具,供想要展示这些信息的适配器使用。用 observe(event) 把核心事件喂给它,给每次 runner 调用传入 tracker.recorder(request),然后调用
workerFinished(executionId),在 runner 返回之后调用。记录器接受模型请求、流式增量、响应、错误,以及工具的开始/输出/结束调用。get(executionId, { before, limit }) 返回某次调用的当前阶段(workspace、worker、model、tool、finalizing、completed 或 failed)、该阶段的开始时间、最后观测到的信号、进行中的模型请求与运行中的工具、宿主声明的 limitations,以及一页按时间排序的条目。历史按执行 ID 索引,所以重复的循环访问各自独立。条目与详情都有上限(默认 200 条条目、每条详情 2,000 字符);最新 50 次之外的已完成调用只保留摘要。formatActivityStatus(activity, now) 渲染一行摘要。记录器的调用从不抛错,也不改变调度或结果。没有新活动的时间是诊断信号,不是卡死的判定。

上下文隔离与模型 runner

核心接受一个 ModelRunner 函数,契约如下:

import type { ModelRequest } from "@chrok/braid";

type ModelRunner = (request: ModelRequest) => Promise<{
output: string;
model?: string;
usage?: { inputTokens: number; outputTokens: number };
}>;

每个请求包含目标、节点、解析后的模型、前驱输出、执行 ID 和中止信号。决策节点还会收到 request.decide(choice)。把这个回调暴露为真正的模型工具,不要靠解析模型输出的文字来推断决策。核心分配 request.workspace,在 Git 仓库中提供本地 request.git(args, input?) 操作,并提供 request.merge.sources 与 request.merge.finish(dispositions) 来合并智能体。适配器必须强制工作区能力,并把会修改文件的工具包进 request.withWorkspaceWrite(operation),这样清理会等待进行中的写入,并拒绝之后的写入。核心的 Git 变更也走这道屏障。如果适配器允许人给运行中的 worker 发消息,就在投递时、在包含该消息的模型请求之前调用 request.recordHumanInput(text)。核心会把它记入该执行的 humanInputs,并记为一个 human_input 事件,这样结果就能显示该执行并非只靠图定义和前驱输入运行;调用结束后再调用会抛错。
要支持暂停,就在 runner 函数上设置 pausable: true,并在每次模型请求前 await request.checkpoint();暂停生效期间,调用会挂起在那里。每次都读取 request.deadlines,不要复制它,因为挂起会把节点截止时间往后推(见暂停运行中的执行)。
内置的 Pi 适配器在读取工具之外,还提供带防护的 write/edit 和 Pi shell 工具。
对于只读工作区,适配器必须省略会修改的工具;核心的写入屏障也会拒绝写入。这包括 Git 之外的所有节点。可写的 Pi 节点可以用 bash(Windows 上还有 powershell)来构建并运行测试。Shell 调用会参与写屏障,并把取消操作转发给各自的进程。

request.predecessors 按入边顺序包含直接活跃的前驱,也包括无条件边上带 error 字段的失败项。每个来源只出现一次:

[{ "nodeId": "route", "output": "Use a detailed comparison.", "decision": "detailed", "model": "router" }]

没有父对话、全局记录或自动的传递历史。每次调用都会拿到全新的节点/上下文对象,所以改动它们不会影响图、其他节点或已记录的结果。提交的输入和选项都会在异步执行前做快照。核心为所有适配器管理工作树;适配器决定哪些工具暴露这些能力。读取类工具遵循宿主文件系统权限,并不是安全沙箱。

工作树与合并智能体

每次 Git 执行都拥有一个全新的工作树。根节点使用任务初始快照中的已跟踪改动和非忽略的未跟踪文件,且不改动真实索引。后继节点使用不可变的前驱检查点;只读执行沿用同样的快照规则,但禁用写入。相互独立的代码分支需要显式合并,普通工作节点才能一起消费它们。

- merge 在新的隔离工作树中合并选定的前驱检查点。
- integrate 把选定结果应用到发起调用的工作检出。

没有自动的最终集成。结果需要进入工作分支时,要显式加一个 integrate 节点。两种操作都接受可选提示词,并要求调用 finish_merge,且每个来源恰好一个处置:

{ "dispositions": [
{ "executionId": "", "disposition": "integrated", "reason": "Applied the reviewed checkpoint" }
] }

由智能体选择 merge、cherry-pick、apply、restore 或直接改文件;核心从不替它做选择。来源包含相对于任务初始快照的有界差异。integrate 还会收到当前来源检出的脏状态,并且必须保留无关的用户改动。冲突未解决、缺少 finish 调用,或处置为 archived,都会让操作失败。

面向模型的 Git 工具把 command 和 args 分开,例如 { "command": "show", "args": ["REF:path"] }。程序化的 request.git 接受完整参数数组。重复的命令前缀、网络 Git、切换分支,以及覆盖文件系统边界,都会被拒绝。

实例会在下游准入前对已跟踪改动和非忽略的新文件做检查点。被忽略的依赖、缓存和构建产物在清理时丢弃;已跟踪或显式强制添加的文件按正常 Git 规则保持跟踪。所有来源检查点都可复用;任何合并都不会消费或删除前驱的结果。任务清理会归档并移除自己拥有的工作树,把 refs 保留在 refs/braid/checkpoints/。集成时还会在 refs/braid/merge-backups/ 下捕获写入前的 backupRef。目标工作区的 dispositions 记录智能体选择的来源。

result.workspaces 以执行 ID 为键;result.nodes[id].workspace 是最新的便捷视图。清理后的路径是历史记录;用 git show <checkpointRef>:path 恢复其内容,或用 git diff <snapshotCommit> <checkpointRef> 查看变更。用 git update-ref -d <ref> 显式删除已审查的 ref。

取消时先排空已跟踪的写入,再清理。检查点/清理失败会让运行失败,并保留不宜删除的路径。集成失败可能留下部分来源编辑或冲突状态,其备份可用于恢复;它不会重置检出。来源集成在单个进程内串行;这不协调父级编辑或其他进程。只读工作节点与这些来源编辑保持隔离。见执行控制。

适配器是信任边界,不是安全沙箱。 它必须避免共享会话状态,只暴露声明的能力,并把 signal 转发给其服务商。核心不提供 shell 工具或递归 Braid 工具;适配器自行选择工具能力。Pi 适配器向可写节点提供 shell 工具,且不改变运行时;核心包不依赖 Pi。安装与测试见 integrations/pi/README.md。

内置的 OpenAI 兼容适配器使用全新的 Chat Completions 上下文、严格的 decide({ choice }) 工具,以及一次无工具的决策续写。合并/集成节点使用本地 git / finish_merge 工具循环;普通 OpenAI 节点没有文件系统工具。Pi 暴露读取、受保护写入和 shell 工具,外加这些核心 Git/合并工具。工具错误会返回节点以便恢复。两个适配器都会汇总其模型调用的用量并转发取消。Pi 写入会拒绝外部路径、Git 元数据、符号链接、硬链接和特殊文件。Shell 工具可绕过这些检查,并以主机权限运行;提示词要求节点尊重工作区边界、共享 Git 状态和外部资源。父级扩展/MCP 工具和钩子不会被继承。这些检查和协作规则不是操作系统沙箱。见 Pi 文件系统能力。

Pi 的工具和时间预算默认无限制。其 options.maxToolRounds 和 options.maxToolCalls 可为每个节点施加正整数限制;计数包含 decide 和被拒绝的请求。超过任一限制会在执行超预算批次前使节点失败。允许在限制处返回最终文本。配置见 Pi 预算选项,包括 nodeTimeoutMs 和 graphTimeoutMs。

对于有限预算,Pi 会插入系统提醒,包含剩余工具和时间每次模型调用前都会检查预算。OpenAI 兼容适配器还会在每次请求前刷新有限时间预算提醒。核心在 performance.now() 时钟上提供可选的 request.deadlines,供适配器计算

remaining node and shared graph time. Reminders do not extend hard limits or
interrupt a model response already in progress. The core API sets no node or
graph timeout unless you pass one.

Results, timeouts, and accounting

BraidResult contains:

- status: completed or failed.
- terminalOutputs: latest successful unconsumed outputs keyed by node ID.
- terminalExecutionIds: exact IDs of the successful execution endpoints.
- nodes: latest states/results per node ID, including output, error, usage,
timing, and workspace metadata. A pending definition has no execution ID yet.
- executions: all immutable invocation definitions and their final results,
keyed by execution ID, including historical rounds and deleted definitions.
- revision: the last committed graph revision.
- workspaces: execution-keyed workspace states, recovery refs, and merge choices.
- events: the immutable execution log described above. onEvent observes live
copies of the same state transitions while the run is in progress.
- metadata: run/root identity, timestamps, monotonic latency, summed reported
token usage, and usageReportedNodes. Missing usage is unknown, not proof of
zero consumption. Usage counts only what the runner actually returns; a
timeout or provider error may leave billable usage unavailable.
- error: one representative error when failed; nodes retains all errors.

With startBraid and an interruptible runner (Pi, DSH, and the OpenAI-compatible
adapter are), a node timeout pauses the execution instead: it keeps its work and
its successors wait until it is resumed, with a new time budget, or cancelled with
cancelExecutions. See pausing on node timeout.
Otherwise, and always with braid() or onNodeTimeout: "fail", a node timeout
marks the running node failed: NODE_TIMEOUT; unconditional successors can
consume its error and partial workspace. A graph timeout pauses a startBraid
run and its running executions until setLimits raises it (see
limits). With braid() or onLimit: "fail",
it marks running nodes failed: GRAPH_TIMEOUT, skips queued/pending nodes with
graph_timeout, and retains already completed terminal outputs. Timers are
cleared when no longer needed.

Timeouts abort the invocation signal and stop waiting for the model even if it
ignores cancellation. Workspace setup, tracked writes, and cleanup are awaited
to avoid deleting work still being written; this may extend total wall time. Late settlements cannot change the returned results, and late
rejections are observed. JavaScript cannot forcibly preempt synchronous work or
stop an uncooperative remote request: providers must honor cancellation to stop
resource consumption. Concurrency limits cover runtime-managed invocations;
uncancelled provider work after timeout can outlive a slot.

Develop from source

git clone https://github.com/Epsirom/braid.git
cd braid
npm ci
npm run check
npm test
npm run build
npm run demo

The demo uses a deterministic fake model runner and makes no network calls. To
run the same graph with an OpenAI-compatible Chat Completions endpoint:

Set OPENAI_API_KEY and BRAID_MODEL in your environment first.
npm run demo -- --live

OPENAI_BASE_URL optionally changes the API root (for example,
https://your-provider.example/v1). Live mode makes billable model requests.
The adapter requires a model with function/tool calling support. No live provider
is needed for the test suite; its HTTP requests are intercepted in tests.

Internal architecture and scope

- src/types.ts: public graph, provider, and result types.
- src/validate.ts: strict validation, graph snapshot,
dependency indexes, and iterative validation of acyclic regions and cycles.
- src/runtime.ts: lineages of execution instances, edge resolution, explicit state transitions,
bounded concurrent scheduling, invocation deadlines, execution events, and result accounting.
- src/workspaces.ts: Git snapshots, checkpoint refs, merge
serialization, local Git tools, and worktree cleanup.
- src/adapters/openai.ts: optional provider translation.
- integrations/dsh/: native DeepSeek Harness model/tool adapter, agent-scoped jobs, reminders, and a native Web graph panel.
- integrations/pi/: thin Pi model-registry/tool adapter, Mermaid graph renderer, and live execution renderer (display.ts).
- test/: deterministic scheduling, execution-event, and intercepted HTTP/tool tests.

There is one in-memory execution context per run, plus a process-local mutex
per source checkout for integrate agents. Worktree registration and removal are
serialized per common Git directory within the process; model calls remain
concurrent. These locks do not coordinate other processes. rootRunId equals
runId. Centralized invocation admission and
usage aggregation leave places to thread a shared root budget in a future
nested-run implementation; nested runs and shared budget enforcement are not
implemented*. The current scheduler deliberately rescans a small graph after
completions; onEvent is an observer for diagnostics and visualization, not a
scheduler event bus.

Out of scope: arbitrary
code nodes, durable workflow recovery, saved templates, a graphical editing UI,
and recursive Braid calls from model nodes. The RSI Mode and Zen Mode milestones
revisit some of these boundaries; see ROADMAP.md.

Releases and upgrades

The 0.5 API is experimental. See GitHub releases
for release and upgrade notes.

- Upgrading from 0.5: read the 0.5 → 0.6 migration guide.
- Upgrading from 0.4: also follow the 0.4 → 0.5 migration guide.
- Upgrading from 0.3: also follow the 0.3 → 0.4 migration guide.
- Upgrading from 0.2: also follow the 0.2 → 0.3 migration guide.
- Upgrading from 0.1: also follow the 0.1 → 0.2 guide.
- Using the previous release: see the 0.5.1 documentation.

Contributing and project status

Start with CONTRIBUTING.md for setup and verification,
ROADMAP.md for scope, and GitHub releases for changes.
See compatibility, resource limits,
and scheduler benchmarks before adopting Braid for a service.
Questions and bugs belong in GitHub issues;
report vulnerabilities privately as described in SECURITY.md.
Participation follows the code of conduct.

License

Braid is released under the MIT License.
预览分享卡片长什么样 ↓Epsirom/braid
分享 · DeepSeek Harness Hub
Epsirom/braid

Braid 用图来协调多个 LLM 智能体。你定义每个智能体的任务,以及它需要哪些结果;Braid…

回到顶部