开发者视角

写给想扩展 LazyZCode、参与贡献或对接集成的开发者。文档 讲的是工作流,这一页讲机器。本页全部内容取自实际源码(plugin/core/cli/)——不画饼,只写已发布的部分。

系统架构

LazyZCode 是边界分明的三块:引擎加载的插件、独占循环状态的 CLI、以及项目 自留的状态目录。

ZCode 引擎 lazyzcode:zw 插件 lzy CLI .lazyzcode/ git 仓库 桌面端 · zcode.cjs skills/zw · 编排文本 hooks ×6 · 经 run-hook 启动器 agents ×3 · 只读角色 目标循环状态机 goal.json · plans · evidence HEAD^{tree} 装载插件 触发钩子事件 官方 plugins enable · config.json 零写入 读 / 写 证据绑定 HEAD^{tree}
边界是有意为之:安装器永不写你的 config.json(启用只走引擎官方 plugins enable),循环状态留在项目内,插件载荷零运行时依赖。

设计准绳按序:Skill > MCP > Tool > Hook。离线了也无所谓的放技能文本; 钩子是最后手段,且一律写成 fail-open。

目标循环:一台状态机

lzy loop 是磁盘上的朴素状态机(无守护进程)。技能文本驱动模型走完它; CLI 把守每一处迁移。

注册 计划门 执行中 终验门 完成 决策完备 HEAVY 须评审 PASS Stop 钩子拉回 · 每会话 ≤2 次 lzy step done · F 项须带证据
每次迁移都是一条 CLI 命令;每道门都是一个有权拒绝的检查。Stop 钩子是唯一能把模型推回工作的东西,而它预算封顶、异常即放行。
lzy loop register <slug> --title "…"
lzy loop plan <计划.md> --review "plan-reviewer: PASS …"
lzy loop start
lzy step done <ID> --evidence "curl /export -> 200,可按 CSV 解析"
lzy loop finish

证据绑定

整个产品的核心技巧:证据绑定到提交的内容快照,因此它不可能悄悄腐烂。

提交 A · tree 95a0… 提交 B… · tree c3f1… 提交 C · tree 7d22… F 项证据取证 绑定:95a0… finish 重查新鲜度 95a0… 的证据对 7d22… 已过期
先提交,再取证。代码一变,旧证据按构造即过期,lzy loop finish 拒绝之;lzy step done 在重取证时重新绑定。

两个有意为之的推论:.lazyzcode/ 自身永不计入脏工作区;「测试全绿」只是 众多表面之一,永远不能替代 F 项指名的表面。

钩子生命周期

六个钩子骑在引擎的会话时间线上。它们全部经 plugin/hooks/run-hook 拉起:POSIX 按 PATH → nvm → Homebrew 顺序解析 node(Windows 经 PATHEXT 把同一清单行解析到 run-hook.cmd 孪生,兜底 nvm-windows/Program Files), 从 Dock 直启的 ZCode(钩子环境没有 node)也能正常工作;解析结果由 lzy doctorhook-node 检查报告。

SessionStart UserPromptSubmit PreToolUse PostToolUse PostToolUseFailure Stop 向新会话重注入 循环状态 触发词匹配 → 注入 zw 引导 命令层 H3R 门 (休眠原型) comment-checker 轻提示 (Edit / Write) 同工具失败连击 绊线告警一次 请求续跑 ≤2 次 · 交接放行 session-start.js · trigger.js · comment-checker.js · h3r-pretool.js · tripwire.js · stop.js — 全部经 run-hook 启动器拉起
引擎暴露 7 个钩子事件和共享池 3 次 stop-continuation(后台通知 同池扣减);LazyZCode 每会话至多花 2 次,任何异常一律放行。

扩展它

加一只纪律角色。plugin/agents/ 丢一个带 frontmatter 的 Markdown 文件即可,引擎自动发现该目录。角色是只读契约:explorer(侦察,给 file:line 证据)、plan-reviewer(VERDICT: PASS | REVISE)、 qa-executor(原样报告实际观察,绝不推断)。新角色的输出契约务必可被机器 校验。

触发词匹配plugin/hooks/trigger.js,分层是有意设计:

模式 触发位置
/^\s*zw(?![a-z0-9_-])/i 仅句首
/lazyzcode[::]zw/i 任意位置,全角冒号亦可
`/(^ [^a-z0-9_-])(ulw

钩子输出契约: 只有 Stop 钩子能续跑会话,且仅限 {continue:true, additionalContexts:[非空]}(引擎自身契约);其余四钩子只发 {additionalContext}——纯注入。其余任何情况,包括崩溃,一律 fail-open, 绝不困住会话。

配置面: 一个环境变量。LZY_ZCODE_ENGINE 整体替换引擎候选列表;其余 一切从仓库与引擎状态推导。

构建、测试、预览

npm test                      # node:test 契约测试,零依赖
cd scripts/docs-preview       # dev-only 工具链(独立 package.json)
npm install
npm run build                 # docs/ -> dist/(Jekyll 同构模拟)
npm run check                 # 爬链 + 锚点完整性,任何 miss 即退出码 1

CI 在 node 22 / 24 上跑全套。文档站由 GitHub Pages 从 /docs 构建 (Jekyll,GFM);scripts/docs-preview/build.mjs 在本地镜像同一条管线—— Pages 在其上多一层 rouge 语法高亮,其余一致。

兼容性备注


LazyZCode 以 MIT 发布。工作流受 lazycodex(MIT)启发;OmO (SUL-1.0)仅贡献思想。文档结构参照 lazycodex 文档并注明出处。