npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

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

About

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

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

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

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

Open Software & Tools

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

© 2026 – Pkg Stats / Ryan Hefner

@mstar-harness/dsh

v4.0.7

Published

Morning Star harness dsh (DeepSeek Harness) cordis function plugin — in-process engine gates (status/dispatch/lease) with hard refusal channels.

Readme

@mstar-harness/dsh

English | 中文

dsh

让 Morning Star 成为一等公民的 dsh(DeepSeek Harness)宿主——一个 cordis 函数插件,将 mstar engine 进程内挂载,实现 engine HostAdapter(host: 'dsh'),守护 {HARNESS_DIR}/status.json 写入(校验 + 咨询;hard 下按修复逃生放行),在 Enforcement: hard 开启时阻止被禁止的 subagent 派发,对挂载技能根下的 SKILL.md 写入执行技能撰写 lint,通过 dsh skill-filesystem 提供者挂载 mstar skills/ 镜像(单一规范挂载),并向每个组合后的 agent 步骤追加一条持久化的 mstar-engine catalog 行(持久化日志的读取方也接受旧标识 mstar-engine-status)。随 dsh Loader 应用启动;一切均通过 seam 的拒绝/咨询通道行使职责,从不改动工具本身。

本插件的运行时要求来自 dsh 宿主:宿主提供的运行时必须提供 mstar store 所需的原生 node:sqlite 模块(store 闸门强制的是这项能力)。Bun 宿主不做版本闸门 —— workspace 各 manifest 里的 engines.bun 只是开发工具链声明 —— store 的 Node 版本下限只作用于 Node 入口。本包不额外要求 Node。

Usage

dsh 应用如何使用本插件——安装路径、配置、挂载时发生什么、强制执行语义。

Install paths

本包以 workspace 包形式发布(workspaces: ["packages/*"]),构建时把 engine 打进 dist/(bun run build;dist 已被 gitignore)。安装途径是 profile bundle,装进现成的 web profile(dsh --profile web——开箱即用的 web 应用 profile,即 dsh web),经 dsh.bundle.patch 清单——一个叠在 dsh-base 默认层之上的补丁层。该补丁还挂载一行宿主中立的 MCP 服务器——即整个宿主共享的 mstar-mcp 连接;需要固定 harness 根的部署用 mstar mcp --harness <绝对路径> 启动它(挂载契约见 bundle/README.md)。

一条命令的 CLI 入口(推荐)——npx @mstar-harness/cli init --target dsh 一次性装齐全量能力:它按序运行下面两条 dsh plugin --profile web add 安装(先 mstar bundle,再 dsh-llm-fallbacks),并可用 npx @mstar-harness/cli doctor --target dsh 逐行报告 uninstalled / disabled / mounted / drifted(drifted = fallbacks 行的安装版本不等于 pin;init --target dsh 会按 pin 重新 add,在此之前 doctor 以非零退出)。它编排的仍是同一条双命令安装;--no-fallbacks 跳过第二行(连带跳过 seeded 角色——见下文「零配置获得什么」)。

(a)registry 安装(发布形态)——npm 包自带构建好的 dist/(安装时无需构建):

dsh plugin --profile web add @mstar-harness/dsh

(b)local checkout 安装(开发)——包检出本身,用于迭代插件:

cd <repo>/packages/dsh
dsh plugin --profile web add .

dsh plugin --profile <name> add <spec> 首次使用时初始化 profile(web 从出厂模板起步:@deepseek-ai/dsh-base + @deepseek-ai/dsh-web-app),把 <spec> 转发给 profile 目录中的 pnpm,并按已安装状态对账 dsh.profile.bundles 层列表:任何 package.json 声明 dsh.bundle 的依赖都会加入层栈。相对 spec(.、file:/link:)锚定调用目录,因此 add . 须在包检出目录内执行;pnpm 须在 PATH 上。local checkout 需要先执行过 bun run build(本包不使用 prepare 脚本——monorepo 与 cli/opencode 一致,显式构建各包)。细节、层位置与出厂默认见 bundle/README.md——registry 与 local checkout 形态均走同一 pnpm + reconcile 机制。cordis 与 @deepseek-ai/dsh-* 各 seam 均为 peerDependencies——由组合后的 dsh 应用提供。

(c)可选能力:dsh-llm-fallbacks(第二条命令)——基于角色的 subagent 配置能力(见 LLM fallbacks integration)是独立的插件行,须以单独命令安装:

dsh plugin --profile web add dsh-llm-fallbacks

双命令安装即契约——把 dsh-llm-fallbacks 行折叠进本 bundle 的补丁明确否决(roadmap §8.3 F4):loader 没有 insert-if-absent 语义,因此同 id 插入是 duplicate loader entry id 启动失败(整个 dsh 会话无法启动);异 id 插入则插件被挂载两次——对同时直接安装该包的人,会出现两次 apply() 与分裂的 fallback 状态(各自独立的 state store、双份监听器、配置覆盖抽签)。层序为 reconcile 追加序:dsh-llm-fallbacks 落在 dsh-base/llm-retry 之后(其硬性排序要求)并位于 mstar 行之后。单命令多激活是上游功能缺口(reconcile 去重或 insert-if-absent 补丁语义),本仓库无法实施。

零配置获得什么——两条行都装上后(经 CLI 入口或上面两条命令),mstar 插件在 boot 时把 13 个 mode: subagent 的 mstar 角色种子(从打包的 harness-agents/ 镜像派生,排除 project-manager)声明进 fallbacks taxonomy:每个 seeded 角色的 persona 默认取其镜像 description 外加一行强制角色加载引导;seeded 状态保持可 revert(fallbacks/revert-seed 网关 / settings 回滚按钮);运行时 advisory 报告缺失 id 与 persona 覆盖。该 seeds 机制即 B4——installed-deployment e2e(tests/install-e2e.spec.ts)本轮把验证闭环:真实 init --target dsh 安装进临时 DSH_HOME、从安装产物 boot,断言 13 个 id 全部出现在 effective taxonomy 且 persona 非空。不含模型路由、不含 automatch 派发、不含 dsh-tui。

被派发子代理的角色身份需要部署方的一处声明。 dsh 0.2.1 通过选择 agent preset 交付子代理身份,因此角色匹配的派发会选择 rolePresets 为该角色映射的 preset。请为每个角色声明一份完整 preset(@deepseek-ai/dsh-agent-preset 行,其 plugins 挂载 @deepseek-ai/dsh-persona 并携带该角色的 persona 文本——persona、工具与技能都在该组合内),并把其 id 列进插件的 rolePresets。未映射的角色保持委派方的组合——不会有任何故障,只是子代理不携带角色身份。详见下文《角色身份交付》。

fresh publish 年龄窗口提示:pnpm 的 minimumReleaseAge 门禁可能让 dsh plugin add <spec> 的 range 解析在全新发布后约 24h 内选中旧版本(不含 seeds surface)——窗口过后重跑 npx @mstar-harness/cli init --target dsh(或显式 pin 版本)即可收敛到最新 surface。

Headless profile(一次性运行)

本插件并非 web 专属:它同样可以挂载进 dsh headless profile(dsh --profile headless "<task>"——一次性、无 GUI/无端口模式)。安装路径完全一致,一条命令:

dsh plugin --profile headless add @mstar-harness/dsh

出厂 headless 模板在首次使用时自动初始化(@deepseek-ai/dsh-base + @deepseek-ai/dsh-headless),reconcile 步骤把 mstar 行追加进 bundle 层栈(dsh-base → dsh-headless → @mstar-harness/dsh)。插件的所有能力都落在 headless 继承的 dsh-base seam 上——status/dispatch/lease/worktree 闸门、技能挂载、engine-status catalog、harness-rules system-prompt 注入、三个原生工具——因此在一次性运行中 harness 完整生效。必须从仓库工作目录启动(runner 写入 meta.cwd = process.cwd(),按工作区的 harness 目录探测从这里开始)。浏览器客户端半体仅属于 web profile,headless 下自然不加载。

Headless 使用注意事项(已在 dsh 0.1.0-rc.6 上验证):

  • 一次性 turn 模型——runner 把任务作为一条 user message 提交,agent 转入 idle(whenIdle())后即退出;它不会等待 run_in_background 子任务。前台 subagent 派发可用(创建子会话、结果回到父会话);后台 QC-tri 式并行在进程内不会完成——要么前台派发 QC 席(串行墙钟时间),要么让 agent 在结束 turn 之前用 tool-subagent-control 收集完后台结果。
  • 无交互通道——没有可用应答者时,ask_user_question 与审批提示会 fail-closed。无人值守运行应保留受限权限预设(workspace-write 搭配 approval ask,或使用 read-only 进行只读检查),并在开始工作前核实会话实际生效的权限。仅执行该边界内已允许的操作;若某项操作需要审批,停止该操作并通过 web profile 获取审批。不要通过解除沙箱限制来绕过缺失的审批通道。交互式 Prepare 流程(grill-me)属于 web profile。
  • 默认模型解析——headless 不组合 fallbacks 行,因此 settings 里 agent-default-model 钉在 FallbacksChain 会以 NO_ADAPTER 失败(web profile 的产物)。把默认模型指向真实 provider,或同样把 dsh-llm-fallbacks 装进 headless profile(注意:已发布的 dsh 0.1.0-rc.6 上,fallbacks 的 settings 集成早于 SettingsProvider.installSection API,虚拟适配器不会注册——随 dsh ≥ 0.1.2-alpha 解决)。

Configuration

| Key | Type | Default | Meaning | | --- | --- | --- | --- | | harnessDir | string | 仓库 .mstarc [config] harness_dir,否则按会话工作区探测(.mstar/ → .agents/ → .plans/ → plans/,从会话工作区根目录开始——绝不从启动 cwd) | 显式 harness 根目录;优先于 engine 探测。harness 根不在探测名列表中的仓库必须配置;探测从会话工作区根开始(绝不从启动 cwd)并在那里停止——永不越过会话工作区向上,因此其上方的 harness 目录(如全局 ~/.mstar)永远不会被采纳。 | | enforcement | 'hard' \| 'soft' | compass,否则仅告警 | 按部署覆盖。优先级:Config 优先;否则取 Assignment 自身的 **Enforcement**: hard 头字段(仅派发闸门);否则取仓库 .mstarc [config] enforcement;否则取迭代 compass frontmatter;否则仅告警。Config / .mstarc soft 是仅有的本地回滚——Assignment 级 soft 不能覆盖 hard compass。 | | dispatchTools | string[] | ['subagent', 'subagent_fork'] | 派发闸门匹配的委派工具名——dsh preset 的两个委派工具:subagent 及其 fork 兄弟 subagent_fork(两者都携带 Assignment 形态的 { description, prompt } 参数;toolName 配置可重命名实例)。 | | dispatchBinding | string | 未设置——caller 从调用方会话推导 | 派发方 agent 自身的 harness 角色(反递归 caller)——根会话身份。Assignment 的 Execute as 等于该 caller 即自我递归(dispatch.anti-recursion.self-type)。该字段只在调用方是根会话(session.header.parentSession 不存在——本 harness 中的协调 agent)时读取:此时显式值(profile patch 或配置页)原样生效,显式置空('')fail-closed,未设置则读作 project-manager(身份读取,绝不凭空编造)。子会话——或闸门读不到会话的路径(无 exec 的宿主 beforeDispatch 钩子)——永不继承它:无论该字段写什么,caller 都是空,于是每一条 Assignment 形态的派发都以 dispatch.anti-recursion.empty-binding fail-closed,因为叶子不得派发,且任何配置都不能解除这条红线。可在 dsh 插件配置页实时编辑(与 roleGate 同一条 volatile 通道)。协调 agent 不是根会话的部署无法用该字段承载。 | | roleMap | Record<string, string> | 未设置 | mstar 角色 id(Execute as)→ dsh-llm-fallbacks 角色 id。仅作日志与未来规则驱动互操作的分类桥——角色-preset 通道按设计不使用(见 LLM fallbacks 集成)。 | | rolePresets | Record<string, string> | 未设置 | mstar 角色 id(Execute as)→ 部署方声明的 agent preset id;角色-preset 通道的唯一载荷来源。角色匹配的 start 会在激活请求上选择该 preset(SubagentStartRequest.agentPreset),由 dsh 把它作为子代理的整份组合挂载(persona 经 @deepseek-ai/dsh-persona、工具与技能),并在 resume 时重放该选择。部署方需为每个角色声明一份完整 preset——preset 是整份组合,绝不是只改 persona 的补丁。合并次序:请求自身已携带 agentPreset(委派工具配置的默认值,或模型自己的 agent_preset 选择)时原样生效;否则从 Assignment 头部读取角色,未映射的角色静默跳过。空/纯空白 id 会在插件挂载时被 Config 校验拒绝。当提供者不支持独立选择(capabilities.agentPreset 为 false,或该提供者继承父会话)或组合未挂载 agentPresets registry(web 与 headless bundle 挂载 @deepseek-ai/dsh-agent-preset-registry;base 与 SDK bundle 不挂载)时,通道跳过选择(恰一条 contained debug 日志,start 不受影响)。配置的 id 每次 apply 校验一次——未声明的 id 会得到一条 warning,而不是等到子代理启动失败才暴露。 | | roleGate | 'off' \| 'warn' \| 'hard' | 'hard' | 子代理启动缝隙处的派发角色归一化(见《角色身份交付》)。显式声明——Execute as: / Act as: / Role: 字段行,或反引号/加粗的已声明角色 id,两者都只在 Assignment 头部内读取——会在 preset 合并前被改写为规范的 Execute as: <role> 头,使两个角色消费方都能绑定。hard 拒绝完全没有可靠角色声明的启动,也拒绝点名两个及以上不同角色的启动(消息点名真实原因与这些 id、确切修复以及逃生口);同时拒绝字段存在但值不可用(为空或不是小写角色 id——消息点名原始值与合法形状)以及只存在于围栏代码块中的规范声明(头部读取不识别围栏,缝隙仍会绑定该引用);warn 每次 apply 只记一条咨询并照常启动;off 只跳过拒绝——单一显式声明仍会被归一化。豁免按子代理实际启动目录判定(绝对 cwd 原样;相对 cwd 相对父目录当前目录解析;缺省 cwd 继承该目录——父目录取运行时自身解析所用的 working-directory 投影,而非不可变的 header.cwd):解析不到 {HARNESS_DIR} 的目录静默直通;已声明可用角色、携带 agentPreset 的请求以及未知提供者同样直通。这是插件两个可实时编辑的设置字段之一(roleGate 与 dispatchBinding):在 dsh 插件配置页保存不同模式会写入 profile patch,并在下一次子代理启动时生效(无需重载);表中其他字段都在 apply 时读一次,需要重载。 | | skillRoots | string[] | 未设置(不注册自定义根) | 向 dsh skill-filesystem 提供者注册的额外技能根(customSkillDirs 语义——先于用户根扫描)。开发期:镜像 <repo-root>/skills 的绝对路径。 | | bundledSkillDir | string | 打包的 harness-skills/ 镜像(包相对路径) | 向 dsh skill-filesystem 提供者注册的打包技能根(bundledSkillDir 语义——最后扫描、受信任)。默认取包内自带的 harness-skills/ 镜像(bundle-assets 同步;gitignore)——包相对路径,非 cwd 锚定。显式值优先。 | | catalogTtlMs | number | 60000 | pre-step catalog 缓存刷新间隔(毫秒):按工作区缓存的统一 mstar-engine 行(迭代闸门 + 工作区摘要)多久重读一次 store.db 执行权威 / compass / 知识索引。刷新间隔之间热路径只是时间戳比较 + Map 命中;会话中 plan/compass/residual 的变化会在一个间隔内落地。 | | workflowGate | 'off' \| 'warn' \| 'ask' \| 'hard' | 'warn' | workflow/ralph 闸门模式(见 Gates → Workflow / ralph gate)。off = 直通且不产生 verdict 行;warn = 仅咨询;ask = 首见名字走审批瀑布(P-c);hard = 策略违规在任何子进程启动前否决。默认 warn 不改任何 hard 行为——除非部署显式选入 ask/hard,闸门仅咨询。 | | workflowNames | string[] | 未设置 | workflow 名字白名单(P-a):被闸门视为 KNOWN 的 meta.name 值。为空或缺省 ⇒ 每个名字都 unknown(有文档——闸门绝不因缺省而"全放行")。ralph 调用不携带 meta.name——P-a 对其永不适用。mstar 只读扇出路径推荐值:['mstar-qc-tri', 'mstar-audit-fanout', 'mstar-pr-seats']。 |

推荐的 operator 覆盖层。 上表三个推荐 workflowNames 覆盖 mstar 只读扇出路径(plan QC tri、大型仓库 /codebase-audit、/amazing-pr-review deep);写入它们是 profile 层的操作者覆盖,绝非 mstar 默认。出厂空列表下每个名字都是 unknown,在默认 workflowGate: 'warn' 下这只是运行会存活的一条 workflow.name.unknown 咨询。生产部署若还要否决 unknown 名字,可设置 workflowGate: 'hard';出厂默认仍为 'warn'。

bundledSkillDir 默认取包内自带的 harness-skills/ 镜像(见 Skills mount)——显式 Config 值仍然优先。相对覆盖仍是 cwd 锚定(skill-filesystem 以 join() 语义相对 dsh 进程 cwd 解析),因此覆盖默认的部署应在 profile 层传绝对路径(见 bundle/README.md)。

组合后的行集合

profile bundle 组合出以下行——注册表行来自 @deepseek-ai/dsh-base 层,本 bundle 的补丁在其上插入 mstar 行并携带中性默认(即全应用 e2e fixture 启动的行集合):

- name: '@deepseek-ai/dsh-skill'   # skill 注册表(ctx.skills)——dsh-base 行
- name: '@deepseek-ai/dsh-tools'   # tool 注册表(ctx.tools)——dsh-base 行
- name: '@deepseek-ai/dsh-commands' # command 注册表(ctx.commands)——dsh-base 行
- name: '@mstar-harness/dsh'       # 本 bundle 补丁插入(config: {}——插件默认生效)

注册表行先于插件挂载,使 mstar 各闸门、seam 工具与 bundled 命令注册时 ctx.skills / ctx.tools / ctx.commands 已存在。

What the plugin does when mounted

  • 状态闸门——fs/write-intent + fs/edit-intent 监听器校验 v3 协调文档目标集——v2 根 {HARNESS_DIR}/status.json、workflows/<id>/snapshot.json 与 projects/<id>/residuals.json——各自使用匹配的 engine 校验器(validateStatus = v2 根 / validateWorkflowSnapshot / validateProjectRegister,即 P2 修复的 harnessDocKindOfTarget 形态),外加快照目标的 findingsCleanupGate 扩展(按配置模式的计划行,从项目注册表读取残留)。
  • 派发闸门——tools/pre-execute 监听器作用于委派工具,通过 engine 的单一 composeDispatchGate 组合(字段闸门、反递归预检、默认分支闸门——与 opencode/omp/CLI 对齐,违规码按构造即相同)校验 subagent Assignment 文本,外加 dsh 租约闸门与 worktree L1/L2 检查。
  • 技能撰写 lint——已配置技能根下的 SKILL.md 写入运行 engine 技能撰写 lint(lintFrontmatter + lintFiveQuestion)。
  • seam lint——harness 下 DESIGN.md / 评审报告({REVIEW_DIR} = {HARNESS_DIR}/reviews/)/ 知识文档 / roles 目录的写入运行各自的 artifact 级 engine lint。
  • 模型可见工具——ctx.tools 上恰好注册三个工具,且只覆盖 MCP 面做不到的事:mstar_plan_bind(持久槽生产者——dsh 本地 executionBinding 槽及其采纳收据的唯一写入者)、mstar_audit_validate(评审报告凭据扫描,mstar_audit 家族没有任何 action 提供)与 mstar_execution_clear(不存在共享的 execution.clear 命令)。其余所有运行时能力都走 MCP 家族:每个家族一个工具 + action 参数。store 级命令(store.*)是刻意的例外:它们搬运整个 store,因此只在 CLI,家族成员以 transport: "cli" 发布。成员规则与各工具的独有贡献见 § Native command surface。
  • bundled 命令——向 ctx.commands 注册 /iteration-start、/iteration-drive、/iteration-loop、/codebase-audit(来自打包的 harness-commands/ 镜像;每条声明 frontmatter input hint,使 web 客户端 claim /name 并等待用户后续输入而非立即执行;handler 把命令正文 + 用户输入 steer 进接收 agent)。
  • 原生执行绑定路径——持久执行绑定由成功的原生 mstar_plan_bind(两个 bind 臂,均在引擎只读 C1 session resume 成功之后)自动采纳,并按需用 mstar_execution_clear 工具清除:身份来自 exec.agent.id(无参数、无模型可选面),清除会保留本会话自己的用户选择与排除下限,未绑定会话或不可读的 binding 记录会得到命名拒绝及其恢复路径,而不是静默写入。这条路径上没有任何斜杠命令——操作者绑定或清除执行会话,用的就是这两个原生工具。
  • pre-step catalog 行——一个咨询式 agent/pre-step 监听器追加一条统一的 mstar-engine catalog 消息,只携带一条 delta 行(workflow / 非 Done plans / branch 锚点 / 解析到 steering compass 时的相位 gate 判定),选中项带警告时再附 workflow warning 披露行。residuals 汇总、branch policy、spec 集成锚点、row scope、知识摘要、compass 方向与 agent-flow ledger 均为 payload-only(面板 + engine 权威)——见 § Engine-status catalog。发射按会话+工作区变更驱动——首次发射之后,仅当渲染出的行或面板相关 payload 变化时才追加;turn 开始本身从不触发,未解析到 {HARNESS_DIR} 的工作区不会组合该行。其背后的构建共享同一份内存 TTL 缓存(catalogTtlMs,默认 60 秒);每会话最新发射持久化到 control 根的 store.db(dsh_status_emissions),而非文件缓存。

Enforcement semantics

默认仅告警:闸门违规记录日志并发出咨询事件(mstar/status-gate、mstar/dispatch-gate、mstar/skill-lint 及各 seam 咨询),动作照常继续。Enforcement: hard——来自迭代 compass frontmatter、Assignment 头字段或插件 Config(enforcement: hard)——把违规升级为经 cordis 拒绝通道的真实否决/拒绝:subagent 派发在不调用 next() 的情况下返回 PreToolDecision { kind: 'deny', reason };状态/技能 lint 写入因 intent 瀑布链内容盲而从不硬否决——对已非法的文档按修复逃生放行(hard: true, repair: true 咨询),让修复性写入能落地。Config soft 是唯一的本地回滚;hard 闸门绝非全局默认。

Gates

Status gate

fs/write-intent + fs/edit-intent 监听器(以 prepend 注册,确保先于 dsh-fs-policy 执行)对 {HARNESS_DIR}/status.json 的写入把关:基于当前磁盘文档运行 validateStatus + 按 plan 的 findingsCleanupGate(文档只解析一次——无 TOCTOU 双重读取)。闸门从不抛出:每次决策都以 mstar/status-gate 咨询事件呈现,并通过 next() 委托 intent 瀑布链。告警模式(默认)在有违规时记录日志并发出事件。hard 模式对已非法的文档按**修复逃生(repair escape)**放行(error 级日志 + hard: true, repair: true 咨询)——intent 瀑布链不携带写入内容,若对非法文档硬否决,反而会卡死修复性写入本身。意外内部错误在两种模式下都降级为放行并发出 degraded: true 咨询(错误隔离包络);首次破坏文档的写入本身无法在此 seam 上被否决(见 Known Limitations)。

Dispatch gate

tools/pre-execute 监听器作用于委派工具:解析载荷中的 Assignment 文本,在头区域上运行 engine 的单一派发闸门组合(composeDispatchGate——形状守卫、validateAssignmentFields、antiRecursionPrecheck、默认分支闸门、头区域强制执行;opencode/omp/CLI 绑定使用同一组合,违规码按构造即相同),外加 dsh 侧 worktree L1/L2 检查与租约闸门。拒绝通道为不调用 next() 而返回 PreToolDecision { kind: 'deny', reason };告警模式记录日志、发出 mstar/dispatch-gate 并委托。非 Assignment 提示与非委派工具保持惰性。两种模式下 engine 故障都降级为放行,且降级可观测:catch 路径发出 degraded: true 的插件自有咨询 + error 日志,使 hard 部署能察觉控制失效而非静默放行。以 prepend 注册,防止更早挂载的决策监听器把本闸门短路在不可达处。

Lease gate

在 opencode 字段之上:声明 Execution mode: sdd 或行处于 InProgress 的可写 Assignment 派发,将 Worktree path/Working branch 与权威行 metadata.worktree_path/metadata.working_branch 比对,不读取 holder 或逐行 lease。缺少登记 scope 产生 lease.dispatch.unverifiable(可写派发前 STOP)。权威/status/snapshot/row 缺失或不可读仍产生 lease.dispatch.unverifiable 或 lease.dispatch.unreadable;warn 咨询,hard 拒绝。Worktree/branch 不匹配保留 lease.dispatch.worktree-mismatch/branch-mismatch;holder-mismatch 已删除。只读角色跳过;其他非 SDD/非 InProgress 派发保持降级放行。读取限定 assignmentHeaderRegion。

Skill lint gate

作用于已配置技能根下 SKILL.md 文件的 fs/write-intent 监听器,对写入前的磁盘文档运行 engine 技能撰写 lint(lintFrontmatter + lintFiveQuestion——与 CLI mstar skill lint 组合一致)。该槽位内容盲(intent 瀑布链只携带 (target, actor)):文件缺失 = 首次创建 = 放行;磁盘文档干净 = 静默放行;告警模式下有违规 = 咨询 + 委托;hard 模式下有违规 = 修复逃生——文档已经非法,本次写入可能就是修复本身(error 级日志 + hard: true, repair: true 咨询,携带强制执行后的 hardBlocked 判定)。强制执行解析方式与其他闸门相同(Config 覆盖优先,否则取迭代 compass,否则仅告警)。闸门从不抛出;读取失败与意外错误降级为放行并发出 degraded: true 咨询。类型化 hard 否决(SkillLintVetoError,码 skill-lint.veto)位于传入文档分支(lintSkillWrite)——当前接线见 Known Limitations。

Workflow / ralph gate

tools/pre-execute 的一个分支(位于 subagent prompt 分支之前)把关 workflow 与 ralph 工具调用——这是剩余的不携带 Assignment 文本、模型可达的扇出路径。它匹配固定工具名(workflow / ralph);重命名后的 workflow 实例不在范围(名字守卫是固定默认)。非 workflow 工具不受影响——subagent 分支照旧拥有它们,语义不变。

WorkflowGate 的 off/warn/ask/hard 四级模式仍独立于 Enforcement。P-b 先检查登记的可写 scope,再检查 P-a 名字与 P-c 首见审批;不再逐行 holder 准入。

| 策略 | off | warn(默认) | ask | hard | | --- | --- | --- | --- | --- | | P-b:InProgress 行缺少 metadata.worktree_path/metadata.working_branch | allow(off) | warn/咨询,workflow.lease.uncovered | warn/咨询;ask 仅服务名字 | 子进程前 deny,workflow.lease.uncovered,点名该行 | | P-a:workflow 名字 ∈ workflowNames(非空列表) | allow(短路) | allow——无咨询(P-a 在任何模式下都放行) | allow——无 ask | allow | | P-a:workflow 名字 unknown(空/缺省列表 ⇒ 每个名字都 unknown) | allow(短路) | warn——放行 + 咨询(workflow.name.unknown)+ 一条 warn | ask(首见)→ {kind:'ask'};之后复用缓存决策(allow/deny)——已解析名字绝不再 ask | deny——在任何子进程启动前否决(workflow.name.unknown),reason 点名该名字 | | ralph(无 meta.name——无白名单身份) | allow(短路) | allow——P-a/P-c 永不适用 | allow——P-a/P-c 永不适用 | allow——P-a/P-c 永不适用;P-b 仍适用(uncovered 时 deny) |

默认 warn 的理由。 默认 warn 使闸门绝不让部署意外吃硬阻断:除非操作者显式选入 ask(人工 ask 通道)或 hard(否决),闸门仅咨询。workflowNames 空/缺省使每个名字都 unknown——闸门绝不因缺省而"全放行",但默认模式把这一点变成咨询而非阻断。

与 Enforcement: hard 的交互。 workflow 闸门的模式是它自己的 Config 旋钮——跨切面的 Enforcement: hard 解析(compass / Assignment 头字段 / Config enforcement)不会升级 workflowGate。hard-enforcement 部署仍按已配置模式运行 workflow 闸门(默认 warn = 仅咨询),除非同时设置 workflowGate: 'ask' 或 'hard';反之 workflowGate: 'hard' 与跨切面解析无关地否决。二者不可混淆:workflow 闸门只在部署把模式选入时才关闭 "Enforcement: hard 下的未把关扇出" 缺口。

Fail-open 边缘(有文档,绝不崩溃合规调用)。(1)畸形参数——workflow 调用缺少非空字符串 meta.name(控制字符归一化之后),或 ralph 调用缺少字符串 objective → 在每个模式下(hard 亦然)直通 + 一条 warn,且无 verdict 行(未产生策略判定)。只含控制字符的名字归一化为空 → 视为畸形。(2)status.json 不可读——经含容解析器路径的 P-b 状态读取抛出 → 仅本次调用的 P-b 降级 + 一条 warn;P-a/P-c(基于名字,无状态依赖)照常运行。闸门从不抛出:每次读取都是结构化的。

Verdict 账本行。 每个被把关的调用都在 agent-flow 账本记录一条持久化 workflow-verdict 行(P2 账本 plan 的记录路径,完全含容——账本写入失败绝不波及闸门):tool(workflow | ralph)、workflow(归一化后的 meta.name)或 objective、mode(绝不为 off——off 在策略前短路)、判定词汇 ok / advisory / denied / ask(ask 判定是本次扩展:首见 ask 本身也是被把关的调用,其行携带 ask 直到审批瀑布解析——"每次被把关的调用一行")。违规码来自判定、绝不猜测:workflow.name.unknown(P-a)vs workflow.lease.uncovered(P-b)。fail-open 路径(畸形参数 / 状态不可读)不记录;未解析出 harness 目录的调用跳过该行(与派发记录路径相同的静默 no-op)。

P-c 答案观测 seam。 闸门无法观测 ask 结果——工具注册表的 serviceAsk 在内部消费审批结果。run-start 观测就是答案 seam:被 ALLOW 的 ask 执行调用 → 持久化 tool-workflow/run-start 会话事件落入父会话日志 → workflow-ledger 消费者记录 W-B2 workflow-run 行并把 allow 按运行名缓存进 apply 作用域的 WorkflowAskCache。被 DENY 的答案不产生运行 → 无观测 → ask 模式下下一次同名调用重新 ask(fail-closed——无授权证据,绝不发明 allow)。缓存键在两个 seam 都是归一化(剥离 ASCII 控制字符)不截断的名字——闸门合成 meta.name 与观测记录 runName 都走同一个 normalizeWorkflowName,因此含控制字符的名字(au\u0000dit)永远无法卡死缓存(ask 一次、同一键观测),>1024 字符的名字仍以完整名字为键(账本行的展示名字单独截断;身份轴从不截断)。缓存是 apply 作用域的——新 apply(HMR 重载)从空开始,因此未解析的首见名字每次调用都会重新 ask,直到一次观测(或显式 record())落地。缓存记录抛错时观测降级为一条 warn——账本行已追加,运行不受影响。

P-b 抢占: InProgress 行缺少登记 source scope 优先于名字策略,对 ralph 同样适用。在可写派发前通过普通 prepare 配置实际 source 事实,不逐行恢复或 claim lease。Warn/ask 仍仅咨询,hard 否决。

LLM fallbacks integration

可选的 dsh-llm-fallbacks 插件(以第二条命令安装——见 Install paths)驱动基于角色的 subagent 配置——角色种子与采纳建议;角色身份交付本身走 dsh 原生 subagent preset 通道(与 fallbacks 无关,见下文)。mstar 插件对该包携带零运行时与零类型引用——src/ 无任何导入(运行时或类型);被消费的服务面由 src/gates/fallbacks-structural.ts 的本地结构类型镜像,该包仅是 mstar 插件的开发期依赖(类型镜像 + 真实包测试 harness)。dist/ 仅在 1 处字符串字面量中命名该包——探测的 loader 条目匹配——绝非导入或类型引用;互操作是决策点能力探测,绝不读取其他插件的模块内部。

能力探测

挂载状态的两个视图(决策点即时读取,无缓存——loader 并发挂载条目):

  • fallbacksService(ctx)——插件被 apply 期间命名的 cordis 服务(ctx.get('llm-fallbacks'));HMR/纤程切换窗口内即使 loader 条目仍在,服务也为 undefined(条目是声明式的,比纤程活得久)。
  • fallbacksMounted(ctx)——能力视图,服务优先 + loader 条目回退:名为 dsh-llm-fallbacks 的 loader 条目存在、启用(尊重 entry.disabled 与 group 行)且纤程存活。

状态区分:mounted(服务已 apply——完整能力)、unmounted(无条目:未安装 fallbacks 插件——mstar 能力降级,绝不中断)、disabled(条目存在但禁用/分组——能力关闭),以及 HMR 窗口(条目在、服务缺——loader 回退覆盖)。

角色身份交付(原生 subagent preset 通道)

角色身份通过选择一个已部署的 agent preset 交付:插件经 cordis internal/get waterfall——框架文档化的服务读取拦截钩子——拦截 ctx.subagents 的服务读取并包装运行时值,使角色匹配的 startActivation(spec) 在子会话组装之前合入 spec.request.agentPreset。dsh 0.2.1 中 startActivation 是唯一的启动面(一次性与 continuable 子代理一致),而 preset 拥有子代理的整份组合(persona、工具、技能);dsh 会把该选择记入子会话日志并在 resume 时重放。底层 SubagentRuntime 对象绝不被改动(无 monkey-patching),包装监听器归 apply fiber 所有(HMR 重挂载会先卸载再恢复,并重新绑定新 Config)。persona 交付走 dsh 0.2.1 的设计而非私有段:上游已移除 SubagentStartRequest.persona 与 start/startContinuable 对,且 tool-subagent 对 persona 配置直接报错「configure persona and tool plugins in an Agent Preset and select it with agentPreset (spawn only)」。

能力闸门:独立选择要求提供者 SubagentCapabilities.agentPreset 为 true 且 inheritsParentContext 为 false——正是上游 tool-subagent 断言的同一组合(「provider does not support independent agent preset selection」)。同时必须挂载 agentPresets registry:没有它 dsh 会 fail loud PRESET_UNAVAILABLE,因此通道跳过选择并记录恰一条 debug 日志(每次 apply 只记一次),start 照常继续。闸门未通过绝不使派发失败。

组合归部署方所有:mstar 只负责角色 → preset 的选择。每个角色指向的 preset 都由部署方声明(@deepseek-ai/dsh-agent-preset 行,通常挂载 @deepseek-ai/dsh-persona 并携带该角色的 persona 文本,与上游自带的 standard/minimal preset 同构);mstar 不生成 preset,因为 preset 是完整组合——由 mstar 并不拥有的行构成。

先归一、后拒绝(roleGate):同一个包装器在 preset 合并之前先归一化显式角色声明——Role: \fullstack-dev` 行、Act as:值(去掉一个前导@、引号或反引号后),或反引号/加粗且属于**已声明**角色 id(rolePresets键 ∪ 打包的harness-agents/shell 文件名)的 token——以上都在 Assignment 头部内读取,都会被改写进规范的Execute as: 头,改写后的 prompt 才是内层消费方与运行时收到的内容。两类候选都限定在头部并读取围栏掩码后的文本:正文句子或围栏示例里引用的角色 id 永远不是候选(粘贴的散文或模板无法武装角色);而头部解析器**只在围栏内**读到的规范声明在hard下会被拒绝而不是静默放行——头部读取不识别围栏,缝隙会绑定该引用。头部里的**每一条**Execute as字段行都会被修复并把标签归一化,因为解析器区分大小写且绑定**最后一条**字段行;两个及以上**不同**候选视为歧义,绝不去猜——该拒绝消息点名这些 id 并说明只能有一个声明(自由散文如「You are an architect doing…」永不挖掘)。只有完全没有可靠角色声明(或有歧义、围栏内、字段存在但不可用——为空或不是小写角色 id)的启动才会被拒绝(默认hard),消息点名真实原因与原始值、确切修复以及**与模式匹配**的恢复路径:hard拒绝提供roleGate: warn|off,而 warn咨询只建议roleGate: off(它已经放行)。非 harness 项目按子代理**实际**启动目录判定(绝对 cwd原样;相对cwd相对父目录**当前**目录解析;缺省cwd继承该目录,与运行时自身resolveDirectory的选择完全一致;父目录取 working-directory 投影而非不可变的header.cwd)并豁免;已携带可用 Execute as的 prompt、携带agentPreset 的请求以及未知提供者同样直通(后者的失败由服务按自身语义抛出)。off` 只跳过拒绝;单一显式声明仍会被归一化。

roleGate 与 dispatchBinding 可在插件配置页编辑 —— 两者都是 volatile schema 节点,经 Loader 的实时引用读取,因此配置页的一次保存写入 profile patch 并在无需重挂载的情况下生效。

反递归绑定(dispatchBinding)是根会话身份,永不被继承——caller 从调用方会话推导,且该字段只在根会话上读取。根会话(session.header.parentSession 不存在)就是本 harness 的协调 agent:显式绑定(profile patch 或配置页)原样生效,显式置空仍然 fail-closed,没有显式值时读作 project-manager——身份读取,绝不凭空编造。子会话(任何 parentSession)永不继承该绑定:无论字段写什么,caller 都保持空,于是每一条 Assignment 形态的派发都以 dispatch.anti-recursion.empty-binding fail-closed——正是引入默认值之前的行为,因为叶子不得派发。闸门读不到会话的路径(无 exec 的宿主 beforeDispatch 钩子)同样回落到空,绝不回落到协调者,也绝不回落到已配置的值。声明或推导出的 caller 仍是真实比较:Execute as 等于它仍按自我递归拒绝(dispatch.anti-recursion.self-type);显式置空状态还会在 apply 时记录一条 warn,指向插件配置页。协调 agent 不是根会话的部署无法用该字段承载。

Seam 探针(fail-loud):通道每次 apply 对 cordis internal/get seam 探测一次(临时 canary 监听器 + 一次受控代理式 ctx.subagents 读取——绝不 ctx.get);seam 缺失或未被识别时记录恰一条 warn——role persona channel not installed — cordis 'internal/get' seam missing or unrecognized (role presets will not be selected for subagent starts) + (reason: seam-absent | wrap-skipped)——而非静默失败。健康 boot 不产生任何 warn(锁定的判定表):在今天的组合形态下 apply ctx 不解析 subagents,因此每次 apply 发出一条无 warn 的 service-absent debug——cordis 在 dispatch 作用域解析该服务,读取在那时逐次被拦截;探针内部错误按 fail-open 降级(一条 debug)。wrap-skipped 已被钉死但无法从当前发布的 apply 布线触达——它只在 apply 时即可解析 subagents 的场景触发,该路径由 harness pins 覆盖。seam 名由专用探针家族 tests/persona-seam-probe.spec.ts 钉死(经导出的 PERSONA_SEAM_EVENT 常量);安装产物断言在携带探针的版本发布后自动启用(tests/install-e2e.spec.ts 的 surface-vintage guard)。

角色 seeds 与采纳建议(Adoption advisory)

当可选的 dsh-llm-fallbacks 能力已挂载(第二条安装命令——见 Install paths)时,mstar 插件会向 fallbacks seed registry 零配置声明 13 个 mode: subagent mstar 角色 seed:persona = harness-agents/ 镜像 description(原样)+ 一行强制加载引导(Load mstar-roles (references/<role-id>.md) first — identity comes before skills; load topic skills only when the Assignment activates them via its Skill presets field.);含 {{...}} 插值风险的 persona 跳过并告警,绝不声明。声明会合并保留 readback 中当前已 seeded 的非 mstar id——例如上游包在其自身 apply 时自声明的 5 个上游 preset 角色:上游 declare 全量替换 registry,若不保留,mstar-only 批会摘掉 preset id 的 seeded 注记(行仍在,仅失去 seeded)。声明在每次 fallbacks(重新)apply(HMR/纤程切换)时幂等重放——绝不用一次性 latch——因此两种 boot 顺序(presets 先或 mstar 先)都收敛到同一 18-id 全 seeded registry。boot 时收敛经 bounded retry(有界重试):上游的 seed 写通道在其 apply 之后一个 macrotask 才绑定,因此 apply 窗口内首次尝试被 seeds: settings service is unavailable 拒绝时会重试(跨上游 apply 窗口的 3 次尝试),暂时性拒绝自行收敛;仅当所有尝试最终失败时,声明才记录恰好一条终态错误,同时 advisory 的决策点 re-declare 仍可用作 retry 路径。无需手动编辑 roles.list。

一条只告警的采纳建议通道(日志器 mstar/fallbacks-advisory)每次 apply 只跑一遍——apply 时先尝试一次;当 fallbacks 行在 dsh 之后挂载(loader 并发挂载条目)时,改在首个 subagent/start 决策点只跑一遍。服务存在时,通道先 await 幂等 re-declare(闭合 boot 竞争窗口)再读取有效状态(getEffectiveRoles),并按每类至多一条告警有界报告:

  • 缺失 mstar 角色——无有效行的 mstar id(一条告警列出全部;id 集合派生自 harness-agents/ 镜像——绝不硬编码;无镜像 → 检查跳过并记一条 debug);
  • persona 覆盖——行 persona 与 seed 默认值不同的 mstar 角色(一条告警点名 + revert 入口:fallbacks/revert-seed gateway / fallbacks 设置卡片回滚按钮——操作者覆盖在 revert 前保留);
  • 空 persona——persona 缺失/空白的行,仅限非 seeded 或 overridden-empty(一条告警点名);
  • 遗留键——chains、roles.default、roles.list[].label/.description、悬空 roles.rules[].role 引用,经已应用服务自带的 detectLegacyKeys(一条告警引用其语义);
  • declare 跳过/冲突——本地跳过(interpolation / no-persona)+ 上游跳过/冲突(码 persona-source——操作者覆盖保留)合并为一条告警;默认已 seeded 静默(一条 debug 点名)。

loader 回退路径(无服务)保留结构化 roles.list 读取(缺失 id / 空 persona;无 revert 入口——无 seeds 面;遗留键检查跳过——绝不重新实现)。行配置缺失或非对象、或 roles.list 不可读 → 跳过并记一条 debug。该建议绝不写入 fallbacks 配置——唯一写路径是经已发布 seeds 面的幂等 seeds re-declare(无差异 → 上游零设置写入)——绝不抛出,且 fallbacks 未挂载时不调用:它是信号,不是闸门。

配置面

| Key | Type | Default | Meaning | | --- | --- | --- | --- | | roleMap | Record<string, string> | 未设置 | mstar 角色 id → fallbacks 角色 id。仅作日志与未来规则驱动互操作的分类桥——角色-preset 通道按设计不使用。 | | rolePresets | Record<string, string> | 未设置 | mstar 角色 id → 已部署的 agent preset id;通道的唯一载荷来源(选中的 preset 拥有子代理的 persona、工具与技能)。 |

Service

apply 构造 ctx.dshMstar(engine 支撑:validateStatus、validateResidual、findingsCleanupGate、resolveCompassEnforcement、resolveHarnessDir、readHarnessVersion、applyEnforcement)。分层:P1 各闸门是本包内与 engine 同置的包装器,直接导入 engine(同一插件,构建时打包 engine);ctx.dshMstar 是供 inject 消费者使用的组合/测试外观;宿主适配器(下节)是面向宿主的门面。两条路径共用 engine 这唯一语法源。伴随入口 @mstar-harness/dsh/invariant 以文档化的空安装器保留包所有权。

Host adapter

插件以 DshHostAdapter 实现 engine HostAdapter 契约(host: 'dsh'),并以 ctx.dshHostAdapter 服务暴露。检测:engine detectHost 将 dsh 委派工具名——ToolSignal subagent(模型可见的 dsh subagent 工具)——映射为 'dsh',在 omp 之后、kimi/zcode/codex 之前求值;混合会话按固定顺序让位于更早的行。适配器与插件内闸门共用同一套校验核心(单一代码路径):beforeStatusWrite(path, doc) 在宿主提供文档时校验传入文档,否则走磁盘文档回退(文件缺失 = 首次创建 = 放行);beforeDispatch(assignment) 运行字段 + 分支 + 反递归闸门并携带强制执行后的 hardBlocked 判定(租约闸门留在监听器侧——它绑定该钩子不携带的 ToolExecution 会话上下文);beforeMerge(lease) 是 engine validateIntegrationMergeLease 的薄包装(向 status.json 的预留写入是 P3 seam)。log 默认路由到 dsh ctx 日志器 mstar/host-adapter。

dsh 的冻结技能根形态(engine resolveSkillRoot('dsh', …))为 $DSH_BUNDLED_SKILL_DIR/<name>[/<rel>]——解析器只定义技能相对路径解析器(resolveAssetPath)所用的规范形态;它不挂载目录。挂载由插件负责(下一节)。

Skills mount

mstar 技能通过 dsh skill-filesystem 提供者以单一规范挂载接入:插件把配置的根注册为一个提供者(providerName: 'mstar'、includeDefaultRoots: false——隔离,绝不看到宿主应用自身的项目/用户技能),上文的 engine 形态是共享的技能根契约。两条 Config 路径填充它:

| 路径 | 机制 | 时机 | | --- | --- | --- | | Bundled 默认 | bundledSkillDir 默认取包内自带的 harness-skills/ 镜像——仓库根 skills/(19 个 mstar-* + pm)由 bundle-assets 在构建时同步(gitignore),按包相对路径解析(非 cwd 锚定——任意启动 cwd 都可用) | 发布包 / 无覆盖的任何部署 | | 自定义根 | skillRoots / 显式 bundledSkillDir → skill-filesystem customSkillDirs / bundledSkillDir 条目(显式值优先) | 本地开发 / 测试 / 使用不同镜像的部署 |

打包镜像是单一规范挂载:技能内容只在仓库根 skills/ 镜像中存一份并同步进包(与 opencode 的 harness-skills/ 相同),mstar 技能在任何地方都保持可独立使用。不重复加载:opencode 插件在自己的包里携带同一批技能,因此 dsh 只能通过这条 skill-filesystem 路径挂载它们。

开发期现实:@deepseek-ai/dsh-skill-filesystem 运行时是 peer stub(契约镜像的注册,无文件 watcher),因此挂载通过真实组合(stub + 实际镜像 skills/ 的 frontmatter,用 engine lintSkillFrontmatter 校验)验证;真实运行时组合(真实 seam 包、watcher、$DSH_BUNDLED_SKILL_DIR 环境变量流)是部署目标,不在本包测试套件覆盖内。

Commands

插件把 bundled 的 mstar 命令(omp/opencode 对齐面)注册到 ctx.commands:harness-commands/*.md——仓库根 commands/ 镜像(iteration-start、iteration-drive、iteration-loop、codebase-audit)由 bundle-assets 在构建时同步(gitignore)。每条注册读取命令的 name/description/input frontmatter;声明了 input hint 的注册会将其作为 input.hint 公布,使 dsh web 客户端的决策表从「脱离式裸执行」翻转为 leadingInput claim——菜单点选后把 /name 插入输入框(命令色 token + ghost hint),按 Enter 才提交,用户可以键入后续参数(与 /plan、/goal、/advisor 相同的交互)。handler 把命令正文以 USER source 消息 steer 进接收 agent(dsh-plan-mode 命令先例——source: { kind: 'user' },模型把正文当作要执行的任务而非注入上下文;即 dsh-commands 的「经接收 Agent 显式调度模型可见工作」路径),用户键入的参数以 ## User input 小节追加在正文后,返回成功结果。注册以 ctx.inject(['commands'], …) 延迟进行——与工具注册相同的可选单元模式——插件在无 commands 服务时也能启动;镜像缺失(未跑 bundle-assets)则不注册任何命令。

Native command surface

本宿主的可写 mstar 命令面是 MCP 路线:整个宿主共享一条 mstar-mcp 连接(即 bundle 行——见 § Shared MCP connection),每个命令家族一个工具(mcp__mstar__mstar_<family> + action 参数)。该连接自身不携带任何身份,但随发行的行以 --trust-caller-session-id opt-in,因此需要会话身份的操作在这条连接上传 sessionId(未 opt-in 的连接不发布选择器并拒绝传入的 id)。下列三个 dsh 原生工具只留给本 MCP 面做不到的事——写不了的插件本地状态,或没有发布的能力;那里身份来自 exec.agent.id。

成员规则——记住它而不是记清单:一个命令只有在满足下列之一时才是 dsh 原生工具

  1. 产出 MCP 路线写不了的 dsh 本地持久记录,或
  2. 提供 MCP 面根本没有发布的能力。

目前恰好有三个工具满足该规则:

  • mstar_plan_bind —— 规则 1。它既绑定引擎 coordinator 行,也持久化本插件自己的持久状态:control 根 store.db 中本会话的 executionBinding 槽,以及 workflow ledger 归因解析器与 mstar_execution_clear 读取的进程内采纳收据。形态:共享 plan.bind 参数按已发布 schema 机械镜像(身份来自 exec.agent.id),引擎拒绝原样返回,已知叶席位在准入前 fail-closed 拒绝。MCP action: "bind" 路线只绑定引擎行、到此为止——两条路线并不等价。
  • mstar_audit_validate —— 规则 2。评审报告凭据扫描(mstar-audit Hard Rule 4,即 mstar audit scaffold 背后的校验器);mstar_audit 家族只发布 scaffold / secret-scan / supply-chain,都不校验已存在的报告文件。
  • mstar_execution_clear —— 规则 2。它清除同一个 dsh 本地 executionBinding 槽,而 MCP 路线没有可承载的共享 execution.clear 命令。它完全不带参数:身份来自 exec.agent.id,因此只能触达调用者自己的绑定,并保留用户的工作流选择与排除下限;已知叶席位在读取 store 之前 fail-closed 拒绝。其拒绝(execution.clear.no-harness / no-binding / store-refused)都点名原因与恢复路径。

其余运行时命令全部走 MCP——store.* 命令只在 CLI,不在此发布;旧的 mstar_<family>_<action> 工具名不会以别名复活:用家族 + action 调用,并用 mcp__mstar__mstar_schema(family: <name>,或单个叶子契约的 command: <command-id>)读取家族真实的 action 与字段。这个表面上的身份、准入与 fail-closed 叶席位拒绝遵循 ADR docs/adr/dsh-native-identity-channels.md。

Shared MCP connection(显式声明的 control 根)

bundle 补丁只插入一行 mstar-mcp,而这一行就是整个宿主的全部 MCP 通道:插件不自行注册任何 MCP client,不存在按 agent 挂载,subagent 共用父级已有的那一条连接。按 agent 的实例本来也拿不到按调用参数(PreToolDecision 没有改写参数的通道),因此它换不来任何能力——只会每个 agent 多一个 Node 进程。

control 根是「声明」出来的,绝不推断。 它按一条有序规则解析,启动 cwd 从不是候选——那个目录属于宿主,它说不出调用方属于哪个工作区,采用它会把写入落到不相干的项目上:

  1. 连接钉——mstar mcp --harness <绝对路径>,否则服务器环境中非空的 MSTAR_HARNESS_DIR;
  2. 否则由被准入的这次调用通过工具的 harness 字段指名根(绝对路径,或相对于服务器启动目录的路径);
  3. 契约不读取任何根的无根命令类以空根运行——harness.scaffold(建立根本身就是它的操作),以及 schema、path.resolve、host.*、doctor 与 lint / skill.lint / qc.validate-report 之类的只读校验器:它们只按显式输入作答,因此从不解析隐式 harness 路径;
  4. 否则该调用以 [mcp.control-root-unresolved] 被拒绝,并点名原因与全部恢复路径——两条启动方恢复路径对任何命令都成立,而按调用的 harness 选择器是依工具而定的(不发布该字段的命令无法接受它)。

连接钉优先于按调用的 harness,因此调用方绝不可能把某次调用钉在启动方未声明的工作区上;这次调用实际使用的那个根还会把调用工作区锚定在其父目录,因此由 cwd 派生的路径落在那份 harness 下,而不是启动 cwd。在未钉的连接上,凡是根不另有来源的工具,其声明的根选择器都是必填——用 harness 指明根的命令就是该字段,sdd.workspace 则是 controlRoot——模型无法漏掉解析所需的这唯一事实,tools/list 也绝不会把解析器拒绝省去的字段公布为可选。只读校验器(review.seats、worktree.qc-alignment、lint、skill.lint、roles.validate、design-md.validate、compound.validate、dispatch.validate、qc.validate-report)的相对路径参数按已声明的工作区解析,因此 --workspace /caller 读的是 /caller 下的文件,而不是宿主检出的;未声明工作区时相对路径一律被拒绝。

连接自身不携带身份;随发行的行信任调用方声明的 sessionId。 共享连接自身无身份,且仅属 MCP 的身份接线已移除:没有 --identity-env、没有已声明身份锁、没有选择器剥离,也没有连接级默认 session id。按调用的 sessionId 选择器只在启动方显式 opt-in(mstar mcp --trust-caller-session-id)的连接上发布;随发行的行会传这个开关,未 opt-in 的连接仍以 mcp.caller-identity-unavailable 拒绝传入的 id。在 opt-in 连接上该值是 bearer 身份:executionContextFor 把它变成 context.caller,引擎据此解析调用方自己的 coordinator 绑定,因此知道一个活跃会话的 id 就足以以它行事——授权仍是那条绑定行加上可选的 --expect CAS 令牌。需要会话身份的操作在本条连接上传 sessionId 运行——包括 plan progress、plan complete、workflow register/evidence/phase、session recover、workflow-note.append。上文列出的三个 dsh 原生工具只留给本 MCP 面做不到的事,那里身份是 exec.agent.id——宿主事实,绝不是模型提供的字段。未 opt-in 的连接没有调用方声明通道,那里才走原生工具或 CLI。

Engine seam mapping

每个 engine 模块都挂到一条 dsh 表面——除 lint 模块的 plan/tdd fs 闸门外均已交付(延后项;见 Known Limitations):

| Engine 模块 | dsh seam | 状态 | |---|---|---| | core(applyEnforcement、GateResult/Severity) | 跨切面否决/拒绝 | 已交付(P1) | | path(resolveHarnessDir) | harness 目录探测 + {HARNESS_DIR}/status.json 目标匹配 | 已交付(P1) | | status(validateStatus、validateResidual、findingsCleanupGate) | status.json 的 fs/write-intent + fs/edit-intent | 已交付(P1) | | lease(verifyPlanExecutionLease、validateIntegrationMergeLease) | exec 租约:tools/pre-execute(派发闸门内);merge 租约:HostAdapter.beforeMerge | 已交付(P1 exec / P3 merge) | | dispatch(composeDispatchGate、isReadOnlyAssignmentRole、parseAssignmentFields) | 作用于 subagent 工具的 tools/pre-execute(PreToolDecision.deny 阻断);agent/pre-step 咨询 | 已交付(P1) | | host(resolveSkillRoot、HostAdapter) | engine host.ts 检测行 + 插件适配器(host: 'dsh') | 已交付(P2) | | skill-authoring(lintFrontmatter、lintFiveQuestion) | skill-filesystem 根 + 对 SKILL.md 的 fs/write-intent | 已交付(P2) | | lint(lintSkillFrontmatter、planQualityBar、assertSddTddTriple) | 未接线——plan/tdd 的 fs 闸门为延后项;lintSkillFrontmatter 仅运行于 skills-mount 测试套件 | 延后 | | agent catalog | 生产者自有的 mstar-engine catalog source(锚点)+ /api/mstar/engineStatus 发射读取(模型可见 ⟺ 已记录) | 已交付(P2) | | sdd(sddWorkspace、taskBrief) | MCP 家族 mstar_sdd(workspace / task-brief)——无 dsh 原生包装 | 已交付(P3) | | iteration(evaluatePhaseGate、parseCompassFrontmatter) | agent/pre-step + iteration 闸门 | 已交付(P3) | | worktree(l1PreDispatchCheck、l2PreDispatchCheck) | tools/pre-execute L1/L2(派发闸门内) | 已交付(P3) | | design-md / audit / compound / roles | fs/write-intent seam + 唯一的原生 mstar_audit_validate;其余为 MCP 家族 | 已交付(P3) |

Engine-status catalog

一个咨询式 agent/pre-step 瀑布监听器向发射时的组合步骤追加一条 mstar-engine catalog MessageSource——生产者自有的 mstar-engine kind,即恰好 { kind: 'mstar-engine', form: 'catalog' }、不含任何其它成员(dsh 生产者自有 source 契约):模型可见的 <mstar_engine_status> 块渲染为 payload 的投影(renderEngineStatusCatalog):渲染为一条 delta 行——workflow: <id> (<kind>) | plans: <非 Done 行> | branch: <base> → <target> | gate: <判定> (<transition>)——只携带选中的生命周期、其非 Done plan 行、解析到的分支锚点,以及 steering compass 校验迭代时的相位闸门判定(FAIL 带违规码;裸判定不指出原因)。payload 里的其余事实刻意不进该行:residuals 汇总与其明细行、branch policy、spec 集成锚点、各 plan 行的 row scope(记录范围,绝不是所有权声明或租约)、knowledge 摘要、compass direction、agent-flow ledger、原先的 iteration/transition 历史以及水印三行。这些事实留在 MstarEngineStatusPayload(面板从已存发射渲染)与其背后的 engine 权威中——mstar status、mstar roadmap show、mstar plan show、compass 文档、{KNOWLEDGE_DIR} 与 dsh_status_emissions——该行只是变更提示,绝不是权威。水印仅存在于 payload:mstar 版本(插件自身清单;单一版本不变量把打包的 engine 钉在同一版本)、harness 目录(解析后的 {HARNESS_DIR},缺失为 none)与 enforcement(compass 模式,soft / hard (compass))留在 MstarEngineStatusPayload(面板 meta dock 渲染版本 + harness 目录),并在常驻 system prompt(mstar:engine-status 摘要 + mstar:harness-rules)中模型可见一次,故该行绝不重复它们。回退组合:只要 prompt 注册未被确认生效——宿主未提供 system-prompt 服务、异步注册失败(返回 true 仅表示 inject 子已排期)、或既有注册被释放——监听器逐步骤求值的 showWatermark 判定即让该行自行重渲染水印三行,版本 / harness 目录 / enforcement 事实因此不会丢失(随后才生效的注册会自动结束回退)。监听器先调用 next() 并基于委托后的决策追加——从不否决步骤、从不替换已组合的消息。未选中任何生命周期时,该行以 workflow selection: ERROR (<code>) <message> 取代状态行(此时的聚合按构造即空,绝不能被读成「无 plans」),该消息不再指向已退役的 status.json 路径——它指出原因并给出真实的恢复命令:plan 用 mstar workflow register、迭代用 mstar iteration register(为本会话从已注册生命周期中挑一个,是另一条出路)。模型可见 ⟺ 已记录:持久化的 source 不携带任何事实——该行是持久化的锚点,其实际发出的 payload 在同一次发射时按会话持久化为 control 根 store.db 表 dsh_status_emissions 的最新一行,因此「会话日志 + 该存储」无需重新解析该块即可重建该行(dsh packages/AGENTS.md)。dsh session-format V4 在消息准入处拒绝已退役的 { kind: 'plugin', plugin } 包装,故 source 上永远只写生产者自有的 kind。锚点 kind(更名,带读兼容):发出的 kind 为 mstar-engine(更名前为 mstar-engine-status);已发布构建发出的行在其 V3 会话日志中持久化旧的 plugin 包装,dsh V3→V4 迁移会把它提升为 plugin:mstar-engine(更名前标识则为 plugin:mstar-engine-status),面板的锚点读取方同时接受这些 kind——任何其它 kind 都不是锚点,会话降级为显式 waiting 态(绝不猜测数据)。工作流面板通过宿主共享的 /api typert 网关按需读取该已存发射:路由由宿主网关持有(插件无法注册路由;connection.rpc.handle 的普通信道会经由调用 fiber 上的 webServer 挂载、并使本行的 boot 挂起——本包刻意不走该机制),本包只经可选 ctx.typert.register(...) 子单元贡献 mstar/engineStatus 端点描述符。浏览器半体调用 connection.rpc.call('/api', 'mstar/engineStatus', { args: { sessionId, cwd } }),得到该会话自己的已存发射,或带原因的显式 unavailable(绝不返回其它会话的数据、绝不静默空字段)。信任边界,如实说明:该端点自身不做任何鉴权——传输层围栏(host/origin + 浏览器鉴权)只证明调用方是本宿主自己服务的页面,因此持有 (sessionId, cwd) 组合 + 能访问本机 /api 网关即为能力。应答按请求限定:查询以被断言的 id 为键,存储记录的 cwd 必须同时等于断言值与服务端解析出的会话 cwd,客户端在渲染前还会复核回显的 id 与工作区——因此一个会话的请求绝不会被返回另一个会话的记录。payload 是工作区摘要(版本、harness 目录、enforcement、plan/residual/row-scope 计数),面板自身的会话记录本就暴露这些信息;它不被当作机密,而不同的 unavailable 原因会让该端点对已持有 id 的调用方成为一个弱的「会话是否存在」探针。fiber 销毁即移除监听器(HMR 安全)。

发射是变更驱动、而非 turn 驱动:按会话+工作区,首次发射时追加,之后仅当渲染文本或面板相关 payload 投影变化时才追加(该投影会把 store revision 归一化,因为发射自身的 store 写入会推进它——直接比较原始 payload 会把这个副作用读成变化,从而每步都重发)——20 步的 turn 只显示一次 catalog,而不是 20 次,20 个不变 turn 的会话也不再每 turn 堆积一份相同副本。turn 开始本身从不触发,因此未解析到 {HARNESS_DIR} 就完全没有该行(否则该块会是空包裹),面板显示其 waiting 态。两个后果值得明说:发出的块是 payload 的投影(不渲染水印三行,见上),且持久化 payload 就在同一闸门写入——因此面板的已存发射是模型最后看到的 payload,其新鲜度页脚 turn / at 意为最后发射、而非当前 turn;只要没有发射,已存行仍是当前状态。仍保留一条显式重锚路径:picker 提交会驱逐该会话的 digest,故下一步即使文本未变也会重发。已知限制:该行不做周期性重锚,因此宿主侧上下文压缩之后它可能在下一次变化之前缺席——常驻 system prompt 摘要仍携带版本、活跃工作流与其未 Done 的 plans。source 共享同一按工作区缓存条目:显式 harnessDir 时在 boot 构建(否则在工作区首次 pre-step 构建),并按 TTL 刷新(catalogTtlMs,默认 60 秒)——刷新间隔之间热路径只是时间戳比较 + Map 命中,会话中 plan/compass/residual 的变化在一个间隔内落地。

Agent-flow ledger

agent-flow 账本位于现有 control-root store.db 的 host 域,不再使用 workflow JSONL 文件。catalog 和面板窗口只是有界读取投影,不裁剪存储的事件。ACTIVE 权威建立之前,dsh 原生会话日志继续记录,authority 持久化如实报告 unavailable/degraded,并提供 store init / store upgrade 恢复路径;绝不伪造成功或回退到旧文件。真实派发与结算证据仍为咨询式、try/catch 包裹:账本不可用不阻断派发或结算。

  • 记录身份——已核实的原生 workflow 事件保留 {sessionId, streamId, seq} 与 wfe1:<kind>:<sessionId>:<streamId>:<seq>。流化身来自持久原生会话头部,绝不是 store epoch 或文件 mtime。实时工具调用行在两个 ID 均已知时可带 wfc1:<sessionId>:<callId>:<kind> 作关联;不伪造缺失 ID,实时行允许重复。
  • 派发(dispatch)——每个 Assignment 形态的派发一行,记录派发身份:role(在写入边界归一化——去首尾空白并剥掉一个前导 @,故 @explore 与 explore 是同一 actor 而非两个角色)、planId、Assignment 的 Task N 标签记为 taskId、taskCategory 与判定。
  • 结算(settle)——仅为真实配对的完成记录。前台调用在 tools/post-execute 监听器结算;{ kind: 'background', jobId } 结果按注册表 jobId 配对(jobs 注册表键,绝非子会话 id),待 ctx.inject(['jobs']) → jobs.events.subscribe 发出终态 settled 事件时结算(completed → ok / killed → denied / failed → error,可用时附 durationMs)。每条配对结算都携带派发身份(Task N 标签仍是 taskId;taskRef 专用于注册表 job id,仅后台结算携带)外加可选 childId——前台 runId,或 catalog 关联已提供的后台子会话 id。可选 id 缺失或超长时只省略该字段:真实完成照常记录,id 绝不截断、绝不重键。未配对载荷不记录任何东西——绝不伪造结算。
  • subagent-link(非终态)——从父会话自有的 subagent/catalog 事件观测子会话 ID,并在派发的 apply 作用域调用窗口内关联。它记录身份而非完成,不伪造 outcome、verdict 或 paired;catalog 证据缺失时不产生 link 行。
  • 原生存储——事件、已接受来源身份、单调扫描下界、会话绑定与最新状态发射分别使用 dsh_ledger_events、dsh_accepted_identities、dsh_scan_bounds、dsh_session_bindings、dsh_status_emissions。不再有共享 JSONL tail/index/cursor/cache 权威、文件压缩、冻结或锁。旧文件字节保留为只读一次性 upgrade 输入/历史。

Workflow 行

同一账本从调用方父会话的原生日志中持久化的 tool-workflow/* 事件记录 workflow / ralph 扇出运行,而非内存中的 workflow/* emits。冷扫描与实时 session/event 监听器消费已核实的来源位置。事件追加、已接受身份/摘要检查与扫描下界推进在同一个原生事务内共同提交。

| tool-workflow/* 事件 | 账本行 | 字段 | | --- | --- | --- | | run-start | workflow-run | runId、name、agent?(承载的父会话 id) | | agent-start | workflow-agent | runId、seq(1 起始的成员序号)、label、phase?、childId | | run-end | workflow-run-end | runId、stopReason(completed / cancelled / error) |

tool-workflow/agent-end 是上游成员簿记,没有账本类型(成员 outcome 有意不持久化)。缺席的可选字段仍省略。既有展示字段限长与身份尺寸校验保留:超长展示值带标记截断,超长 runId / childId 整行跳过,绝不制造身份碰撞。读取窗口限制只是投影,不是存储截断。

第四种类型 workflow-verdict 由 workflow/ralph 闸门(而非本消费者)写入——每个被把关的调用一行(tool、workflow/objective、mode、判定 ok/advisory/denied/ask、违规 code)——见 Gates → Workflow / ralph gate。展示身份字段(workflow / objective)同样带 1024 字符上限;判定的违规码绝不猜测(P-a workflow.name.unknown vs P-b workflow.lease.uncovered)。

已接受来源回放。 已核实的原生 workflow 事件 ID 经数据库身份/摘要域只接受一次,覆盖冷热重叠与插件重启;同一已接受 ID 携不同字节会被拒绝而非覆写。扫描下界在已核实的流化身内单调推进。会话头部不可读时不接受事件,也不臆造化身。构造期带种子日志的会话在 session/created 上扫描;分叉从 inheritedEventCount 之后开始,保留父会话归属。实时 dispatch/settle/link/verdict 行允许重复,关联 ID 不使它们成为 accepted-operation 权威。缺失、staged、损坏或 schema 拒绝的 authority 如实保持 unavailable;真实的定址无记录仍与这些状态区分,并保留原生拒绝原因和恢复路径。

childId 关联 + 成员计数。 workflow-agent 行保留已发布成员的 childId(子会话 id);运行的展示 name 只存在于 workflow-run 行,面板为 agent/end 行经窗口查找解析(同一 runId——成员行本身不带名称)。面板把成员 COUNT 挂到 workflow-run 行(窗口内该 runId 的 workflow-agent 行数;窗口有界——被 ≤50 事件窗口截掉的成员如实缺席,绝不猜 0)。

深度咨询(观察时)。 agent-start 时,消费者经 sessions.get(childId) 解析子会话,当其 header.delegationDepth ≥ 2 时告警——每个运行至多一次(per-runId 闩锁),日志器 mstar/workflow-ledger。仅观察时,绝不是拒绝通道:子会话读取抛出只降级咨询本身,绝不影响行或运行。

零行为变更保证。 消费者仅观察:零门禁——每次读取与追加都 try/catch 包裹;账本写入失败绝不崩溃或改变 workflow 运行;会话读取抛出只记一条 warn 并继续。sessions 服务经 ctx.get('sessions') 结构化读取——对 @deepseek-ai/dsh-session 无运行时依赖。

挂载顺序说明。 消费者只在 apply 时 sessions 服务可用时激活——dsh-session 行必须先于 mstar 行挂载(标准 web profile 顺序即如此)。dsh-session 后于插件挂载(或缺失)的组合静默降级:一条 debug 日志(sessions service absent — workflow-ledger consumer disabled)且不记录任何行——绝不是错误,绝不是运行损坏。

面板可见性。 三种 workflow 行经现有事件行样式(无重设计)渲染在 事件记录(Event Log)tab 的 Agent 流转事件分区:摘要身份是运行 NAME(agent/end 行经窗口查找解析;回退 runId → 「未知」),详情体新增四个 workflow 字段——run-id / name / members / stop-reason(缺失 → 「—」)——expected/settled 席位渲染「—」(workflow 行不是角色派发——不存在 settle 配对,与 settle 行同先例)。未知 kind 字符串渲染为通用行(kind 原文、无 workflow 字段)——绝不丢弃、绝不猜测。catalog 摘要把 workflow 行计为独立 workflow 桶(模型行 by role: workflow N)——绝不并入派发角色计数。

Web 客户端插件(工作流面板)

本包为 dsh web profile 提供浏览器客户端半体,在已安装的 mstar bundle 行上被自动发现(package.json 的 dsh.client 声明 + exports["./client"] → dist/client.js——上游 web dsh.client 发现逻辑扫描 loader entries,并把每个客户端的 exports["./client"] 解析进 boot 图)——无需独立 profile 层或安装步骤(spec §6.1)。web 应用在 /plugins/@mstar-harness/dsh/client.js 提供该 bundle,并经 closure-factory loader 握手加载(window.__ModuleLoader__.load({ id, factory }))。

客户端入口经公开的两段式席位契约把面板注册为右 Sidebar 页签类型:ctx.sidebarRightTabs.register(definition)——id: '@mstar-harness/dsh'、kind: 'mstar-workflow'(页类型——无 patterns/canOpen/priority,按 kind 打开)、跟随 locale 的 title() thunk,以及恰好一个引导页 capsule(order: 20,描述 + MStar glyph 图标)——点选 capsule 会在该 pane 的槽位打开面板(替换引导页签、展开侧栏),再次点选聚焦既有页签(宿主页去重规则)——不自动打开、不重复表面。旧 conversation.view view-ring 页签已移除(迁移,而非第二表面):sidebar 页签取代会话区页签。面板体与其 chip 标题在同一 id 下注册为 keyed 席位(sidebar.right.pane.tab + sidebar.right.pane.tab.title;chip 为 glyph + 打开时捕获的标题——不跟随会话中途的语言切换)。tab.visible === false(列折叠或同 pane 其它页签激活)时面板体不渲染任何内容(无投影、无 DOM),选中分区存放在按页签记录键控的 entry slot store 中,因此能在 docked 面板体卸载后存活。文案来自 mstar-panel locale 命名空间:"晨星工作流"(zh)/ "Morning Star Workflow"(en)。

面板是最新 catalog 快照(取自宿主 /api/mstar/engineStatus 端点——刷新跟随拉取,不轮询)的纯渲染:窄列布局为绑定 sidebar pane 确定高度的单列 flex,恰好三个分区——分区导航(任务迭代 / 代理执行 / 事件记录,flex: none)、面板自有的唯一滚动主体([data-mstar-scroll]——面板内唯一 overflow-y 元素;任何元素都不横向滚动;data-mstar-graph 随其上)、钉住的 meta 小面板(版本 + harness 目录;永不滚动)。工作区状态摘要(计划 ≤5 时间倒序 + +N more、未决残留 findings ≤10 带 severity chip、策略 enforcement 首位 + push / worktree / control worktree、租约、知识、方向)以流内内容位于滚动主体末尾——固定 300px 兄弟列及其嵌套滚动器已删除——新鲜度 footer(last-updated HH:MM:SS + turn)收尾滚动主体。宿主 composer-overlay opt-in 不再需要(sidebar pane 体本就是确定高度盒),过时的视口媒体查询已删除:壳层携带 container-type: inline-size,宽度规则为容器查询——容器宽 480px 以下内距与分组间距收紧(300px 下限的紧凑节奏);≥720px 共享分组网格铺开为两列(repeat(auto-fit, minmax(280px, 1fr)))——这是任何宽度带来的唯一结构变化(一份 DOM、一棵树;无 JS 布局测量)。缺失字段显式降级为空态/最后已知态(muted,绝无橙色 warn 框);waiting 保留 muted hint;无 harness 时渲染居中未激活态卡片,检测到后自动呈现。

三个分区在唯一滚动主体内堆叠。任务迭代渲染迭代头部(未激活时为折叠摘要)+ 竖直 5 步 stepper(每步一行——徽标 · 相位 · chip · 预留 verdict 席位;保留四态 current / next / done / idle 状态机:current 之前的步骤投影为 done「已完成」,next 为唯一前向目标,idle 仅为 schema 余项;steering compass 为 status: active 时 Step 1 即当前步——无 PASS/FAIL 徽标——Step 5 永远不会是当前步)+ 分支面板(迭代 base / 目标 / spec 集成分支,仅激活时渲染)+ 计划板为五个竖排状态组(恒定顺序——Todo / InProgress / InReview / Done / 合并的「受阻/未知」/「Blocked / Unknown」列),每 data-kanban-column / data-kanban-arrow / data-kanban-count 锚点全保留;每组渲染行数以 PLAN_CAP 封顶,超限显示可点击「更多」/「收起」展开按钮(data-kanban-more)展开全量(投影保留全部 plan 行——封顶只是渲染关注点,绝不丢弃)——随后是项目 rollup。事件记录把两个分区(Agent 流转事件 / 违规记录)渲染为流内容——每条可展开原生 <details> 呈现完整 catalog 字段(缺失显示「—」,绝不捏造;workflow 行保留 name / 成员数 / stop-reason 字段),无分区自有滚动器。代理执行把 agents 渲染为竖直分组列表——绝对定位画布连同 SVG 连线层、卡片端口与指针 pan 已删除:两个 Phase 组恒定顺序,Phase 1(iteration-start——顺序完成的 Review & Edit 链:product-manager → architect → writing-specialist)在上,Phase 2(autonomous-execute——循环迭代 plans;其组标签标注当前 plan:投影 activePlanId(data-agent-group-plan),多个进行中 → +N more(data-agent-group-plan-more),无 → 灰字「无进行中 plan」(data-agent-group-no-plan))在下;每个 Phase 组竖排其 stage 组——sdd-implement 拆为上方 implementor 分区(flow 角色 fullstack-dev / fullstack-dev-2 / frontend-dev 按 flow 序,随后 on-demand 角色 ops-engineer / prompt-engineer,带虚线按需徽标)与下方 reviewer 分区(code-reviewer),general 桶下沉到最后一个 stage 组底部的 unknown 子桶、仅有成员时渲染;每个 stage 组把完整 14 角色 roster 渲染为全宽流行(flow row)(idle 行虚线 muted——roster 永不隐藏),带 role chip / 状态点 / ×N 计数 / 记录行(session id · 任务标签——辅助字段,绝不作标题),头部为 N 执行中 · M 待执行 摘要(data-agent-summary-*),三态图例以流内形式位于列表下方。行携带投影透明度分级:emphasis: 'current' | 'next' | 'off' | null——当前阶段角色 100% chrome 强度、后续阶段预期角色 75%、已过阶段 / 无阶段角色(on-demand、general)45%,null(无迭代 / transition 不可解析)不覆盖——恒为 chrome alpha 混合(--mstar-canvas-emphasis-* token;绝不整行 opacity,状态点与 running 辉光保持不透明)。已结算实体带独立绿色完成框 + 绿 ✓(data-agent-done="true"——圆角行体 success 边框 + 1px ring + 状态点绿 ✓,全强度 evidence 态)——仅当 emphasis ≠ 'off';off 档角色显示灰字圆点、绝不显示完成标记。代理执行页含零 <svg> 元素、零 data-agent-port / data-canvas-* 锚点、无 pan 变换。派发证据仍只投影当前迭代的 plans(steering compass iterationId 活跃时取之,否则经 catalog plans[].iterationRefs 推导最近迭代);可证明跨迭代的事件不产生实体——roster 常驻 idle 卡,无 plan / 未知 plan / 独立 plan 的派发绝不隐藏。状态诚实:advisory 不再终态——软执法派发落到配对 settle(有 settle 绿 ✓ 已完成、无 settle 显示执行中),denied 仍为终态,advisory verdict 仍在事件记录页呈现。迭代信息 Section 由任务迭代与代理执行两页共用——单一 IterationInfoSection 组件,两页渲染同一 view.iteration 块(摘要 + steps + 分支)。投影为纯函数 projectGraph(source)(schema 常量与 catalog 证据严格分离;永不 throw)。

依赖:面板客户端 bundle 不携带任何图库——@xyflow/react devDependency(此前构建期内联进 dist/client.js)随 react-flow 渲染层一并移除,唯一消费者是 @xyflow/react/dist/style.css 的 plain-.css text loader 也已删除(CLIENT_EXTERNALS 不变——react / react-dom 与 @deepseek-ai/dsh-client-* 平台模块保持外部)。构建脚本端到端断言移除成立:产物不得含 xyflow/reactflow 标记、@deepseek-ai/* 值导入为 0、无 import.meta / ESM 语句——web loader 以经典 <script> 执行插件 bundle,字面 import.meta 是 parse-time SyntaxError(zustand v4 的 import.meta.env 读取已在构建期 define 消除;见本迭代 install-verification guide §6)。当前 bundle 体积:145,159 B raw / 29,460 B gzip(以各迭代 install-verification guide 为重新测量 SSOT——react-flow 移除后缩至约 85 KB,代理执行页实体渲染落地后回升,透明度分级样式后再度增长)。

安装 / 验证(客户端半体与服务器半体走同一条 bundle 行安装):

cd <repo>/packages/dsh
bun run build               # dist/client.js(closure-factory CJS)+ dist/client.d.ts
# corepack 机器(仓库根声明 packageManager: bun):命令前加 COREPACK_ENABLE_PROJECT_SPEC=0
dsh plugin --profile web add <abs packages/dsh path>   # 同一 profile bundle 安装
dsh web                     # 启动 → 服务 /plugins/@mstar-harness/dsh/client.js

本地已验证(install-verification guide):boot 图包含客户端 entry(@mstar-harness/dsh 携声明的 inject 面)、/plugins/<id>/client.js 路由服务的正是构建产物(rev = 内容 sha1)、浏览器握手 materialize 出插件入口(inject + apply + CSS 注入,经典脚本语义)——见 panel-beautify 迭代的 install-verification.md guide(本地 harness root)。

Known Limitations(本迭代):迭代 stepper 的 Step 1(iteration-start)在 steering compass status: active(Phase 1 进行中——catalog compassStatus 字段)时为当前步,且不携带 PASS/FAIL 徽标(Phase 1 无 gate 判定);Step 5(merge-ready)永远不会是当前步——engine 相位门只评估 Phase 2→3→4(merge-ready 从不是 gate transition);仅当 Step 4(pr-delivery)为当前步时渲染 next,其余为 idle;当前步跟随 TTL 刷新的 compassStatus——会话中途 active→locked 翻转后最多落后一个 catalog 间隔(60 秒)(有界、已记录的陈旧;绝不给出错误判定);代理实体状态按精确配对派生(paired settle 携带的 (agent, role, planId, taskId) 标识精确配对到对应派发——QC tri N=3 并发下各卡各自结算;未配对派发保持 running,绝不捏造);无 steering compass 时的「当前迭代」过滤按 plan id(8 位日期前缀)+ doneAt 推导迭代——确定性、已记录的启发式,且只丢弃可证明跨迭代的事件);不回溯 resumed 长日志的历史行(该行按变更发射、而非每 turn 首步:resumed 会话在 app 重启后的首个组合步骤会再次显示锚点——digest 在内存中——此后仅在行变化时才显示);sidebar chip 标题在打开时捕获(会话中途切换语言不会翻转它——为与一方 chip 的 glyph 形态对齐而接受);列折叠或同 pane 其它页签激活时(tab.visible === false)面板体不渲染任何内容(无投影、无 DOM、隐藏期零快照开销)。面板验收为双轨:in-loop 浏览器 harness 验证(对重建 bundle)+ 用户重启后 GUI 终验——重跑步骤见 install-verification guide §8。

Development

命令(在 packages/dsh 下执行):覆盖率门禁为 src/ 逐文件 100%(dsh 测试策略);构建命令把 src 条目 bun 打包进 dist/(内联 engine 与 schemastery;@deepseek-ai/cordis 与运行时 seam 导入——@deepseek-ai/dsh-skill-filesystem、@deepseek-ai/dsh-tools(defineTool)、@deepseek-ai/dsh-llm——保持外部),运行 build-client(scripts/build-client-bundle.ts——按 spec §6.2 产出的 closure-factory CJS 浏览器 bundle dist/client.js)并输出 tsc 声明。

bun test --coverage
bunx tsc --noEmit
bun run build

bun run test 会先构建客户端 bundle(pretest 钩子执行 build-client——manifest-contract 套件断言 dist/client.js 存在);fresh checkout 下直接 bun test 会以 bun run build 提示失败而非裸断言。

开发期 seam 表面(类型、事件形态、运行时)是来自公开 npm registry(registry.npmjs.org,无需根 .npmrc)的真实 @deepseek-ai/dsh-* 包(bun 默认自动安装 peer)。

Model Experience

Request surface and condition

What the model sees

组合步骤在该行被发射时携带一条 mstar-engine catalog 用户消息(<mstar_engine_status> 块——见 Engine-status catalog 一节):首次发射与变化时发射,绝不仅因 turn 开始,未解析到 {HARNESS_DIR} 的工作区则完全没有。该块是 payload 的投影,故其中不重复版本 / harness 目录 / enforcement 水印——常驻 system prompt 已携带它们(未提供 system-prompt 服务的组合则由该行自行携带这三行)。闸门决策额外添加:派发否决以注册表物化的 PreToolDecision { kind: 'deny', reason } 错误呈现;状态闸门以 mstar/status-gate 咨询呈现(告警放行、hard 修复逃生或降级放行);派发闸门以 mstar/dispatch-gate 咨询呈现(告警放行或降级);技能 lint 闸门以 mstar/skill-lint 咨询呈现(告警放行、hard 修复逃生或降级放行)。每条模型可见的行都能从会话日志重建(catalog 形态 source + 咨询事件)。

Leaf 交付纪律(PM 2026-08-12):leaf 子代理在最终(closing)消息中交回完成报告,不通过 report 工具交付——dsh tool-subagent-report 默认 reportDelivery: quiet 会把报告投递到父代理的 next-step 队列,父代理 turn 结束(无 step 边界)后报告会滞留队列。closing 消息是可靠交付通道;report 保留给「中途发现、需要父代理改变下一步」的发现(SSOT:skills/mstar-host/references/dsh.md → PM dispatch)。

Token effect

catalog 在该行被发射时追加一条固定、稳定的用户消息(小的常量块——不随会话长度增长:按会话的发射摘要会抑制未变化的行,故长 idle 会话不堆积副本)。否决与咨询文本仅在闸门触发时存在。

KV Cache effect

catalog 行在委托之后追加到组合步骤消息的末尾——请求前缀(system prompt 与先前消息)不受影响,因此插件既不创建也不失效前缀缓存状态;已发射的行在未变化的工作区上逐字节相同,而未变化的行根本不会再次追加(变更驱动发射)。工具错误文本随违规变化,但从不参与请求前缀。

Known Limitations and Deferred Work

  • 开发期 seam 从 npm registry 解析 —— @deepseek-ai/dsh-* 各 seam 仅为 peerDependencies(运行时由宿主提供);开发期 typecheck/测试/构建从公开 npm registry(registry.npmjs.org,无需根 .npmrc)解析(bun 默认自动安装 peer)。全部运行时 seam 导入在构建时外部化(--external @deepseek-ai/cordis / @deepseek-ai/dsh-skill-filesystem / @deepseek-ai/dsh-tools / @deepseek-ai/dsh-llm——发布的 dist/ 导入它们而非内联占位代码);闸门通过真实注册表/fs 工具执行的同一 ctx.waterfall 派发来验证。本包套件直接运行来自 npm registry 的真实 seam 包——不再有提交的 peer-stubs/ 占位、不再有本地 link farm。
  • 反递归绑定是根会话身份,永不被继承 —— dsh 在工具执行上下文上不暴露每 agent 角色,故 dispatchBinding 声明派发方根会话的角色(可在插件配置页实时编辑);未设置时根会话读作 project-manager。子会话(以及闸门读不到会话的路径)无论该字段写什么都保持空并 fail-closed,因此叶子无法靠配置把自己塞进协调者席位。Execute as 不同的 Assignment 无法被识别为自我递归,多角色派发方需要按实例拆分插件,而非根会话的协调者无法用该字段承载(该字段只对根会话调用方读取)。读不到会话的路径(无 exec 的 beforeDispatch 宿主钩子)只能由不提供调用会话的宿主钩子触达——本仓库内只有测试驱动它;而每一条生产派发路径都经 tools/pre-execute 监听器携带调用方 agent,故该拒绝在生产派发路径上从不触发。接入此类钩子的嵌入方必须在派发前解析出会话,该字段不是它的恢复手段。根会话判定信任 session.header.parentSession:不为子会话标记该字段的宿主 provider 会被读作根会话,从而获得协调者身份。
  • 租约闸门有意与 opencode 分叉 —— opencode 的 beforeDispatch 不运行租约检查;dsh 租约闸门是新增的(lease.dispatch.* 码),且仅对可写 SDD/InProgress 派发触发,故对齐覆盖字段集而非租约面。
  • 已采纳 engine 共享组合 —— 派发闸门核心即 engine 的单一 composeDispatchGate(与 opencode/omp/CLI 对齐,字段/分支/反递归违规码按构造即相同),compass frontmatter 解析器即 engine 的共享 parseCompassFrontmatter(本地 dsh 镜像与 CLI 副本均已删除——不再有可漂移的分叉)。两者都运行在 dsh 头区域切片上;租约 + worktree L1/L2 检查仍为叠加上去的 dsh 侧扩展。
  • engine 单一版本钉定 —— @mstar-harness/engine 为精确 2.1.1 devDependency,构建时打入 dist/(绝非运行时依赖);readHarnessVersion() 读取 bundle 旁的 dsh 包清单 —— 2.1.1,按单一版本不变量与钉定的 engine 相等。
  • Schemastery 空数组物化 —— 省略的可选 ARRAY Config 键会物化为 [];派发键通过 .default(undefined) 保留省略语义,未来任何可选数组键都必须同样处理。
  • 载荷边界 —— 派发闸门校验委派载荷(Assignment 文本),而非子代理的运行时行为;如需向模型可见的子活动建面,事后经 subagent/start 观察仍为可选项。
  • 状态闸门因 seam 设计而内容盲——fs/write-intent/fs/edit-intent 瀑布链只携带 (target, actor),从不携带写入内容,因此首次把合法 status.json 写坏的写入在两种模式下都会通过(闸门只校验写入前的磁盘文档)。hard 模式因此从不否决状态写入:对已非法文档按修复逃生放行(error 级咨询,hard: true, repair: true),让修复性写入能落地。恢复路径:就地修复文档(闸门允许)或删除 status.json 让 harness 重建;hard 部署应监控 repair: true 咨询。
  • 缺失 status.json 的租约行为——sdd 可写派发遇到缺失状态文件会发出 lease.dispatch.unverifiable(告警下 advisory,hard 下 deny);非 SDD 派发无租约义务,保持静默降级放行。
  • 闸门匹配跟随 displayPath——状态闸门按 fs target 的解析后 displayPath 匹配。后端报告工作区相对路径、harness 目录为符号链接、或远程/URI target 时永不匹配,闸门对其惰性(无误报);受守护的 harness 写入请使用绝对本地路径。
  • design-md seam 作用域为全局 basename 匹配——isSeamTarget('design-md') 匹配文件系统上任意 DESIGN.md / DESIGN.dark.md,无论解析出的 {HARNESS_DIR} / 仓库根是什么。因此对不遵循 mstar token 格式的外部项目 DESIGN.md 的写入,在 hard 模式下会在 harness 之外记录 error 级修复逃生咨询(hard: true, repair: true)——一个嘈杂的误报面(写入从不被阻断)。有意为之(「工件即文件本身,无论设计位于何处」);在 harness 目录可解析时把作用域收窄到仓库根是可能的后续项。
  • audit seam 作用域需要有可解析的 {HARNESS_DIR} 才够收敛——作用域是解析出的 {REVIEW_DIR}({HARNESS_DIR}/reviews/,感知 .mstarc review_dir)下的 markdown;当 harness 目录完全无法解析时(事件不携带会话工作区、也未配置 harnessDir),该 seam 退化为匹配路径中的 reviews 段,因此无关目录树的 reviews/**.md 在写入时也会被凭据扫描。仅咨询、从不阻断,且凭据扫描就是该 seam 的全部契约——评审产物不再携带计划 Status 块。
  • <root>/mstar-roles/SKILL.md 上 skill-lint × roles seam 双重触发——当某个已配置技能根包含 mstar-roles 目录(开发期的仓库根镜像情形,以及发布形态的打包镜像)时,对 mstar-roles/SKILL.md 的一次写入会同时触发技能撰写 lint 闸门与 roles seam 闸门(hard 下两条咨询 / 两条修复逃生日志)。两个校验器都合理适用——双重 lint 仅为咨询,并非正确性破坏;「作用域互不重叠」的性质只在四个 seam 之间成立,不跨技能闸门。
  • 内容盲的 skill-lint 盲区——fs/write-intent 槽位只携带 (target, actor):首次创建的传入内容不被 lint,合法→非法覆盖在监听器路径上无法检出(它只 lint 写入前的磁盘文档)。告警/hard 咨询只呈现已存在的磁盘违规——与状态闸门同类限制。
  • 显式相对 bundledSkillDir 覆盖锚定 cwd——skill-filesystem 对相对打包根按普通 join() 语义解析到 dsh 进程 cwd。插件的默认打包根是包内自带的 harness-skills/ 镜像,按包相对路径解析(非 cwd 锚定——任意启动 cwd 都可用);只有显式的相对覆盖继承 cwd 锚定,因此覆盖默认的部署应在 profile 层传绝对路径(见 bundle/README.md)。
  • Bundled 镜像是构建期同步——harness-skills/ + harness-commands/ 由 bundle-assets 在构建时产出(仓库根 skills/ + commands/ 镜像;gitignore)。未跑 bundle-assets 的检出不挂载 bundled 技能、不注册命令(默认挂载惰性,而非报错)。
  • profile-bundle 安装到 web profile:registry 与 local checkout——dsh plugin --profile web add @mstar-harness/dsh(registry)与 add <本地检出> 为受支持途径,均走同一 pnpm + reconcile 机制(reconcile 步骤把 @mstar-harness/dsh 并入 dsh.profile.bundles)。local checkout 需要先执行 bun run build——本包没有 prepare 脚本(monorepo 显式构建各包),未构建的检出会装入空的 dist/。
  • lintSkillWrite 类型化否决尚未接入生产——传入文档分支的 hard 否决(SkillLintVetoError,码 skill-lint.veto)已导出并测试覆盖,但尚无生产调用方:engine HostAdapter 没有携带内容的技能写入钩子(只有 beforeStatusWrite/beforeDispatch/beforeMerge),且 fs intent 槽位内容盲。接线随未来携带内容的钩子落地;在此之前监听器路径只通过修复逃生咨询执行(从不否决)。
  • CLI 宿主信号列表与 engine 联合一致——CLI 的 hostSignals 列表(packages/commands/src/families/local.ts)接受与 engine ToolSignal 联合相同的 token,包括 subagent 与 Agent Teams 载体 spawn_teammate / team_task_create;因此 mstar host detect --signals subagent 解析为 dsh 而不再被拒绝,未知 token 仍返回 usage 信封。
  • 入口是 src/gates/* 之上的模块索引——src/index.ts 提供 gate 模块的具名导出,保留插件 manifest、单一 cordis augmentation 点、命令注册与 apply() 启动接线,不再冻结导出数量。入口必须仅使用具名导出,因为存在 default export 时 dsh Loader 会丢弃 namespace metadata;service 导出同时向消费者提供 ctx.dshMstar 的类型 augmentation。
  • engine dsh 行待上游化——engine host.ts 的 dsh 改动(DetectResult、ToolSignal、resolveSkillRoot)位于 mstar-workflow engine 镜像,计划经用户授权的上游 PR 合入 mstar-harness;mstar-host 技能镜像(§ Detect / § Resolve loaded skill root / references/dsh.md)随之一并更新。
  • 迭代 stepper:Step 1 为 compass 驱动,Step 5 为 schema 驱动——工作流面板的 Step 1(iteration-start)在 steering compass status: active(Phase 1 进行中)时为当前步(无 gate 判定 → 无 PASS/FAIL 徽标);Step 5(merge-ready)是 engine 闸门永不点亮为当前的 schema 常量(transition 只覆盖 Phase 2→3→4,merge-ready 从不是 gate transition);仅当 Step 4 为当前步时作为 next 渲染,其余为 idle——已记录于迭代 guide,非缺陷。完整面板限制清单见 Web 客户端插件一节。
  • dsh-llm-fallbacks 为可选的开发期依赖——dsh 原生覆盖 subagent 定制,fallbacks 因此严格可选:src/ 对其零导入(运行时与类型——被消费面是本地结构镜像 fallbacks-structural.ts,由探测的 exact-keys 漂移闸门 + typecheck:tests 的 real → view 可赋值检查保持同步),package.json 仅在 devDependencies 携带它(类型镜像 + 真实包测试 harness),dist/ 无导入也无类型引用(仅 1 处命名该包的字符串字面量——探测的 loader 条目匹配;建议日志写作 fallbacks)。激活是单独显式安装(双命令契约),绝不传递;不再有 --external 护栏——未来的值导入必须按设计重新加入运行时依赖。
  • 本批次未交付角色→模型覆盖——把角色路由到 fallbacks model(或经 fallbacks 规则路由 persona)需要改写启动请求上的子会话 agentOptions,但启动请求选项由调用方控制(tool-subagent 自己的 Config;调用参数为 cwd/description/prompt 以及可选的 preset/route 字段,且深度冻结)。等待上游 fallbacks-explicit-role-tool 或 N-B1 systemPrompt 采纳(roadmap §10.4)。
  • 角色身份通过 preset 选择交付——角色匹配的 startActivation 设置 SubagentStartRequest.agentPreset,由选中的 preset 组合子代理(persona 经 @deepseek-ai/dsh-persona、工具、技能);该选择记入子会话日志并在 resume 时重放。dsh 0.2.1 移除了逐次启动的 persona 槽与 start/startContinuable 对,因此不再存在「只合入 persona」的路径,也不再有 mstar:role-persona 系统提示段:部署方为每个角色声明一份完整 preset。
  • 角色-preset 选择与 fallbacks 无关——dsh-llm-fallbacks 只路由 LLM 失败;角色身份从不依赖它。未挂载 → 仍以单条交付 debug 日志选中同一 preset。不支持独立选择的提供者(capabilities.agentPreset 为 false,或 inheritsParentContext)与未挂载 agentPresets registry 的组合会跳过选择并记录恰一条 contained debug 日志——通道绝不因此使 start 失败。
  • fork 门禁仅默认开启;显式 dispatchTools 可省略 subagent_fork——自定义 dispatchTools 列表整体覆盖默认(既有重命名模式),因此自行声明列表的部署须包含 subagent_fork 才能继续门禁 fork 派发。
  • preset 的 persona 文本由 dsh 渲染——@deepseek-ai/dsh-persona 提供 deployment:persona-prefix/-suffix 模板,dsh 的严格 {{variable}} 插值对与后文 }} 配对的 {{(未知/畸形/未定义引用)在子会话提示组装时直接抛错。该约束如今属于 preset 作者(mstar 只原样传递 id);打包的 harness-agents/ persona 现在只喂给 fallbacks seeds 面,那里对含风险的默认值是告警并跳过、绝不抛错。
  • fallbacks HMR 重挂后的 seeds 再收敛受 seeded-only preservation 设计边界限制——seed registry 是每次 apply 的内存态,纤程切换(HMR / 设置编辑)会丢弃它并让双方 declarer 从头重放。mstar re-declare 只合并保留已 seeded 的 id(seeded-only,设计使然),因此在 preset-last 提交顺序下,preset 行的 seeded 注记不会被 re-declare 恢复——它们在下一次 fallbacks apply 时恢复(上游 preset 自声明重新播种)。llm-fallbacks 服务消失时 advisory 一次性 latch 会重新武装(inject teardown),因此下一个决策点会重新收敛 mstar 侧;preset 侧是 seeded-only preservation 设计的有文档说明的暂时现象。
  • 咨询跳过原因 no-persona 亦涵盖 extraction 失败——在 extraction 期被拒绝的镜像默认(例如含 {{...}} 插值风险)会在合并的 declare-outcome 行中以 no-persona 呈现(extraction 在风险门之前就返回无可用的 persona);逐 id 的 extraction 诊断保留在 debug 通道(mstar/fallbacks-advisory / mstar/fallbacks-seeds)。