# deepseek-harness-studio

> Allow DSH to launch the official Claude Code sub-agent in a one-time, unattended manner within a delegation session: submit a plain text task via `dsh-subagent` to the Claude Agent SDK for execution and return the final answer based on strict success criteria.

## 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: 403
- 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/subagent/subagent-claude-code
```

## Wiki

## 一句话定位
subagent-claude-code 让 DSH 会话在需要的时候临时拉起一个独立的 Claude Code 子进程来跑一段纯文本任务：每次都开新的 CLI、不需要人按键审批、跑完把最终答案或失败诊断交给上游；它不改写你的 Claude 账户和设置，只是把官方 SDK 接到 DSH 的 subagent 服务上。

## 核心能力
- 在委托 Session 的工作目录里拉起官方 Claude Agent SDK 的真 CLI 子进程，进程归 dsh-subprocess 的进程树统一管控（src/run.ts:362-368 / src/process.ts:46-94）
- 一次性文本任务：只接受非空纯文本块，按规范结果（`subtype: "success"` 且非错误且非空白）才作为任务成功；任何偏离都被映射到固定的失败分类（src/run.ts:182-224, 234-260）
- 不让任何弹窗等用户：禁用 `AskUserQuestion`，权限请求一律拒绝，MCP elicitation 一律拒绝，阻塞对话一律取消（src/run.ts:323-360）
- 失败会带诊断：把 lifecycle 阶段（query-start / query-run / process / teardown）、SDK 错误分类、子进程退出码/信号拼成最多 4096 字节的失败摘要，写到 `SubagentResult.diagnostic`（README.md:19 / src/run.ts:82-97）
- 一次只跑一次：不持有会话状态、不续接、不持久化，每次都是新的 SDK query + 新的 CLI 进程 + 一次性产品会话（README.md:141 / README.md:115-117）
- 安装/卸载通过 Profile Bundle：安装才让宿主上多出一个休眠 provider，卸载后下次启动就连同其私有运行时一起撤回（README.md:44 / cordis.patch.yml:1-6）

## 技术实现
- **语言**: TypeScript（ESM，发布产物 `lib/index.js` 与 `lib/types/*.d.ts`，见 package.json:13-27）。
- **关键依赖**: `@anthropic-ai/claude-agent-sdk@0.3.220`（官方 SDK，含八个平台子包携带 Claude Code 2.1.220）、`@deepseek-ai/dsh-subagent`（共享任务接缝与结果结算）、`@deepseek-ai/dsh-subprocess`（负责真 CLI 进程的进程树托管）、`@deepseek-ai/dsh-timeout`（`MAX_TIMER_DELAY_MS` 上限校验）（package.json:40-54 / src/run.ts:9-37 / src/process.ts:9-18）。
- **架构模式**: 函数插件 + Profile Bundle——`src/index.ts` 命名导出 `name`/`inject`/`Config`/`apply`；`apply(ctx, config)` 把一个 `ClaudeCodeProvider` 注册到 `ctx.subagents`，由 `cordis.patch.yml` 顺势注入 dsh-base 之上。运行时通过 SDK 的 `spawnClaudeCodeProcess` 自定义钩子把进程生成路径转交给 `dsh-subprocess` 持有的共享 handle，再由 `ManagedClaudeCodeProcess` 把事件流回灌给 SDK 协议层（src/index.ts:30-32, 129-151 / cordis.patch.yml:1-6 / src/run.ts:362-368 / src/process.ts:67-159）。
- **入口文件**: `src/index.ts`（Cordis 注册入口）、`src/run.ts`（一次性任务生命周期与 SDK 选项）、`src/process.ts`（SDK 到子进程句柄的投影）。

## 适用场景
把"我不想动手、就让 Claude 自己去干"的一段独立任务交给子 Agent，常见做法是让 DSH 主对话里的模型在工具白名单里看到 `subagent_claude_code` 后按需触发，比如一次性生成长文档、批量改文件、或让 Claude 自己拉一份现状总结再带回主对话。本包不适合需要持续对话、要看中间步骤、或者要求 Claude 工具一路弹交互确认的场景——这些需求跟"一次性、无人工、只读最终答案"的定位天然冲突。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH（launcher） | 0.1.0-rc.8 | 本包和同仓库其它包同版本（package.json:4），作为 Profile Bundle 注入 dsh-base 上层（cordis.patch.yml:1-6）。 |
| Node.js | ^22.19.0 \|\| >=24.0.0 | 仓库根 `engines.node` 约束，subagent-claude-code 自身未声明独立范围（仓库根 package.json:8-10）。 |
| 平台 | 跨平台（macOS / Windows / Linux） | 实际可执行的 CLI 由 `@anthropic-ai/claude-agent-sdk` 的八个平台子包按系统/CPU/Linux libc 自带；省略 optional dependencies、不被支持的系统、载荷文件缺失都会让 provider 注册能成功但第一次委派在 SDK 启动边界失败（README.md:101, 103）。 |
| Claude Code CLI | 2.1.220（随 SDK 平台包） | 由 SDK `0.3.220` 锁定，不依赖宿主 `claude`；本包也不查 `PATH`、不做平台选择、不回退到宿主二进制（README.md:42, 103）。 |
| 原生模块 | `claude` / `claude.exe`（来自 `@anthropic-ai/claude-agent-sdk`） | 安装后由 SDK 平台包携带，DSH 这边不再引入新的原生模块（README.md:101）。 |
| `disposeGraceMs` 上限 | ≤ `MAX_TIMER_DELAY_MS`（2 147 483 647） | `apply()` 启动时校验，正有限值且不得超过仓库 `dsh-timeout` 共享上限（src/index.ts:136-145 / packages/util/timeout/src/index.ts:25）。 |

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

## 配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `providerName` | 字符串（非空） | 在 `ctx.subagents` 上的注册名，同时给 dsh-tool-subagent 工具行的 `provider` 字段引用；同一个 Profile 挂多份实例时需要互不重复（src/index.ts:58 / README.md:29）。 | `claude-code` |
| `env` | 对象（`Record<string, string>`） | 显式透传给 Claude Code 子进程的环境变量，叠在父环境已被共享机制清掉凭证后的子集上；想让子进程拿到 `ANTHROPIC_API_KEY` 时必须在这里显式声明（src/index.ts:60 / src/run.ts:321 / README.md:42）。 | `{}` |
| `permissionMode` | 枚举：`dontAsk` / `acceptEdits` / `auto` / `plan` / `bypassPermissions` | 选定这个 provider 实例对子进程的非交互权限策略；选 `plan` 还会把 `ExitPlanMode` 也放进 `disallowedTools`，强迫模型把计划当最终答案（src/run.ts:43-55, 323-342 / README.md:34-40）。 | `dontAsk` |
| `disposeGraceMs` | 数字（毫秒，正有限值） | 共享进程树主人在各终止 tier 之间的等待时长，随后要等到整棵进程树退出才算清场（src/index.ts:62, 136-145 / src/process.ts:46-61）。 | `3000` |

## 常见问题
**Q: 跟前一个 Claude 工具链有什么区别？是不是更简单的接入？**

A: 不一样。这个包是 dsh 的"subagent 供应商"角色，承接 dsh-tool-subagent 那边发来的一次性请求，每次启全新的 Claude Code 进程跑完就结束；它不替 Claude 选模型、不持久化会话、不复制 Claude settings。dsh-base 里默认的 deepseek 入口是主对话模型，跟这个 provider 在进程级别就是独立的两条线（README.md:42, 115-117）。

**Q: env 是不是只放 ANTHROPIC_API_KEY？别的变量怎么传？**

A: 不是只能放 key，但请把 key 放在这里；父进程里任何被判定为凭证形态的环境变量在传给子进程前都会被 dsh-subprocess 剥掉。`PATH`、`HOME`、`ANTHROPIC_BASE_URL` 这种非凭证变量会被自然继承，要在 env 里显式覆盖也可以。DSH 这边不会创建账户、不会登录 Claude、不会改 settings 文件；登录态和有效 key 都得由 Claude 那一侧自己保证存在（README.md:42 / src/run.ts:321 / src/process.ts:30-38）。

**Q: 安装好之后，模型怎么才知道有 subagent_claude_code 这个工具？**

A: 并不知道，要靠你的 Agent Preset。full Preset 默认把对应的 tool 行设成 `disabled: true`，需要先复制 Preset 再去掉这一字段；起一个基于复制品的新 Session 时，模型才会看到那个静态工具名。每个 dsh-tool-subagent 行需要一个独立 toolName 暴露给模型，因此同 Profile 下挂多份 provider 时也要给每个工具起不同的名字（README.md:52）。

**Q: 子进程里跟 Claude 的设置文件是怎样生效的？**

A: 走原生 Claude settings 的相对路径，本包既不指定 `settingSources`，也不去 copy / 过滤它们的文件。所以在父会话的工作目录下会按 Claude 自家的 user / project / local 三层去找配置和登录态。也就是说你能在项目里放一份 `.claude/settings.json` 影响这个 provider，而卸载本包不会动到你这些文件（README.md:17 / README.md:144）。

**Q: 怎么从失败里看出到底是 SDK 报错还是子进程没起来？**

A: 看 `SubagentResult.diagnostic` 里的 `stage` 段：`query-start` 多半是 SDK / 平台包找不到、`query-run` 是跑着跑出错（比如 SDK 的四种错误子类型被显式保留成原名）、`process` 是 CLI 已经跑了但没正确出结果、`teardown` 是清理阶段 sub-process 退出失败。同时出现的 `exit code` / `signal` 行就是进程层的真实退出原因。原始的产品层或 Host 错误永远在 Error 的 cause 链里，不会直接进入这条 diagnostic（README.md:19 / src/run.ts:82-97, 540-568）。

**Q: 我能让一个工具实例同时支持 foreground 和后台跑吗？**

A: 可以，但需要分两个工具行。`dsh-tool-subagent` 的 `backgroundMode` 选 `one-shot` 时，省略 `run_in_background` 或传 `false` 走前台（同步阻塞）；传 `true` 则立刻返回一个由父 Agent 拥有的 Job id，配合 dsh-tool-jobs 提供的 `job_output` / `job_kill` 后续拉。前提是你的 Profile 已经装好本地作业服务（@deepseek-ai/dsh-jobs-local / dsh-tool-jobs）（README.md:52）。

## 上手难度
进阶 —— 需要先看懂 dsh 的 Profile Bundle 模型、cordis patch 注入顺序、dsh-tool-subagent 与 job 的接缝，并且要会自己配置 Claude 那边的 settings 和 key 才能让子进程跑通；如果只想"插上去就能用"会觉得整条链路偏长。

## 已知问题与限制
- 每次运行都新建一个 SDK query 和一个新 CLI 进程：不支持续接、resume、池化、进度流、产品会话持久化（README.md:141）
- 实例选择是静态的：Profile 行固定 provider 名与工具绑定；模型不能在调用时挑 provider，每个对外工具必须有唯一 `toolName`（README.md:142）
- 宿主 Claude settings 始终是权威：本包不提供"经过筛选或与宿主环境隔离"的生产模式，项目和用户层 settings 能改模型和工具（README.md:143）
- 认证与账户状态由 Claude 原生侧管理：本包不创建账户、不登录、不改 settings；配置或认证失败会以生命周期阶段 + `unknown` 回退报出来（README.md:144）
- 委派时必须有 SDK 平台载荷：可选依赖被跳过、平台不被支持、平台载荷缺失或损坏都会在首次 query 失败，不存在"宿主 CLI 回退"路径（README.md:145）
- 不存在人工交互通道：`AskUserQuestion` 已禁用，权限提示会被拒，MCP elicitation 会被拒，未声明的对话会快速失败不挂起（README.md:146 / src/run.ts:323-360）
- assistant 载荷仅含最终文本：推理 / 中间消息 / 工具调用 / 用量 / 进程 stderr / 工作区差异都留在 Claude 那侧；失败时按需多带一段独立安全诊断（README.md:147）
- 不支持可选共享能力：共享 subagent 服务会拒掉本 provider 的输出 schema、子角色、工具筛选、harness 深度强制（README.md:148）
- 没有按经过时长触发的超时或副作用回滚：调用方主动 abort 才会停；停之前子进程已经写过、改过、调过外部接口的状态不会被自动还原（README.md:149）

---

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/subagent/subagent-claude-code)
Wiki generated by AI (model: `MiniMax-M3`)
