# deepseek-harness-studio

> 让 DSH 在委托会话里一次性无人工地拉起官方 Codex 子代理：通过 app-server 协议把一条纯文本任务交给 Codex 跑并按严格成功条件回传最终答案。

## 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-codex
```

## Wiki

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

## 核心能力
- 在委托 Session 的工作目录里拉起官方 Codex 的 `app-server --stdio` 子进程，进程归 dsh-subprocess 的进程树统一管控（src/run.ts:236-249 / src/run.ts:185-217）
- 一次性文本任务：只接受非空纯文本块，Codex 必须返回带 `phase: "final_answer"` 的 agentMessage，没明确 final phase 时回退到最后一条 `phase: null` 的消息；空回答也会判为错误（README.md:11 / src/run.ts:162-177）
- 无人值守审批：命令/文件审批一律走 Codex 的 `thread/start` 配置，三种 `permissionMode` 都不会触发 DSH 交互；未知 server request 直接失败关闭（src/wire.ts:25-36, 86-94 / README.md:13）
- 失败带诊断：把 lifecycle 阶段（initialize / thread-start / turn-start / turn / process / teardown）、Codex 错误分类、HTTP 状态码、子进程退出码/信号拼成失败摘要，写到 `SubagentResult.diagnostic`（src/run.ts:84-114 / src/run.ts:358-365）
- 不继承父会话：明确 `inheritsParentContext: false`，父会话的对话、角色、工具过滤、深度策略都不会下发到子 Codex（src/index.ts:62 / README.md:21）
- 安装/卸载通过 Profile Bundle：安装才让宿主上多出一个休眠 provider，卸载后下次启动就连同其私有运行时一起撤回（README.md:44 / cordis.patch.yml:1-5）

## 技术实现
- **语言**: TypeScript（ESM，发布产物 `lib/index.js` 与 `lib/types/*.d.ts`，见 package.json:13-27）。
- **关键依赖**: `@openai/codex@0.147.0`（官方 SDK，含六个平台子包携带 app-server 2.1.220 的 JavaScript wrapper 与原生 `codex` 二进制）、`@deepseek-ai/dsh-subagent`（共享任务接缝与结果结算）、`@deepseek-ai/dsh-subprocess`（负责真 CLI 进程的进程树托管）、`@deepseek-ai/dsh-timeout`（`MAX_TIMER_DELAY_MS` 上限校验）（package.json:49-53 / src/run.ts:9-29 / src/index.ts:11）。
- **架构模式**: 函数插件 + Profile Bundle——`src/index.ts` 命名导出 `name`/`inject`/`Config`/`apply`；`apply(ctx, config)` 把一个 `CodexProvider` 注册到 `ctx.subagents`，由 `cordis.patch.yml` 顺势注入 dsh-base 之上。运行时通过 `createRequire` 解析 `@openai/codex/package.json` 的 `bin.codex`，用当前 Node 可执行文件拉起 wrapper；JSON-RPC 帧层由 `dsh-sdk-protocol` 提供，`wire.ts` 只负责产品方法、当前 thread/turn 关联、无人值守审批应答和最终答案选择（src/index.ts:30-32, 113-135 / cordis.patch.yml:1-5 / src/run.ts:43-52, 132-134 / src/wire.ts:9-14）。
- **入口文件**: `src/index.ts`（Cordis 注册入口）、`src/run.ts`（一次性任务生命周期与 run spec）、`src/wire.ts`（Codex app-server 0.147.0 协议适配器）。

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

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

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

## 配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `providerName` | 字符串（非空） | 在 `ctx.subagents` 上的注册名，同时给 dsh-tool-subagent 工具行的 `provider` 字段引用；同一个 Profile 挂多份实例时需要互不重复（src/index.ts:38, 51 / README.md:27）。 | `codex` |
| `env` | 对象（`Record<string, string>`） | 显式透传给 Codex app-server 子进程的环境变量，叠在父环境已被共享机制清掉凭证后的子集上；想让子进程拿到 `OPENAI_API_KEY` 时必须在这里显式声明（src/index.ts:43, 52 / src/run.ts:241 / README.md:42）。 | `{}` |
| `permissionMode` | 枚举：`never` / `approve-for-me` / `dangerously-bypass-approvals-and-sandbox` | 选定这个 provider 实例的 Codex 原生非交互权限与沙箱模式；`never` 表示不发审批请求、`approve-for-me` 走 Codex 自动评审、`dangerously-bypass-approvals-and-sandbox` 会同时关掉审批和沙箱（src/run.ts:55-68 / README.md:32-36）。 | `never` |
| `disposeGraceMs` | 数字（毫秒，正有限值） | 共享进程树主人在各终止 tier 之间的等待时长，随后要等到整棵进程树退出才算清场（src/index.ts:47, 55, 120-129 / src/run.ts:240）。 | `3000` |

## 常见问题
**Q: 跟直接接 Codex API 有什么区别？是不是更简单的接入？**

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

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

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

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

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

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

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

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

A: 看 `SubagentResult.diagnostic` 里的 `stage` 段：`initialize` / `thread-start` 多半是启动期问题（比如平台包找不到、载荷缺失），`turn-start` / `turn` 是 Codex 协议层出错，`process` 是 CLI 已经退出但没正常出结果，`teardown` 是清理阶段 sub-process 退出失败。同时出现的 `exit code` / `signal` 行就是进程层的真实退出原因；HTTP 状态码只在 Codex 提供时才会出现在诊断里。原始的产品层或 Host 错误永远在 Error 的 cause 链里，不会直接进入这条 diagnostic（src/run.ts:84-114, 358-365 / src/wire.ts）。

**Q: permissionMode 的三个值该怎么选？**

A: 不想弹任何审批框就用默认的 `never`，Codex 对没预先授权的操作会直接拒绝；想让 Codex 改文件但仍然不让它问人就把 `permissionMode` 换成 `approve-for-me`，这时 Codex 会走自动评审而不是 DSH 弹窗；`dangerously-bypass-approvals-and-sandbox` 是把原生审批与沙箱同时关掉，让 Codex 像脱缰一样能在任何路径下做任何事，原则上只在受控 / 沙箱环境里用。DSH 这边三种模式都不会创建交互通道，所有审批都走 Codex 自身的设置（README.md:34-40 / src/wire.ts:25-36）。

**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）。

**Q: 卸载这个包会不会带走什么副作用？**

A: 没有持久副作用。卸载后下一次 Profile 启动就把这个 provider 注销，本包没有任何独立磁盘写入或独立账户创建；登录态、Codex settings 文件、缓存都还在 Codex 那一侧独立保留（README.md:44 / README.md:144）。

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

## 已知问题与限制
- 每次运行都新建一个 app-server、一个 Codex 线程和一个 turn：不支持续接、resume、池化、进度流、产品会话持久化（README.md:135）
- 实例选择是静态的：Profile 行固定 provider 名与工具绑定；模型不能在调用时挑 provider，每个对外工具必须有唯一 `toolName`（README.md:136）
- 宿主 Codex settings 始终是权威：本包不提供"经过筛选或与宿主环境隔离"的生产模式，项目和用户层 settings 能改模型、provider、MCP、hook、skill 等（README.md:42, 137）
- 认证与账户状态由 Codex 原生侧管理：本包不创建账户、不登录、不改 settings；配置或认证失败会以生命周期阶段 + `unknown` 回退报出来（README.md:137）
- 委派时必须有 Codex 平台载荷：可选依赖被跳过、平台不被支持、平台载荷缺失或损坏都会在首次 `initialize` 失败，不存在"宿主 CLI 回退"路径（README.md:138 / src/run.ts:243-248）
- 兼容性由 0.147.0 协议基线锁定：升级 Codex 必须重新生成上游 schema 证据并重跑握手 / 答案选择 / 审批 / 取消 / 真实产品测试（README.md:139）
- 不存在人工审批路径：已知无人值守审批请求会被拒绝，未知 server request 会以默认拒绝方式让运行失败；三种 `permissionMode` 都不会创建 DSH 交互通道或逐次调用 allow 策略（README.md:140 / src/wire.ts:38-51）
- assistant 载荷仅含最终文本：推理 / 过程说明 / 中间消息 / 工具调用 / 用量 / 进程 stderr / 工作区差异都不会进入父会话；失败时按需多带一段独立安全诊断（README.md:141）
- 不支持可选共享能力：共享 subagent 服务会拒掉本 provider 的输出 schema、子角色、工具筛选、harness 深度强制（README.md:142）
- 没有按经过时长触发的超时或副作用回滚：调用方主动 abort 才会停；停之前子进程已经写过、改过、调过外部接口的状态不会被自动还原（README.md:143）

---

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-codex)
Wiki generated by AI (model: `MiniMax-M3`)
