TDD代理工作流编排器(Pi Native)
一个深度集成的代理TDD工作流引擎,用于 Pi编码代理它用原生Pi子代理会话取代了严格的基于JSON的编排,使用本地或云LLM提供手术文件编辑和自校正开发循环。
运作原理
Pi says "/tdd implement JWT auth"
│
▼
┌─────────────┐
│ Planner │ ← Web search for best practices
│ (sub-agent) │
└──────┬──────┘
│ Subtasks
▼
┌─────────────┐ ┌───────────────────┐
│ Implementer │ ──▶ │ Quality Gates │
│ (Sub-Agent) │ │ lens (Type/AST) │
└──────┬──────┘ │ tsc → tests │
│ │ → lint │
│ │ + test metrics │
│ │ + coverage │
│ └──────┬────────────┘
│ (Read/Edit) │ Pass/Fail
▼ ▼
┌─────────────┐ Algorithm decides:
│ Reviewer │ merge or retry
│ (Sub-Agent) │ (not the AI)
└─────────────┘编排器诞生了 短暂的无头子代理会话 用于规划、实施和审查。这些代理使用Pi的原生 read, write, edit,以及 bash 工具直接放在文件系统上。
- 自愈:如果质量门失败,执行器将回滚更改并将确定性故障日志注入到 *下一个* 尝试的系统提示。
- Git沙盒:每个子任务都在一个独立的git分支中运行。只有经过验证和审查的代码才会被合并。
- 确定性质量:虽然实现是代理的,但门(TSC、Vitest等)是100%确定的。
快速开始
1.先决条件
- Node.js 20+
- llama.cpp 跑步(与 Pi-llama.cpp提供者 建议用于自动模型设置)
2.安装并注册
npm install
npm run build
# Register the extension with Pi
pi install local:.3.配置模型
从任何Pi会话中运行交互式设置:
/setup这将从llama.cpp中发现可用的模型,允许您将每个模型分配给代理角色,并保存配置。使用 --global 保存为系统范围的默认值(~/.config/tdd-workflow/models.config.json)这适用于所有项目。
4.启动工作流
在任何项目中,使用斜线命令:
- 设置:
/setup--交互式配置模型路由 - 计划:
/plan "Build a secure login system"--分解为Epics/WorkItems - 实施:
/tdd 1--从加载Epic 1WorkItems/并执行 - 从失败中恢复:
/tdd 1 retry--从头开始重试失败的任务;/tdd 1 resume--在保留审阅者反馈的情况下重试;/tdd 1 continue--跳过失败并继续 - 暂停/停止/恢复 _(工作流程中期)_:
- /tdd:pause --完成当前代理回合,然后停止。WIP分支+反馈+尝试被保留。 - /tdd:stop --立即中止正在运行的代理,回滚当前任务,将其重置为挂起。Repo看起来任务从未运行过。 - /tdd:resume --从暂停的工作流中恢复。
- 清理:
/tdd:project-cleanup--扫描所有质量门,然后运行TDD工作流来修复每个预先存在的故障 - 运行测试:
/tdd:test--运行项目的测试套件并报告失败 - 研究:
/research "Best practices for React state 2026"--deepweb研究代理 - 分析:
/analyze--建筑蓝图
5.MCP服务器模式
编排器也可以作为独立的MCP服务器运行:
node dist/interfaces/mcp/index.js模型配置
模型路由由以下因素驱动 models.config.json系统检查两个位置并将其合并,项目配置在任何冲突中获胜:
| 地点 | 目的 |
|---|---|
~/.config/tdd-workflow/models.config.json | 全系统默认值(所有项目) |
| ` | |
| /models.config.json` | 项目特定覆盖 |
创建或更新任一文件的最简单方法是通过 /setup 在Pi。您也可以直接编辑JSON。
最小配置形状:
{
"models": {
"my-fast-model": {
"name": "Qwen3 30B-A3B",
"ggufFilename": "qwen3-30b-a3b-q4.gguf",
"provider": "local",
"contextWindow": 40960,
"maxOutputTokens": 8192,
"architecture": "moe",
"speed": "fast",
"enableThinking": false
},
"my-thinking-model": {
"name": "Gemma 4 27B",
"ggufFilename": "gemma-4-27b-q4.gguf",
"provider": "local",
"contextWindow": 128000,
"maxOutputTokens": 8192,
"architecture": "dense",
"speed": "slow",
"enableThinking": true
}
},
"routing": {
"plan": "my-thinking-model",
"project-plan": "my-thinking-model",
"implement": "my-fast-model",
"review": "my-thinking-model",
"arbitrate": "my-thinking-model",
"research": "my-fast-model"
}
}路由密钥 除了你实际使用的那些之外,其他都是可选的。任何未明确路由的角色都将回退到 plan 模型。 /setup 配置 plan, project-plan, implement, review,以及 research --您可以添加 arbitrate 如果您希望死锁打破仲裁器与计划器位于不同的模型上,请手动操作。
enableThinking 告诉指挥者激活Pi的推理模式(setThinkingLevel('medium'))并从多回合消息历史中去除思维障碍,以保持高质量。推理令牌注入是在llama.cpp/chat模板级别处理的——不需要插件端的提示突变。
云提供商 也得到了支持。API密钥必须通过环境变量提供-从不硬编码:
{
"modelId": "anthropic/claude-sonnet-4",
"provider": "openrouter",
"apiKeyEnvVar": "OPENROUTER_API_KEY"
}models.config.json和models.config.local.json列在.gitignore以防止意外的秘密犯罪。
执行者→ 审阅者交接
实现者和审阅者是通过结构化工件而不是共享内存进行通信的独立代理:
- 实现注意事项 --在会话结束时,实现者写道
.tdd-workflow/implementation-notes.md解释设计决策、权衡以及它故意留下的任何预先存在的问题。 - Git 差异 --执行者捕获
git diff HEAD在实现者完成并将其(加上更改的文件列表)直接注入审阅者的提示符后。 - 范围审查 --审阅者被指示将diff视为其主要事实来源,只有在diff本身不足以评估类型或测试路径时才读取其他文件。
这意味着审阅者总是确切地知道发生了什么变化以及为什么——它不需要通过探索文件系统来发现变化。
安全和失控保护
| 守卫 | 它捕获了什么 | 行为 |
|---|---|---|
| 最大尝试次数 (5/任务) | 持续失败 | 放弃前触发中立仲裁器 |
| 仲裁者 (尝试5次后) | 实施者/审阅者死锁 | 批准、最多额外授予3轮或升级给您 |
| 输出相似性 (>90%) | 代理人陷入困境 | 在浪费审稿人的时间之前,立即保释 |
| 执行器超时 (60分钟) | 挂起执行者会话 | 扔进接球区;下一次尝试重新开始 |
| 审阅者超时 (60分钟) | 暂停评审环节 | 相同——不受执行者预算限制 |
| 仲裁员超时 (20分钟) | 暂停仲裁会话 | 默认升级 |
| 断路器 (连续3次失败) | 系统问题 | 停止整个工作流程 |
每个代理通过以下方式独立执行超时 Promise.race当一个任务用尽所有尝试时 中立仲裁者 审查最终差异、质量门状态和审查员反馈,然后决定:
- 批准 --QA通过,审核人员过于严格;按原样合并
- 继续N --额外资助1-3轮实施
- 升级 --将情况发布到Pi聊天,等待您的回复
approve,continue 1–3,或stop
当任务最终失败时,工作流停止并发布一条聊天消息,其中包含分支名称、状态文件位置和确切的恢复命令。故障的分支会被保留以供检查,不会自动清理任何内容。
暂停和停止工作流
编排器在后台运行一次 /tdd 被调用,但您可以随时中断它的聊天:
| 操作 | 它的作用 | 当前任务最终为 | 分支 | 反馈/尝试 |
|---|---|---|---|---|
/tdd:pause | 完成当前代理回合,然后停止工作流。 | paused | 保存 | 保存 |
/tdd:stop | 立即中止正在运行的代理,将任务分支回滚到基。 | pending (重置) | 回滚 | 清除 |
/tdd:resume | 恢复暂停的工作流程——拾取暂停的任务,其WIP分支+反馈保持不变。 | pending → 运行到完成 | 重用 | 保留 |
何时使用哪个:
- 暂停 当您需要退出、重新启动或上下文切换,并希望稍后在代理所在的位置继续时。保留任务的进度和审阅者的反馈。
- 停止 当你意识到当前的任务毫无进展,你想要一个全新的开始——例如,计划员对工作范围界定错误,或者你想手工编辑和重新计划。史诗中的其他任务未被触及。
/tdd:resume 拿起任何 paused 自动任务。您还可以使用现有的 /tdd N resume / /tdd N retry / /tdd N continue 子命令——它们与暂停/停止一起工作。
项目清理
/tdd:project-cleanup 在任何代理启动之前运行质量门,总结聊天中的每个失败门,然后将结构化的清理简报交给标准TDD执行者。即时计划器将“修复这些特定故障”分解为每个门的子任务,每个子任务都要经过正常的实施→ 审查→ 合并循环。
- 实现者被指示只修复其正在修改的文件中的故障,因此清理保持作用域,不会导致无关的漂移。
- 在清理过程中始终会收集覆盖率快照(即使没有
coverageThresholds)因此,规划者可以看到覆盖率低的地方,并在有意义的情况下添加测试改进子任务。除非明确配置了阈值,否则覆盖率数字永远不会阻止清理工作流程。 - 全栅极输出(可能较大)被写入
.tdd-workflow/logs/gate-report-.log。清理简报嵌入了指向此文件的截断摘要;实现者代理可以在需要更多上下文时读取完整日志。 - 描述中提到“覆盖率”或“添加测试”的子任务会自动告诉实现者使用覆盖率命令进行验证,并在
DONE:消息。
多语言支持
编排器包括一个本机代码分析器,支持:
- Types/JavaScript:通过以下方式进行完整的AST分析
ts-morph. - C:通过Roslyn sidecar进行分析(需要.NET 10 SDK)。
- C:AST分析
tree-sitter.
提交消息
每次尝试的实施者提交都包括质量门结果和测试/覆盖率指标:
TDD [Attempt 1]: Create JWT token generation
---
Attempt: 1
Quality Gates:
✅ typescript (blocking)
✅ tests (blocking)
✅ coverage (blocking)
⚠️ lint
Tests: 47/47 passed
Coverage: 87.3% lines, 72.1% branches, 91.0% functions发展
npm run test # Run unit tests (vitest)
npm run test:watch # Run tests in watch mode
npm run test:coverage # Run tests with coverage
npm run build # Compile TypeScript + bundle
npm run build:csharp # Build the Roslyn C# analyzer (requires .NET 10 SDK)
npm run build:all # Full build (csharp + typescript)
npm run deploylocal # Symlink into ~/.pi/extensions for live development项目配置(tddConfig 在 package.json)
可选设置可以放置在 tddConfig 项目的关键 package.json:
"tddConfig": {
"coverageThresholds": {
"lines": 80,
"functions": 80,
"branches": 70
},
"fileSafetyAllowlist": ["fixtures/", "custom-dir/"]
}| 密钥 | 默认值 | 描述 |
|---|---|---|
coverageThresholds | _(未设置)_ | 选择加入。 当存在时,覆盖门会阻塞并强制执行这些最小值。完全省略此键以禁用阻塞覆盖门(仍会收集覆盖指标以进行报告)。支持的阈值: lines, functions, branches, statements. |
fileSafetyAllowlist | [] | 不应标记文件安全门的额外路径前缀。请参阅下面的内置前缀。 |
内置文件安全前缀 (始终允许--无需配置): src/, tests/, test/, __tests__/, e2e/, lib/, libs/, apps/, packages/, docs/, scripts/, config/, public/, static/, assets/, styles/, schemas/, migrations/, prisma/, coverage/, .github/, .vscode/, .pi-lens/, .tdd-workflow/
内置文件安全模式 (在回购根目录匹配):
- 包裹清单/锁文件(
package.json,pnpm-lock.yaml,yarn.lock,bun.lockb,pnpm-workspace.yaml) - TS/lint/格式化器配置(
tsconfig*.json,.eslintrc*,eslint.config.*,vitest.config.*,jest.config.*,prettier.config.*,.prettierrc*) - 根点文件(
.gitignore,.gitattributes,.editorconfig,.nvmrc,.dockerignore,.env.example等等) - 框架/单回购/捆绑商配置(
turbo.json,nx.json,project.json,vite.config.*,next.config.*,tailwind.config.*等等) - Docker(
Dockerfile*,docker-compose*.yml,.docker/) - 根文档(
README*,CHANGELOG*,LICENSE*,CONTRIBUTING*,以及任何*.md/*.mdx根)
环境变量
| 变量 | 默认值 | 描述 |
|---|---|---|
LLAMA_CPP_URL | http://localhost:8080/v1 | llama.cpp服务器URL |
SEARXNG_URL | http://localhost:8888 | SearXNG搜索URL |
OPENROUTER_API_KEY | - | OpenRouter模型的API密钥 |
OPENAI_API_KEY | - | OpenAI模型的API密钥 |
TDD_WORKFLOW_CONFIG_DIR | -- | 覆盖配置文件搜索目录 |
LENS_FAIL_POLICY | fail-closed | fail-open 碰撞时跳过镜头门; fail-closed 将碰撞视为失败 |
TDD_SLOT_RECOVERY_MS | 5000 | 在重新使用插槽之前,子代理处理后等待毫秒 |
TDD_MCP_STARTUP_MS | 5000 | 会话创建后等待MCP服务器(上下文模式,searxng)注册工具的毫秒数 |
