Compound Engineering 实践指南:从安装到浏览器验收

本文以 mystu(铁矿石价格预测 Agent) 项目为例,记录 Compound Engineering(以下简称 CE)在 Cursor 中的安装、命令链、产出文件的生命周期,以及 /ce-test-browser --port 5000 的实际效果与工作原理。


1. Compound Engineering 是什么?

Compound Engineering 是一套面向 AI 编程助手的工作流插件,目标不是「写一次代码就结束」,而是让需求 → 计划 → 实现 → 测试 → 审查 → 知识沉淀形成可复用的闭环。

核心理念叫 Compounding(复利)

  • 第一次解决「Redis Cluster 启动失败」可能要查文档 30 分钟;
  • /ce-compound 沉淀后,下次同类问题 2 分钟检索 docs/solutions/ 即可;
  • 团队知识随每次修复而累积,而不是散落在聊天记录里。

在本项目中,CE 与 Cursor Agent 配合,主要入口是 Slash 命令 (如 /ce-setup/ce-plan)和 Skill 文件(插件内置的操作规程)。


2. 安装与环境准备

2.1 安装 Compound Engineering 插件

CE 作为 Cursor 插件安装(Compound Engineering local plugin)。安装后,Agent 会话中可使用 /ce-* 系列命令。

2.2 运行 /ce-setup 做健康检查

首次使用或环境变更后,执行:

复制代码
/ce-setup

它会检查:

类别 典型工具 用途
CLI 工具 agent-browser 浏览器自动化(/ce-test-browser 专用)
gh GitHub PR/Issue
jq JSON 处理
ffmpeg / vhs 演示录屏
ast-grep 结构化代码搜索
Agent Skills ast-grep skill 等 子 Agent 能力扩展

Windows 环境说明: 官方 health check 脚本为 bash,在 Windows 上可能需手动安装缺失项。本项目中通过 npm 全局安装 agent-browser

复制代码
npm install -g agent-browser
agent-browser install   # 安装浏览器驱动

2.3 项目级配置文件

/ce-setup 会在仓库中引导创建:

复制代码
.compound-engineering/
├── config.local.example.yaml   # 提交 Git,团队可见的配置模板
└── config.local.yaml           # 本地偏好,已在 .gitignore,不提交

作用:

  • config.local.example.yaml:文档化所有可选项(输出格式、Product Pulse 等),默认全部注释;
  • config.local.yaml:你的机器专属偏好,例如 plan_output: html 让计划输出 HTML。

生命周期: example 随插件模板更新而刷新;local 只创建一次,由开发者自行维护。


3. CE 命令链与完整工作流

3.1 总览:从想法到知识沉淀

#mermaid-svg-PUEYkUmHaNTKj51O{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PUEYkUmHaNTKj51O .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PUEYkUmHaNTKj51O .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PUEYkUmHaNTKj51O .error-icon{fill:#552222;}#mermaid-svg-PUEYkUmHaNTKj51O .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PUEYkUmHaNTKj51O .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PUEYkUmHaNTKj51O .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PUEYkUmHaNTKj51O .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PUEYkUmHaNTKj51O .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PUEYkUmHaNTKj51O .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PUEYkUmHaNTKj51O .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PUEYkUmHaNTKj51O .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PUEYkUmHaNTKj51O .marker.cross{stroke:#333333;}#mermaid-svg-PUEYkUmHaNTKj51O svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PUEYkUmHaNTKj51O p{margin:0;}#mermaid-svg-PUEYkUmHaNTKj51O .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PUEYkUmHaNTKj51O .cluster-label text{fill:#333;}#mermaid-svg-PUEYkUmHaNTKj51O .cluster-label span{color:#333;}#mermaid-svg-PUEYkUmHaNTKj51O .cluster-label span p{background-color:transparent;}#mermaid-svg-PUEYkUmHaNTKj51O .label text,#mermaid-svg-PUEYkUmHaNTKj51O span{fill:#333;color:#333;}#mermaid-svg-PUEYkUmHaNTKj51O .node rect,#mermaid-svg-PUEYkUmHaNTKj51O .node circle,#mermaid-svg-PUEYkUmHaNTKj51O .node ellipse,#mermaid-svg-PUEYkUmHaNTKj51O .node polygon,#mermaid-svg-PUEYkUmHaNTKj51O .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PUEYkUmHaNTKj51O .rough-node .label text,#mermaid-svg-PUEYkUmHaNTKj51O .node .label text,#mermaid-svg-PUEYkUmHaNTKj51O .image-shape .label,#mermaid-svg-PUEYkUmHaNTKj51O .icon-shape .label{text-anchor:middle;}#mermaid-svg-PUEYkUmHaNTKj51O .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PUEYkUmHaNTKj51O .rough-node .label,#mermaid-svg-PUEYkUmHaNTKj51O .node .label,#mermaid-svg-PUEYkUmHaNTKj51O .image-shape .label,#mermaid-svg-PUEYkUmHaNTKj51O .icon-shape .label{text-align:center;}#mermaid-svg-PUEYkUmHaNTKj51O .node.clickable{cursor:pointer;}#mermaid-svg-PUEYkUmHaNTKj51O .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PUEYkUmHaNTKj51O .arrowheadPath{fill:#333333;}#mermaid-svg-PUEYkUmHaNTKj51O .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PUEYkUmHaNTKj51O .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PUEYkUmHaNTKj51O .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PUEYkUmHaNTKj51O .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PUEYkUmHaNTKj51O .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PUEYkUmHaNTKj51O .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PUEYkUmHaNTKj51O .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PUEYkUmHaNTKj51O .cluster text{fill:#333;}#mermaid-svg-PUEYkUmHaNTKj51O .cluster span{color:#333;}#mermaid-svg-PUEYkUmHaNTKj51O div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PUEYkUmHaNTKj51O .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PUEYkUmHaNTKj51O rect.text{fill:none;stroke-width:0;}#mermaid-svg-PUEYkUmHaNTKj51O .icon-shape,#mermaid-svg-PUEYkUmHaNTKj51O .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PUEYkUmHaNTKj51O .icon-shape p,#mermaid-svg-PUEYkUmHaNTKj51O .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PUEYkUmHaNTKj51O .icon-shape .label rect,#mermaid-svg-PUEYkUmHaNTKj51O .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PUEYkUmHaNTKj51O .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PUEYkUmHaNTKj51O .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PUEYkUmHaNTKj51O :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 持续维护
交付阶段
实施阶段
规划阶段
/ce-brainstorm
docs/brainstorms/*.md
/ce-plan
docs/plans/*.md
/ce-work plan:...
业务代码 + tests/
/ce-test-browser
浏览器验收报告
/ce-code-review
审查意见 / 修复
/ce-commit
Git 提交
/ce-compound
docs/solutions/ + CONCEPTS.md
/ce-compound-refresh
更新过时 learning

3.2 各命令职责一览

命令 输入 产出 何时用
/ce-setup 环境诊断 + CE 配置 首次、换机器、缺工具时
/ce-brainstorm 功能想法 docs/brainstorms/ 需求文档 需求不清晰、多方案权衡
/ce-plan brainstorm 或描述 docs/plans/ 实施计划 多文件/跨层改动前
/ce-work plan 路径 代码实现 按计划编码
/ce-test-browser --port 5000 浏览器测试报告 UI/路由/SSE 改动后
/ce-code-review 可选 plan/base 结构化审查 大改动合并前
/ce-commit Git commit 用户明确要求提交时
/ce-compound 可选上下文 docs/solutions/ 问题已解决、要沉淀经验
/ce-compound-refresh 范围 hint 更新旧文档 发现 learning 过时

3.3 本项目的真实执行顺序(用户认证功能)

以下为本仓库 feat/user-auth 分支上的实际路径:
本地服务 :5000 文件系统 CE Agent 开发者 本地服务 :5000 文件系统 CE Agent 开发者 #mermaid-svg-iiq8JnPvHuSkkbcN{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-iiq8JnPvHuSkkbcN .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-iiq8JnPvHuSkkbcN .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-iiq8JnPvHuSkkbcN .error-icon{fill:#552222;}#mermaid-svg-iiq8JnPvHuSkkbcN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-iiq8JnPvHuSkkbcN .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-iiq8JnPvHuSkkbcN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-iiq8JnPvHuSkkbcN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-iiq8JnPvHuSkkbcN .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-iiq8JnPvHuSkkbcN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-iiq8JnPvHuSkkbcN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-iiq8JnPvHuSkkbcN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-iiq8JnPvHuSkkbcN .marker.cross{stroke:#333333;}#mermaid-svg-iiq8JnPvHuSkkbcN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-iiq8JnPvHuSkkbcN p{margin:0;}#mermaid-svg-iiq8JnPvHuSkkbcN .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-iiq8JnPvHuSkkbcN text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-iiq8JnPvHuSkkbcN .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-iiq8JnPvHuSkkbcN .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-iiq8JnPvHuSkkbcN .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-iiq8JnPvHuSkkbcN .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-iiq8JnPvHuSkkbcN #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-iiq8JnPvHuSkkbcN .sequenceNumber{fill:white;}#mermaid-svg-iiq8JnPvHuSkkbcN #sequencenumber{fill:#333;}#mermaid-svg-iiq8JnPvHuSkkbcN #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-iiq8JnPvHuSkkbcN .messageText{fill:#333;stroke:none;}#mermaid-svg-iiq8JnPvHuSkkbcN .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-iiq8JnPvHuSkkbcN .labelText,#mermaid-svg-iiq8JnPvHuSkkbcN .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-iiq8JnPvHuSkkbcN .loopText,#mermaid-svg-iiq8JnPvHuSkkbcN .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-iiq8JnPvHuSkkbcN .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-iiq8JnPvHuSkkbcN .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-iiq8JnPvHuSkkbcN .noteText,#mermaid-svg-iiq8JnPvHuSkkbcN .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-iiq8JnPvHuSkkbcN .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-iiq8JnPvHuSkkbcN .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-iiq8JnPvHuSkkbcN .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-iiq8JnPvHuSkkbcN .actorPopupMenu{position:absolute;}#mermaid-svg-iiq8JnPvHuSkkbcN .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-iiq8JnPvHuSkkbcN .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-iiq8JnPvHuSkkbcN .actor-man circle,#mermaid-svg-iiq8JnPvHuSkkbcN line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-iiq8JnPvHuSkkbcN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} /ce-brainstormdocs/brainstorms/2026-06-22-user-auth-management-requirements.md/ce-plandocs/plans/2026-06-22-user-auth-management-plan.md修改 plan(Redis Session)更新 plan 中 KTD、.env、U1-U8/ce-work plan:...mystu/auth/, config/, controller/, static/, tests/scripts/sql/init.sql, AGENTS.md, pyproject.toml/ce-test-browser --port 5000uv run python main.pyagent-browser 打开 /login, /, /admin/users浏览器测试结果表(全部 Pass)/ce-commitgit commit 88288e9/ce-compounddocs/solutions/runtime-errors/redis-cluster-....mdCONCEPTS.mdAGENTS.md(discoverability 补充)


4. 生成文件的作用与生命周期

4.1 文档类(决策产物,长期保留)

路径 创建命令 作用 生命周期
docs/brainstorms/*.md /ce-brainstorm 需求、决策、成功标准(R/S 编号) 只读决策档案;plan 引用它,代码变更不反向修改 brainstorm
docs/plans/*.md /ce-plan 实施计划:U1-U8 单元、API、文件布局、测试场景 执行指南/ce-work 读取但不修改 plan 正文
docs/solutions/**/*.md /ce-compound 已解决问题的 playbook(YAML frontmatter 可检索) 复利知识库 ;可被 /ce-compound-refresh 更新
CONCEPTS.md /ce-compound 项目领域词汇(Session、角色、用户等) 随 learning 累积;Agent orient 时参考
AGENTS.md 人工 + CE 补充 AI 协作规范、端口、目录、CE 命令索引 Agent 的「项目 README」;随项目演进更新

重要原则: Plan 是决策 artifact,进度记在 Git commit 和任务追踪里,而不是在 plan 里打勾。

4.2 配置类(环境/偏好)

路径 是否提交 Git 生命周期
.compound-engineering/config.local.example.yaml ✅ 提交 模板;/ce-setup 可覆盖刷新
.compound-engineering/config.local.yaml ❌ gitignore 本机 CE 偏好;长期存活
.env ❌ gitignore MySQL/Redis/LLM 密钥;运行时读取

4.3 代码与测试类(可运行产物)

路径 创建阶段 作用
mystu/auth/, mystu/config/ /ce-work U1-U3 鉴权、Session、MySQL/Redis
mystu/controller/auth_api.py U4-U6 HTTP API + 页面路由
mystu/static/login.html U7 前端三页
scripts/sql/init.sql U1 数据库初始化
tests/ U8 pytest(内存替身,不依赖真实 Redis/MySQL)

生命周期: 随功能演进修改 → /ce-commit 入库 → CI/本地 pytest 持续验证。


5. /ce-test-browser --port 5000 详解

5.1 它测什么?依据哪个「测试用例文件」?

关键结论:CE 浏览器测试不依赖仓库里单独的 browser-tests.yaml 之类文件。

测试范围由 Skill 工作流 + Git 变更 + 项目约定 共同决定,数据来源如下:
#mermaid-svg-WdMf3x6yBRkTFAEB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WdMf3x6yBRkTFAEB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WdMf3x6yBRkTFAEB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WdMf3x6yBRkTFAEB .error-icon{fill:#552222;}#mermaid-svg-WdMf3x6yBRkTFAEB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WdMf3x6yBRkTFAEB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WdMf3x6yBRkTFAEB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WdMf3x6yBRkTFAEB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WdMf3x6yBRkTFAEB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WdMf3x6yBRkTFAEB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WdMf3x6yBRkTFAEB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WdMf3x6yBRkTFAEB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WdMf3x6yBRkTFAEB .marker.cross{stroke:#333333;}#mermaid-svg-WdMf3x6yBRkTFAEB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WdMf3x6yBRkTFAEB p{margin:0;}#mermaid-svg-WdMf3x6yBRkTFAEB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WdMf3x6yBRkTFAEB .cluster-label text{fill:#333;}#mermaid-svg-WdMf3x6yBRkTFAEB .cluster-label span{color:#333;}#mermaid-svg-WdMf3x6yBRkTFAEB .cluster-label span p{background-color:transparent;}#mermaid-svg-WdMf3x6yBRkTFAEB .label text,#mermaid-svg-WdMf3x6yBRkTFAEB span{fill:#333;color:#333;}#mermaid-svg-WdMf3x6yBRkTFAEB .node rect,#mermaid-svg-WdMf3x6yBRkTFAEB .node circle,#mermaid-svg-WdMf3x6yBRkTFAEB .node ellipse,#mermaid-svg-WdMf3x6yBRkTFAEB .node polygon,#mermaid-svg-WdMf3x6yBRkTFAEB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WdMf3x6yBRkTFAEB .rough-node .label text,#mermaid-svg-WdMf3x6yBRkTFAEB .node .label text,#mermaid-svg-WdMf3x6yBRkTFAEB .image-shape .label,#mermaid-svg-WdMf3x6yBRkTFAEB .icon-shape .label{text-anchor:middle;}#mermaid-svg-WdMf3x6yBRkTFAEB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WdMf3x6yBRkTFAEB .rough-node .label,#mermaid-svg-WdMf3x6yBRkTFAEB .node .label,#mermaid-svg-WdMf3x6yBRkTFAEB .image-shape .label,#mermaid-svg-WdMf3x6yBRkTFAEB .icon-shape .label{text-align:center;}#mermaid-svg-WdMf3x6yBRkTFAEB .node.clickable{cursor:pointer;}#mermaid-svg-WdMf3x6yBRkTFAEB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WdMf3x6yBRkTFAEB .arrowheadPath{fill:#333333;}#mermaid-svg-WdMf3x6yBRkTFAEB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WdMf3x6yBRkTFAEB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WdMf3x6yBRkTFAEB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WdMf3x6yBRkTFAEB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WdMf3x6yBRkTFAEB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WdMf3x6yBRkTFAEB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WdMf3x6yBRkTFAEB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WdMf3x6yBRkTFAEB .cluster text{fill:#333;}#mermaid-svg-WdMf3x6yBRkTFAEB .cluster span{color:#333;}#mermaid-svg-WdMf3x6yBRkTFAEB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WdMf3x6yBRkTFAEB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WdMf3x6yBRkTFAEB rect.text{fill:none;stroke-width:0;}#mermaid-svg-WdMf3x6yBRkTFAEB .icon-shape,#mermaid-svg-WdMf3x6yBRkTFAEB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WdMf3x6yBRkTFAEB .icon-shape p,#mermaid-svg-WdMf3x6yBRkTFAEB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WdMf3x6yBRkTFAEB .icon-shape .label rect,#mermaid-svg-WdMf3x6yBRkTFAEB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WdMf3x6yBRkTFAEB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WdMf3x6yBRkTFAEB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WdMf3x6yBRkTFAEB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 执行
推导
输入
/ce-test-browser --port 5000
git diff 变更文件列表
ce-test-browser SKILL.md文件→路由映射表
AGENTS.md端口 5000
docs/plans/*.md页面路由 + 成功标准 S1-S8
静态页与 controller 路由
待测 URL 列表
交互场景(登录/改密/登出/聊天)
agent-browser CLI
测试报告表格

5.2 执行原理(agent-browser)

CE 强制 使用 agent-browser CLI,不用 Playwright MCP 等替代方案。
FastAPI :5000 Headless/Headed Chrome agent-browser CE Agent FastAPI :5000 Headless/Headed Chrome agent-browser CE Agent #mermaid-svg-PDRhtA17ldQr8gQf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PDRhtA17ldQr8gQf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PDRhtA17ldQr8gQf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PDRhtA17ldQr8gQf .error-icon{fill:#552222;}#mermaid-svg-PDRhtA17ldQr8gQf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PDRhtA17ldQr8gQf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PDRhtA17ldQr8gQf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PDRhtA17ldQr8gQf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PDRhtA17ldQr8gQf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PDRhtA17ldQr8gQf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PDRhtA17ldQr8gQf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PDRhtA17ldQr8gQf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PDRhtA17ldQr8gQf .marker.cross{stroke:#333333;}#mermaid-svg-PDRhtA17ldQr8gQf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PDRhtA17ldQr8gQf p{margin:0;}#mermaid-svg-PDRhtA17ldQr8gQf .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PDRhtA17ldQr8gQf text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-PDRhtA17ldQr8gQf .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-PDRhtA17ldQr8gQf .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-PDRhtA17ldQr8gQf .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-PDRhtA17ldQr8gQf .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-PDRhtA17ldQr8gQf #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-PDRhtA17ldQr8gQf .sequenceNumber{fill:white;}#mermaid-svg-PDRhtA17ldQr8gQf #sequencenumber{fill:#333;}#mermaid-svg-PDRhtA17ldQr8gQf #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-PDRhtA17ldQr8gQf .messageText{fill:#333;stroke:none;}#mermaid-svg-PDRhtA17ldQr8gQf .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PDRhtA17ldQr8gQf .labelText,#mermaid-svg-PDRhtA17ldQr8gQf .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-PDRhtA17ldQr8gQf .loopText,#mermaid-svg-PDRhtA17ldQr8gQf .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-PDRhtA17ldQr8gQf .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-PDRhtA17ldQr8gQf .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-PDRhtA17ldQr8gQf .noteText,#mermaid-svg-PDRhtA17ldQr8gQf .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-PDRhtA17ldQr8gQf .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PDRhtA17ldQr8gQf .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PDRhtA17ldQr8gQf .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PDRhtA17ldQr8gQf .actorPopupMenu{position:absolute;}#mermaid-svg-PDRhtA17ldQr8gQf .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-PDRhtA17ldQr8gQf .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PDRhtA17ldQr8gQf .actor-man circle,#mermaid-svg-PDRhtA17ldQr8gQf line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-PDRhtA17ldQr8gQf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 检查 agent-browser 是否安装确认服务监听 5000(或提示启动)open http://localhost:5000/login导航HTTP GET /loginlogin.htmlsnapshot -i可交互元素 @e1 @e2 ...fill @e2 admin / fill @e3 密码click @e4 登录POST /auth/api/loginSet-Cookie + JSONsnapshot / screenshot汇总 Pass/Fail 表格

常用命令:

复制代码
agent-browser open http://localhost:5000/login
agent-browser snapshot -i          # 获取带 ref 的可点击元素
agent-browser fill '@e2' 'admin'   # PowerShell 中 ref 需引号
agent-browser click '@e4'
agent-browser screenshot out.png
agent-browser --headed open ...    # 可见浏览器窗口

5.3 本次 mystu 项目的测试结果(与截图一致)

路由 状态 说明 依据来源
/login ✅ Pass 登录表单正常 login.html + S1
/(未登录) ✅ Pass 302 → /login controller/__init__.py + S1
/(登录后) ✅ Pass 聊天页、退出、管理入口 index.html + 权限矩阵
强制改密 ✅ Pass 首次登录弹出改密面板 plan S5 + auth_api
/admin/users ✅ Pass 用户列表与 CRUD 按钮 admin/users.html + S3
退出登录 ✅ Pass 退出后 / 回登录页 auth.js + Session 设计
聊天 + Agent API ✅ Pass 发「你好」流式回复正常 api.py 鉴权 + SSE

与 pytest 的分工:

层级 工具 覆盖
API/逻辑 pytest tests/ 登录 API、权限 403、软删除等 11 项
UI/E2E /ce-test-browser 页面渲染、Cookie、重定向、流式聊天

两者互补;浏览器测试不替代 tests/test_auth_api.py


6. 其它 CE 命令的使用效果(本项目实例)

6.1 /ce-work --- 实施

  • 输入: plan:docs/plans/2026-06-22-user-auth-management-plan.md
  • 效果: 按 U1→U8 顺序生成约 30+ 文件,11 个 pytest 全绿
  • 分支: 自动使用 feat/user-auth

6.2 /ce-commit --- 提交

  • 效果: 中文 conventional commit,例如 feat(auth): 新增用户登录与 Session 鉴权体系
  • 原则: 仅用户明确要求时提交;不主动 push

6.3 /ce-compound --- 知识沉淀

  • 触发场景: Redis Cluster 启动 AttributeError: 'dict' object has no attribute 'host'
  • 产出:
    • docs/solutions/runtime-errors/redis-cluster-startup-nodes-clusternode-dict-host.md
    • CONCEPTS.md(Session、用户、角色等术语)
    • AGENTS.md 增加 docs/solutions/ 检索提示

frontmatter 示例(便于 Agent 检索):

复制代码
module: auth
problem_type: runtime_error
tags: [redis-cluster, clusternode, startup-nodes]

7. 文件生命周期总图

#mermaid-svg-XMsJsiG4zQ1if6cK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XMsJsiG4zQ1if6cK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XMsJsiG4zQ1if6cK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XMsJsiG4zQ1if6cK .error-icon{fill:#552222;}#mermaid-svg-XMsJsiG4zQ1if6cK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XMsJsiG4zQ1if6cK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XMsJsiG4zQ1if6cK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XMsJsiG4zQ1if6cK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XMsJsiG4zQ1if6cK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XMsJsiG4zQ1if6cK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XMsJsiG4zQ1if6cK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XMsJsiG4zQ1if6cK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XMsJsiG4zQ1if6cK .marker.cross{stroke:#333333;}#mermaid-svg-XMsJsiG4zQ1if6cK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XMsJsiG4zQ1if6cK p{margin:0;}#mermaid-svg-XMsJsiG4zQ1if6cK defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-XMsJsiG4zQ1if6cK g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-XMsJsiG4zQ1if6cK g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-XMsJsiG4zQ1if6cK g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-XMsJsiG4zQ1if6cK g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-XMsJsiG4zQ1if6cK g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-XMsJsiG4zQ1if6cK .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-XMsJsiG4zQ1if6cK .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-XMsJsiG4zQ1if6cK .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-XMsJsiG4zQ1if6cK .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-XMsJsiG4zQ1if6cK .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-XMsJsiG4zQ1if6cK .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-XMsJsiG4zQ1if6cK .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-XMsJsiG4zQ1if6cK .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XMsJsiG4zQ1if6cK .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XMsJsiG4zQ1if6cK .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XMsJsiG4zQ1if6cK .edgeLabel .label text{fill:#333;}#mermaid-svg-XMsJsiG4zQ1if6cK .label div .edgeLabel{color:#333;}#mermaid-svg-XMsJsiG4zQ1if6cK .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-XMsJsiG4zQ1if6cK .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-XMsJsiG4zQ1if6cK .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-XMsJsiG4zQ1if6cK .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-XMsJsiG4zQ1if6cK .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-XMsJsiG4zQ1if6cK .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XMsJsiG4zQ1if6cK .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XMsJsiG4zQ1if6cK #statediagram-barbEnd{fill:#333333;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XMsJsiG4zQ1if6cK .cluster-label,#mermaid-svg-XMsJsiG4zQ1if6cK .nodeLabel{color:#131300;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-XMsJsiG4zQ1if6cK .note-edge{stroke-dasharray:5;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-note text{fill:black;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram-note .nodeLabel{color:black;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagram .edgeLabel{color:red;}#mermaid-svg-XMsJsiG4zQ1if6cK #dependencyStart,#mermaid-svg-XMsJsiG4zQ1if6cK #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-XMsJsiG4zQ1if6cK .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XMsJsiG4zQ1if6cK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} /ce-commit
/ce-brainstorm
/ce-plan
/ce-work
/ce-test-browser
pytest tests/
/ce-compound
/ce-compound-refresh
更新过时文档
Brainstorm
docs/brainstorms/*.md
Plan
docs/plans/*.md
Code
mystu/**
tests/**
scripts/**
BrowserTest
Pytest
Commit
Solution
docs/solutions/**
CONCEPTS.md
Refresh

各阶段文件是否修改:

阶段 可修改 不应修改
/ce-work 执行中 源代码、tests、AGENTS.md plan 正文(决策档案)
/ce-compound 新增 solutions、CONCEPTS 已关闭的 brainstorm
生产运行 .env、本地 config config.local.example 以外的密钥进 Git

8. 推荐使用方式(Checklist)

8.1 新功能(中大型)

  1. /ce-setup --- 确认 agent-browser 等工具就绪
  2. /ce-brainstorm --- 产出需求文档
  3. /ce-plan --- 产出实施计划(含 U 单元、测试场景)
  4. /ce-work plan:docs/plans/xxx.md --- 编码
  5. pytest tests/ -q --- 自动化回归
  6. python main.py + /ce-test-browser --port 5000 --- UI 验收
  7. /ce-code-review --- 大改动审查
  8. /ce-commit --- 提交
  9. 遇坑并解决后 /ce-compound --- 沉淀

8.2 小修复

  • 可直接 /ce-work 或 Agent 改代码
  • 仍建议 /ce-compound 记录非显然的问题(如 Redis ClusterNode)

8.3 Agent 如何找到历史经验

AGENTS.md 中已补充:

  • docs/solutions/ --- 按 moduletagsproblem_type 检索
  • CONCEPTS.md --- 理解 Session、用户等领域词

9. 常见问题

Q1:为什么没有 browser-tests.yml

CE 的设计是 「变更驱动 + Skill 规程 + 计划成功标准」,而不是维护第二套静态 E2E 用例文件。好处是与 PR/分支 diff 自动对齐;代价是测试步骤由 Agent 现场执行,需本地服务与账号可用。

Q2:/ce-test-browser 和 pytest 哪个优先?

先 pytest(快、稳定、可 CI),再 browser(验 UI、Cookie、SSE、重定向)。

Q3:plan 里的 U 单元和 browser 测试的关系?

  • U 单元/ce-work 的实施顺序与完成定义
  • U 内 Test scenarios:指导 pytest 写哪些 case
  • S1--S8 成功标准 :指导 /ce-test-browser 验哪些用户路径

三者同源(plan),但执行载体不同。

Q4:Windows 上 bash 脚本失败怎么办?

/ce-setupcheck-health 可能无法运行;可手动 npm install -g agent-browser,并参照 AGENTS.md 端口与命令。


10. 总结

Compound Engineering 把 AI 编程从「一次性对话」升级为可检索、可复用、可验收的工程流程:

层次 代表命令 复利价值
环境 /ce-setup 工具与配置一次就绪
决策 brainstorm → plan 需求与方案可追溯
交付 /ce-work + pytest 可运行代码
体验 /ce-test-browser 真实浏览器路径验证
记忆 /ce-compound 下次同类问题更快

/ce-test-browser --port 5000 的测试表并非来自单一配置文件,而是 Git 变更 + Skill 路由映射 + plan 成功标准 + 静态页/路由实现 共同推导;Agent 用 agent-browser 在真实浏览器里执行登录、改密、管理页、流式聊天等路径,最终给出你截图中的 Pass 表。