# @sstreichan/oh-my-dsh-slim

[English](README.md) | 中文

一个函数式 Cordis 插件，将 oh-my-opencode-slim 的智能体阵容——编排器 + 7 个专家、斜杠命令、AST-grep + webfetch + 任务控制工具、9 个内置技能、context7 + gh_grep MCP 回退、多路复用器窗格适配器、访谈面板、以及 Rust 伴随窗口——移植到 DeepSeek Harness。

## 功能

在 dsh Context 上注册以下内容：

- **系统提示词段** — `omo:orchestrator-rules`（委派提示词，包含 `<Role>`、`<Agents>`、`<Workflow>`、`<Communication>`）和 `omo:agent-catalog`（每个专家的显示名称 + 角色），通过 `ctx.systemPrompt.section({ name, order, text })` 注册。两者均**仅对编排器可见**：其 `text` 提供者检查装配上下文的 agent，对生成的专家、其后代以及专家 agent-loop agent 一律不渲染——而主用户会话（`omo-orchestrator` agent-loop 会话、headless 新建会话或无预设的 web 会话）就是编排器通道，会获得完整的规则。
- **工具** — 11 个模型可见工具，通过 `ctx.tools.register(defineTool(...))` 注册：`ast_grep_search`、`ast_grep_replace`、`webfetch`、`acp_run`、`task_cancel`、`task_message`、`task_result`、`task_revive`、`task_status`、`wait_for_user`、`preset_switch`。
- **斜杠命令** — `/deepwork`、`/reflect`、`/loop`、`/preset`，通过 `ctx.commands.register({ name, description, handler })` 注册。处理器返回 `{ kind: 'success', text }`，并通过 `agent.session.append('user/message', ...)` 调度模型可见的工作。
- **技能** — 9 个内置 `SKILL.md` 文件，当 `dsh-skill` 已挂载时通过 `ctx.skills.registerProvider()` 注册，否则回退为 `ctx.systemPrompt.section()`。
- **MCP 回退** — `context7_search` 和 `gh_grep_search` 工具，当 `dsh-mcp-client` 未挂载时通过 HTTP 获取。
- **钩子** — 7 个事件监听器，通过 `ctx.on(event, listener)` 注册：cache-monitor、json-error-recovery、phase-reminder、image-routing、foreground-fallback、orchestrator-wake、post-file-tool-nudge。
- **多路复用器窗格适配器** — tmux、zellij、kitty、herdr、cmux，通过环境变量自动检测。
- **访谈子系统** — 每会话 HTTP 服务器 + 可选的 SSE 面板。
- **Rust 伴随窗口** — 独立的 egui 桌面窗口，轮询 JSON 状态文件。
- **UI 可配置模型** — 当 `@deepseek-ai/dsh-settings` 已挂载时（例如通过 `@deepseek-ai/dsh-settings-file`，dsh 基础 bundle 默认挂载），插件注册 `oh-my-dsh-slim` 设置命名空间并附带浏览器卡片，dsh web 的 **设置 → 插件** 页面会显示 "Oh My DSH Slim" 卡片，每个万神殿智能体一个模型字段。编辑会持久化到 `$DSH_HOME/settings.yaml`，实时应用到运行中的 agent-loop 智能体，并对未来的专家委派生效；Cordis 配置仍是基础层（见 [设置 UI：每智能体模型卡片](#设置-ui每智能体模型卡片)）。

专家委派需要子智能体脊柱（`dsh-subagent` + `dsh-subagent-spawn-in-process` + `dsh-tool-subagent`，均由基础 bundle 挂载）。插件在此基础上叠加 `omo` 提供者：bundle 补丁将 `tool-subagent` 指向它，它会把每次委派中的专家 `@handle` 解析为该专家的完整提示词 + 工具集。

## 导出形状

函数/命名空间插件：导出 `name` / `inject` / `Config` / `apply`，无默认导出。多余的 `export default` 会通过 Loader 的 `unwrapExports` 折叠模块并丢弃 `inject`（参见 [docs/postmortem/0001](https://github.com/deepseek-ai/deepseek-harness/blob/main/docs/postmortem/0001-acp-default-export-drops-inject.md)）。

`inject: ['tools', 'agents', 'systemPrompt', 'llm', 'sessions']`。可选服务（`subagents`、`skills`、`commands`）通过 `ctx.get(name)` 解析。

## 配置

| 字段 | 默认值 | 含义 |
|---|---|---|
| `preset` | — | 活动预设名称（必须存在于 `presets` 中）。 |
| `setDefaultAgent` | `true` | 会话创建时强制 `default_agent = 'orchestrator'`。 |
| `autoUpdate` | `true` | 定期轮询 npm 注册表；有更新时显示通知。 |
| `presets` | — | 命名的每智能体覆盖集合；通过 `preset` 选择。 |
| `agents` | — | 在活动预设之上应用的每智能体覆盖。`model` 接受字符串或有序回退链 `[{id, variant?}]`。 |
| `disabledAgents` | `['observer']` | 要从阵容中排除的智能体。`orchestrator` 和 `councillor` 受保护。 |
| `disabledMcps` | `[]` | 要跳过的 MCP（`context7`、`gh_grep`）。 |
| `disabledTools` | `[]` | 要跳过的工具。 |
| `disabledSkills` | `[]` | 要跳过的技能。 |
| `imageRouting` | `'auto'` | `'auto'` 通过 `@observer` 路由图像；`'direct'` 从不拦截。 |
| `multiplexer` | `{type:'none',...}` | 窗格适配器配置。 |
| `interview` | `{maxQuestions:2,...}` | 访谈子系统配置。 |
| `backgroundJobs` | `{maxSessionsPerAgent:2,...}` | 后台任务限制 + 唤醒调度器。 |
| `fallback` | `{enabled:true,maxRetries:3}` | 可重试错误时的模型回退。 |
| `companion` | — | Rust 桌面窗口配置。 |

## 运行

该插件通过 `cordis.yml` 组合。示例配置位于 [`examples/oh-my-dsh-slim-profile/cordis.yml`](examples/oh-my-dsh-slim-profile/cordis.yml)：

```yaml
- id: oh-my-dsh-slim
  name: '@sstreichan/oh-my-dsh-slim'
  config:
    preset: openai
    setDefaultAgent: true
    agents:
      explorer:
        model: anthropic/claude-3-5-sonnet
        temperature: 0.1
```

将其放入 `$DSH_HOME/profiles/oh-my-dsh-slim/cordis.yml` 并运行：

```sh
dsh --profile oh-my-dsh-slim web
```

对于 MCP 服务器，将 [`examples/mcp-context7.cordis.yml`](examples/mcp-context7.cordis.yml) 和 [`examples/mcp-gh-grep.cordis.yml`](examples/mcp-gh-grep.cordis.yml) 中的示例配置放入您的 profile。这些挂载 `@deepseek-ai/dsh-mcp-client` 行，提供完整的 MCP 工具表面。没有它们，本插件注册降级的 HTTP 获取回退工具。

### 设置 UI：每智能体模型卡片

当设置服务已挂载时，插件向 dsh 的设置系统发布 `oh-my-dsh-slim` 命名空间，并附带一个 web 客户端 bundle，在 dsh web UI 的 **设置 → 插件** 下将其渲染为卡片。卡片按万神殿顺序列出每个智能体的模型字段（`orchestrator`、`explorer`、`librarian`、`oracle`、`designer`、`fixer`、`observer`、`council`、`councillor`）。

每个字段接受两种形式：

- **`provider/model`** — 例如 `anthropic/claude-sonnet-4-5`；同时覆盖 provider 路由和模型。
- **裸模型 id** — 例如 `deepseek-v4-flash`；仅覆盖模型，保留智能体已配置的 provider 路由。

编辑行为：

- **持久化** — 保存将用户层写入 `$DSH_HOME/settings.yaml` 的 `oh-my-dsh-slim:` 下（每个智能体一个平铺键）。留空的字段继承基础层。
- **重置** — 字段标签旁的 `·` 标记表示该值是用户覆盖；清空字段（并保存）会移除覆盖并恢复配置的基础值。
- **实时应用** — 保存的值会推送到运行中 agent-loop 智能体的 option 对象，因此该智能体的下一个请求立即使用新模型，无需重启 dsh，也不会丢失会话历史。
- **委派路由** — 未来的专家委派通过同一个值解析模型（UI 覆盖优先，其次 `agents.<name>.model` 配置）。

智能体有效模型的优先级（从高到低）：

1. 设置 UI 的值（`$DSH_HOME/settings.yaml` 中 `oh-my-dsh-slim` 用户层）。
2. Cordis 配置的 `agents.<name>.model`（插件配置 / 预设 / profile 补丁）。
3. 基础 agent-loop 行的路由（默认：`deepseek-official` / `deepseek-v4-flash`）。

要求与说明：

- 设置提供者行（`@deepseek-ai/dsh-settings-file`，由 dsh 基础 bundle 挂载）必须处于活动状态；没有它，插件会记录一条调试日志并无 UI 设置运行——模型仅来自配置。
- 命名空间的 schema 是平铺的（每个智能体一个顶层字段）。这一形状是 web 设置作用域所要求的，它只写顶层路径编辑；不要改回嵌套的 `agents` 对象。
- 无法解析的暂存编辑在保存时被拒绝（保存按钮保持禁用）而不是被静默丢弃；保存失败会保留草稿以便修正。

## 组合

示例 profile 组合了 dsh 基础（`settings`、`credentials`、`llm-deepseek`、`session`、`agent-loop`、`tools`、`system-prompt`、`sandbox`、`bash`、`fs`、`todo`、子智能体脊柱、技能子系统、命令适配器）加上本插件：

| 插件 | 角色 |
|---|---|
| `@deepseek-ai/dsh-session` + 持久化 + 投影 | 事件溯源的会话日志，带 JSONL 持久化和 SQLite 查询。 |
| `@deepseek-ai/dsh-agent` + `dsh-agent-loop` | 智能体工厂 + 智能体循环。 |
| `@deepseek-ai/dsh-tools` + `dsh-system-prompt` | 工具注册表 + 系统提示词组装。 |
| `@deepseek-ai/dsh-subagent` + `dsh-subagent-spawn-in-process` + `dsh-tool-subagent` | 专家委派脊柱。 |
| `@deepseek-ai/dsh-skill` + `dsh-skill-filesystem` + `dsh-tool-skill` | 技能注册表 + 文件系统提供者 + `skill` 工具。 |
| `@deepseek-ai/dsh-commands` | 斜杠命令适配器。 |
| `@deepseek-ai/dsh-tool-bash` + `dsh-tool-fs` + `dsh-tool-todo` | Bash、文件系统和 todo 工具。 |
| `@deepseek-ai/dsh-sandbox` + `dsh-sandbox-policy` + `dsh-approval` | 沙箱 + 权限门。 |
| `@sstreichan/oh-my-dsh-slim` | 本插件：编排器 + 7 个专家 + 工具 + 命令 + 技能 + 钩子 + 多路复用器 + 访谈 + 伴随窗口。 |

## 模型体验

### 编排器系统提示词

#### 模型所见

编排器看到约 3k token 的系统提示词，由 `omo:orchestrator-rules`（委派提示词）和 `omo:agent-catalog`（专家显示名称 + 描述）组装。专家提示词各加约 1k token，但仅在编排器通过 `subagent` 工具调度时可见。

#### Token 影响

每个编排器轮次固定成本。专家提示词是每次委派的，不是每轮的。

#### KV 缓存影响

当编排器提示词文本和每智能体覆盖不变时前缀稳定。切换预设、禁用智能体或热重载提示词会从第一个受影响的系统提示词 token 起使复用失效。

### 专家委派

编排器通过 `subagent` 工具（来自 `dsh-tool-subagent`）委派，并在 `description` 参数中用 `@handle` 指明专家通道：

```
subagent(description: "@explorer: locate route handlers", prompt: "...", run_in_background: true)
```

插件的 `omo` 提供者拦截该调用：

1. 在 `persona`、`description` 或提示词中解析 `@handle`（规范名、显示名或别名）到已配置的阵容；
2. 将 persona 替换为该专家的完整提示词（例如只读的 `@explorer`、可写的 `@designer`），并应用该专家的工具过滤；
3. 将该专家配置的模型路由到子代理的 `agentOptions` —— `agents.<name>.model: 'anthropic/claude-3-5-sonnet'` 变为 `provider: 'anthropic'`、`model: 'claude-3-5-sonnet'`；裸模型 id（`'deepseek-v4-flash'`）只覆盖模型并保留父级 provider 路由；
4. 交给与标准 `spawn` 提供者相同的进程内驱动。

委派通道为 `backgroundMode: one-shot`（而非基础 bundle 的 `continuable`），因此每次委派都流经提供者，工具链在此处尊重专家的 persona、工具过滤和模型。一次性后台运行返回任务 id —— 用 `job_output` 收集，用 `job_kill` 停止。

如果切回 `continuable`（以获得持久子代理对话和 `send_message` 后续消息），`omo` 提供者会被绕过——但插件的 `registerContinuableSetup` 贡献会从每个 continuable 子代理的持久描述符中安装其完整提示词 + 工具过滤，因此该通道上仅丢失专家的模型路由（continuable 子代理使用工具请求中的 agent options 物化）。

专家子代理自身的提示词组装永远不会包含编排器的委派规则：omo 提示词段仅对编排器 agent 渲染。未指明专家的委派保留显式配置的 `persona`，或使用中立的回退身份。

#### Token 影响

固定架构成本。每次委派将提示词 + 结果添加到轮次的 token 预算。

#### KV 缓存影响

仅追加；委派结果跟随可复用的请求前缀，不会使现有 KV 缓存条目失效。

### 技能目录

#### 模型所见

当 `dsh-tool-skill` 已挂载时，模型看到 `skill` 工具架构和列出可用技能的 `<system-reminder>` 目录。没有 `dsh-tool-skill` 时，技能作为 `ctx.systemPrompt.section()` 条目注入，仅对编排器可见。

#### Token 影响

目录成本随启用的技能数量缩放（默认 9 个，减去 `disabledSkills`）。

#### KV 缓存影响

当技能集不变时前缀稳定。添加或删除技能会从目录段起使复用失效。

### 阶段提醒和文件工具后提示

#### 模型所见

`agent/pre-step` 瀑布向编排器的最新用户消息追加 `<system-reminder>`：阶段提醒（工作流纪律）和文件工具后提示（todo 更新提醒）。

#### Token 影响

每次注入约 50 token，仅在合格的编排器轮次上。

#### KV 缓存影响

这些追加到用户消息，而非系统提示词，因此不会使系统提示词 KV 缓存失效。如果消息之前被缓存，可能使用户消息缓存失效。

## 已知限制和待办工作

- **子智能体委派需要子智能体脊柱** — 必须挂载 `dsh-subagent` + `dsh-subagent-spawn-in-process` + `dsh-tool-subagent`（均为基础 bundle 的一部分）；插件的 `omo` 提供者建立在其之上。没有脊柱时提供者不会注册，`subagent` 工具也不存在。
- **专家解析是词法匹配** — `omo` 提供者在委派请求中匹配 `@handle` 提及（或裸专家名）；它不是命名 persona 的注册表。以其他方式表述专家的委派会回退到中立身份。编排器提示词会教导 `@handle` 约定以保持匹配可靠。
- **Omo 段身份基于会话** — 编排器作用域渲染匹配 `omo-orchestrator` agent-loop 会话 id、`orchestrator` agent 预设或任何根（非子代理、非 `omo-` 专家）会话。重命名编排器 `sessionId`（或使用不同命名的编排器预设）的 profile 必须相应更新 `OMO_ORCHESTRATOR_SESSION_ID` / 预设匹配，否则 `omo-` 前缀的专家排除和 agent 预设检查将不再适用。
- **专家工具过滤基于基础 bundle 工具表面** — 只读过滤器的 `allow` 列表仅包含基础 bundle 加本插件自带的工具（`read`、`glob`、`grep`、`ast_grep_search`、`webfetch`、`gh_grep_search`、`context7_search`、`job_output`、`job_list`、`list_agents`）。`tools.restrict()` 会拒绝未知名称，因此禁用了其中某个工具（或挂载缺少该工具的最小 bundle）的 profile 必须修剪过滤器，否则委派专家无法启动。oh-my-opencode-slim 时代的名称（`lsp`、`list`、`codesearch`、`apply_patch`、`task`、`question`）已移除。
- **没有 `dsh-mcp-client` 时 MCP 集成仅为回退** — context7 和 gh_grep 作为单个 HTTP 获取工具暴露，而非完整的 MCP 服务器。在 profile 中挂载 `@deepseek-ai/dsh-mcp-client` 行以获得完整的工具表面。
- **伴随二进制文件必须单独构建** — Rust 源码位于 `companion/`；运行 `cargo build --release` 并将二进制文件安装到 `PATH` 或设置 `config.companion.binaryPath`。
- **没有 GitHub 技能同步** — oh-my-opencode-slim 的 `skills-lock.json` 机制未移植；仅 9 个内置技能可用。
- **没有 ACP 权限流程** — `acp_run` 生成智能体但未实现完整的 ACP 权限协商。
- **webfetch HTML 提取已简化** — 完整的 Readability + Turndown 管道未移植；HTML 通过正则表达式剥离为文本。
- **多路复用器窗格注册表未持久化** — tmux 窗格注册表文件未写入；子窗格仅通过环境变量定位父窗格。
- **缓存安全纪律不完整** — 标记的合成部分未移植；阶段提醒和文件工具后提示钩子注入纯文本块。
- **没有 `README.i18n.yaml` 一致性记录** — 中文镜像已存在，但 i18n 配对文件尚未生成。
