Autonomous task loop — analyze, plan, execute, verify, review, finish. Runs as visible TUI agent in git worktree. Use when user says "yesloop", "loop", "run it autonomously".
Scanned 9/2/2026
Install to Claude Code
npx -y skills add carsteneu/yesmem --skill yesloop --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Yesloop?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/carsteneu-yesloop)More formats (shields.io, HTML) on the badges page.
---
name: yesloop
description: Autonomous task loop — analyze, plan, execute, verify, review, finish. Runs as visible TUI agent in git worktree. Use when user says "yesloop", "loop", "run it autonomously".
user-invocable: true
disable-model-invocation: false
allowed-tools: Bash(git *) Bash(go *) Bash(make *) Bash(npm *) Bash(docker *) Bash(python3 *) Bash(sqlite3 *) Bash(curl *) Bash(find *) Bash(ls *) Bash(cat *) Bash(rg *) Bash(mv *) Bash(cp *) Bash(rm *) Bash(mkdir *) Bash(test *) Grep Glob Read Write Edit todowrite Task
---
# Autonomous Task Loop
You are an autonomous agent. Work through tasks without asking the user.
## CRITICAL: Always spawn in a worktree
When invoked from an interactive session, **do NOT execute the pipeline yourself.** Instead, spawn an isolated agent in a git worktree:
1. **Create worktree:** `git worktree add -b yesloop/<task-slug> <repo>/.worktrees/yesloop-<task-slug>`
- Isolates agent changes from your working directory
- Multiple agents can run in parallel without conflicts
- Easy cleanup: delete worktree + branch if abandoned
2. Write the task to scratchpad with worktree path and skill-read mandate:
`scratchpad_write(project="<project>", section="yesloop-<task-slug>", content="YOU ARE A YESLOOP-AGENT. MANDATORY - YOU MUST READ THE YESLOOP SKILL AND YOU MUST FOLLOW THE INSTRUCTIONS IN THIS SKILL. Load the yesloop skill: use your platform's skill tool, or read ~/.claude/skills/yesloop/SKILL.md, or <repo-root>/skills/bundled-skills/yesloop/SKILL.md. Follow the 6-phase pipeline (ANALYZE → PLAN → EXECUTE → VERIFY → REVIEW → FINISH) FORMALLY AND SUBSTANTIVELY with ATTENTION.\n\nWorktree: <path>\nTask: <description>\n\nReport to scratchpad.")`
The spawned agent has NOT auto-loaded this skill — the mandate prefix is mandatory.
3. Spawn TUI agent: `yesmem_spawn_agent(project="<project>", section="yesloop-<task-slug>", backend="opencode", work_dir="<worktree-path>")`
4. Wait 15s for opencode TUI to load + PTY injection to deliver the startup prompt
5. **Relay kick (backup):** `yesmem_relay_agent(to="<agent-id>", content="Read scratchpad section 'yesloop-<task-slug>' AND load the yesloop skill (skill tool or ~/.claude/skills/yesloop/SKILL.md). MANDATORY - YOU MUST READ THE YESLOOP SKILL AND YOU MUST FOLLOW THE INSTRUCTIONS IN THIS SKILL. Begin the 6-phase pipeline FORMALLY AND SUBSTANTIVELY with ATTENTION.\n")` — backup if PTY is slow
6. Confirm: "Agent spawned in worktree — visible in terminal."
**Only run inline if:** the user EXPLICITLY says `--inline`. There is NO trivial-task exception — "< 2 min" is not a license to skip the worktree. If you'd commit it, it runs in the worktree. Create the worktree BEFORE the first edit.
**"Pipeline" includes exploratory work.** Writing tests, spiking an approach, "just quickly trying the fix on main to see if it works" — if you'd commit it, it belongs in the worktree. Create the worktree BEFORE the first edit, not after you've verified the fix works.
## Model selection (opencode backend)
`yesmem_spawn_agent(model=...)` accepts three forms, resolved by `resolveSpawnModel` in `internal/daemon/spawn_model.go`:
- **Empty** → returns "" — lets the opencode CLI pick its default from its own configuration. No model is hardcoded in the daemon.
- **Slash-qualified** (e.g. `zai/glm-5.2`, `zai-coding-plan/glm-5.2`) → passed through verbatim.
- **Bare model name** (e.g. `glm-5.2`, `deepseek-v4-pro`) → resolved against the auto-discovered provider map (built from `~/.cache/opencode/models.json` + `~/.config/opencode/opencode.json`). The daemon prepends the matching providerID, e.g. `glm-5.2` becomes `zai/glm-5.2`.
**Coding-optimized variants** (any provider whose ID contains "coding", e.g. `zai-coding-plan`) are included in the auto-discovery map like any other provider. When multiple providers carry the same bare modelID, the alphabetically-first ProviderID wins deterministically; resolve ambiguity explicitly via `model="provider/model"`. Rule of thumb: bare names resolve to whatever the active opencode config exposes; if only `zai-coding-plan` carries `glm-5.2`, bare `glm-5.2` resolves to `zai-coding-plan/glm-5.2`.
Unknown bare names log a warning and pass through unchanged (best-effort, no error).
## Orchestrator Contract (what to prescribe vs. delegate)
When you spawn a yesloop agent, the scratchpad task defines the working relationship. Over-prescribing takes ANALYZE+PLAN away from the agent; under-prescribing sends it into orientation loops. Get the level right.
**Prescribe (orchestrator's job):**
- **Skill-Read-Mandate** — The scratchpad task MUST start with 'YOU ARE A YESLOOP-AGENT.' and instruct the agent to load the yesloop skill AND read it with: MANDATORY - YOU MUST READ THE YESLOOP SKILL AND YOU MUST FOLLOW THE INSTRUCTIONS IN THIS SKILL. The agent MUST follow this skill FORMALLY AND SUBSTANTIVELY — every phase, block format, guardrail, and rule — with ATTENTION and MANDATORY. The spawned agent has NOT auto-loaded this skill; without the mandate it works without pipeline context. Path fallbacks: platform skill tool, `~/.claude/skills/yesloop/SKILL.md`, or `<repo-root>/skills/bundled-skills/yesloop/SKILL.md`.
- **Goal** in 1-2 sentences — what success looks like, not how to get there
- **Dense context** — facts, file paths, relevant learning IDs, what's already been tried, what failed. The agent starts cold; you don't.
- **Hard constraints** — schema-breaking changes, backfills, new dependencies, destructive ops, files off-limits
- **Escalation triggers** — decisions that belong to the user (product direction, API shape changes, breaking compatibility)
**Delegate (agent's job):**
- **ANALYZE** — reading code, grepping, finding the call sites, identifying edge cases
- **PLAN** — commit structure, file selection, test strategy, step ordering, milestone breakdown
- **EXECUTE/VERIFY/REVIEW** — the full 6-phase pipeline on the agent's plan, not yours
**Calibration test:** Before writing the scratchpad, ask: "If the agent came back with a plan, would I be surprised?" If yes for the right reasons (better approach), you prescribed right. If yes for wrong reasons (misunderstood goal), add context. If bored (matches what you'd write), over-prescribed — shorten.
## Relay-to-Resume Timing (paused agents)
Relay delivery to a `paused` agent is **asynchronous**: the daemon heartbeats the inject socket at ~1s intervals, the opencode TUI may be mid-turn, and the PTY bridge buffers. A relay is NOT reflected in agent status or scratchpad within seconds.
**Rule: after `relay_agent` on a paused agent, wait ≥ 2 minutes before re-checking status or concluding the relay failed.** A status that still reads `paused` 10 seconds after a relay is expected behavior, not a failure — the relay hasn't been picked up yet.
Anti-pattern (observed): orchestrator relays approval → checks status 5s later → still `paused` → concludes "relay did nothing, must resume manually" → calls `resume_agent`. This is redundant (paused PID is alive, PTY bridge open — resume is a no-op dressed up as action) and confusing. See Learning #81175: for `paused` agents, `relay_agent` is the correct action; `resume_agent` is only for genuinely dead processes.
Correct sequence after relaying to a paused agent:
1. `relay_agent(to=<id>, content="...")` — approval/instruction delivered
2. **Wait ≥ 2 minutes** — the agent needs to pick up the relay on its next tick, process it, write scratchpad, and call `update_agent_status`. Shorter windows produce false negatives.
3. THEN re-check: `get_agent` status + `scratchpad_read(project, section)` for new evidence (phase update, milestone, DONE marker)
4. If after 2 min there is NO new scratchpad activity AND status unchanged → read the `progress` field. If it shows an escalation/waiting state, the agent is correctly paused — relay again or escalate higher. Only consider `resume_agent` if PID is dead or `progress` indicates a real stall (crash, timeout without escalation line).
## Monitoring discipline (running agents)
Intervention requires stale **activity signals**, not just a stale status label. A running agent's status field can lag behind actual work — the agent may be mid-turn, processing a long tool call, or writing scratchpad while `update_agent_status` hasn't fired yet.
**Rule: only intervene when ALL of these are stale for several minutes:**
- `last_activity_at` — no new activity timestamp
- `turns_used` — turn count not advancing
- `stream_bytes` — SSE stream not producing output
A status label alone is not a trigger. If activity signals are advancing, the agent is working — let it run. The monitoring job (heartbeat) is the next check, not a manual poke.
Anti-pattern: orchestrator sees status `paused` or `running` with no recent context → assumes stall → relays/resumes/kills. This disrupts agents that are mid-work. Check the activity signals first. See Learning #82126.
## Temp file discipline
NEVER write to `/tmp/` or `~/.claude/yesmem/tmp/` in autonomous operations. `/tmp/` is unreliable across sandbox/container contexts (logs vanish, see #72938). Global paths collide when multiple agents run in parallel.
Use `<worktree>/.yesmem/tmp/` instead. Project-local, always writable from any agent context, cleaned up with worktree removal. `mkdir -p .yesmem/tmp` at session start.
## Execution Modes
**tui-agent** (DEFAULT) — Spawned via yesmem_spawn_agent → gnome-terminal, visible, non-blocking.
**inline** — User explicitly requested inline. Run in current context.
**scheduled** — User asked for recurring work. Use yesmem_schedule.
## Definition of DONE
DONE is a contract, not a feeling. Status is DONE only when ALL six phase sections exist in scratchpad and each carries `**Status:** COMPLETE`.
**Valid Status values per phase:**
- `IN PROGRESS` — actively working
- `COMPLETE` — phase finished, evidence present
- `BLOCKED — <reason>` — cannot proceed, needs orchestrator input
**Phase status update is mandatory at every transition:**
```
update_agent_status(phase="Phase N/6 NAME")
update_agent_status(phase="Phase N/6 NAME (milestone M/K)") # EXECUTE with milestones
update_agent_status(phase="Phase N/6 NAME (blocked: <why>)")
```
Free-form string, canonical format. Single source of truth for live progress.
**Orchestrator validates DONE:**
- DONE-guard (auto, every 30s) checks phase block compliance via regex
- Manual fallback: Read scratchpad section
- Check `### Phase 1` through `### Phase 6` headers exist
- Each has `**Status:** COMPLETE` (or `BLOCKED — <reason>` for genuinely blocked phases)
- Phase 5 Stage 2 has `task() dispatched: yes` or `REVIEW BLOCKED: <reason>`
- Phase 6 has `Deploy executed: yes` or `Deploy required: no`
Missing evidence → guard fires automatically (freeze + notify orchestrator).
## Automated DONE-Guard (v3)
Since yesmem v2.1.21, the heartbeat scheduler enforces the DONE contract **automatically** every 30 seconds. The DONE-guard (`internal/daemon/done_gate.go`) uses deterministic regex validation — no LLM, no `claude -p`, no false positives from model drift.
**What the guard checks:**
1. All 6 phase blocks (`### Phase 1` through `### Phase 6`) must be present in scratchpad
2. Each block must have `**Status:**` on its own line with valid value (COMPLETE|BLOCKED|IN PROGRESS)
3. Per-phase required fields (see Phase Pipeline below)
4. Phase 5 must contain `**Stage 2: Cold Review` subsection header AND `task() dispatched: yes|blocked`
5. Phase 4 must contain `**Regression baseline:**` with a non-empty value and `**RED proof:**`
6. Phase 5 must contain `**Stage 3: Consequence & Intent` subsection header AND `**consequence dispatched:** yes|blocked`
7. Phase 6 must contain `send_to orchestrator:` and deploy evidence
**When the guard fires:**
- Agent is paused with reason `DONE-GUARD: phase validation failed — <errors>`
- Orchestrator receives `⛔ DONE-GUARD:` notification via `send_to`
- Agent must fix phase blocks and be resumed
Before pausing, the guard relays the concrete missing fields and re-fires up to 2 times at 90s intervals. If a DONE-GUARD-paused agent's scratchpad becomes compliant, the guard unpauses it automatically (RECOVERY) and notifies the orchestrator.
**Phases missing from scratchpad = still in progress.** The guard only escalates when all 6 phase blocks exist but their content is non-compliant.
### DISMISSAL-PATTERN
These patterns cause the guard to reject the DONE claim:
| Pattern | Detection | Why it fails |
|---|---|---|
| Status on same line as header | `### Phase N: → **Status:**` inline | Status must be on its own `**Status:**` line |
| Missing Stage 2 header | No `**Stage 2: Cold Review` in Phase 5 | Stage 2 is mandatory per Learning #75412 |
| Missing Stage 3 header | No `**Stage 3: Consequence & Intent` in Phase 5 | Stage 3 consequence check is mandatory (quality stage-2) |
| Missing consequence dispatch | No `**consequence dispatched:** yes|blocked` in Phase 5 | Stage 3 dispatch must be evidenced |
| Missing regression baseline | No `**Regression baseline:**` with a non-empty value in Phase 4 | Deterministic base-vs-head test diff is mandatory (quality stage-2) |
| Missing orchestrator notification | No `send_to orchestrator:` in Phase 6 | Orchestrator must be notified for DONE |
| Missing **Security:** field in Phase 5 | No `**Security:**` line in Phase 5 block | Security review (item 6) is mandatory per security-review skill integration |
| Partial fields in Phase 5 | No issue breakdown, no Subagent ID | Self-Review must be structured |
| No deploy evidence in Phase 6 | No `Deploy executed:` or `Deploy required:` | Must document deployment outcome |
| Missing status line | Phase block exists but no `**Status:**` | Every phase needs a status |
| Missing session id note | Phase 1 has no `**Session id:**` field and no "session id missing" note | `whoami()` must be called at Phase 1 start; backend session id (or retry-failure note) must appear in Phase 1 block |
### Findings-Table
When the DONE-guard rejects a claim, its findings are structured as:
| Phase | Missing/Invalid Field | Detail |
|---|---|---|
| 5 | `**Stage 2: Cold Review` | required field not found in phase block |
| 6 | `send_to orchestrator:` | required field not found in phase block |
**DISMISSAL → DONE is rejected. Fix fields → resume agent.**
## Phase Pipeline
Each phase writes ONE structured block to scratchpad. Block format is mandatory — prose-only entries are not valid phase completion.
### CRITICAL — scratchpad project string + session id
All `scratchpad_write` and `scratchpad_read` calls MUST use the `project` value returned by `whoami()`. Call `whoami()` as the FIRST action at Phase 1 start and use its `project` field verbatim for every scratchpad call afterwards. Do NOT guess, do NOT use the worktree basename, do NOT hardcode a short name. The orchestrator and the idle/done-verify state machines read from `agent.Project` (set by `yesmem_spawn_agent`); using a different string means your writes and reads land in a different scope and the orchestrator never sees your progress.
`whoami()` also returns the backend session id (`opencode_session_id` for opencode, `codex_session_id` for codex). This id is required for `resume_agent` after crashes. The daemon polls it asynchronously after spawn, so the first `whoami()` call may return it empty. Retry up to 3 times with 5 seconds sleep between calls. If still empty after 3 retries, note "session id missing — resume may fail" in Phase 1 scratchpad and proceed. Do not block beyond 15 seconds.
**SCRATCHPAD DISCIPLINE (MANDATORY — prevents briefing clobber):**
`scratchpad_write` is an UPSERT — it REPLACES the entire section. **The FIRST action after spawn MUST be `scratchpad_read`.** Never call `scratchpad_write` before your first `scratchpad_read` — it will overwrite the orchestrator's briefing (#80063).
For intermediate progress updates (milestone complete, phase done, status markers), use **`scratchpad_append`** instead of `scratchpad_write`. `scratchpad_append` adds content WITH A DIVIDER, preserving the original briefing.
|| Action | Tool |
|---|---|---|
|| First thing after spawn | `scratchpad_read` |
|| Progress update (milestone/phase done) | `scratchpad_append` |
|| Full DONE report (all 6 phases) | `scratchpad_write` |
|| DRIFT alert / STUCK notice | `scratchpad_append` (preserves briefing) |
### Phase 1: ANALYZE
```
update_agent_status(phase="Phase 1/6 ANALYZE")
### Phase 1: ANALYZE
**Status:** COMPLETE
**Goal understood:** <1 sentence>
**Task type:** <debug|feature|chore|docs>
**Session id:** <opencode_session_id or codex_session_id from whoami(), or "missing after 3 retries">
**Codebase explored:** <files/packages inspected>
**Constraints identified:** <list>
**Dense context from memory:** <learning IDs relevant, or "none">
**Risks:** <list>
**Open questions:** none (must be inferrable, no user questions)
```
Information gathering is automatic — never ask the user. Code questions → search_code_index, grep, graph_traverse. API/docs → docs_search, hybrid_search. Errors → deep_search. Unknown concepts → WebFetch. NEVER guess — if you don't know, look it up (WebFetch or the indexed docs); infer only from code/context already in your turn.
### Phase 2: PLAN
```
update_agent_status(phase="Phase 2/6 PLAN")
### Phase 2: PLAN
**Status:** COMPLETE
**Plan stored via set_plan:** yes
**Decisions resolved:** all — files, schema, API, blast radius
- File selection: <which files, why not others>
- Schema decisions: <data structures, interfaces, types>
- API surface: <public interface, signature choices>
- Blast radius: <what else could break, dependencies affected>
**Milestones:** N total (see criteria below)
- Milestone 1: <name> (<step count> steps)
- Milestone 2: <name> (<step count> steps)
**Files in scope:** <list>
**Test strategy:** <approach>
**Verification gates between milestones:** <compile/test/deploy checks>
```
**When `**Task type:** debug` — Depth-lock-Disziplin (Pflichtfeld, vom DONE-Guard erzwungen):**
Phase 2 braucht zusätzlich diese Zeile:
`**Depth-lock:** D1 home=<file::function>; D3 deepest=<file::function>; D4 repro=<RED am unpatched Stand VOR Implementierung>`
- **D3 bestimmt die Fix-Ebene:** der Fix muss genau auf der D3-Ebene liegen. Ein Fix auf einer höheren/niederen Ebene als D3 ist ein depth-miss → zurück zum Plan, D1/D3 überarbeiten.
- **D4 muss echt gelaufen sein**, nicht geplant: der RED-Output stammt vom unpatched Stand VOR der Implementierung. Ohne realen RED-Lauf ist der Depth-Lock nicht erfüllt.
- Kompakt halten — Single-Agent-Format, keine Multi-Agent-Overheads (der Autoprompt darf 5 Agenten spannen, yesloop nicht, #73504).
**Milestone criteria (agent decides):**
- ≤5 steps: single milestone
- 6-15 steps: MUST split into 2-3 milestones à 3-6 steps
- 16+ steps: MUST split into 4-6 milestones à 3-5 steps
Milestones are a recovery aid for context-collapse, not a bureaucracy. Small plan (≤5 steps) → one milestone suffices; this is a granularity choice, NOT a license to skip the phase structure or the milestone blocks.
**NO OVERENGINEERING.** If a step looks complicated, ask: "Can I solve this with a boolean flag and 10 lines?" Usually yes. Resist: per-agent configuration, persistence layers, abstract Strategy interfaces, retry mechanisms with backoff. Prefer: global constants, single struct + map, simple if/return.
### Ledger Plan-Schema (set_plan convention — feeds the Live-Ledger)
Shape the stored plan (set_plan) so the live-ledger subscriber (`ledger_nudge`) can render it as a compact, immediately readable system-state block. A plan following this schema gives the orchestrator and the next self a shared proof-ledger, not a wish-list.
**Schema keys (Goal/Core/Verified/Open/Next):**
- **Goal:** the one aim of this session, 1-2 lines
- **Core:** fixed decisions / constraints that are NO LONGER up for debate
- **Verified:** what is already proven — every item carries a proof line:
- `<claim>` — `proof: <command> → <result>` (e.g. `proof: go test ./internal/... → exit 0, 18/18`)
- **Open:** open questions / alternatives still to be decided
- **Next:** the immediate next step
**Proof-line requirement:** only an item with a `proof:` line counts as Verified. A claim without a proof pointer belongs in **Open**, not **Verified**. The ledger is an evidence ledger — claims must cite the command and its result.
### Phase 3: EXECUTE
```
update_agent_status(phase="Phase 3/6 EXECUTE")
# or with milestones:
update_agent_status(phase="Phase 3/6 EXECUTE (milestone 1/3)")
### Phase 3: EXECUTE
**Status:** IN PROGRESS
**Plan items:** N total
#### Milestone 1: <name>
**Status:** COMPLETE
**Commits:** <hash> <msg>, <hash> <msg>
**Steps completed:** N/N
**todowrite synced:** yes
#### Milestone 2: <name>
**Status:** IN PROGRESS
**Current step:** N/M
**Last commit:** <hash> <msg>
**Total progress:** M/N milestones, X/Y steps
**Uncommitted work:** none | <list with reason>
```
**Per-milestone discipline:**
- `update_plan(completed=["milestone M"])` after each milestone finishes — persistence for collapse recovery
- `scratchpad_write` per milestone, not per step — controls bloat
- DRIFT CHECK before each milestone (not each step): re-read goal, compare scope
**Context-collapse recovery:** `get_plan()` → see current milestone → `update_agent_status` → read milestone block from scratchpad → continue.
**Commit cadence:** one commit per logical unit. Never leave uncommitted work across phase boundary without documenting why.
### Phase 4: VERIFY
```
update_agent_status(phase="Phase 4/6 VERIFY")
### Phase 4: VERIFY
**Status:** COMPLETE
**Tests run:** <command> → exit <code>, last 5 lines: <output>
**Regression baseline:** base=<origin/main hash> failures=<none|list>; head failures=<none|list>; diff=<none|new failures>
**RED proof:** <neuer Test RED vor Fix, GREEN nach Fix> | none — docs-only
**Lint/type-check:** <command> → <result>
**Build:** <command> → <binary mtime if applicable>
**Coverage gaps:** none | <list>
**VERIFY cycles used:** N/5
```
**Regression baseline (mandatory, deterministic):**
1. In Phase 2 (PLAN), note the merge-base: `git merge-base HEAD origin/main`
2. In Phase 4, create a temp checkout of origin/main INSIDE your worktree:
`git worktree add .yesmem/tmp/base-checkout origin/main` (project-local, never /tmp)
3. Run the relevant test suite there (same commands as head), record pass/fail sets
4. Remove it after use: `git worktree remove .yesmem/tmp/base-checkout --force`
5. `diff=` lists ONLY test failures that are green on base but fail on head — each is a
REGRESSION and must be fixed before REVIEW exit (or proven pre-existing on base)
If issues found → fix and re-verify (max 5 cycles, see CONVERGENCE GATE).
### Phase 5: REVIEW (Three-Stage: Self + Cold + Consequence)
```
update_agent_status(phase="Phase 5/6 REVIEW")
### Phase 5: REVIEW
**Status:** COMPLETE
**Stage 1: Self-Review**
- Strengths: <list with file:line refs>
- Issues: Critical (N) / Important (N) / Minor (N), with file:line + reasoning
- Recommendations: <list>
- Assessment: Yes | With fixes | No
**Stage 2: Cold Review via task()**
**task() dispatched:** yes | blocked — <error>
**Subagent ID:** <id>
**Findings:** <list or "none">
**Merged assessment:** Yes | With fixes | No — <reasoning>
**Fix commits:** <hashes or "none needed">
**Stage 3: Consequence & Intent**
**consequence dispatched:** yes
**Subagent ID:** <id>
**Findings:** <intended-vs-actual list or "none">
**Security:** <findings list with NEW/MODIFIED distinction per security-review skill, OR "none — diff reviewed, no findings", OR "skipped — diff is docs-only">
**REVIEW→VERIFY cycles used:** N/5
```
**Stage 1 — Self-Review** (catches mechanical issues): Get full delta `git diff origin/main` + `git log origin/main..HEAD --oneline`. Checklist: Plan alignment, Code quality, Architecture, Testing, Production readiness, **Security (item 6 — MANDATORY)**, Second-order effects ("if this ships, what happens next? trace 2+ levels"), Assumption surfacing ("what must be TRUE for this to work?").
**Stage 1 Item 6 — Security (MANDATORY):** INVOKE the `security-review` skill via the Skill tool when the diff contains ANY executable code (`.go/.py/.js/.ts/.tsx/.jsx/.java/.rs/.php/.rb`). Apply the NEW/MODIFIED doctrine: for NEW code (diff-added), fix ALL findings HIGH/MEDIUM/LOW; for MODIFIED code (existing function touched), fix issues the diff introduces and document pre-existing issues as OUT OF SCOPE with a Learning reference. Skip ONLY if the diff is docs/config/comments-only — then record `skipped — diff is docs-only` in `**Security:**`. Every finding line carries either a fix-commit-hash, a "not exploitable because X" note, or an OUT-OF-SCOPE annotation.
**Stage 2 — Cold Review via task()** (fresh eyes, catches architectural blind spots):
- Dispatch focused task()-subagent with code-reviewer template (superpowers requesting-code-review)
- Input: `git diff origin/main` + Phase 2 plan only (no exploration, for speed)
- **MANDATORY — Cold Review is NOT optional.** Phase 5 is only complete when Stage 2 has actually run. Empirically verified (2026-06-20, Learning #75412): agents skip Stage 2 silently if framed as additive. Required evidence: `task() dispatched: yes` + Subagent ID in scratchpad.
- **ALL subagent findings must be PROVEN ON CODE.** Every finding requires code-anchored evidence: file line refs, a call path (graph_traverse output), or a reproducing command/failing test. A finding without a code anchor is INVALID and must be reworked by the subagent.
- **If task() truly fails:** status must be `REVIEW BLOCKED: task() unavailable — <error>`, NOT `DONE`. Orchestrator spawns separate TUI reviewer as fallback.
**Stage 3 — Consequence & Intent Check via task()** (fresh subagent, MANDATORY):
- Dispatch a focused task()-subagent (separate from Stage 2's reviewer) with:
`git diff origin/main`, the Phase 2 **Decisions resolved** block, and this mandate:
(a) trace second-order consequences: callers, exposed contracts, defaults, schema,
dependent behavior — what breaks or changes that the diff does not show?
(b) intent fidelity: does the landed behavior match what Phase 2 decided?
Anything drifting into an unwanted direction?
- **ALL Stage-3 findings must be PROVEN ON CODE** — same evidence bar as Stage 2:
file line refs, call path, or a reproducing command/failing test. Unanchored
findings are INVALID and must be reworked by the subagent.
- Evidence in the Phase 5 block: `**Stage 3: Consequence & Intent` header,
`**consequence dispatched:** yes`, `**Subagent ID:**`, `**Findings:**`
- If task() truly fails: `**consequence dispatched:** blocked — <error>` (NOT COMPLETE)
**Double-loop exit criteria (REVIEW→VERIFY):** the loop exits only when ALL of
these hold: Stages 1-3 complete, Security field clean-or-annotated, and Phase 4
Regression baseline shows `diff=none` (or all new failures fixed + re-run). If a
check that must be clean stays red after 2 fix cycles → REVIEW BLOCKED
escalation.
**Merging & Resolution:**
- Merge findings from both stages (deduplicate, preserve highest severity)
- **ALL findings MUST be fixed autonomously** -- no user feedback, no escalation for fixable issues
- Critical, Important, medium, mittel → MUST fix immediately
- Minor also MUST fix immediately
- After fixes → loop back to Phase 4 VERIFY, then re-review (max 5 REVIEW→VERIFY cycles total)
- Assessment "No" (unfixable) → STOP, escalate via send_to: "REVIEW BLOCKED: <reasons>"
- **Never leave fixable issues for the user** -- review is a work phase, not advisory
- After `git show`/`git diff` always `Read` the current file — diffs show what changed, not what's there NOW
### Behauptungs-Inventar (proof-poverty check for the DONE-Report)
Every coverage / success claim in the DONE-Report must carry a proof pointer (command + result) on the same line; a claim without one is marked UNVERIFIED explicitly. This complements the Phase 4 `**Tests run:**` line — that records the overall run, here each individual claim is bound to its own evidence.
**Format per claim:**
- `<claim>` → `proof: <command> → <result>` (e.g. `proof: bun test plugins/opencode-yesmem → exit 0, 24/24`)
- not verifiable now → `<claim>` → `UNVERIFIED: <why not verified>`
Corollary from the ledgere schema: don't claim success you cannot back. Move unproven items to **Open** in the plan instead of asserting them in **Verified**.
### Phase 6: FINISH
```
update_agent_status(phase="Phase 6/6 FINISH")
### Phase 6: FINISH
**Status:** COMPLETE
**Deploy required:** yes (binary/skill/cap/code change) | no (docs/config only)
**Deploy executed:** yes — <evidence: make build output, md5sum diff>
| no — <REASON. Default: BLOCKED, escalate to orchestrator>
**Branch pushed:** yes — <git log origin/<branch> -1 output> | no — <reason>
**PR created:** yes — <url> | no — left for orchestrator
**Merged to main:** NO — agents do not merge (merge is orchestrator-only)
**Worktree:** kept (pending merge confirmation)
**send_to orchestrator:** yes — <timestamp>
**send_to payload:** `[DONE] [DEPLOY: yes|no|skipped|failed] [COMMIT: <hash>] [BRANCH: <name>] [MERGE: no|pending-PR|blocked-PR] <summary>`
**set_plan complete:** yes
```
- **send_to marker convention (mandatory in Phase 6):** Orchestrator parses these markers — keep them leading in the `send_to` payload, summary free-text after.
- `DEPLOY`: `yes` (deployed), `no` (docs-only, not required), `skipped` (required but skipped per instruction/contract), `failed` (attempted, failed — escalate)
- `MERGE`: `no` (default — agents never merge), `pending-PR` (PR created, awaits orchestrator), `blocked-PR` (PR has blockers)
- **Merge policy: Agents NEVER merge to main themselves.**
- Default: push the worktree branch to origin, create a PR (or leave for the orchestrator to create one), then `send_to caller_session: "[DONE] [DEPLOY: <status>] [COMMIT: <hash>] [BRANCH: <name>] [MERGE: pending-PR] <summary>"`. Markers are parsed by orchestrator — keep leading, free-text summary after.
- `--merge` flag on the /yesloop command means the **orchestrator** requested auto-merge after PR checks pass. Even then the agent only pushes the branch and reports the PR URL — it does not run `git merge main` / `git checkout main && git merge <branch>` itself. The orchestrator handles the merge.
- Running `git checkout main` + `git merge <branch>` inside the agent's Phase 6 is ALWAYS wrong, regardless of flag, confidence, or test results. The agent's git scope is its worktree branch. Main is the orchestrator's scope.
- Rationale: the orchestrator owns release decisions, rollback, commit-message control, and PR review. A self-merge bypasses all four.
- **Do NOT delete worktree** — keep until the orchestrator confirms the merge is done.
## Mini Example (abbreviated — field names and headers are guard-compliant, copy them EXACTLY)
```
### Phase 1: ANALYZE
**Status:** COMPLETE
**Goal understood:** Add config.yaml read/write to set_config/get_config
**Session id:** ses_abc123 (from whoami())
**Codebase explored:** internal/daemon/handler_state.go, internal/config/config.go
**Constraints identified:** no breaking MCP API, proxy_state overrides must still work
**Risks:** concurrent writes, type coercion
**Open questions:** none
### Phase 2: PLAN
**Status:** COMPLETE
**Plan stored via set_plan:** yes
**Decisions resolved:** all
- File selection: config.go, handler_state.go, cmd_config.go, main.go
- Schema decisions: yaml config struct with Get/Set methods
- API surface: Save/GetValue/SetValue on Config type
- Blast radius: proxy_state override precedence, concurrent write
**Milestones:** 2 total
- Milestone 1: config.go Save/GetValue + tests (4 steps)
- Milestone 2: handler rewiring + CLI (3 steps)
**Files in scope:** internal/config/config.go, internal/daemon/handler_state.go, cmd_config.go, main.go
**Test strategy:** table-driven for coercion, integration for handler
**Verification gates:** go test ./internal/config/... between milestones
### Phase 3: EXECUTE
**Status:** COMPLETE
**Plan items:** 7 total
#### Milestone 1: config.go Save/GetValue + tests
**Status:** COMPLETE
**Commits:** a9ba499 feat(config): add Save/GetValue/SetValue + 11 tests
**Steps completed:** 4/4
**todowrite synced:** yes
#### Milestone 2: handler rewiring + CLI
**Status:** COMPLETE
**Commits:** a9ba499 feat(config): wire set/get_config to yaml, add CLI
**Steps completed:** 3/3
**Total progress:** 2/2 milestones, 7/7 steps
**Uncommitted work:** none
### Phase 4: VERIFY
**Status:** COMPLETE
**Tests run:** go test ./internal/config/... ./internal/daemon/... → exit 0
**Regression baseline:** base=9e8aa888 failures=none; head failures=none; diff=none
**Build:** go build ./... → success
**VERIFY cycles used:** 1/5
### Phase 5: REVIEW
**Status:** COMPLETE
**Stage 1: Self-Review**
- Strengths: clean API, good test coverage
- Issues: Important (2) / Minor (4), with file:line
- Assessment: With fixes
**Stage 2: Cold Review via task()**
**task() dispatched:** yes
**Subagent ID:** agent-234
**Findings:** same 2 Important + 4 Minor
**Merged assessment:** With fixes — ALL 6 findings (2 Important + 4 Minor) fixed before merge
**Fix commits:** cd2ba04 fix(config): proxy_state dual-write, type coercion + all 4 minors
**Stage 3: Consequence & Intent**
**consequence dispatched:** yes
**Subagent ID:** agent-237
**Findings:** none
**Security:** none — diff reviewed, no HIGH/MEDIUM/LOW findings
### Phase 6: FINISH
**Status:** COMPLETE
**Deploy required:** yes (Go code change)
**Deploy executed:** yes — make build → binary mtime 2026-06-20T00:40
**PR created:** no — merged directly per orchestrator (merge commit 27e35ca)
**send_to orchestrator:** yes — 2026-06-20T00:47
**send_to payload:** `[DONE] [DEPLOY: yes] [COMMIT: 27e35ca] [BRANCH: yesloop/example-task] [MERGE: no] Add config.yaml read/write`
**set_plan complete:** yes
```
## Guardrails (Prevent Agent Drift)
### DRIFT CHECK — Before each MILESTONE (not each step)
1. Re-read the original goal from `scratchpad_read(project, section)` or `get_plan()`
2. Compare current state against original scope:
- **Still on track?** → proceed
- **Minor drift?** → MANDATORY fix immediately — correct course NOW, document what drifted and how you corrected it in scratchpad, then continue
- **Major divergence?** → **STOP.** scratchpad_write("⚠️ DRIFT: <what changed>") + send_to orchestrator: "DRIFT: <details>. Continue or abort?"
What counts as drift:
- Touching files outside the original scope (scope creep)
- Solving a different problem than the one given
- Adding features not requested ("while I'm here, I'll also...")
- Changing architecture without justification
### CONVERGENCE GATE — When progress stalls
| Pattern | Detection | Action |
|---|---|---|
| Edit-Test loop | Same test fails 3+ times with different fixes | **STOP.** scratchpad_write + send_to: "STUCK: <test> fails after 3 attempts." |
| Rewrite loop | Reverting your own changes and trying again | **STOP after 2 rewrites.** |
| Search loop | Searching for the same information repeatedly | Cache in scratchpad. After 3 empty searches, document as unknown. |
| Fix-then-break | Each fix breaks something else | **STOP after 2 cascades.** Code too coupled. |
**Hard limit:** No forward progress (no completed steps in todowrite) for 5 turns → escalate and stop.
### PROOF BURDEN (BEWEISLAST) for scratchpad claims
Before writing "DONE", "completed", "verified" to scratchpad, confirm the artifact matches the claim — not just that the command exited 0.
| Claim | Required independent check |
|---|---|
| "build succeeded" | `go build ./...` exit + binary exists with new mtime |
| "tests green" | show last 5 lines of test output, not just "PASS" |
| "deployed" | curl/GET against running service shows new version, OR md5sum live vs bundled exit 0 |
| "bundle rolled out" | `diff source installed && echo identical` (exit 0) |
| "commit pushed" | `git log origin/<branch> --oneline -1` shows the hash |
| "PR created" | `gh pr view <url>` exit 0 |
| "cold review ran" | task()-subagent ID present in scratchpad |
| "consequence finding" (Stage 3) | file line reference, call path, or repro evidence — unanchored findings are invalid |
| "file edited" | `Read` the file (not just `git show`) |
| "new test tests something" | **RED proof:** RED-Output am unpatched Stand (vor dem Fix), nicht nur geplant — bei docs-only explizit `none — docs-only` |
| "DONE-guard passed" | `ValidatePhaseBlocks(content).Compliant == true` (auto-checked every 30s) |
**Rule:** if verification was skipped, say so explicitly: `<claim> (not independently verified)`. If run, paste observable evidence (one line is enough).
**Apply only to consequential claims:** build, deploy, bundle rollout, merge, migrate, config change, destructive ops. Routine todowrite step-completion does not need this.
## State Recovery (every wake-up)
Your state lives in yesmem, not context. On every wake-up:
1. `get_plan()` — restore active goal and progress
2. `scratchpad_read(project, section)` — restore detailed context
3. **`check_messages`** — poll for orchestrator messages (OpenCode has no push, DB-poll is the only reliable path)
4. Reconstruct current phase + milestone
5. `update_agent_status(phase="Phase N/6 NAME (milestone M/K)")` — re-assert current state
6. Continue where you left off
## TUI Agent Mode (You were spawned in a worktree)
You are a **subagent** — spawned via yesmem_spawn_agent. You run in an isolated git worktree.
### ⛔ WORKTREE GUARDRAIL — Execute BEFORE any file modification
On startup, before ANY other action:
```
1. pwd → must match worktree path from scratchpad
2. git rev-parse --show-toplevel → must be the worktree, NOT main repo
3. git branch --show-current → must be yesloop/<task-slug>, NOT main
4. git status --short → must be clean
5. Write-Probe → mkdir -p .yesmem/tmp && printf probe > .yesmem/tmp/write-probe, dann read-back verifizieren (Inhalt == "probe")
```
**IF ANY CHECK FAILS:** STOP. Do not touch files. `scratchpad_write + send_to orchestrator: "⛔ WORKTREE GUARD FAILED: pwd=<actual>, branch=<actual>. Expected <expected>."` Wait for orchestrator.
**IF ALL PASS:** Identify via `whoami`, `scratchpad_read(project, section)`, `get_plan()`, `update_agent_status(phase="Phase 1/6 ANALYZE")`, then begin pipeline.
Write-Probe-Regel: die Probe-Datei wird NICHT gelöscht (kein rm) — sie bleibt im Worktree liegen und wird mit dem Worktree-Cleanup entfernt.
### Completion — MUST do all three:
1. `scratchpad_write(content="✅ DONE: <summary>. PR: <url>")` — final write with all 6 phase blocks COMPLETE
2. `send_to(target=<caller_session>, content="[DONE] [DEPLOY: <status>] [COMMIT: <hash>] [BRANCH: <name>] [MERGE: <status>] <summary>. PR: <url>")` — markers leading, parsed by orchestrator; summary free-text after
3. `set_plan(...)` mark as completed
**NOTE:** `send_to` stores in DB but push delivery is unreliable for OpenCode targets. Orchestrator polls `check_messages`. Scratchpad is primary completion channel.
**Periodic polling:** Every 5 turns, `check_messages` for new instructions or cancellation.
## Decision Gates (Autonomous)
| Situation | Action |
|---|---|
| Simple fix, clear solution | Execute directly |
| 2-3 approaches, unclear best | Pick one, document rationale, proceed |
| Need to change scope | MANDATORY fix immediately — stop the drift, correct course NOW, document it. Escalate only if the correction itself is impossible or blocking |
| Tests fail repeatedly | Debug max 3 cycles → CONVERGENCE GATE |
| Irreversible action (force-push, drop table) | Pause, request confirmation |
| 3 consecutive ticks with nothing to do | End the loop, report idle |
| Scope creep detected | DRIFT CHECK, correct or escalate |
| Same approach failed 3x | CONVERGENCE GATE — stop and escalate |
## Communication
- **inline mode:** short progress updates to user between phases
- **TUI agent mode:** scratchpad_write for detailed state, send_to for completion
- **scheduled mode:** scratchpad_write for state, broadcast on completion
- Never ask "should I continue?" — just continue unless blocked
## Automated Idle-Trigger
Layer 2 of the yesloop guarantee: **Idle Detection** for yesloop agents with a live PID but inactive SSE stream for >10 minutes. The daemon heartbeat runs an idle state machine (`checkYesloopIdle` in `internal/daemon/yesloop_idle.go`) that pushes agents through a 4-state escalation protocol.
### State Machine
| State | Condition | Action |
|---|---|---|
| 0 WORKING | stream_active=true or idle <10min | No action |
| 1 SELF_CHECK | stream_active=false for 10min, PID alive | Relay 1: ask agent to prove completion via scratchpad marker |
| 2 REMARK_REQUEST | PROVEN marker found | Relay 2: ask agent to mark all 6 phases as done |
| 3 COMMIT_REQUEST | 6 phases marked done | Relay 3: ask agent to commit and send_to orchestrator |
| 4 DONE | send_to evidence in scratchpad | Terminal — notify orchestrator |
### Relay Messages
The daemon sends these exact messages (metachar-free, no markdown, no backticks):
1. **State 0 → 1:** `Have you completed all 6 phases? If not do it now. For each phase prove you have done each, IF you have proven mark each phase in scratchpad with [x] showing it is done. MANDATORY: Make sure that you have also done phase 5 with all code reviews including Stage 2 cold review and Stage 3 consequence check via task subagents. REVIEW BLOCKED without subagent trace is not acceptable. Mandatory: only mark as PROVEN if it IS proven.`
2. **State 1 → 2:** `Mark all 6 phases as done with x in scratchpad.`
3. **State 2 → 3:** `If 1 through 6 are ok commit and send_to to caller.`
### Scratchpad Markers
The idle checker reads the agent's scratchpad section to detect progress:
- **PROVEN** (case-insensitive): signals that the agent has verified all 6 phases are complete → triggers State 1 → 2
- **6x `**Status:** COMPLETE`**: when all 6 phase blocks are completed (detected by `CountCompletedPhases()`) → triggers State 2 → 3
- **send_to orchestrator:** evidence in scratchpad → triggers State 3 → 4
### Re-fire and Escalation
- Each state re-fires the relay after 90 seconds if no progress
- After 2 re-fires (3 total attempts), the agent is **paused** as DEAD_AGENT
- The orchestrator (caller_session) is notified via send_to
### What triggers idle detection
- Section prefix: `yesloop-`
- Agent status: `running`
- PID: alive (`isPIDAlive()` returns true)
- Stream state: `stream_active` false for >10 consecutive minutes
## Automated Done-Verify (v3.2)
Layer 3 of the yesloop guarantee: **Done-Verify** for yesloop agents that emit a DONE-claim (Phase 6 header, `send_to ... DONE`, or `Phase 6/6` marker). The heartbeat runs a 4-state verify machine (`checkYesloopDoneVerify` in `internal/daemon/yesloop_done_verify.go`, called every 5 minutes) that asks the agent to **BEWEISEN** all 6 phases ran — especially Phase 5 Cold Review — before marking DONE.
### State Machine
| State | Condition | Action |
|---|---|---|
| 0 NOT_DONE | No DONE-claim in scratchpad | Not tracked, cron inactive |
| 1 VERIFY_REQUESTED | DONE-claim detected | Relay: "Hast du wirklich alle Phasen abgehakt..." |
| 2 DONE_VERIFIED | BEWEISEN marker + send_to orchestrator + 6 phases COMPLETE | Terminal — cron stops for this agent |
| 3 DEAD_AGENT_ESCALATION | 3 re-fires without progress | Freeze + notify orchestrator |
### DONE-Claim Indicators (any one triggers)
- `### Phase 6:` header (case-insensitive)
- `send_to ... DONE` pattern
- `Phase 6/6` marker
- `DONE: ` prefix in content
### Relay Message (metachar-free)
`Hast du wirklich alle Phasen abgehakt. Vor allem Phase 5 Code Review. Falls nicht bitte durchfuehren und BEWEISEN dass alle 5 Phasen durch sind und DANN Phase 6 Finish durchfuehren mit commit und send_to. KEIN auto-deploy.`
### Scratchpad Markers
The done-verify checker reads the agent's scratchpad section to detect progress:
- **DONE-claim** (any indicator above): triggers NOT_DONE → VERIFY_REQUESTED
- **BEWEISEN** (case-insensitive) + `send_to orchestrator:` line + 6 phases COMPLETE: triggers VERIFY_REQUESTED → DONE_VERIFIED
- Missing evidence after 3 re-fires: triggers VERIFY_REQUESTED → DEAD_AGENT_ESCALATION
### Re-fire and Escalation
- Re-fires the relay every 5 minutes if no progress
- After 3 re-fires (total 4 relay attempts), the agent is **paused** as DEAD_AGENT
- The orchestrator (caller_session) is notified via send_to
### What triggers done-verify
- Section prefix: `yesloop-`
- Agent status: `running`
- Scratchpad content matches any DONE-claim indicator
- Agent not already in DONE_VERIFIED or DEAD_AGENT_ESCALATION state
### Boundary with other layers
- **Idle Detection (Layer 2)** triggers on stream inactivity; Done-Verify (Layer 3) triggers on DONE-claims. They are complementary and can both fire for the same agent.
- **DONE-Guard (Layer 3 regex validator)** freezes agents that claim DONE with malformed phase blocks. Done-Verify catches the case where phase blocks look valid but Phase 5 Cold Review was silently skipped — the agent must actively BEWEISEN it ran Stage 2.
## Automated Skill-Reload Check (Layer 4)
Layer 4 of the yesloop guarantee: **Context-Compaction-Re-Read** gegen Skill-Verlust. Lange yesloop-Läufe können den Skill-Text verlieren, wenn der Kontext kompaktiert wird — der Agent würde dann ohne Pipeline-Vorgaben weitermachen. Der Daemon (`checkYesloopSkillCheck` in `internal/daemon/yesloop_skillcheck.go`, 30s-Heartbeat) beobachtet das kumulierte Arbeitsvolumen je Agent (OutputTokens-Delta seit Reset-Basis ≥ 100.000, Fallback TurnsUsed-Delta ≥ 50) und erinnert per Relay daran, den Skill neu zu laden.
### State Machine
| State | Condition | Action |
|---|---|---|
| 0 TRACKING | Arbeitsvolumen unter Schwelle seit Baseline | No action |
| 1 REMIND | OutputTokens-Delta ≥ 100k ODER Turns-Delta ≥ 50 seit Baseline | Relay: Skill-Ladezustand prüfen, bei Bedarf neu laden, per Marker bestätigen |
| 2 CONFIRMED | **SKILL-RELOAD-<N>:** yes mit aktueller Runden-Nummer im Scratchpad | Baseline auf aktuellen Stand zurücksetzen → zurück zu TRACKING |
| 3 DEAD_AGENT_ESCALATION | 3 Re-Fires ohne Marker | Freeze + notifyOrchestrator |
### Context-Compaction-Re-Read (Agentenseite — MANDATORY)
- Erhält der Agent einen Relay, der auf Context-Compaction / Skill-Verlust hinweist (Absender `yesloop-skillcheck`): DEN SKILL SOFORT NEU LADEN (`skill`-Tool oder `~/.claude/skills/yesloop/SKILL.md` / Bundle-Pfad lesen).
- Danach als Beweis per `scratchpad_append` die EXAKTE Bestätigungszeile aus dem Relay schreiben, inklusive der aktuellen Runden-Nummer: `SKILL-RELOAD-<N>: yes` (z.B. `**SKILL-RELOAD-3:** yes`).
- Der Daemon erkennt den Marker nur, wenn die Runden-Nummer zum aktuellen Fenster passt (case-insensitive, tolerant gegenüber `**`) und setzt dann seine Tracking-Basis zurück — der nächste Reminder feuert erst nach der nächsten akkumulierten Schwelle.
- Die Runden-Nummer ändert sich pro Fenster: ein alter Marker aus einem früheren Fenster bestätigt ein neues Fenster NICHT. Nur eine echte, aktuelle Bestätigung verdient den Reload.
- Ohne echten Reload KEINEN Marker setzen — der Zustand wird nur durch eine tatsächlich geladene Skill-Instanz verdient.
### Re-fire and Escalation
- Re-fires alle 5 Minuten ohne Marker-Progress für das aktuelle Runden-Fenster.
- Nach dem 3. Re-Fire-Intervall ohne Fortschritt (initialer Relay + max 2 weitere gesendete Re-Fires) wird der Agent als DEAD_AGENT gepaust und der Orchester via send_to benachrichtigt.
### Boundary with other layers
- **Compaction-Check (Layer 4)** feuert auf akkumuliertes Arbeitsvolumen eines LAUFENDEN Agents — orthogonal zu Idle (Stream-Inaktivität) und Done-Verify (DONE-Claims). Alle drei können für denselben Agent feuern.
## Automated Stagnation Monitor (Layer 5)
Layer 5 of the yesloop guarantee: **Stagnation Detection** for agents with an **active** stream and a live PID that produce no observable progress (no scratchpad writes, no `update_agent_status` changes) for >2 hours. Complements the Idle guard (which only fires on stream *inactivity*) — catches day-scale runs where the stream stays active but nothing advances. AVO-inspired conditional intervention (arXiv 2603.24517 §3.3): the trigger is fully deterministic, not a permanent supervisor.
**Trigger condition:** running `yesloop-` agent, PID alive, stream `active`, `CountCompletedPhases < 6`, and the progress signal — `stagnationSig(scratchpad content, agent.Progress)` — unchanged for >1h. Any change to the signal resets tracking. Reset happens on PROGRESS only, never on stream blips (#82787 lesson).
### State Machine
| State | Condition | Action |
|---|---|---|
| TRACKING | signal unchanged <2h | no action |
| REFIRING | signal unchanged >1h | relay STAGNATION + up to 3 refires @30min |
| ESCALATION | refires > 2 | `pauseAgent` + `notifyOrchestrator` (DEAD_AGENT) |
Upon receiving a STAGNATION relay: write a status line with current evidence to the scratchpad immediately (scratchpad_append). If genuinely stuck, either change approach or document BLOCKED with the reason. Do not ignore the relay — escalation pauses you after 4 relays.
## Anti-Patterns
- Do NOT write design documents unless the task is architectural
- Do NOT ask clarifying questions — infer from context, document assumptions
- Do NOT scope-creep beyond the given task — see DRIFT CHECK
- Do NOT run endlessly — 3 idle ticks = stop
- Do NOT modify agent config files (.claude/, SYSTEM.md, yesloop.md, etc.)
- Do NOT keep trying the same approach — if 3 attempts fail, approach is wrong
- **⛔ Do NOT work in main.** Always verify worktree before touching files.
- Do NOT report DONE with missing phase sections — report PARTIAL instead
- Do NOT report COMPLETE for a phase without `update_agent_status` having been called for that phase
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!