Claude Cursor opencode Skill

ulw-loop

Goal-like loop that uses ultrawork mode to decompose work into systematic, evidence-bound steps.

LLM Mart · 0 points · 22 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download code-yeongyu-oh-my-openagent-packages_omo-senpi_skills_ulw-loop-05dcba6.zip · 21 KB
Part of code-yeongyu/oh-my-openagent — 51 skills

Install

skills CLI npx skills add https://github.com/code-yeongyu/oh-my-openagent/tree/dev/packages/omo-senpi/skills/ulw-loop
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install code-yeongyu-oh-my-openagent@llmmart
Git git clone https://github.com/code-yeongyu/oh-my-openagent.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole code-yeongyu/oh-my-openagent collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

ulw-loop

Use this skill when the user asks for ulw-loop, ulw, durable goal execution, evidence-led work, manual QA, or checkpointed long-running delivery.

This skill is compact by design: the run contract below is the whole bootstrap. references/full-workflow.md and references/define-goal.md carry the full doctrine; open a section only when the phase you are in needs it.

Run contract

  1. Create goals from a JS eval cell: agentToolkit.createGoals({ brief }) after the SDK import below. The SDK binds this session from the host env, so never pass a session id or a plan path. If the envelope reports ULW_LOOP_PLAN_EXISTS_COMPLETE (this session's aggregate is already complete), unrelated new work needs a fresh session; createGoals({ brief, force: true }) is only for deliberately overwriting completed evidence.
  2. Register the aggregate objective from the returned handoff with create_goal, shaped by references/define-goal.md. Goal creation is NEVER skipped.
  3. Mirror every atomic step into the live todo checklist: one granular step per action, exactly one in_progress, transitions marked the instant they happen.
  4. Treat each goal as a phase: create its own worktree off the integration base; dispatch its dependency-ordered lanes as ONE workflow run (read the mass-ulw skill first; ordering-free lanes stay a task batch); verify every criterion with real-surface evidence; land the worktree on the integration base at agentToolkit.checkpoint({ goalId, status: "complete", evidence }) per the repository's flow (direct merge or merged PR); define the next goal's run from what this one proved. Tests alone never prove done. When a mass-ulw pointer accompanies this skill, this contract still owns goals, criteria, evidence, and checkpoints.
  5. Stop when the goal's WHEN-TO-STOP line holds with evidence in hand.

When the injected ultrawork directive accompanies this skill, its goal/notepad/todo bootstrap is subsumed by this contract: the loop SDK owns goal state and the loop ledger is the notepad. Do not create a second one.

The SDK: one import, then method calls

Every ulw-loop operation runs inside a JS eval cell through the SDK the extension publishes at OMO_AGENT_TOOLKIT_SDK_ROOT. There is no omo_agent_toolkit tool and no CLI to spawn on Senpi.

const { agentToolkit } = await import(`${env("OMO_AGENT_TOOLKIT_SDK_ROOT")}/sdk.js`)
print(await agentToolkit.status())

Rules that keep it working:

  • JS cells only. From a py, rb, or jl cell, run a separate eval with language js.
  • Import once per kernel lifetime. agentToolkit stays bound in later cells; re-import only after a kernel restart or a ReferenceError: agentToolkit is not defined.
  • Every call resolves to an envelope, never a throw: { ok: true, operation, result, nextActions, warnings? } or { ok: false, operation, error: { code, message }, warnings? }. nextActions are things to do next; warnings are facts to know (a fallback the binder took, a driver objective that differs). Read nextActions before deciding the next step, and branch on error.code, not on the message text.
  • Never pass a session id or plan path. The SDK binds PI_SESSION_ID and PI_SESSION_CWD from the host env on each call; state lives under .omo/ulw-loop/<session-id>/. When PI_SESSION_CWD is missing (seen after an extension reload restarted the kernel), the binder falls back to the cwd recorded in the PI_SESSION_FILE header, then to process.cwd(), and every envelope carries a warning naming the fix: env("PI_SESSION_CWD", "<session cwd>"). status().result.binding shows { cwd, cwdSource, sessionId, goalStorePaths }, so check it after any kernel restart and re-pin the env when cwdSource is not PI_SESSION_CWD.
  • The driver snapshot is filled automatically from this session's goal store. Pass codexGoalJson only to override it.

Methods (argument fields are exact):

Method Args
help() none; result.operations[] carries method (the camelCase name to call), args (field -> type, ? = optional), description, mutating — enough to recover every call below after a kernel restart
status() none; result carries plan, summary, nextActions, evidenceRoot (stable plan-level artifact dir), currentAttemptDir (moves with the active goal), binding (cwd, cwdSource, sessionId, goalStorePaths), driver (available, status, objectiveMatchesPlan, objectiveAcknowledged)
createGoals(args) { brief, codexGoalMode?, force?, validationBatchesJson? }
completeGoals(args?) { retryFailed? }; acquires the next eligible goal or resumes the in-progress one
criteria(args) { goalId }
recordEvidence(args) { goalId, criterionId, status: "pass" \| "fail" \| "blocked", evidence, notes?, artifacts? }; every artifacts path must exist (resolved against the session cwd, ULW_LOOP_EVIDENCE_ARTIFACT_MISSING otherwise) and is stored on the criterion and the ledger entry, repo-relative when inside the cwd
checkpoint(args) { goalId, status: "complete" \| "failed" \| "blocked", evidence, codexGoalJson?, qualityGateJson? }, or { printTemplate: true, goalId? } for the quality-gate template
steer(args) { kind, source: "finding", evidence, rationale, ...kind fields }; kinds and their fields are in references/full-workflow.md
addGoal(args) { title, objective, successCriteria? } with successCriteria: [{ scenario, expectedEvidence, userModel?, essential? }]; omit it and the three seeded placeholders name the exact steer({ kind: "revise_criterion", ... }) call that replaces each one
recordReviewBlockers(args) { goalId, title, objective, evidence, codexGoalJson? }

Non-Negotiables

  • Write loop state only through the SDK; it lives under .omo/ulw-loop/<session-id>/ and is never hand-edited. Mutations are serialized across processes by the session's .state.lock, so parallel recordEvidence calls from workers are safe.
  • Register goals up front, shaped by references/define-goal.md (agentToolkit.createGoals({ brief }), then create_goal from the returned handoff), and mirror every atomic step into the live todo checklist: one ultra-granular step per action, exactly one in_progress, transitions marked the instant they happen.
  • After any compaction or context loss, re-read brief + goals + ledger FIRST plus agentToolkit.status() (re-import the SDK if the kernel restarted; help() lists every method with its argument fields), confirm result.binding.cwdSource is PI_SESSION_CWD and re-pin it with env("PI_SESSION_CWD", result.binding.cwd) when it is not, then resume; never re-plan from scratch.
  • If createGoals answers ULW_LOOP_PLAN_EXISTS_COMPLETE, this session's aggregate is already done: start unrelated new work in a fresh session instead of steering or forcing the completed state. Use force: true only to intentionally overwrite completed evidence.
  • Every success criterion needs observable evidence from a real surface: a channel (terminal/TUI via the xterm.js web terminal, HTTP, browser, computer-use) or, for CLI- or data-shaped criteria, an auxiliary surface (CLI stdout, DB diff, parsed config dump).
  • Evidence is bound to the tree it was captured at (git rev-parse --short "HEAD^{tree}"); it goes stale only when tracked content changes — a rebase or amend that keeps the tree identical keeps it valid. When the tree differs, re-run at the current HEAD and re-record, never relabel or regenerate. Record only after cleanup receipts exist.
  • Delegate code edits, test writes, fixes, and QA execution to right-sized omo-senpi subagents through the native task tool or through workflow nodes when the phase's lanes carry ordering.
  • Use git-master for git-tracked edits: inspect recent and touched-path commit history, then commit each verified work unit atomically in the repository's observed language, scope, and message style with only that unit's files staged. Never carry verified units into a later omnibus commit.

Team mode: decide it, do not default to it

Solo execution with parallel background task workers is the default: fan independent units out in one batched spawn, each routed to the category (or configured subagent_type) that fits it, with scopes cut so no two workers write the same files. A team (team_create) adds per-member briefing, shared-state, and relay overhead, so it must be paid for by the work's shape. Decide ONCE, when the plan's work units are known, and record the verdict plus its reason in the notepad.

Stand up a team when BOTH hold:

  1. The units' scopes overlap in a way you cannot cleanly cut. They touch the same module, contract, or migration, so one unit's discovery changes what another should do. Fire-and-forget workers cannot exchange that mid-flight; teammates can, because the lead relays it.
  2. Running them at the same time actually finishes sooner. The units are each substantial and none is merely waiting on another's output. Two units where the second only consumes the first's result are a sequence, not a team.

When the units are genuinely independent — separate files, no shared contract — spawn parallel background task workers instead and avoid the team coordination overhead entirely. When the work is one cohesive unit, do it yourself. Overlap alone is not enough: near-identical units that would collide on the same lines are faster done in sequence by one worker.

Under team mode, isolate and land per unit:

  • One git worktree per member, never a shared checkout — concurrent members editing one working tree corrupt each other's diffs and evidence. Give each member its own branch off the base and its own worktree path.
  • Merge per work unit, as each unit is verified. A member's unit lands when its own evidence is captured and its gates are green; it does not wait for the slowest sibling. Integrate each merged unit back into the base the others branch from, so overlapping members rebase onto real merged work rather than guessing at it.
  • Conflicts are the lead's job. When two members' units touch the same lines, the lead decides the order they land and tells the later member what changed; members never resolve a sibling's conflict blind.

Native Senpi Task Contract

Senpi already exposes its real subagent spawn surface through the omo-senpi task component. Use it directly. Do not route delegation through external app-server threads or another harness.

Intent Native Senpi tool
Spawn one worker task({ prompt, subagent_type | category, run_in_background: true })
Fan out independent workers task({ tasks: [{ prompt, subagent_type | category }, ...], run_in_background: true })
Send context or correction task_send({ task_id, message })
Inspect one midpoint task_output({ task_id, mode: "tail" })
Stop a runaway worker task_cancel({ task_id })
Coordinate overlapping work team_create, task_create, task_get, task_list, task_update; communicate with task_send

Every worker prompt starts with TASK: and names DELIVERABLE, SCOPE, VERIFY, and STOP WHEN. Put requested skill names and all required context inside prompt; children do not inherit interview context automatically.

Driver goal lifecycle

The session goal you create with create_goal is a DRIVER the loop instructs, never a gate. A checkpoint accepts an optional driver snapshot, records it verbatim, and never rejects on its status or objective; the advice comes back in nextActions. The snapshot is filled from this session's goal store automatically, so pass codexGoal only to override it. If the driver was completed early, the advice tells you to create_goal again with the plan's objective verbatim - a completed goal is replaced, not reused. If the driver is paused or usage/budget limited, the advice tells you to resume it. A different objective is a warning, not a refusal, and it is reported once: the first checkpoint under that driver records the objective in the plan (acknowledgedDriverObjectives) and later calls stay quiet; status().result.driver shows the relation at any time. create_goal is advised only when the goal store really holds no goal.

Files (oh-my-openagent)
  • references
    • define-goal.md 8.9 KB
      # Define Goal
      
      How to turn a brief into a registered goal the run can be held to. Read this BEFORE calling `create_goal`: the objective you register is the binding contract for the whole run, and the run's quality is capped by the quality of this objective.
      
      A goal is a prompt to the agent that executes it, including future-you after compaction. It earns its tokens the way any prompt does: it carries only what the run cannot re-derive later, the outcome, the proof, the bounds, and the stop state. Everything else is noise that steals attention from the parts that decide completion.
      
      ## The quality bar
      
      Before registering, the objective must answer all five:
      
      1. What concrete thing will be TRUE when this is done? An outcome, never an activity.
      2. What evidence will prove it? Commands, validators, artifacts someone can open.
      3. What quantitative or binary threshold defines success?
      4. What scope boundaries matter? What is in, and what is explicitly out.
      5. What should make the agent stop and ask instead of grinding?
      
      An objective that cannot answer one of these is not ready. Repair it (below) before calling the tool.
      
      ## Objective anatomy
      
      Write the objective outcome-first, in this order:
      
      1. **Outcome**: one sentence stating what will be true, naming the artifact, system, repo, or user-facing behavior involved.
      2. **Deliverables**: the named surfaces the work lands on (files, endpoints, packages, environments). Use literal paths and names: the executing agent interprets the objective literally and will not infer surfaces you did not name.
      3. **Success criteria**: sized by tier (below), each one a binary observable with its scenario and evidence named upfront.
      4. **Constraints and scope bounds**: Record the user's stated constraints verbatim, including what is explicitly out of scope wherever ambiguity would let the run expand. Where the user was silent on a bound the work forks on, SET it yourself: derive the clearest defensible bound from repo evidence and best practice (stack already in use, compatibility surfaces, scale the code must serve, audience or compliance the repo implies) and record it inside the objective as `assumed: <constraint> — <rationale>, <reversible?>`, binding until the user vetoes it. Unstated bounds do not exist — which is why you write them.
      5. **WHEN TO STOP**: one line, "I'll stop right away when <the exact observable state that ends this run>". This line is binding: the moment it holds, the run delivers and stops. Work past it is a defect, not diligence.
      
      State the motivation when it changes execution ("p95 matters because the checkout SLA is 300ms") and omit it when it does not. Positive statements beat prohibitions: "verify against staging" carries more signal than "do not touch production".
      
      ## Success criteria construction
      
      Count by tier, mirroring the run's tier triage:
      
      - LIGHT (known pattern, no open design decisions): 1-2 criteria, happy path plus the riskiest edge.
      - HEAVY (new module or abstraction, auth or security, external integration, schema or migration, concurrency, cross-domain refactor, or the user demanded care): 3+ criteria covering happy path, edge (boundary, empty, malformed, concurrent), adjacent-surface regression named by file and function, and the adversarial risk the change actually creates.
      
      Every criterion carries, at definition time, not after the work:
      
      - a binary pass condition ("returns 200 and the body matches the schema", never "works correctly");
      - the exact scenario: the literal command, request, page action, or payload that will prove it;
      - the evidence artifact it will capture: transcript, status plus body, screenshot path, diff, parsed dump.
      
      A criterion that cannot fail is not a criterion. If no input could make the scenario fail, it measures nothing; rewrite it until failure is possible.
      
      ## Make it quantitative
      
      Prefer numbers that represent real success over decorative precision. A threshold nobody would act on differently is noise.
      
      | Domain | Quantify as |
      | --- | --- |
      | Bug fix | reproduction first, fix second: the failing case captured before, the same case passing after |
      | Tests | the exact command and required pass condition, plus run count for flake-sensitive suites |
      | Performance | metric, target threshold, measurement method, and run count ("p95 under 250ms across 3 consecutive local runs") |
      | Quality work | the observable acceptance bar: lint, typecheck, and test pass; reviewed examples; a user-approved artifact |
      | Research | the decision the research must enable, the sources or systems in scope, and the evidence standard per claim |
      | Operations | healthy state, monitoring window, failure threshold, and the rollback or escalation trigger |
      
      ## Repair weak goals
      
      Reject pure activity objectives: "make progress", "keep investigating", "improve things", "work on X". They cannot fail, so they cannot finish.
      
      Rewrite vague goals into measurable ones when local context makes the rewrite safe. Ask ONE narrow question only when the missing detail is an OWNER-DECISION — irreversible, destructive, safety-critical, or a cross-cutting product choice (real budget or spend, public surface, external dependency, data shape, target audience) — that changes the intended outcome or its validation, shaped around the missing validator or bound:
      
      - "What metric defines success here: latency, cost, accuracy, or user-visible behavior?"
      - "Which environment do I verify against: local, staging, or production?"
      - "What is the minimum evidence you want before this goal is marked complete?"
      
      Every other missing constraint follows Objective anatomy #4: adopt the clearest defensible default, state it in the objective as `assumed:`, and let the user veto.
      
      When the user cannot provide a metric, propose the most honest binary validator available and proceed with it stated in the objective.
      
      Weak: "Make checkout faster."
      Repaired: "Reduce checkout API p95 below 250ms on the documented slow path with the smallest safe server-side change; prove it with `npm run test:checkout` green plus the local latency benchmark showing p95 under 250ms across 3 consecutive runs; out of scope: client-side changes and new caching layers."
      
      Weak: "Keep investigating the PR comments."
      Repaired: "Resolve every open change-requesting review comment on PR 123 touching only the affected auth files and their tests; prove it with the targeted auth test command green plus `gh pr view 123` showing zero unresolved change-request threads."
      
      ## Registration protocol
      
      1. Call `get_goal` first, then act by state:
      
      | get_goal shows | Action |
      | --- | --- |
      | no active goal | Register with `create_goal`, passing exactly `objective`. Never include lifecycle fields such as `status`; never register a goal in prose, a notepad, or a plan instead of the tool. |
      | an active goal matching this intent | Continue it. Never register a duplicate. |
      | an active goal conflicting with this intent | Stop and surface the conflict; the user decides whether to finish it, complete it, or branch. |
      
      2. Goals are unlimited. Never invent a numeric budget, token limit, or deadline the user did not state — that ban covers run quotas; the `assumed:` work constraints from Objective anatomy #4 are different and required.
      3. In a ulw-loop run, the loop CLI owns per-goal state (`.omo/ulw-loop/goals.json`): `create_goal` registers the aggregate objective from the printed handoff, and this reference shapes both that objective and every goal's `successCriteria` at `create-goals` time.
      
      ## Completion honesty
      
      - Report `update_goal` complete only after auditing every criterion against evidence captured in this run. A green suite is supporting evidence, never completion proof by itself.
      - Waiting is not blocked: while a monitor, background child, or scheduled continuation can wake the run, end the turn and let it fire. Blocked requires a true impasse: no live resumption channel, and the same block recurring across consecutive turns.
      - The moment the WHEN TO STOP line holds with evidence in hand, deliver and stop.
      
      ## Anti-patterns
      
      | Anti-pattern | Why it fails | Instead |
      | --- | --- | --- |
      | Activity objective ("investigate X") | Cannot fail, so cannot finish; the run wanders | Name the outcome the activity must produce and its evidence |
      | Criteria added after implementation | The contract bent to fit the work; nothing was proven | Write criteria and scenarios at registration, before any edit |
      | Decorative precision ("99.97% uptime" nobody measures) | A threshold no validator checks is noise wearing a suit | Only thresholds a named validator will actually check |
      | Padded objective (role prose, restated context, filler) | Every extra token competes with the criteria for attention | Outcome, deliverables, criteria, bounds, stop line; nothing else |
      | Goal registered in prose or a notepad | Nothing binds the run; completion becomes a vibe | `create_goal` with the objective, every time the tool exists |
      | Duplicate goal for the same intent | Two contracts, neither authoritative | Continue the active goal or surface the conflict |
      
    • full-workflow.md 30.4 KB
      ## Role
      Expert goal orchestration agent. You conduct; right-sized subagents play. Plan durable multi-goal work, fan independent work out, QA every result yourself, record only proven evidence.
      Use GPT-5.x style: outcome-first, evidence-bound, atomic decisions, no nested branching prose.
      
      ## Goal
      Deliver every goal in `.omo/ulw-loop/goals.json` end-to-end.
      Prove EVERY success criterion with captured observable evidence from a real-usage scenario you ran (HTTP / tmux / browser / computer-use below).
      TESTS ALONE NEVER PROVE DONE. A green test suite is supporting evidence, not completion proof.
      Audit each pass, fail, block, steering change, and checkpoint in `.omo/ulw-loop/<session-id>/ledger.jsonl`.
      
      ## Manual-QA channels
      Run each criterion's real-surface proof yourself through the channel that faithfully exercises it; capture the artifact before recording PASS.
      
      1. **HTTP call** — hit the live endpoint with `curl -i` (or an HTTP client from js eval); capture status line + headers + body.
      2. **Terminal / TUI** - prove it through the xterm.js web terminal; tmux `send-keys` is fine for a boot smoke, but NEVER `tmux capture-pane` for color/layout/CJK evidence (it degrades truecolor).
      3. **Browser use** — omowright from js eval (staged in the `browser` skill): the owned engine (`connectPipe` on a task-owned profile, `connectCloakProfile` for bot-scored targets) for unauthenticated pages, the attached engine (`connectBrowserSkill()` in the user's signed-in browser) when the page needs their login — never a clone of, or a launch against, the live profile. Capture action log + screenshot path. Never downgrade a browser-facing criterion, and never launch a headless browser because the attached one is missing.
      4. **Computer use** — for desktop/GUI apps, drive the running app via OS automation (computer-use, AppleScript, xdotool, etc.); capture action log + screenshot.
      
      For TUI visual QA (mandatory when a PR or review must inspect the terminal screen),
      run `bun script/qa/web-terminal-visual-qa.mjs --command "<cmd>" --input "{Enter}"
      --evidence-dir <dir>` (live pty + xterm.js in Chrome; `--from-file` replays a raw
      stream) and record `terminal.png`, `terminal.txt`, and `metadata.json`.
      
      Auxiliary surfaces (CLI stdout / DB state diff / parsed config dump) are first-class evidence for CLI- or data-shaped criteria; use a channel scenario when the behavior is user-facing. `--dry-run`, printing the command, "should respond", and "looks correct" never count.
      
      ## Delegation model (CONDUCTOR-STYLE — YOU CONDUCT, WORKERS PLAY)
      
      Size each worker to the task. Put the intended role, rigor level, and specialty inside the worker `prompt`.
      
      | Task shape | Message instruction |
      |---|---|
      | Trivial / mechanical (rename, move, obvious one-liner, config edit) | `TASK: act as a focused worker for a trivial mechanical edit. ...` |
      | Pure implementation against a clear spec (new function, endpoint, test from a named pattern) | `TASK: act as a high-rigor implementation worker. ...` |
      | Deep debugging / race / perf / subtle cross-module reasoning | `TASK: act as a deep debugging worker. ...` |
      | QA execution (drive a channel, capture evidence) | `TASK: act as a QA execution worker. ...` |
      | Read-only codebase search | `TASK: act as an explorer. ...` |
      | Implementation — pick the tier by change SIZE: LOW small (one-file fix, boilerplate) / MEDIUM mid-sized (standard feature, a few files) / HIGH large (new module, cross-module, concurrency/security/migration, or a big complex problem with one clear goal) | `TASK: act as a <low|medium|high>-difficulty implementation worker. ...` + the matching configured `subagent_type` or `category` |
      | External library / docs research | `TASK: act as a librarian. ...` |
      | Final verification audit | `TASK: act as a rigorous final verification reviewer. ...` |
      
      For reviewer work, use a self-contained reviewer assignment, tight scope, and explicit verification in `prompt`. Never spawn a context-only child for review.
      
      Difficulty is orthogonal to LIGHT/HEAVY rigor. Select a configured `subagent_type` or `category`, and state the intended tier and specialty inside `prompt`.
      
      Every worker prompt MUST carry: goal + exact files in scope; the PIN + failing-first proof before production code; constraints + project rules; verification commands; the ONE Manual-QA channel and exact artifact; for git-tracked edits, require `git-master` plus repo and touched-path commit history before commit. Workers have NO interview context — be exhaustive, and forward learnings.
      
      omo-senpi subagent reliability:
      - Senpi's native spawn surface is the `task` tool. Use `task({ prompt, subagent_type | category, run_in_background: true })` for one worker or `task({ tasks: [...], run_in_background: true })` for a parallel batch. Never substitute external app-server threads or another harness.
      - Paste only the context the child needs into `prompt`; full parent history is not inherited automatically.
      
      ## Artifacts
      - `.omo/ulw-loop/brief.md`: original brief and durable constraints.
      - `.omo/ulw-loop/goals.json`: goals with embedded `successCriteria` per goal.
      - `.omo/ulw-loop/ledger.jsonl`: append-only audit trail.
      - Read artifacts before resuming, steering, or checkpointing.
      - After compaction or context loss, re-read brief + goals + ledger FIRST, then `agentToolkit.status()` (re-import the SDK first if the kernel restarted). Recover from artifacts; never re-plan from scratch or repeat completed work.
      - Never invent state outside `.omo/ulw-loop` artifacts or `agentToolkit.status()`.
      
      ## Bootstrap
      Do all three steps before execution. No edits, goal tools, or checkpointing before bootstrap completes.
      
      ### 1. Create goals from the brief
      Every ulw-loop operation is a method call on the SDK the extension publishes at `OMO_AGENT_TOOLKIT_SDK_ROOT`, run inside a JS eval cell. Import it once per kernel lifetime; later cells reuse the binding, and only a kernel restart (or a `ReferenceError: agentToolkit is not defined`) calls for a re-import. From a py, rb, or jl cell, run a separate eval with language `js`. If `env("OMO_AGENT_TOOLKIT_SDK_ROOT")` is undefined, the omo-senpi extension is not active: record that in the notepad and surface the installer issue instead of probing for a CLI.
      
      ```js
      const { agentToolkit } = await import(`${env("OMO_AGENT_TOOLKIT_SDK_ROOT")}/sdk.js`)
      print(await agentToolkit.status())
      ```
      
      Run one form:
      ```js
      print(await agentToolkit.createGoals({ brief: "<brief text>" }))
      print(await agentToolkit.createGoals({ brief: "<brief text>", validationBatchesJson: "<json-or-path>" }))
      ```
      Every call resolves to an envelope and never throws: `{ ok: true, operation, result, nextActions, warnings? }` on success, `{ ok: false, operation, error: { code, message } }` on failure. Branch on `error.code`. The SDK binds this session from the host env (`PI_SESSION_ID`, `PI_SESSION_CWD`) on every call, so never pass a session id or a plan path; a host that cannot prove the session answers `ULW_LOOP_SESSION_ID_REQUIRED` instead of touching the shared `.omo/ulw-loop` root. State lives under `.omo/ulw-loop/<session-id>/`. Mutations are serialized across processes by `.omo/ulw-loop/<id>/.state.lock`, so parallel `recordEvidence` calls from several workers are safe; `ULW_LOOP_LOCK_TIMEOUT` means another live process held the state for more than 10s. Retry, and never delete the lock while that process is alive.
      If `createGoals` answers `ULW_LOOP_PLAN_EXISTS_COMPLETE`, this session's aggregate is already complete: do not steer or force the completed state for unrelated new work. Start that work in a fresh session, since automatic continuation follows the session's own id. Pass `force: true` only when deliberately overwriting completed evidence.
      Write state through the SDK. Do not hand-edit state files.
      
      ### 2. Refine success criteria + a plan-quality QA and parallelism plan per goal
      Shape every goal's objective and `successCriteria` by `references/define-goal.md`: its quality bar, objective anatomy, and criterion construction govern this step. Where the brief is silent on a constraint the work forks on, derive the default per that reference, record it via `annotate_ledger` (`evidence` naming the repo fact, `rationale` the default plus reversibility), and surface the assumed list in the first user-visible report so a wrong default is a one-line veto, not a finished run.
      Gather context BEFORE planning with parallel `explorer` / `librarian` workers plus your own read-only tools.
      First survey available skills: read every loosely-relevant skill's description, deliberately choose which this work uses, and prefer applying genuinely-relevant skills over working raw.
      Then run tier triage per goal — rigor (LIGHT/HEAVY below) and shape (`delivery` default, or `research` when the deliverable is a cited answer, not an artifact) — and record both in an `annotate_ledger` steering entry. Default is LIGHT — a narrow change inside existing layers. Take HEAVY only on a fact you can point to: a new module / abstraction / domain model; auth, security, or session; an external integration; a DB schema or migration; concurrency, transaction boundaries, or cache invalidation; a cross-domain refactor; or the user signaled care or demanded review. When unsure, take HEAVY; upgrade the moment a HEAVY fact surfaces, never downgrade mid-run.
      Planning depends on unresolved design uncertainty, not the rigor tier: after discovery, spawn the `plan` agent only when unclear boundaries, competing decompositions, or uncertain dependency ordering remain; otherwise plan directly, including for HEAVY goals with a known procedure. HEAVY goals carry 3+ successCriteria covering happy path, edge, regression, and adversarial risk. LIGHT goals carry 1-2 successCriteria (happy path + the riskiest edge) with one real-surface proof of the deliverable.
      Research-shape goals change the cycle: BEFORE each investigation, read this goal's prior ledger findings and open hypotheses, then extend them — never re-investigate an answered question (the ledger is your research notebook). Record findings via `annotate_ledger` with their source (`file:line`, command output, doc URL) as `evidence`. Track hypotheses as `HYPOTHESIS[id]: <claim> | status: open`, flipped to `confirmed`/`refuted` only on an observed source. A research criterion passes on a cited answer — skip QA-channel, cleanup, and commit, but keep source-observability (never "looks correct"). Keep hypotheses inside the user's stated question; a scope-widening one is an `add_subgoal` proposal you surface, never silent creep. For a `research`-shape goal you MAY load `ulw-research` without hesitation — otherwise explicit-request-only, a research-shape goal IS that explicit demand. Research-only: never for a `delivery` goal. It composes with the librarian routing above — `ulw-research` for saturation (many parallel sources, recursive expansion), a single `librarian` for one lookup.
      For each criterion, define upfront: `id`, exact `scenario` (tool + inputs + binary pass/fail), `expectedEvidence` artifact path, adversarial classes, stop condition, and Manual-QA channel. Vague QA ("verify it works") is a rejected criterion — revise it before execution. Every goal also declares, in one line, WHEN TO STOP: "stop right away when <the exact observable state that ends this goal>". A goal without that line is rejected — revise it before execution; the Stop Rules bind to it.
      For optimization work, capture baseline speed before changes plus behavior/regression proof. Every attempt records speed, behavior/regression, and the keep/revert/iterate decision.
      A criterion's adversarial classes are the ultraqa classes a fact about the change triggers: malformed input, prompt injection, cancel/resume, stale state, dirty worktree, hung or long commands, flaky tests, misleading success output, repeated interruptions. Record untriggered classes as not-applicable in one line.
      Use channel-table evidence verbs — not vibes.
      
      **Plan for maximum parallelism (HEAVY goals).** Decompose each goal's criteria into atomic tasks (Implementation + its Test = ONE task, never split) and group them into dependency waves. Target 5–8 tasks per wave; <3 per wave (except the final wave) means under-splitting — extract shared prerequisites into Wave 1. For each task record its wave, what it blocks, what blocks it, the worker tier from the Delegation table, and its QA scenario + evidence path. Build a dependency matrix (Task | Depends on | Blocks | Can parallelize with) and name the critical path. Anything not on a real dependency edge MUST share a wave and dispatch together.
      Revise any criterion that lacks observable `expectedEvidence` or a named channel before execution.
      
      ### 3. Inspect state
      Run `print(await agentToolkit.status())`.
      Read pending goals, criteria IDs, current ledger head, blockers, and aggregate omo-senpi objective.
      
      ## Execution Loop
      Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures at 3.
      
      ### Acquire Next Goal
      1. Run `print(await agentToolkit.completeGoals())` and read the handoff, including criteria. It acquires the next eligible pending goal, or resumes the goal already in progress; call it after every complete checkpoint and on every resume.
      2. Call `get_goal` and inspect active omo-senpi state.
      3. Apply this table exactly:
      
      | get_goal result | action |
      |-----------------|--------|
      | no active goal | You MUST call `create_goal` — goal registration goes through the tool, never prose — with objective only from `instruction.json.objective`; do not copy lifecycle fields such as `status`. |
      | same aggregate objective active | Continue the current ulw-loop story. |
      | different goal active | STOP. Checkpoint blocked and surface the conflict. |
      4. If retrying failed work, run `print(await agentToolkit.completeGoals({ retryFailed: true }))`.
      5. Never create a second omo-senpi goal for the same aggregate objective.
      
      ### Per-Criterion Cycle
      1. PLAN: read `criterion.scenario`, `criterion.expectedEvidence`, prior ledger entries, and safety bounds. Identify which tasks in the current wave are independent — write scopes disjoint, no two workers editing the same files; units whose edits overlap wait for a later wave or run under team mode with per-member worktrees.
      2. Register atomic todos via the `todo` tool — one ultra-granular step per action, `path: <action> for <criterion> - verify by <check>`. Call `todo` on every transition (start → `in_progress`, finish → `completed`); exactly one `in_progress`, mark completed immediately, never batch, never let the rendered plan lag behind reality.
      3. DISPATCH-ONE-PER-WAVE: use one native dispatch for the wave: `task({ tasks })` when its units are independent, or ONE `workflow` run when its lanes carry ordering (implementation nodes plus a verification node; recover with `retry`, `amend`, or `send`, never a second graph for the same wave). Each prompt starts with `TASK:` and names `DELIVERABLE`, `SCOPE`, `VERIFY`, and `STOP WHEN`. Keep doing independent root work while children run; consume injected progress/completion and use `task_send`, `task_output`, or `task_cancel` only as defined by the native task contract.
      4. INTEGRATE + CRITICAL SELF-QA + GIT CHECKPOINT (EVERY WORKER RETURN): do NOT trust the worker's report. Read the diff yourself, re-run its tests, and run LSP diagnostics on the changed files. Treat "done" as a claim to disprove. If the diff drifts, the test is hollow, or evidence is missing, RESPAWN the worker with the specific failure context. Once the work unit is verified, use `git-master` before staging: inspect recent repository commits and touched-path history to infer commit language, Conventional Commit scope, message shape, and unit size. Stage only that unit's files and commit in the observed style; do not carry verified work forward into a later omnibus commit. If no git-tracked files changed or committing is unsafe, record the no-commit reason as evidence. Forward every finding/learning to subsequent workers.
      5. EXECUTE-AS-SCENARIO: ACTUALLY run the Manual-QA scenario the criterion named (channel table above). Run it yourself for the orchestrator check; for heavier flows dispatch a dedicated QA execution worker (category `unspecified-low` by default; `unspecified-high` when the QA flow itself is hard) whose ONLY job is to drive the channel and write the artifact to the named evidence path. If the scenario FAILS, respawn the implementing worker with the captured failure — do not hand-patch around it.
      6. CAPTURE: collect the observable artifact path: transcript, stdout, screenshot, assertion, status+body, diff, or parsed dump. No artifact written at the evidence path — not done; record BLOCKED and respawn QA.
      7. CLEAN (PAIRED, NEVER SKIP): tear down every runtime artifact step 5 spawned BEFORE recording — server PIDs (`kill`, verify `kill -0` fails), `tmux` sessions (`tmux kill-session -t ulw-qa-<criterion>`; confirm `tmux ls`), browser / Playwright contexts (`.close()`), containers (`docker rm -f`), bound ports (`lsof -i :<port>` empty), temp sockets / files / dirs (`rm -rf` the `mktemp` paths), QA-only env vars, AND cancel any runaway child with `task_cancel` while allowing completed children to end normally. Register each teardown as its own todo the moment the QA spawns the resource (scripts, tmux assets, browser contexts, PIDs, ports) so none is forgotten. Embed a one-line cleanup receipt in the evidence string, e.g. `cleanup: killed 12345; tmux kill-session ulw-qa-foo; rm -rf /tmp/ulw.aB12cD; task_cancel <runaway-id>`. Missing receipt → record BLOCKED, not PASS.
      8. RECORD one result immediately from the artifact you just wrote — never from memory or a later turn — stamping the capture tree `$(git rev-parse --short "HEAD^{tree}")` into the evidence:
         - PASS: `agentToolkit.recordEvidence({ goalId, criterionId, status: "pass", evidence })`
         - FAIL: `agentToolkit.recordEvidence({ goalId, criterionId, status: "fail", evidence, notes })`
         - BLOCKED: `agentToolkit.recordEvidence({ goalId, criterionId, status: "blocked", evidence, notes })`
      9. If actual does not match expected, diagnose, respawn the right-sized worker with the failure context to fix at the root cause, and rerun the SAME criterion (including a fresh cleanup).
      10. After 3 same-criterion failures, exit the goal with diagnosis.
      11. After 5 cycles on one goal without required criteria passing, checkpoint failed.
      12. Continue only when the next pending criterion has a concrete `expectedEvidence` target.
      
      ### Goal Completion
      1. Non-final aggregate goal: confirm every `essential` criterion is `pass`; non-essential criteria may remain pending. Final aggregate goal: confirm every criterion across the whole plan is `pass`.
      2. Call `get_goal` for a fresh snapshot.
      3. Confirm the goal's worktree has landed on the integration base per the repository's flow, then run `agentToolkit.checkpoint({ goalId, status: "complete", evidence })`. The driver snapshot is filled from this session's goal store automatically; pass `codexGoalJson` only to override it. Read the envelope's `nextActions`, then acquire the next goal with `agentToolkit.completeGoals()`.
      4. If blocked or failed, checkpoint with `status: "blocked"` or `status: "failed"` and include diagnosis evidence.
      5. If this is the final goal, run the final quality gate first and pass `qualityGateJson`.
      
      ## Exact final-story sequence
      For the final story, follow this exact checkpoint sequence:
      
      ```js
      // Same kernel as the import above; re-import only after a kernel restart.
      print(await agentToolkit.status())
      // Read nextActions and currentAttemptDir.
      print(await agentToolkit.recordEvidence({ goalId: "<g>", criterionId: "<c>", status: "pass", evidence: "..." }))
      // Repeat recordEvidence once per criterion.
      // Then use the harness update_goal tool with status complete.
      print(await agentToolkit.checkpoint({ printTemplate: true, goalId: "<g>" }))
      // Fill the printed template: replace every placeholder and use real artifact paths under currentAttemptDir.
      print(await agentToolkit.checkpoint({ goalId: "<g>", status: "complete", evidence: "...", qualityGateJson: "<json-or-path>" }))
      print(await agentToolkit.completeGoals())
      ```
      
      The omo-senpi gate uses the four sections shown in the sample below; it intentionally has no `codeReview` section.
      
      ## Final Quality Gate
      Trigger only for the final aggregate goal after every criterion in every goal is `pass`.
      1. Run targeted verification for changed behavior.
      2. FREEZE first — no more edits or rebases. At the frozen HEAD, re-run Manual-QA for any PASS criterion whose stamped tree differs from `git rev-parse --short "HEAD^{tree}"`, so every criterion is proven on the frozen tree; each artifact exists and is non-empty.
      3a. Run manual QA YOURSELF through the appropriate real surface. Write the QA matrix and every captured artifact under the current attempt directory. Set `manualQa.by` to the exact literal `main-session`.
      3b. Spawn ONE gate reviewer with `task({ category: "deep-high", run_in_background: true })`, passing the brief, goals, diff, evidence, and QA artifact paths. If the task returns `model_unavailable`, retry with `category: "deep-low"`, then `category: "unspecified-high"`, then `category: "unspecified-low"`; never mention the attempted chain in the gate. Set `gateReview.by` to the exact category literal used for the successful reviewer.
      3c. On omo-senpi the ledger has TWO lanes only: hands-on QA and goal/gate verification. The gate approval binds to the frozen tree and full commit SHA. Record one durable ledger entry per lane with its lane name, SHA, verdict, and report artifact/source. A later fix restarts the freeze and requires fresh evidence and gate review.
      4. Treat timeout, missing deliverable, ack-only, `BLOCKED:`, or inconclusive review as a blocker. Any fix restarts the freeze at the new HEAD: re-run only the proofs it invalidated and stamp the fresh output; never relabel stale output to HEAD. Re-review the delta at most twice, then record-review-blockers and surface to the user.
      5. If review remains blocked, run `agentToolkit.recordReviewBlockers({ goalId, title, objective, evidence })`; it blocks the final goal and appends a blocker goal in one mutation.
      6. If clean, checkpoint final completion:
      ```js
      print(await agentToolkit.checkpoint({ goalId: "<id>", status: "complete", evidence: "<e2e evidence + manual QA notes>", qualityGateJson: "<json-or-path>" }))
      ```
      `qualityGateJson` shape. In `manualQa.artifactRefs`, `kind` must be one of `cli-transcript`, `log`, `screenshot`, `image`, `http-dump`, or `data-diff`; review and QA reports belong in `codeReview.reportPath` or `gateReview.reportPath`, not `artifactRefs`. `surfaceEvidence.surface` must be one of `cli`, `http`, `tmux`, `browser`, `gui`, or `data`. Compatibility is `cli`/`tmux` -> `cli-transcript`/`log`, `http` -> `http-dump`, `browser`/`gui` -> `screenshot`/`image`, and `data` -> `data-diff`.
      
      `qualityGateJson` shape:
      ```json
      {
        "manualQa":{"by":"main-session","status":"passed","evidence":"Ran CLI and data QA myself.","surfaceEvidence":[{"id":"surface-cli-pass","criterionRef":"C1","surface":"cli","invocation":"agentToolkit.checkpoint({ goalId: \"G001\", status: \"complete\", evidence: \"...\", qualityGateJson: \"sample-quality-gate.json\" })","verdict":"passed","artifactRefs":["artifact-cli-pass"]},{"id":"surface-data-pass","criterionRef":"C2","surface":"data","invocation":"diff -u before-ledger.json after-ledger.json","verdict":"passed","artifactRefs":["artifact-data-pass"]}],"adversarialCases":[{"id":"adv-malformed-input","criterionRef":"C3","scenario":"malformed gate input omits manual QA evidence","expectedBehavior":"validator rejects ULW_LOOP_QUALITY_GATE_INVALID","verdict":"passed","artifactRefs":["artifact-cli-reject"]}],"artifactRefs":[{"id":"artifact-cli-pass","kind":"cli-transcript","description":"CLI pass artifact.","path":"test/fixtures/artifacts/cli-pass.txt"},{"id":"artifact-cli-reject","kind":"log","description":"Reject log artifact.","path":"test/fixtures/artifacts/rejection.txt"},{"id":"artifact-data-pass","kind":"data-diff","description":"Data diff artifact.","path":"test/fixtures/artifacts/data-diff.txt"}]},
        "gateReview":{"by":"category:deep-high","recommendation":"APPROVE","reportPath":"test/fixtures/artifacts/gate-review.md","evidence":"Verified the goal and gate evidence.","blockers":[]},
        "iteration":{"fullRerun":true,"status":"passed","rerunCommands":["bunx vitest run test/quality-gate-doc.test.ts"],"evidence":"Focused rerun passed."},
        "criteriaCoverage":{"totalCriteria":3,"passCount":3,"originalIntent":"User wanted artifact-backed completion.","desiredOutcome":"Behavior ships with hands-on QA and goal/gate verification.","userOutcomeReview":"The artifacts show the requested behavior from the user's perspective.","adversarialClassesCovered":["malformed_input","stale_state"]}
      }
      ```
      
      Artifacts must be non-empty; counts alone fail. LIGHT without adversarial class records `"adversarialClassesCovered": ["none-applicable: <reason>"]`; untriggered adversarialCases may use verdict `not_applicable` + `reason`; WATCH passes, notes surfaced.
      
      ## Dynamic Steering
      Use steering only for structured evidence-backed mutation. Reject natural-language steering requests.
      
      | Kind | When to use | Required fields |
      |------|-------------|-----------------|
      | add_subgoal | Any defect met mid-run, pre-existing included, or a real blocker; it becomes a story fixed to the ideal state, never a follow-up note. | `title`, `objective`, `evidence`, `rationale` |
      | split_subgoal | Story too large; needs decomposition | `targetGoalId`, `childGoals` (array of `{ title, objective }`), `evidence`, `rationale` |
      | reorder_pending | Discovered dependency order | `pendingOrder` (array of ids), `evidence`, `rationale` |
      | revise_pending_wording | Title/objective ambiguous | `targetGoalId`, `revisedTitle?`, `revisedObjective?`, `evidence`, `rationale` |
      | revise_criterion | Criterion lacks observable PASS evidence (placeholder criteria name this call) | `goalId`, `criterionId`, at least one of `scenario`, `expectedEvidence`, `userModel`, plus `evidence`, `rationale` |
      | annotate_ledger | Audit-only note | `evidence`, `rationale` |
      | mark_blocked_superseded | Old story replaced by new evidence | `targetGoalId`, `childGoals?` (replacements), `evidence`, `rationale` |
      
      `goalId` is accepted everywhere `targetGoalId` is. Revising a seeded criterion: `agentToolkit.steer({ kind: "revise_criterion", source: "finding", goalId: "G002", criterionId: "C001", scenario: "curl -i /health returns 200", expectedEvidence: "status line captured in health.log", evidence: "<what was observed>", rationale: "<why this proof>" })`. A goal you add yourself needs no revise pass at all: `agentToolkit.addGoal({ title, objective, successCriteria: [{ scenario, expectedEvidence, userModel?, essential? }] })` defines the criteria in one call.
      
      Call form for the other kinds: `agentToolkit.steer({ kind: "<kind>", source: "finding", ...fields })`, for example `agentToolkit.steer({ kind: "annotate_ledger", source: "finding", evidence: "<what was observed>", rationale: "<what it changes>" })`. Each call applies one proposal atomically: it is accepted whole or rejected with `rejectedReasons` and no partial plan mutation. Discovered several changes together? Issue one `steer` call per proposal, in dependency order.
      
      Validation batches are optional aggregate-mode review boundaries declared at create time with `createGoals({ brief, validationBatchesJson })`. A batch-final member requires all other members resolved, all member criteria pass, and a member-spanning quality gate; split/supersede steering keeps batch membership updated.
      Structured prompt directives accepted: `OMO_ULW_LOOP_STEER: { ... }` and `omo.ulw-loop.steer: {...}` in a prompt, or `agentToolkit.steer({...})` from a cell.
      
      ## Constraints
      1. NEVER call `update_goal` mid-aggregate; only on final story after the quality gate passes.
      2. NEVER call `create_goal` when `get_goal` shows a different active goal.
      3. Evidence is bound to the tree it was captured at; changed tracked content invalidates it — re-run the QA at the current HEAD and re-record (an identical tree after rebase/amend stays valid). NEVER mark PASS from memory, and NEVER relabel, pin, refresh, or regenerate prior output to a moved HEAD.
      4. NEVER bypass the criteria gate: non-final aggregate completion requires all essential criteria; final aggregate completion requires all criteria across the whole plan.
      5. Baseline build/lint/typecheck/test commands are necessary evidence, NOT SUFFICIENT completion proof. Criteria coverage with observable evidence is the gate.
      6. Treat `.omo/ulw-loop/ledger.jsonl` as the durable audit trail; checkpoint after every success or failure.
      7. Per-story omo-senpi goal mode is opt-in only with `createGoals({ brief, codexGoalMode: "per_story" })`; default is aggregate.
      8. Structured steering directives mutate state through validation; normal prose does not.
      9. Evidence MUST be observable from the real surface per the Manual-QA channel table — never a printed command, `--dry-run`, or "looks correct".
      10. Probe the adversarial classes each criterion's trigger facts name (list in Bootstrap step 2); record untriggered classes as not-applicable in one line.
      11. After completing an aggregate ulw-loop run, clear the omo-senpi goal manually with `/goal clear` before starting another in the same session.
      12. The SDK envelope carries a model-facing handoff; only the omo-senpi agent calls `get_goal`, `create_goal`, or `update_goal` tools.
      13. NEVER record PASS while any QA-spawned process, `tmux` session, browser context, bound port, container, temp path, or open worker is still alive; the evidence MUST carry the cleanup receipt. Leftover state = BLOCKED.
      15. Every verified work unit that touched git-tracked files must leave either an atomic `git-master`-style commit hash or explicit no-commit blocker evidence before the next unit starts.
      
      ## Stop Rules
      - STOP GOAL: all goals complete plus every plan criterion `pass` plus final quality gate clean. The decisive test — outranking every other consideration — is whether the completion conditions are FUNDAMENTALLY fulfilled and the user's problem ACTUALLY SOLVED in observable behavior; a `pass` ledger never substitutes for it. The moment both hold, checkpoint, report, and STOP — no extra review cycles, no evidence regeneration, no polish.
      - 3x same criterion failure: checkpoint failed, surface diagnosis.
      - 5 cycles on one goal without required criteria passing: checkpoint failed, surface.
      - Safety boundary such as destructive command, secret exfiltration, or production write: block and surface a safe substitute.
      - omo-senpi `get_goal` reports a different active goal: checkpoint blocker, stop, surface.
      - Leftover state from QA (live process, `tmux` session, browser context, bound port, temp dir): NOT pass. Clean up, append the receipt, then continue.
      - User issues `/cancel`: release in-progress state cleanly and do not auto-resume.
      
  • SKILL.md 12.3 KB
    ---
    name: ulw-loop
    description: "A goal-like loop that decomposes work into systematic, evidence-bound ultrawork steps. Use when the user wants a goal loop or durable, checkpointed execution."
    metadata:
      short-description: Goal-like ultrawork loop for systematic decomposition
    ---
    
    # ulw-loop
    
    Use this skill when the user asks for `ulw-loop`, `ulw`, durable goal execution, evidence-led work, manual QA, or checkpointed long-running delivery.
    
    This skill is compact by design: the run contract below is the whole bootstrap. `references/full-workflow.md` and `references/define-goal.md` carry the full doctrine; open a section only when the phase you are in needs it.
    
    ## Run contract
    
    1. Create goals from a JS eval cell: `agentToolkit.createGoals({ brief })` after the SDK import below. The SDK binds this session from the host env, so never pass a session id or a plan path. If the envelope reports `ULW_LOOP_PLAN_EXISTS_COMPLETE` (this session's aggregate is already complete), unrelated new work needs a fresh session; `createGoals({ brief, force: true })` is only for deliberately overwriting completed evidence.
    2. Register the aggregate objective from the returned handoff with `create_goal`, shaped by `references/define-goal.md`. Goal creation is NEVER skipped.
    3. Mirror every atomic step into the live `todo` checklist: one granular step per action, exactly one in_progress, transitions marked the instant they happen.
    4. Treat each goal as a phase: create its own worktree off the integration base; dispatch its dependency-ordered lanes as ONE `workflow` run (read the mass-ulw skill first; ordering-free lanes stay a `task` batch); verify every criterion with real-surface evidence; land the worktree on the integration base at `agentToolkit.checkpoint({ goalId, status: "complete", evidence })` per the repository's flow (direct merge or merged PR); define the next goal's run from what this one proved. Tests alone never prove done. When a mass-ulw pointer accompanies this skill, this contract still owns goals, criteria, evidence, and checkpoints.
    5. Stop when the goal's WHEN-TO-STOP line holds with evidence in hand.
    
    When the injected ultrawork directive accompanies this skill, its goal/notepad/todo bootstrap is subsumed by this contract: the loop SDK owns goal state and the loop ledger is the notepad. Do not create a second one.
    
    ## The SDK: one import, then method calls
    
    Every ulw-loop operation runs inside a JS eval cell through the SDK the extension publishes at `OMO_AGENT_TOOLKIT_SDK_ROOT`. There is no `omo_agent_toolkit` tool and no CLI to spawn on Senpi.
    
    ```js
    const { agentToolkit } = await import(`${env("OMO_AGENT_TOOLKIT_SDK_ROOT")}/sdk.js`)
    print(await agentToolkit.status())
    ```
    
    Rules that keep it working:
    
    - JS cells only. From a py, rb, or jl cell, run a separate eval with language `js`.
    - Import once per kernel lifetime. `agentToolkit` stays bound in later cells; re-import only after a kernel restart or a `ReferenceError: agentToolkit is not defined`.
    - Every call resolves to an envelope, never a throw: `{ ok: true, operation, result, nextActions, warnings? }` or `{ ok: false, operation, error: { code, message }, warnings? }`. `nextActions` are things to do next; `warnings` are facts to know (a fallback the binder took, a driver objective that differs). Read `nextActions` before deciding the next step, and branch on `error.code`, not on the message text.
    - Never pass a session id or plan path. The SDK binds `PI_SESSION_ID` and `PI_SESSION_CWD` from the host env on each call; state lives under `.omo/ulw-loop/<session-id>/`. When `PI_SESSION_CWD` is missing (seen after an extension reload restarted the kernel), the binder falls back to the cwd recorded in the `PI_SESSION_FILE` header, then to `process.cwd()`, and every envelope carries a warning naming the fix: `env("PI_SESSION_CWD", "<session cwd>")`. `status().result.binding` shows `{ cwd, cwdSource, sessionId, goalStorePaths }`, so check it after any kernel restart and re-pin the env when `cwdSource` is not `PI_SESSION_CWD`.
    - The driver snapshot is filled automatically from this session's goal store. Pass `codexGoalJson` only to override it.
    
    Methods (argument fields are exact):
    
    | Method | Args |
    |---|---|
    | `help()` | none; `result.operations[]` carries `method` (the camelCase name to call), `args` (field -> type, `?` = optional), `description`, `mutating` — enough to recover every call below after a kernel restart |
    | `status()` | none; `result` carries `plan`, `summary`, `nextActions`, `evidenceRoot` (stable plan-level artifact dir), `currentAttemptDir` (moves with the active goal), `binding` (`cwd`, `cwdSource`, `sessionId`, `goalStorePaths`), `driver` (`available`, `status`, `objectiveMatchesPlan`, `objectiveAcknowledged`) |
    | `createGoals(args)` | `{ brief, codexGoalMode?, force?, validationBatchesJson? }` |
    | `completeGoals(args?)` | `{ retryFailed? }`; acquires the next eligible goal or resumes the in-progress one |
    | `criteria(args)` | `{ goalId }` |
    | `recordEvidence(args)` | `{ goalId, criterionId, status: "pass" \| "fail" \| "blocked", evidence, notes?, artifacts? }`; every `artifacts` path must exist (resolved against the session cwd, `ULW_LOOP_EVIDENCE_ARTIFACT_MISSING` otherwise) and is stored on the criterion and the ledger entry, repo-relative when inside the cwd |
    | `checkpoint(args)` | `{ goalId, status: "complete" \| "failed" \| "blocked", evidence, codexGoalJson?, qualityGateJson? }`, or `{ printTemplate: true, goalId? }` for the quality-gate template |
    | `steer(args)` | `{ kind, source: "finding", evidence, rationale, ...kind fields }`; kinds and their fields are in `references/full-workflow.md` |
    | `addGoal(args)` | `{ title, objective, successCriteria? }` with `successCriteria: [{ scenario, expectedEvidence, userModel?, essential? }]`; omit it and the three seeded placeholders name the exact `steer({ kind: "revise_criterion", ... })` call that replaces each one |
    | `recordReviewBlockers(args)` | `{ goalId, title, objective, evidence, codexGoalJson? }` |
    
    ## Non-Negotiables
    
    - Write loop state only through the SDK; it lives under `.omo/ulw-loop/<session-id>/` and is never hand-edited. Mutations are serialized across processes by the session's `.state.lock`, so parallel `recordEvidence` calls from workers are safe.
    - Register goals up front, shaped by `references/define-goal.md` (`agentToolkit.createGoals({ brief })`, then `create_goal` from the returned handoff), and mirror every atomic step into the live `todo` checklist: one ultra-granular step per action, exactly one in_progress, transitions marked the instant they happen.
    - After any compaction or context loss, re-read brief + goals + ledger FIRST plus `agentToolkit.status()` (re-import the SDK if the kernel restarted; `help()` lists every method with its argument fields), confirm `result.binding.cwdSource` is `PI_SESSION_CWD` and re-pin it with `env("PI_SESSION_CWD", result.binding.cwd)` when it is not, then resume; never re-plan from scratch.
    - If `createGoals` answers `ULW_LOOP_PLAN_EXISTS_COMPLETE`, this session's aggregate is already done: start unrelated new work in a fresh session instead of steering or forcing the completed state. Use `force: true` only to intentionally overwrite completed evidence.
    - Every success criterion needs observable evidence from a real surface: a channel (terminal/TUI via the xterm.js web terminal, HTTP, browser, computer-use) or, for CLI- or data-shaped criteria, an auxiliary surface (CLI stdout, DB diff, parsed config dump).
    - Evidence is bound to the tree it was captured at (`git rev-parse --short "HEAD^{tree}"`); it goes stale only when tracked content changes — a rebase or amend that keeps the tree identical keeps it valid. When the tree differs, re-run at the current HEAD and re-record, never relabel or regenerate. Record only after cleanup receipts exist.
    - Delegate code edits, test writes, fixes, and QA execution to right-sized omo-senpi subagents through the native `task` tool or through `workflow` nodes when the phase's lanes carry ordering.
    - Use `git-master` for git-tracked edits: inspect recent and touched-path commit history, then commit each verified work unit atomically in the repository's observed language, scope, and message style with only that unit's files staged. Never carry verified units into a later omnibus commit.
    
    ## Team mode: decide it, do not default to it
    
    Solo execution with parallel background `task` workers is the default: fan independent units out in one batched spawn, each routed to the `category` (or configured `subagent_type`) that fits it, with scopes cut so no two workers write the same files. A team (`team_create`) adds per-member briefing, shared-state, and relay overhead, so it must be paid for by the work's shape. Decide ONCE, when the plan's work units are known, and record the verdict plus its reason in the notepad.
    
    Stand up a team when BOTH hold:
    
    1. **The units' scopes overlap in a way you cannot cleanly cut.** They touch the same module, contract, or migration, so one unit's discovery changes what another should do. Fire-and-forget workers cannot exchange that mid-flight; teammates can, because the lead relays it.
    2. **Running them at the same time actually finishes sooner.** The units are each substantial and none is merely waiting on another's output. Two units where the second only consumes the first's result are a sequence, not a team.
    
    When the units are genuinely independent — separate files, no shared contract — spawn parallel background `task` workers instead and avoid the team coordination overhead entirely. When the work is one cohesive unit, do it yourself. Overlap alone is not enough: near-identical units that would collide on the same lines are faster done in sequence by one worker.
    
    Under team mode, isolate and land per unit:
    
    - **One git worktree per member**, never a shared checkout — concurrent members editing one working tree corrupt each other's diffs and evidence. Give each member its own branch off the base and its own worktree path.
    - **Merge per work unit, as each unit is verified.** A member's unit lands when its own evidence is captured and its gates are green; it does not wait for the slowest sibling. Integrate each merged unit back into the base the others branch from, so overlapping members rebase onto real merged work rather than guessing at it.
    - **Conflicts are the lead's job.** When two members' units touch the same lines, the lead decides the order they land and tells the later member what changed; members never resolve a sibling's conflict blind.
    
    ## Native Senpi Task Contract
    
    Senpi already exposes its real subagent spawn surface through the omo-senpi `task` component. Use it directly. Do not route delegation through external app-server threads or another harness.
    
    | Intent | Native Senpi tool |
    | --- | --- |
    | Spawn one worker | `task({ prompt, subagent_type | category, run_in_background: true })` |
    | Fan out independent workers | `task({ tasks: [{ prompt, subagent_type | category }, ...], run_in_background: true })` |
    | Send context or correction | `task_send({ task_id, message })` |
    | Inspect one midpoint | `task_output({ task_id, mode: "tail" })` |
    | Stop a runaway worker | `task_cancel({ task_id })` |
    | Coordinate overlapping work | `team_create`, `task_create`, `task_get`, `task_list`, `task_update`; communicate with `task_send` |
    
    Every worker prompt starts with `TASK:` and names `DELIVERABLE`, `SCOPE`, `VERIFY`, and `STOP WHEN`. Put requested skill names and all required context inside `prompt`; children do not inherit interview context automatically.
    
    ## Driver goal lifecycle
    
    The session goal you create with `create_goal` is a DRIVER the loop instructs, never a gate. A checkpoint accepts an optional driver snapshot, records it verbatim, and never rejects on its status or objective; the advice comes back in `nextActions`. The snapshot is filled from this session's goal store automatically, so pass `codexGoal` only to override it. If the driver was completed early, the advice tells you to `create_goal` again with the plan's objective verbatim - a completed goal is replaced, not reused. If the driver is paused or usage/budget limited, the advice tells you to resume it. A different objective is a warning, not a refusal, and it is reported once: the first checkpoint under that driver records the objective in the plan (`acknowledgedDriverObjectives`) and later calls stay quiet; `status().result.driver` shows the relation at any time. `create_goal` is advised only when the goal store really holds no goal.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related