oh-my-opencode 4.16.3 → 4.17.0

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.
Files changed (177) hide show
  1. package/.agents/command/omomomo.md +1 -1
  2. package/.agents/skills/hyperplan/SKILL.md +3 -3
  3. package/.agents/skills/omomomo/SKILL.md +1 -1
  4. package/.opencode/command/omomomo.md +1 -1
  5. package/.opencode/skills/hyperplan/SKILL.md +3 -3
  6. package/.opencode/skills/pre-publish-review/SKILL.md +3 -0
  7. package/README.ja.md +4 -4
  8. package/README.ko.md +4 -4
  9. package/README.md +2 -2
  10. package/README.ru.md +4 -4
  11. package/README.zh-cn.md +4 -4
  12. package/dist/cli/index.js +179 -63
  13. package/dist/cli-node/index.js +179 -63
  14. package/dist/features/team-mode/test-support/async-test-helpers.d.ts +2 -2
  15. package/dist/index.js +121 -58
  16. package/dist/plugin/chat-message/types.d.ts +4 -0
  17. package/dist/plugin/command-execute-before.d.ts +1 -0
  18. package/dist/plugin/stop-continuation.d.ts +17 -0
  19. package/dist/skills/remove-ai-slops/SKILL.md +2 -2
  20. package/dist/skills/start-work/SKILL.md +5 -2
  21. package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  22. package/dist/tui.js +71 -29
  23. package/package.json +15 -14
  24. package/packages/git-bash-mcp/package.json +27 -0
  25. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +3 -1
  26. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +84 -19
  27. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  30. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  31. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  33. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  34. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/AGENTS.md +2 -2
  35. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +6 -2
  36. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +6 -2
  37. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +2 -2
  38. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  39. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +6 -2
  40. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/cli.test.ts +1 -1
  41. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +67 -2
  42. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  43. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  44. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +0 -13
  45. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +1 -1
  46. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  47. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  49. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  50. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +1 -79
  51. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  52. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  53. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  54. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  55. package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +2 -2
  56. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
  57. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +6 -6
  58. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +5 -5
  59. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +26 -0
  60. package/packages/omo-codex/plugin/components/ultrawork/agents/{lazycodex-executor.toml → lazycodex-worker-low.toml} +6 -4
  61. package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +26 -0
  62. package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +2 -2
  63. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +4 -4
  64. package/packages/omo-codex/plugin/components/ultrawork/directive.md +55 -28
  65. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  66. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  67. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +55 -28
  68. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  69. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +22 -0
  70. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +0 -68
  71. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +1 -1
  72. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +2 -0
  73. package/packages/omo-codex/plugin/components/ulw-loop/README.md +3 -1
  74. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +55 -28
  75. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +6 -1
  76. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +1 -1
  77. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -2
  78. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +405 -25
  79. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +12 -1
  80. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +4 -2
  81. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.d.ts +7 -0
  82. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +16 -1
  83. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +1 -0
  84. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.d.ts +6 -0
  85. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +20 -0
  86. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +1 -0
  87. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +12 -9
  88. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.d.ts +3 -0
  89. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +148 -0
  90. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.d.ts +2 -0
  91. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +209 -0
  92. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +25 -2
  93. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  94. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +14 -15
  95. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +29 -27
  96. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +6 -1
  97. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +14 -3
  98. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +10 -0
  99. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +12 -1
  100. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +4 -2
  101. package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +27 -1
  102. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +1 -0
  103. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +23 -0
  104. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +16 -9
  105. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +138 -0
  106. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +208 -0
  107. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +12 -0
  108. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +4 -1
  109. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +8 -35
  110. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +24 -13
  111. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -2
  112. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +43 -8
  113. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +55 -2
  114. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +228 -0
  115. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +193 -0
  116. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  117. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  118. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  119. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  120. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  121. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  122. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  123. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  124. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  125. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +18 -0
  126. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  127. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  128. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  129. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  130. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  131. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  132. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  133. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +17 -0
  134. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  135. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +2 -2
  136. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  137. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  138. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  139. package/packages/omo-codex/plugin/model-catalog.json +16 -7
  140. package/packages/omo-codex/plugin/package-lock.json +13 -13
  141. package/packages/omo-codex/plugin/package.json +1 -1
  142. package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
  143. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +8 -2
  144. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +2 -2
  145. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +2 -2
  146. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +4 -4
  147. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +8 -2
  148. package/packages/omo-codex/plugin/skills/start-work/SKILL.md +5 -2
  149. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +55 -28
  150. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +14 -15
  151. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +29 -27
  152. package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  153. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +2 -2
  154. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +2 -2
  155. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +76 -16
  156. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +23 -2
  157. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +1 -1
  158. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +4 -4
  159. package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -4
  160. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
  161. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +4 -101
  162. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +14 -14
  163. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +11 -0
  164. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
  165. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -2
  166. package/packages/omo-codex/plugin/test/ulw-plan-skill-contract.test.mjs +9 -40
  167. package/packages/omo-codex/plugin/test/ulw-research-skill-contract.test.mjs +4 -277
  168. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +5 -5
  169. package/packages/omo-codex/scripts/install-config.test.mjs +22 -3
  170. package/packages/omo-codex/scripts/install-dist/install-local.mjs +91 -21
  171. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +2 -2
  172. package/packages/shared-skills/skills/start-work/SKILL.md +5 -2
  173. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +2 -2
  174. package/dist/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
  175. package/packages/omo-codex/plugin/components/ulw-loop/test/skill-contract.test.ts +0 -70
  176. package/packages/omo-codex/plugin/test/ulw-research-epistemic-contract.test.mjs +0 -98
  177. package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +0 -296
@@ -13,8 +13,7 @@ metadata:
13
13
  [CODE RED] Maximum precision. Outcome-first. Evidence-driven.
14
14
 
15
15
  # Role
16
- Expert coding agent. Plan obsessively. Ship verified work. No process
17
- narration.
16
+ Expert coding agent. Ship verified work. No process narration.
18
17
 
19
18
  # Goal
20
19
  Deliver EXACTLY what the user asked, end-to-end working, proven by
@@ -44,10 +43,10 @@ success criteria (happy path + the riskiest edge); one real-surface
44
43
  proof of the user-visible deliverable, where auxiliary surfaces are
45
44
  first-class for CLI- or data-shaped work; self-review recorded in the
46
45
  notepad instead of the reviewer loop.
47
- HEAVY — anything a fact above names: the `plan` agent decides waves;
48
- 3+ success criteria (happy, edge, regression, adversarial risk), each
49
- with its own channel scenario and both evidence pieces; reviewer loop
50
- until unconditional approval.
46
+ HEAVY — anything a fact above names: 3+ success criteria (happy,
47
+ edge, regression, adversarial risk), each with its own channel
48
+ scenario and both evidence pieces; reviewer loop until unconditional
49
+ approval.
51
50
 
52
51
  # Manual-QA channels
53
52
  Run real-surface proof yourself through the channel that faithfully
@@ -97,16 +96,24 @@ evidence: screenshot + plain transcript + cleanup receipt.
97
96
 
98
97
  # Bootstrap (DO ALL FOUR BEFORE ANY OTHER WORK — NO SKIPPING)
99
98
 
100
- ## 0. Survey the skills, then size the work
99
+ ## 0. Survey the skills, gather context, then size the work
101
100
  First, survey the loaded skill list and read the description of each
102
101
  loosely relevant skill. Decide explicitly which skills this task will
103
102
  use and prefer using every genuinely applicable one — name them in the
104
103
  notepad with a one-line reason each. Skipping a skill that fits the
105
104
  task is a defect.
106
- Then run Tier triage (above) on the change set and record the tier.
107
- HEAVY: spawn the `plan` agent with the gathered context, follow its
108
- wave order and parallel grouping exactly, and run the verification it
109
- specifies. LIGHT: plan directly in the notepad.
105
+ Next, fire the first discovery wave in ONE parallel action (Finding
106
+ things below): direct lookups plus `explorer` / `librarian` children
107
+ for unfamiliar layout or external contracts.
108
+ Then run Tier triage (above) on the change set and record the tier —
109
+ tier sizes evidence and review, never who plans. Size planning by the
110
+ gathered scope: 5+ interdependent steps, multi-file waves, or
111
+ boundaries still unclear after the wave → spawn the `plan` agent,
112
+ pass it the gathered findings (file:line facts, constraints,
113
+ unknowns), and follow its wave order, parallel grouping, and
114
+ verification exactly. Anything smaller, either tier: plan directly in
115
+ the notepad. Never spawn `plan` before the discovery wave has
116
+ returned.
110
117
 
111
118
  ## 1. Create the goal with binding success criteria
112
119
  Call `create_goal` (or open your reply with a `# Goal` block treated as
@@ -224,6 +231,14 @@ Until every success criterion PASSES with its evidence captured:
224
231
  scenario captured failing when no test seam exists. It must fail
225
232
  for the RIGHT reason (not a syntax error, not a missing import).
226
233
  Paste RED output into the notepad. No production code yet.
234
+ PROSE TARGET (prompt, SKILL.md, rule, markdown): the wording is
235
+ NOT the behavior — never pin sentences, phrase presence/absence,
236
+ or word/char counts. PIN only a machine-consumed value (parsed
237
+ frontmatter field, a sentinel token a hook greps, the doc's JSON
238
+ sample through its real validator) or one `toBe` equality between
239
+ two shipped copies. A pure-prose change with no machine consumer
240
+ has NO seam: ship it on review + QA-by-read, NO test — a text grep
241
+ is pretend-coverage, not RED proof.
227
242
  3. GREEN: write the SMALLEST production change that flips RED→GREEN.
228
243
  Before GREEN work that depends on external review, PR, issue, or
229
244
  branch state, refresh current branch/PR/issue state and preserve existing ordering/policy;
@@ -269,13 +284,17 @@ make the child continue old parent context instead of the delegated task.
269
284
  If your tool list has a flat `spawn_agent` with a required `task_name` instead of `multi_agent_v1.*` (`multi_agent_v2`), rewrite: `fork_context: false` becomes `fork_turns: "none"`, `send_input` becomes `send_message`, finished agents end on their own (no `close_agent`; `followup_task` re-tasks, `interrupt_agent` stops), and `wait_agent` takes only `timeout_ms`, returning on any child mailbox activity.
270
285
 
271
286
  # TOML-backed subagent routing compatibility
272
- Treat TOML-backed role routing as **routing-unverified**. The
273
- `multi_agent_v1.spawn_agent` schema accepts `message`, `fork_context`,
274
- `agent_type`, and `model`; it cannot select a TOML-backed role, model, reasoning
275
- effort, or `service_tier` by name alone. Say so briefly in the notepad, paste the
276
- role requirements into the message, and judge the result from delivered
277
- evidence. Never claim the reviewer, planner, or explorer role was
278
- selected from TOML unless runtime evidence confirms it.
287
+ Installed role TOMLs (`~/.codex/agents/`) bind ONLY via `agent_type`.
288
+ `multi_agent_v1.spawn_agent` exposes `agent_type`; the deployed
289
+ `multi_agent_v2` `collaboration.spawn_agent` schema does NOT (verified
290
+ 2026-07-11: only `fork_turns`, `message`, `task_name`). On a v2 surface,
291
+ omit `agent_type`, describe the role and difficulty tier inside
292
+ `message`, and expect the session model for children. Difficulty tiers
293
+ when `agent_type` IS exposed: low -> `lazycodex-worker-low`
294
+ (gpt-5.6-luna/high), medium -> `lazycodex-worker-medium`
295
+ (gpt-5.6-luna/max), high -> `lazycodex-worker-high` (gpt-5.6-sol/max);
296
+ explorer/librarian carry their own TOMLs (gpt-5.6-luna/low). Difficulty
297
+ (model power) is orthogonal to LIGHT/HEAVY rigor (process size).
279
298
 
280
299
  Treat child status as a progress signal, not a timeout counter. For
281
300
  work likely to exceed one wait cycle, tell the child to send
@@ -304,7 +323,7 @@ transition, `create_goal` continuation, implementation tool call, plan
304
323
  drafting, approval-gate work, PR handoff, or final response. A timeout is
305
324
  not terminal status.
306
325
  Do not write the final answer, PR handoff, or completion summary while
307
- active child agents remain open. Use short `multi_agent_v1.wait_agent` cycles.
326
+ active child agents remain open. Use `multi_agent_v1.wait_agent` cycles with growing timeouts: start short (~30s) and double up to ~5 minutes.
308
327
  After two silent waits send `TASK STILL ACTIVE: return <deliverable> or
309
328
  BLOCKED: <reason>`. After four silent or ack-only checks, close the lane as
310
329
  inconclusive, record that it is not approval, and respawn smaller only
@@ -326,15 +345,20 @@ Procedure (NON-NEGOTIABLE):
326
345
  the message.
327
346
  Pass: goal, success-criteria, scenario evidence, full diff, notepad
328
347
  path.
329
- 2. Treat the reviewer's verdict as binding. There is NO "false
330
- positive". Every concern is real. Do not argue. Do not minimise. Do
331
- not explain it away.
332
- 3. Fix every issue. Re-run the FULL scenario QA. Capture fresh
333
- evidence. Update notepad.
334
- 4. Re-submit to the SAME reviewer. Loop until you receive an
335
- UNCONDITIONAL approval ("looks good but..." = REJECTION).
336
- 5. Only on unconditional approval may you declare done. Stopping early
337
- IS failure.
348
+ 2. Verify each reviewer concern yourself. A concern blocks only when
349
+ it names a success criterion the evidence fails; record concerns
350
+ that cite no criterion as notes with a one-line reason — fixed or
351
+ declined at your judgment.
352
+ 3. Fix every criterion-cited blocker. Re-run ONLY the scenario QA
353
+ affected by the fix; capture fresh evidence for the delta. Update
354
+ notepad.
355
+ 4. Re-submit to the SAME reviewer at most twice, passing only the
356
+ delta diff, the blockers it cited, and the already-approved criteria
357
+ marked out-of-scope. An approval whose only remaining items are
358
+ notes counts as approval.
359
+ 5. On approval, declare done. If criterion-cited blockers remain after
360
+ two re-reviews, stop and surface them to the user (mirroring the
361
+ 2-attempt stop rule below) — do not loop further.
338
362
 
339
363
  # Commits
340
364
  Atomic, Conventional Commits (`<type>(<scope>): <imperative>` — feat /
@@ -375,6 +399,9 @@ message + present for approval.
375
399
  list (`<sha> <subject>`). No file-by-file changelog unless asked.
376
400
 
377
401
  # Stop rules
402
+ - After each result, ask whether the user's core request can now be
403
+ answered with useful evidence in hand. If yes, answer now — skip any
404
+ remaining retrieval, ceremony, or verification that adds no evidence.
378
405
  - Stop ONLY when every scenario PASSES with captured evidence, every
379
406
  cleanup receipt is recorded, notepad is current, and (if gate
380
407
  triggered) reviewer approved unconditionally.
@@ -221,7 +221,7 @@ Your next move: <fill - e.g. approve, or run a high-accuracy review>. Full execu
221
221
  ## Verification strategy
222
222
  > Zero human intervention - all verification is agent-executed.
223
223
  - Test decision: <TDD | tests-after | none> + framework
224
- - Evidence: .omo/evidence/task-<N>-${slug}.<ext>
224
+ - Evidence: <attemptDir>/task-<N>-${slug}.<ext> (attemptDir = currentAttemptDir from 'omo ulw-loop status --json', .omo/evidence/ulw/<session>/<goalId>/a<attempt>; outside ulw-loop use .omo/evidence/)
225
225
 
226
226
  ## Execution strategy
227
227
  ### Parallel execution waves
@@ -239,7 +239,7 @@ Your next move: <fill - e.g. approve, or run a high-accuracy review>. Full execu
239
239
  Parallelization: Wave <N> | Blocked by: <...> | Blocks: <...>
240
240
  References (executor has NO interview context - be exhaustive): <src/path:lines>
241
241
  Acceptance criteria (agent-executable): <exact command or assertion>
242
- QA scenarios (name the exact tool + invocation): happy + failure, Evidence .omo/evidence/task-1-${slug}.<ext>
242
+ QA scenarios (name the exact tool + invocation): happy + failure, Evidence <attemptDir>/task-1-${slug}.<ext>
243
243
  Commit: <Y/N> | <type>(<scope>): <summary>
244
244
 
245
245
  ## Final verification wave
@@ -284,4 +284,26 @@ describe("codex ultrawork hook", () => {
284
284
  expect(directive).toMatch(/ratchet up only/i);
285
285
  expect(directive).toMatch(/`plan` agent/);
286
286
  });
287
+
288
+ it("#given directive #when inspected #then orders discovery before scope-gated planning", () => {
289
+ // given
290
+ const payload = {
291
+ hook_event_name: "UserPromptSubmit",
292
+ prompt: "ulw",
293
+ };
294
+
295
+ // when
296
+ const output = runUserPromptSubmitHook(payload, { skillFilePath: null });
297
+ const parsed = parseHookOutput(output);
298
+
299
+ // then
300
+ const directive = parsed.hookSpecificOutput.additionalContext;
301
+ expect(directive).toMatch(/fire the first discovery wave[\s\S]*?spawn the `plan` agent/i);
302
+ expect(directive).toMatch(/5\+ interdependent steps/);
303
+ expect(directive).toMatch(/[Nn]ever spawn `plan` before the discovery wave/);
304
+ expect(directive).toMatch(/tier sizes\s+evidence and review, never who plans/i);
305
+ expect(directive).not.toMatch(/HEAVY: spawn the `plan` agent/);
306
+ expect(directive).not.toMatch(/`plan` agent decides waves/);
307
+ expect(directive).not.toMatch(/Plan obsessively/);
308
+ });
287
309
  });
@@ -37,72 +37,4 @@ describe("codex ultrawork package metadata", () => {
37
37
  expect(hookCommands).toContain(`node "${pluginRoot}/dist/cli.js" hook user-prompt-submit`);
38
38
  expect(hookCommands).not.toContainEqual(expect.stringMatching(/\bpython3?\b|ultrawork-detector\.py/));
39
39
  });
40
-
41
- it("#given explorer guidance #when inspected #then names the packaged code-search surfaces", () => {
42
- // given
43
- const explorer = readTextFile("agents/explorer.toml");
44
-
45
- // when
46
- const guidance = explorer.toLowerCase();
47
-
48
- // then
49
- expect(guidance).toContain("ast-grep");
50
- expect(guidance).toContain("structural");
51
- });
52
-
53
- it("#given explorer guidance #when inspected #then starts codebase inspection with native search", () => {
54
- // given
55
- const explorer = readTextFile("agents/explorer.toml");
56
- const directive = readTextFile("directive.md");
57
-
58
- // when
59
- const guidance = explorer.toLowerCase();
60
- const repoInspectionIndex = guidance.indexOf("repo-wide inspection");
61
- const lspIndex = guidance.indexOf("lsp_goto_definition");
62
- const structuralIndex = guidance.indexOf("ast-grep");
63
-
64
- // then
65
- expect(repoInspectionIndex).toBeGreaterThanOrEqual(0);
66
- expect(lspIndex).toBeGreaterThan(repoInspectionIndex);
67
- expect(structuralIndex).toBeGreaterThan(repoInspectionIndex);
68
- expect(explorer).toContain("`rg`, `rg --files`, `cat`, and `git`");
69
- expect(directive).toContain("`rg`, `rg --files`,");
70
- });
71
-
72
- it("#given librarian guidance #when inspected #then names the packaged research MCP surfaces", () => {
73
- // given
74
- const librarian = readTextFile("agents/librarian.toml");
75
-
76
- // when
77
- const guidance = librarian.toLowerCase();
78
-
79
- // then
80
- expect(guidance).toContain("grep_app");
81
- expect(guidance).toContain("context7");
82
- expect(guidance).toContain("ast-grep");
83
- });
84
-
85
- it("#given ulw-plan skill #when inspected #then requires dynamic adversarial workflow phases", () => {
86
- // given
87
- const skill = readTextFile("skills/ulw-plan/SKILL.md");
88
- const workflow = readTextFile("skills/ulw-plan/references/full-workflow.md");
89
- const skillContracts = ["CodeGraph first", "scripts/scaffold-plan.mjs", "Approval gate"] as const;
90
- const workflowContracts = [
91
- "dynamic adversarial workflow phases",
92
- "stale_state",
93
- "source-vs-packaged split",
94
- "misleading_success_output",
95
- "confirm a test really ran",
96
- "prompt_injection",
97
- "Discord / external content as claims",
98
- ] as const;
99
-
100
- // then
101
- for (const contract of skillContracts) {
102
- expect(skill, `skill should include ${contract}`).toContain(contract);
103
- }
104
- for (const contract of workflowContracts) {
105
- expect(workflow, `workflow should include ${contract}`).toContain(contract);
106
- }
107
- });
108
40
  });
@@ -45,4 +45,4 @@ Conventions for human contributors and AI agents working on this repository.
45
45
  ## Build and Hooks
46
46
 
47
47
  - Build output goes to `dist/`.
48
- - `hooks/hooks.json` runs `node ${PLUGIN_ROOT}/dist/cli.js hook user-prompt-submit --with-ultrawork`.
48
+ - `hooks/hooks.json` wires `hook user-prompt-submit --with-ultrawork` (UserPromptSubmit), `hook pre-tool-use` (create_goal budget), `hook pre-tool-use-spawn` (spawn guards), and `hook stop` (auto-resume).
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## [0.1.0] - unreleased
4
4
 
5
+ - **Hooks:** new `Stop` hook auto-resumes a turn that died with unfinished goals (defers to start-work-continuation while its plan has remaining tasks, bails under context pressure, and caps at two resumes without ledger movement via a separate `.stuck` marker). New `PreToolUse` spawn guard adds a per-session fan-out cap (`OMO_SPAWN_FANOUT_LIMIT`, default 60) and denies final gate-reviewer spawns while the reviewer artifacts the gate audits are missing.
6
+
5
7
  - **Memory:** steering ledger entries no longer embed the full plan four times (`before`/`after` at both the audit and entry level). Accepted steers now record a compact `UlwLoopSteeringPlanSnapshot` (plan counters + only the goals the mutation touched), shrinking a measured real-world entry from 189KB to 7.8KB (~24x) and ending quadratic `ledger.jsonl` growth over long runs.
6
8
  - **Memory:** steering dedup (`--idempotency-key` / `promptSignature`) streams the ledger line-by-line with a substring pre-filter instead of `JSON.parse`-ing every entry into memory; dedup returns strip legacy full-plan `before`/`after` payloads from re-surfaced audits. `readSteeringLedgerEntries` streams too.
7
9
  - **Memory:** `withUlwLoopMutationLock` no longer retains the mutation result (full plan/audit) per `(repo, scope)` in its module-level lock map; settled gates self-evict, so long-lived embedders stop accumulating entries.
@@ -27,9 +27,11 @@ The final quality gate parsed by `checkpoint` validates `codeReview`, `manualQa`
27
27
 
28
28
  This directory is a component of the aggregate `@sisyphuslabs/omo-codex-plugin` root. Plugin discovery (`.codex-plugin/plugin.json`) is owned by that aggregate root, not by this component. The component ships:
29
29
 
30
- - `hooks/hooks.json` registering two hooks:
30
+ - `hooks/hooks.json` registering four hooks:
31
31
  - `UserPromptSubmit` -> `node "${PLUGIN_ROOT}/dist/cli.js" hook user-prompt-submit --with-ultrawork`
32
32
  - `PreToolUse` matching `^create_goal$` -> `node "${PLUGIN_ROOT}/dist/cli.js" hook pre-tool-use`
33
+ - `PreToolUse` matching the spawn tool tokens -> `node "${PLUGIN_ROOT}/dist/cli.js" hook pre-tool-use-spawn` (fan-out cap + gate-artifact preflight)
34
+ - `Stop` -> `node "${PLUGIN_ROOT}/dist/cli.js" hook stop` (auto-resume with a two-strike no-progress cap)
33
35
  - `skills/ulw-loop/` for the bundled `ulw-loop` skill.
34
36
  - `bin.omo-ulw-loop` -> `dist/cli.js` for standalone CLI invocation.
35
37
 
@@ -6,8 +6,7 @@
6
6
  [CODE RED] Maximum precision. Outcome-first. Evidence-driven.
7
7
 
8
8
  # Role
9
- Expert coding agent. Plan obsessively. Ship verified work. No process
10
- narration.
9
+ Expert coding agent. Ship verified work. No process narration.
11
10
 
12
11
  # Goal
13
12
  Deliver EXACTLY what the user asked, end-to-end working, proven by
@@ -37,10 +36,10 @@ success criteria (happy path + the riskiest edge); one real-surface
37
36
  proof of the user-visible deliverable, where auxiliary surfaces are
38
37
  first-class for CLI- or data-shaped work; self-review recorded in the
39
38
  notepad instead of the reviewer loop.
40
- HEAVY — anything a fact above names: the `plan` agent decides waves;
41
- 3+ success criteria (happy, edge, regression, adversarial risk), each
42
- with its own channel scenario and both evidence pieces; reviewer loop
43
- until unconditional approval.
39
+ HEAVY — anything a fact above names: 3+ success criteria (happy,
40
+ edge, regression, adversarial risk), each with its own channel
41
+ scenario and both evidence pieces; reviewer loop until unconditional
42
+ approval.
44
43
 
45
44
  # Manual-QA channels
46
45
  Run real-surface proof yourself through the channel that faithfully
@@ -90,16 +89,24 @@ evidence: screenshot + plain transcript + cleanup receipt.
90
89
 
91
90
  # Bootstrap (DO ALL FOUR BEFORE ANY OTHER WORK — NO SKIPPING)
92
91
 
93
- ## 0. Survey the skills, then size the work
92
+ ## 0. Survey the skills, gather context, then size the work
94
93
  First, survey the loaded skill list and read the description of each
95
94
  loosely relevant skill. Decide explicitly which skills this task will
96
95
  use and prefer using every genuinely applicable one — name them in the
97
96
  notepad with a one-line reason each. Skipping a skill that fits the
98
97
  task is a defect.
99
- Then run Tier triage (above) on the change set and record the tier.
100
- HEAVY: spawn the `plan` agent with the gathered context, follow its
101
- wave order and parallel grouping exactly, and run the verification it
102
- specifies. LIGHT: plan directly in the notepad.
98
+ Next, fire the first discovery wave in ONE parallel action (Finding
99
+ things below): direct lookups plus `explorer` / `librarian` children
100
+ for unfamiliar layout or external contracts.
101
+ Then run Tier triage (above) on the change set and record the tier —
102
+ tier sizes evidence and review, never who plans. Size planning by the
103
+ gathered scope: 5+ interdependent steps, multi-file waves, or
104
+ boundaries still unclear after the wave → spawn the `plan` agent,
105
+ pass it the gathered findings (file:line facts, constraints,
106
+ unknowns), and follow its wave order, parallel grouping, and
107
+ verification exactly. Anything smaller, either tier: plan directly in
108
+ the notepad. Never spawn `plan` before the discovery wave has
109
+ returned.
103
110
 
104
111
  ## 1. Create the goal with binding success criteria
105
112
  Call `create_goal` (or open your reply with a `# Goal` block treated as
@@ -217,6 +224,14 @@ Until every success criterion PASSES with its evidence captured:
217
224
  scenario captured failing when no test seam exists. It must fail
218
225
  for the RIGHT reason (not a syntax error, not a missing import).
219
226
  Paste RED output into the notepad. No production code yet.
227
+ PROSE TARGET (prompt, SKILL.md, rule, markdown): the wording is
228
+ NOT the behavior — never pin sentences, phrase presence/absence,
229
+ or word/char counts. PIN only a machine-consumed value (parsed
230
+ frontmatter field, a sentinel token a hook greps, the doc's JSON
231
+ sample through its real validator) or one `toBe` equality between
232
+ two shipped copies. A pure-prose change with no machine consumer
233
+ has NO seam: ship it on review + QA-by-read, NO test — a text grep
234
+ is pretend-coverage, not RED proof.
220
235
  3. GREEN: write the SMALLEST production change that flips RED→GREEN.
221
236
  Before GREEN work that depends on external review, PR, issue, or
222
237
  branch state, refresh current branch/PR/issue state and preserve existing ordering/policy;
@@ -262,13 +277,17 @@ make the child continue old parent context instead of the delegated task.
262
277
  If your tool list has a flat `spawn_agent` with a required `task_name` instead of `multi_agent_v1.*` (`multi_agent_v2`), rewrite: `fork_context: false` becomes `fork_turns: "none"`, `send_input` becomes `send_message`, finished agents end on their own (no `close_agent`; `followup_task` re-tasks, `interrupt_agent` stops), and `wait_agent` takes only `timeout_ms`, returning on any child mailbox activity.
263
278
 
264
279
  # TOML-backed subagent routing compatibility
265
- Treat TOML-backed role routing as **routing-unverified**. The
266
- `multi_agent_v1.spawn_agent` schema accepts `message`, `fork_context`,
267
- `agent_type`, and `model`; it cannot select a TOML-backed role, model, reasoning
268
- effort, or `service_tier` by name alone. Say so briefly in the notepad, paste the
269
- role requirements into the message, and judge the result from delivered
270
- evidence. Never claim the reviewer, planner, or explorer role was
271
- selected from TOML unless runtime evidence confirms it.
280
+ Installed role TOMLs (`~/.codex/agents/`) bind ONLY via `agent_type`.
281
+ `multi_agent_v1.spawn_agent` exposes `agent_type`; the deployed
282
+ `multi_agent_v2` `collaboration.spawn_agent` schema does NOT (verified
283
+ 2026-07-11: only `fork_turns`, `message`, `task_name`). On a v2 surface,
284
+ omit `agent_type`, describe the role and difficulty tier inside
285
+ `message`, and expect the session model for children. Difficulty tiers
286
+ when `agent_type` IS exposed: low -> `lazycodex-worker-low`
287
+ (gpt-5.6-luna/high), medium -> `lazycodex-worker-medium`
288
+ (gpt-5.6-luna/max), high -> `lazycodex-worker-high` (gpt-5.6-sol/max);
289
+ explorer/librarian carry their own TOMLs (gpt-5.6-luna/low). Difficulty
290
+ (model power) is orthogonal to LIGHT/HEAVY rigor (process size).
272
291
 
273
292
  Treat child status as a progress signal, not a timeout counter. For
274
293
  work likely to exceed one wait cycle, tell the child to send
@@ -297,7 +316,7 @@ transition, `create_goal` continuation, implementation tool call, plan
297
316
  drafting, approval-gate work, PR handoff, or final response. A timeout is
298
317
  not terminal status.
299
318
  Do not write the final answer, PR handoff, or completion summary while
300
- active child agents remain open. Use short `multi_agent_v1.wait_agent` cycles.
319
+ active child agents remain open. Use `multi_agent_v1.wait_agent` cycles with growing timeouts: start short (~30s) and double up to ~5 minutes.
301
320
  After two silent waits send `TASK STILL ACTIVE: return <deliverable> or
302
321
  BLOCKED: <reason>`. After four silent or ack-only checks, close the lane as
303
322
  inconclusive, record that it is not approval, and respawn smaller only
@@ -319,15 +338,20 @@ Procedure (NON-NEGOTIABLE):
319
338
  the message.
320
339
  Pass: goal, success-criteria, scenario evidence, full diff, notepad
321
340
  path.
322
- 2. Treat the reviewer's verdict as binding. There is NO "false
323
- positive". Every concern is real. Do not argue. Do not minimise. Do
324
- not explain it away.
325
- 3. Fix every issue. Re-run the FULL scenario QA. Capture fresh
326
- evidence. Update notepad.
327
- 4. Re-submit to the SAME reviewer. Loop until you receive an
328
- UNCONDITIONAL approval ("looks good but..." = REJECTION).
329
- 5. Only on unconditional approval may you declare done. Stopping early
330
- IS failure.
341
+ 2. Verify each reviewer concern yourself. A concern blocks only when
342
+ it names a success criterion the evidence fails; record concerns
343
+ that cite no criterion as notes with a one-line reason — fixed or
344
+ declined at your judgment.
345
+ 3. Fix every criterion-cited blocker. Re-run ONLY the scenario QA
346
+ affected by the fix; capture fresh evidence for the delta. Update
347
+ notepad.
348
+ 4. Re-submit to the SAME reviewer at most twice, passing only the
349
+ delta diff, the blockers it cited, and the already-approved criteria
350
+ marked out-of-scope. An approval whose only remaining items are
351
+ notes counts as approval.
352
+ 5. On approval, declare done. If criterion-cited blockers remain after
353
+ two re-reviews, stop and surface them to the user (mirroring the
354
+ 2-attempt stop rule below) — do not loop further.
331
355
 
332
356
  # Commits
333
357
  Atomic, Conventional Commits (`<type>(<scope>): <imperative>` — feat /
@@ -368,6 +392,9 @@ message + present for approval.
368
392
  list (`<sha> <subject>`). No file-by-file changelog unless asked.
369
393
 
370
394
  # Stop rules
395
+ - After each result, ask whether the user's core request can now be
396
+ answered with useful evidence in hand. If yes, answer now — skip any
397
+ remaining retrieval, ceremony, or verification that adds no evidence.
371
398
  - Stop ONLY when every scenario PASSES with captured evidence, every
372
399
  cleanup receipt is recorded, notepad is current, and (if gate
373
400
  triggered) reviewer approved unconditionally.
@@ -1,3 +1,4 @@
1
+ import { ulwLoopAttemptEvidenceDir } from "./paths.js";
1
2
  import { existsSync, statSync } from "node:fs";
2
3
  import { readFile } from "node:fs/promises";
3
4
  import { resolve } from "node:path";
@@ -79,12 +80,13 @@ function ledgerKind(status, goal, aggregateCompletion) {
79
80
  return status === "blocked" ? "goal_blocked" : "goal_failed";
80
81
  }
81
82
  function buildLedger(now, args, goal, qualityGate, codexGoal, aggregateCompletion) {
83
+ const watch = qualityGate?.codeReview.codeQualityStatus === "WATCH";
82
84
  const entry = {
83
85
  at: now,
84
86
  kind: ledgerKind(args.status, goal, aggregateCompletion),
85
87
  goalId: goal.id,
86
88
  status: goal.status,
87
- evidence: args.evidence,
89
+ evidence: watch ? `${args.evidence} | codeQuality=WATCH: ${qualityGate.codeReview.evidence}` : args.evidence,
88
90
  };
89
91
  if (codexGoal !== undefined)
90
92
  entry.codexGoal = codexGoal;
@@ -148,6 +150,9 @@ export async function checkpointUlwLoop(repoRoot, args, scope) {
148
150
  qualityGate = validateQualityGate(await readJsonInput(args.qualityGateJson, repoRoot), {
149
151
  repoRoot,
150
152
  fs: QUALITY_GATE_FS,
153
+ ...(plan.evidenceLayoutVersion === 2
154
+ ? { currentAttemptDir: ulwLoopAttemptEvidenceDir(goal.id, goal.attempt, scope) }
155
+ : {}),
151
156
  });
152
157
  goal.status = "complete";
153
158
  goal.completedAt = now;
@@ -1,4 +1,4 @@
1
- import type { UlwLoopScope } from "./paths.js";
1
+ import { type UlwLoopScope } from "./paths.js";
2
2
  export declare function createGoals(repoRoot: string, argv: readonly string[], json: boolean, scope?: UlwLoopScope): Promise<number>;
3
3
  export declare function status(repoRoot: string, json: boolean, scope?: UlwLoopScope): Promise<number>;
4
4
  export declare function completeGoals(repoRoot: string, argv: readonly string[], json: boolean, scope?: UlwLoopScope): Promise<number>;
@@ -6,6 +6,7 @@ import { parseSteeringProposal, printSteerResult } from "./cli-steering.js";
6
6
  import { buildCodexGoalInstruction } from "./codex-goal-instruction.js";
7
7
  import { recordEvidence } from "./evidence.js";
8
8
  import { isEssentialCriterion } from "./goal-status.js";
9
+ import { ulwLoopAttemptEvidenceDir } from "./paths.js";
9
10
  import { addUlwLoopGoal, createUlwLoopPlan, startNextUlwLoop, summarizeUlwLoopPlan } from "./plan-crud.js";
10
11
  import { readUlwLoopPlan } from "./plan-io.js";
11
12
  import { recordFinalReviewBlockers } from "./review-blockers.js";
@@ -34,8 +35,18 @@ export async function createGoals(repoRoot, argv, json, scope) {
34
35
  }
35
36
  export async function status(repoRoot, json, scope) {
36
37
  const plan = await readUlwLoopPlan(repoRoot, scope);
37
- if (json)
38
- printJson({ ok: true, plan, summary: summarizeUlwLoopPlan(plan) });
38
+ if (json) {
39
+ const active = plan.goals.find((goal) => goal.id === plan.activeGoalId);
40
+ const currentAttemptDir = plan.evidenceLayoutVersion === 2 && active
41
+ ? ulwLoopAttemptEvidenceDir(active.id, active.attempt, scope)
42
+ : undefined;
43
+ printJson({
44
+ ok: true,
45
+ plan,
46
+ summary: summarizeUlwLoopPlan(plan),
47
+ ...(currentAttemptDir === undefined ? {} : { currentAttemptDir }),
48
+ });
49
+ }
39
50
  else
40
51
  printStatus(plan);
41
52
  return 0;