@ai-content-space/loopx 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,10 +25,12 @@ clarify -> plan -> build -> review -> approve review->done -> archive
25
25
  ## Features
26
26
 
27
27
  - Installs and exposes eleven bundled loopx Codex skills: workflow skills `clarify`, `plan`, `build`, `review`, `archive`, and `autopilot`; quality support skills `debug`, `tdd`, and `verify`; and Go support skills `go-style` and `kratos`.
28
+ - Keeps bundled skill routing explicit in `skills/RESOLVER.md`, with deterministic governance checks for frontmatter, plugin mirrors, resolver coverage, local references, package inclusion, and version alignment.
28
29
  - Supports npm global install and Codex plugin install through the same install/discovery core.
29
30
  - Installs a managed Codex workflow hook that surfaces loopx workflow state and safe next-action hints inside Codex.
30
31
  - Stores runtime state and stage artifacts locally under `.loopx/` for auditability, recovery, and migration.
31
32
  - Stores clarify intake snapshots under `.loopx/intake/` so `.loopx/specs/` stays reserved for long-lived domain specs.
33
+ - Records existing project AI rule files, existing spec sources, and detected verification commands in `.loopx/config.json` during init so loopx can preserve local sources of truth while still running the full workflow.
32
34
  - Runs `plan` with a Planner -> Architect -> Critic consensus loop by default.
33
35
  - Writes OpenSpec-inspired change artifacts during `plan`: proposal, spec delta, design, vertical slices, tasks, and an artifact dependency graph.
34
36
  - Provides per-repo agent context under `.loopx/agents/` and `.loopx/context/domain.md`, consumed by build/review context manifests.
@@ -174,6 +176,24 @@ The CLI is primarily for runtime, debugging, status inspection, and maintenance.
174
176
 
175
177
  `loopx status` remains a CLI/runtime diagnostic command rather than a Codex skill. `loopx render` generates human-readable HTML views from existing runtime artifacts; without a slug it renders every non-legacy workflow plus the workspace index. Markdown and JSON remain the canonical machine-readable and editable sources.
176
178
 
179
+ ## Skill Routing and Governance
180
+
181
+ The bundled skill resolver lives at:
182
+
183
+ ```text
184
+ skills/RESOLVER.md
185
+ ```
186
+
187
+ It is the human-readable routing map for the eleven bundled skills. Keep it aligned with each `skills/<name>/SKILL.md` and mirrored `plugins/loopx/skills/<name>/SKILL.md`.
188
+
189
+ Skill governance is enforced by:
190
+
191
+ ```bash
192
+ node scripts/verify-skills.mjs
193
+ ```
194
+
195
+ The verifier checks that bundled skill frontmatter is triggerable and bounded, `metadata.version` matches `package.json`, plugin skill mirrors match the canonical skills, `skills/RESOLVER.md` covers every bundled skill without stale bundled-skill references, local skill references exist, the plugin manifest version matches the package version, and the verifier itself is included in the npm package.
196
+
177
197
  ## Skills
178
198
 
179
199
  ### clarify
@@ -337,11 +357,14 @@ loopx writes runtime state under `.loopx/` in the current project:
337
357
  review.html
338
358
  plan-reviews/
339
359
  build-support/
360
+ review-support/
340
361
  autopilot/
341
362
  <slug>/
342
363
  run.json
343
364
  ```
344
365
 
366
+ `config.json` records the loopx product contract plus init-time project discovery: existing AI rules such as `AGENTS.md` / `CLAUDE.md` / Cursor / Copilot files, existing spec sources such as `docs/changes` or ADR/RFC folders, and detected install/test/lint/typecheck/build/E2E commands. This does not create a lighter loopx mode; it keeps project facts available to `plan`, `build`, and `review` while preserving loopx's full closed workflow.
367
+
345
368
  `intake` contains immutable clarify snapshots for a specific request. `workflows` contains the active runtime working set. `changes` contains the proposed change delta for the current request. `specs` contains accepted long-lived behavior after archive.
346
369
 
347
370
  `views/` and `workflows/<slug>/view/` are derived HTML reading views generated by `loopx render`. They are for human review only and are safe to regenerate; agents and tooling should continue to read and update the Markdown and JSON artifacts.
@@ -359,6 +382,7 @@ Documents users normally need to watch:
359
382
  Documents users may read and modify as workflow fact sources:
360
383
 
361
384
  - `.loopx/workflows/<slug>/*.md`: editable working-copy artifacts for the active workflow; changes still need to pass the relevant stage gates.
385
+ - `.loopx/config.json`: workspace configuration, project-rule/spec-source discovery, and default verification commands; update it if the repository's canonical commands or project-rule files change.
362
386
  - `.loopx/context/domain.md` and `.loopx/agents/*.md`: project context, domain vocabulary, and agent collaboration guidance.
363
387
  - `.loopx/changes/active/<change-id>/*.md`: plan-generated change proposal, design, tasks, and spec delta; edits should be followed by plan/build/review validation.
364
388
  - `.loopx/specs/<domain>/spec.md`: long-lived archived behavior specs; normally synced by `archive`, and manual edits should stay consistent with later change deltas.
@@ -392,6 +416,12 @@ Check skill discovery state only:
392
416
  node scripts/install-skills.mjs --check
393
417
  ```
394
418
 
419
+ Verify bundled skill governance:
420
+
421
+ ```bash
422
+ node scripts/verify-skills.mjs
423
+ ```
424
+
395
425
  ## Codex Workflow Hook
396
426
 
397
427
  `install-skills.mjs` and the Codex plugin installer automatically install `scripts/codex-workflow-hook.mjs` to:
@@ -443,9 +473,17 @@ Run tests:
443
473
  npm test
444
474
  ```
445
475
 
476
+ `npm test` runs bundled skill governance first, then the Node test suites:
477
+
478
+ ```bash
479
+ node scripts/verify-skills.mjs
480
+ node --test test/*.test.mjs
481
+ ```
482
+
446
483
  Useful verification commands:
447
484
 
448
485
  ```bash
486
+ node scripts/verify-skills.mjs
449
487
  node --test test/*.test.mjs
450
488
  node scripts/install-skills.mjs --check
451
489
  node --test plugins/loopx/scripts/plugin-install.test.mjs
@@ -462,6 +500,7 @@ node src/cli.mjs status --json
462
500
  - `README.zh-CN.md`
463
501
  - `package.json`
464
502
  - `scripts/install-skills.mjs`
503
+ - `scripts/verify-skills.mjs`
465
504
  - `scripts/codex-stop-hook.mjs`
466
505
  - `scripts/codex-workflow-hook.mjs`
467
506
  - `assets/logo.svg`
package/README.zh-CN.md CHANGED
@@ -27,10 +27,12 @@ clarify -> plan -> build -> review -> approve review->done -> archive
27
27
  ## 特性
28
28
 
29
29
  - 安装并公开 11 个 loopx Codex skills:工作流 skills `clarify`、`plan`、`build`、`review`、`archive`、`autopilot`,质量辅助 skills `debug`、`tdd`、`verify`,以及 Go 支持 skills `go-style`、`kratos`。
30
+ - 通过 `skills/RESOLVER.md` 明确 bundled skill 路由,并用确定性治理脚本检查 frontmatter、plugin 镜像、resolver 覆盖、本地引用、发布包包含项和版本一致性。
30
31
  - 支持 npm 全局安装和 Codex plugin 安装,两种安装方式共享同一套 install/discovery 逻辑。
31
32
  - 自动安装 loopx 管理的 Codex workflow hook,在 Codex 中提示当前 workflow 状态和安全下一步。
32
33
  - 所有运行时状态和阶段产物都写入项目本地 `.loopx/`,便于审计、恢复和迁移。
33
34
  - clarify 需求快照写入 `.loopx/intake/`,让 `.loopx/specs/` 只承载长期领域规格。
35
+ - init 时会把已有项目 AI 规则、既有 spec 来源和自动发现的验证命令记录到 `.loopx/config.json`,让 loopx 保留项目原有事实源,同时继续执行完整闭环。
34
36
  - `plan` 默认采用 Planner -> Architect -> Critic 的共识规划循环。
35
37
  - `plan` 会写入借鉴 OpenSpec 的 change artifacts:proposal、spec delta、design、tasks 和 artifact dependency graph。
36
38
  - 提供项目级 agent context:`.loopx/agents/` 和 `.loopx/context/domain.md`,供 build/review 的 context manifest 消费。
@@ -176,6 +178,24 @@ CLI 主要用于运行时、调试、状态观察和维护。日常面向 Codex
176
178
 
177
179
  `loopx status` 仍然是 CLI/runtime 诊断命令,不作为单独 Codex skill 暴露。`loopx render` 会基于现有运行时产物生成给人阅读的 HTML 视图;不传 slug 时会渲染所有非 legacy workflow 和工作区首页。Markdown 和 JSON 仍然是机器可读、可编辑的事实源。
178
180
 
181
+ ## Skill 路由与治理
182
+
183
+ bundled skill resolver 位于:
184
+
185
+ ```text
186
+ skills/RESOLVER.md
187
+ ```
188
+
189
+ 它是 11 个 bundled skills 的可读路由表。修改任一 `skills/<name>/SKILL.md` 或镜像的 `plugins/loopx/skills/<name>/SKILL.md` 时,都要保持 resolver 同步。
190
+
191
+ skill 治理由下面的确定性脚本执行:
192
+
193
+ ```bash
194
+ node scripts/verify-skills.mjs
195
+ ```
196
+
197
+ 该脚本会检查 bundled skill frontmatter 是否可触发且有排除边界、`metadata.version` 是否匹配 `package.json`、plugin skill 镜像是否与 canonical skills 一致、`skills/RESOLVER.md` 是否覆盖所有 bundled skills 且没有陈旧 bundled-skill 引用、本地 skill 引用是否存在、plugin manifest 版本是否匹配 package 版本,以及 verifier 本身是否进入 npm 发布包。
198
+
179
199
  ## Skill 说明
180
200
 
181
201
  ### clarify
@@ -199,6 +219,7 @@ CLI 主要用于运行时、调试、状态观察和维护。日常面向 Codex
199
219
  - `.loopx/changes/active/<change-id>/spec-delta.md`
200
220
  - `.loopx/changes/active/<change-id>/design.md`
201
221
  - `.loopx/changes/active/<change-id>/tasks.md`
222
+ - `.loopx/changes/active/<change-id>/slices.json`
202
223
  - `.loopx/changes/active/<change-id>/artifact-graph.json`
203
224
  - `.loopx/workflows/<slug>/plan.md`
204
225
  - `.loopx/workflows/<slug>/architecture.md`
@@ -347,11 +368,14 @@ loopx 在当前项目下写入 `.loopx/`:
347
368
  review.html
348
369
  plan-reviews/
349
370
  build-support/
371
+ review-support/
350
372
  autopilot/
351
373
  <slug>/
352
374
  run.json
353
375
  ```
354
376
 
377
+ `config.json` 记录 loopx 产品契约和 init 时的项目发现结果:已有 AI 规则文件,例如 `AGENTS.md`、`CLAUDE.md`、Cursor / Copilot 规则;已有 spec 来源,例如 `docs/changes`、ADR/RFC 目录;以及自动发现的 install/test/lint/typecheck/build/E2E 命令。这不会引入轻量版 loopx;它只是让 `plan`、`build`、`review` 能看到项目事实,同时保持完整闭环。
378
+
355
379
  `intake` 保存一次需求的 clarify 快照;`workflows` 保存当前任务的运行时工作副本;`changes` 保存本次需求对长期行为的 change delta;`specs` 只保存 archive 后的长期领域行为契约。
356
380
 
357
381
  `views/` 和 `workflows/<slug>/view/` 是 `loopx render` 生成的派生 HTML 阅读视图,只服务于人的浏览和评审,可以随时重新生成;agent 和工具仍应读取、修改 Markdown 与 JSON 产物。
@@ -369,6 +393,7 @@ loopx 在当前项目下写入 `.loopx/`:
369
393
  用户可以阅读和按流程修改的事实源文档:
370
394
 
371
395
  - `.loopx/workflows/<slug>/*.md`:当前 workflow 的可编辑工作副本;修改后仍需通过对应阶段门禁。
396
+ - `.loopx/config.json`:workspace 配置、项目规则/spec 来源发现结果和默认验证命令;当仓库的 canonical 命令或规则文件变化时可以更新。
372
397
  - `.loopx/context/domain.md` 和 `.loopx/agents/*.md`:项目级背景、术语和 agent 协作约定。
373
398
  - `.loopx/changes/active/<change-id>/*.md`:plan 生成的 change proposal、design、tasks 和 spec delta;修改后应重新过 plan/build/review。
374
399
  - `.loopx/specs/<domain>/spec.md`:archive 后的长期行为规格;通常由 `archive` 同步,人工改动需要保持和后续 change delta 一致。
@@ -402,6 +427,12 @@ loopx repair-install
402
427
  node scripts/install-skills.mjs --check
403
428
  ```
404
429
 
430
+ 检查 bundled skill 治理状态:
431
+
432
+ ```bash
433
+ node scripts/verify-skills.mjs
434
+ ```
435
+
405
436
  ## Codex Workflow Hook
406
437
 
407
438
  `install-skills.mjs` 和 Codex plugin 安装脚本会自动把 `scripts/codex-workflow-hook.mjs` 安装到:
@@ -453,9 +484,17 @@ node scripts/codex-stop-hook.mjs
453
484
  npm test
454
485
  ```
455
486
 
487
+ `npm test` 会先运行 bundled skill 治理检查,再运行 Node 测试套件:
488
+
489
+ ```bash
490
+ node scripts/verify-skills.mjs
491
+ node --test test/*.test.mjs
492
+ ```
493
+
456
494
  也可以直接执行项目内的验证命令:
457
495
 
458
496
  ```bash
497
+ node scripts/verify-skills.mjs
459
498
  node --test test/*.test.mjs
460
499
  node scripts/install-skills.mjs --check
461
500
  node --test plugins/loopx/scripts/plugin-install.test.mjs
@@ -472,6 +511,7 @@ node src/cli.mjs status --json
472
511
  - `README.zh-CN.md`
473
512
  - `package.json`
474
513
  - `scripts/install-skills.mjs`
514
+ - `scripts/verify-skills.mjs`
475
515
  - `scripts/codex-stop-hook.mjs`
476
516
  - `scripts/codex-workflow-hook.mjs`
477
517
  - `assets/logo.svg`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ai-content-space/loopx",
3
3
  "type": "module",
4
- "version": "0.1.4",
4
+ "version": "0.1.5",
5
5
  "description": "Skill-first loopx workflow product for Codex",
6
6
  "repository": {
7
7
  "type": "git",
@@ -22,6 +22,7 @@
22
22
  "README.zh-CN.md",
23
23
  "package.json",
24
24
  "scripts/install-skills.mjs",
25
+ "scripts/verify-skills.mjs",
25
26
  "scripts/codex-stop-hook.mjs",
26
27
  "scripts/codex-workflow-hook.mjs",
27
28
  "assets/logo.svg",
@@ -35,6 +36,6 @@
35
36
  },
36
37
  "scripts": {
37
38
  "postinstall": "node scripts/install-skills.mjs",
38
- "test": "node --test test/*.test.mjs"
39
+ "test": "node scripts/verify-skills.mjs && node --test test/*.test.mjs"
39
40
  }
40
41
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopx",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Skill-first loopx workflow product for Codex",
5
5
  "skills": "./skills/",
6
6
  "interface": {
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: archive
3
- description: Sync an approved loopx change delta into long-lived specs after review is done.
3
+ description: "Archives an approved loopx change delta into long-lived specs and writes an ADR candidate after done approval. Not for active builds or unapproved reviews."
4
+ when_to_use: "archive, done workflow, spec delta, long-lived specs, ADR candidate, review approved, 归档, 同步规格"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "<workflow slug>"
5
8
  ---
6
9
 
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: autopilot
3
- description: Richer internal-phase loopx autonomous orchestration over the public clarify/plan/build/review flow.
3
+ description: "Runs one bounded autonomous loopx orchestration over clarify, plan, build, and review while preserving canonical artifacts. Not for manual gate-by-gate control."
4
+ when_to_use: "autopilot, autonomous loopx run, end-to-end workflow, run all stages, bounded orchestration, 自动执行, 全流程"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "<workflow slug>"
5
8
  ---
6
9
 
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: build
3
- description: Ralph-style loopx execution runtime under the public build stage.
3
+ description: "Executes an approved loopx plan or review rework contract with evidence, verification, deslop, and regression gates. Not for unclear requirements or independent review."
4
+ when_to_use: "build, implement approved plan, execute PRD, --from-review, review rework, implementation fixes, 执行, 实现, 修改"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "[--no-deslop] <approved PRD path or workflow slug> | --from-review <review artifact path>"
5
8
  ---
6
9
 
@@ -30,6 +33,7 @@ By default, `build` is not a one-shot draft writer. It is a persistence loop wit
30
33
  - Execution may parallelize internally without exposing a public `team` stage.
31
34
  - `build` does not replace `review`.
32
35
  - `execution-record.md` remains the sole canonical execution and verification artifact.
36
+ - `.loopx/config.json` is supporting context for existing project AI rules, existing spec sources, and discovered verification commands; use it to preserve local sources of truth, not to skip loopx stages.
33
37
  - Feature work and bug fixes should use `tdd`: write a failing test, confirm it fails for the intended reason, then implement the smallest passing change.
34
38
  - Bug, test-failure, build-failure, and unexpected-behavior work should use `debug` before proposing fixes.
35
39
  - Completion and review-ready claims should use `verify` before they are stated.
@@ -72,6 +76,8 @@ Compatible skill / CLI input:
72
76
  When invoked with a PRD path, derive `<slug>` from `prd-<slug>.md` and still use the matching workflow-local plan package and test spec.
73
77
 
74
78
  When invoked with `--from-review`, derive `<slug>` from the workflow directory, treat the review artifact as the implementation-fix contract, and load the matching PRD, test spec, previous `execution-record.md`, and workflow-local plan package as supporting context. This Codex skill invocation consumes the `review -> build` rework intent; users should not need a separate bash `loopx approve ... --from review --to build` step for the normal Codex-facing flow.
79
+
80
+ Also load `.loopx/config.json` when present. Its `project_conventions` entries identify existing project rule/spec files that should be preserved, and its `verification_commands` entries are the first project-native commands to consider for fresh evidence.
75
81
  </Inputs>
76
82
 
77
83
  <Execution_Model>
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: clarify
3
- description: Comprehensive loopx clarify skill for requirements, boundaries, and design-ready specs.
3
+ description: "Clarifies ambiguous loopx work into requirements, non-goals, decision boundaries, and design-ready specs before planning. Not for already-approved plans or concrete implementation tasks."
4
+ when_to_use: "clarify, requirements, ambiguous request, unclear scope, non-goals, decision boundaries, acceptance criteria, 需求澄清, 范围不清"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # loopx Clarify
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: debug
3
- description: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
3
+ description: "Finds root cause for bugs, failing tests, build failures, regressions, and unexpected behavior before fixes. Not for new feature planning or routine code review."
4
+ when_to_use: "debug, bug, test failure, build failure, regression, unexpected behavior, root cause, 报错, 失败, 回归, 排查"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Systematic Debugging
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: go-style
3
- description: Go language style support for loopx. Use before creating or editing Go (.go) files, especially inside build execution lanes.
3
+ description: "Applies loopx Go coding style for .go edits, tests, errors, context, naming, and interface boundaries. Not for non-Go code or Kratos-specific architecture by itself."
4
+ when_to_use: "go-style, Go, golang, .go files, go tests, gofmt, idiomatic Go, Go style, Go 代码"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Go Style
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: kratos
3
- description: Go-Kratos framework support for loopx. Use for Kratos microservices, proto/buf API work, service/biz/data layering, Kratos middleware, auth, configuration, and troubleshooting.
3
+ description: "Supports Go-Kratos microservices, proto/buf APIs, service/biz/data layers, middleware, auth, config, and troubleshooting. Not for generic Go style alone."
4
+ when_to_use: "kratos, Go-Kratos, proto, buf, service layer, biz layer, data layer, middleware, auth, config, Kratos 微服务"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Kratos
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: plan
3
- description: Consensus-first loopx planning skill with Planner, Architect, and Critic review.
3
+ description: "Creates a consensus-first loopx plan package with Planner, Architect, and Critic review from an approved spec. Not for unresolved requirements or direct implementation."
4
+ when_to_use: "plan, planning, consensus planning, PRD, architecture plan, test plan, approved clarify spec, 规划, 方案, 架构评审"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "[--interactive] [--deliberate] [--direct <spec-path>] <clarified task or spec path>"
5
8
  ---
6
9
 
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: review
3
- description: Repo-local acceptance surface for loopx.
3
+ description: "Reviews a loopx build execution record for acceptance, code risks, evidence quality, and architecture smells. Not for doing implementation work or replanning."
4
+ when_to_use: "review, code review, acceptance, go no-go, execution-record, architecture smell, build complete, 审查, 验收"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "<execution-record path or workflow slug>"
5
8
  ---
6
9
 
@@ -22,6 +25,8 @@ Compatible skill / CLI input:
22
25
 
23
26
  When invoked with an execution record path, derive `<slug>` from the workflow directory and evaluate the matching active run.
24
27
 
28
+ When present, use `.loopx/config.json` as supporting context for project-native verification commands, existing AI rule files, and existing spec sources. Do not treat those external or pre-existing sources as replacements for the loopx execution record and review artifact.
29
+
25
30
  ## Expected Outputs
26
31
 
27
32
  - a review artifact tied to the run being evaluated
@@ -42,6 +47,7 @@ Use stable machine values only where they are commands, file paths, JSON/state f
42
47
  - Use this only after build has produced execution and verification evidence for a specific run.
43
48
  - Stop here if review evidence is incomplete. `review` remains an independent gate and does not auto-complete the workflow.
44
49
  - Review must include code review of the build-owned implementation diff. Do not limit review to artifact/schema checks.
50
+ - Review should compare verification evidence against project-native commands recorded in `.loopx/config.json` when available, while still accepting stronger task-specific verification from the approved plan.
45
51
  - Review must include the architecture-smell lane as part of review evidence. This is not a new workflow stage and must not create extra user steps.
46
52
  - Review must compare the execution scope against the approved workflow scope. If `execution-record.md` declares non-empty `remaining_scope`, `completion_claim` other than `full`, or a mismatch between `planned_scope` and `implemented_scope`, review must return no-go and route to build or plan. A partial slice may be accepted as useful work, but it must not be approved as full workflow completion.
47
53
  - Code review findings should focus on real bugs, regressions, missing tests, broken contracts, security/data-integrity risks, and user-visible behavior gaps.
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: tdd
3
- description: Use when implementing any feature or bugfix, before writing implementation code
3
+ description: "Guides feature and bugfix implementation through a failing test before production code and red-green-refactor discipline. Not for generated files or throwaway prototypes."
4
+ when_to_use: "tdd, failing test first, feature implementation, bugfix, regression test, red green refactor, 测试先行"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Test-Driven Development (TDD)
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: verify
3
- description: Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
3
+ description: "Requires fresh verification evidence before claiming work is complete, fixed, passing, review-ready, or ready to commit. Not for speculative confidence or stale results."
4
+ when_to_use: "verify, completion claim, fixed claim, tests pass, review-ready, commit, fresh evidence, 验证, 完成前检查"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Verification Before Completion
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+
3
+ import assert from 'node:assert/strict';
4
+ import { existsSync } from 'node:fs';
5
+ import { readdir, readFile } from 'node:fs/promises';
6
+ import { dirname, join, resolve } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ import { LOOPX_BUNDLED_SKILLS } from '../src/install-discovery.mjs';
10
+
11
+ const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
12
+ const packageJson = JSON.parse(await readFile(join(repoRoot, 'package.json'), 'utf8'));
13
+ const pluginManifest = JSON.parse(await readFile(join(repoRoot, 'plugins', 'loopx', '.codex-plugin', 'plugin.json'), 'utf8'));
14
+ const resolverPath = join(repoRoot, 'skills', 'RESOLVER.md');
15
+ const markdownPaths = [
16
+ 'README.md',
17
+ 'README.zh-CN.md',
18
+ 'AGENTS.md',
19
+ 'skills/RESOLVER.md',
20
+ ];
21
+ const personalPathPattern = /\/(?:Users|home)\/[A-Za-z0-9._-]+\//;
22
+ const localRefPattern = /(?<![/.])\b(?:references|agents|scripts)\/[\w/.-]+\b/g;
23
+
24
+ function parseFrontmatter(path, text) {
25
+ assert.equal(text.startsWith('---\n'), true, `${path} must start with YAML frontmatter`);
26
+ const end = text.indexOf('\n---\n', 4);
27
+ assert.notEqual(end, -1, `${path} frontmatter must close with ---`);
28
+
29
+ const fields = {};
30
+ let inMetadata = false;
31
+ for (const line of text.slice(4, end).split('\n')) {
32
+ if (line === 'metadata:') {
33
+ inMetadata = true;
34
+ continue;
35
+ }
36
+ if (inMetadata && line.startsWith(' version:')) {
37
+ fields.version = line.split(':', 2)[1].trim().replace(/^"|"$/g, '');
38
+ continue;
39
+ }
40
+ if (!line || line.startsWith(' ')) {
41
+ continue;
42
+ }
43
+ inMetadata = false;
44
+ const separator = line.indexOf(':');
45
+ assert.notEqual(separator, -1, `${path} has invalid frontmatter line: ${line}`);
46
+ const key = line.slice(0, separator).trim();
47
+ const raw = line.slice(separator + 1).trim();
48
+ fields[key] = raw.replace(/^"|"$/g, '');
49
+ }
50
+ return fields;
51
+ }
52
+
53
+ function assertSkillDescription(skillName, description) {
54
+ assert.ok(description, `${skillName} missing description`);
55
+ assert.ok(description.length >= 40, `${skillName} description is too short`);
56
+ assert.ok(description.length <= 500, `${skillName} description is too long`);
57
+ assert.match(description, /not for/i, `${skillName} description must include a Not for exclusion`);
58
+ }
59
+
60
+ async function assertMarkdownStructure(relativePath) {
61
+ const path = join(repoRoot, relativePath);
62
+ assert.equal(existsSync(path), true, `${relativePath} missing`);
63
+ const text = await readFile(path, 'utf8');
64
+ assert.equal(text.endsWith('\n'), true, `${relativePath} missing final newline`);
65
+
66
+ const fenceStack = [];
67
+ text.split('\n').forEach((line, index) => {
68
+ assert.equal(/^(<<<<<<<|=======|>>>>>>>)($| )/.test(line), false, `${relativePath}:${index + 1}: merge conflict marker`);
69
+ const match = line.match(/^(`{3,}|~{3,})/);
70
+ if (!match) {
71
+ return;
72
+ }
73
+ const marker = match[1];
74
+ if (fenceStack.length > 0 && marker[0] === fenceStack.at(-1).char && marker.length >= fenceStack.at(-1).length) {
75
+ fenceStack.pop();
76
+ return;
77
+ }
78
+ fenceStack.push({ char: marker[0], length: marker.length, line: index + 1 });
79
+ });
80
+
81
+ assert.deepEqual(fenceStack, [], `${relativePath} has unclosed fenced block`);
82
+ }
83
+
84
+ function assertContains(text, value, label) {
85
+ assert.match(text, new RegExp(value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')), `${label} missing ${value}`);
86
+ }
87
+
88
+ async function assertPublicDocsAligned() {
89
+ const readme = await readFile(join(repoRoot, 'README.md'), 'utf8');
90
+ const readmeZh = await readFile(join(repoRoot, 'README.zh-CN.md'), 'utf8');
91
+ const commands = [
92
+ 'loopx init',
93
+ 'loopx clarify',
94
+ 'loopx approve',
95
+ 'loopx plan',
96
+ 'loopx build',
97
+ 'loopx review',
98
+ 'loopx archive',
99
+ 'loopx autopilot',
100
+ 'loopx render',
101
+ 'loopx status',
102
+ 'loopx setup-context',
103
+ 'loopx doctor',
104
+ 'loopx migrate',
105
+ 'loopx repair-install',
106
+ 'node scripts/verify-skills.mjs',
107
+ ];
108
+ for (const command of commands) {
109
+ assertContains(readme, command, 'README.md');
110
+ assertContains(readmeZh, command, 'README.zh-CN.md');
111
+ }
112
+
113
+ const releaseNotesRoot = join(repoRoot, 'docs', 'release-notes');
114
+ const releaseNotes = existsSync(releaseNotesRoot)
115
+ ? (await readdir(releaseNotesRoot)).filter((name) => name.endsWith('.md'))
116
+ : [];
117
+ assert.ok(releaseNotes.includes(`${packageJson.version}.md`), `docs/release-notes/${packageJson.version}.md missing`);
118
+ for (const name of releaseNotes) {
119
+ await assertMarkdownStructure(`docs/release-notes/${name}`);
120
+ }
121
+ }
122
+
123
+ async function assertSkill(skillName, resolverText) {
124
+ const rootPath = join(repoRoot, 'skills', skillName, 'SKILL.md');
125
+ const pluginPath = join(repoRoot, 'plugins', 'loopx', 'skills', skillName, 'SKILL.md');
126
+ assert.equal(existsSync(rootPath), true, `${skillName} root SKILL.md missing`);
127
+ assert.equal(existsSync(pluginPath), true, `${skillName} plugin SKILL.md missing`);
128
+
129
+ const rootText = await readFile(rootPath, 'utf8');
130
+ const pluginText = await readFile(pluginPath, 'utf8');
131
+ assert.equal(pluginText, rootText, `${skillName} plugin mirror drifted`);
132
+ assert.equal(personalPathPattern.test(rootText), false, `${skillName} contains a personal absolute path`);
133
+
134
+ const fields = parseFrontmatter(rootPath, rootText);
135
+ assert.equal(fields.name, skillName, `${skillName} frontmatter name mismatch`);
136
+ assert.equal(fields.version, packageJson.version, `${skillName} metadata.version must match package.json`);
137
+ assert.ok(fields.when_to_use && fields.when_to_use.length >= 20, `${skillName} missing useful when_to_use metadata`);
138
+ assertSkillDescription(skillName, fields.description);
139
+ assert.match(resolverText, new RegExp(`skills/${skillName}/SKILL\\.md`), `${skillName} missing from skills/RESOLVER.md`);
140
+
141
+ const refs = [...rootText.matchAll(localRefPattern)].map((match) => match[0]);
142
+ for (const ref of refs) {
143
+ const target = join(repoRoot, 'skills', skillName, ref);
144
+ assert.equal(existsSync(target), true, `${skillName} references missing local file: ${ref}`);
145
+ }
146
+ }
147
+
148
+ assert.equal(pluginManifest.version, packageJson.version, 'plugin manifest version must match package.json');
149
+ assert.equal(existsSync(resolverPath), true, 'skills/RESOLVER.md missing');
150
+
151
+ for (const relativePath of markdownPaths) {
152
+ await assertMarkdownStructure(relativePath);
153
+ }
154
+ await assertPublicDocsAligned();
155
+
156
+ const resolverText = await readFile(resolverPath, 'utf8');
157
+ for (const skillName of LOOPX_BUNDLED_SKILLS) {
158
+ await assertSkill(skillName, resolverText);
159
+ }
160
+
161
+ const staleRefs = [...resolverText.matchAll(/skills\/([a-z][a-z0-9-]*)\/SKILL\.md/g)]
162
+ .map((match) => match[1])
163
+ .filter((skillName) => !LOOPX_BUNDLED_SKILLS.includes(skillName));
164
+ assert.deepEqual([...new Set(staleRefs)], [], 'skills/RESOLVER.md contains stale bundled-skill refs');
165
+
166
+ console.log(`ok: verified ${LOOPX_BUNDLED_SKILLS.length} loopx bundled skills`);
@@ -0,0 +1,45 @@
1
+ # loopx Skill Resolver
2
+
3
+ Central routing map for loopx bundled skills. Keep this file in sync with every bundled `skills/<name>/SKILL.md` and `plugins/loopx/skills/<name>/SKILL.md`.
4
+
5
+ Read the selected skill file before acting. If multiple skills match, read every likely candidate and use the disambiguation rules below.
6
+
7
+ ## Public Workflow Skills
8
+
9
+ | Trigger | Skill |
10
+ |---|---|
11
+ | Ambiguous request, unclear scope, non-goals, decision boundaries, requirements interview | `skills/clarify/SKILL.md` |
12
+ | Approved clarify spec, direct requirements artifact, PRD/test/architecture planning, consensus planning | `skills/plan/SKILL.md` |
13
+ | Approved plan execution, implementation persistence, review-requested implementation fixes | `skills/build/SKILL.md` |
14
+ | Independent acceptance, code review, architecture-smell review, go/no-go after build | `skills/review/SKILL.md` |
15
+ | Completed workflow needs long-lived spec sync and ADR candidate | `skills/archive/SKILL.md` |
16
+ | User wants one bounded end-to-end loopx run over clarify/plan/build/review | `skills/autopilot/SKILL.md` |
17
+
18
+ ## Support Skills
19
+
20
+ | Trigger | Skill |
21
+ |---|---|
22
+ | Bug, test failure, build failure, regression, unexpected behavior, root-cause investigation | `skills/debug/SKILL.md` |
23
+ | Feature or bugfix implementation where behavior should be covered by a failing test first | `skills/tdd/SKILL.md` |
24
+ | Completion, fixed, passing, review-ready, commit, or handoff claims need fresh evidence | `skills/verify/SKILL.md` |
25
+ | Editing `.go` files or reviewing Go style inside build/review | `skills/go-style/SKILL.md` |
26
+ | Go-Kratos proto, service, biz, data, middleware, auth, config, or Kratos troubleshooting | `skills/kratos/SKILL.md` |
27
+
28
+ ## Disambiguation
29
+
30
+ 1. If intent, scope, non-goals, or decision boundaries are unresolved, use `clarify` before `plan`.
31
+ 2. If requirements are approved but execution has not started, use `plan` before `build`.
32
+ 3. If implementation is broken or tests fail during build, use `debug` as the diagnostic lens before patching.
33
+ 4. If code is already implemented and needs acceptance, use `review`; do not run new build work from review.
34
+ 5. If review requests implementation-only fixes, route to `build --from-review`; route to `plan` only when the plan itself is wrong.
35
+ 6. If the user asks for autonomous execution, use `autopilot` only when requirements are bounded enough to run without new human decisions.
36
+ 7. Treat `tdd`, `verify`, `go-style`, and `kratos` as support lenses unless the user explicitly invokes them directly.
37
+ 8. `archive` is only valid after `review -> done`.
38
+
39
+ ## Deterministic Guard
40
+
41
+ Run this before release or when changing bundled skills:
42
+
43
+ ```bash
44
+ node scripts/verify-skills.mjs
45
+ ```
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: archive
3
- description: Sync an approved loopx change delta into long-lived specs after review is done.
3
+ description: "Archives an approved loopx change delta into long-lived specs and writes an ADR candidate after done approval. Not for active builds or unapproved reviews."
4
+ when_to_use: "archive, done workflow, spec delta, long-lived specs, ADR candidate, review approved, 归档, 同步规格"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "<workflow slug>"
5
8
  ---
6
9
 
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: autopilot
3
- description: Richer internal-phase loopx autonomous orchestration over the public clarify/plan/build/review flow.
3
+ description: "Runs one bounded autonomous loopx orchestration over clarify, plan, build, and review while preserving canonical artifacts. Not for manual gate-by-gate control."
4
+ when_to_use: "autopilot, autonomous loopx run, end-to-end workflow, run all stages, bounded orchestration, 自动执行, 全流程"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "<workflow slug>"
5
8
  ---
6
9
 
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: build
3
- description: Ralph-style loopx execution runtime under the public build stage.
3
+ description: "Executes an approved loopx plan or review rework contract with evidence, verification, deslop, and regression gates. Not for unclear requirements or independent review."
4
+ when_to_use: "build, implement approved plan, execute PRD, --from-review, review rework, implementation fixes, 执行, 实现, 修改"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "[--no-deslop] <approved PRD path or workflow slug> | --from-review <review artifact path>"
5
8
  ---
6
9
 
@@ -30,6 +33,7 @@ By default, `build` is not a one-shot draft writer. It is a persistence loop wit
30
33
  - Execution may parallelize internally without exposing a public `team` stage.
31
34
  - `build` does not replace `review`.
32
35
  - `execution-record.md` remains the sole canonical execution and verification artifact.
36
+ - `.loopx/config.json` is supporting context for existing project AI rules, existing spec sources, and discovered verification commands; use it to preserve local sources of truth, not to skip loopx stages.
33
37
  - Feature work and bug fixes should use `tdd`: write a failing test, confirm it fails for the intended reason, then implement the smallest passing change.
34
38
  - Bug, test-failure, build-failure, and unexpected-behavior work should use `debug` before proposing fixes.
35
39
  - Completion and review-ready claims should use `verify` before they are stated.
@@ -72,6 +76,8 @@ Compatible skill / CLI input:
72
76
  When invoked with a PRD path, derive `<slug>` from `prd-<slug>.md` and still use the matching workflow-local plan package and test spec.
73
77
 
74
78
  When invoked with `--from-review`, derive `<slug>` from the workflow directory, treat the review artifact as the implementation-fix contract, and load the matching PRD, test spec, previous `execution-record.md`, and workflow-local plan package as supporting context. This Codex skill invocation consumes the `review -> build` rework intent; users should not need a separate bash `loopx approve ... --from review --to build` step for the normal Codex-facing flow.
79
+
80
+ Also load `.loopx/config.json` when present. Its `project_conventions` entries identify existing project rule/spec files that should be preserved, and its `verification_commands` entries are the first project-native commands to consider for fresh evidence.
75
81
  </Inputs>
76
82
 
77
83
  <Execution_Model>
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: clarify
3
- description: Comprehensive loopx clarify skill for requirements, boundaries, and design-ready specs.
3
+ description: "Clarifies ambiguous loopx work into requirements, non-goals, decision boundaries, and design-ready specs before planning. Not for already-approved plans or concrete implementation tasks."
4
+ when_to_use: "clarify, requirements, ambiguous request, unclear scope, non-goals, decision boundaries, acceptance criteria, 需求澄清, 范围不清"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # loopx Clarify
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: debug
3
- description: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes
3
+ description: "Finds root cause for bugs, failing tests, build failures, regressions, and unexpected behavior before fixes. Not for new feature planning or routine code review."
4
+ when_to_use: "debug, bug, test failure, build failure, regression, unexpected behavior, root cause, 报错, 失败, 回归, 排查"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Systematic Debugging
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: go-style
3
- description: Go language style support for loopx. Use before creating or editing Go (.go) files, especially inside build execution lanes.
3
+ description: "Applies loopx Go coding style for .go edits, tests, errors, context, naming, and interface boundaries. Not for non-Go code or Kratos-specific architecture by itself."
4
+ when_to_use: "go-style, Go, golang, .go files, go tests, gofmt, idiomatic Go, Go style, Go 代码"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Go Style
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: kratos
3
- description: Go-Kratos framework support for loopx. Use for Kratos microservices, proto/buf API work, service/biz/data layering, Kratos middleware, auth, configuration, and troubleshooting.
3
+ description: "Supports Go-Kratos microservices, proto/buf APIs, service/biz/data layers, middleware, auth, config, and troubleshooting. Not for generic Go style alone."
4
+ when_to_use: "kratos, Go-Kratos, proto, buf, service layer, biz layer, data layer, middleware, auth, config, Kratos 微服务"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Kratos
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: plan
3
- description: Consensus-first loopx planning skill with Planner, Architect, and Critic review.
3
+ description: "Creates a consensus-first loopx plan package with Planner, Architect, and Critic review from an approved spec. Not for unresolved requirements or direct implementation."
4
+ when_to_use: "plan, planning, consensus planning, PRD, architecture plan, test plan, approved clarify spec, 规划, 方案, 架构评审"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "[--interactive] [--deliberate] [--direct <spec-path>] <clarified task or spec path>"
5
8
  ---
6
9
 
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: review
3
- description: Repo-local acceptance surface for loopx.
3
+ description: "Reviews a loopx build execution record for acceptance, code risks, evidence quality, and architecture smells. Not for doing implementation work or replanning."
4
+ when_to_use: "review, code review, acceptance, go no-go, execution-record, architecture smell, build complete, 审查, 验收"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  argument-hint: "<execution-record path or workflow slug>"
5
8
  ---
6
9
 
@@ -22,6 +25,8 @@ Compatible skill / CLI input:
22
25
 
23
26
  When invoked with an execution record path, derive `<slug>` from the workflow directory and evaluate the matching active run.
24
27
 
28
+ When present, use `.loopx/config.json` as supporting context for project-native verification commands, existing AI rule files, and existing spec sources. Do not treat those external or pre-existing sources as replacements for the loopx execution record and review artifact.
29
+
25
30
  ## Expected Outputs
26
31
 
27
32
  - a review artifact tied to the run being evaluated
@@ -42,6 +47,7 @@ Use stable machine values only where they are commands, file paths, JSON/state f
42
47
  - Use this only after build has produced execution and verification evidence for a specific run.
43
48
  - Stop here if review evidence is incomplete. `review` remains an independent gate and does not auto-complete the workflow.
44
49
  - Review must include code review of the build-owned implementation diff. Do not limit review to artifact/schema checks.
50
+ - Review should compare verification evidence against project-native commands recorded in `.loopx/config.json` when available, while still accepting stronger task-specific verification from the approved plan.
45
51
  - Review must include the architecture-smell lane as part of review evidence. This is not a new workflow stage and must not create extra user steps.
46
52
  - Review must compare the execution scope against the approved workflow scope. If `execution-record.md` declares non-empty `remaining_scope`, `completion_claim` other than `full`, or a mismatch between `planned_scope` and `implemented_scope`, review must return no-go and route to build or plan. A partial slice may be accepted as useful work, but it must not be approved as full workflow completion.
47
53
  - Code review findings should focus on real bugs, regressions, missing tests, broken contracts, security/data-integrity risks, and user-visible behavior gaps.
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: tdd
3
- description: Use when implementing any feature or bugfix, before writing implementation code
3
+ description: "Guides feature and bugfix implementation through a failing test before production code and red-green-refactor discipline. Not for generated files or throwaway prototypes."
4
+ when_to_use: "tdd, failing test first, feature implementation, bugfix, regression test, red green refactor, 测试先行"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Test-Driven Development (TDD)
@@ -1,6 +1,9 @@
1
1
  ---
2
2
  name: verify
3
- description: Use when about to claim work is complete, fixed, or passing, before committing or creating PRs - requires running verification commands and confirming output before making any success claims; evidence before assertions always
3
+ description: "Requires fresh verification evidence before claiming work is complete, fixed, passing, review-ready, or ready to commit. Not for speculative confidence or stale results."
4
+ when_to_use: "verify, completion claim, fixed claim, tests pass, review-ready, commit, fresh evidence, 验证, 完成前检查"
5
+ metadata:
6
+ version: "0.1.5"
4
7
  ---
5
8
 
6
9
  # Verification Before Completion
@@ -138,6 +138,7 @@ export async function generateBuildContextManifest({ cwd, root, state, slug }) {
138
138
  row(cwd, { stage: 'build', kind: 'review-rework', path: reviewReworkPath, reason: 'review_requested_implementation_fixes', priority: 33, required: requiresReviewRework }),
139
139
  row(cwd, { stage: 'build', kind: 'domain-context', path: contextPaths.domainGlossary, reason: 'domain_vocabulary', priority: 34, required: contextSetup.status !== 'missing' }),
140
140
  row(cwd, { stage: 'build', kind: 'agent-domain', path: contextPaths.agentDomain, reason: 'agent_context_rules', priority: 35, required: false }),
141
+ row(cwd, { stage: 'build', kind: 'workspace-config', path: join(cwd, '.loopx', 'config.json'), reason: 'project_rules_spec_sources_and_verification_commands', priority: 36, required: false }),
141
142
  ];
142
143
  const manifestPath = buildContextManifestPath(root);
143
144
  await writeContextManifest(manifestPath, rows);
@@ -157,6 +158,7 @@ export async function generateReviewContextManifest({ cwd, root, state, slug })
157
158
  row(cwd, { stage: 'review', kind: 'residual-risks', path: join(root, 'execution-record.md'), reason: 'residual_risk_reference', priority: 26, required: false }),
158
159
  row(cwd, { stage: 'review', kind: 'build-support', path: join(root, 'build-support'), reason: 'build_gate_evidence', priority: 30, required: false }),
159
160
  row(cwd, { stage: 'review', kind: 'agent-domain', path: contextPaths.agentDomain, reason: 'agent_context_rules', priority: 31, required: false }),
161
+ row(cwd, { stage: 'review', kind: 'workspace-config', path: join(cwd, '.loopx', 'config.json'), reason: 'project_rules_spec_sources_and_verification_commands', priority: 32, required: false }),
160
162
  row(cwd, { stage: 'review', kind: 'state', path: join(root, 'state.json'), reason: 'workflow_state', priority: 40 }),
161
163
  ];
162
164
  const manifestPath = reviewContextManifestPath(root);
@@ -0,0 +1,163 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir, readFile, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+
5
+ async function readJsonIfExists(path) {
6
+ if (!existsSync(path)) {
7
+ return null;
8
+ }
9
+ try {
10
+ return JSON.parse(await readFile(path, 'utf8'));
11
+ } catch {
12
+ return null;
13
+ }
14
+ }
15
+
16
+ async function pathKind(path) {
17
+ if (!existsSync(path)) {
18
+ return null;
19
+ }
20
+ const info = await stat(path);
21
+ return info.isDirectory() ? 'directory' : 'file';
22
+ }
23
+
24
+ async function candidate(path, label) {
25
+ const kind = await pathKind(path);
26
+ if (!kind) {
27
+ return null;
28
+ }
29
+ return { path: label, kind };
30
+ }
31
+
32
+ async function directoryChildren(root, label) {
33
+ if (!existsSync(root)) {
34
+ return [];
35
+ }
36
+ const info = await stat(root);
37
+ if (!info.isDirectory()) {
38
+ return [];
39
+ }
40
+ const entries = await readdir(root);
41
+ return entries
42
+ .filter((entry) => /\.(md|mdc|txt)$/i.test(entry))
43
+ .sort()
44
+ .map((entry) => ({ path: `${label}/${entry}`, kind: 'file' }));
45
+ }
46
+
47
+ async function discoverAiRules(cwd) {
48
+ const direct = await Promise.all([
49
+ candidate(join(cwd, 'AGENTS.md'), 'AGENTS.md'),
50
+ candidate(join(cwd, 'CLAUDE.md'), 'CLAUDE.md'),
51
+ candidate(join(cwd, '.cursor', 'rules'), '.cursor/rules'),
52
+ candidate(join(cwd, '.github', 'copilot-instructions.md'), '.github/copilot-instructions.md'),
53
+ ]);
54
+ return [
55
+ ...direct.filter(Boolean),
56
+ ...await directoryChildren(join(cwd, '.cursor', 'rules'), '.cursor/rules'),
57
+ ].filter((item, index, items) => items.findIndex((other) => other.path === item.path) === index);
58
+ }
59
+
60
+ async function discoverSpecSources(cwd) {
61
+ const direct = await Promise.all([
62
+ candidate(join(cwd, 'openspec.yaml'), 'openspec.yaml'),
63
+ candidate(join(cwd, 'openspec.yml'), 'openspec.yml'),
64
+ candidate(join(cwd, 'openspec.json'), 'openspec.json'),
65
+ candidate(join(cwd, 'open-spec.yaml'), 'open-spec.yaml'),
66
+ candidate(join(cwd, '.specify'), '.specify'),
67
+ candidate(join(cwd, 'specs'), 'specs'),
68
+ candidate(join(cwd, 'docs', 'changes'), 'docs/changes'),
69
+ candidate(join(cwd, 'docs', 'specs'), 'docs/specs'),
70
+ candidate(join(cwd, 'docs', 'adr'), 'docs/adr'),
71
+ candidate(join(cwd, 'docs', 'rfcs'), 'docs/rfcs'),
72
+ ]);
73
+ return direct.filter(Boolean);
74
+ }
75
+
76
+ function packageRunner(cwd, packageJson) {
77
+ const packageManager = String(packageJson?.packageManager || '');
78
+ if (packageManager.startsWith('pnpm@') || existsSync(join(cwd, 'pnpm-lock.yaml'))) {
79
+ return 'pnpm';
80
+ }
81
+ if (packageManager.startsWith('yarn@') || existsSync(join(cwd, 'yarn.lock'))) {
82
+ return 'yarn';
83
+ }
84
+ if (packageManager.startsWith('bun@') || existsSync(join(cwd, 'bun.lock')) || existsSync(join(cwd, 'bun.lockb'))) {
85
+ return 'bun';
86
+ }
87
+ return 'npm';
88
+ }
89
+
90
+ function runScriptCommand(runner, scriptName) {
91
+ if (runner === 'npm') {
92
+ return scriptName === 'test' ? 'npm test' : `npm run ${scriptName}`;
93
+ }
94
+ return `${runner} ${scriptName}`;
95
+ }
96
+
97
+ function firstScript(scripts, names) {
98
+ return names.find((name) => Object.prototype.hasOwnProperty.call(scripts, name));
99
+ }
100
+
101
+ async function discoverPackageCommands(cwd) {
102
+ const packageJson = await readJsonIfExists(join(cwd, 'package.json'));
103
+ if (!packageJson) {
104
+ return {};
105
+ }
106
+ const runner = packageRunner(cwd, packageJson);
107
+ const scripts = packageJson.scripts || {};
108
+ const install = runner === 'npm' && existsSync(join(cwd, 'package-lock.json'))
109
+ ? 'npm ci'
110
+ : `${runner} install`;
111
+ return {
112
+ install,
113
+ test: scripts.test ? runScriptCommand(runner, 'test') : null,
114
+ lint: scripts.lint ? runScriptCommand(runner, 'lint') : null,
115
+ typecheck: scripts.typecheck ? runScriptCommand(runner, 'typecheck') : null,
116
+ build: scripts.build ? runScriptCommand(runner, 'build') : null,
117
+ e2e: (() => {
118
+ const script = firstScript(scripts, ['test:e2e', 'e2e', 'test:browser', 'playwright']);
119
+ return script ? runScriptCommand(runner, script) : null;
120
+ })(),
121
+ };
122
+ }
123
+
124
+ function compactCommands(commands) {
125
+ return Object.fromEntries(
126
+ ['install', 'test', 'lint', 'typecheck', 'build', 'e2e']
127
+ .map((key) => [key, commands[key] || null]),
128
+ );
129
+ }
130
+
131
+ export async function discoverVerificationCommands(cwd) {
132
+ const packageCommands = await discoverPackageCommands(cwd);
133
+ if (Object.keys(packageCommands).length > 0) {
134
+ return compactCommands(packageCommands);
135
+ }
136
+ if (existsSync(join(cwd, 'go.mod'))) {
137
+ return compactCommands({
138
+ test: 'go test ./...',
139
+ build: 'go build ./...',
140
+ });
141
+ }
142
+ if (existsSync(join(cwd, 'pyproject.toml'))) {
143
+ return compactCommands({
144
+ install: 'pip install -e .',
145
+ test: 'pytest',
146
+ });
147
+ }
148
+ return compactCommands({});
149
+ }
150
+
151
+ export async function inspectProjectConventions(cwd) {
152
+ const [existingAiRules, existingSpecSources, verificationCommands] = await Promise.all([
153
+ discoverAiRules(cwd),
154
+ discoverSpecSources(cwd),
155
+ discoverVerificationCommands(cwd),
156
+ ]);
157
+ return {
158
+ existing_ai_rules: existingAiRules,
159
+ existing_spec_sources: existingSpecSources,
160
+ verification_commands: verificationCommands,
161
+ source_of_truth_policy: 'preserve-existing-project-rules-and-use-loopx-artifacts-only-after-init',
162
+ };
163
+ }
package/src/workflow.mjs CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  import { doctorRuntime, ensureLoopxRoot, resolveLoopxRoot } from './runtime-maintenance.mjs';
17
17
  import { DEFAULT_BUILD_MAX_ITERATIONS, createDefaultBuildAdapter } from './build-runtime.mjs';
18
18
  import { DEFAULT_MAX_ITERATIONS, createDefaultPlanAdapter } from './plan-runtime.mjs';
19
+ import { inspectProjectConventions } from './project-discovery.mjs';
19
20
  import { createDefaultReviewAdapter } from './review-runtime.mjs';
20
21
  import { appendWorkspaceJournal } from './workspace-memory.mjs';
21
22
  import { inspectWorkspaceContext, setupWorkspaceContext } from './workspace-context.mjs';
@@ -2509,6 +2510,7 @@ async function refreshExecutionStatus(root, state) {
2509
2510
 
2510
2511
  export async function initWorkspace(cwd, { slug } = {}) {
2511
2512
  const workspaceRoot = resolveWorkspaceRoot(cwd);
2513
+ const projectConventions = await inspectProjectConventions(cwd);
2512
2514
  await ensureLoopxRoot(cwd);
2513
2515
  await ensureDir(join(workspaceRoot, 'context'));
2514
2516
  await ensureDir(join(workspaceRoot, 'intake'));
@@ -2527,6 +2529,12 @@ export async function initWorkspace(cwd, { slug } = {}) {
2527
2529
  product_contract: 'skill-first-v1',
2528
2530
  default_flow: ['clarify', 'plan', 'build', 'review', 'done', 'archive'],
2529
2531
  preferred_surface: ['clarify', 'plan', 'build', 'review', 'archive', 'autopilot'],
2532
+ source_of_truth_policy: projectConventions.source_of_truth_policy,
2533
+ project_conventions: {
2534
+ existing_ai_rules: projectConventions.existing_ai_rules,
2535
+ existing_spec_sources: projectConventions.existing_spec_sources,
2536
+ },
2537
+ verification_commands: projectConventions.verification_commands,
2530
2538
  };
2531
2539
 
2532
2540
  if (!existsSync(workspaceConfigPath(workspaceRoot))) {