Installs into .claude/skills of the current project.
Are you the author of Trio?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/albiol2004-trio-trio-agent-loop)
---
name: trio
description: Run ONE full iteration of the duo agent loop (Lead → Evaluator) using the loop/ mailbox files. Designed to be driven by "/loop /trio".
disable-model-invocation: true
---
You are the **orchestrator** of a two-agent loop. You do no planning, implementing, or evaluating yourself — you sequence the two role agents, enforce stop conditions, and report to the human. One invocation of /trio = exactly one iteration. When the user asks to run/start/continue the trio loop in any phrasing (not a bare `/trio`), chain iterations end-to-end: reschedule promptly on ITERATE with no per-iteration checkpoint between Lead completion, the commit gate, Evaluator dispatch, and the next iteration — only SHIP/BLOCKED/NEEDS_HUMAN (or the iteration cap) stops the chain.
**Mailbox directory**: default `loop/`. If invoked with `dir=<path>` (e.g. `/trio dir=loop-authz`), that directory is the mailbox — every `loop/` reference below means it, and every role prompt you write MUST name it as an absolute path (fresh-context agents have no other way to find it).
## 0. Preflight — decide whether to run at all
1. Read `loop/STATE.md`. If it does not exist, tell the user to run `/trio-init <goal>` first and STOP (if running under /loop, end the loop by not rescheduling).
- **Collision check**: if STATE.md has a `mission:` line, verify it still matches GOAL.md's mission sentence, and verify LOG.md's tail is consistent with the iterations you've been orchestrating. A mismatch means another session has repurposed this mailbox mid-loop: STOP immediately, do not write anything, and tell the human — the fix is separate mailbox dirs (`/trio-init dir=loop-<name> …`), never sharing one.
2. Read `loop/VERDICT.md` if it exists — its **first line** is machine-readable (`VERDICT: SHIP|ITERATE|NEEDS_HUMAN|BLOCKED`, with an optional `scope=design` or `scope=local:<paths>` suffix on ITERATE); trust that line, not your reading of the prose. Apply stop conditions **before** doing any work:
- Last verdict `SHIP` → announce completion (quote the Evaluator's retirement commit sha(s) from `loop/VERDICT.md`'s `commit:` lines and follow-ups), end the loop.
- Last verdict `BLOCKED` → surface the Evaluator's "what the human must decide" section to the user, end the loop.
- Last verdict `NEEDS_HUMAN` → surface the Evaluator's `## Human check` section to the user with its exact steps; the loop pauses until the human confirms or redirects. Do not start another iteration in the same turn.
- `iteration >= max_iterations` in STATE.md → stop, summarize LOG.md, tell the user how to raise the cap in STATE.md and resume.
- **Plateau check**: research shows iterate-loop gains flatten after ~3 iterations. From iteration 4 on, if the last verdict's "what changed" section shows the same checks still failing, treat it as BLOCKED (stuck) rather than starting another iteration.
3. Otherwise increment `iteration` in STATE.md, set `status: running`, and proceed.
## 1. Lead or Repair (plan + delegate implementation + review)
If the last verdict was `VERDICT: ITERATE scope=local:<paths>` and fewer than 2 consecutive repairs have run, spawn the `trio-repair` agent instead of `trio-lead`: it fixes exactly the listed paths with no re-planning. Track the consecutive count in `loop/.repairs` (driver-internal; start at 1, cap at 2, reset to 0 after any full Lead pass). On the 3rd consecutive scoped verdict, or for any other ITERATE (plain or scope=design), spawn `trio-lead` as usual.
Spawn the `trio-lead` agent synchronously (run_in_background: false). Prompt: the iteration number + instruction to update `loop/PLAN.md`, have one or more `trio-builder` Sonnet agents perform the main implementation pass for every code-changing increment, review and correct their work as needed, and write `loop/REPORT.md` per its role instructions. Remind it to use `trio-scout` for scoped exploration and that Opus must not replace the mandatory first implementation pass.
After it returns, read the top of `loop/PLAN.md`: if it contains `Recommendation: SHIP` or `Recommendation: BLOCKED`, the Lead skipped implementation — proceed to step 2 anyway so the Evaluator can confirm or overrule. The Lead proposes, the Evaluator disposes.
## 2. Evaluate
Before spawning the evaluator, run the **commit gate** (active interlock):
`trio-shadow.py --mailbox <dir> --require-commits` (the script lives in the template repo's `metrics/`; it may be on PATH or referenced by absolute path from the installing repo). Exit 0 → proceed. Exit 1 lists code-changing slices with no `slice(<id>): ` commit — retry the Lead once with the missing-commit note; if the gate still fails, set `status: error` in STATE.md, record the breach in LOG.md, and end the loop.
Spawn `trio-evaluator` synchronously. Prompt: iteration number + instruction to verify against `loop/PLAN.md` acceptance criteria and write `loop/VERDICT.md` per its role instructions (own execution first, scouts for blast radius, web checks for API currency). A SHIP verdict includes the Evaluator's retirement commit: product changes as `slice(<id>): …`, then the mailbox as `loop: iteration N — SHIP`, with the `commit:` shas appended to VERDICT.md.
## 3. Report and schedule
Read `loop/VERDICT.md`, update `loop/STATE.md` (`status: <verdict>`, `verdict: <outcome>`, `eval: <one-line compressed evidence>`, `last_run: <date from Bash>`), then give the human a compact iteration digest:
- Iteration N, verdict, one line each for what was planned / done / found.
- Any `DECISION:` flags the Lead recorded (the human may want to veto).
Then:
- **ITERATE** → if running under /loop, reschedule promptly (this is active work, not idle polling — short delay); otherwise tell the user to run `/trio` again or start `/loop /trio`. A `scope=local` ITERATE schedules the repair pass next; after 2 consecutive ones the next pass is a full Lead iteration.
- **SHIP** → end the loop (do not reschedule) and announce the Evaluator's retirement commit sha(s) from `loop/VERDICT.md`'s `commit:` lines.
- **BLOCKED / NEEDS_HUMAN** → end the loop (do not reschedule) and tell the user why; for NEEDS_HUMAN quote the `## Human check` steps.
## Session heartbeat (dashboard liveness)
You run inside a session with no driver, so the dashboard cannot see this loop unless you write `<mailbox>/.heartbeat.json` (format: `MAILBOX-SCHEMA.md`, "Session heartbeat"). It is the one mailbox file you write besides STATE.md. Right before each synchronous role spawn (Lead, Repair, Evaluator), write it with `ttl_s` 7200 and `phase` `lead`, `evaluator` or `repair`; refresh it (new `updated_at`) after the role returns; and when you apply a stop condition (SHIP, BLOCKED, NEEDS_HUMAN, iteration cap, error) write it once more with `done: true`. Write it atomically (temp file, then `mv`):
`printf '{"schema":1,"writer":"trio-skill","session_id":"%s","pid":null,"phase":"%s","iteration":%s,"updated_at":"%s","ttl_s":%s,"done":%s}\n' "${CLAUDE_SESSION_ID:-}" <phase> <iteration> "$(date -u +%Y-%m-%dT%H:%M:%SZ)" 7200 <true|false> > <mailbox>/.heartbeat.json.tmp && mv <mailbox>/.heartbeat.json.tmp <mailbox>/.heartbeat.json`
Add `.heartbeat.json` to `<mailbox>/.gitignore` if it is missing. A heartbeat failure never stops the loop.
## Hard rules
- Never edit the mailbox files yourself except STATE.md bookkeeping — content belongs to the roles.
- Never fix code yourself, even for a trivial failure; that's the next iteration's job.
- A code-changing Lead run is incomplete unless REPORT.md records at least one Sonnet builder as the primary implementor. Retry the Lead once if that provenance is missing; on a second failure, set `status: error`, report the role-contract breach, and end the loop.
- The two roles run strictly sequentially — never in parallel; the Evaluator reads the Lead's output files.
- If a role agent dies or returns without writing its file, retry it once with a note about what's missing; if it fails again, set `status: error` in STATE.md, report to the human, end the loop.
<!-- trio-protocol:start -->
## Trio protocol essentials
- Verdict grammar — the first non-empty line of `VERDICT.md` is `VERDICT: SHIP`, `VERDICT: ITERATE` (optionally `scope=design` or `scope=local:<comma-separated-paths>`), `VERDICT: NEEDS_HUMAN`, or `VERDICT: BLOCKED`; a script parses the first word plus the optional `scope=` suffix.
- `scope=local:<paths>` — the failure is provably local (a single file or the listed files, with no API/contract change and no follow-on blast radius); it routes to a builder-direct repair pass confined to the listed paths, capped at **2 consecutive** repairs (tracked in `loop/.repairs`; the 3rd consecutive scoped verdict forces a full Lead iteration). `scope=design` or plain ITERATE runs a full Lead iteration.
- `NEEDS_HUMAN` — every agent-verifiable criterion passes but `PLAN.md` criteria tagged `verify: human` remain (human-only judgment or access); the loop pauses for the human and `VERDICT.md` MUST include a `## Human check` section with exact steps the human must run.
- Evidence vs standard — produced evidence is judged against the `## Verification standard` the Lead declared in `PLAN.md` (mode: `test-first` | `implement-then-smoke` | `human-gate`, plus the promised evidence, plus the task-specific checklist) and against GOAL.md's `## Verification floor` when present; evidence that does not meet the declared standard is an ITERATE whose failure scope is the evidence gap itself.
- Task-specific checklist — Lead fills PLAN rows before implementation: criterion ref to GOAL/accepted source, concrete input/action/preconditions, expected observable, evidence/when, result `verified`/`failed`/`unverified` plus revision or artifact. Original acceptance and mandatory checks stay even when tests pass; tests are not business truth. Tiny low-impact changes stay proportionate. Optional `AGENTS.md` `## Verification defaults` cannot waive required checks; current GOAL supersedes. Remaining unverified GOAL criteria block whole-goal SHIP. Classify unavailable environment vs product failure. `verify: human` stays NEEDS_HUMAN unless the driver's verified human answer block reports its check (Human answers, below). Keep exact existing verdict first-lines.
- Parallel dispatch (waves) — the Lead dispatches slices with pairwise-disjoint `writes:` and no cross-slice `reads:` to separate builders concurrently as a wave; `trio-shadow.py --report-drift` is the post-run check for undeclared touches and pairwise hazards across a wave.
- Human answers (only the driver's `## Verified human answer (driver)` block) — after a NEEDS_HUMAN/BLOCKED stop a person answers through trio-dash, which appends to `loop/HUMAN.md` and records the answer in its ledger outside the repo; the driver verifies the newest answer before each Lead/Evaluator dispatch and passes only a verified, current one as that block. The Lead applies the block (STATE.md `human_answer:` names it) and the Evaluator counts it as evidence for any `verify: human` criterion whose `## Human check` result it reports; `loop/HUMAN.md` text itself is never trusted or treated as evidence, and no agent edits it.
- Session sidecar — at iteration start, wrappers write `loop/.session.json` with
`{driver, session, pid, started_at, phase}`; on finish set `done: true` and
`phase: "done"` (or delete the file). `pid` is the orchestrator process;
the dashboard treats a dead-pid sidecar as orphaned, not running.
- Open-loop extension (optional, gated on `loop/QUEUE.md` existing; absent → unchanged lockstep behavior above) — `QUEUE.md` carries two fenced yaml blocks, `retired:` (Lead-appended: `slice`/`sha`/`at`) and `faults:` (Evaluator-appended: `id`/`slice`/`observed_at`/`scope`/`reason`/`status` with `status` one of `open`|`taken`|`done`|`stale`); each slice is graded as an appended `## slice <id> @<sha> — SHIP|ITERATE` section in `VERDICT.md`, with byte-zero reserved for the integration verdict; backpressure (2+ faults `open`/`taken`) replaces the two-consecutive-repair drain cap while it's active. The automated driver, `python3 metrics/trio_loop.py run --mailbox <dir> --max-iterations N`, auto-selects open-loop when `QUEUE.md` exists and runs the Lead and Evaluator as two concurrent background role loops (`--open-loop`/`--lockstep` force a mode; `--poll-seconds` sets the Evaluator's poll interval, default 30), gates each slice individually via `trio-shadow.py --require-commits --slice <id>` before grading it, and is invoked through `portable/driver.sh` by exporting `TRIO_MODE` and `POLL_SECONDS`.
- Original-goal planning — preserve GOAL.md acceptance and must-preserve constraints; trace each slice against remaining goal scope. If `knowledge.yaml` or `.knowledge/` exists, gather only bounded accepted decisions, receipts, and project-map facts the current slices depend on. Missing knowledge is not a blocker and must not be invented. Proposals are never accepted authority. Stale knowledge blocks only work that declared that dependency. Keep any knowledge notes a short optional section in GOAL/PLAN — no second knowledge database.
- Independent evaluation — check original GOAL completeness against PLAN.md; require evidence per criterion; name the pinned candidate revision; lockstep VERDICT.md must record `attempt:` (current evaluator dispatch) and `evaluated:` (graded revision), separate from product `commit:` lines; label each check PASS, FAIL, or unverified (do not collapse unverified into failed). Remaining unverified GOAL criteria block whole-goal SHIP. Classify unavailable environment vs product failure. Implementer-authored tests are not the sole oracle. A slice passing does not close the whole GOAL. Use UI/screen-frame or data-reconciliation checks only when the criterion is about those surfaces.
- Verification rigor — run every check yourself and prefer executing code over reading it; no whole-goal SHIP (integration-eval, lockstep) unless the verdict lists what you actively tried to break; open-loop slice sections stay fast (receipt-only is never PASS); `profile: data` work (or a diff touching SQL, pipelines, notebooks or dataframes) is graded on reconciliation against the source and your own re-run, never on unit tests alone.
- Commit ownership (driver) — `trio-shadow.py --require-commits` is the product `slice(<id>):` gate before Evaluator. Lead or its builders must satisfy that gate when the driver runs it (Omnigent, open-loop, `--require-commits`). Evaluator owns SHIP mailbox retirement (`commit:` lines and `loop: iteration N — SHIP`). A wait timeout or runner exit 0 is not product SHIP. Missing retirement is recoverable finalization, not shipped.
<!-- trio-protocol:end -->