mcpField
M
moai-workflow-loop

moai-workflow-loop

github.com/modu-ai测试与质量1.2k75 次安装今天更新
代码仓库

关于 moai-workflow-loop

moai-workflow-loop 是用于 Claude Code 的迭代式代码质量检查与修复技能,结合 LSP 诊断、AST-grep 扫描和测试验证,直至满足配置的完成条件。

主要功能

  1. 01文件编辑后的 LSP 诊断
  2. 02AST-grep 安全与质量扫描
  3. 03带完成检查的迭代修复循环
  4. 04Claude Code PostToolUse 与 Stop 钩子

适用场景

  1. 01持续修复代码,直至诊断通过
  2. 02检查代码安全与质量规则
  3. 03修复过程中运行测试和覆盖率检查

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/modu-ai/moai-adk --skill moai-workflow-loop

安装后在 Claude Code 中输入/moai-workflow-loop确认已加载。

附带文件references/examples.mdreferences/reference.md

详细介绍

Ralph Engine

自动化反馈循环系统,集成 LSP 诊断、AST-grep 安全扫描和测试验证,持续提升代码质量。

预设架构 — Ralph Engine 作为目标预设

/moai loop 技能(~/.claude/skills/moai/workflows/loop.md)将这个 Ralph engine 重新表述为构建于目标引擎之上的目标预设:扫描阶段会构建有限的问题队列,而持续迭代直至完成的决策则交由目标引擎(stop-goal)处理,并预先填入条件“队列清空 + 诊断无误”。在这种预设架构中,本 SKILL.md 文档记录了目标预设扫描所驱动的底层 LSP / AST-grep / 测试 / 覆盖率诊断机制;预设在该机制之上叠加目标引擎的组合方式,不会改变该机制。四种循环象限(基于目标的扫描、基于轮次的 /moai fix、基于时间的周期执行、主动监控 CI)是同一个目标引擎上的预设,而非独立引擎。

快速参考

核心功能:

  • LSP 集成:从语言服务器获取实时诊断信息
  • AST-grep 扫描:结构化代码分析与安全检查
  • 反馈循环:反复修正错误,直至满足完成条件
  • 钩子系统:通过 PostToolUse 和 Stop 钩子与 Claude Code 无缝集成

核心组件:

  • .claude/hooks/moai/handle-post-tool.sh (PostToolUse):在 Write/Edit 操作后运行 LSP 诊断
  • .claude/hooks/moai/handle-stop.sh (Stop):控制循环迭代
  • ralph.yaml:配置设置

命令:

  • /moai:一键完成 Plan-Run-Sync 自动化(默认)
  • /moai loop:启动反馈循环
  • /moai fix:执行一次自动修复

适用场景:

  • 以零错误为目标实现功能
  • 自动提升代码质量
  • 持续集成工作流
  • 错误驱动的开发模式

实现指南

架构概述

Ralph Engine 采用分层架构。用户命令(如 /moai:loop、/moai:fix 和 /moai)进入命令层。命令层调用钩子系统,其中包含用于 LSP 诊断的 PostToolUse 钩子和用于循环控制的 Stop 钩子。钩子系统连接到后端服务,包括 LSP 客户端(MoAILSPClient)、AST-grep 扫描器和测试运行器。后端服务将结果传递给完成检查,由其评估错误是否为零、测试是否通过以及覆盖率是否达标。根据完成检查的结果,系统会继续循环或完成任务。

配置

ralph.yaml 配置文件包含以下部分和设置。

在 ralph 部分,enabled 控制 Ralph 是否启用(默认值为 true)。

在 lsp 部分,auto_start 控制是否自动启动语言服务器(默认值为 true),timeout_seconds 设置连接超时时间(默认值为 30 秒),graceful_degradation 用于在 LSP 不可用时启用回退到代码检查工具(默认值为 true)。

在 ast_grep 部分,enabled 控制是否集成 AST-grep(默认值为 true),security_scan 启用安全规则检查(默认值为 true),quality_scan 启用代码质量规则检查(默认值为 true)。

在 loop 部分,max_iterations 设置最大循环次数(默认值为 10),auto_fix 控制是否自动应用修复(默认值为 false,需要确认),require_confirmation 要求在修复前获得用户批准(默认值为 true)。

在 loop 的 completion 子部分,zero_errors 要求不存在 LSP 或编译器错误(默认值为 true),zero_warnings 要求不存在警告(默认值为 false,可选),tests_pass 要求所有测试通过(默认值为 true),coverage_threshold 设置最低覆盖率百分比(默认值为 85)。

在 hooks 部分,post_tool_lsp 的 enabled 为 true(默认值),severity_threshold 为 error(默认值)。stop_loop_controller 的 enabled 默认设为 true。

钩子集成
PostToolUse Hook

PostToolUse Hook 会在 Write 和 Edit 操作后触发。调用时,Claude Code 会提供 Hook 输入,其中包含 tool_name(例如 Write)和包含 file_path 与 content 的 tool_input。

Hook 会处理诊断结果,并返回包含 hookSpecificOutput 的 Hook 输出,其中包括 hookEventName(PostToolUse)和用于描述诊断结果的 additionalContext。例如,上下文可能会报告 LSP 在 file.py 中发现 2 个错误和 3 个警告,并提供包含行号的具体错误消息。

退出代码 0 表示无需采取任何操作。退出代码 2 表示发现错误,需要关注。

循环控制器的 Stop Hook

Stop Hook 会在每次 Claude 响应后触发。Hook 会读取位于 .moai/cache/.moai_loop_state.json 的循环状态文件。此状态包含 active 状态(true 或 false)、当前迭代编号、max_iterations 限制、上一轮迭代的 last_error_count,以及完成时的 completion_reason。

Hook 会返回包含 hookSpecificOutput 的输出,其中包括 hookEventName(Stop)和用于报告循环状态的 additionalContext。例如,它可能会报告 Ralph Loop CONTINUE,当前为第 3 轮迭代(共 10 轮),有 2 个错误,并给出修复剩余错误的后续操作。

退出代码 0 表示循环已完成或处于非活动状态。退出代码 1 表示继续循环,还需要执行更多工作。

LSP 客户端用法

Go LSP 客户端已集成到 Hook 系统中。LSP 诊断会通过 PostToolUse Hook(moai hook post-tool-use)自动收集。

要获取某个文件的诊断结果,请使用文件路径异步调用 get_diagnostics 方法。

遍历返回的每个诊断对象来处理诊断结果。检查 severity 属性是否为 DiagnosticSeverity.ERROR,以识别错误。通过 diag.range.start.line 获取行号,通过 diag.message 获取消息。

完成条件

所有启用的条件都满足时,循环即完成。

zero_errors 条件(默认值为 true)要求不存在 LSP 或编译器错误。

zero_warnings 条件(默认值为 false)可选地要求不存在警告。

tests_pass 条件(默认值为 true)要求所有测试通过。

coverage_threshold 条件(默认值为 85)要求达到最低覆盖率百分比。

高级模式

自定义完成条件

通过实现检查函数,为循环控制器扩展自定义条件。例如,创建一个函数来统计代码库中的 TODO 注释,并仅在数量为零时返回 true。

与 CI/CD 集成

要集成 GitHub Actions,请创建一个工作流步骤,使用 /moai:loop 命令和 max-iterations 标志运行 Claude。将 MOAI_LOOP_ACTIVE 环境变量设为 true,以启用循环模式。

优雅降级

LSP 不可用时,系统会回退到基于 linter 的诊断,使用 ruff 或 eslint 等工具;然后回退到编译器错误检测,最后回退到测试失败检测。

故障排除

循环未启动

检查配置中的 ralph.enabled 是否设为 true。确认未设置 MOAI_DISABLE_LOOP_CONTROLLER 环境变量。确保状态文件所在位置可写。

缺少 LSP 诊断

检查 .moai/config/sections/lsp.yaml 中的 LSP 服务配置。确认已为你的语言安装语言服务器。检查是否未设置 MOAI_DISABLE_LSP_DIAGNOSTIC 环境变量。

循环卡住

检查 max_iterations 设置,确保允许足够的迭代次数。检查完成条件,确认这些条件可以实现。发送任意消息以中断循环,或删除状态文件(.moai/cache/.moai_loop_state.json)以重置。

适配良好的工具

技能:

  • moai-foundation-quality:TRUST 5 验证
  • moai ast-grep / moai ast-edit:安全扫描模式与重写
  • moai-workflow-testing:DDD 集成
  • .claude/rules/moai/languages/python.md:Python 特定模式(通过 paths frontmatter 自动加载)
  • .claude/rules/moai/languages/typescript.md:TypeScript 模式(通过 paths frontmatter 自动加载)

Agent:

  • manager-develop:DDD 实现
  • manager-develop (cycle_type=autofix):复杂调试与修复方案(前 manager-quality 调试角色)
  • /moai gate 技能或 sync-phase-quality-gate.sh Stop 钩子:质量验证(前 manager-quality gate 角色)

命令:

  • /moai:run:DDD 实现
  • /moai:sync:文档同步

参考

环境变量

设置 MOAI_DISABLE_LSP_DIAGNOSTIC 后会禁用 LSP 钩子。

设置 MOAI_DISABLE_LOOP_CONTROLLER 后会禁用循环钩子。

MOAI_LOOP_ACTIVE 表示循环当前是否处于活动状态。

MOAI_LOOP_ITERATION 包含当前迭代编号。

CLAUDE_PROJECT_DIR 包含项目根目录路径。

文件位置

配置存储在 .moai/config/sections/ralph.yaml 中。

循环状态存储在 .moai/cache/.moai_loop_state.json 中。

LSP 钩子位于 .claude/hooks/moai/handle-post-tool.sh。

循环钩子位于 .claude/hooks/moai/handle-stop.sh。

支持的语言

LSP 诊断适用于 MoAI 支持的全部 16 种语言:C++、C#、Elixir、Flutter、Go、Java、JavaScript、Kotlin、PHP、Python、R、Ruby、Rust、Scala、Swift 和 TypeScript。Ralph 通过标记文件(例如,Go 使用 go.mod、Python 使用 pyproject.toml、TypeScript 使用 tsconfig.json、Rust 使用 Cargo.toml、Flutter 使用 pubspec.yaml)检测项目语言,并按需启动相应的语言服务器。用户只需安装项目实际需要的服务器;缺少服务器时会发出警告并跳过,同时提示安装方式,不会导致硬性失败。完整的语言服务器到二进制文件映射表请参见 references/reference.md。根据 .claude/rules/moai/development/coding-standards.md § Language Policy(16 种语言中立性约定),任何语言都不会获得优先权。


版本:1.2.0 状态:Active 集成:Claude Code Hooks、LSP Protocol、AST-grep 技能名称:moai-workflow-loop(前称 moai-ralph)

常见托词

托词实际情况
“我会在循环结束后手动修复剩余错误。”后续手动修复意味着循环没有完成任务。遗留错误就是已交付的错误。
“循环达到最大迭代次数了,剩余问题都不重要。”迭代次数限制是为了控制成本,不是质量保证。请报告尚未解决的问题列表。
“LSP 警告不是真正的错误。”跨迭代持续存在的警告表明有结构性问题被忽略了。请处理这些问题,或明确抑制它们。
“我修复了根本原因,其他诊断结果会自行消失。”级联修复并无保证。请再次运行诊断,并验证每项问题都已解决。
“ast-grep 规则对这个代码库来说太严格了。”规则体现了项目约定。请说明理由后禁用特定规则,不要跳过整个扫描。
“这次迭代没有进展,我应该停下来。”停滞 2 次迭代后应升级处理,而不是悄然退出。请遵循升级处理流程。

500 行规则:涉及超过 500 行的更改,应单独进行一次循环迭代并针对性地运行诊断。大规模更改会掩盖个别回归。

危险信号

  • 循环退出时仍有未解决的错误,且没有停滞报告
  • 同一诊断结果连续多个迭代出现,却没有得到处理
  • 完全禁用了 ast-grep 扫描,而非禁用特定规则
  • 循环开始迭代时未采集 LSP 基线
  • 循环迭代之间进行了手动代码更改,却没有重新运行诊断

验证

  • 进度日志中记录了每次迭代及错误数量变化
  • 最后一次迭代显示错误数量为零,或包含明确的停滞报告
  • 在循环开始时捕获了 LSP 基线(显示诊断数量)
  • 循环期间至少运行过一次 ast-grep 扫描(显示输出)
  • 记录了未解决项及无法修复的原因
  • 连续迭代之间的诊断数量没有增加

评论

支持 Markdown