dev-manager-tauri/.blueprint/modules/project-dev-variables.md
lanrtop d1e75d2270
All checks were successful
Push & PR Check / check (push) Successful in 1m26s
docs(blueprint): 新建 agent-client-parity 模块,记录三端无头基线
- 三端(Claude Code / Codex / DSH 桌面版)同一只读任务的 A–F 矩阵作为基线证据
- 立 P1–P5:统一项目专用地址、Claude skill 投影、稳定 helper 入口、
  探针固化、落地兜底;原 V17/V18 迁入 P1/P3
- manifest 项目描述同步为「管家」定位

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 19:12:03 +09:00

26 KiB
Raw Blame History

id name status progress
project-dev-variables 项目开发变量补给 in_progress 91

设计决策:人填写、Agent 按项目取值(2026-09-26)

背景与目标

开发 Agent 在子项目验收时会反复需要本机专属配置,例如非生产测试账号、沙箱 API Key 或测试端点。用户希望在炼境的项目 UI 填写一次,此后 Agent 能稳定发现并读取,避免把值留在子项目 .env 中。首轮只解决 Agent 获取开发变量;子项目进程的 process.env 自动注入、CI、生产凭证及部署能力不在范围内。

本模块是已完成的 project-resource-broker 的明确例外:R1–R11 保持 Gitea/API Key/webhook 常态不泄露、按操作代办;只有用户明确放入“Agent 可读开发变量”的值,才允许经专门工具返回明文。不能将旧的 get_secret 禁令改写成通用任意取密接口。

方案选择

方案 收益 代价与结论
继续各项目 .env 与现有脚本直接兼容 需要重复配置,仍有误提交与 Agent 访问不稳定的问题;保留为回退路径
炼境保存后由无认证 scoped MCP 返回值 最省实现步骤 scoped URL 仅隔离误操作,不认证调用者;任何能访问本机端口的进程可能取值,否决
项目级开发变量 + 认证的 scoped MCP 单项读取 人填一次、Agent 跨会话复用、仓库无值 Agent 会看到明文;需要验证 Codex 的认证头与本机凭据供应链,选定

信任与数据边界

  • 仅支持登记在炼境的项目、明确标为开发用途且允许 Agent 读取的标量值。用户在对应项目 UI 填写、修改、撤销;Agent 可登记名称/用途和读取状态,但不能通过 MCP 设置值。非生产、低权限、可重置是使用规则,不能靠变量名称自动判断生产性质。
  • SQLite 只保存 project_id、规范化变量名、用途、状态所需元数据和随机 credential_ref;值保存在现有 Windows Credential Manager adapter。普通列表、readiness、日志、错误与文档不含值。
  • 唯一明文出口是 read_project_dev_variable(project_id, name);必须同时验证真实项目绑定、scoped MCP 连接的项目 ID、客户端认证以及记录已由人配置。全局 /mcp、未认证请求和跨项目请求必须拒绝。明文进入 Agent 工具结果与会话,因此本方案不声称对 Agent 保密。
  • MCP 认证材料不得写入项目仓库、URL 或普通日志。Codex http_headers_helper 已用两次独立真实 CLI 会话验证:从 Windows Credential Manager 的随机合成项取得 bearer,真实 initialize 请求均带正确 Authorization;失败不得降级成无认证接口。正式打包路径尚未验证。
  • 同一 Windows 用户的恶意进程仍可能读取用户可访问的配置或受保护存储;认证只阻断无凭据的本机 HTTP 调用,不提供跨进程强隔离。其他客户端 adapter 未验证前不宣称兼容。

系统边界与预计文件

  • 数据:src-tauri/src/db.rs 增加兼容 migration;新业务模块 src-tauri/src/commands/dev_variables.rs 注入数据库连接和 CredentialStore,实现登记、保存、读取、撤销的单点边界。
  • 认证:src-tauri/src/mcp_server.rs / mcp_tools.rs 在取值调用前验证项目绑定及 bearer;src-tauri/src/credential_store.rs 存储随机认证材料;src-tauri/src/main.rs 与 mcp_inject.rs 评估最小本机 header helper 和配置注入。旧 MCP 工具继续按原契约可用。
  • 人的投影:src-tauri/src/lib.rs 注册 Tauri commands,src/lib/commands.ts 同步类型与封装;在 src/components/dashboard/ProjectCard.tsx 就近入口接入项目级面板,值仅通过显式填写表单提交。
  • Agent 投影:src-tauri/src/mcp_tools.rs 暴露登记需求、查询非秘密状态、单项取值;不提供批量导出、任意命令、HTTP/SSH/SQL 或部署代理。
  • 契约同步:docs/ai-context/project-context.yaml 与 docs/ai-context/agent-button-system.md 说明例外与信任模型;保留旧设计历史,不将项目通用 API Key 改为 Agent 可读。

验证路径

  • [Codex CLI + 合成 MCP] 用 http_headers_helper 提供合成 bearer 后初始化 → 服务端观测认证头;无 header/错误 header → 敏感工具拒绝;未通过则停止实现取值接口。
  • [cargo test] 用 in-memory SQLite + 模拟 CredentialStore 登记、保存、重启式重建后读取、撤销 → 状态正确,旧值不可再取,列表与错误不含合成值。
  • [真实 scoped MCP] Agent 在 p1 登记 E2E_PASSWORD,人通过同一本体保存合成值,Agent 单项读取 → 仅 p1 的已认证调用得到该值;p2、全局路由和无认证调用失败。
  • human_verify: 炼境项目 UI 的待填写、已配置、修改和撤销路径可用,默认不显示值;使用者判断是否比重复配置 .env 省事。

风险与阶段闸门

  • 认证材料供应:helper 与客户端跨会话读取已用随机合成项验证,正式打包版尚未验证;若后续失败必须回到设计,不把 token 写进受 Git 跟踪的 .codex/config.toml。
  • 明文工具结果:用户选择开发便利,Agent 可能在会话中持有值;先只用合成数据验证,不读取或迁移真实账号。生产和高权限凭证仍用原有代办/CI/运行时机制。
  • 不替代运行时 .env:Agent 读取值不自动设置子进程环境变量;需要时另立任务,不在本迭代暗加 export_env。
  • 依赖 PR #22:从已提交的 R11 基线独立分支开发,先核验 PR #22 状态;不得把新改动混入已有 PR 或原 master 脏工作区。

任务拆解

✅ V1 — 认证头 helper 真实客户端可行性

  • status: done
  • complexity: M
  • files: src-tauri/src/main.rs, src-tauri/src/lib.rs, src-tauri/src/credential_store.rs, src-tauri/src/mcp_inject.rs
  • depends: project-resource-broker
  • acceptance: "agent_verify: [Codex CLI + 合成 MCP] 通过本机 helper 从模拟受保护存储提供 bearer → initialize 请求含正确 Authorization,重启客户端后仍可读取;helper 缺失/失败时连接或取值 fail closed,项目配置文件不含 token。未通过即停止 V2–V7。"
  • evidence: cargo test --locked codex_client_reads_windows_helper_header_across_sessions -- --ignored 双会话通过;真实 exe helper 的读取/缺失 fail closed 测试通过;config 测试断言无 token。

✅ V2 — 敏感 MCP 调用认证与项目绑定

  • status: done
  • complexity: M
  • files: src-tauri/src/mcp_server.rs, src-tauri/src/mcp_tools.rs, src-tauri/src/credential_store.rs
  • depends: V1
  • acceptance: "[cargo test] 合成 bearer 下 p1 的敏感 tools/call 认证门槛通过;无 header、错误 header、p2 和全局 /mcp 均在 dispatch 前拒绝,现有非敏感 scoped 工具保持可调用;cargo test 全绿。真实取值工具的 HTTP 端到端验收归 V6。"
  • evidence: sensitive_read_requires_matching_project_bearer_on_both_transports 通过;完整 cargo test --locked 通过。

✅ V3 — 开发变量元数据与受保护存储本体

  • status: done
  • complexity: M
  • files: src-tauri/src/db.rs, src-tauri/src/commands/dev_variables.rs, src-tauri/src/credential_store.rs
  • depends: V2
  • acceptance: "[cargo test] in-memory DB + 模拟 CredentialStore 完成登记、保存、覆盖、读取、撤销;模拟写入或删除失败时旧值/引用可恢复,列表序列化和错误不含合成值;旧 schema 经 migrate 后可用。"
  • evidence: dev_variables::tests 与 dev_variable_migration_adds_metadata_table_to_existing_database 通过;数据库重开后仍可读取合成值,删除失败保留旧引用。

✅ V4 — Tauri 人用命令与前端契约

  • status: done
  • complexity: M
  • files: src-tauri/src/commands/dev_variables.rs, src-tauri/src/lib.rs, src/lib/commands.ts
  • depends: V3
  • acceptance: "[Tauri command/cargo test] 以项目 ID 查询待填写/已配置、保存合成值、撤销 → 状态随真实存储变化;常态返回类型无 value,pnpm typecheck exit 0。"
  • evidence: tauri_commands_use_same_state_and_never_return_value_in_list 通过,mise exec -- pnpm typecheck exit 0。

✅ V5 — 项目 UI 填写与撤销投影

  • status: done
  • complexity: M
  • files: src/components/dashboard/ProjectCard.tsx, src/components/dashboard/ProjectDevVariablesPanel.tsx, src/lib/commands.ts
  • depends: V4
  • acceptance: "agent_verify: [Tauri command/cargo test] 填写、覆盖、撤销同一本体状态正确,pnpm typecheck exit 0。human_verify: 在对应项目可见用途与待填写状态,填写/修改/撤销顺手,常态不显示值。"
  • human_verify: pending(未启动隔离分支的真实桌面 UI;交人终验时判断交互摩擦)
  • evidence: Tauri command 真实函数路径测试与 TypeScript 类型检查通过;填写值从 React Query mutation 缓存中移除。

✅ V6 — Agent 登记、状态和单项读取工具

  • status: done
  • complexity: M
  • files: src-tauri/src/mcp_tools.rs, src-tauri/src/commands/dev_variables.rs, src-tauri/src/mcp_server.rs
  • depends: V4, V5
  • acceptance: "[真实 scoped MCP] p1 Agent 登记 E2E_PASSWORD → UI 待填写;人保存合成值后已认证 Agent 单项读取成功;未认证、p2 和全局路由拒绝;tools/list 无批量导出或任意代理。"
  • evidence: scoped_dev_variable_http_pilot_denies_missing_wrong_cross_and_global_auth 真实本机 HTTP 测试通过;撤销后读取失败,工具清单无批量出口。

✅ V7 — 契约、合成试点与改动边界验收

  • status: done
  • complexity: M
  • files: docs/ai-context/project-context.yaml, docs/ai-context/agent-button-system.md, .blueprint/modules/project-dev-variables.md, src-tauri/src/mcp_server.rs
  • depends: V6
  • acceptance: "agent_verify: [真实 Codex CLI + 合成数据] 跨会话登记→填写→读取→撤销后再读失败,项目目录无新 .env 或 token;[CLI] cargo test、pnpm typecheck、git diff --check 均 exit 0。human_verify: 不使用真实生产账号、不触发真实 PR/部署/数据库写入,确认日常开发摩擦是否下降。"
  • resolved_blocker: 原阻碍为非交互 exec 默认 approval=never 拒绝写工具。2026-09-30 用户授权单次 --approve-for-me(仅会话 A 登记这一写调用),沿用 R11 先例;未放宽全局策略,读工具无需审批。
  • verification: "2026-09-30:新增 ignored 宿主 mcp_server::tests::isolated_dev_variables_client_pilot(内存 DB、随机合成账户、临时 scoped MCP,认证走真实 dev-manager-tauri.exe --lianjing-mcp-header helper 取 Windows 凭据中的项目 bearer)。自检:helper exit 0;无认证 read_project_test_account → HTTP 403。真实 Codex CLI 0.155.0-alpha.9.2(gpt-5.6-terra)三个独立会话:A 登记 PILOT_LOGIN(environment=local)→ 宿主代人填写;B 新会话 list → configured=true、read → username=pilot-user-12abb974,与宿主生成值一致;宿主代人撤销后 C 新会话 read → 失败「开发变量尚未由用户填写」。finish 后宿主断言:状态全部未配置、目录无 .env*、任何文件不含 MCP token 与测试密码、MCP 认证材料已删除、临时目录已清理,test ok。回归:cargo test --locked 227 passed / 5 ignored,pnpm typecheck exit 0,git diff --check 通过。"
  • human_verify: "2026-09-30 用户在 dev-variables 构建(真实 DB,已备份)对 Enterprise AGENT_ADMIN 两轮终验:首轮否决两处——修改时空白(→ V12)、撤销无确认框(→ f74fe11,根因 plugin-dialog 异步 confirm,同类 5 处一并修复);次轮通过。日常开发摩擦是否下降待合并后真实任务观察。"
  • unverified: "正式打包版 helper 路径;Claude/DeepSeek 等非 Codex 客户端的 bearer helper 取值;B 会话中模型把 list/read 各重复调用 3 次(结果一致,属模型行为,未影响断言);宿主强制终止时 Drop 不保证执行,可能残留合成 Windows 凭据。"

设计决策:测试账户一次填写与跨会话复用(2026-09-28)

背景

单个开发变量虽已能登记、填写和读取,但测试登录通常同时需要账号与密码。让 Agent 分别登记两个变量、让用户分别填写,仍有重复操作和半配置状态;本迭代把常见测试账户做成一个有语义的需求卡,不扩展到生产凭证或任意表单生成器。

方案选择

方案 取舍
两个独立变量由 UI 猜测配对 无迁移,但没有可靠的同一需求身份,保存时可能只写成功一个字段;不选
在现有开发变量记录上增加 test_account 类型,账号/密码作为一份受保护值原子保存 复用现有项目边界、Windows Credential Manager 与撤销路径,增加少量非秘密元数据;选定
新建通用表单/凭证库 能支持任意字段,却扩大明文出口与维护面;本轮不做

系统边界与受影响文件

  • src-tauri/src/db.rs:旧表兼容迁移,新增类型、目标系统和环境元数据;旧记录保持 scalar。
  • src-tauri/src/commands/dev_variables.rs:需求登记幂等;账号/密码按一份结构化值写入同一受保护引用,读写和撤销沿用项目校验;普通标量 API 不读取或覆盖测试账户记录。
  • src-tauri/src/mcp_tools.rs、mcp_server.rs:项目级登记、状态发现、专用读取;读取遵守现有 bearer 门槛,未认证、跨项目和全局路由拒绝,不增加通用 get_secret。
  • src-tauri/src/lib.rs、src/lib/commands.ts、src/components/dashboard/ProjectDevVariablesPanel.tsx:一张卡一次填写账号与密码;常态列表仅展示目标系统、环境、用途和配置状态,不回显值。
  • docs/ai-context/project-context.yaml、docs/ai-context/agent-button-system.md:同步外部契约与例外边界。

验证路径

  • [cargo test] 旧 schema 迁移后旧标量仍可读;重复登记同一测试账户只得一张卡,语义冲突拒绝;一次保存后账号与密码同时可读,撤销后同时不可读,列表与错误不含合成值。
  • [真实 scoped MCP] 合成项目登记→Tauri 本体填写→已认证读取→跨项目、无认证及全局路由拒绝;工具目录没有批量导出或任意代理。
  • human_verify: 用户在项目面板一次填写账号与密码,后续会话无需重复填写;仅在人主动修改时出现输入框。

风险与闸门

  • Agent 读取时会得到明文;本能力仅用于用户明确放入的非生产、低权限、可重置测试账户,不承诺对 Agent 保密。
  • 真实 Codex 非交互 exec 对写工具的客户端限制属于 V7 接入验证,不以错误标注只读或放宽全局策略绕过;业务层合成验收可以独立先做,真实客户端全链路未通过前不宣称日常可用。
  • 不自动把值注入子进程环境、不写 .env、不接管生产账号、SSH、SQL、HTTP 或部署。

拆解建议

按类型与受保护存储 → scoped Agent 投影 → 人用单表单投影 → 合成链路与文档四卡实施;既有 V7 仍单独保持 blocked,直到真实客户端验证通过。

任务拆解:测试账户预设

✅ V8 — 测试账户类型与原子受保护存储

  • status: done
  • complexity: M
  • files: src-tauri/src/db.rs, src-tauri/src/commands/dev_variables.rs
  • depends: V6
  • acceptance: "agent_verify: [cargo test] 旧 schema migrate 后旧 scalar 正常;register_test_account(project,name,service,environment,purpose) 重复调用只保留一条且语义冲突拒绝;save_test_account 一次写入合成账号/密码,read_test_account 同时返回,revoke 后同时不可读;列表及错误不含值,写入失败不留下半配置。"
  • evidence: cargo test --locked test_account 4 项通过;旧表迁移幂等、登记幂等、类型隔离、一次写入/撤销和初次/覆盖失败恢复均由合成数据断言。

✅ V9 — Agent 测试账户需求与项目级读取

  • status: done
  • complexity: M
  • files: src-tauri/src/mcp_tools.rs, src-tauri/src/mcp_server.rs
  • depends: V8
  • acceptance: "agent_verify: [真实 scoped MCP/cargo test] p1 登记一张合成测试账户需求、查询无秘密状态、已认证读取账号与密码;未认证、p2、全局 /mcp 拒绝读取,普通 scalar API 不能读取测试账户;tools/list 不含批量导出或任意代理。"
  • evidence: sensitive_read_requires_matching_project_bearer_on_both_transports 与扩展后的 scoped_dev_variable_http_pilot_denies_missing_wrong_cross_and_global_auth 通过;新明文工具先接入认证门槛再暴露,真实本机 HTTP 拒绝未认证/错误认证/p2/全局调用。

✅ V10 — 一张卡填写账号与密码

  • status: done
  • complexity: M
  • files: src-tauri/src/lib.rs, src/lib/commands.ts, src/components/dashboard/ProjectDevVariablesPanel.tsx
  • depends: V8
  • acceptance: "agent_verify: [Tauri command/cargo test + pnpm typecheck] UI 一次提交调用 save_test_account,状态从待填写到已配置,修改与撤销共用本体;常态 DTO、React Query 缓存与日志不含账号或密码,typecheck exit 0。human_verify: 项目面板一张卡一次填写两个字段,默认不回显值。"
  • human_verify: pending(隔离分支真实桌面 UI 尚未由用户终验)
  • evidence: tauri_test_account_command_uses_same_state_without_listing_values 通过,mise exec -- pnpm typecheck exit 0;UI 通过独立调用提交两字段,列表 DTO 只有非秘密元数据和配置状态。

✅ V11 — 合成复用验收与契约同步

  • status: done
  • complexity: M
  • files: src-tauri/src/mcp_server.rs, docs/ai-context/project-context.yaml, docs/ai-context/agent-button-system.md
  • depends: V9, V10
  • acceptance: "agent_verify: [真实 scoped MCP/cargo test] 合成项目登记→同一本体填写→再次查询已配置→读取→撤销后读取失败,并确认目录没有新增 .env 或明文配置;cargo test、pnpm typecheck、git diff --check exit 0。human_verify: 真实桌面 UI 与真实 Agent 客户端跨会话便利性另报未验证,不冒充 V7 完成。"
  • human_verify: pending(真实桌面 UI 和真实 Agent 客户端跨会话复用尚未终验;V7 保持 blocked)
  • evidence: 真实本机 scoped MCP HTTP 合成链路逐步断言登记、待填写、受保护存储填写、复查已配置、项目 bearer 读取、撤销后拒绝;数据库重开复用测试通过。cargo test --locked 227 passed/4 ignored,mise exec -- pnpm typecheck 与 git diff --check exit 0;未新增 .env 或明文配置文件。

任务拆解:UI 终验反馈与 agent 可发现性(2026-09-30)

来源:用户对 V7 的 human_verify 否决理由——「修改时空白,应像修改配置一样呈现旧值」「撤销无确认框」(后者为 bug,已由 f74fe11 修复并加回归测试);以及 agent 侧可发现性缺口:接入包 skill 未提示「需要测试账号时先查炼境」,agent 会继续向人索要。

✅ V12 — 修改时显式查看原值(人用投影)

  • status: done
  • complexity: M
  • files: src-tauri/src/commands/dev_variables.rs, src-tauri/src/lib.rs, src/lib/commands.ts, src/components/dashboard/ProjectDevVariablesPanel.tsx, docs/ai-context/project-context.yaml
  • depends: V10
  • acceptance: "agent_verify: [cargo test] reveal(已配置测试账户) → 账号与密码原值;reveal(标量) → 原值;未配置 → 错误;MCP tools/list 不含任何 reveal 工具。human_verify: 点「修改」→ 账号预填可见、密码预填但默认遮罩,点「显示」可见;保存后生效。"
  • verification: "2026-09-30:cargo test reveal_returns_original_value_by_kind_only_for_humans 覆盖测试账户/标量取回、未配置与撤销后报错、MCP tools/list 不含 reveal;全量 cargo test --locked 228 passed / 5 ignored,pnpm typecheck exit 0,vitest 8 passed。"
  • human_verify: "2026-09-30 通过:修改预填原账号、密码遮罩可切换显示、撤销弹出确认框且取消不生效。"
  • decision: 值仅经本机 Tauri command 在人显式点「修改」时取回,沿用 API Key R2 的显式 reveal 模式;不进 MCP,agent 取值仍只走已认证的 read_project_test_account。密码默认遮罩防截图/旁观泄露。

✅ V13 — 接入包 skill 提示 agent 先查炼境测试账户

  • status: done
  • complexity: S
  • files: src-tauri/resources/onboarding/.agents/skills/lian-jing/SKILL.md, src-tauri/src/commands/onboarding.rs
  • depends: V9
  • acceptance: "agent_verify: [cargo test onboarding] base-onboarding 版本升级后旧版本项目报告 version_mismatch、新模板含测试账户指引。human_verify: 合并并重建后对 Enterprise apply_onboarding_pack,agent 需要登录时先查炼境而非向人索要。"
  • verification: "2026-09-30:SKILL.md 新增第 8 步(先 list,已配置单项读取,否则登记并请用户在 UI 填写;禁止对话索要明文、禁止登记生产、禁止写入 Git 跟踪文件、认证被拒如实报告);BASE_ONBOARDING_PACK_VERSION 与模板 capability-packs.json 同步升至 1.5.0(仅升常量时 2 个 onboarding 测试失败,已同步修正);cargo test --locked 全绿。"
  • human_verify: pending(分发到 Enterprise 后观察 agent 行为)
  • distribution: "2026-09-30:master 6105c3d 重建后对 Enterprise 执行 inject_mcp(托管块新增 http_headers_helper)与 apply_onboarding_pack(SKILL.md、capability-packs.json 1.5.0、git-workflow 托管块 1.6.0→1.7.0;AGENTS.md/lefthook/mise skipped);写入前备份并逐文件比对,Enterprise 44 项既有未提交改动均在托管块外、内容未变。verify_onboarding 13/13 + runtime ready。真实 Codex 新会话在 Enterprise 目录经项目自身配置与 helper:list → AGENT_ADMIN configured,read 成功,username 与用户填写一致。该次为显式指示调用;未提示时 agent 是否自发先查炼境,待真实任务观察。旁证:Codex 仍尝试执行 shell 触发 Windows 沙箱提权 helper 被取消(1223),不影响结果。"

后续立卡(2026-09-30,按实测摩擦排序)

📋 V14–V16 — 测试账户落地到被 Git 忽略文件

  • status: todo
  • complexity: M×3
  • 设计与卡片草案:docs/tasks/2026-09-30-dev-variables-materialize.md(落地本体 / MCP 投影 / Enterprise worktree 试点);开工前需用户确认设计。
  • 为什么:agent 读到明文后仍需自行 export 或写 .env.agent 才能喂给 agent-auth.mjs,明文过一手会话且每个新 worktree 重复。

设计决策:各客户端稳定携带项目认证(V17+V18 合并,2026-09-30,待用户确认)

调研事实

客户端 动态请求头 不进仓库的按项目配置 现状
Codex 0.155 http_headers_helper:经 %COMSPEC% /Q /D /C 执行,env_clear 后只留白名单(含 LOCALAPPDATA);10s 超时;连接时调用,401/403 刷新一次 无:user config 的 [projects] 只有 trust_level;项目 .codex/config.toml 仅 trusted 项目加载,与 user 层递归深合并 受跟踪项目文件写入本机 exe 绝对路径
Claude Code headersHelper:stdout JSON;每次连接调用,401/403 重试;10s local scope(~/.claude.json 按项目条目),优先级 local > project > user,整条替换不合并 仅 user scope 注册全局 /mcp(SSE),敏感读取被拒
DSH 0.1.5-rc.2 仅静态 headers 仅机器级 ~/.dsh/cordis.patch.yml,无按项目 连全局 /mcp,敏感读取被拒

方案

  1. 稳定 helper 入口(解 V18 根因):炼境每次启动(debug 或安装版)重写 %LOCALAPPDATA%\lian-jing\bin\lianjing-mcp-header.cmd 指向当前 exe。Codex 项目配置改为 http_headers_helper = '"%LOCALAPPDATA%\lian-jing\bin\lianjing-mcp-header.cmd" <digest>'——digest = sha256(project_id) 非秘密,整行在任何机器、任何构建下相同,可安全提交;换构建无需逐项目重注入。
  2. Claude(V17 主体):inject_mcp 在项目目录以 local scope 写入 lian-jing(scoped url + headersHelper 指向同一 shim;local 条目不进仓库,可用绝对路径);保留 user scope 全局注册作兜底。
  3. DSH:不写静态 token。静态 header 意味着 bearer 明文落在用户目录配置文件,且 DSH 配置无法按项目拆分;DSH 取值改走 V14–V16 落地路径(写入被忽略文件、不返回值、无需认证),待 dsh-mcp-client 支持动态 header 再评估。
  4. 推论:V14–V16 是唯一全客户端通用的路径(落地不返回值,无需认证);读取明文的有界例外只服务支持动态 header 的客户端。

风险与闸门

  • %LOCALAPPDATA% 在 Codex helper 中可展开属源码推断(白名单含该变量),实施首步须真实 Codex 会话实测;不成立则回到设计,不退回写绝对路径。
  • Claude headersHelper 在 Windows 的执行 shell(cmd 或 Git Bash)文档未写明,须实测 shim 调用写法。
  • shim 位于用户可写目录:同一 Windows 用户进程可替换它——与既有威胁模型一致(不提供同用户隔离),不宣称增强。
  • 已接入项目需一次迁移:重新 inject_mcp 后 .codex/config.toml 托管块变化,由项目自行提交。

➡️ V17、V18 — 已迁至 agent-client-parity(2026-09-30)

  • V18 → P3(稳定 helper 入口);V17 → P1(Claude 连项目专用地址 + headersHelper)。
  • 为什么迁移:三端无头基线探针表明 Claude 与 DSH 的首要缺口是连全局 /mcp、看不到开发变量工具(路由问题),而非认证本身;这属于跨客户端对等问题,单独建模块统一推进,本模块不再重复描述。

调研来源

  • Claude Code:code.claude.com/docs/en/mcp(Dynamic headers、Environment variable expansion、installation scopes、Trust a folder before headersHelper runs)
  • Codex:learn.chatgpt.com/docs/extend/mcp、config-basic、config-reference;源码 openai/codex tag rust-v0.155.0-alpha.9 的 rmcp-client/src/http_headers.rs、config/src/merge.rs、config/src/config_toml.rs、codex-mcp/src/runtime.rs、cli/src/mcp_cmd.rs
  • DSH:本机 dsh-mcp-client@0.1.5-rc.2 类型定义(headers: Record<string,string>)与 ~/.dsh/cordis.patch.yml