npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-agent-graph

v0.2.1

Published

Lightweight graph orchestration for DeepSeek Harness: scoped agent nodes, handoff contracts, bounded rework, and a layered global ledger.

Readme

dsh-agent-graph

一个「交付这个需求」的任务,可以拆成各管一段的节点:调研、spec、实现、测试计划、写测试。dsh-agent-graph 负责运行这张图。每个节点都是一次性的 DSH 子 agent;上游把交付以结构化契约的形式交给下游;下游发现上游交付不足时,带着证据把问题退回直接上游;所有节点的进度、todo、关键决策与踩坑都记录在同一个分层账本里,人和 agent 都能从 README 分层下钻查看。

dsh plugin --profile web add dsh-agent-graph

目录

它是什么

| 关注点 | dsh-agent-graph 的做法 | | --- | --- | | 任务拆解 | 用 needs 边声明依赖的 YAML 图;运行前校验环、未知引用、重复 id | | 节点执行 | 每次激活 = 一次 ctx.subagents.start('spawn', …);注入 scope prompt、上游交接、账本指针与结构化输出 schema | | 注意力聚焦 | 节点之间不共享会话;一次激活只看到自己的 prompt、上游交付与账本 | | 可视化编排 | 在 DSH Web 的 编排 会话页签中,以拖拽画布、节点属性、依赖勾选和即时校验创建 DAG | | 节点间交付 | 结构化交接版本(summary / artifacts / openIssues)注入每一个直接下游激活 | | 上游交付不足 | 有界返工请求退回直接上游,附证据与验收标准;可 provide / decline / 逐跳 forward | | 共享记忆 | 每次运行一个账本(README → index → 节点分区 → 明细),节点读写,引擎确定性再生 | | 失败行为 | 停图(fail-fast);/graph resume 重试失败与中断的节点 | | 可观察 | /graph status + 账本;每次激活、交接、返工轨迹与索引都落盘 |

图以人类斜杠命令(/graph)的形式在 DSH 会话里执行,不是暴露给模型的工具。但节点本身是普通子 agent,可以使用宿主授予它们的工具。

为什么需要它

DSH 已经很擅长一次性的委派。长链路多步任务会碰到三个反复出现的问题:

  • 上下文串味:一个会话把所有关注点堆在一起;被要求写测试的节点开始操心架构。历史越长,职责边界越模糊。
  • 沉默补偿:上游结果不够好时,下游倾向于猜、绕过去、或悄悄扩大自己的范围,而不是把精确的请求退回去。
  • 推理蒸发:节点被重新拉起(重试、resume、追加)时,对话没了,当时的关键决策和踩坑也一并消失。

dsh-agent-graph 用机制而不是提示词来对应这三件事:用声明的图管边界,用带证据与上限的返工协议管升级,用持久账本管记忆。agent 保持一次性;图和账本持久。

与其他方式对比

这些能力解决的是相邻而非相同的问题,可以组合使用;按任务形态选表面即可。

| 需求 | dsh-agent-graph | 内置 subagent | 内置 workflow | 内置 ralph | | --- | --- | --- | --- | --- | | 工作单元 | 依赖图中的一个声明节点 | 一次委派调用 | 模型写的 JS 编排脚本 | 一个固定目标的迭代 | | 依赖关系 | 显式 needs 边 + 拓扑调度 | 在对话里人工决定 | 脚本里命令式安排 | 不适用 | | agent 间数据 | 结构化交接契约 + 产物 | 最终回答文本 | 脚本变量 | 有界结构化报告 | | 上游交付不足时 | 有界返工请求退回直接上游,附证据与验收标准 | 调用方重试或重新提示 | 脚本自行决定(无协议) | 工作区 + 下一轮 | | 重启后保留什么 | 图、交接版本、账本、运行状态(/graph resume) | 无 | 运行快照 / effect cache(随插件) | 工作区 | | 人类审查面 | /graph status + 分层账本 | 聊天 | 运行 UI | 聊天 |

任务有真实依赖结构、参与者超过两三个、且链路长到「谁在什么时候决定了什么」必须活过重新拉起时,用 dsh-agent-graph。只有一两次委派时,内置 subagent 是更短的路。

使用示例

仓库自带五节点示例(examples/feature-delivery.yaml)与无模型干跑脚本(examples/fake-script.json):

npm install
npm run demo

真实运行用同一张图,节点换成真实子 agent:

/graph run examples/feature-delivery.yaml
Started run feature-delivery-20260918-024342 (graph "feature-delivery", 5 nodes, concurrency 2).
Ledger: /path/to/workspace/.agent-graph/runs/feature-delivery-20260918-024342
Track with /graph status; nodes are DSH subagents, so this may take a while.

追踪与查看都在会话里完成:

/graph status

Run feature-delivery-20260918-024342 — feature-delivery · status completed
activations 7/24 · started 2026-09-17T18:43:42.782Z · finished 2026-09-17T18:43:42.807Z

node               state            try  handoff
implement          ok               2    nodes/implement/handoff/v1.md
research           ok               1    nodes/research/handoff/v1.md
spec               ok               1    nodes/spec/handoff/v2.md
test-plan          self_handled     2    nodes/test-plan/handoff/v1.md
tests              ok               1    nodes/tests/handoff/v1.md

/graph show test-plan     # 打印该节点的账本分区

干跑脚本演示了两种返工结局:implement 把缺失细节退回 spec,spec 提供补充件(provided);test-plan 向 implement 索要接口边界,implement 以「不属于我的职责」拒绝 —— test-plan 随后自行明确缺口(declined → self_handled)。两次交换都记录在 requests/ 下。

可视化 DAG 编排器(V2)

安装到 DSH 的 Web profile 后,会话顶部与内置视图并列的位置会出现新的 编排 页签。它编辑的仍是同一份图定义:拖动卡片调整画布布局;在右侧属性面板修改节点 id、职责范围、提示词与产物;勾选直接上游即可绘制依赖边。草稿和布局按浏览器会话保存;点击保存会把规范化后的 YAML 写入 .agent-graph/graphs/<name>.yaml。这个路径相对于 DSH 主进程的工作目录(即启动 dsh web 时所在的目录),可用插件配置里的 workspace 覆盖;因此图定义与运行账本都落在该工作区,而不是各个会话自己的 cwd。

节点会话的创建边界是刻意严格的:

  1. 编辑或保存图:只校验并写 YAML,绝不调用 ctx.subagents.start(),因此不会创建任何 agent 会话。
  2. 保存并运行:先保存同一份 YAML,再启动一次图运行。
  3. 调度器激活就绪节点:只有根节点会立即启动;下游必须等所有直接上游结算。真正轮到某个节点时,调度器才为这一次激活调用 DSH 的 ctx.subagents.start()。
  4. DSH 侧边栏展示子会话:这些激活是普通 DSH 子 agent 会话(标签为 agent-graph:<graph>:<node>),会出现在父会话的侧边栏中。仍在 pending 或被依赖阻塞的节点没有子会话,自然也不会占用侧边栏。

因此画布可以先作为低成本的规划面:先搭建、移动并校验复杂 DAG,不产生任何模型工作;真正运行后,再通过 DSH 的子会话和持久账本观察执行过程。

安装

装进 DSH

从 npm 安装(推荐):

dsh plugin --profile web add dsh-agent-graph

从 GitHub 安装(可加 #<sha> 固定版本):

dsh plugin --profile web add github:wrc093/dsh-agent-graph

从本地目录(开发):

cd /path/to/dsh-agent-graph
npm install && npm run build
dsh plugin --profile web add "$(pwd)"

安装或修改后重启 dsh web。确认插件行已进入合成树:

dsh --profile web --dump-config | grep -i agent-graph

要求:Node.js >=22;DSH profile 具备 commands 与 subagents 服务;subagent provider 必须支持结构化输出(spawn 支持;acp、claude-code、codex 不支持)。

更新 / 卸载

dsh plugin --profile web add dsh-agent-graph                       # 从 npm 更新
dsh plugin --profile web add github:wrc093/dsh-agent-graph#<sha>  # 或固定 commit
dsh plugin --profile web remove dsh-agent-graph                    # 卸载

图定义

name: feature-delivery
description: 调研 → spec → 实现 → 测试计划 → 测试
concurrency: 2
budget:
  maxNodeRuns: 24     # 整个 run 的最大激活次数(含返工重跑)
  reworkPerEdge: 2    # 每条依赖边允许的返工次数
nodes:
  - id: research
    scope: 调研事实、约束与风险;不产出方案、不写代码
    prompt: |
      围绕本次需求完成调研:相关模块、约束、风险……
    outputs: [facts, constraints, risks]
  - id: spec
    needs: [research]        # 直接上游;同时也是唯一允许返工的对象
    scope: 把调研固化为可执行的 spec;不写代码
    prompt: |
      基于上游交接产出 spec……

| 字段 | 含义 | | --- | --- | | name、description | 图的身份,记录进账本 | | concurrency | 最大并行激活数,默认 2 | | budget.maxNodeRuns | 整个 run 的激活上限,默认 40 | | budget.reworkPerEdge | 每条依赖边的返工上限,默认 2 | | nodes[].id | ^[a-z][a-z0-9_-]*$,图内唯一 | | nodes[].scope | 职责边界;是节点(和上游)判断返工请求是否成立的依据 | | nodes[].prompt | 每次激活注入的任务说明 | | nodes[].needs | 直接上游 id;决定调度顺序,也是唯一可返工对象 | | nodes[].outputs | 可选,仅文档用途(展示在节点账本分区) |

编译器会拒绝环、未知/重复引用、自环、非正数预算与非法字段。拓扑序按 id 排序的 frontier 计算,同一份图永远得到同一顺序。

命令

| 命令 | 行为 | | --- | --- | | /graph run <file.yaml> | 校验图、建立账本、后台启动运行并立即返回 | | /graph status [runId] | 展示运行:状态表、未决返工请求、失败、最近动态(默认最近一次) | | /graph resume [runId] | 从 run.json 重建引擎继续跑;失败与中断节点重试 | | /graph show [runId] <node> | 打印某个节点的账本分区(nodes/<id>/index.md) | | /graph runs | 列出本工作区的运行,最新在前 | | /graph editor save <base64url> | 编排 页签使用的内部桥接命令:校验并保存规范 YAML,绝不启动 run 或子 agent |

节点是完整子 agent,所以运行在后台执行;账本是权威进度面,/graph status 在运行活跃时读内存状态,否则读 run.json。

运行机制

  1. 校验与编译:解析 YAML、检查图、计算上下游映射与规范拓扑序。
  2. 调度:所有 needs 已结算(ok / self_handled)的节点进入就绪队列,最多并行 concurrency;未决返工请求的 holder 激活占用同一并发额度。
  3. 激活:以一次性子 agent 启动。prompt 由引擎确定性拼装:scope + prompt、上游最新交接、账本路径(运行 README、本节点分区、decisions/pitfalls 索引)、记录义务,以及适用时的返工请求或重试结论。
  4. 交接:成功后写出 nodes/<id>/handoff/vN.md;其 summary / artifacts / openIssues 注入每一个直接下游激活。
  5. 记录:每次激活写入 nodes/<id>/attempts/NNN.md;账本的 README、索引、时间线与节点分区在每次状态变化后确定性再生。
  6. 结算或失败:所有节点 ok/self_handled 即完成;第一个节点失败即停图(在途激活被中止),resume 把失败与中断节点放回 pending。

所有持久化写入经过单一 persist 链串行化,并发节点完成不会在同一批文件上竞争。

返工协议

无法完成职责的节点以 status: "needs_rework" 结束,并给出:

| 字段 | 含义 | | --- | --- | | target | 直接上游节点 id(非直接上游会降级为自理) | | problem | 缺什么 / 哪里不对 | | evidence | 账本/交接引用,例如 nodes/spec/handoff/v1.md#interface | | acceptance | 补到什么程度算够 |

上游被重新拉起作为 holder,必须给出恰好一种结局:

| 结局 | 效果 | | --- | --- | | provided | 补充件写为该 holder 的新交接版本并交回发起方;发起方带着新材料与出处(providedBy)重新激活 | | declined | 发起方重新激活并被要求自己补齐;最终状态为 self_handled | | forward | holder 以 needs_rework 把请求交给自己的直接上游;请求逐跳传递并保留完整轨迹 |

有界规则保证循环必收敛:

  • 每个请求对每个节点最多 forward 一次;非法/缺失 target 降级为 declined。
  • 同一问题(problem 归一化后按 origin 哈希)只允许请求一次。重复请求给发起方一次自理机会;再犯则节点显式失败(unbounded rework)。
  • budget.reworkPerEdge 限制每条边的请求数;超限的请求降级为自理。
  • holder 激活失败与普通节点失败一致:停图。

每个请求都写入 requests/R-XXXX.md 并带完整轨迹,升级路径事后可审。

全局账本

.agent-graph/runs/<runId>/
├── README.md              # 运行总览、节点表、最近动态
├── index.md               # 分区索引
├── progress.md            # 完整活动时间线
├── run.json               # 机器可读的持久化状态
├── nodes/<id>/
│   ├── index.md           # 职责、状态、上下游、交接、尝试
│   ├── handoff/vN.md      # 交付版本(含返工补充件)
│   └── attempts/NNN.md    # 引擎写的每次激活记录
├── decisions/index.md     # 节点写的 `D-*.md` 汇总
├── pitfalls/index.md      # 节点写的 `P-*.md` 汇总
└── requests/R-XXXX.md     # 返工请求与完整轨迹

节点 agent 被要求用普通文件工具维护自己的工作记录(attempts/、decisions/D-<HHMMSS>-<slug>.md、pitfalls/P-<HHMMSS>-<slug>.md、todo.md)。布局与索引归引擎所有,节点从不编辑共享文件。阅读是分层的:README → index → 节点分区 → 按需下钻。

.agent-graph/ 默认被仓库 .gitignore 忽略;是否提交或导出某个账本,按工作区自行决定。

节点输出契约

每次激活必须以结构化输出结束,通过 DSH outputSchema 强制(子 agent 调用 structured-output 工具):

{
  "status": "ok | needs_rework | failed",
  "summary": "给下游的交接摘要",
  "artifacts": ["产物路径"],
  "openIssues": ["下游需要知道的事"],
  "rework": {
    "target": "直接上游 id",
    "problem": "缺什么",
    "evidence": ["nodes/spec/handoff/v1.md#section"],
    "acceptance": "补到什么程度算够"
  },
  "reworkOutcome": "provided | declined",
  "addendum": "交回发起方的补充内容",
  "declineReason": "拒绝理由"
}

status 为 needs_rework 时必须给出 rework;节点作为返工 holder 应答时必须给出 reworkOutcome 与 addendum/declineReason。违反契约的结果会让节点带明确原因失败;引擎对真实与脚本结果一视同仁地校验。

CLI

CLI 负责校验、干跑与检查。真实执行发生在 DSH 内,因为节点是宿主子 agent。

dsh-agent-graph validate <file.yaml>                        # 解析 + 校验,打印拓扑序
dsh-agent-graph run <file.yaml> --fake <script.json>        # 用脚本化响应干跑(无模型、无网络)
dsh-agent-graph status [--run <runId>] [--workspace <dir>]  # 查看运行(状态表、请求、失败)
dsh-agent-graph resume [--run <runId>] --fake <script.json> # 继续已停止/失败运行

--fake 脚本格式:{ "nodes": { "<nodeId>": [ {result}, … ] } },示例见 examples/fake-script.json。退出码:0 成功、1 用法/校验错误、2 运行失败结束。

数据处理与限制

  • 账本是 <workspace>/.agent-graph/ 下的本地纯文本,包含节点摘要、产物路径、决策与踩坑;不包含模型凭据、其他会话的 prompt 或工具调用参数。节点写的摘要可能引用项目内容,分享账本前请自行审查。
  • 节点以 DSH 子 agent 身份运行,权限跟随宿主授予;本插件不会放宽沙箱或审批设置。
  • 每次激活都是一次真实子 agent 运行并消耗 token。预算用于约束花费:budget.maxNodeRuns 限制总激活数,budget.reworkPerEdge 限制返工,nodeTimeoutMs(插件配置,默认 30 分钟)限制单次激活。

| 限制 | 默认 | 含义 | | --- | ---: | --- | | concurrency | 2 | 最大并行激活数 | | budget.maxNodeRuns | 40 | 整个 run 的激活总数(含重试与返工) | | budget.reworkPerEdge | 2 | 每条依赖边的返工请求数 | | nodeTimeoutMs | 1800000 | 单次激活硬超时;0 表示关闭 |

超出 maxNodeRuns 以 budget exhausted 结束运行;超时使该节点失败(停图),原因写入账本。

排查

| 现象 | 检查 | | --- | --- | | /graph 变成普通聊天 | 插件是否装在当前 profile、commands 服务是否存在、安装后是否重启 | | subagent provider … does not support … capability | 换支持 outputSchema 的 provider(spawn/fork);acp、claude-code、codex 不支持 | | finished without structured output | 子 agent 未调用 structured-output 工具;检查 provider 支持情况并重试该节点 | | 运行立刻 failed 且 budget exhausted | 调大 budget.maxNodeRuns 或减少返工;返工循环可在 requests/ 里看到 | | unbounded rework 失败 | 节点重复请求了一个已被自理的问题;收紧节点 prompt 或上游交付 | | no runnable nodes: the graph is stuck | 某个依赖从未结算;在 /graph status 看节点状态与未决请求 | | 时间线里出现 invalid rework target | 节点指向了非上游节点,已降级自理;修节点 prompt 或 needs 边 | | 崩溃后状态里有 pending 节点 | 执行 /graph resume <runId>;已完成节点不会重跑 | | 启动时报图校验错误 | 未知/重复 id、环、自环或非正数预算;错误信息会列出全部问题 |

开发

npm install
npm run typecheck
npm test
npm run demo        # 完整干跑自带示例(不需要模型)
npm run build       # dist/(插件入口 + CLI)

| 文件 | 职责 | | --- | --- | | src/core/graph.ts | YAML 解析、校验、规范拓扑编译 | | src/core/engine.ts | 调度、交接、返工状态机、持久化 | | src/core/store.ts | 账本布局与索引/时间线的确定性再生 | | src/core/runner.ts | 节点结果契约、JSON schema、脚本化测试替身 | | src/core/prompt.ts | 确定性激活 prompt 组装(scope、交接、账本、规则) | | src/core/types.ts | 共享词汇(图、运行状态、请求、结果) | | src/dsh/contracts.ts | ctx.commands 与 ctx.subagents 的结构契约 | | src/dsh/subagent-runner.ts | 一次性 spawn runner(结构化输出) | | src/plugin.ts、src/cli.ts | 斜杠命令面与 CLI | | test/、examples/ | 单元/集成测试与自带示例 |

测试是确定性的:脚本化 runner 替代子 agent,调度、返工与账本语义无需模型或网络即可覆盖;插件命令面针对 fake host 验证。V1 设计记录见 mydocs/specs/。

本地 DSH 开发:构建 checkout、把路径装进开发 profile,改完重启 DSH。不要把 .agent-graph/ 与凭据提交进仓库。

贡献

带最小图、脚本化 trace(或账本片段)与期望的调度/返工行为,开一个 issue。语义改动请补一个聚焦的回归测试并跑上面的检查。文档需要区分「协议保证的行为」与「依赖节点 prompt 与模型行为的部分」。

许可

本项目基于 MIT License 开源。