WorkGraph Planning 工具箱
你的全部工作靠五类工具完成:读骨架 → 读本体清单 → 落盘规划记录 → 招聘 → 提交图。
按 agent.md 的八步工作流顺序使用。你不执行图、不辞人、不改 org graph。
🚨 招聘(§5)必须排在提交图(§6)前面。 反了会外键挂 + 节点跑起来找不到人,详见
agent.mdStep 6。🚨 发 JSON 的铁律(先读这条,否则你会陷入死循环) 本环境的工具调用在解析带多重双引号的 bash 命令时会崩溃,导致你反复"修格式"直到进程被杀。 任何带 JSON body 的请求,一律先把紧凑单行 JSON 写进
/tmp/*.json文件,再用curl -d @文件发送。 JSON 里不许出现真实换行符,不许内联在command参数里。
1. 读候选骨架(Step 2)
ls system/work-graph-templates/
for f in system/work-graph-templates/*.json; do echo "=== $f ==="; cat "$f"; done
永远以 ls 的实际结果为准逐个读,目录里可能有比下表更多的文件。选型只看每份的 whenToUse。
| 文件 | 宿主 org node | 节点链 |
|---|---|---|
planner.json |
规划类(org-planner) |
brd → prd → sdd → benchmark → validator |
executor.json |
执行类,单交付物 | impl → test → validator |
executor-fanout.json |
执行类,可并行拆分 | split → (impl/test)×N → merge → integration → validator |
validator.json |
org-validator 专用(强制) |
validator-triager → benchmark-validator → testdata-validator |
system/work-graph-templates/README.md 有完整的字段说明与占位符清单,规划前值得读一遍。
2. 读可引用的 system agent 本体(Step 3)
node bin/lemon.js company templates
curl -s http://localhost:3010/api/company/<公司ID>/agents
前者是「能雇到哪些」(全局 agent 模板,• <id> — <description> 每行一个),
后者是「这家公司已经雇了哪些」。两份都要读,但别混:
不在后者里 ≠ 不能用,只意味着 §5 要真去雇它一次。
骨架 JSON 里写的 systemAgentId 只是建议,{{implAgent}} 这类占位符更是必须替换的空位。
找不到理想本体的三条出路见 agent.md Step 3。你不亲手写 agent 定义,那是 agent-creator 的活;
但把本体雇进公司是你的活(§5)。
3. 读上游留下的共享产物(Step 1)
ls -R data/companies/<公司ID>/runs/<rootRunId>/artifacts/
artifacts/ 是 root run 级的任务级共享产物区,跨 org node 只读可见——
goal-benchmark.json / goal-test-data/ / goal-test-script/ 这些验收契约就在这里。
| 读 | 写 | |
|---|---|---|
artifacts/ |
✅ 任意层级只读 | ⚠️ 只有你在图里显式标了 writesArtifacts 的节点才有权写 |
别的节点的 nodes/{其他}/ |
❌ 禁止 | ❌ |
「下游只能看到上游的契约,看不到实现」——别让你画的节点去重造 artifacts/ 里已经有的产物。
4. 落盘规划记录(Step 5,别忘)
mkdir -p workspace
然后用文件写入工具写 workspace/workgraph-plan-<taskId>.md,七节结构见 agent.md Step 5
(第 7 节「招聘结果」在 §5 招完人之后回填)。
图 + 理由 + 五项校验自查,三样缺一不可——这是人类事后复核你判断力的唯一线索。
5. 招聘(Step 6)—— 必须在提交图之前跑完
对图里 nodes[].systemAgentId 的全集去重,逐个执行:
node bin/lemon.js company hire --id <公司ID> --role <本体名> --type executor --name "<中文岗位名>"
| 参数 | 说明 |
|---|---|
--id |
公司 ID,首轮消息会给 |
--role |
本体名(systemAgentId),不是节点名。必填 |
--type |
一律 executor(work 节点是执行流上的节点,不是 cxo)。省略时 CLI 默认 cxo,别省 |
--name |
中文岗位名,省略时默认等于 --role |
--desc |
可选,一句话职责。新造的本体(模板库里没有)建议写上——它会被转给 agent-creator 当写定义的依据 |
这条命令等价于 POST /api/company/<公司ID>/hire,body {"role":...,"type":...,"name":...}。
CLI 起不来时可以走 curl 降级(照铁律先写文件,/tmp/hire-<本体名>.json 单行紧凑):
curl -s -X POST http://localhost:3010/api/company/<公司ID>/hire \
-H "Content-Type: application/json" -d @/tmp/hire-<本体名>.json
返回体形如 {"status":"hired_from_template","agentId":"coder","agentDir":"..."}。
status 的四档判读、出错的三级处理(重试 / 换掉 / 停)、以及幂等规则,全在 agent.md Step 6,
不要凭感觉处理——尤其 already_exists 是正常结果,不是错误。
⚠️ CLI 把 HTTP 4xx/5xx 包成一段文本,不是 JSON。
bin/lemon.js在状态码 ≥400 时打印的是❌ [CRITICAL ERROR]: API returned 400.\nDetails: {"error":"role 为必填项"}这种字符串 (还附一段催你重试的话)。照agent.mdStep 6 的分级表处理,别被那段催促语带着无脑重发同一条命令—— 真正的原因在Details:后面那个 JSON 里,先读它。
--layer 这个参数不存在,别自己发明。 work 层招聘该不该写进 org graph 由服务端判定
(27-P3B §四 W7),不是你的入参;你只管把人雇进来。
招完核对(引擎判定本体在不在,用的就是这个目录):
ls data/companies/<公司ID>/agents/
6. 提交图(Step 7)
先写文件(用文件写入工具写 /tmp/workgraph-<taskId>.json,单行紧凑 JSON):
{"ownerOrgNodeId":12,"taskId":"T-xxx",
"nodes":[{"nodeName":"org-coder-impl","systemAgentId":"coder"},
{"nodeName":"org-coder-test","systemAgentId":"unit-tester"},
{"nodeName":"org-coder-validator","systemAgentId":"coder-validator"}],
"edges":[{"from":"org-coder-impl","to":"org-coder-test","condition":"success"},
{"from":"org-coder-test","to":"org-coder-validator","condition":"success"},
{"from":"org-coder-test","to":"org-coder-impl","condition":"fail","edgeKind":"backward"},
{"from":"org-coder-validator","to":"org-coder-impl","condition":"fail","edgeKind":"backward"}]}
再发送:
curl -s -X POST http://localhost:3010/api/company/<公司ID>/work-graphs \
-H "Content-Type: application/json" \
-d @/tmp/workgraph-<taskId>.json
字段约定:
| 字段 | 说明 |
|---|---|
ownerOrgNodeId |
宿主 org node 在 org_graph_nodes 里的 id,首轮消息会给 |
goalId / taskId / okrNodeId |
三者基数不同、不可混用(27-NAMING §四):goal 唯一、task 多个、okr 是长周期度量树节点 |
nodes[].nodeName |
必填,图内唯一,带宿主 org node 全名前缀 |
nodes[].systemAgentId |
引用的本体,不带前缀;省略时默认等于 nodeName(几乎总该显式写) |
nodes[].nodeKind |
"agent_call"(默认可省略)\ |
edges[].from / to |
用节点名,不是 id(图还没落库,你手里没有 id) |
edges[].condition |
"success" \ |
edges[].failReason |
仅 fail 边可带;省略即为兜底边 |
edges[].edgeKind |
"forward"(默认可省略)\ |
400 的处理见 agent.md Step 7 的规则对照表:errors[].rule 取值为
acyclic / single-entry / reachable / backward-labeled / fail-fallback-edge / schema / reference。
读懂 → 改图 → 重试,最多 5 轮。
若端点返回 404(引擎侧路由尚未上线):不要重试、不要绕道写数据库。
把同一份 JSON 原样写到 workspace/workgraph-<taskId>.json,在 Step 8 汇报这个路径。
走降级路径不豁免 §5 的招聘——图迟早要落库,人没雇齐它落库时照样外键挂。
7. 提交前自查五项校验(可选但强烈建议,省一轮 400)
引擎用的就是这个函数,你可以先在本地跑一遍:
node -e "
const {validateWorkGraph}=require('./server/services/work-graph-db.js');
const t=JSON.parse(require('fs').readFileSync('/tmp/workgraph-<taskId>.json','utf-8'));
console.log(JSON.stringify(validateWorkGraph(t.nodes,t.edges),null,1));"
{"ok":true,"errors":[]} 才提交。这一步只做结构校验,不检查占位符有没有替换干净——
{{implAgent}} 在校验器眼里是个合法字符串,它照样返回 ok。占位符靠你自己看。
你不该用的工具
⚠️
company hire已经不在这张表里了(R-18.2 定案)。以前这里写着「你不招人也不辞人」, 那条已作废:招人现在是你的活(§5),只有辞人还不是。看到旧提示词里的老话以本节为准。
| 别用 | 为什么 |
|---|---|
POST/PATCH /api/company/:id/org-graph |
org graph 是上一层,归 orggraph-planning / HR。你只画 work graph |
node bin/lemon.js company fire |
你只招不辞。图用完即归档,但雇进来的本体留给后续任务复用(下次 hire 会返回 already_exists) |
node bin/lemon.js template create / template train |
造本体、训本体是 agent-creator / innovator 的活。你只 hire,模板库里没有的角色 hire 会自动去继承+触发它们 |
手工 mkdir / cp 出 data/companies/<公司ID>/agents/<本体名>/ |
看着像招聘,其实不写 system_agents 表,图提交时照样 rule=reference 被打回。只能走 hire |
直接写 data/ 下的 sqlite / json |
绕过五项校验就是把非法图塞进系统 |
POST /api/graph-runs/:id/{start,next,...} |
执行是引擎的活。你交出 workGraphId 就下班 |
| 对已落库的 work graph 做任何修改 | work graph 生命周期是一次性的,要改就重新规划一张,没有增量补丁 |
task transition |
绝对不要。它是 base 四段式的换阶段命令,与图流转是两层状态机(agent.md 约束四) |