v0.10: add automated Codex orchestration and deployment check
This commit is contained in:
@@ -0,0 +1,77 @@
|
|||||||
|
# Codex Command: dr-run
|
||||||
|
|
||||||
|
You are the Deep Research PM main thread for `/dr-run $ARGUMENTS`.
|
||||||
|
|
||||||
|
This command is the Codex equivalent of letting `dr-pm` own orchestration. Do not ask the user to run each phase manually. Inspect the project state, continue from the correct phase, spawn the required Codex custom agents, wait for their results, and only pause at the defined human decision gates.
|
||||||
|
|
||||||
|
## Resolve Target
|
||||||
|
|
||||||
|
1. Treat `$ARGUMENTS` as either a project slug/path or a new research topic.
|
||||||
|
2. If it matches an existing project, load `projects/<slug>/manifest.json` and continue from its current status.
|
||||||
|
3. If it is a new topic, run Phase 1 initialization and create the project structure before planning.
|
||||||
|
4. If `$ARGUMENTS` is empty, use the most recently modified project and confirm the inferred slug in your first status update.
|
||||||
|
|
||||||
|
## Global Rules
|
||||||
|
|
||||||
|
- Follow `AGENTS.md`, all relevant `.agents/skills/*/SKILL.md`, and the project `manifest.json`.
|
||||||
|
- Keep `projects/**` research artifacts out of system commits unless the user explicitly asks to commit research output.
|
||||||
|
- Use Codex subagents deliberately: spawn them when parallel work materially advances the phase, wait for results, and consolidate before moving on.
|
||||||
|
- Do not simulate subagent work in the main thread when the task calls for independent review, chapter research, or counter-evidence.
|
||||||
|
- Respect the required pause gates:
|
||||||
|
- Stop after Phase 1 framework is ready and ask the user to approve or revise it.
|
||||||
|
- Stop after Phase 3 critique is ready and ask whether to fix, rerun Phase 2, or restart.
|
||||||
|
- Ask for approval before expensive broad web searches, long-running external API work, or irreversible file operations.
|
||||||
|
|
||||||
|
## Phase 1: Framework Planning
|
||||||
|
|
||||||
|
Run this phase when there is no approved `phase1/framework.md`.
|
||||||
|
|
||||||
|
1. Spawn `dr-plan` to interview the user if the topic is underspecified.
|
||||||
|
2. Spawn `dr-searcher` workers in parallel for initial source discovery across scientific, regulatory, clinical, commercial, and patent angles.
|
||||||
|
3. Have `dr-plan` synthesize a MECE framework with chapter-level word budgets and source strategy.
|
||||||
|
4. Write `phase1/interview.md`, `phase1/initial-scan.md`, and `phase1/framework.md`.
|
||||||
|
5. Update `manifest.json` and stop for user framework approval.
|
||||||
|
|
||||||
|
## Phase 2: Deep Research
|
||||||
|
|
||||||
|
Run this phase when `phase1.approved == true` and Phase 2 is incomplete.
|
||||||
|
|
||||||
|
1. Act as `dr-pm`: parse `phase1/framework.md`, create chapter batches, and keep the main thread focused on orchestration.
|
||||||
|
2. Spawn `dr-analyst` subagents in parallel, one per chapter or chapter group depending on size.
|
||||||
|
3. Require each analyst to write English chapter drafts plus evidence matrices.
|
||||||
|
4. After analyst outputs are present, spawn independent `dr-verifier` subagents for counter-evidence and source-quality checks.
|
||||||
|
5. Reconcile verifier findings into the relevant evidence files and chapter TODOs.
|
||||||
|
6. Deduplicate and normalize `phase2/sources.jsonl`.
|
||||||
|
7. Update `manifest.json` and continue to Phase 3 unless the evidence base is materially inadequate.
|
||||||
|
|
||||||
|
## Phase 3: Chief Editor Review
|
||||||
|
|
||||||
|
Run this phase when Phase 2 is complete and Phase 3 is incomplete.
|
||||||
|
|
||||||
|
1. Spawn `dr-chief-editor` as a read-only reviewer.
|
||||||
|
2. Have it assess MECE structure, evidence sufficiency, unsupported claims, source quality, chapter balance, and executive-level narrative.
|
||||||
|
3. Write `phase3/critique.md`.
|
||||||
|
4. Stop for user decision: targeted fix, rerun Phase 2 for weak chapters, or restart framework.
|
||||||
|
|
||||||
|
## Phase 4: Finalization
|
||||||
|
|
||||||
|
Run this phase only after the user approves Phase 3.
|
||||||
|
|
||||||
|
1. Spawn `dr-editor-in-chief` to merge English drafts into `phase4/final_en.md`, Executive Summary, Abstract, and glossary seed.
|
||||||
|
2. Run the deterministic pipeline with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python scripts/dr.py finalize <slug>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. If needed, spawn `dr-reporter` for final PDF/DOCX validation and citation backfill checks.
|
||||||
|
4. Report final artifact paths and remaining risks.
|
||||||
|
|
||||||
|
## Status Discipline
|
||||||
|
|
||||||
|
Give concise progress updates after each phase or batch. Always say:
|
||||||
|
|
||||||
|
- current phase
|
||||||
|
- agents spawned and why
|
||||||
|
- files produced or changed
|
||||||
|
- whether the workflow is continuing or waiting for user decision
|
||||||
+22
-16
@@ -1,13 +1,13 @@
|
|||||||
profile = "deep-research"
|
|
||||||
model = "gpt-5.4"
|
model = "gpt-5.4"
|
||||||
model_reasoning_effort = "high"
|
model_reasoning_effort = "high"
|
||||||
sandbox_mode = "workspace-write"
|
sandbox_mode = "workspace-write"
|
||||||
approval_policy = "on-request"
|
approval_policy = "never"
|
||||||
project_doc_max_bytes = 65536
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
[tools]
|
|
||||||
web_search = "live"
|
web_search = "live"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
multi_agent = true
|
||||||
|
|
||||||
[agents]
|
[agents]
|
||||||
max_threads = 6
|
max_threads = 6
|
||||||
max_depth = 1
|
max_depth = 1
|
||||||
@@ -16,46 +16,52 @@ max_depth = 1
|
|||||||
model = "gpt-5.4"
|
model = "gpt-5.4"
|
||||||
model_reasoning_effort = "high"
|
model_reasoning_effort = "high"
|
||||||
sandbox_mode = "workspace-write"
|
sandbox_mode = "workspace-write"
|
||||||
approval_policy = "on-request"
|
approval_policy = "never"
|
||||||
project_doc_max_bytes = 65536
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
[profiles.deep-research.tools]
|
|
||||||
web_search = "live"
|
web_search = "live"
|
||||||
|
|
||||||
[profiles.deep-research-fast]
|
[profiles.deep-research-fast]
|
||||||
model = "gpt-5.4-mini"
|
model = "gpt-5.4-mini"
|
||||||
model_reasoning_effort = "medium"
|
model_reasoning_effort = "medium"
|
||||||
sandbox_mode = "workspace-write"
|
sandbox_mode = "workspace-write"
|
||||||
approval_policy = "on-request"
|
approval_policy = "never"
|
||||||
project_doc_max_bytes = 65536
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
[profiles.deep-research-fast.tools]
|
|
||||||
web_search = "live"
|
web_search = "live"
|
||||||
|
|
||||||
[profiles.deep-research-review]
|
[profiles.deep-research-review]
|
||||||
model = "gpt-5.4"
|
model = "gpt-5.4"
|
||||||
model_reasoning_effort = "xhigh"
|
model_reasoning_effort = "xhigh"
|
||||||
sandbox_mode = "workspace-write"
|
sandbox_mode = "workspace-write"
|
||||||
approval_policy = "on-request"
|
approval_policy = "never"
|
||||||
project_doc_max_bytes = 65536
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
[profiles.deep-research-review.tools]
|
|
||||||
web_search = "live"
|
web_search = "live"
|
||||||
|
|
||||||
[mcp_servers.openaiDeveloperDocs]
|
[mcp_servers.openaiDeveloperDocs]
|
||||||
url = "https://developers.openai.com/mcp"
|
url = "https://developers.openai.com/mcp"
|
||||||
|
|
||||||
|
[mcp_servers.openaiDeveloperDocs.tools.fetch_openai_doc]
|
||||||
|
approval_mode = "approve"
|
||||||
|
|
||||||
[mcp_servers.tavily]
|
[mcp_servers.tavily]
|
||||||
command = "npx"
|
command = "npx"
|
||||||
args = ["-y", "tavily-mcp@latest"]
|
args = ["-y", "tavily-mcp@latest"]
|
||||||
env = { TAVILY_API_KEY = "${TAVILY_API_KEY}" }
|
env_vars = ["TAVILY_API_KEY"]
|
||||||
|
enabled = true
|
||||||
|
required = false
|
||||||
|
|
||||||
[mcp_servers.brave_search]
|
[mcp_servers.brave_search]
|
||||||
command = "npx"
|
command = "npx"
|
||||||
args = ["-y", "@modelcontextprotocol/server-brave-search"]
|
args = ["-y", "@modelcontextprotocol/server-brave-search"]
|
||||||
env = { BRAVE_API_KEY = "${BRAVE_API_KEY}" }
|
env_vars = ["BRAVE_API_KEY"]
|
||||||
|
enabled = true
|
||||||
|
required = false
|
||||||
|
|
||||||
[mcp_servers.exa]
|
[mcp_servers.exa]
|
||||||
command = "npx"
|
command = "npx"
|
||||||
args = ["-y", "exa-mcp-server"]
|
args = ["-y", "exa-mcp-server"]
|
||||||
env = { EXA_API_KEY = "${EXA_API_KEY}" }
|
env_vars = ["EXA_API_KEY"]
|
||||||
|
enabled = true
|
||||||
|
required = false
|
||||||
|
|
||||||
|
[sandbox_workspace_write]
|
||||||
|
network_access = true
|
||||||
|
|||||||
@@ -529,16 +529,20 @@ OpenCode 的坑:如果只是在主会话里装样子地写"让 X agent 做",
|
|||||||
**已落地的共享层**:
|
**已落地的共享层**:
|
||||||
- 新增 `scripts/dr.py` 平台无关 CLI:支持 `status`、`prompt`、`glossary`、`finalize`。
|
- 新增 `scripts/dr.py` 平台无关 CLI:支持 `status`、`prompt`、`glossary`、`finalize`。
|
||||||
- 新增 `scripts/install_codex_adapter.py`:从 `codex_adapter_templates/codex/**` 安装 `.codex/**`,并把 `.opencode/skills/**` 复制到 `.agents/skills/**`。
|
- 新增 `scripts/install_codex_adapter.py`:从 `codex_adapter_templates/codex/**` 安装 `.codex/**`,并把 `.opencode/skills/**` 复制到 `.agents/skills/**`。
|
||||||
- 新增 `codex_adapter_templates/codex/**`:包含 Codex 项目配置、8 个 custom agents 和 7 个命令模板。
|
- 新增 `scripts/deploy_check.py`:新环境部署自检;必要时用 `--repair --force` 从模板重建 `.codex/**` 并同步 `.agents/skills/**`。
|
||||||
|
- 新增 `codex_adapter_templates/codex/**`:包含 Codex 项目配置、8 个 custom agents 和命令模板;`dr-run` 是主入口,用 Codex 主线程承担 PM 调度,阶段命令只作为调试和人工接管入口。
|
||||||
- `configs/model_profiles.yaml` 新增 `codex_native` profile,使用 OpenAI 原生 `gpt-5.4` / `gpt-5.4-mini` 角色映射。
|
- `configs/model_profiles.yaml` 新增 `codex_native` profile,使用 OpenAI 原生 `gpt-5.4` / `gpt-5.4-mini` 角色映射。
|
||||||
- `docs/codex-usage.md` 重写为 Codex native adapter 使用说明。
|
- `docs/codex-usage.md` 重写为 Codex native adapter 使用说明。
|
||||||
|
|
||||||
**设计约定**:
|
**设计约定**:
|
||||||
- Codex 默认走 OpenAI 原生模型,不依赖 ZenMux provider。
|
- Codex 默认走 OpenAI 原生模型,不依赖 ZenMux provider。
|
||||||
- Phase 1-3 由 Codex custom agents + command prompt 执行;Phase 4 由 `scripts/dr.py finalize` 调确定性 Python 流水线。
|
- Codex 不会因 custom agent 文件存在而自动启动 subagent;`dr-run` prompt 必须明确要求主线程 spawn / wait / consolidate。
|
||||||
|
- Phase 1-3 由 `dr-run` 主线程调度 Codex custom agents 执行;Phase 4 由 `scripts/dr.py finalize` 调确定性 Python 流水线。
|
||||||
- `.opencode/**` 不改不删,避免破坏 OpenCode 已可用流程。
|
- `.opencode/**` 不改不删,避免破坏 OpenCode 已可用流程。
|
||||||
- `.opencode/skills` 将复制到 `.agents/skills`,而非软链接,以保证 Git 与跨机器可移植。
|
- `.opencode/skills` 将复制到 `.agents/skills`,而非软链接,以保证 Git 与跨机器可移植。
|
||||||
|
|
||||||
**安装方式**:
|
**安装方式**:
|
||||||
- 在本机运行 `uv run python scripts/install_codex_adapter.py --force`。
|
- 在本机运行 `uv run python scripts/install_codex_adapter.py --force`。
|
||||||
- 安装后运行 `/debug-config` 确认 `.codex/config.toml` 被 Codex 加载。
|
- 安装后运行 `/debug-config` 确认 `.codex/config.toml` 被 Codex 加载。
|
||||||
|
- 自动化研究默认权限:`sandbox_mode = "workspace-write"`、`approval_policy = "never"`、`web_search = "live"`、`sandbox_workspace_write.network_access = true`。
|
||||||
|
- Tavily / Brave / Exa MCP server 在模板中默认 `enabled = true` 且 `required = false`;确认本机 key、npm 与网络可用可直接使用,某个服务异常时再单独关闭。
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ uv run python scripts/build_report.py <slug>
|
|||||||
### 多平台兼容
|
### 多平台兼容
|
||||||
|
|
||||||
- OpenCode:主适配器,使用 `.opencode/agents` 与 `.opencode/commands`。
|
- OpenCode:主适配器,使用 `.opencode/agents` 与 `.opencode/commands`。
|
||||||
- Codex:native adapter,目标是使用 `.codex/config.toml`、`.codex/agents`、`.codex/commands`、`.agents/skills` 与 `scripts/dr.py` 独立运行;详见 `docs/codex-usage.md`。
|
- Codex:native adapter,使用 `.codex/config.toml`、`.codex/agents`、`.codex/commands`、`.agents/skills` 与 `scripts/dr.py` 独立运行;主入口是 `dr-run`,由 Codex 主线程承担 PM 调度并主动 spawn subagents,详见 `docs/codex-usage.md`。
|
||||||
- Gemini CLI / Claude Code:暂不做强适配,后续以同一套脚本与配置为基础扩展。
|
- Gemini CLI / Claude Code:暂不做强适配,后续以同一套脚本与配置为基础扩展。
|
||||||
|
|
||||||
安装 Codex adapter:
|
安装 Codex adapter:
|
||||||
@@ -177,6 +177,21 @@ uv run python scripts/build_report.py <slug>
|
|||||||
uv run python scripts/install_codex_adapter.py --force
|
uv run python scripts/install_codex_adapter.py --force
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Codex adapter 默认面向自动化研究:workspace 可写、命令不逐次审批、实时 web search 与脚本网络访问开启;Tavily / Brave / Exa MCP 会默认启用但不设为必需服务。
|
||||||
|
|
||||||
|
部署到新环境后自检:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python scripts/deploy_check.py
|
||||||
|
uv run python scripts/deploy_check.py --repair --force
|
||||||
|
```
|
||||||
|
|
||||||
|
运行 Codex 总调度:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codex exec "$(uv run python scripts/dr.py prompt dr-run <slug-or-topic>)"
|
||||||
|
```
|
||||||
|
|
||||||
模型与搜索 API 选择见:
|
模型与搜索 API 选择见:
|
||||||
- `docs/model-playbook.md`
|
- `docs/model-playbook.md`
|
||||||
- `docs/search-playbook.md`
|
- `docs/search-playbook.md`
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# Codex Command: dr-run
|
||||||
|
|
||||||
|
You are the Deep Research PM main thread for `/dr-run $ARGUMENTS`.
|
||||||
|
|
||||||
|
This command is the Codex equivalent of letting `dr-pm` own orchestration. Do not ask the user to run each phase manually. Inspect the project state, continue from the correct phase, spawn the required Codex custom agents, wait for their results, and only pause at the defined human decision gates.
|
||||||
|
|
||||||
|
## Resolve Target
|
||||||
|
|
||||||
|
1. Treat `$ARGUMENTS` as either a project slug/path or a new research topic.
|
||||||
|
2. If it matches an existing project, load `projects/<slug>/manifest.json` and continue from its current status.
|
||||||
|
3. If it is a new topic, run Phase 1 initialization and create the project structure before planning.
|
||||||
|
4. If `$ARGUMENTS` is empty, use the most recently modified project and confirm the inferred slug in your first status update.
|
||||||
|
|
||||||
|
## Global Rules
|
||||||
|
|
||||||
|
- Follow `AGENTS.md`, all relevant `.agents/skills/*/SKILL.md`, and the project `manifest.json`.
|
||||||
|
- Keep `projects/**` research artifacts out of system commits unless the user explicitly asks to commit research output.
|
||||||
|
- Use Codex subagents deliberately: spawn them when parallel work materially advances the phase, wait for results, and consolidate before moving on.
|
||||||
|
- Do not simulate subagent work in the main thread when the task calls for independent review, chapter research, or counter-evidence.
|
||||||
|
- Respect the required pause gates:
|
||||||
|
- Stop after Phase 1 framework is ready and ask the user to approve or revise it.
|
||||||
|
- Stop after Phase 3 critique is ready and ask whether to fix, rerun Phase 2, or restart.
|
||||||
|
- Ask for approval before expensive broad web searches, long-running external API work, or irreversible file operations.
|
||||||
|
|
||||||
|
## Phase 1: Framework Planning
|
||||||
|
|
||||||
|
Run this phase when there is no approved `phase1/framework.md`.
|
||||||
|
|
||||||
|
1. Spawn `dr-plan` to interview the user if the topic is underspecified.
|
||||||
|
2. Spawn `dr-searcher` workers in parallel for initial source discovery across scientific, regulatory, clinical, commercial, and patent angles.
|
||||||
|
3. Have `dr-plan` synthesize a MECE framework with chapter-level word budgets and source strategy.
|
||||||
|
4. Write `phase1/interview.md`, `phase1/initial-scan.md`, and `phase1/framework.md`.
|
||||||
|
5. Update `manifest.json` and stop for user framework approval.
|
||||||
|
|
||||||
|
## Phase 2: Deep Research
|
||||||
|
|
||||||
|
Run this phase when `phase1.approved == true` and Phase 2 is incomplete.
|
||||||
|
|
||||||
|
1. Act as `dr-pm`: parse `phase1/framework.md`, create chapter batches, and keep the main thread focused on orchestration.
|
||||||
|
2. Spawn `dr-analyst` subagents in parallel, one per chapter or chapter group depending on size.
|
||||||
|
3. Require each analyst to write English chapter drafts plus evidence matrices.
|
||||||
|
4. After analyst outputs are present, spawn independent `dr-verifier` subagents for counter-evidence and source-quality checks.
|
||||||
|
5. Reconcile verifier findings into the relevant evidence files and chapter TODOs.
|
||||||
|
6. Deduplicate and normalize `phase2/sources.jsonl`.
|
||||||
|
7. Update `manifest.json` and continue to Phase 3 unless the evidence base is materially inadequate.
|
||||||
|
|
||||||
|
## Phase 3: Chief Editor Review
|
||||||
|
|
||||||
|
Run this phase when Phase 2 is complete and Phase 3 is incomplete.
|
||||||
|
|
||||||
|
1. Spawn `dr-chief-editor` as a read-only reviewer.
|
||||||
|
2. Have it assess MECE structure, evidence sufficiency, unsupported claims, source quality, chapter balance, and executive-level narrative.
|
||||||
|
3. Write `phase3/critique.md`.
|
||||||
|
4. Stop for user decision: targeted fix, rerun Phase 2 for weak chapters, or restart framework.
|
||||||
|
|
||||||
|
## Phase 4: Finalization
|
||||||
|
|
||||||
|
Run this phase only after the user approves Phase 3.
|
||||||
|
|
||||||
|
1. Spawn `dr-editor-in-chief` to merge English drafts into `phase4/final_en.md`, Executive Summary, Abstract, and glossary seed.
|
||||||
|
2. Run the deterministic pipeline with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python scripts/dr.py finalize <slug>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. If needed, spawn `dr-reporter` for final PDF/DOCX validation and citation backfill checks.
|
||||||
|
4. Report final artifact paths and remaining risks.
|
||||||
|
|
||||||
|
## Status Discipline
|
||||||
|
|
||||||
|
Give concise progress updates after each phase or batch. Always say:
|
||||||
|
|
||||||
|
- current phase
|
||||||
|
- agents spawned and why
|
||||||
|
- files produced or changed
|
||||||
|
- whether the workflow is continuing or waiting for user decision
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
profile = "deep-research"
|
|
||||||
model = "gpt-5.4"
|
model = "gpt-5.4"
|
||||||
model_reasoning_effort = "high"
|
model_reasoning_effort = "high"
|
||||||
sandbox_mode = "workspace-write"
|
sandbox_mode = "workspace-write"
|
||||||
approval_policy = "on-request"
|
approval_policy = "never"
|
||||||
project_doc_max_bytes = 65536
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
[tools]
|
|
||||||
web_search = "live"
|
web_search = "live"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
multi_agent = true
|
||||||
|
|
||||||
[agents]
|
[agents]
|
||||||
max_threads = 6
|
max_threads = 6
|
||||||
max_depth = 1
|
max_depth = 1
|
||||||
@@ -16,46 +16,52 @@ max_depth = 1
|
|||||||
model = "gpt-5.4"
|
model = "gpt-5.4"
|
||||||
model_reasoning_effort = "high"
|
model_reasoning_effort = "high"
|
||||||
sandbox_mode = "workspace-write"
|
sandbox_mode = "workspace-write"
|
||||||
approval_policy = "on-request"
|
approval_policy = "never"
|
||||||
project_doc_max_bytes = 65536
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
[profiles.deep-research.tools]
|
|
||||||
web_search = "live"
|
web_search = "live"
|
||||||
|
|
||||||
[profiles.deep-research-fast]
|
[profiles.deep-research-fast]
|
||||||
model = "gpt-5.4-mini"
|
model = "gpt-5.4-mini"
|
||||||
model_reasoning_effort = "medium"
|
model_reasoning_effort = "medium"
|
||||||
sandbox_mode = "workspace-write"
|
sandbox_mode = "workspace-write"
|
||||||
approval_policy = "on-request"
|
approval_policy = "never"
|
||||||
project_doc_max_bytes = 65536
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
[profiles.deep-research-fast.tools]
|
|
||||||
web_search = "live"
|
web_search = "live"
|
||||||
|
|
||||||
[profiles.deep-research-review]
|
[profiles.deep-research-review]
|
||||||
model = "gpt-5.4"
|
model = "gpt-5.4"
|
||||||
model_reasoning_effort = "xhigh"
|
model_reasoning_effort = "xhigh"
|
||||||
sandbox_mode = "workspace-write"
|
sandbox_mode = "workspace-write"
|
||||||
approval_policy = "on-request"
|
approval_policy = "never"
|
||||||
project_doc_max_bytes = 65536
|
project_doc_max_bytes = 65536
|
||||||
|
|
||||||
[profiles.deep-research-review.tools]
|
|
||||||
web_search = "live"
|
web_search = "live"
|
||||||
|
|
||||||
[mcp_servers.openaiDeveloperDocs]
|
[mcp_servers.openaiDeveloperDocs]
|
||||||
url = "https://developers.openai.com/mcp"
|
url = "https://developers.openai.com/mcp"
|
||||||
|
|
||||||
|
[mcp_servers.openaiDeveloperDocs.tools.fetch_openai_doc]
|
||||||
|
approval_mode = "approve"
|
||||||
|
|
||||||
[mcp_servers.tavily]
|
[mcp_servers.tavily]
|
||||||
command = "npx"
|
command = "npx"
|
||||||
args = ["-y", "tavily-mcp@latest"]
|
args = ["-y", "tavily-mcp@latest"]
|
||||||
env = { TAVILY_API_KEY = "${TAVILY_API_KEY}" }
|
env_vars = ["TAVILY_API_KEY"]
|
||||||
|
enabled = true
|
||||||
|
required = false
|
||||||
|
|
||||||
[mcp_servers.brave_search]
|
[mcp_servers.brave_search]
|
||||||
command = "npx"
|
command = "npx"
|
||||||
args = ["-y", "@modelcontextprotocol/server-brave-search"]
|
args = ["-y", "@modelcontextprotocol/server-brave-search"]
|
||||||
env = { BRAVE_API_KEY = "${BRAVE_API_KEY}" }
|
env_vars = ["BRAVE_API_KEY"]
|
||||||
|
enabled = true
|
||||||
|
required = false
|
||||||
|
|
||||||
[mcp_servers.exa]
|
[mcp_servers.exa]
|
||||||
command = "npx"
|
command = "npx"
|
||||||
args = ["-y", "exa-mcp-server"]
|
args = ["-y", "exa-mcp-server"]
|
||||||
env = { EXA_API_KEY = "${EXA_API_KEY}" }
|
env_vars = ["EXA_API_KEY"]
|
||||||
|
enabled = true
|
||||||
|
required = false
|
||||||
|
|
||||||
|
[sandbox_workspace_write]
|
||||||
|
network_access = true
|
||||||
|
|||||||
+57
-4
@@ -36,16 +36,42 @@ find .agents/skills -maxdepth 2 -name SKILL.md | sort
|
|||||||
uv run python scripts/dr.py status <slug>
|
uv run python scripts/dr.py status <slug>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
新机器部署后可以先跑自检:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python scripts/deploy_check.py
|
||||||
|
```
|
||||||
|
|
||||||
|
如果隐藏目录缺失或 skills 没同步:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python scripts/deploy_check.py --repair --force
|
||||||
|
```
|
||||||
|
|
||||||
|
默认自动化权限:
|
||||||
|
|
||||||
|
- `sandbox_mode = "workspace-write"`:允许写入当前研究 workspace。
|
||||||
|
- `approval_policy = "never"`:命令执行不逐次弹窗。
|
||||||
|
- `web_search = "live"`:默认使用实时网络检索。
|
||||||
|
- `[sandbox_workspace_write].network_access = true`:脚本和 MCP server 默认可访问网络。
|
||||||
|
- Tavily / Brave / Exa MCP 默认启用,且 `required = false`,某个搜索服务临时不可用时不阻塞 Codex 主流程。
|
||||||
|
|
||||||
## Codex Commands
|
## Codex Commands
|
||||||
|
|
||||||
Codex custom command templates 位于 `.codex/commands/`。在 CLI 中可以用 `scripts/dr.py prompt` 展开:
|
Codex custom command templates 位于 `.codex/commands/`。在 CLI 中可以用 `scripts/dr.py prompt` 展开:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
uv run python scripts/dr.py prompt dr-frame dual-target-rnai-pipeline-2026
|
uv run python scripts/dr.py prompt dr-run dual-target-rnai-pipeline-2026
|
||||||
codex exec "$(uv run python scripts/dr.py prompt dr-frame dual-target-rnai-pipeline-2026)"
|
codex exec "$(uv run python scripts/dr.py prompt dr-run dual-target-rnai-pipeline-2026)"
|
||||||
```
|
```
|
||||||
|
|
||||||
建议流程:
|
推荐入口是 `dr-run`:让 Codex 主线程进入 PM 模式,读取 manifest,判断当前应该继续哪个 phase,并在 Phase 2 主动调度 `dr-analyst` / `dr-verifier` subagents。用户不需要逐个执行每个 phase;只有 Phase 1 框架确认和 Phase 3 审校决策这类人类暂停点需要停下来。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codex exec "$(uv run python scripts/dr.py prompt dr-run <slug-or-topic>)"
|
||||||
|
```
|
||||||
|
|
||||||
|
分阶段命令保留为调试和人工接管入口:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codex exec "$(uv run python scripts/dr.py prompt dr-init '<topic>')"
|
codex exec "$(uv run python scripts/dr.py prompt dr-init '<topic>')"
|
||||||
@@ -75,7 +101,7 @@ uv run python scripts/dr.py finalize <slug> \
|
|||||||
|
|
||||||
## Subagent Usage
|
## Subagent Usage
|
||||||
|
|
||||||
Codex subagents 不会自动启动;主线程必须明确要求。例如:
|
Codex 的平台限制是:subagents 不会仅因为 `.codex/agents/*.toml` 存在就自动启动,必须由当前主线程明确要求。`dr-run` 已把这个要求写进 PM prompt:Phase 1 会调度 `dr-plan` / `dr-searcher`,Phase 2 会调度 `dr-analyst` / `dr-verifier`,Phase 3 会调度 `dr-chief-editor`。
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Spawn dr-searcher agents in parallel for four keyword groups, wait for all results, then synthesize phase1/initial-scan.md.
|
Spawn dr-searcher agents in parallel for four keyword groups, wait for all results, then synthesize phase1/initial-scan.md.
|
||||||
@@ -121,3 +147,30 @@ uv run python scripts/install_codex_adapter.py --force
|
|||||||
- `.opencode/skills/**` → `.agents/skills/**`
|
- `.opencode/skills/**` → `.agents/skills/**`
|
||||||
|
|
||||||
安装后,在 Codex 中运行 `/debug-config`,确认 project `.codex/config.toml` 已加载。
|
安装后,在 Codex 中运行 `/debug-config`,确认 project `.codex/config.toml` 已加载。
|
||||||
|
|
||||||
|
## Config Troubleshooting
|
||||||
|
|
||||||
|
如果 `.codex/config.toml` 生效后启动报错,先按下面顺序排查:
|
||||||
|
|
||||||
|
1. 确认当前 project 已被 Codex trust。未 trust 时,Codex 会跳过项目级 `.codex/**`,此时 `--profile deep-research` 会报 profile 不存在。
|
||||||
|
2. Tavily / Brave / Exa MCP 默认启用但不是 required。若某个 server 启动异常,先确认对应环境变量存在,再临时把该 server 改成 `enabled = false`。
|
||||||
|
3. 如果要完全离线排障,先把第三方 MCP 全部关掉,只保留 OpenAI Docs MCP 和内置 web search。
|
||||||
|
4. 如果仍然报错,临时保留最小配置确认 Codex 主体能启动:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
model = "gpt-5.4"
|
||||||
|
model_reasoning_effort = "high"
|
||||||
|
sandbox_mode = "workspace-write"
|
||||||
|
approval_policy = "never"
|
||||||
|
project_doc_max_bytes = 65536
|
||||||
|
web_search = "live"
|
||||||
|
|
||||||
|
[agents]
|
||||||
|
max_threads = 6
|
||||||
|
max_depth = 1
|
||||||
|
|
||||||
|
[sandbox_workspace_write]
|
||||||
|
network_access = true
|
||||||
|
```
|
||||||
|
|
||||||
|
这个最小配置只启用模型、沙盒、项目说明、web search 与 subagent 上限;确认能启动后,再逐个恢复 profiles 和 MCP server。
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Check and repair a Deep Research deployment checkout."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
try:
|
||||||
|
import tomllib
|
||||||
|
except ModuleNotFoundError: # pragma: no cover - Python < 3.11 fallback.
|
||||||
|
tomllib = None # type: ignore[assignment]
|
||||||
|
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
CODEX_TEMPLATE = REPO_ROOT / "codex_adapter_templates" / "codex"
|
||||||
|
CODEX_ROOT = REPO_ROOT / ".codex"
|
||||||
|
OPENCODE_ROOT = REPO_ROOT / ".opencode"
|
||||||
|
AGENTS_SKILLS = REPO_ROOT / ".agents" / "skills"
|
||||||
|
OPENCODE_SKILLS = OPENCODE_ROOT / "skills"
|
||||||
|
|
||||||
|
REQUIRED_PATHS = [
|
||||||
|
"AGENTS.md",
|
||||||
|
"README.md",
|
||||||
|
"PLAN.md",
|
||||||
|
".opencode/opencode.json",
|
||||||
|
".codex/config.toml",
|
||||||
|
".codex/agents/dr-pm.toml",
|
||||||
|
".codex/commands/dr-run.md",
|
||||||
|
".agents/skills/search-strategy/SKILL.md",
|
||||||
|
"scripts/dr.py",
|
||||||
|
"scripts/install_codex_adapter.py",
|
||||||
|
]
|
||||||
|
|
||||||
|
REQUIRED_ENV_KEYS = [
|
||||||
|
"ZENMUX_API_KEY",
|
||||||
|
"TAVILY_API_KEY",
|
||||||
|
"BRAVE_API_KEY",
|
||||||
|
"EXA_API_KEY",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def rel(path: Path) -> str:
|
||||||
|
return str(path.relative_to(REPO_ROOT))
|
||||||
|
|
||||||
|
|
||||||
|
def copy_tree_contents(src: Path, dst: Path, *, force: bool) -> list[Path]:
|
||||||
|
written: list[Path] = []
|
||||||
|
if not src.exists():
|
||||||
|
raise RuntimeError(f"source not found: {rel(src)}")
|
||||||
|
dst.mkdir(parents=True, exist_ok=True)
|
||||||
|
for item in src.rglob("*"):
|
||||||
|
target = dst / item.relative_to(src)
|
||||||
|
if item.is_dir():
|
||||||
|
target.mkdir(parents=True, exist_ok=True)
|
||||||
|
continue
|
||||||
|
if target.exists() and not force:
|
||||||
|
continue
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copy2(item, target)
|
||||||
|
written.append(target)
|
||||||
|
return written
|
||||||
|
|
||||||
|
|
||||||
|
def parse_env(path: Path) -> dict[str, str]:
|
||||||
|
values: dict[str, str] = {}
|
||||||
|
if not path.exists():
|
||||||
|
return values
|
||||||
|
for raw in path.read_text(encoding="utf-8").splitlines():
|
||||||
|
line = raw.strip()
|
||||||
|
if not line or line.startswith("#") or "=" not in line:
|
||||||
|
continue
|
||||||
|
key, value = line.split("=", 1)
|
||||||
|
values[key.strip()] = value.strip().strip('"').strip("'")
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
def git_tracked(paths: list[str]) -> set[str]:
|
||||||
|
proc = subprocess.run(
|
||||||
|
["git", "ls-files", *paths],
|
||||||
|
cwd=REPO_ROOT,
|
||||||
|
text=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.DEVNULL,
|
||||||
|
check=False,
|
||||||
|
)
|
||||||
|
return set(proc.stdout.splitlines())
|
||||||
|
|
||||||
|
|
||||||
|
def check_toml(path: Path, issues: list[str]) -> None:
|
||||||
|
if not path.exists():
|
||||||
|
return
|
||||||
|
if tomllib is None:
|
||||||
|
issues.append("Python tomllib unavailable; skip TOML parse checks")
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
tomllib.loads(path.read_text(encoding="utf-8"))
|
||||||
|
except Exception as exc: # noqa: BLE001 - deployment diagnostics.
|
||||||
|
issues.append(f"{rel(path)} TOML parse failed: {exc}")
|
||||||
|
|
||||||
|
|
||||||
|
def check_deployment() -> int:
|
||||||
|
issues: list[str] = []
|
||||||
|
warnings: list[str] = []
|
||||||
|
|
||||||
|
for item in REQUIRED_PATHS:
|
||||||
|
if not (REPO_ROOT / item).exists():
|
||||||
|
issues.append(f"missing required path: {item}")
|
||||||
|
|
||||||
|
tracked = git_tracked([".codex", ".opencode", ".agents/skills"])
|
||||||
|
for item in REQUIRED_PATHS:
|
||||||
|
if item.startswith((".codex/", ".opencode/", ".agents/")) and item not in tracked:
|
||||||
|
warnings.append(f"not tracked by git: {item}")
|
||||||
|
|
||||||
|
skill_files = sorted(AGENTS_SKILLS.glob("*/SKILL.md"))
|
||||||
|
if len(skill_files) < 10:
|
||||||
|
issues.append(f"expected at least 10 Codex skills, found {len(skill_files)}")
|
||||||
|
|
||||||
|
check_toml(CODEX_ROOT / "config.toml", issues)
|
||||||
|
for path in sorted((CODEX_ROOT / "agents").glob("*.toml")):
|
||||||
|
check_toml(path, issues)
|
||||||
|
|
||||||
|
env_values = {key: os.environ.get(key, "") for key in REQUIRED_ENV_KEYS}
|
||||||
|
env_values.update({k: v for k, v in parse_env(REPO_ROOT / "secrets.env").items() if not env_values.get(k)})
|
||||||
|
missing_env = [key for key in REQUIRED_ENV_KEYS if not env_values.get(key)]
|
||||||
|
if missing_env:
|
||||||
|
warnings.append("missing optional/required API keys for full automation: " + ", ".join(missing_env))
|
||||||
|
|
||||||
|
print("Deep Research deployment check")
|
||||||
|
print(f" repo: {REPO_ROOT}")
|
||||||
|
print(f" codex files tracked: {sum(1 for p in tracked if p.startswith('.codex/'))}")
|
||||||
|
print(f" opencode files tracked: {sum(1 for p in tracked if p.startswith('.opencode/'))}")
|
||||||
|
print(f" codex skills: {len(skill_files)}")
|
||||||
|
|
||||||
|
if warnings:
|
||||||
|
print("\nWarnings:")
|
||||||
|
for item in warnings:
|
||||||
|
print(f" - {item}")
|
||||||
|
|
||||||
|
if issues:
|
||||||
|
print("\nIssues:")
|
||||||
|
for item in issues:
|
||||||
|
print(f" - {item}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print("\nDeployment check passed.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def repair(force: bool) -> int:
|
||||||
|
try:
|
||||||
|
codex_written = copy_tree_contents(CODEX_TEMPLATE, CODEX_ROOT, force=force)
|
||||||
|
skills_written = copy_tree_contents(OPENCODE_SKILLS, AGENTS_SKILLS, force=force)
|
||||||
|
except PermissionError as exc:
|
||||||
|
print(f"repair failed: permission denied: {exc}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
except RuntimeError as exc:
|
||||||
|
print(f"repair failed: {exc}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print("Repair completed.")
|
||||||
|
print(f" .codex files written: {len(codex_written)}")
|
||||||
|
print(f" .agents skills written: {len(skills_written)}")
|
||||||
|
return check_deployment()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Check or repair Deep Research deployment files")
|
||||||
|
parser.add_argument("--repair", action="store_true", help="copy Codex templates and skills into hidden dirs")
|
||||||
|
parser.add_argument("--force", action="store_true", help="overwrite existing files during --repair")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.repair:
|
||||||
|
return repair(force=args.force)
|
||||||
|
return check_deployment()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user