208 lines
13 KiB
Markdown
208 lines
13 KiB
Markdown
---
|
||
version: 1.1.0
|
||
updated: 2026-09-26
|
||
usage: 炼境 agent 按钮体系的完整设计文档,供 Claude 理解体系全貌和设计意图;也是分发给子项目的方针来源
|
||
---
|
||
|
||
# Agent 按钮体系
|
||
|
||
> 炼境的核心设计理念:让 AI agent 具备无人值守执行能力的工程基础设施。
|
||
|
||
## 核心命题
|
||
|
||
> 功能只有一份实现,但有两种投影:UI 按钮是给人的,agent 按钮是同一个功能给 AI agent 的投影。
|
||
> 当 agent 按钮完备,验证环路就能在 agent 内部闭合,人不再是执行链的瓶颈。
|
||
|
||
## 双投影设计
|
||
|
||
```
|
||
功能本体(单一实现)
|
||
├── UI 按钮 → 人操作
|
||
└── agent 按钮 → agent 调用
|
||
├── 可发现(agent 知道它存在)
|
||
├── 可调用(结构化接口)
|
||
└── 边界清晰(调的是同一条路径,不是捷径)
|
||
```
|
||
|
||
"调同一条路径"是关键:agent 走的验证路径和人走的一致,终验才有意义。
|
||
|
||
## 分工重构
|
||
|
||
没有 agent 按钮时,人卡在验证环节,成为执行链瓶颈:
|
||
|
||
```
|
||
人定目标 → agent执行 → 人验证 → 人反馈 → ...(人是瓶颈)
|
||
```
|
||
|
||
有了 agent 按钮后,中间的验证环路在 agent 内部闭合:
|
||
|
||
```
|
||
人定目标 → agent执行 → agent自验(走agent按钮) → 人终验
|
||
```
|
||
|
||
人只保留两件事:
|
||
- **需求澄清**(目标定义权)
|
||
- **目标验收**(终验权)
|
||
|
||
**人在目标层,agent 在执行层,层间边界清晰,各自自洽。**
|
||
|
||
## 四层体系
|
||
|
||
### 意图层 — AGENTS.md
|
||
声明方针 + agent 按钮清单。agent 进来第一件事:知道这个项目有哪些 agent 按钮可以调用。
|
||
|
||
### 执行层 — agent 按钮本体
|
||
按项目类型就近选择载体:
|
||
|
||
| 项目类型 | agent 按钮载体 |
|
||
|---------|---------------|
|
||
| Web 服务 | HTTP API(前端按钮与 curl 调同一 endpoint,天然双投影) |
|
||
| CLI/脚本 | 命令与 npm scripts |
|
||
| 桌面应用 | 测试直接调用 command 函数 |
|
||
| UI 呈现层 | Playwright(最后手段,仅关键路径) |
|
||
|
||
### 验证层 — acceptance + 可执行断言
|
||
acceptance 是 agent 自验的唯一判断依据,必须是可执行断言:
|
||
|
||
```
|
||
❌ "功能正常运行"(描述性,agent 无法执行)
|
||
❌ "代码正确"(主观,无可执行路径)
|
||
✅ "pnpm typecheck 无报错"
|
||
✅ "cargo test 通过(src-tauri/)"
|
||
✅ "MCP tool list_projects 返回新增项目名"
|
||
✅ "pnpm test import-project 全绿"
|
||
```
|
||
|
||
最小结构:`<可执行命令>` + `<通过标准>` = 一条合格的 acceptance。
|
||
|
||
验证层的触发机制,按优先级(模型无关性递减):
|
||
|
||
| 机制 | 触发时机 | 模型无关 |
|
||
|------|---------|---------|
|
||
| git hooks(lefthook) | commit 时 | ✅ 最强 |
|
||
| CI/CD(Gitea Actions) | push 后 | ✅ |
|
||
| .claude/settings.json hooks | Claude Code 专属 | ❌ |
|
||
| AGENTS.md 约定 | 靠 agent 主动调用 | 语言约束 |
|
||
|
||
> `.claude/settings.json` hooks 是 Claude Code 专属的,Cursor / Qwen 等其他工具不会读这个文件。模型无关的验证层靠 git hooks + CI,不能靠 Claude 专属配置。
|
||
|
||
### 持久层 — 目标持久化
|
||
让 agent 跨会话续接,不靠对话记忆:
|
||
- 炼境项目:蓝图(`.blueprint/`)
|
||
- 子项目完整接入:随炼境分发的蓝图规范
|
||
- 子项目最小接入:`.agent/task.md`
|
||
|
||
蓝图在体系里的三个角色:
|
||
1. **目标的结构化载体** — 把自然语言目标翻译成带 acceptance 的可执行任务卡
|
||
2. **跨会话共享状态** — agent 跨对话续接的记忆
|
||
3. **自验的判断依据** — acceptance 字段告诉 agent "走到什么状态算通过"
|
||
|
||
## 消费者驱动验证
|
||
|
||
普通应用的验证在自身边界内,一个角色(实现者)够用。
|
||
|
||
当产品的产出要被"圈外"消费时(工具、平台、SDK、炼境这类跨 APP 产品),验证必须出圈,天然产生两个角色:
|
||
|
||
```
|
||
实现者角色 → "我跑通了"(项目内部视角)
|
||
消费者角色 → "你的产出我真的能用"(圈外消费视角)
|
||
```
|
||
|
||
两个角色博弈,才能覆盖完整目标。
|
||
|
||
**判断是否需要双角色**:你的产出,有没有圈外消费者?
|
||
|
||
| 产品类型 | 消费者在哪 | 需要几个角色 |
|
||
|---------|-----------|------------|
|
||
| 普通业务应用 | 圈内(用户即使用者) | 1 个 |
|
||
| SDK / 工具 / 平台 | 圈外(其他项目) | 2 个 |
|
||
| 炼境 | 圈外(被管理的子项目) | 2 个 |
|
||
|
||
> **验证边界要跟着目标边界走,不是跟着实现边界走。**
|
||
|
||
炼境的双角色示例:
|
||
- 实现者角色:炼境开发角度(导入新项目、跑通接入包分发流程)
|
||
- 消费者角色:被管理项目角度(接入包能否真的在子项目里用起来)
|
||
|
||
## 本地 Agent 控制面的稳定边界
|
||
|
||
炼境对 Codex、Claude 等客户端提供同一份本地能力本体,客户端插件与 UI 只是不同投影:
|
||
|
||
- MCP 仅监听 IPv4 loopback `127.0.0.1`,不以 Agent 易用性为由暴露到局域网。
|
||
- 项目使用 `/mcp/projects/<project_id>` scoped endpoint;服务端以连接 scope 为准,拒绝跨项目参数和全局管理写工具。旧 `/mcp` 仅用于兼容迁移,不扩展新写能力。
|
||
- readiness 分为 `configured → reachable → handshake → tools_ready → reload_required`。配置存在不等于当前任务已加载;停在哪层,就只修哪一层。
|
||
- `.lian-jing/context.json` 是项目身份唯一来源;Skill 和插件不复制项目身份、Gitea 凭证或 MCP 实现。
|
||
- Windows 登录自启动只服务正式安装版,默认关闭且由用户主动启用;debug 和 `target/release` 直接运行明确拒绝注册。single-instance 继续保证同一时间只有一个炼境实例。
|
||
- 日常开发优先运行 `pnpm tauri dev`,Agent 直接消费同一 loopback MCP;正式安装包只在安装、自启动、升级或发布里程碑做一次验收,不作为每次提交的前置条件。
|
||
- 开发炼境前先从托盘完全退出正式安装版;不得把正式版与 `pnpm tauri dev` 并行运行。single-instance 是运行时兜底,不替代这一开发约定。
|
||
- updater 是独立的发布能力,不属于自启动或 readiness 的完成条件。
|
||
|
||
这套 scope 是单用户本机的误操作隔离,不是多租户认证。威胁模型变化前,不向项目配置写持久 token。
|
||
|
||
项目开发变量是明确、有限的例外:Codex 项目配置只保存本机 helper 命令和项目 ID digest,随机 bearer 留在 Windows Credential Manager;helper 在连接时向 Codex 提供认证头。普通 scoped MCP 工具继续兼容无认证调用,但 `read_project_dev_variable` 与 `read_project_test_account` 在服务端验证该项目的 bearer,跨项目、全局 `/mcp`、无认证及错误认证均拒绝。同一 Windows 用户的恶意进程仍可能读取该用户可访问的凭证,本机制不声称提供同用户进程隔离;其他 Agent 客户端未验证前不承诺同等取值能力。
|
||
|
||
## 项目资源与凭证代办边界
|
||
|
||
项目开发变量由 Agent 在 scoped MCP 中登记名称和用途,人通过对应项目 UI 明确填写、修改或撤销。测试登录前 Agent 先查询非秘密需求状态:已有测试账户卡就复用;没有才以 `register_project_test_account` 登记稳定名称、目标系统、非生产环境和用途,不能通过 MCP 提交账号或密码。用户在同一张卡一次填写账号与密码;两字段作为一份结构化值原子写入 Windows Credential Manager,SQLite 仅保存非秘密元数据与随机引用。常态列表只报告待填写/已配置;`read_project_test_account` 经项目级认证后返回单张卡的账号与密码,旧的 `read_project_dev_variable` 仅返回标量,双方不能跨类型取值。结果会进入 Agent 会话,因此只允许非生产、低权限、可重置的开发数据;不替代子项目运行时 `.env` 注入,也不改变下述 Gitea/API Key 代办边界。
|
||
|
||
`get_project_resource_status(project_id)` 是同一项目绑定上的只读 MCP/Tauri 投影,只报告 Gitea PR 与 webhook 的 `configured`、`pending_migration`、`not_configured`、`unavailable` 或 `needs_repair` 及非秘密来源。旧 SQLite 凭证未迁移时只报告 `pending_migration`,不提前宣称可执行;scoped MCP 连接拒绝跨项目参数;状态不含原始凭证、凭证引用、仓库 URL 或连接串。`configured` 仅表示本机代办凭证就绪,不代表远端 Gitea、CI 或部署已验证。
|
||
|
||
Gitea PR 继续使用既有 `create_pull_request` 有界操作;Windows 本机代办凭证由 Credential Manager 保护,SQLite 只存引用及非秘密元数据。旧值在显式操作时,先在数据库同目录以 SQLite `VACUUM INTO` 生成 `dev-manager.pre-credential-migration.db`,校验完整性和当前旧值确在备份中,再按写入、读取校验、事务切换引用并清除旧列的顺序迁移;备份不可用或失败则保留旧值并报告 `needs_repair`。此备份可能含历史明文,须按原数据库同等敏感级别保护,不能因当前列清空就宣称历史明文已消失。普通 Gitea/API Key DTO 不带原始值;人的 API Key 查看与复制仍通过本机 Tauri 的显式 reveal,MCP 不暴露该入口。Gitea Actions secrets、项目运行时密钥与服务器凭证仍留在各自原用途位置;炼境不提供 `get_secret` 或任意 SSH、SQL、HTTP、部署代理。同一 Windows 用户下的进程隔离不是本方案提供的安全保证。
|
||
|
||
## production 交付观测边界
|
||
|
||
项目可自主管理 `.lian-jing/capabilities.yaml` 的 `delivery.targets.production`,声明 Gitea Actions 的**精确 status context** 与公开 HTTP JSON 版本探针。炼境只读该声明;接入包不生成或覆盖项目的 production 配置。探针不接受 URL 凭证、认证头、查询参数、非 HTTP(S) 协议或本机/内网地址;连接时过滤域名解析出的私网地址,不走环境代理、不跟随重定向,并限制请求时间与响应大小。
|
||
|
||
`get_delivery_status` 分别采集 Gitea 默认分支目标 SHA 的部署过程证据和当前服务报告的运行 SHA。只有部署 context 成功、探针健康、两个完整 SHA 相等时才报告 `deployed`。`failed` 保留实际运行版本;部署成功但版本不一致才报告 `drifted`;本次提交的部署 job 被跳过时报告 `skipped` 并保留运行 SHA,不把文档类提交误报为漂移。缺失/不可达证据明确降级。该状态仅是技术交付观测,不替代业务测试、上线决策,也不赋予炼境部署、回滚、SSH 或数据库写权限。
|
||
|
||
## 三条设计原则
|
||
|
||
辩证结论,缺一会让体系在现实中碎裂。
|
||
|
||
### 原则一:无人值守 ≠ 消灭人工介入
|
||
人工介入是设计内的降级路径,不是体系失败。体系的目标是把人从"执行路径"移到"降级路径"。
|
||
|
||
**自验失败降级约定**:
|
||
- 失败 2 次内:自行修正,继续自验
|
||
- 失败 3 次:停止执行,输出以下内容后等待人工介入:
|
||
1. 失败原因(具体报错或不通过的断言)
|
||
2. 已尝试的修正路径
|
||
3. 需要人决策的具体问题
|
||
|
||
### 原则二:框架由炼境保证,内容由子项目填
|
||
炼境能分发的是结构(AGENTS.md 模板、蓝图规范、lefthook、CI 配置),不能替子项目实现 agent 按钮。
|
||
|
||
分发的最高价值物是 **acceptance 写法规范**——让子项目知道怎么写才算可执行断言,而不是描述性语句。
|
||
|
||
### 原则三:acceptance 是体系的核心关节
|
||
体系其他部分都能降级,acceptance 不能将就。acceptance 写得可执行,自验才是真自验;写得模糊,整个环路是假闭合,无人值守名存实亡。
|
||
|
||
## 炼境自己的 Agent 按钮清单
|
||
|
||
| 能力 | 调用方式 | 通过标准 |
|
||
|------|---------|---------|
|
||
| TypeScript 类型检查 | `pnpm typecheck` | 无输出,exit 0 |
|
||
| 前端单元测试 | `pnpm test` | exit 0,无 FAILED |
|
||
| Rust 单元测试 | `cargo test`(src-tauri/ 目录) | 无 FAILED |
|
||
| MCP 工具调用 | 见 `src-tauri/src/mcp_tools.rs` 工具列表 | 返回 JSON,无 error 字段 |
|
||
| 蓝图状态读取 | 读 `.blueprint/manifest.yaml` | 文件可解析,字段完整 |
|
||
| 蓝图状态更新 | 编辑 `.blueprint/modules/<id>.md` | 文件写入成功,格式合法 |
|
||
|
||
## 分发给子项目的方案
|
||
|
||
接入包只有一档,要么接,要么不接。
|
||
|
||
```
|
||
接入包
|
||
├── AGENTS.md 模板 ← 含方针 + 按钮清单占位 + 降级约定
|
||
├── .blueprint/CONVENTIONS.md ← 含 acceptance 写法规范 + 蓝图工作流
|
||
├── lefthook.yml ← git hooks(模型无关验证层)
|
||
└── .gitea/workflows/ci.yml ← CI/CD(模型无关验证层)
|
||
```
|
||
|
||
子项目接入后需要自己填入:
|
||
- AGENTS.md 里 agent 按钮清单的具体命令和通过标准
|
||
- 任务卡 acceptance 字段的可执行断言
|
||
|
||
> 没有蓝图就没有飞轮数据,炼境对该项目的感知断链。不接入蓝图的项目不应通过炼境分发接入包,直接使用 AGENTS.md 开放规范即可。
|