Skip to content

fix(ulw-plan): recognize approval intent and stop the approval-gate loop#54

Closed
JSap0914 wants to merge 1 commit into
code-yeongyu:mainfrom
JSap0914:fix/48-ulw-plan-approval-gate-loop
Closed

fix(ulw-plan): recognize approval intent and stop the approval-gate loop#54
JSap0914 wants to merge 1 commit into
code-yeongyu:mainfrom
JSap0914:fix/48-ulw-plan-approval-gate-loop

Conversation

@JSap0914

@JSap0914 JSap0914 commented Jun 13, 2026

Copy link
Copy Markdown

Fixes #48.

Problem

ulw-plan's approval gate waits for the user to reply with one exact phrase before it writes .omo/plans/<slug>.md, and it keeps no durable record of what it is waiting on. After context growth or a turn transition the planner re-runs exploration and re-emits the full "blocked at the approval gate" message — a token-burning loop, even when the user has clearly approved ("yes", "proceed", etc.).

Fix

Tighten the gate wording in the ulw-plan skill and its references/full-workflow.md so the planner:

  • treats common approval replies — "yes", "approve", "proceed", "go ahead", "write/create the plan", and localized equivalents — as approval instead of demanding one magic phrase;
  • persists the pending gate to .omo/drafts/<slug>.md (exact pending action + target plan path) and reads that durable state on the next turn instead of re-running exploration or restating the whole plan;
  • emits a single concise approval prompt when still unapproved, so the gate cannot loop.

The safety boundary is unchanged: still planner-only, still no plan file / Metis / execution before approval, and the narrow $start-work bootstrap exception is preserved.

Verification

Extended plugins/omo/test/ulw-plan-skill.test.mjs with assertions for the approval-intent / durable-state / single-prompt contract:

node --test plugins/omo/test/ulw-plan-skill.test.mjs
# tests 3 / pass 3 / fail 0

Component (components/ultrawork/skills/ulw-plan/) and packaged (skills/ulw-plan/) copies are kept byte-identical, so the sync-skills drift check stays green.


Summary by cubic

Stops the approval-gate loop in ulw-plan by recognizing approval intent and persisting gate state to .omo/drafts/<slug>.md. Fixes #48 while keeping the planner-only safety boundary and the $start-work exception unchanged.

  • Bug Fixes
    • Accept common and localized approvals (e.g., "yes", "approve", "proceed", "go ahead", "write/create the plan"); no magic phrase.
    • Persist the pending gate (action + target .omo/plans/<slug>.md) and read it on the next turn to avoid re-running exploration.
    • When still unapproved, ask one concise approval prompt instead of restating the full brief.
    • Updated SKILL/workflow docs and tests to enforce this behavior.

Written for commit e3c3f10. Summary will update on new commits.

Review in cubic

The planner waited for one exact approval phrase before writing
`.omo/plans/<slug>.md` and kept no durable record of what it was
waiting on, so after context growth it re-ran exploration and re-emitted
the full blocked-gate message — a token-burning loop even when the user
clearly approved.

Tighten the gate wording so the planner accepts common approval replies
(and localized equivalents), persists the pending gate to
`.omo/drafts/<slug>.md` and reads that state on the next turn instead of
restating the whole plan, and emits a single concise prompt when still
unapproved. The planner-only safety boundary and the `$start-work`
bootstrap exception are unchanged. Extends ulw-plan-skill.test.mjs.

Fixes code-yeongyu#48.
Copilot AI review requested due to automatic review settings June 13, 2026 20:52
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the PR! Changes to LazyCodex land through oh-my-openagent — could you open this against omo-codex over there instead? PRs in this repository can't be merged.

If you're working with a coding agent, prompt it like this:

I opened #54 ("fix(ulw-plan): recognize approval intent and stop the approval-gate loop") against code-yeongyu/lazycodex, but changes there land through code-yeongyu/oh-my-openagent, where the Codex implementation lives under packages/omo-codex. Read my original PR, then open an equivalent PR against code-yeongyu/oh-my-openagent. In the new PR body, link the original PR (#54), explain that it was first opened against lazycodex, and describe in detail what that PR changed and why.

@github-actions github-actions Bot closed this Jun 13, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates the ulw-plan skill documentation and tests to make the “approval gate” more robust and less prone to looping by persisting gate state and accepting flexible approval intent.

Changes:

  • Added new “recognize approval intent / persist gate / avoid looping” guidance to SKILL.md and full-workflow.md.
  • Mirrored the same approval-gate guidance into the components/ultrawork copies of the docs.
  • Strengthened tests to assert the new guidance is present in the skill/workflow references.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
plugins/omo/test/ulw-plan-skill.test.mjs Adds assertions to enforce new approval-gate wording in docs.
plugins/omo/skills/ulw-plan/references/full-workflow.md Documents robust approval handling + durable gate state persistence.
plugins/omo/skills/ulw-plan/SKILL.md Adds a compact bullet describing the new approval gate behavior.
plugins/omo/components/ultrawork/skills/ulw-plan/references/full-workflow.md Mirrors the same workflow guidance for the ultrawork component.
plugins/omo/components/ultrawork/skills/ulw-plan/SKILL.md Mirrors the same SKILL.md bullet for the ultrawork component.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +31 to +34
assert.match(skill, /Recognize approval intent/);
assert.match(skill, /do not demand one exact magic phrase/);
assert.match(skill, /record the pending gate in `\.omo\/drafts\/<slug>\.md`/);
assert.match(skill, /ask ONE concise approval question/);

Then **wait for the user's explicit okay** before generating the plan. No Metis, no plan file, no execution until the user approves. If the user amends scope, fold it in and re-present the brief. This gate replaces any automatic interview-to-plan transition.

Handle approval intent robustly so the gate never loops. Accept clear approval replies — "yes", "approve", "approved", "proceed", "go ahead", "do it", "write the plan", "create the plan", and localized equivalents (e.g. Korean "네", "응", "진행", "ㄱㄱ", "작성해") — as approval; never require one exact magic phrase. When you present the brief, persist the pending gate to `.omo/drafts/<slug>.md` with the exact pending action ("awaiting approval to write `.omo/plans/<slug>.md`") and target plan path; on the next turn read that durable gate state first instead of re-running exploration or re-explaining the full planning status. If the reply is still not approval, emit a single concise approval prompt rather than restating the whole brief, so the gate cannot burn context in a re-approval loop. Replies that amend scope update the brief and re-present it; they never trigger plan generation.

Then **wait for the user's explicit okay** before generating the plan. No Metis, no plan file, no execution until the user approves. If the user amends scope, fold it in and re-present the brief. This gate replaces any automatic interview-to-plan transition.

Handle approval intent robustly so the gate never loops. Accept clear approval replies — "yes", "approve", "approved", "proceed", "go ahead", "do it", "write the plan", "create the plan", and localized equivalents (e.g. Korean "네", "응", "진행", "ㄱㄱ", "작성해") — as approval; never require one exact magic phrase. When you present the brief, persist the pending gate to `.omo/drafts/<slug>.md` with the exact pending action ("awaiting approval to write `.omo/plans/<slug>.md`") and target plan path; on the next turn read that durable gate state first instead of re-running exploration or re-explaining the full planning status. If the reply is still not approval, emit a single concise approval prompt rather than restating the whole brief, so the gate cannot burn context in a re-approval loop. Replies that amend scope update the brief and re-present it; they never trigger plan generation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ulw-plan approval gate can loop after planning draft is ready

2 participants