Wave 7:最小化 Root-Orchestrator 架构计划(冻结 D1-D13 落地)
August 25, 2026 · View on GitHub
0. 定稿决策
- Root Agent 是唯一 Orchestrator,"信息是否足够"由 Root 的 system prompt 判断,TypeScript 不做 criteria engine。
- 6 概念模型:Project / PentestRun / Stage / AgentProfile / Delegation / Deliverable(File)。
- Delegation 取代 Task + AgentRun:一次委托 = 一个 DSH child session;
task_prompt为不可变 snapshot。 - Deliverable = 文件(
workspace/stages/<NN>-<stage>/delegations/D-00N/目录),删除全部 store/journal 实体。 - PTAP 整套删除;Worker 禁止 delegate,编排树永远只有 Root → Workers 一层。
- One Workspace = One Primary Target = One PentestRun = One Git 仓库 = One active timeline = One Toolbox 容器 = Many Workers。
Root 工具面(4 个):pentester_delegate / pentester_cancel_delegation /
pentester_advance_stage / pentester_rollback_stage。Root 不能使用
pentester_container_exec:per-Root-agent tools.restrict deny 只隐藏这一条
(deny 必须落在 Root 自己的 layer:官方 subagent child 会 join 父 preset,
mount 级 deny 会把 container_exec 也挡给 Worker;且 tools.restrict 对未知名字
整体拒绝,不能把别的 preset 才注册的工具名加进来)。通用 subagent/job/bash/fs
工具由组合排除:本 deployment 把它们作为 per-preset 行(standard 等 preset
自带),pentester preset 组合不带 → Root 天然看不到。工具注册在 preset scope:
宿主不向 global registry 注册 pentester 工具(standard Session 完全看不到),
preset 行 run-state.mjs 经宿主 pentester service 注册。
Worker 工具面(1 个):pentester_container_exec。不增加 fs/complete/submit/
status/sync/git 工具。
Bootstrap 位置(定稿):Pre-engagement 不创建 Worker —— 由
User + Root + ask_user_question 完成(targets / scope / RoE / language)。
首次初始化在 pentester_advance_stage:无 run.json 时,
pentester_advance_stage({run, summary}) 承担 bootstrap —— 创建 workspace 骨架、
run.json、target 文件,git init + 初始 commit,然后同一调用完成 pre-engagement
checkpoint 并激活 intelligence-gathering。pentester_delegate 不 bootstrap:
无 Run 时明确报错(先完成 pre-engagement 并调用 advance_stage 初始化)。
Root 每次推理前注入的 compact state 包含 Available AgentProfiles:当前 stage
的合法 AgentProfile 列表由 STAGE_DEFINITIONS.agentIds ∩ AgentProfile registry
生成(插件 apply 时写成 preset 目录 stage-profiles.json,run-state.mjs 同目录
读取),不硬编码第二套映射。Root 只从该列表选 agent id。
全 Workspace git 跟踪(Owner 要求完整回溯):不忽略 work/、traffic/、
*.pcap、*.mitm;.gitignore 只保留 tmp/ cache/ *.log。
远程阶段边界(§24):advance 时先 remote → local 同步 Worker 数据(本地 bind 下 no-op),再 promotion / summary / transition / git checkpoint / local → remote。
Worker 执行 = DeepSeek Harness 官方 Subagent seam(定稿):
不再维护自定义 ctx.agents.create() / agent.inject() / agent.followup() /
agent.whenIdle() Worker lifecycle。Worker 走:
ctx.subagents(Service,dsh-base 已挂载)→ provider spawn
(@deepseek-ai/dsh-subagent-spawn-in-process,dsh-base 已注册)→ durable continuable child(startContinuable / followup / interrupt;跨
Activation 持续,FIFO inbox,官方管理 cold resume)。无 ctx.jobs、无 one-shot
SubagentRun.result/dispose。基础设施缺失(ctx.subagents / provider 不存在)
fail loud,禁止 fallback 回自定义 lifecycle。Root 不获得通用
subagent/job/bash/fs 工具(组合排除 + per-Root deny,见 §0),只通过
pentester_* 领域工具编排。Worker prompt 拆分:persona = WORKER_BASELINE +
AgentProfile.systemPrompt(官方 persona 模板);prompt = standalone task
context(Delegation ID / Stage / Target / RoE / 目录 / 完成契约 / task_prompt)——
spawn child 不继承 parent transcript,所以 task_prompt 必须自包含。
worker toolFilter = { deny: [4 个 pentester Root 工具 + ask_user_question] }。Delegation ↔
childSessionId 绑定:startContinuable 发布后宿主立即把 childId 写入
Delegation.sessionId(pentester_container_exec 据此解析 worker work 目录并校验调用者身份)。
Pre-engagement 固定问卷(定稿):Pre-engagement 由 User + Root + 原生
ask_user_question 完成,使用固定结构问卷(五问一次调用):
target_confirm / scope_confirm / exclusions_confirm / roe_confirm /
language_confirm。不封装 pentester_ask_user,不临时加问。
1. 目标架构
User ⇄ DSH Root Session(pentester persona preset)
│ Root 工具面 4 个(见上)
▼
Delegation(并行、可多个)── 每个对应一个 DSH child session
│ Worker prompt = baseline + AgentProfile.systemPrompt
│ + host 注入 trusted metadata + task_prompt
▼
pentester_container_exec(dockerode;Root 不可见)
▼
workspace/stages/<NN>-<stage>/delegations/D-00N/ ← Deliverable 就是文件
▼
Worker 是 durable continuable child:写/更新 result.md 作为当前可交付结果,
可接收 Root 的 send_message 后续;Root 自行判断再派 / advance / rollback
Root 每次 reasoning 前,宿主从 run.json 注入 compact state
(target / branch / run 状态 / current stage / stage 状态 / delegations 摘要),
经 preset systemPrompt.context(text 函数每次 assembly 求值)实现;不注入
完整 run.json,不提供 status 工具。
1b. Workspace + Git Checkpoint
- 交付树 =
workspace/(= 容器/workspace)。固定骨架每次 run 一致:.git/.dsh-pentester/(run.json/workspace.json/events.jsonl)target/(target.json scope.md roe.md inputs/)stages/<NN>-<stage>/ {summary.md, delegations/D-00N/{input,work,artifacts,evidence,result.md}}findings/ report/ traffic/。 - run.json 位于 workspace git 树内(
workspace/.dsh-pentester/run.json): 阶段 checkpoint 的 commit 记录 transition 后的机器状态,rollback checkout 后 状态随 git 还原。这是"commit 里 current completed / next active"(T16)与 rollback 恢复(§31)的前提。 - Workspace 挂载:本地 Docker → host
workspace/bind mount(无复制版); 远程 Docker → 共享 named volume,阶段边界才 full sync。 - 同步(仅远程)为 mirror 语义:create/update/delete 都反映;pull 排除
.git/与.dsh-pentester/(Host 控制态,防止 stale remote 覆盖宿主 run.json)。 - Stage 生命周期
pending → active → reviewing → completed。 - advance = mechanical validation(无 running/starting delegation)→
远程先 remote→local sync(§24)→ promotion → 写 summary.md(Root 提供)→
run transition → saveRun → git checkpoint(
ptes(<NN>-<stage>): complete+ tag)→ push。首次 advance(无 run.json)额外承担 bootstrap(见 §0)。 - result.md = 当前正式可交付结果:Worker 写/更新 result.md 作为当前产出 (不是 Session 终止标志)。continuable child 跨轮持续;宿主不自动 settle/完成 检测,不自动生成。
- delivery receipt(result.md + artifacts/evidence 文件清单)宿主可按需读取, 只存在于运行时响应,不持久化 INDEX/registry。
- 不需要:STATUS.md、INDEX.*、manifest.json、logs/、Deliverable Registry、 全局 assets.json。
- git 仓库宿主侧管理(
workspace/.git),Worker 容器内无 .git;输出语言: 宿主生成文件用 run.language,Worker 文件跟随 task_prompt 语言,工具原始输出 保持原样。
2. 源码布局
src/
├── index.ts # cordis 入口:apply/Config/inject;preset 发布;ctx.provide('pentester') 发布工具实现 + Settings RPC
├── model.ts # 6 概念类型 + Delegation status + StageDefinition + StageStatus
├── stages.ts # 7 个 PTES StageDefinition
├── profiles.ts # AgentProfile 注册表(agents/*/profile.yml 加载校验)
├── store.ts # run.json 读写(workspace/.dsh-pentester/run.json;原子写、schemaVersion)
├── workspace.ts # 工作区骨架/target 落盘/events.jsonl/summary/promotion
├── git.ts # GitCheckpointService(init/checkpoint/rollback timeline,injectable runner)
├── dsh.ts # DSH seam:spawn child、cancel、完成捕获、followup 唤醒、trusted caller
├── delegations.ts # Delegation 生命周期 + task_prompt snapshot + 目录骨架 + result.md 契约 + receipt + childSessionId 绑定
├── tools.ts # 4 个 Root 工具(注册经 pentester service,preset scope)+ caller=root 校验 + advance + rollback
├── worker-tools.ts # container_exec(注册经 pentester service,preset scope)+ caller=worker-only 校验 + 默认 cwd=work/
├── docker/
│ ├── host.ts # docker host 解析 + 连接探测 + 引擎构造
│ ├── connection.ts # Settings 测试连接(TLS/SSH)
│ ├── images.ts # Toolbox 白名单
│ └── runtime.ts # 硬化、容器/卷生命周期、exec、bind/volume、mirror sync、recovery
├── rpc.ts / settings-store.ts # Settings UI 的 Typert RPC 与全局设置
└── ui/client/ # 仅 Settings(Docker Engine Tab),无数据面板
presets/pentester/ # persona + ask_user + run-state.mjs(preset scope 工具注册 + per-Root deny + 动态状态注入)
3. 关键设计
- Delegation 生命周期:starting → active → interrupted/closed/failed; resultSummary 由 Root 在 cancel 时提供(reason)。 task_prompt/objective 持久化为不可变 snapshot;后续 steer/followup 不改写。
- 完成信号:continuable 模式下无 host 自动 settle —— Worker 是 durable child,写/更新 result.md 作为当前可交付结果;Root 自行判断 advance / cancel / 再派;Worker 经 report 工具主动上报重要发现(Worker lifecycle 属 DSH, 宿主只管 PTES 领域状态)。
- 并行:delegate 批量 assignments,内部 Promise.allSettled。
- 目录:每 Delegation 独立
workspace/stages/<NN>-<stage>/delegations/D-00N/(input/work/artifacts/evidence),prompt 告知"只写自己目录、可读全 workspace/"。 - dockerode 层:窄接口 seam 供测试注入 fake。安全不变量:镜像白名单、 禁 privileged/host net/pid/ipc、capAdd 白名单、禁 docker.sock、exec 超时与 输出截断、1 PentestRun = 1 容器。
- Worker fs:当前为 prompt 级协作约束(只写自己的 delegation 目录)。
这是有意接受的设计(owner 决策):
- 不实现 UID 隔离 / ACL / filesystem jail / 独立 container / mount namespace;
- 不把该约束宣传为 security boundary;
- 原因:多个 Worker 属于同一个授权 Pentest Project、同一个信任域,当前架构
优先保证共享 Workspace、多 Agent 协作、实现简单和可维护性。
Worker 默认只写自己的 Delegation 目录,但整个
/workspace全局可读,且技术上 同一共享 Container 内 Worker 仍可能写入其他 Workspace 路径 —— 这是接受的边界。
- Worker prompt 注入:delegationId/stage/workspaceDir 由 host 注入 metadata 段。
- 安全让步(显式记录):无程序化 approval/scope 检查,RoE/Scope 作为数据 注入 prompt + engagement 开始前 ask_user 预授权门 + 镜像白名单 + 容器硬化。
4. Rollback / Rework Timeline
pentester_rollback_stage({stage, reason}):stage 是领域 StageId(如 intelligence-gathering),rollback 到该 stage 的 checkpoint,从下一 stage 重新开始(§27)。- Host 流程:cancel 当前 starting/running delegation → quiescent →
(远程)pull worker 数据 → dirty 则建
backup/rollback-<ts>+ WIP commit (wip: before rollback to <stage>)→ 在 HEAD first-parent reachable 历史中 按 subjectptes(<NN>-<stage>): complete找 checkpoint → 从 checkpoint 建rework/<next-stage-slug>-<n>(n 自动递增)并 checkout(run.json 随还原)→ (远程)push → 返回 delta。 - D-ID 在 branch timeline 内跨 Stage 全局递增;rollback 后新 branch 允许复用旧 编号(不搞跨 branch global allocator)。
- tag 冲突(T25):main 与 rework 都完成同一 stage 时,
checkpointStage遇已 存在 tag 直接跳过(tag 只作人类可读 ref,正确性靠 commit subject)。 - 不重写历史:当前 active branch 原历史不得 reset/rewrite;不自动 merge、 不自动删旧 branch。
5. Recovery
- remote volume 还在 → 复用(不 local→remote 覆盖)。
- container 丢失但 volume 存在 → 重建容器复用 volume。
- container 与 volume 都丢失 → 新建 volume 并从本地 mirror 恢复。
- 未完成 Delegation:reconcile 标记 failed/interrupted,不自动重跑; Root 决定是否重新 delegate。
6. 测试计划
- model/stages/profiles 校验;store 原子写 round-trip。
- Delegation 生命周期(fake DSH client):批量并行、cancel、continuable start/interrupt、task_prompt 不可变。
- 工具 caller 身份:worker 调 Root 工具被拒、Root 面无 container_exec。
- rollback:cancel workers、backup branch、rework branch、checkpoint 查找、tag 冲突。
- docker 层(fake engine seam):白名单拒绝、HostConfig 硬化、bind/volume 选择、 mirror sync、recovery。
- run-state:compact 状态渲染、branch 读取。
- Worker prompt 组装 snapshot。
7. 新增依赖
dockerode+@types/dockerode:容器管理/exec 库。tar-stream:volume 同步。zod:Settings RPC strict codec。其余零新增。
8. 本 wave 明确不做
approval 流 / scope 参数级检查;数据面板 UI;HTML/PDF 报告(report.md 即终稿); 多 PentestRun 并发;stage 跳跃 override;Worker 二级委派;workspace_fs / UID / ACL 文件隔离;Git LFS。