dsh-workflow-kit
Manifest valid★ 2DeepSeek Harness workflow kit: 5 agent presets + 18 skills + routing table
dsh-workflow-kit
让 AI 代理真正"会干活",而不只是"会安排"。 DeepSeek Harness 的协作方法论套件:2 个入口模式 + 可插拔模式库 + 8 个方法论 skill + 任务书模板与判决契约。
它是什么
主力方向:工程编码与多代理协作。
本套件不提供任何具体领域的知识(不教你怎么画图、怎么写论文、怎么检索文献)。 它提供的是代理怎么工作这件事本身:
- 什么时候该自己干,什么时候该派出去
- 怎么判断"做完了"是真的做完了
- 怎么让多个代理协作而不互相拖累
- 怎么让上下文保持干净,不越用越糊涂
一个关键的职责划分
很多套件按「做什么行业」切分(代码档、文献档、绘图档、写作档)。这是混淆:
| 层 | 职责 | 例子 |
|---|---|---|
| 模式(本套件提供) | 代理怎么工作:判据、失败模式、验证方式 | 从零开始 / 存量深化 |
| prompt 层(你的任务) | 拆任务、写任务书、决定每个子任务需要什么领域能力 | "这个子任务要画火山图" |
| 领域 skill(按需装) | 具体领域知识 | sci-figure-kit / literature-review-skill |
领域是任务的属性,不是代理的身份。
一篇论文的任务里,可能同时要:先调研 → 再分析数据 → 再画图 → 再写正文。 如果按领域切档,一个任务要来回切四次档,反而割裂。 正确的做法是:模式固定,领域能力随任务流动。
目标:自我审查 + 上下文洁净。
| 目标 | 含义 |
|---|---|
| 自我审查 | 每个"完成"都能被证伪,不靠代理自己说"我做好了" |
| 上下文洁净 | 判据常驻但极短,知识按需加载,细节不回流 |
用了会怎样
如果你用默认预设
| 现象 | 根因 |
|---|---|
| 改了代码说"应该可以了",但没跑 | persona 没有"能跑才算完成"这条硬判据 |
| 修好 A 结果 B 坏了 | 改签名前没查调用方 |
| 顺手重构了无关代码,diff 三百行 | 没有"最小改动"约束 |
| 长任务里自己单线程硬扛,上下文爆掉 | 没有委派判断,或者判断太宽导致无效委派 |
| 派了子代理,回一句"已完成",你也不知道对不对 | 子代理只能回自然语言,没有证据契约 |
| 换会话/压缩后忘了做到哪 | 进度只在上下文里,没落到文件 |
装了本套件之后
| 变化 | 机制 |
|---|---|
| 声称完成必须附命令输出 | verification-before-completion 铁律:没当场跑过不许说通过 |
| 改代码前先查调用方 | brownfield 模式判据第 4 条 |
| 一次只做一件事,分开验证 | 两种模式都有的判据 |
| 长任务自动拆解分发 | brownfield 强委派 + subagent-driven-development |
| 子代理只回三行证据 | 改了什么 / 凭什么说对 / 最不确定的一点 |
| 进度写 ledger 文件,不怕压缩 | subagent-driven-development 的恢复机制 |
| 能看见子代理在干什么 | Agent Teams 的 Web 任务板与队友导航 |
| 上下文增长变慢 | 判据极短 + 细节走文件指针 |
原理
一、判据常驻,规则不常驻
传统做法是往 system prompt 里堆规则:写 200 行操作手册教代理"该怎么做"。 问题是——规则改变流程,判据改变否决。
驳回力测试:把一条知识从代理脑子里删掉。 如果它仍能否决同样多的错误产出 → 这条是杂质,该外置。 如果它丧失了某种否决能力 → 必须常驻。
按这个标准,绝大多数"操作步骤"都该外置。真正需要常驻的只有: 验收判据、失败模式、钩子表、通道纪律、红线——合计不超过 60 行。
二、上下文分层
| 层 | 装什么 | 量级 | 加载时机 |
|---|---|---|---|
| L0 常驻 | 判据 · 失败模式 · 通道纪律 | ≤60 行 | 每轮都在 |
| L1 路径知识 | 岔路口集合、决策点 | 5–10 行 | 需要时 read |
| L2 执行细节 | 命令、语法、参数 | 0 | 全部交给子代理 |
| L3 产物与证据 | 日志、diff、报告 | 只留指针 | 按路径取 |
关键:L2 可以完全外包,L1 不能。 因为"接收报告的带宽由接收方的知识决定"——不懂路径就消费不了路径级报告, 只能要求"说简单点",于是永远不懂。这是唯一会越外包越糟的一层。
三、跨层只走文件,不走对话
对话里的每一句话都会在后续所有轮次重复计费。所以:
子代理 → 写产物文件 + verdict.json
→ 回三行摘要(改了什么 / 凭什么说对 / 最不确定的一点)
主代理 → 只读判决,不读过程
主代理需要细节时,按路径 read 或 grep,而不是让子代理转述。
verdict.json 的格式见 checks/verdict.schema.json,用 checks/verify.py 校验:
python checks/verify.py tasks/<id>/verdict.json
退出码:0 通过 / 1 判决不合法 / 2 打回。
verdict 缺失视为 fail,不是 pass —— 沉默绝不等于通过。
四、判定塌缩成默认动作
"该不该派子代理"如果写成规则,每次都要检索匹配权衡,本身就是上下文成本。所以塌缩成默认动作:
| 情况 | 动作 |
|---|---|
| 两分钟内自己看清的 | 自己做 |
| 明显多文件并行、互不依赖 | 派 |
| 中间地带 | 默认自己做第一步(做完性质自然暴露,判定变成已知事实) |
一条硬边界:探索可以委派,交付必须可验收。 直接禁止最典型的退化动作——"我不懂,所以我派出去"。
主要内容
两个入口模式
预设只回答**「怎么工作」,不回答「做什么领域的事」**。在 GUI 里选一个即可。
brownfield —— 存量深化
适用:目标处已经有能跑的代码 / 完整的实验设计 / 成型的文献集,而你还没完全掌握它。
七条常驻判据:
| 判据 | 什么意思 |
|---|---|
| 先摸基线,再动手 | 不读清结构就改 = 瞎改。第一动作是调研,不是改 |
| 最小改动 | 只改与目标相关的。不顺手重构、不调格式、不重命名无关变量 |
| 先查调用方再改签名 | 改函数签名/返回值/数据结构前,先搜谁在用它 |
| 先复现再修 | 修 bug 前先写能稳定复现的最小用例。没有复现的修复等于猜 |
| 尊重既有约定 | 命名、分层、错误处理跟着项目走。一致性优于局部最优 |
| 能跑才算完成 | 改完必须实际执行原有测试/构建,证据是命令输出 |
| 一次一件事 | 多个不相关的修改分开做、分次验证 |
委派节奏:强委派。三条默认动作 + 三条硬规则,见下文「怎么决定派不派」。
greenfield —— 从零开始
适用:目标目录确实是空的,或只有无关文件;没有可复用的既有约定。
六条常驻判据:
| 判据 | 什么意思 |
|---|---|
| 先定接口,再写实现 | 函数签名、数据结构、模块边界先确定,再填内部逻辑 |
| 最小可行,先跑通再加 | 第一版只求端到端能跑,哪怕功能很少 |
| 快速验证假设 | 库能不能用、API 长什么样,用最小实验验证,别写完一整套才发现走不通 |
| 不过度设计 | YAGNI。第一次只需一个实现时,不造工厂、不留扩展点 |
| 一次一件事 | 多个不相关的模块分开做、分次验证 |
| 能跑才算完成 | 写完必须实际执行,证据是命令输出 |
委派节奏:轻委派。接口已定、边界清楚的活可以派;需要决策的自己留。
判定顺序
先查 brownfield,不匹配再看 greenfield。
因为把存量项目当新项目做(重复造轮子、破坏既有约定、改坏调用方)的代价, 远高于把新项目多花几分钟确认"确实是空的"。
模式即插件(可扩展)
模式不是写死在代码里的。modes/ 目录下每个 .md 就是一个模式:
modes/
├── MODES.md ← 路由表:什么情况用哪个模式
├── brownfield.md
├── greenfield.md
└── <你自加的>.md ← 加文件 + 在 MODES.md 加一行,立即生效
两个入口预设的 persona 都写着:先 read MODES.md 判断实际模式,若与入口不同则按该模式执行。
所以即使用户选了 brownfield 进去,发现其实是从零开始,代理会自动切到 greenfield 的判据。
扩展方式:新建 modes/my-mode.md,写清适用场景、判据、失败模式、委派策略、完成标准,
在 MODES.md 加一行即可。不用改代码、不用重装。
写模式的纪律见
modes/MODES.md:判据必须能改变否决行为;不写流程步骤;每模式 ≤80 行。
领域能力不进预设
文献、绘图、写作这些领域能力按需加载,不绑定到预设:
skills/ROUTING.md—— 按任务信号查该用哪个 skill- 派子代理时在任务书里显式指定(如"本任务用
sci-figure-kit")
这样同一个任务可以先调研、再画图、再写正文,不用来回切档。
八个 skill
每个 skill 只解决一类问题。什么时候加载它,比它写了什么更重要。
协作流程(来自 superpowers,MIT)
| skill | 什么时候用 | 产出 |
|---|---|---|
dispatching-parallel-agents | 有 2 个以上互不依赖的任务,且没有共享状态 | 一批并行子代理,各自自包含任务书 |
subagent-driven-development | 有写好的计划,要逐任务执行 | 每任务一个 fresh 执行者 + 任务级审查;进度写 ledger 文件 |
verification-before-completion | 即将说"完成 / 修好 / 通过"之前 | 命令与输出。没有输出就不算完成 |
systematic-debugging | 遇到 bug、测试失败、行为异常,还没定位到根因 | 四阶段定位:根因 → 模式 → 假设 → 实现 |
writing-plans | 需求明确但步骤多,直接开工会漏 | 一份带验收条件的计划文件 |
executing-plans | 计划已经写好,要在新会话里执行 | 带检查点的逐步执行 |
自建
| skill | 什么时候用 | 产出 |
|---|---|---|
baseline-survey | 接手一个你不熟、但已经有东西在跑的项目 | survey/{structure,baseline,hotspots,risks}.md,主代理只读 ≤15 行摘要 |
kit-selftest | 想确认包内 skill provider 是否正常工作 | 能加载即证明自包含生效(该 skill 只存在于包内) |
加载 skill 之前先看
skills/ROUTING.md。它有一列「什么时候不要加载」—— 否决比匹配更省事。例如任务小到一次工具调用就能完成时,不该加载writing-plans。
怎么决定派不派
这是本套件最核心的判据,也是最容易被做错的地方。
三条默认动作
两分钟内能自己看清的 → 自己做(这同时就是"看证据"的动作)
中间地带 → 默认自己做第一步;做完性质自然暴露,判定变成已知事实
明显多文件、多阶段、可并行的 → 派
判据不是任务大小,是"我是否已经理解到能验收"。
第二条是关键:先做一步不是浪费时间。它把"该不该派"从需要权衡的判断, 变成已知事实——你做完第一步,任务的性质自己就暴露了。
三条硬规则
-
探索可以委派,交付必须可验收 派出去获取知识("我不懂,你去搞清楚")→ 允许,产出是信息。 派出去产生结果("你去把它做出来")→ 必须事先能验收,否则不许派。 这条禁止最典型的退化动作:"我不懂,所以我派出去"。
-
并发派,不要造中间层 子任务互相独立时,自己一次性并发派出去。 (技术原因:
spawn_teammate只允许 Team Lead 调用,被派出去的调度代理拿不到派发能力。) -
默认新建子代理 只有三条同时满足才复用已有的:
- 任务同质:与它上次做的属于同一类工作
- 结论要用:你需要它记得上次的结论,否则重复劳动
- 状态未过期:上次的调研结论、读过的文件,对新任务仍有效
不同质就新建。复用不同质的任务是负收益——它带着旧上下文看新问题,更容易套错模板。
派发前先建任务板
team_task_create(...) ← 每个子任务一条,写明 write_scopes
team_task_list(ready: true) ← 返回的就是"现在能并发几路"
ready 的行数就是并发宽度,不需要自己推导。
依赖关系用 blocked_by 声明,不要用判断。
任务书模板
子代理不继承你的上下文,所以任务书必须自包含。模板在 templates/brief.md:
| 字段 | 写什么 |
|---|---|
| 目标 | 可验收的最终状态。写"什么算做完",不写"做什么步骤" |
| 输入 | 路径 + 现状 + 参考文档指针 |
| 领域能力 | 本任务要用哪个 skill,点名,不写"按需选择" |
| 约束 | 可写路径 / 禁止路径 / 风格要求 |
| 验收条件 | 能跑的命令 + 期望输出 |
| 期望产出 | 产物路径 + 三行证据 |
三条纪律:
- 验收条件必须可执行。写不出命令 → 说明这活还不该派,或验收标准要重定。
- 禁止范围要具体到路径。"别乱改"不是约束,"不许改
src/auth/**"才是。 - 领域能力必须点名。写"按需选择"等于没写。
子代理协作基础设施
随包启用 DSH 官方的 Agent Teams 三件套:
| 组件 | 提供 |
|---|---|
dsh-experimental-agent-team | Host:名册 + 直接 peer messaging + 共享任务 DAG |
dsh-experimental-tool-agent-team | 模型侧团队工具(spawn_teammate / send_message / team_task_*) |
dsh-experimental-client-ui-agent-team | Web 任务板 + teammate 导航 |
配合两种模式使用:子代理可以互相沟通、任务状态可视、用完的队友保留能力可复用。
派子代理时可指定它用哪个预设(agentPreset 参数),为将来扩展能力预设留了口子。
三种派发工具,别混用:
| 工具 | 用途 | 限制 |
|---|---|---|
subagent | 独立上下文、干净起点(默认) | provider 名是 spawn |
subagent_fork | 继承主线决策历史 | provider 名是 fork;不能另选预设 |
spawn_teammate | 具名、可复用、能横向沟通的队友 | 仅 Team Lead 可调 |
spawn/fork是 provider 名,不是工具名。调错会失败, 而失败后最常见的退化动作就是"算了我自己干"。
什么时候该用
强烈建议用
- 改存量代码:需要"改完真跑一遍"和"别扩大 diff" →
brownfield - 修 bug:需要先复现再修,而不是猜 →
brownfield - 接手不熟的项目:先用
baseline-survey摸清基线 →brownfield - 从零搭新东西:需要先定接口、不过度设计 →
greenfield - 长任务:多步骤、要迭代、上下文会爆 →
brownfield(强委派) - 多线程推进:几个互不依赖的模块要同时做 →
brownfield+dispatching-parallel-agents - 不想被"已完成"糊弄:需要证据而不是断言 → 两者皆可
不必用
- 一次性问答、查资料
- 纯文本整理,不涉及执行验证
- 任务小到一次工具调用就能完成
安装
git clone git@github.com:Ke-wood/dsh-workflow-kit.git ~/dsh-workflow-kit
在 DSH 里执行 plugin_manager,action: install_bundle,target 填该目录绝对路径。
skills 会由 index.js 自动注册(ctx.skills.registerProvider() 扫描包内 skills/),
无需手动复制或改配置。
验证
# 在 DSH 里
/skill kit-selftest
能加载即说明包内 skill provider 生效(该 skill 只存在于包内,不在 ~/.dsh/skills)。
快速上手
- 选入口:GUI 模式选择里选
brownfield(存量项目)或greenfield(从零开始) —— 选错也没关系,代理会读MODES.md自行纠正 - 让它先看:存量项目会先跑
baseline-survey摸清结构 - 声明完成时要求证据:它会自动走
verification-before-completion - 长任务它会自己拆:
brownfield模式强委派,会把活派出去、收三行证据回来 - 看进度:侧边栏 Fleet 视图 / 任务板
加自己的模式
# 1. 写模式文档
vim ~/dsh-workflow-kit/modes/my-mode.md
# 2. 在 MODES.md 加一行
# | `my-mode` | 什么时候用 | `modes/my-mode.md` |
不用改代码、不用重装,下次对话即生效。
建议在 ~/.dsh/AGENTS.md 加一行,让 skill 路由生效:
- 选 skill / 不确定用哪个 → 读 <kit>/skills/ROUTING.md
配合使用的领域包
本包只管方法论。具体领域能力按项目另行安装,装好后预设的钩子表会自动识别。
| 领域 | 项目 |
|---|---|
| 科研绘图(figkit / R / omicverse,15+ 绘图 mod) | sci-figure-kit |
| 中文文献综述全链路 | literature-review-skill |
| Nature 系写作 / 润色 / 引用 / 精读 | nature-skills |
| 每日论文抓取与笔记 | dailypaper-skills |
# 装到用户 skill 目录即可
cp -r <项目>/skills/* ~/.dsh/skills/
注意:skill 目录名须匹配
^[a-z0-9]+(?:-[a-z0-9]+)*$。中文名会被静默跳过, 需改为英文名并同步SKILL.md的name字段。
设计原则
- 判据常驻,规则外置 —— 能被删掉还不影响否决力的,都是杂质。
- 能写成断言的就别靠人审 —— 但写不成断言的不等于不能委托,而是分三档: 机器能判的交给脚本;需要判断力的交给独立审查者(fresh 上下文); 确实只能由主代理判的,当场把它沉淀成判据脚本。
- 探索可委派,交付必须可验收。
- 格式成本落在信息产生方 —— 子代理写结构化产物,主代理只读判决。
- 可执行验证优于模型自省 —— 测试 / diff / schema 校验 > "我检查过了"。
- 不重复造轮子 —— 先用已有 skill 和工具。
已知限制
试过但不适用的做法
下面这些做法在直觉上都合适,实际用起来不成立。写在这里是为了省你一次试错。
| 做法 | 为什么不适用 |
|---|---|
| 按领域切预设(代码档 / 文献档 / 绘图档 / 写作档) | 领域是任务的属性,不是代理的身份。一个论文任务要调研 → 分析 → 画图 → 写正文,按领域切档要来回切四次,反而割裂 |
| 用"起一个调度代理,让它再派执行者"来分层 | 调度代理拿不到派发能力(spawn_teammate 仅 Team Lead 可调),它派不出执行者。这条通路走不通 |
| 用规模表决定派不派("≥3 个子任务就派") | 数子任务个数是容易的,但它不告诉你"能不能验收"。判据应该是"我是否已经理解到能验收" |
靠 deferLoading 省 token | 在非 anthropic 路径上该字段会被 strip,schema 照样下发 |
| 按预设裁剪浏览器工具 | 那批工具来自 profile 级 bundle,预设管不到;ctx.tools.restrict() 要求 agent.ctx 作用域,预设插件调用会抛错 |
| 做右侧栏实时工作台 | 技术能做,但信息在对话里本来就能看到,没带来新的判断力 |
| 靠不断追加判据来纠偏 | 判据只允许被"证据"替换,不允许被"教训"追加。每次想加一条时问:能不能改成可执行检查?不能,说明这是暂时的人类判断,该由人持有 |
环境限制
| 限制 | 说明 |
|---|---|
| 浏览器工具无法按预设裁剪 | 34 个 dsh_browser_* 来自 profile 级 bundle,preset 管不到;ctx.tools.restrict() 要求 agent.ctx 作用域,preset 插件调用会抛错 |
| 超长 skill 会被静默裁剪 | 超过 8192 字节的 skill 正文会被 pruner 截断(保留头 4096 + 尾 1024),中间内容丢失且无提示。本包所有 skill 均已控制在阈值内;安装外部 skill 时需自查 |
| skill 正文加载后不可撤回 | 一旦加载即进历史,只能靠 compaction 折叠 |
| compaction 压不动 system / tools | 只压历史,不是"重置成空" |
结构
dsh-workflow-kit/
├── package.json dsh.bundle.patch 声明 + npm scripts
├── index.js 自注册 skill provider(无硬编码路径)
├── cordis.patch.yml ⚠️ 生成物,勿手改
├── personas/ ★ persona 源文本(改这里)
│ ├── brownfield.txt
│ └── greenfield.txt
├── scripts/
│ └── gen-patch.mjs 生成 + 校验 cordis.patch.yml
├── modes/ ★ 模式库(可扩展)
│ ├── MODES.md 路由表:什么情况用哪个模式
│ ├── brownfield.md 存量深化
│ ├── brownfield-delegation.md 委派细节(按需 read)
│ ├── greenfield.md 从零开始
│ └── <你自加的>.md
├── templates/
│ └── brief.md ★ 任务书模板
├── checks/
│ ├── verdict.schema.json ★ 判决契约
│ └── verify.py ★ 判决校验器
├── skills/ 8 个方法论 skill + ROUTING.md
├── licenses/ 第三方许可全文
├── LICENSE MIT
└── THIRD-PARTY-NOTICES.md 来源与修改说明
加一个模式 = 加一个 .md 文件 + 在 MODES.md 加一行。 不用改代码、不用重装。
改 persona 的正确姿势
cordis.patch.yml 是生成物,手改会被下次生成覆盖:
# 1. 改源文本
vim personas/brownfield.txt
# 2. 重新生成
npm run build:patch
# 3. 校验(CI 友好,不一致退出码 1)
npm run check:patch
生成器用 import.meta.url 定位自身,从任何目录调用都能跑。
判决契约
子代理交付时必须产出 verdict.json,主代理只读判决不读过程:
python checks/verify.py tasks/<id>/verdict.json
文件长什么样:
{
"pass": false,
"failed": [
{
"item": "调用方未同步:auth/login.ts 仍用旧签名",
"impact": "high",
"repro": "grep -rn 'parseConfig(' src/ | grep -v config/"
}
],
"reviewed_at": "2026-11-01T08:00:00Z",
"reviewer": "fresh-context"
}
| 字段 | 必填 | 含义 |
|---|---|---|
pass | ✅ | 是否接受。false 即打回 |
failed | ✅ | 失败项数组。pass=true 时必须为空 |
failed[].item | ✅ | 具体问题,指向可定位的位置(文件/函数/行) |
failed[].impact | ✅ | high / med / low。high 必须由主代理亲自复核 |
failed[].repro | ✅ | 复现方式:命令,或可寻址的路径+行号 |
reviewed_at | ✅ | ISO 8601 时间戳 |
reviewer | — | 审查者标识,应独立于实现者 |
checks | — | 可执行断言的执行结果(命令 + 退出码 + 输出尾部) |
退出码:
| 码 | 含义 |
|---|---|
| 0 | 通过 |
| 1 | 判决不合法(schema 违规 / 逻辑自相矛盾) |
| 2 | 打回 |
| 3 | 自检未通过,拒绝出判决 |
三条硬规则:
- verdict 缺失 = fail,不是 pass。沉默绝不等于通过。
- 失败项必须有
repro,否则不可信。 --selftest红不了就拒绝出判决,不靠"建议先跑"的纪律。
为什么要有这个契约:子代理回三行摘要时,"凭什么说对"那行如果只有自然语言,
主代理无法否决。verdict.json 把它变成结构化判决——主代理读一个 pass 字段和
failed[].impact,就能决定收不收,而不用读完整过程。
许可
原创部分 MIT(LICENSE);skills/ 下第三方 skill 沿用原许可,
详见 THIRD-PARTY-NOTICES.md。
Comments
Loading…
From the same category
by ranxianglei
基本稳定可用 100K tokens is enough. Universal context-compression proxy for ALL AI coding agents,10w上下文足矣
★ 3.6k
↓ 788.3k/wk
MIT
TypeScript
Nov 2, 2026
dsh plugin --profile web add billion-contextA DeepSeek coding agent harness: persistent shell, Ultra subagents, auto approval, Chrome MCP and session telemetry
★ 1k
MIT
JavaScript
by Han-1413141
DeepSeek Harness session cost meter plugin: session/daily cost, budget, history, OpenCode Go quota, official & custom-provider balance, Codex-like token heatmap, peak/off-peak pricing with pre-switch
★ 597
↓ 26k/wk
MIT
JavaScript
Nov 1, 2026
dsh plugin --profile web add dsh-cost-meterby Yuuyuko-uu
DSH 鱼的记忆:给会话一份会淡忘的长期记忆,每条都带时间
★ 451
MIT
JavaScript
Nov 1, 2026
dsh plugin --profile web add dsh-fish-memoryby MichengAI
DSH Archive Manager — 在 DeepSeek Harness 中安全查看、恢复和管理已归档会话 · Safely view, restore, and manage archived sessions in DSH
★ 276
↓ 30.5k/wk
Apache-2.0
JavaScript
Nov 2, 2026
dsh plugin --profile web add @michengai/dsh-archive-managerby Nwflower
Import 14+ external agent chat histories (Claude Code, Codex, ChatGPT, Cursor, Gemini, Reasonix, opencode, ZCode, Grok Build, OpenClaw, Pi, Hermes, Kimi CLI, DSH) into DeepSeek Harness as resumable se
★ 275
↓ 5k/wk
MIT
JavaScript
Oct 31, 2026
dsh plugin --profile web add dsh-chat-import