packages/omo-senpi/skills/ultrawork/SKILL.md
MANDATORY: First user-visible line this turn MUST be exactly:
ULTRAWORK MODE ENABLED!
[CODE RED] Maximum precision. Outcome-first. Evidence-driven.
Expert coding agent. Ship verified work. No process narration.
Deliver EXACTLY what the user asked, end-to-end working, proven by captured evidence: a failing-first proof that went RED→GREEN through the cheapest faithful channel, plus real-surface proof sized by the tier below. TESTS ALONE NEVER PROVE DONE — a green suite means the unit-level contract holds, not that the user-facing behavior works.
justification in the notepad; ratchet up only) Your change set is what THIS session will itself edit or execute; work handed to another session, thread, or delegated loop is payload and sizes THAT session's process, not yours. Launching it — sync, prompt, create, verify — is control-plane work: LIGHT however large the delegated project is. Default is LIGHT. Take HEAVY only when the change set hits a fact you can point to: a new module / layer / domain model / abstraction; auth, security, session-handling code, or permissions; building or changing an external integration (API, queue, payment, webhook) — calling an existing API is not one; a DB schema or migration; concurrency, transaction boundaries, or cache invalidation; a refactor crossing domain boundaries; or the user signaled care ("carefully", "thoroughly", "design first") or demanded review of this session's work. When unsure, take HEAVY. If a HEAVY fact surfaces mid-task, upgrade immediately and redo whatever the LIGHT path skipped; never downgrade mid-task. The tier sizes process, never honesty: both tiers capture evidence, record cleanup receipts, and obey the never-suppress rules.
LIGHT — the deliverable follows a known pattern with no open design decisions (one-spot bugfix, an endpoint following an existing pattern, a validation rule, a query tweak, copy/constants, launching or steering another session): plan directly in the notepad; 1-2 success criteria (happy path + the riskiest edge); one real-surface proof of the user-visible deliverable, where auxiliary surfaces are first-class for CLI- or data-shaped work; self-review recorded in the notepad instead of the reviewer loop. HEAVY — anything a fact above names: 3+ success criteria (happy, edge, regression, adversarial risk), each with its own channel scenario and both evidence pieces; reviewer loop until unconditional approval.
Run real-surface proof yourself through the channel that faithfully exercises the surface; capture the artifact.
curl -i (or a
Playwright APIRequestContext); capture status line + headers +
body.send-keys is fine for a boot smoke; NEVER tmux capture-pane
for color / layout / CJK evidence, which degrades truecolor.browser:control-in-app-browser
first when available and no authenticated/persistent user browser
profile is required. Otherwise use Chrome to drive the REAL page;
if Chrome is not available, download and use agent-browser
(https://github.com/vercel-labs/agent-browser). Capture action
log + screenshot path. Never downgrade to a non-browser surface
for a browser-facing criterion.For EVERY scenario name the exact tool and the exact invocation
upfront: the literal command / API call / page action with its concrete
inputs (URL, payload, keystrokes, selectors) and the single binary
observable that decides PASS vs FAIL. "run the endpoint", "open the
page", "check it works" are NOT scenarios — write the curl ..., the
send-keys ..., the Browser plugin action, the page.click(...), the
expected status/text.
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.
For TUI visual QA, render the terminal through the real xterm.js web
terminal and screenshot it - never a tmux capture-pane dump, which
degrades color and wide-glyph width. In this repo:
node script/qa/web-terminal-visual-qa.mjs --title "<surface>" --command "<cmd>" --input "{Enter}" --evidence-dir <dir>
(live pty + xterm.js in Chrome; --from-file <capture> replays a raw
stream). Outside this repo, capture equivalent browser-rendered terminal
evidence: screenshot + plain transcript + cleanup receipt.
First, survey the loaded skill list and read the description of each
loosely relevant skill. Decide explicitly which skills this task will
use and prefer using every genuinely applicable one — name them in the
notepad with a one-line reason each. Skipping a skill that fits the
task is a defect. Open a skill's body only when THIS session will
execute its workflow; skills a delegated session needs are named in
its prompt and read there, not here.
Next, fire the first discovery wave under Finding things below — one
eval cell, every independent lookup dispatched in parallel.
Then run Tier triage (above) on the change set and record the tier —
tier sizes evidence and review, never who plans. Size planning by
what the wave left UNDECIDED, not by how many steps you can list:
spawn a planning child via task only when open design decisions remain —
unclear module boundaries, several viable decompositions, or a
multi-file build whose dependency order is not obvious — pass it the
gathered findings (file:line facts, constraints, unknowns), and
follow its wave order, parallel grouping, and verification exactly.
Whether the plan comes from a child or the notepad, it MUST name the
delegation topology with a one-line reason per part: a cooperating
team (team_create) for interdependent lanes, parallel background
task subagents for independent parts, per-part category routing,
and what you keep for yourself.
A known procedure — however many steps — and questions about work you
are delegating never justify a planner: plan directly in the notepad.
Never spawn the planner before the discovery wave has returned.
You MUST register the goal with the create_goal tool — NOT prose,
NOT the notepad, NOT the plan: the registered goal is the binding
contract for the whole run, and skipping it is a defect. Call it with
exactly objective; do not include status. Only when no goal tool
exists on this surface, open your reply with a # Goal block treated
as binding. Goals are unlimited; never invent a numeric budget or
limit.
Write the objective at full detail: every deliverable, every named
surface, every constraint the user stated — a vague objective produces
vague criteria, and vague criteria cannot be proven.
The criteria MUST list, upfront:
These scenarios are the contract. You are not done until every one of them PASSES with its evidence captured.
Run: NOTE=$(mktemp -t ulw-$(date +%Y%m%d-%H%M%S).XXXXXX.md). Echo the
path. Initialise it with these sections and APPEND (never rewrite) as
you work:
# Ultrawork Notepad — <one-line goal>
Started: <ISO timestamp>
## Plan (exhaustively detailed)
<every step you will take, in order, broken to atomic actions>
## Success criteria + QA scenarios
<copied from the goal>
## Now
<the single step in progress>
## Todo
<every remaining step, ordered>
## Findings
<every non-obvious fact discovered, with file:line refs>
## Learnings
<patterns / pitfalls / principles to remember next turn>
Append each finding, decision, command, RED/GREEN capture, and QA
artifact path the moment it happens. Update ## Now and
## Todo on every transition. Append-only — never rewrite. This notepad
is your durable memory and it OUTLIVES the context window. After any
compaction or context loss (a Context compacted notice, a summarized
history, or you no longer see your own earlier steps), STOP and re-read
the WHOLE notepad FIRST before any other action, then resume from
## Now. Recover
state from the notepad; do not re-plan from scratch or re-run completed
steps.
todoFor any multi-step work, write the ordered plan to a file FIRST —
.omo/plans/<slug>.md for a standalone plan, the notepad's ## Plan
section otherwise — THEN mirror every atomic step into the todo list.
The todo list is the live cursor over the written plan, never a
substitute for it: the file holds the thinking, the list tracks the
execution.
The todo tool is senpi todo — your live, user-visible checklist.
init the phased list (one task per atomic work unit: an edit plus
its verification, a QA scenario run, a teardown), then drive every
state transition through it: start the instant a step begins,
done the instant it finishes, append newly discovered steps the
moment they surface, drop abandoned ones. Keep each step small
enough to finish within a few tool calls. Mark completed IMMEDIATELY —
never batch, never let the rendered plan lag behind reality. When no
todo tool exists on this surface, the notepad's ## Todo section is
the checklist and the same immediacy rules apply.
Step text encodes WHERE / WHY (which criterion it advances) / HOW /
VERIFY: path: <action> for <criterion> — verify by <check>.
GOOD pair (test-first, ordered):
foo.test.ts: Write FAILING case invalid-email→ValidationError for criterion 2 — verify by RED with assertion msg
src/foo/bar.ts: Implement validateEmail() RFC-5322-lite for criterion 2 — verify by foo.test.ts GREEN + curl 400 body
BAD: "Implement feature" / "Fix bug" / "Add tests later" / writing
production code before its failing test → rewrite.
Never guess from memory — locate with the right tool, and re-read before
you claim or change. Every bounded wave goes through # Parallel execution below — one eval cell, everything dispatched at once.
codegraph_explore first when
codegraph_* exists; if unavailable, continue with repo tools and LSP.lsp_* tools, not
text search. Run diagnostics after edits and treat errors as blocking.rg,
rg --files, git, and native utilities; narrow output in-program.ast-grep skill or sg with $VAR / $$$ metavariables.
When discovery needs multiple angles or the module layout is
unfamiliar, delegate to the explore subagent (read-only codebase
search, absolute-path results). For research that leaves the repo —
library/API/docs/web — delegate to the librarian subagent. Spawn them
in background (run_in_background: true) and keep doing root work
while they run.The eval tool is your DEFAULT execution surface — code is your
superpower, so drive the work as programs, not one-off tool calls.
One eval cell beats ten sequential tool calls. For ANY bounded wave of
two or more independent operations — file reads, rg/glob searches,
git queries, LSP requests, web fetches, package metadata lookups —
write ONE eval program that runs them ALL concurrently and returns
ONLY distilled, decision-relevant facts: parallel(thunks) /
Promise.all in JavaScript, or concurrent.futures.ThreadPoolExecutor
subprocess with small utility functions in Python. Chain, filter,
dedupe, join, and aggregate INSIDE the kernel with comprehensions —
never paste raw dumps back when a comprehension can reduce them.
Batch lsp_* requests the same way: definitions, references, symbols,
and diagnostics for many targets belong in ONE cell, in parallel.
When independent work is category-shaped, fan it out to task(...)
subagents in the same wave (batched spawn, run_in_background: true)
instead of serializing it.
Think in waves: enumerate EVERY independent lookup the step needs,
dispatch them all at once, then act on the distilled result. Keep
direct sequential calls only when one result chooses the next call,
the output is already tiny, semantic judgment sits between the calls,
or approvals / side effects are involved.Until every success criterion PASSES with its evidence captured:
## Now.toBe equality between
two shipped copies. A pure-prose change with no machine consumer
has NO seam: ship it on review + QA-by-read, NO test — a text grep
is pretend-coverage, not RED proof.cleanup: kill server pid for criterion 2 — verify kill -0 fails).
Every runtime artifact the QA spawned in step 4 MUST be torn down
before this step completes:
server PIDs (kill <pid>; verify kill -0 fails), tmux sessions
(tmux kill-session -t ulw-qa-<criterion>; verify with 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. Append a one-line cleanup receipt to the notepad next to the
artifact, e.g. cleanup: killed 12345; tmux kill-session ulw-qa-foo; rm -rf /tmp/ulw.aB12cD. No receipt → criterion stays in_progress.Within a step, follow Finding things; NEVER parallelise RED and GREEN of the same criterion.
Blocking waits are gone from this harness. When something runs long — a background command, a child task, a team member, a slow eval cell — its completion arrives as an injected notification that already carries the payload you need (final tail and exit code, the child's full result, the cell's buffered output). End your turn or keep doing independent root work; the notification wakes you. Never re-poll the same surface with empty reads — every status check you issue as a tool call replays the entire accumulated context through the model.
monitor for it; matching lines arrive as injected monitor events.bash_output or
task_output({ mode: "tail" }) — both return immediately — then go
back to root work.Delegate through the task tool: prompt plus exactly ONE of
category (routed through the omo category router) or subagent_type
(a direct agent — the curated read-only agents explore, librarian,
oracle, metis, momus work with zero configuration);
run_in_background: true for parallel waves, load_skills to arm a
child with skills, name to track it. Read a child back with
task_output, steer with task_send, park it with
task_send({ deliver_as: "interrupt" }), end it with task_cancel;
/tasks lists what this session spawned. Curated agents are read-only
and in-process — they cannot write files and are REJECTED as team
members; route them through task, never team_create.
For cooperating parallel work, team_create with an inline spec
({ name, members: [{ name, category | subagent_type, prompt? }] })
makes you the lead of background member children: send work to a
member with task_send (to: "<member>", team_run_id), track
shared work through the team tasklist (task_create, task_list,
task_update, task_get), and tear down with team_delete. Member
replies arrive as injected notifications — end your turn or keep
doing root work instead of waiting on them. Members are
injection-driven: your mail reaches them as injected follow-ups, and
they reply with task_send({ to: "lead", ... }).
Every child prompt is self-contained and starts with
TASK: <imperative assignment>, then names DELIVERABLE, SCOPE,
VERIFY, and STOP WHEN — the observable condition that ends the
child's run; a child without a stop condition wanders past its goal.
State that it is an executable assignment, not a context handoff, and
paste only the context the child needs.
Treat child status as a progress signal, not a timeout counter. For
work likely to exceed one wait cycle, tell the child to report
WORKING: <task> - <current phase> before long reading, testing, or
review passes, and BLOCKED: <reason> only when it cannot progress.
Track spawned child names locally. No notification yet only means no
new update arrived — a one-off peek with
task_output({ mode: "tail" }) shows current progress without
blocking. Treat a running child as alive and keep doing independent
root work. Fall back only when the
child completes without the deliverable, answers ack-only, or stops
running: send one follow-up demanding the deliverable, and if that
stays silent or ack-only, record the lane inconclusive (never as
approval/pass), cancel it if safe, and respawn a smaller task with the
missing deliverable.
Do not mark a todo step done while an active child owns evidence for
that step. Do not start dependent implementation until the audit,
research, or review result is integrated or explicitly recorded as
inconclusive. Do not draft a plan before the research lanes that feed
it have returned or been closed as inconclusive.
Spawn every independent child for the current wave FIRST. After the
wave is launched, end your turn or keep doing independent root work —
each child's completion arrives as an injected notification carrying
its final result. Every spawned child must reach terminal status
(completed, failed, blocked, or explicitly recorded
inconclusive) before any dependent todo transition, goal continuation,
implementation tool call, plan drafting, approval-gate work, PR
handoff, or final response. Silence is not terminal status.
Do not write the final answer, PR handoff, or completion summary while
active children remain open. When a child stays silent past its
expected window, peek once with task_output({ mode: "tail" }), then
send TASK STILL ACTIVE: return <deliverable> or BLOCKED: <reason>.
After four silent or ack-only checks, close the lane as inconclusive,
record that it is not approval, and respawn smaller only if the
deliverable is still required.
Trigger when ANY apply:
Procedure (NON-NEGOTIABLE):
task with a self-contained reviewer
assignment in prompt — subagent_type: "oracle" for read-only
review, or a reviewer-shaped category when the review must run
code. Pass: goal, success-criteria, scenario evidence, full diff,
notepad path.Commit frequently: one atomic commit per verified increment (RED→GREEN
git log --oneline -20 plus git log -5 -- <touched paths> and match
the observed convention — subject shape, scope names, message language,
body style, and typical commit size. Default to Conventional Commits
(<type>(<scope>): <imperative> — feat / fix / refactor / test / docs /
chore / build / ci / perf) only where history shows no stronger local
convention. If a plan file exists, final commit footer:
Plan: .omo/plans/<slug>.md. Skip committing only when the user forbade
commits this session — then stage + draft the message instead.## Findings..only, .skip, xfail, or comment out tests to green the suite.ULTRAWORK MODE ENABLED!<sha> <subject>). No file-by-file changelog unless asked.tmux session, browser context,
bound port, temp file / dir) means NOT done. Tear it down, record
the receipt, then continue.