# deepseek-harness-studio

> dsh Shared Core Package: Inserts tools, model adapters, subagent providers, persistence, and policies as a first-layer patch onto the profile root—every profile includes this layer by default.

## Metadata

- Author: [@fufankeji](https://github.com/fufankeji)
- Repo: <https://github.com/fufankeji/deepseek-harness-studio.git>
- GitHub: [fufankeji/deepseek-harness-studio](https://github.com/fufankeji/deepseek-harness-studio)
- Stars: 404
- Language: TypeScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Homepage: <https://www.beyondata.com/>
- Topics: `ai-agent`, `deepseek`, `deepseek-harness`, `deepseek-harness-studio`, `desktop-app`, `developer-tools`, `dsh`, `dsh-plugin`, `electron`, `macos`, `plugin-manager`, `windows`
- Forks: 43
- Open Issues: 2
- Last push: 2026-08-20T10:56:44.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:fufankeji/deepseek-harness-studio/packages/bundle/base
```

## Wiki

## 一句话定位
dsh 的「共享核心」组合包。它自己不提供运行时 API，作用是把每个 dsh profile 都需要的基础能力一次性挂到 profile 根上——默认的 DeepSeek 适配器、bash / pwsh 工具、文件系统、subagent、权限预设、Settings / Credentials、Telemetry 都在这一层；后续的 web / headless 等表层 bundle 都建立在这一层之上。

## 核心能力
- 以一份 `cordis.patch.yml` 一次性插入约 78 行插件，构成所有 dsh profile 的共享基底（cordis.patch.yml:15-451 / tests/base.spec.ts:30-42）
- 引入默认模型适配器：在没有用户 settings 覆盖时，给所有 Agent 装配 `deepseek-official` provider 的 `deepseek-v4-flash` 模型（cordis.patch.yml:62-68）
- 提供 bash / pwsh 两套互补的 shell 栈，并在加载时按平台自动只保留其中一套：bash 在 POSIX 启用、PowerShell 在 Windows 启用（cordis.patch.yml:178-217 / README.md:7）
- 给出三层权限预设（`read-only` / `workspace-write` / `danger-full-access`），并把审批服务与权限预设挂钩，全局权限模式可通过 `DSH_PERMISSION_MODE` 切换（cordis.patch.yml:170-217）
- 提供基础工具集：bash（pwsh）、文件系统读 / 写 / 搜索、jobs、`web_search`（DeepSeek 搜索源）、todo、goal、subagent（spawn / fork）、str-replace-editor、ralph、skill、workflow（cordis.patch.yml:210-419）
- 持久化与可观测：session 落 JSONL、附件图片走内容寻址本地存储、SQLite 索引默认走内存模式、Telemetry 通过 `DSH_TELEMETRY_MODE` 环境变量开关（cordis.patch.yml:98-161）

## 技术实现
- **语言**: TypeScript (ESM)，`"type": "module"`，`package.json` `lib/index.js` 入口只导出 `export {}`
- **关键依赖**: `@deepseek-ai/cordis`（Cordis 插件宿主，对等依赖）、`@deepseek-ai/cordis-plugin-loader`（patch 加载器）、`@deepseek-ai/dsh-invariants`（对等依赖 + invariant companion）、约 70 个 `dsh-*` 工作区包（构成 patch 中插入的 78 个插件行）
- **架构模式**: 该包「自己」不是插件——它的 `package.json` 在 `dsh.bundle.patch` 字段下挂一份 `cordis.patch.yml`，由 profile composer 在加载时把它当作「第一个 patch 层」插入空 profile 根；按 id 寻址，后续 bundle / 用户 profile 的 patch 可以覆盖这些行；`src/invariant.ts` 是只挂占位的 invariant companion（每个被插入的 row 各自的包自带 invariants）
- **入口文件**: `src/index.ts`（空导出，仅含模块注释）+ `src/invariant.ts`（`base-bundle-invariant` companion）+ `cordis.patch.yml`（包的实际内容）

## 适用场景
任何想自己「从零搭一套 dsh profile」、或要给 profile 加一个共享基底的开发者：装上 dsh-base，等于一次性把 DeepSeek 适配器、bash / pwsh 工具、文件系统、subagent、持久化、telemetry、权限预设这些共用行为默认打开——之后 web / headless / 桌面表层只需在它之上再叠加自己关心的层。普通用户一般不会直接安装这一层，而是通过 dsh-cli 内置或 `dsh plugin --profile` 安装 web-app、headless 这些表层 bundle 间接使用它。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH | 0.1.0-rc.8 | 作为「第一层 patch」叠加在 dsh-base 之上，需使用同主版本的 dsh CLI |
| Node | ^22.19.0 \|\| >=24.0.0 | 仓库根 `engines` 字段声明；当前 patch 不直接使用任何 Node 22+ API，但所插入的 row 包以这条线为准 |
| 平台 | macOS / Linux / Windows | bundle 在自身 patch 中按平台门控 bash / pwsh，因此同一份 patch 在三种系统上都能加载，但只挂一个 shell 栈 |
| 原生模块 | node:sqlite（`@deepseek-ai/dsh-session-query-sqlite`） | 默认 `:memory:`，需重启进程重开索引；不持久化到磁盘 |
| Cordis | peerDependency | `@deepseek-ai/cordis`，由宿主提供 |

## 安装方式
```bash
dsh plugin --profile web add github:fufankeji/deepseek-harness-studio/packages/bundle/base
```

## 配置项
本 bundle 自身不直接暴露用户配置——它通过 `cordis.patch.yml` 给每个被挂载的 row 注入一份配置。下面列出值得记的几条全局 / 行为级默认：

| 名称 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `sandbox.mode` | 字符串 | 文件效果边界，取自 `DSH_PERMISSION_MODE` 环境变量 | `workspace-write` |
| `sandbox.workspaceRoot` | 路径 | 受限子进程允许写入的工作区根 | `process.cwd()` |
| `user-approval.policy` | 字符串 | 危险操作前是否询问 | `DSH_PERMISSION_MODE === 'danger-full-access'` 时 `never`，否则 `ask` |
| `bash-sandbox.timeoutMs` | 毫秒 | 单条 bash 命令最长等待时间 | `60000` |
| `web-search-deepseek.apiKeyEnv` | 环境变量名 | DeepSeek 搜索用的 key 环境变量名 | `DEEPSEEK_API_KEY` |
| `tool-web.searchTimeoutMs` | 毫秒 | web_search 单次超时 | `60000`（DeepSeek 路由），其它 `30000` |
| `tool-str-replace-editor.maxOutputChars` | 数字 | str_replace_editor 单次最多输出多少字符 | `16000` |
| `tool-result-pruner` 阈值 | 字符 | 超长工具结果被自动裁剪的字符阈值 / 保留头 / 保留尾 | `8192 / 4096 / 1024` |
| `repeat-tool-reminder.thresholds` | 数字数组 | 连续重复同一工具调用时提示的回合数 | `[3, 5, 8]` |
| `session-telemetry.mode` | 字符串 | OTLP / HTTP 上报模式，取自 `DSH_TELEMETRY_MODE`；空值 = 不上报 | `DISABLED` |
| `session-telemetry.exporter.url` | URL | OTLP logs 上报端点，可被 `DSH_TELEMETRY_OTLP_URL` 覆盖 | `https://harness-telemetry.deepseeksvc.com/v1/logs` |
| `session-query-sqlite.openAt` | 字符串 | SQLite 索引何时打开；默认值禁止内容搜索 | `never` |
| `session-query-sqlite.path` | 字符串 | 索引存储位置；`:memory:` 是默认 | `:memory:` |
| `session-persistence-jsonl.root` | 路径 | session log 文件根 | `$DSH_HOME/sessions` |
| `spill-policy.maxInlineBytes` | 字节 | 工具结果以 inline 形式携带的最大尺寸，超过则 spill 到本地 | `50000` |
| `tool-todo.allowParallelInProgress` | 布尔 | todo_write 是否允许同时存在多个 `in_progress` 项 | `true` |
| `tool-ralph.maxRounds` | 数字 | Ralph 工具的最大迭代回合 | `64` |
| `tool-fs-search.sampleOverCapGlobResults` | 布尔 | 通配超过上限时是否降采样返回 | `false` |
| `session-title-llm.targetWords` / `targetCjkCharacters` | 数字 | 默认标题长度（西文 / 中文） | `5` / `10` |

> 用户也可在 home 的 `settings.yaml` 中加 `llm-deepseek:` / `llm-pi-ai:` 段覆盖默认的 DeepSeek adapter 与激活 pi-ai 多 provider；不在 patch 内的「配置项」不展开。

## 常见问题

**Q: 这个 bundle 是什么？为什么要先装它？**

A: dsh 的「共享核心」组合包。它的 `cordis.patch.yml` 把所有 profile 都需要的基础插件一次性挂到 profile 根上——LLM 适配器、bash / pwsh 工具、文件系统、subagent、持久化、telemetry、权限预设都来自这一层。任何 dsh profile（web / headless / 桌面等）都默认以这一层为底，不装它就只剩空 profile。

**Q: 安装 dsh-base 之后，还需要装官方 dsh-cli 吗？**

A: 不重复。dsh-base 是 dsh 安装内部的 in-box bundle，普通用户通过 `dsh plugin --profile <name> add` 安装的通常是 web-app、headless 这类表层 bundle，dsh-base 已经默认存在于 `@deepseek-ai/dsh` 生产闭包里。

**Q: 安装 dsh-base 会同时启用 Codex / Claude Code 子代理吗？**

A: 不会。本包显式不带 `@deepseek-ai/dsh-subagent-codex` 和 `@deepseek-ai/dsh-subagent-claude-code`，这两类是可选的「产品 provider」，需要单独安装 profile bundle 才会被激活。

**Q: 装上后看到 telemetry 行为，是开了吗？**

A: 默认没开。`session-telemetry-otel` 行虽然被 patch 进来，但 `mode` 默认从环境变量 `DSH_TELEMETRY_MODE` 取值；该变量为空时落到 `'DISABLED'`。要上报就把环境变量显式设成 `FULL` 或 `FEEDBACK_ONLY`（其它值仍走禁用分支）。

**Q: 我用的是 Windows，跑起来为什么 bash / pwsh 工具表现不一样？**

A: bundle 在自身 patch 里按平台门控：bash 在 win32 上被 `disabled: !!js process.platform === 'win32'` 关掉，pwsh 在非 win32 上被关掉——同一份 patch，每台机器恰好挂一个 shell 栈。要在 Windows 上强行使用 bash 需要在 profile 或 home cordis.patch.yml 同时禁 pwsh-sh / tool-pwsh 并重新启用 bash-sh / tool-bash，缺一项会因重复注册同一个 `bash` 服务而加载失败。

**Q: 偏好不联网的本地模型（或 Anthropic / OpenAI / 其它 provider），需要加 provider bundle 吗？**

A: 需要。dsh-base 已经把 `@deepseek-ai/dsh-llm-pi-ai` 作为「零路由」provider 挂上，但没注入任何 provider profile；要让 pi-ai 跑起来要在 home `settings.yaml` 的 `llm-pi-ai:` 段填 provider profiles（Web 表层 Models 页面是入口）。不填的话 picker 里只有默认的 DeepSeek adapter。

**Q: dsh-base 有自己的运行时 API 吗？我能 `import` 它的 `apply()` / 主入口吗？**

A: 没有。`src/index.ts` 是空导出并写明「package's substance is `cordis.patch.yml`」，profile composer 通过 manifest 的 `dsh.bundle.patch` 字段解析 patch，不会经过 import。`src/invariant.ts` 提供一个 no-op companion，理由是本包不挂服务、不发事件、不持可变状态，每条 row 各自的包自带 invariants。

**Q: 升级 dsh-base 会修改用户的 home settings.yaml / sessions 目录吗？**

A: 不会。settings、sessions、`.anonymous-user-id`、`.credentials.yaml` 都由相应的服务独立管理在 `$DSH_HOME` 下，升级 dsh-base 不动这些位置；session-query-sqlite 默认走 `:memory:`，重启进程后只把内存中的搜索索引清空，不动磁盘。

## 上手难度
入门 — 只要会用 `dsh plugin --profile` 加 bundle、按 home `settings.yaml` 配 key 和 provider profile 就能让它工作；不需要写 Cordis 插件、不需要跑 loader；要深入则要理解 patch layer 的覆盖语义和键约束。

## 已知问题与限制
- **patch 替换整行 config**：profile 覆盖必须重述该行需要保留的每个字段，不存在深度合并层（README.md:19-22 / README.zh.md:19-22）
- **Windows 临时目录授权是按会话的私有子目录**——`workspace-write` 把写入限制在工作区与会话自己的 temp 子目录（`<temp>\dsh-<hash>`，受限子进程的 TMP/TEMP 被改写）；`read-only` 不授予任何临时目录写入权限（README.md:19-22）
- **session 内容搜索默认关闭**——`session-query-sqlite.openAt: never` 让精确读、标题、lineage 仍可用，但搜索调用会以 `SESSION_QUERY_SEARCH_DISABLED` 失败；想启用需要在更上层 patch 中把 `openAt` 改为 `first-search` 或 `startup`，通常配合一个稳定的 `path`（cordis.patch.yml:111-122 / 注释在 109-117）
- **DSH 基线采用整行替换、不做合并**：见 `cordis.patch.yml` 文件头与 README `## Known Limitations and Deferred Work` 节
- **telemetry 默认禁用但 OTLP 上报端点仍写死一个官方域名**——`session-telemetry-otel.exporter.url` 默认指向 `https://harness-telemetry.deepseeksvc.com/v1/logs`，可通过 `DSH_TELEMETRY_OTLP_URL` 改写但默认就是该域（cordis.patch.yml:148-161）

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [deepseek-harness-studio](https://deepseek-plugin.org/plugins/fufankeji/deepseek-harness-studio/packages/bundle/base)
Wiki generated by AI (model: `MiniMax-M3`)
