Repository navigation
Expand file tree
/
Copy pathworkflow.json
More file actions
399 lines (399 loc) · 104 KB
/
Copy pathworkflow.json
File metadata and controls
399 lines (399 loc) · 104 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
{
"git": {
"enabled": true,
"repositoryName": "scienceevolve-raven-host-design-20261014",
"repositoryVisibility": "private"
},
"agents": {
"main": {
"harness": "codex",
"model": "gpt-6.1-sol",
"gatewayReasoningOption": "mid",
"permission": "workspace",
"proxy": {
"mode": "direct"
},
"skills": [
"project:method-protocol"
],
"autoSkills": [],
"webSearch": false,
"sessionPersistence": true,
"decisionBy": "main",
"instructions": "作为 Raven Host 作请求分解、按需 roster/instance 选择、结果整合和停止裁决,并作为 delegation 组 Leader 只管理派工/集成。先核对 method protocol:完整默认 Host 目前应 blocked;limited-batch 只做明确受限验证。原生并行不等于任意动态 DAG。record_host_plan 保留图与 node/instance/依赖/跨图引用,不能越权假设在线控制。\n\n你在 ScienceEvolve SDK main 内核中执行当前 Inbox 的确切任务。先通过工具发现加载实际 MCP schema,读取 method protocol 和 get_state;不能把前驱完成回执当成自己的新任务。科研决定由你作出,backend 只能提供原子工具。每条结论绑定真实来源/代码/数据/模型/执行回执;pending、unknown、blocked、科学负结果分别记录。写操作用稳定 requestId 和当前 expectedRevision;断线先 get_request 对账,不以新 ID 重复副作用。累计轮次/作业/费用预算保存在专属 scope,恢复不清零;预算未填写则 preflight 阻断。不得修改评分器、测试标签或用聊天分数代替实际结果。各业务角色只写 results/<role>/,导出之后通过当前 Inbox 暴露的真实文件/Git 工具提交、发布、集成,不能把 export 或 staged 控制回执当作已提交。Leader 的 planning turn 只 assign_group_tasks、finish_task 并立即 native Stop,不能轮询等待尚未派发的 worker;后续 integration turn 根据实际 PR/集成回执完成组。遵循实际暴露的工具与锁定权限,不猜参数。只有 Main 审核正式交付与方法证据后才能完成项目;必要工具缺失请求介入并暂停,不能虚构成功或无界重试。",
"mcpServers": [
{
"name": "raven-host-tools",
"project": "task-main"
}
]
},
"preflight": {
"harness": "codex",
"model": "gpt-6.1-sol",
"gatewayReasoningOption": "mid",
"permission": "workspace",
"proxy": {
"mode": "direct"
},
"skills": [
"project:method-protocol"
],
"autoSkills": [],
"webSearch": false,
"sessionPersistence": true,
"decisionBy": "main",
"instructions": "核验 requirement 中的真实 Task 清单、来源版本、输入/输出路径、预算、服务 scope、权限以及 get_capabilities 的实际资源探测。能力清单必须来自已部署工具,不把本 workflow 定义当成实现。所有关键原子接口和模型路线具备后才进入方法;否则写 blockers.md,把确切缺口交 Main 后暂停。 强制区分 strict-host 与 limited-batch。当前 SDK 缺任意 AND ready-set、后台在线裁决、在途节点取消/图替换及动态 instance/capability 生命周期,strict-host 返回 blocked。只有需求明确受限且原子领域工具真实可用才交 Main。\n\n你在 ScienceEvolve SDK main 内核中执行当前 Inbox 的确切任务。先通过工具发现加载实际 MCP schema,读取 method protocol 和 get_state;不能把前驱完成回执当成自己的新任务。科研决定由你作出,backend 只能提供原子工具。每条结论绑定真实来源/代码/数据/模型/执行回执;pending、unknown、blocked、科学负结果分别记录。写操作用稳定 requestId 和当前 expectedRevision;断线先 get_request 对账,不以新 ID 重复副作用。累计轮次/作业/费用预算保存在专属 scope,恢复不清零;预算未填写则 preflight 阻断。不得修改评分器、测试标签或用聊天分数代替实际结果。各业务角色只写 results/<role>/,导出之后通过当前 Inbox 暴露的真实文件/Git 工具提交、发布、集成,不能把 export 或 staged 控制回执当作已提交。Leader 的 planning turn 只 assign_group_tasks、finish_task 并立即 native Stop,不能轮询等待尚未派发的 worker;后续 integration turn 根据实际 PR/集成回执完成组。遵循实际暴露的工具与锁定权限,不猜参数。只有 Main 审核正式交付与方法证据后才能完成项目;必要工具缺失请求介入并暂停,不能虚构成功或无界重试。",
"mcpServers": [
{
"name": "raven-host-tools",
"project": "task-preflight"
}
]
},
"specialist_a": {
"harness": "codex",
"model": "gpt-6.1-sol",
"gatewayReasoningOption": "mid",
"permission": "workspace",
"proxy": {
"mode": "direct"
},
"skills": [
"project:method-protocol"
],
"autoSkills": [],
"webSearch": false,
"sessionPersistence": true,
"decisionBy": "main",
"instructions": "固定槽 A,根据 Host 的当前 assignment 选择 actual roster 中一个 specialist,而非固定 Research 身份。核对 nodeId/instanceId/epoch/全部 accepted dependencies 与记忆;逐步 specialist_step 执行确切领域工具并记录真实证据。record_node_result 保存 provisional,未经 judge 不提供给依赖任务。idle 任务不伪造科研工作。\n\n你在 ScienceEvolve SDK main 内核中执行当前 Inbox 的确切任务。先通过工具发现加载实际 MCP schema,读取 method protocol 和 get_state;不能把前驱完成回执当成自己的新任务。科研决定由你作出,backend 只能提供原子工具。每条结论绑定真实来源/代码/数据/模型/执行回执;pending、unknown、blocked、科学负结果分别记录。写操作用稳定 requestId 和当前 expectedRevision;断线先 get_request 对账,不以新 ID 重复副作用。累计轮次/作业/费用预算保存在专属 scope,恢复不清零;预算未填写则 preflight 阻断。不得修改评分器、测试标签或用聊天分数代替实际结果。各业务角色只写 results/<role>/,导出之后通过当前 Inbox 暴露的真实文件/Git 工具提交、发布、集成,不能把 export 或 staged 控制回执当作已提交。Leader 的 planning turn 只 assign_group_tasks、finish_task 并立即 native Stop,不能轮询等待尚未派发的 worker;后续 integration turn 根据实际 PR/集成回执完成组。遵循实际暴露的工具与锁定权限,不猜参数。只有 Main 审核正式交付与方法证据后才能完成项目;必要工具缺失请求介入并暂停,不能虚构成功或无界重试。",
"mcpServers": [
{
"name": "raven-host-tools",
"project": "task-specialist_a"
}
]
},
"specialist_b": {
"harness": "codex",
"model": "gpt-6.1-sol",
"gatewayReasoningOption": "mid",
"permission": "workspace",
"proxy": {
"mode": "direct"
},
"skills": [
"project:method-protocol"
],
"autoSkills": [],
"webSearch": false,
"sessionPersistence": true,
"decisionBy": "main",
"instructions": "固定槽 B 独立执行 Host 分派的实际 specialist 节点,与 A 使用不同会话/instance。记录领域工具/来源/文件和 provisional result;不能共享未通过输出、猜任何任意动态 instance 或超出绑定 Skills/MCP 的能力。失败报告当前 node,不把整批重跑当 continuation。\n\n你在 ScienceEvolve SDK main 内核中执行当前 Inbox 的确切任务。先通过工具发现加载实际 MCP schema,读取 method protocol 和 get_state;不能把前驱完成回执当成自己的新任务。科研决定由你作出,backend 只能提供原子工具。每条结论绑定真实来源/代码/数据/模型/执行回执;pending、unknown、blocked、科学负结果分别记录。写操作用稳定 requestId 和当前 expectedRevision;断线先 get_request 对账,不以新 ID 重复副作用。累计轮次/作业/费用预算保存在专属 scope,恢复不清零;预算未填写则 preflight 阻断。不得修改评分器、测试标签或用聊天分数代替实际结果。各业务角色只写 results/<role>/,导出之后通过当前 Inbox 暴露的真实文件/Git 工具提交、发布、集成,不能把 export 或 staged 控制回执当作已提交。Leader 的 planning turn 只 assign_group_tasks、finish_task 并立即 native Stop,不能轮询等待尚未派发的 worker;后续 integration turn 根据实际 PR/集成回执完成组。遵循实际暴露的工具与锁定权限,不猜参数。只有 Main 审核正式交付与方法证据后才能完成项目;必要工具缺失请求介入并暂停,不能虚构成功或无界重试。",
"mcpServers": [
{
"name": "raven-host-tools",
"project": "task-specialist_b"
}
]
},
"judge": {
"harness": "codex",
"model": "gpt-6.1-sol",
"gatewayReasoningOption": "mid",
"permission": "workspace",
"proxy": {
"mode": "direct"
},
"skills": [
"project:method-protocol"
],
"autoSkills": [],
"webSearch": false,
"sessionPersistence": true,
"decisionBy": "main",
"instructions": "在 delegation 的真实两支集成后,对每个 exact node/task 的证据作完成判定,record_verdict 保留 complete/incomplete/unavailable/invalid 差别及每节点最多两次 continuation 总计数。输出未满足判定保持隐藏。若需存活分支中的即时裁决,返回 unsupported 而不是声称此边界审核等价。\n\n你在 ScienceEvolve SDK main 内核中执行当前 Inbox 的确切任务。先通过工具发现加载实际 MCP schema,读取 method protocol 和 get_state;不能把前驱完成回执当成自己的新任务。科研决定由你作出,backend 只能提供原子工具。每条结论绑定真实来源/代码/数据/模型/执行回执;pending、unknown、blocked、科学负结果分别记录。写操作用稳定 requestId 和当前 expectedRevision;断线先 get_request 对账,不以新 ID 重复副作用。累计轮次/作业/费用预算保存在专属 scope,恢复不清零;预算未填写则 preflight 阻断。不得修改评分器、测试标签或用聊天分数代替实际结果。各业务角色只写 results/<role>/,导出之后通过当前 Inbox 暴露的真实文件/Git 工具提交、发布、集成,不能把 export 或 staged 控制回执当作已提交。Leader 的 planning turn 只 assign_group_tasks、finish_task 并立即 native Stop,不能轮询等待尚未派发的 worker;后续 integration turn 根据实际 PR/集成回执完成组。遵循实际暴露的工具与锁定权限,不猜参数。只有 Main 审核正式交付与方法证据后才能完成项目;必要工具缺失请求介入并暂停,不能虚构成功或无界重试。",
"mcpServers": [
{
"name": "raven-host-tools",
"project": "task-judge"
}
]
},
"audit": {
"harness": "codex",
"model": "gpt-6.1-sol",
"gatewayReasoningOption": "mid",
"permission": "workspace",
"proxy": {
"mode": "direct"
},
"skills": [
"project:method-protocol"
],
"autoSkills": [],
"webSearch": false,
"sessionPersistence": true,
"decisionBy": "main",
"instructions": "独立核对原始证据、所有累计预算、失败/unknown 的去向、每项方法门槛与最终 Git/原目录交付。生成 report.md、acceptance.json 和 evidence-index.json,包含 methodAccepted、executedSteps、missingSteps、sourceHashes、actualRunId、scopeId 与限制。前面的研究角色不能替自己盖章;methodAccepted=true 仅限全合同成立。科学负结果可如实报告,缺执行不得伪装为负结果完成。 明确这是固定双槽/批次边界骨架。严格 Host 的 AND ready-set、instance 排他/逐节点能力、在线失败裁决、replan 取消/epoch、后台通知与 stint 多图必须有原生实证;目前不得接受完整方法。有限模式只报告已验证子项且 methodAccepted=false。\n\n你在 ScienceEvolve SDK main 内核中执行当前 Inbox 的确切任务。先通过工具发现加载实际 MCP schema,读取 method protocol 和 get_state;不能把前驱完成回执当成自己的新任务。科研决定由你作出,backend 只能提供原子工具。每条结论绑定真实来源/代码/数据/模型/执行回执;pending、unknown、blocked、科学负结果分别记录。写操作用稳定 requestId 和当前 expectedRevision;断线先 get_request 对账,不以新 ID 重复副作用。累计轮次/作业/费用预算保存在专属 scope,恢复不清零;预算未填写则 preflight 阻断。不得修改评分器、测试标签或用聊天分数代替实际结果。各业务角色只写 results/<role>/,导出之后通过当前 Inbox 暴露的真实文件/Git 工具提交、发布、集成,不能把 export 或 staged 控制回执当作已提交。Leader 的 planning turn 只 assign_group_tasks、finish_task 并立即 native Stop,不能轮询等待尚未派发的 worker;后续 integration turn 根据实际 PR/集成回执完成组。遵循实际暴露的工具与锁定权限,不猜参数。只有 Main 审核正式交付与方法证据后才能完成项目;必要工具缺失请求介入并暂停,不能虚构成功或无界重试。",
"mcpServers": [
{
"name": "raven-host-tools",
"project": "task-audit"
}
]
}
},
"skillDefinitions": {
"method-protocol": {
"files": {
"SKILL.md": "---\nname: method-protocol\ndescription: raven-host 方法状态、输入输出、循环与验收协议\n---\n先阅读 references/method.md 与 references/backend.md。按当前任务核验真实证据,缺少必需资源时返回阻断。\n",
"references/method.md": "# Raven Host 受限设计与阻断协议\n来源:EverMind-AI/Raven 25c5768 的 dag_graph/dag_runner/dag_control_tools/dag_verdict/dag_resume、config/raven.py、playbook/stint.py;本目录 contract-audit.test.mjs 与 sdk/src/core/scoped-workflow-planner.ts。旧 docs/sdk/raven-fidelity-audit.md 关于单 worker 已过时,但任意 AND 依赖/在线控制缺口仍需按当前合同核对。\n\n本模板只提供固定双 specialist 并行批次+边界 judge+Host 决策。严格默认 Host 模式必须在 preflight 阻断,不能拿这个骨架作完整 Raven。scoped input 的 parallel 是原生并发;A→C 与 B→C 会产生两个 C arrival,不是 AND join。backend 只存图/实例/记忆和执行原子工具,不增加第二套 DAG 运行时,也不整套调用 Raven。\n\nHost 根据问题选择自己处理、单次委派或多步 DAG,并保存动态节点/依赖/instance 计划。此固定模板只有两个预绑定 slot,严格任意 roster/instance/每节点 Skills/MCP 需求返回 unsupported。受限批次实验需 Task manifest 明确 limited-batch 模式;Host 只能把当前两个依赖满足节点分给槽位,不能把整个任意 DAG 伪装成固定两支。少于两个任务时另一槽位是明确 idle,不产生任务/完成证据;这是容量演示的适配,不是原单次委派语义。Research/Code/Design/Oncall 按 roster 挑选,Design 的 PPT 路由只有 actual 能力就绪才允许,不强制全角色执行。\n\n每个 specialist 使用确切 node/instance/epoch/context、已 accepted 的跨图证据与实际 memory,逐步选择原子领域工具并保存 provisional 输出。judge 在批次边界检验任务完成,区分 incomplete、judge unavailable、signature invalid;未通过的输出不可给后继。最多两次 continuation(总共三尝试)计数跨重启保留;继续、放弃与重规划是 Host 决策,但此骨架不能对存活 worker 执行这些控制。需要“失败 A 等裁决时 B 继续”、后台通知中 Host 即时响应、取消旧图在途节点/继承已完成引用时,返回完整语义 unsupported,不能改为整批重跑。\n\n持久 stint 包含 playbook/round/budget/stop reason/graph successor 与 evidence。静态 sessionPersistence 仅覆盖两个槽位固定会话,不等价任意动态 instance 注册。恢复通过原 SDK run/state,不声称还原进程中协程/mailbox;孤立未终结节点须 interrupted 对账。strict-host 若未实现关键原生控制只能写 gaps.md 并暂停。离线 Evolver 和实验 Curator 不在此 Host 图内。",
"references/backend.md": "# 新增工作流的原子工具合同\n\n2026-10-14。此接口是本次设计选择,不是上游原有 API。`task-bridge.cjs` 是传输适配器,不能提供训练器、设备、知识图谱或科研算法本身;相应服务尚未实现/接入。所有新 workflow 内嵌该代码及逐角色 `tools.json`,可单独复制 JSON 校验。SDK 提供 MCP 协议库;外部依赖由服务部署方负责。\n\n## 部署与请求\n\n每个方法配置其 `*_BACKEND_URL`、`*_BACKEND_TOKEN` 和全新的 `*_SCOPE_ID` 环境变量。认证可选,但未启用认证时 `*_BACKEND_TOKEN` 仍须显式定义为空值,不能省略该 envFrom 源变量。workflow 的 `envFrom` 映射到桥接器的 `SCIENCEEVOLVE_TASK_BACKEND_URL/TOKEN/SCOPE_ID`。URL 是明确的 HTTPS 或本机 HTTP POST 端点;不保存凭据,不自动重定向。backend 在远端按 token/scope/actor 校验权限,不能把调用方传来的 actor 当身份认证。\n\n请求格式:\n\n```json\n{\"schemaVersion\":1,\"method\":\"internagent-1-5\",\"scopeId\":\"unique-run-scope\",\"actor\":\"verification\",\"operation\":\"get_state\",\"requestId\":\"unique-read-id\",\"arguments\":{}}\n```\n\n响应必须回显 schemaVersion、method、scopeId、operation、requestId,并返回 `status: ok|blocked|failed|unknown`、`data` 和 `evidence` 数组。每个证据包含 `id/uri/kind/sha256`,SHA-256 是真实字节摘要。成功写入必须有非空的持久回执。`read_artifact` 返回 `data.text/data.sha256`,桥接器核验实际 UTF-8 字节;其他证据的科学内容仍需审核,不由传输层判定正确。成功提交作业表示已入队,只有后续 `get_job` 的真实终态与测量能证明执行。\n\n## 一致性与恢复\n\n- 状态保存在 backend 的专属 scope,不能放在 SDK 会刷新的 Skill/MCP 执行副本。各 worktree 只导出自己的结果目录。\n- 写操作要求稳定 `requestId`;状态变更还要求 `expectedRevision`。backend 在事务中实现幂等、CAS 和追加式事件账本。参数相同的重放返回原回执;同 ID 不同参数拒绝。\n- 30 秒传输超时或异常响应后,写操作结果为 unknown。用 `get_request(originalRequestId)` 对账,不换 ID 重复训练、部署或物理作业。查询本身不触发新作业。\n- backend 返回类型化的能力清单、原子接口版本、软件/模型/数据/评分器摘要、资源探测和预算。能力缺失返回 blocked,不提供模拟回执。\n- 服务只能提供检索、图/记忆存取、数值选择/回传、具体环境步、编译、实验作业、训练作业和权重部署等原子操作。禁止暴露 `run_internagent/run_raven_host/run_coscientist` 等完整自治系统入口。研究规划、候选内容、优化方向和终止裁决由 SDK Agent 作出。\n\n## 各方法的附加合同\n\n### InternAgent 1.5\n\n能力清单至少包括真实文献检索/全文、图+向量检索、FlowGraph CAS、可执行 baseline、实验评分器、图增强 Monte Carlo 的数值选择/回传、SPM/TEM/SKM 以及有效 embedding。任务记忆、在线保存、长期 IdeaGraph/PromptEvolver 与 DR 的 SPM 需区分。`select_search_context` 返回选择参数、visit/value、父/祖先/跨支引用、运算符和租约,Agent 产生候选;`record_evaluation` 根据真实 job 回执回传分数。不得把最新 MLEvolve 整体启动当成这些能力。\n\nFlowGraph 节点含 search/solve/answer 类型、任务、状态、结果 context;边含 requires/provides/constrains 语义、来源与修订。`claim_flow_node` 事务中检查全部依赖、节点未重复执行、分支身份与 epoch。当前 SDK 用两个 worker 在批次边界调度,新增动态节点只能由 Planner 后续批次处理:这保持数据依赖,但不是原方法即时按 ready-set 推进,报告须扣分。\n\n### Biomni-R0\n\n`read_training_recipe` 必须给出已溯源的原方法 recipe 及待核对项、基础权重/环境/任务版本、真实 reward 定义、数据划分、训练/评估参数。无法核对原训练策略时,不能填写自选 GRPO/PPO 或随意 reward 当作原方法。此设计没有固化未经证实的 SFT/RL 阶段;服务按核实 recipe 执行原子训练作业。训练前核验 reward 与 split,held-out 标注不进入训练上下文。\n\n`collect_trajectories` 是固定 policy 与真实 E1 工具环境的任务执行;轨迹保留 observation/action/tool result/terminal outcome/policy hash,不包含自改研究规划。`score_trajectories` 由独立评分器产出奖励。`submit_training` 必须返回 job、输入轨迹/奖励/recipe 摘要;终态返回真实 checkpoint。部署和评估均绑定 checkpoint 字节摘要,明确环境与旧权重回退。使用发布成品 R0 只能作为比较基线,不能替代训练。\n\n### Chemical Coscientist\n\n检索/设备文档工具返回真实 URL、版本、内容摘要及可读取证据;文档必须与实际设备/API 匹配。`compile_protocol` 校验输入代码和设备能力,返回源码摘要、编译结果与设备绑定。`submit_experiment` 需要真实 `authorizationId` 和相同代码/设备摘要;设备服务在提交端核验授权、参数范围与资源,workflow prompt 不代替设备约束。\n\n`get_job` 返回真实物理作业状态、测量/错误/样品链;断线未知作业先对账。优化读取真实结果、噪声/失败和预算后决定下一实验。Git 只管理代码/报告,不能撤销湿实验。simulation/historical-data 是独立标记的模式,不计为湿实验复现。\n\n### Raven Host\n\n新模板只提供 SDK 内可执行的固定双 specialist 批次及边界判定骨架。backend 仅记录图、节点、instance、记忆与原子领域工具,不可承担 Host 规划或另建运行时来声称 SDK 原生支持完整 Raven。严格默认 Host 需求在 preflight 返回 blocked:当前合同缺任意 AND ready-set、在线通知/裁决、在途取消与图替换。\n\njudge 回执区分 incomplete、判定不可用、参数错误;未通过节点输出不能提供给依赖节点。最多两次 continuation 是节点总预算,不因新批次/重启归零。固定两个 SDK 会话仅提供有限 instance 复用;跨任意图实例、逐节点 Skills/MCP、stint 自动推进仍是待实现接口。这个模板不能把所有 specialist 强制串行,也不能把批次重跑写成原语义的在线 continue/replan。\n\n## 运行前应做的验证\n\n先离线校验 JSON 和实际 Skill/MCP 暂存,再对部署后的原子服务验证资源/权限/幂等/CAS/unknown 对账,最后才运行真实方法。JSON 校验、桥接 localhost 合同或接口清单不等于方法/论文验收。每次新运行记录唯一 SDK run ID 与 backend scope,保留负面结果、源字节摘要、累计预算和完整事件链。\n"
}
}
},
"mcpDefinitions": {
"task-main": {
"command": "node",
"entrypoint": "task-bridge.cjs",
"args": [],
"envFrom": {
"SCIENCEEVOLVE_TASK_BACKEND_URL": "SCIENCEEVOLVE_RAVEN_BACKEND_URL",
"SCIENCEEVOLVE_TASK_BACKEND_TOKEN": "SCIENCEEVOLVE_RAVEN_BACKEND_TOKEN",
"SCIENCEEVOLVE_TASK_SCOPE_ID": "SCIENCEEVOLVE_RAVEN_SCOPE_ID"
},
"files": {
"task-bridge.cjs": "'use strict';\n// Transport only. Scientific decisions stay in SCIENCEEVOLVE agents; backends expose atomic tools.\nconst { Server } = require('@modelcontextprotocol/sdk/server/index.js');\nconst { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');\nconst { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');\nconst { randomUUID, createHash } = require('node:crypto');\nconst spec = require('./tools.json');\n\nfunction check(schema, value, at = 'arguments') {\n if (schema.enum && !schema.enum.includes(value)) throw new Error(`${at}: unsupported enum`);\n if (schema.type === 'object') {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${at}: object required`);\n for (const key of schema.required || []) if (!(key in value)) throw new Error(`${at}.${key}: required`);\n for (const [key, item] of Object.entries(value)) {\n if (schema.properties?.[key]) check(schema.properties[key], item, `${at}.${key}`);\n else if (schema.additionalProperties === false) throw new Error(`${at}.${key}: unknown field`);\n }\n } else if (schema.type === 'array') {\n if (!Array.isArray(value)) throw new Error(`${at}: array required`);\n if (schema.minItems !== undefined && value.length < schema.minItems) throw new Error(`${at}: too few items`);\n if (schema.maxItems !== undefined && value.length > schema.maxItems) throw new Error(`${at}: too many items`);\n for (const item of value) check(schema.items, item, `${at}[]`);\n } else if (schema.type === 'string') {\n if (typeof value !== 'string' || value.length < (schema.minLength ?? 0) || value.length > (schema.maxLength ?? Infinity)) throw new Error(`${at}: invalid string`);\n if (schema.pattern && !new RegExp(schema.pattern).test(value)) throw new Error(`${at}: invalid pattern`);\n } else if (schema.type === 'integer') {\n if (!Number.isSafeInteger(value) || value < (schema.minimum ?? -Infinity) || value > (schema.maximum ?? Infinity)) throw new Error(`${at}: invalid integer`);\n } else if (schema.type === 'boolean') {\n if (typeof value !== 'boolean') throw new Error(`${at}: boolean required`);\n }\n}\n\nasync function dispatch(tool, args) {\n check(tool.inputSchema, args);\n const raw = process.env.SCIENCEEVOLVE_TASK_BACKEND_URL;\n const scopeId = process.env.SCIENCEEVOLVE_TASK_SCOPE_ID;\n if (!raw || !scopeId) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: 'blocked', reason: 'Configure the method-specific backend URL and a fresh scope ID; no backend is bundled.' }) }] };\n const endpoint = new URL(raw);\n if (!(endpoint.protocol === 'https:' || (endpoint.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(endpoint.hostname))) || endpoint.username || endpoint.password || endpoint.search || endpoint.hash) throw new Error('Use an explicit HTTPS or loopback HTTP endpoint without inline credentials');\n const requestId = tool.mode === 'write' ? args.requestId : randomUUID();\n if (tool.mode === 'write' && !requestId) throw new Error('Mutation requires a stable requestId');\n let response;\n try {\n response = await fetch(endpoint, {\n method: 'POST', redirect: 'error', signal: AbortSignal.timeout(30000),\n headers: { 'content-type': 'application/json', ...(process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN ? { authorization: `Bearer ${process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN}` } : {}) },\n body: JSON.stringify({ schemaVersion: 1, method: spec.method, scopeId, actor: spec.actor, operation: tool.name, requestId, arguments: args })\n });\n } catch {\n // Never retry a possibly accepted training/physical job automatically.\n return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, reason: 'Transport failed; reconcile this exact requestId using get_request. Do not create a replacement job.' }) }] };\n }\n if (!response.ok) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, httpStatus: response.status, reason: 'Reconcile before replaying any mutation.' }) }] };\n const body = await response.text();\n if (Buffer.byteLength(body) > 2 * 1024 * 1024) throw new Error('Backend response too large; use paged evidence');\n const result = JSON.parse(body);\n if (result.schemaVersion !== 1 || result.method !== spec.method || result.scopeId !== scopeId || result.operation !== tool.name || result.requestId !== requestId) throw new Error(`Mismatched backend receipt; mutation outcome remains unknown: ${requestId}`);\n if (!['ok', 'blocked', 'failed', 'unknown'].includes(result.status)) throw new Error(`Invalid receipt status: ${requestId}`);\n if (!Array.isArray(result.evidence)) throw new Error(`Receipt requires an evidence array: ${requestId}`);\n for (const evidence of result.evidence) {\n if (!evidence || typeof evidence.id !== 'string' || typeof evidence.uri !== 'string' || typeof evidence.kind !== 'string' || !/^[a-f0-9]{64}$/.test(evidence.sha256)) throw new Error(`Malformed evidence reference: ${requestId}`);\n }\n if (tool.mode === 'write' && result.status === 'ok' && result.evidence.length === 0) throw new Error(`Successful mutation requires a durable receipt: ${requestId}`);\n if (tool.name === 'read_artifact' && result.status === 'ok') {\n if (typeof result.data?.text !== 'string' || createHash('sha256').update(result.data.text, 'utf8').digest('hex') !== result.data.sha256) throw new Error('Artifact bytes do not match the claimed SHA-256');\n }\n // Evidence references and an HTTP OK are not a scientific pass. Agents audit actual bytes/results.\n return { isError: result.status !== 'ok', content: [{ type: 'text', text: JSON.stringify(result) }] };\n}\n\nconst server = new Server({ name: `${spec.method}-${spec.actor}-atomic-tools`, version: '1.0.0' }, { capabilities: { tools: {} } });\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: spec.tools.map(({ mode, ...tool }) => tool) }));\nserver.setRequestHandler(CallToolRequestSchema, async request => {\n const tool = spec.tools.find(item => item.name === request.params.name);\n if (!tool) throw new Error('Tool is not assigned to this role');\n try { return await dispatch(tool, request.params.arguments || {}); }\n catch (error) { return { isError: true, content: [{ type: 'text', text: error.message }] }; }\n});\nserver.connect(new StdioServerTransport());\nprocess.stdin.on('end', () => { server.close().finally(() => process.exit()); });\n\n",
"tools.json": "{\n \"method\": \"raven-host\",\n \"actor\": \"main\",\n \"tools\": [\n {\n \"name\": \"get_capabilities\",\n \"description\": \"Read actual method/tool versions, resources, scope budget, provenance and capability limitations. A design declaration is not a resource probe.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_state\",\n \"description\": \"Read durable current scope revision, budgets, jobs, graph/memory/weight versions and accepted evidence. Do not infer current tasks from an old predecessor handoff.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_request\",\n \"description\": \"Reconcile the original durable request without submitting another job; preserve unknown until authoritative evidence exists.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"originalRequestId\"\n ],\n \"properties\": {\n \"originalRequestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_job\",\n \"description\": \"Read actual job status, input/output hashes, error or measurement receipts. Accepted/queued is not completed.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"jobId\"\n ],\n \"properties\": {\n \"jobId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"read_artifact\",\n \"description\": \"Read a small retained UTF-8 artifact and verify its SHA-256 bytes; paginate large evidence at the backend.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"artifactId\"\n ],\n \"properties\": {\n \"artifactId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_roster\",\n \"description\": \"Read actual Research/Code/Design/Oncall capabilities and conditional Design-to-PPT route; unavailable skills/tools are explicit.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"record_host_plan\",\n \"description\": \"Persist Host-authored graph/node IDs, dependencies, instance assignments, verdict/continuation budget and cross-graph accepted evidence. State storage does not schedule a dynamic DAG.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"graph\",\n \"assignments\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"graph\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"assignments\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n {\n \"name\": \"record_stint\",\n \"description\": \"Record playbook round, accepted evidence, budget, stop reason and graph successor lineage; does not implement live graph cancellation or automatic stint execution.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"stint\",\n \"evidenceIds\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"stint\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"evidenceIds\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"minItems\": 1,\n \"maxItems\": 100\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n {\n \"name\": \"retrieve_memory\",\n \"description\": \"Retrieve an actual SPM, TEM or SKM record with query, similarity, record IDs and injected context; report empty/unavailable explicitly.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"query\",\n \"memoryType\"\n ],\n \"properties\": {\n \"query\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"memoryType\": {\n \"type\": \"string\",\n \"enum\": [\n \"SPM\",\n \"TEM\",\n \"SKM\"\n ]\n }\n }\n }\n }\n ]\n}\n"
}
},
"task-preflight": {
"command": "node",
"entrypoint": "task-bridge.cjs",
"args": [],
"envFrom": {
"SCIENCEEVOLVE_TASK_BACKEND_URL": "SCIENCEEVOLVE_RAVEN_BACKEND_URL",
"SCIENCEEVOLVE_TASK_BACKEND_TOKEN": "SCIENCEEVOLVE_RAVEN_BACKEND_TOKEN",
"SCIENCEEVOLVE_TASK_SCOPE_ID": "SCIENCEEVOLVE_RAVEN_SCOPE_ID"
},
"files": {
"task-bridge.cjs": "'use strict';\n// Transport only. Scientific decisions stay in SCIENCEEVOLVE agents; backends expose atomic tools.\nconst { Server } = require('@modelcontextprotocol/sdk/server/index.js');\nconst { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');\nconst { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');\nconst { randomUUID, createHash } = require('node:crypto');\nconst spec = require('./tools.json');\n\nfunction check(schema, value, at = 'arguments') {\n if (schema.enum && !schema.enum.includes(value)) throw new Error(`${at}: unsupported enum`);\n if (schema.type === 'object') {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${at}: object required`);\n for (const key of schema.required || []) if (!(key in value)) throw new Error(`${at}.${key}: required`);\n for (const [key, item] of Object.entries(value)) {\n if (schema.properties?.[key]) check(schema.properties[key], item, `${at}.${key}`);\n else if (schema.additionalProperties === false) throw new Error(`${at}.${key}: unknown field`);\n }\n } else if (schema.type === 'array') {\n if (!Array.isArray(value)) throw new Error(`${at}: array required`);\n if (schema.minItems !== undefined && value.length < schema.minItems) throw new Error(`${at}: too few items`);\n if (schema.maxItems !== undefined && value.length > schema.maxItems) throw new Error(`${at}: too many items`);\n for (const item of value) check(schema.items, item, `${at}[]`);\n } else if (schema.type === 'string') {\n if (typeof value !== 'string' || value.length < (schema.minLength ?? 0) || value.length > (schema.maxLength ?? Infinity)) throw new Error(`${at}: invalid string`);\n if (schema.pattern && !new RegExp(schema.pattern).test(value)) throw new Error(`${at}: invalid pattern`);\n } else if (schema.type === 'integer') {\n if (!Number.isSafeInteger(value) || value < (schema.minimum ?? -Infinity) || value > (schema.maximum ?? Infinity)) throw new Error(`${at}: invalid integer`);\n } else if (schema.type === 'boolean') {\n if (typeof value !== 'boolean') throw new Error(`${at}: boolean required`);\n }\n}\n\nasync function dispatch(tool, args) {\n check(tool.inputSchema, args);\n const raw = process.env.SCIENCEEVOLVE_TASK_BACKEND_URL;\n const scopeId = process.env.SCIENCEEVOLVE_TASK_SCOPE_ID;\n if (!raw || !scopeId) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: 'blocked', reason: 'Configure the method-specific backend URL and a fresh scope ID; no backend is bundled.' }) }] };\n const endpoint = new URL(raw);\n if (!(endpoint.protocol === 'https:' || (endpoint.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(endpoint.hostname))) || endpoint.username || endpoint.password || endpoint.search || endpoint.hash) throw new Error('Use an explicit HTTPS or loopback HTTP endpoint without inline credentials');\n const requestId = tool.mode === 'write' ? args.requestId : randomUUID();\n if (tool.mode === 'write' && !requestId) throw new Error('Mutation requires a stable requestId');\n let response;\n try {\n response = await fetch(endpoint, {\n method: 'POST', redirect: 'error', signal: AbortSignal.timeout(30000),\n headers: { 'content-type': 'application/json', ...(process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN ? { authorization: `Bearer ${process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN}` } : {}) },\n body: JSON.stringify({ schemaVersion: 1, method: spec.method, scopeId, actor: spec.actor, operation: tool.name, requestId, arguments: args })\n });\n } catch {\n // Never retry a possibly accepted training/physical job automatically.\n return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, reason: 'Transport failed; reconcile this exact requestId using get_request. Do not create a replacement job.' }) }] };\n }\n if (!response.ok) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, httpStatus: response.status, reason: 'Reconcile before replaying any mutation.' }) }] };\n const body = await response.text();\n if (Buffer.byteLength(body) > 2 * 1024 * 1024) throw new Error('Backend response too large; use paged evidence');\n const result = JSON.parse(body);\n if (result.schemaVersion !== 1 || result.method !== spec.method || result.scopeId !== scopeId || result.operation !== tool.name || result.requestId !== requestId) throw new Error(`Mismatched backend receipt; mutation outcome remains unknown: ${requestId}`);\n if (!['ok', 'blocked', 'failed', 'unknown'].includes(result.status)) throw new Error(`Invalid receipt status: ${requestId}`);\n if (!Array.isArray(result.evidence)) throw new Error(`Receipt requires an evidence array: ${requestId}`);\n for (const evidence of result.evidence) {\n if (!evidence || typeof evidence.id !== 'string' || typeof evidence.uri !== 'string' || typeof evidence.kind !== 'string' || !/^[a-f0-9]{64}$/.test(evidence.sha256)) throw new Error(`Malformed evidence reference: ${requestId}`);\n }\n if (tool.mode === 'write' && result.status === 'ok' && result.evidence.length === 0) throw new Error(`Successful mutation requires a durable receipt: ${requestId}`);\n if (tool.name === 'read_artifact' && result.status === 'ok') {\n if (typeof result.data?.text !== 'string' || createHash('sha256').update(result.data.text, 'utf8').digest('hex') !== result.data.sha256) throw new Error('Artifact bytes do not match the claimed SHA-256');\n }\n // Evidence references and an HTTP OK are not a scientific pass. Agents audit actual bytes/results.\n return { isError: result.status !== 'ok', content: [{ type: 'text', text: JSON.stringify(result) }] };\n}\n\nconst server = new Server({ name: `${spec.method}-${spec.actor}-atomic-tools`, version: '1.0.0' }, { capabilities: { tools: {} } });\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: spec.tools.map(({ mode, ...tool }) => tool) }));\nserver.setRequestHandler(CallToolRequestSchema, async request => {\n const tool = spec.tools.find(item => item.name === request.params.name);\n if (!tool) throw new Error('Tool is not assigned to this role');\n try { return await dispatch(tool, request.params.arguments || {}); }\n catch (error) { return { isError: true, content: [{ type: 'text', text: error.message }] }; }\n});\nserver.connect(new StdioServerTransport());\nprocess.stdin.on('end', () => { server.close().finally(() => process.exit()); });\n\n",
"tools.json": "{\n \"method\": \"raven-host\",\n \"actor\": \"preflight\",\n \"tools\": [\n {\n \"name\": \"get_capabilities\",\n \"description\": \"Read actual method/tool versions, resources, scope budget, provenance and capability limitations. A design declaration is not a resource probe.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_state\",\n \"description\": \"Read durable current scope revision, budgets, jobs, graph/memory/weight versions and accepted evidence. Do not infer current tasks from an old predecessor handoff.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_request\",\n \"description\": \"Reconcile the original durable request without submitting another job; preserve unknown until authoritative evidence exists.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"originalRequestId\"\n ],\n \"properties\": {\n \"originalRequestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_job\",\n \"description\": \"Read actual job status, input/output hashes, error or measurement receipts. Accepted/queued is not completed.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"jobId\"\n ],\n \"properties\": {\n \"jobId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"read_artifact\",\n \"description\": \"Read a small retained UTF-8 artifact and verify its SHA-256 bytes; paginate large evidence at the backend.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"artifactId\"\n ],\n \"properties\": {\n \"artifactId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_roster\",\n \"description\": \"Read actual Research/Code/Design/Oncall capabilities and conditional Design-to-PPT route; unavailable skills/tools are explicit.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n }\n ]\n}\n"
}
},
"task-specialist_a": {
"command": "node",
"entrypoint": "task-bridge.cjs",
"args": [],
"envFrom": {
"SCIENCEEVOLVE_TASK_BACKEND_URL": "SCIENCEEVOLVE_RAVEN_BACKEND_URL",
"SCIENCEEVOLVE_TASK_BACKEND_TOKEN": "SCIENCEEVOLVE_RAVEN_BACKEND_TOKEN",
"SCIENCEEVOLVE_TASK_SCOPE_ID": "SCIENCEEVOLVE_RAVEN_SCOPE_ID"
},
"files": {
"task-bridge.cjs": "'use strict';\n// Transport only. Scientific decisions stay in SCIENCEEVOLVE agents; backends expose atomic tools.\nconst { Server } = require('@modelcontextprotocol/sdk/server/index.js');\nconst { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');\nconst { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');\nconst { randomUUID, createHash } = require('node:crypto');\nconst spec = require('./tools.json');\n\nfunction check(schema, value, at = 'arguments') {\n if (schema.enum && !schema.enum.includes(value)) throw new Error(`${at}: unsupported enum`);\n if (schema.type === 'object') {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${at}: object required`);\n for (const key of schema.required || []) if (!(key in value)) throw new Error(`${at}.${key}: required`);\n for (const [key, item] of Object.entries(value)) {\n if (schema.properties?.[key]) check(schema.properties[key], item, `${at}.${key}`);\n else if (schema.additionalProperties === false) throw new Error(`${at}.${key}: unknown field`);\n }\n } else if (schema.type === 'array') {\n if (!Array.isArray(value)) throw new Error(`${at}: array required`);\n if (schema.minItems !== undefined && value.length < schema.minItems) throw new Error(`${at}: too few items`);\n if (schema.maxItems !== undefined && value.length > schema.maxItems) throw new Error(`${at}: too many items`);\n for (const item of value) check(schema.items, item, `${at}[]`);\n } else if (schema.type === 'string') {\n if (typeof value !== 'string' || value.length < (schema.minLength ?? 0) || value.length > (schema.maxLength ?? Infinity)) throw new Error(`${at}: invalid string`);\n if (schema.pattern && !new RegExp(schema.pattern).test(value)) throw new Error(`${at}: invalid pattern`);\n } else if (schema.type === 'integer') {\n if (!Number.isSafeInteger(value) || value < (schema.minimum ?? -Infinity) || value > (schema.maximum ?? Infinity)) throw new Error(`${at}: invalid integer`);\n } else if (schema.type === 'boolean') {\n if (typeof value !== 'boolean') throw new Error(`${at}: boolean required`);\n }\n}\n\nasync function dispatch(tool, args) {\n check(tool.inputSchema, args);\n const raw = process.env.SCIENCEEVOLVE_TASK_BACKEND_URL;\n const scopeId = process.env.SCIENCEEVOLVE_TASK_SCOPE_ID;\n if (!raw || !scopeId) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: 'blocked', reason: 'Configure the method-specific backend URL and a fresh scope ID; no backend is bundled.' }) }] };\n const endpoint = new URL(raw);\n if (!(endpoint.protocol === 'https:' || (endpoint.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(endpoint.hostname))) || endpoint.username || endpoint.password || endpoint.search || endpoint.hash) throw new Error('Use an explicit HTTPS or loopback HTTP endpoint without inline credentials');\n const requestId = tool.mode === 'write' ? args.requestId : randomUUID();\n if (tool.mode === 'write' && !requestId) throw new Error('Mutation requires a stable requestId');\n let response;\n try {\n response = await fetch(endpoint, {\n method: 'POST', redirect: 'error', signal: AbortSignal.timeout(30000),\n headers: { 'content-type': 'application/json', ...(process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN ? { authorization: `Bearer ${process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN}` } : {}) },\n body: JSON.stringify({ schemaVersion: 1, method: spec.method, scopeId, actor: spec.actor, operation: tool.name, requestId, arguments: args })\n });\n } catch {\n // Never retry a possibly accepted training/physical job automatically.\n return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, reason: 'Transport failed; reconcile this exact requestId using get_request. Do not create a replacement job.' }) }] };\n }\n if (!response.ok) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, httpStatus: response.status, reason: 'Reconcile before replaying any mutation.' }) }] };\n const body = await response.text();\n if (Buffer.byteLength(body) > 2 * 1024 * 1024) throw new Error('Backend response too large; use paged evidence');\n const result = JSON.parse(body);\n if (result.schemaVersion !== 1 || result.method !== spec.method || result.scopeId !== scopeId || result.operation !== tool.name || result.requestId !== requestId) throw new Error(`Mismatched backend receipt; mutation outcome remains unknown: ${requestId}`);\n if (!['ok', 'blocked', 'failed', 'unknown'].includes(result.status)) throw new Error(`Invalid receipt status: ${requestId}`);\n if (!Array.isArray(result.evidence)) throw new Error(`Receipt requires an evidence array: ${requestId}`);\n for (const evidence of result.evidence) {\n if (!evidence || typeof evidence.id !== 'string' || typeof evidence.uri !== 'string' || typeof evidence.kind !== 'string' || !/^[a-f0-9]{64}$/.test(evidence.sha256)) throw new Error(`Malformed evidence reference: ${requestId}`);\n }\n if (tool.mode === 'write' && result.status === 'ok' && result.evidence.length === 0) throw new Error(`Successful mutation requires a durable receipt: ${requestId}`);\n if (tool.name === 'read_artifact' && result.status === 'ok') {\n if (typeof result.data?.text !== 'string' || createHash('sha256').update(result.data.text, 'utf8').digest('hex') !== result.data.sha256) throw new Error('Artifact bytes do not match the claimed SHA-256');\n }\n // Evidence references and an HTTP OK are not a scientific pass. Agents audit actual bytes/results.\n return { isError: result.status !== 'ok', content: [{ type: 'text', text: JSON.stringify(result) }] };\n}\n\nconst server = new Server({ name: `${spec.method}-${spec.actor}-atomic-tools`, version: '1.0.0' }, { capabilities: { tools: {} } });\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: spec.tools.map(({ mode, ...tool }) => tool) }));\nserver.setRequestHandler(CallToolRequestSchema, async request => {\n const tool = spec.tools.find(item => item.name === request.params.name);\n if (!tool) throw new Error('Tool is not assigned to this role');\n try { return await dispatch(tool, request.params.arguments || {}); }\n catch (error) { return { isError: true, content: [{ type: 'text', text: error.message }] }; }\n});\nserver.connect(new StdioServerTransport());\nprocess.stdin.on('end', () => { server.close().finally(() => process.exit()); });\n\n",
"tools.json": "{\n \"method\": \"raven-host\",\n \"actor\": \"specialist_a\",\n \"tools\": [\n {\n \"name\": \"get_capabilities\",\n \"description\": \"Read actual method/tool versions, resources, scope budget, provenance and capability limitations. A design declaration is not a resource probe.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_state\",\n \"description\": \"Read durable current scope revision, budgets, jobs, graph/memory/weight versions and accepted evidence. Do not infer current tasks from an old predecessor handoff.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_request\",\n \"description\": \"Reconcile the original durable request without submitting another job; preserve unknown until authoritative evidence exists.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"originalRequestId\"\n ],\n \"properties\": {\n \"originalRequestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_job\",\n \"description\": \"Read actual job status, input/output hashes, error or measurement receipts. Accepted/queued is not completed.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"jobId\"\n ],\n \"properties\": {\n \"jobId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"read_artifact\",\n \"description\": \"Read a small retained UTF-8 artifact and verify its SHA-256 bytes; paginate large evidence at the backend.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"artifactId\"\n ],\n \"properties\": {\n \"artifactId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_roster\",\n \"description\": \"Read actual Research/Code/Design/Oncall capabilities and conditional Design-to-PPT route; unavailable skills/tools are explicit.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_node\",\n \"description\": \"Read exact node/attempt/instance/epoch, accepted dependencies, completion receipt and output visibility.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"retrieve_memory\",\n \"description\": \"Retrieve an actual SPM, TEM or SKM record with query, similarity, record IDs and injected context; report empty/unavailable explicitly.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"query\",\n \"memoryType\"\n ],\n \"properties\": {\n \"query\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"memoryType\": {\n \"type\": \"string\",\n \"enum\": [\n \"SPM\",\n \"TEM\",\n \"SKM\"\n ]\n }\n }\n }\n },\n {\n \"name\": \"specialist_step\",\n \"description\": \"Execute one atomic role-specific domain tool chosen by the SDK specialist. Does not run Raven Host or an autonomous specialist loop.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\",\n \"instanceId\",\n \"operation\",\n \"payload\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"instanceId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"operation\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"payload\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n {\n \"name\": \"record_node_result\",\n \"description\": \"Persist specialist evidence as provisional, not successor-visible until judged complete; bind instance and ownership epoch.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\",\n \"result\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"result\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n {\n \"name\": \"export_evidence\",\n \"description\": \"Create an immutable scope evidence manifest for this actor. Export receipt does not commit SDK branch files or complete a group.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"selection\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"selection\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"minItems\": 1,\n \"maxItems\": 100\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n }\n ]\n}\n"
}
},
"task-specialist_b": {
"command": "node",
"entrypoint": "task-bridge.cjs",
"args": [],
"envFrom": {
"SCIENCEEVOLVE_TASK_BACKEND_URL": "SCIENCEEVOLVE_RAVEN_BACKEND_URL",
"SCIENCEEVOLVE_TASK_BACKEND_TOKEN": "SCIENCEEVOLVE_RAVEN_BACKEND_TOKEN",
"SCIENCEEVOLVE_TASK_SCOPE_ID": "SCIENCEEVOLVE_RAVEN_SCOPE_ID"
},
"files": {
"task-bridge.cjs": "'use strict';\n// Transport only. Scientific decisions stay in SCIENCEEVOLVE agents; backends expose atomic tools.\nconst { Server } = require('@modelcontextprotocol/sdk/server/index.js');\nconst { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');\nconst { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');\nconst { randomUUID, createHash } = require('node:crypto');\nconst spec = require('./tools.json');\n\nfunction check(schema, value, at = 'arguments') {\n if (schema.enum && !schema.enum.includes(value)) throw new Error(`${at}: unsupported enum`);\n if (schema.type === 'object') {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${at}: object required`);\n for (const key of schema.required || []) if (!(key in value)) throw new Error(`${at}.${key}: required`);\n for (const [key, item] of Object.entries(value)) {\n if (schema.properties?.[key]) check(schema.properties[key], item, `${at}.${key}`);\n else if (schema.additionalProperties === false) throw new Error(`${at}.${key}: unknown field`);\n }\n } else if (schema.type === 'array') {\n if (!Array.isArray(value)) throw new Error(`${at}: array required`);\n if (schema.minItems !== undefined && value.length < schema.minItems) throw new Error(`${at}: too few items`);\n if (schema.maxItems !== undefined && value.length > schema.maxItems) throw new Error(`${at}: too many items`);\n for (const item of value) check(schema.items, item, `${at}[]`);\n } else if (schema.type === 'string') {\n if (typeof value !== 'string' || value.length < (schema.minLength ?? 0) || value.length > (schema.maxLength ?? Infinity)) throw new Error(`${at}: invalid string`);\n if (schema.pattern && !new RegExp(schema.pattern).test(value)) throw new Error(`${at}: invalid pattern`);\n } else if (schema.type === 'integer') {\n if (!Number.isSafeInteger(value) || value < (schema.minimum ?? -Infinity) || value > (schema.maximum ?? Infinity)) throw new Error(`${at}: invalid integer`);\n } else if (schema.type === 'boolean') {\n if (typeof value !== 'boolean') throw new Error(`${at}: boolean required`);\n }\n}\n\nasync function dispatch(tool, args) {\n check(tool.inputSchema, args);\n const raw = process.env.SCIENCEEVOLVE_TASK_BACKEND_URL;\n const scopeId = process.env.SCIENCEEVOLVE_TASK_SCOPE_ID;\n if (!raw || !scopeId) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: 'blocked', reason: 'Configure the method-specific backend URL and a fresh scope ID; no backend is bundled.' }) }] };\n const endpoint = new URL(raw);\n if (!(endpoint.protocol === 'https:' || (endpoint.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(endpoint.hostname))) || endpoint.username || endpoint.password || endpoint.search || endpoint.hash) throw new Error('Use an explicit HTTPS or loopback HTTP endpoint without inline credentials');\n const requestId = tool.mode === 'write' ? args.requestId : randomUUID();\n if (tool.mode === 'write' && !requestId) throw new Error('Mutation requires a stable requestId');\n let response;\n try {\n response = await fetch(endpoint, {\n method: 'POST', redirect: 'error', signal: AbortSignal.timeout(30000),\n headers: { 'content-type': 'application/json', ...(process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN ? { authorization: `Bearer ${process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN}` } : {}) },\n body: JSON.stringify({ schemaVersion: 1, method: spec.method, scopeId, actor: spec.actor, operation: tool.name, requestId, arguments: args })\n });\n } catch {\n // Never retry a possibly accepted training/physical job automatically.\n return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, reason: 'Transport failed; reconcile this exact requestId using get_request. Do not create a replacement job.' }) }] };\n }\n if (!response.ok) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, httpStatus: response.status, reason: 'Reconcile before replaying any mutation.' }) }] };\n const body = await response.text();\n if (Buffer.byteLength(body) > 2 * 1024 * 1024) throw new Error('Backend response too large; use paged evidence');\n const result = JSON.parse(body);\n if (result.schemaVersion !== 1 || result.method !== spec.method || result.scopeId !== scopeId || result.operation !== tool.name || result.requestId !== requestId) throw new Error(`Mismatched backend receipt; mutation outcome remains unknown: ${requestId}`);\n if (!['ok', 'blocked', 'failed', 'unknown'].includes(result.status)) throw new Error(`Invalid receipt status: ${requestId}`);\n if (!Array.isArray(result.evidence)) throw new Error(`Receipt requires an evidence array: ${requestId}`);\n for (const evidence of result.evidence) {\n if (!evidence || typeof evidence.id !== 'string' || typeof evidence.uri !== 'string' || typeof evidence.kind !== 'string' || !/^[a-f0-9]{64}$/.test(evidence.sha256)) throw new Error(`Malformed evidence reference: ${requestId}`);\n }\n if (tool.mode === 'write' && result.status === 'ok' && result.evidence.length === 0) throw new Error(`Successful mutation requires a durable receipt: ${requestId}`);\n if (tool.name === 'read_artifact' && result.status === 'ok') {\n if (typeof result.data?.text !== 'string' || createHash('sha256').update(result.data.text, 'utf8').digest('hex') !== result.data.sha256) throw new Error('Artifact bytes do not match the claimed SHA-256');\n }\n // Evidence references and an HTTP OK are not a scientific pass. Agents audit actual bytes/results.\n return { isError: result.status !== 'ok', content: [{ type: 'text', text: JSON.stringify(result) }] };\n}\n\nconst server = new Server({ name: `${spec.method}-${spec.actor}-atomic-tools`, version: '1.0.0' }, { capabilities: { tools: {} } });\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: spec.tools.map(({ mode, ...tool }) => tool) }));\nserver.setRequestHandler(CallToolRequestSchema, async request => {\n const tool = spec.tools.find(item => item.name === request.params.name);\n if (!tool) throw new Error('Tool is not assigned to this role');\n try { return await dispatch(tool, request.params.arguments || {}); }\n catch (error) { return { isError: true, content: [{ type: 'text', text: error.message }] }; }\n});\nserver.connect(new StdioServerTransport());\nprocess.stdin.on('end', () => { server.close().finally(() => process.exit()); });\n\n",
"tools.json": "{\n \"method\": \"raven-host\",\n \"actor\": \"specialist_b\",\n \"tools\": [\n {\n \"name\": \"get_capabilities\",\n \"description\": \"Read actual method/tool versions, resources, scope budget, provenance and capability limitations. A design declaration is not a resource probe.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_state\",\n \"description\": \"Read durable current scope revision, budgets, jobs, graph/memory/weight versions and accepted evidence. Do not infer current tasks from an old predecessor handoff.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_request\",\n \"description\": \"Reconcile the original durable request without submitting another job; preserve unknown until authoritative evidence exists.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"originalRequestId\"\n ],\n \"properties\": {\n \"originalRequestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_job\",\n \"description\": \"Read actual job status, input/output hashes, error or measurement receipts. Accepted/queued is not completed.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"jobId\"\n ],\n \"properties\": {\n \"jobId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"read_artifact\",\n \"description\": \"Read a small retained UTF-8 artifact and verify its SHA-256 bytes; paginate large evidence at the backend.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"artifactId\"\n ],\n \"properties\": {\n \"artifactId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_roster\",\n \"description\": \"Read actual Research/Code/Design/Oncall capabilities and conditional Design-to-PPT route; unavailable skills/tools are explicit.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_node\",\n \"description\": \"Read exact node/attempt/instance/epoch, accepted dependencies, completion receipt and output visibility.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"retrieve_memory\",\n \"description\": \"Retrieve an actual SPM, TEM or SKM record with query, similarity, record IDs and injected context; report empty/unavailable explicitly.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"query\",\n \"memoryType\"\n ],\n \"properties\": {\n \"query\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"memoryType\": {\n \"type\": \"string\",\n \"enum\": [\n \"SPM\",\n \"TEM\",\n \"SKM\"\n ]\n }\n }\n }\n },\n {\n \"name\": \"specialist_step\",\n \"description\": \"Execute one atomic role-specific domain tool chosen by the SDK specialist. Does not run Raven Host or an autonomous specialist loop.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\",\n \"instanceId\",\n \"operation\",\n \"payload\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"instanceId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"operation\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"payload\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n {\n \"name\": \"record_node_result\",\n \"description\": \"Persist specialist evidence as provisional, not successor-visible until judged complete; bind instance and ownership epoch.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\",\n \"result\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"result\": {\n \"type\": \"object\",\n \"additionalProperties\": true\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n {\n \"name\": \"export_evidence\",\n \"description\": \"Create an immutable scope evidence manifest for this actor. Export receipt does not commit SDK branch files or complete a group.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"selection\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"selection\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"minItems\": 1,\n \"maxItems\": 100\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n }\n ]\n}\n"
}
},
"task-judge": {
"command": "node",
"entrypoint": "task-bridge.cjs",
"args": [],
"envFrom": {
"SCIENCEEVOLVE_TASK_BACKEND_URL": "SCIENCEEVOLVE_RAVEN_BACKEND_URL",
"SCIENCEEVOLVE_TASK_BACKEND_TOKEN": "SCIENCEEVOLVE_RAVEN_BACKEND_TOKEN",
"SCIENCEEVOLVE_TASK_SCOPE_ID": "SCIENCEEVOLVE_RAVEN_SCOPE_ID"
},
"files": {
"task-bridge.cjs": "'use strict';\n// Transport only. Scientific decisions stay in SCIENCEEVOLVE agents; backends expose atomic tools.\nconst { Server } = require('@modelcontextprotocol/sdk/server/index.js');\nconst { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');\nconst { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');\nconst { randomUUID, createHash } = require('node:crypto');\nconst spec = require('./tools.json');\n\nfunction check(schema, value, at = 'arguments') {\n if (schema.enum && !schema.enum.includes(value)) throw new Error(`${at}: unsupported enum`);\n if (schema.type === 'object') {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${at}: object required`);\n for (const key of schema.required || []) if (!(key in value)) throw new Error(`${at}.${key}: required`);\n for (const [key, item] of Object.entries(value)) {\n if (schema.properties?.[key]) check(schema.properties[key], item, `${at}.${key}`);\n else if (schema.additionalProperties === false) throw new Error(`${at}.${key}: unknown field`);\n }\n } else if (schema.type === 'array') {\n if (!Array.isArray(value)) throw new Error(`${at}: array required`);\n if (schema.minItems !== undefined && value.length < schema.minItems) throw new Error(`${at}: too few items`);\n if (schema.maxItems !== undefined && value.length > schema.maxItems) throw new Error(`${at}: too many items`);\n for (const item of value) check(schema.items, item, `${at}[]`);\n } else if (schema.type === 'string') {\n if (typeof value !== 'string' || value.length < (schema.minLength ?? 0) || value.length > (schema.maxLength ?? Infinity)) throw new Error(`${at}: invalid string`);\n if (schema.pattern && !new RegExp(schema.pattern).test(value)) throw new Error(`${at}: invalid pattern`);\n } else if (schema.type === 'integer') {\n if (!Number.isSafeInteger(value) || value < (schema.minimum ?? -Infinity) || value > (schema.maximum ?? Infinity)) throw new Error(`${at}: invalid integer`);\n } else if (schema.type === 'boolean') {\n if (typeof value !== 'boolean') throw new Error(`${at}: boolean required`);\n }\n}\n\nasync function dispatch(tool, args) {\n check(tool.inputSchema, args);\n const raw = process.env.SCIENCEEVOLVE_TASK_BACKEND_URL;\n const scopeId = process.env.SCIENCEEVOLVE_TASK_SCOPE_ID;\n if (!raw || !scopeId) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: 'blocked', reason: 'Configure the method-specific backend URL and a fresh scope ID; no backend is bundled.' }) }] };\n const endpoint = new URL(raw);\n if (!(endpoint.protocol === 'https:' || (endpoint.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(endpoint.hostname))) || endpoint.username || endpoint.password || endpoint.search || endpoint.hash) throw new Error('Use an explicit HTTPS or loopback HTTP endpoint without inline credentials');\n const requestId = tool.mode === 'write' ? args.requestId : randomUUID();\n if (tool.mode === 'write' && !requestId) throw new Error('Mutation requires a stable requestId');\n let response;\n try {\n response = await fetch(endpoint, {\n method: 'POST', redirect: 'error', signal: AbortSignal.timeout(30000),\n headers: { 'content-type': 'application/json', ...(process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN ? { authorization: `Bearer ${process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN}` } : {}) },\n body: JSON.stringify({ schemaVersion: 1, method: spec.method, scopeId, actor: spec.actor, operation: tool.name, requestId, arguments: args })\n });\n } catch {\n // Never retry a possibly accepted training/physical job automatically.\n return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, reason: 'Transport failed; reconcile this exact requestId using get_request. Do not create a replacement job.' }) }] };\n }\n if (!response.ok) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, httpStatus: response.status, reason: 'Reconcile before replaying any mutation.' }) }] };\n const body = await response.text();\n if (Buffer.byteLength(body) > 2 * 1024 * 1024) throw new Error('Backend response too large; use paged evidence');\n const result = JSON.parse(body);\n if (result.schemaVersion !== 1 || result.method !== spec.method || result.scopeId !== scopeId || result.operation !== tool.name || result.requestId !== requestId) throw new Error(`Mismatched backend receipt; mutation outcome remains unknown: ${requestId}`);\n if (!['ok', 'blocked', 'failed', 'unknown'].includes(result.status)) throw new Error(`Invalid receipt status: ${requestId}`);\n if (!Array.isArray(result.evidence)) throw new Error(`Receipt requires an evidence array: ${requestId}`);\n for (const evidence of result.evidence) {\n if (!evidence || typeof evidence.id !== 'string' || typeof evidence.uri !== 'string' || typeof evidence.kind !== 'string' || !/^[a-f0-9]{64}$/.test(evidence.sha256)) throw new Error(`Malformed evidence reference: ${requestId}`);\n }\n if (tool.mode === 'write' && result.status === 'ok' && result.evidence.length === 0) throw new Error(`Successful mutation requires a durable receipt: ${requestId}`);\n if (tool.name === 'read_artifact' && result.status === 'ok') {\n if (typeof result.data?.text !== 'string' || createHash('sha256').update(result.data.text, 'utf8').digest('hex') !== result.data.sha256) throw new Error('Artifact bytes do not match the claimed SHA-256');\n }\n // Evidence references and an HTTP OK are not a scientific pass. Agents audit actual bytes/results.\n return { isError: result.status !== 'ok', content: [{ type: 'text', text: JSON.stringify(result) }] };\n}\n\nconst server = new Server({ name: `${spec.method}-${spec.actor}-atomic-tools`, version: '1.0.0' }, { capabilities: { tools: {} } });\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: spec.tools.map(({ mode, ...tool }) => tool) }));\nserver.setRequestHandler(CallToolRequestSchema, async request => {\n const tool = spec.tools.find(item => item.name === request.params.name);\n if (!tool) throw new Error('Tool is not assigned to this role');\n try { return await dispatch(tool, request.params.arguments || {}); }\n catch (error) { return { isError: true, content: [{ type: 'text', text: error.message }] }; }\n});\nserver.connect(new StdioServerTransport());\nprocess.stdin.on('end', () => { server.close().finally(() => process.exit()); });\n\n",
"tools.json": "{\n \"method\": \"raven-host\",\n \"actor\": \"judge\",\n \"tools\": [\n {\n \"name\": \"get_capabilities\",\n \"description\": \"Read actual method/tool versions, resources, scope budget, provenance and capability limitations. A design declaration is not a resource probe.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_state\",\n \"description\": \"Read durable current scope revision, budgets, jobs, graph/memory/weight versions and accepted evidence. Do not infer current tasks from an old predecessor handoff.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_request\",\n \"description\": \"Reconcile the original durable request without submitting another job; preserve unknown until authoritative evidence exists.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"originalRequestId\"\n ],\n \"properties\": {\n \"originalRequestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_job\",\n \"description\": \"Read actual job status, input/output hashes, error or measurement receipts. Accepted/queued is not completed.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"jobId\"\n ],\n \"properties\": {\n \"jobId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"read_artifact\",\n \"description\": \"Read a small retained UTF-8 artifact and verify its SHA-256 bytes; paginate large evidence at the backend.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"artifactId\"\n ],\n \"properties\": {\n \"artifactId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_node\",\n \"description\": \"Read exact node/attempt/instance/epoch, accepted dependencies, completion receipt and output visibility.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"record_verdict\",\n \"description\": \"Persist an Agent-authored evidence verdict, separating incomplete/unavailable/invalid and enforcing at most two continuations across resume. Does not control an in-flight SDK node.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\",\n \"verdict\",\n \"evidenceIds\",\n \"rationale\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"verdict\": {\n \"type\": \"string\",\n \"enum\": [\n \"complete\",\n \"incomplete\",\n \"unavailable\",\n \"invalid\"\n ]\n },\n \"evidenceIds\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"minItems\": 1,\n \"maxItems\": 100\n },\n \"rationale\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n },\n {\n \"name\": \"export_evidence\",\n \"description\": \"Create an immutable scope evidence manifest for this actor. Export receipt does not commit SDK branch files or complete a group.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"selection\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"selection\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"minItems\": 1,\n \"maxItems\": 100\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n }\n ]\n}\n"
}
},
"task-audit": {
"command": "node",
"entrypoint": "task-bridge.cjs",
"args": [],
"envFrom": {
"SCIENCEEVOLVE_TASK_BACKEND_URL": "SCIENCEEVOLVE_RAVEN_BACKEND_URL",
"SCIENCEEVOLVE_TASK_BACKEND_TOKEN": "SCIENCEEVOLVE_RAVEN_BACKEND_TOKEN",
"SCIENCEEVOLVE_TASK_SCOPE_ID": "SCIENCEEVOLVE_RAVEN_SCOPE_ID"
},
"files": {
"task-bridge.cjs": "'use strict';\n// Transport only. Scientific decisions stay in SCIENCEEVOLVE agents; backends expose atomic tools.\nconst { Server } = require('@modelcontextprotocol/sdk/server/index.js');\nconst { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');\nconst { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');\nconst { randomUUID, createHash } = require('node:crypto');\nconst spec = require('./tools.json');\n\nfunction check(schema, value, at = 'arguments') {\n if (schema.enum && !schema.enum.includes(value)) throw new Error(`${at}: unsupported enum`);\n if (schema.type === 'object') {\n if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`${at}: object required`);\n for (const key of schema.required || []) if (!(key in value)) throw new Error(`${at}.${key}: required`);\n for (const [key, item] of Object.entries(value)) {\n if (schema.properties?.[key]) check(schema.properties[key], item, `${at}.${key}`);\n else if (schema.additionalProperties === false) throw new Error(`${at}.${key}: unknown field`);\n }\n } else if (schema.type === 'array') {\n if (!Array.isArray(value)) throw new Error(`${at}: array required`);\n if (schema.minItems !== undefined && value.length < schema.minItems) throw new Error(`${at}: too few items`);\n if (schema.maxItems !== undefined && value.length > schema.maxItems) throw new Error(`${at}: too many items`);\n for (const item of value) check(schema.items, item, `${at}[]`);\n } else if (schema.type === 'string') {\n if (typeof value !== 'string' || value.length < (schema.minLength ?? 0) || value.length > (schema.maxLength ?? Infinity)) throw new Error(`${at}: invalid string`);\n if (schema.pattern && !new RegExp(schema.pattern).test(value)) throw new Error(`${at}: invalid pattern`);\n } else if (schema.type === 'integer') {\n if (!Number.isSafeInteger(value) || value < (schema.minimum ?? -Infinity) || value > (schema.maximum ?? Infinity)) throw new Error(`${at}: invalid integer`);\n } else if (schema.type === 'boolean') {\n if (typeof value !== 'boolean') throw new Error(`${at}: boolean required`);\n }\n}\n\nasync function dispatch(tool, args) {\n check(tool.inputSchema, args);\n const raw = process.env.SCIENCEEVOLVE_TASK_BACKEND_URL;\n const scopeId = process.env.SCIENCEEVOLVE_TASK_SCOPE_ID;\n if (!raw || !scopeId) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: 'blocked', reason: 'Configure the method-specific backend URL and a fresh scope ID; no backend is bundled.' }) }] };\n const endpoint = new URL(raw);\n if (!(endpoint.protocol === 'https:' || (endpoint.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(endpoint.hostname))) || endpoint.username || endpoint.password || endpoint.search || endpoint.hash) throw new Error('Use an explicit HTTPS or loopback HTTP endpoint without inline credentials');\n const requestId = tool.mode === 'write' ? args.requestId : randomUUID();\n if (tool.mode === 'write' && !requestId) throw new Error('Mutation requires a stable requestId');\n let response;\n try {\n response = await fetch(endpoint, {\n method: 'POST', redirect: 'error', signal: AbortSignal.timeout(30000),\n headers: { 'content-type': 'application/json', ...(process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN ? { authorization: `Bearer ${process.env.SCIENCEEVOLVE_TASK_BACKEND_TOKEN}` } : {}) },\n body: JSON.stringify({ schemaVersion: 1, method: spec.method, scopeId, actor: spec.actor, operation: tool.name, requestId, arguments: args })\n });\n } catch {\n // Never retry a possibly accepted training/physical job automatically.\n return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, reason: 'Transport failed; reconcile this exact requestId using get_request. Do not create a replacement job.' }) }] };\n }\n if (!response.ok) return { isError: true, content: [{ type: 'text', text: JSON.stringify({ status: tool.mode === 'write' ? 'outcome_unknown' : 'unavailable', requestId, operation: tool.name, httpStatus: response.status, reason: 'Reconcile before replaying any mutation.' }) }] };\n const body = await response.text();\n if (Buffer.byteLength(body) > 2 * 1024 * 1024) throw new Error('Backend response too large; use paged evidence');\n const result = JSON.parse(body);\n if (result.schemaVersion !== 1 || result.method !== spec.method || result.scopeId !== scopeId || result.operation !== tool.name || result.requestId !== requestId) throw new Error(`Mismatched backend receipt; mutation outcome remains unknown: ${requestId}`);\n if (!['ok', 'blocked', 'failed', 'unknown'].includes(result.status)) throw new Error(`Invalid receipt status: ${requestId}`);\n if (!Array.isArray(result.evidence)) throw new Error(`Receipt requires an evidence array: ${requestId}`);\n for (const evidence of result.evidence) {\n if (!evidence || typeof evidence.id !== 'string' || typeof evidence.uri !== 'string' || typeof evidence.kind !== 'string' || !/^[a-f0-9]{64}$/.test(evidence.sha256)) throw new Error(`Malformed evidence reference: ${requestId}`);\n }\n if (tool.mode === 'write' && result.status === 'ok' && result.evidence.length === 0) throw new Error(`Successful mutation requires a durable receipt: ${requestId}`);\n if (tool.name === 'read_artifact' && result.status === 'ok') {\n if (typeof result.data?.text !== 'string' || createHash('sha256').update(result.data.text, 'utf8').digest('hex') !== result.data.sha256) throw new Error('Artifact bytes do not match the claimed SHA-256');\n }\n // Evidence references and an HTTP OK are not a scientific pass. Agents audit actual bytes/results.\n return { isError: result.status !== 'ok', content: [{ type: 'text', text: JSON.stringify(result) }] };\n}\n\nconst server = new Server({ name: `${spec.method}-${spec.actor}-atomic-tools`, version: '1.0.0' }, { capabilities: { tools: {} } });\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: spec.tools.map(({ mode, ...tool }) => tool) }));\nserver.setRequestHandler(CallToolRequestSchema, async request => {\n const tool = spec.tools.find(item => item.name === request.params.name);\n if (!tool) throw new Error('Tool is not assigned to this role');\n try { return await dispatch(tool, request.params.arguments || {}); }\n catch (error) { return { isError: true, content: [{ type: 'text', text: error.message }] }; }\n});\nserver.connect(new StdioServerTransport());\nprocess.stdin.on('end', () => { server.close().finally(() => process.exit()); });\n\n",
"tools.json": "{\n \"method\": \"raven-host\",\n \"actor\": \"audit\",\n \"tools\": [\n {\n \"name\": \"get_capabilities\",\n \"description\": \"Read actual method/tool versions, resources, scope budget, provenance and capability limitations. A design declaration is not a resource probe.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_state\",\n \"description\": \"Read durable current scope revision, budgets, jobs, graph/memory/weight versions and accepted evidence. Do not infer current tasks from an old predecessor handoff.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_request\",\n \"description\": \"Reconcile the original durable request without submitting another job; preserve unknown until authoritative evidence exists.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"originalRequestId\"\n ],\n \"properties\": {\n \"originalRequestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_job\",\n \"description\": \"Read actual job status, input/output hashes, error or measurement receipts. Accepted/queued is not completed.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"jobId\"\n ],\n \"properties\": {\n \"jobId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"read_artifact\",\n \"description\": \"Read a small retained UTF-8 artifact and verify its SHA-256 bytes; paginate large evidence at the backend.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"artifactId\"\n ],\n \"properties\": {\n \"artifactId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"get_roster\",\n \"description\": \"Read actual Research/Code/Design/Oncall capabilities and conditional Design-to-PPT route; unavailable skills/tools are explicit.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [],\n \"properties\": {}\n }\n },\n {\n \"name\": \"get_node\",\n \"description\": \"Read exact node/attempt/instance/epoch, accepted dependencies, completion receipt and output visibility.\",\n \"mode\": \"read\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"nodeId\"\n ],\n \"properties\": {\n \"nodeId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n }\n }\n }\n },\n {\n \"name\": \"export_evidence\",\n \"description\": \"Create an immutable scope evidence manifest for this actor. Export receipt does not commit SDK branch files or complete a group.\",\n \"mode\": \"write\",\n \"inputSchema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"selection\",\n \"requestId\",\n \"expectedRevision\"\n ],\n \"properties\": {\n \"selection\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 4000\n },\n \"minItems\": 1,\n \"maxItems\": 100\n },\n \"requestId\": {\n \"type\": \"string\",\n \"minLength\": 1,\n \"maxLength\": 128\n },\n \"expectedRevision\": {\n \"type\": \"integer\",\n \"minimum\": 0\n }\n }\n }\n }\n ]\n}\n"
}
}
},
"orchestration": {
"schemaVersion": 3,
"agents": [
{
"name": "main",
"template": "main"
},
{
"name": "preflight",
"template": "general"
},
{
"name": "specialist_a",
"template": "general"
},
{
"name": "specialist_b",
"template": "general"
},
{
"name": "judge",
"template": "general"
},
{
"name": "audit",
"template": "general"
}
],
"collaborations": [
{
"id": "delegation",
"displayName": "Explicit limited two specialist batch",
"memberAgentIds": [],
"renamePolicy": "editable"
}
],
"scopedWorkflow": {
"schemaVersion": 1,
"rootAgentIds": [
"main",
"preflight",
"judge",
"audit"
],
"groups": [
{
"id": "delegation",
"leaderAgentId": "main",
"allowLeaderReconfiguration": false,
"workflow": {
"nodes": [
{
"kind": "agent",
"nodeId": "slot_a",
"agentId": "specialist_a"
},
{
"kind": "agent",
"nodeId": "slot_b",
"agentId": "specialist_b"
}
],
"input": {
"source": "input",
"edges": [
{
"kind": "parallel",
"target": "slot_a"
},
{
"kind": "parallel",
"target": "slot_b"
}
]
},
"routes": {
"slot_a": [
{
"kind": "strong",
"target": "finish"
}
],
"slot_b": [
{
"kind": "strong",
"target": "finish"
}
]
}
}
}
]
},
"input": {
"source": "input",
"target": "preflight"
},
"routes": {
"main": [
{
"kind": "weak",
"target": "delegation"
},
{
"kind": "weak",
"target": "audit"
}
],
"preflight": [
{
"kind": "strong",
"target": "main"
}
],
"delegation": [
{
"kind": "strong",
"target": "judge"
}
],
"judge": [
{
"kind": "strong",
"target": "main"
}
],
"audit": [
{
"kind": "weak",
"target": "main"
},
{
"kind": "weak",
"target": "finish"
}
]
},
"decisionPlans": {
"main": "strict-host 或需要完整在线/任意 DAG 语义则 request_user 暂停,不路由假运行。仅明确 limited-batch、依赖与原子能力核验、累计预算允许时 delegation;子项报告完成时 audit。不自动重配置制造未支持字段。",
"audit": "受限运行只交付 methodAccepted=false 的子项证据;完整 Host 当前不可 finish。"
},
"allowMainReconfiguration": false,
"allowUserIntervention": true,
"termination": {
"agent": "audit",
"condition": "完整 Raven 默认 Host 只有所有动态 DAG/AND/instance/在线通知裁决/在途 replan/判定续跑/stint/记忆和领域能力均有实证,且正式交付,才可接受。当前模板不满足该条件;limited-batch 报告保持 methodAccepted=false,并由 Main 暂停/交接。",
"decisionBy": "main",
"automatic": false
},
"resultFormat": {
"presets": [
"markdown",
"code"
],
"custom": "交付 report.md、acceptance.json、evidence-index.json、真实源码/结果/失败回执、版本摘要与 SDK/Git/原目录交付证据。完整方法与缩小/受限模式分开;不以配置校验代替方法验收。"
}
}
}