| name | loop-engineering |
| description | Designs and runs agentic feedback loops instead of one-shot prompts. Use it when: (1) starting any coding task an agent will iterate on (bug fix, migration, refactor, integration debug), (2) the user asks to 'design the loop', 'set up validation', 'make the agent run until tests pass', or mentions loop engineering, (3) an agent session is thrashing — repeated edits to the same files with no progress, oversized diffs, or actions taken without observing results, (4) choosing the right feedback signal (tests vs compiler vs review vs runtime logs) for a task, (5) auditing why an autonomous coding loop failed (overfit-to-test, context drift, unsafe autonomy), (6) designing a STANDING loop — a scheduled maintenance loop with a triage skill, state file, worktree isolation, maker/checker split, budget, and human gates (daily triage, CI sweeper, changelog drafter), or running loop-audit/loop-init/loop-cost. |
Loop Engineering — Design the Feedback Cycle, Not the Prompt
Loop engineering is the discipline of designing the feedback cycle an agent
runs inside: the agent plans, edits, observes real evidence, and adjusts —
repeating until validation passes. Prompt engineering optimizes one model
input; loop engineering designs the whole cycle around the model so the
agent can keep going until the work is provably done.
Summary principle: don't prompt step-by-step — design the loop and let
the agent run until validation passes.
Two sources, both credited in CREDITS.md:
- Khoa Nguyen's article "Loop Engineering"
(https://khoa.pl/loop-engineering.html) — the single-task feedback cycle
(stages, signals, failure modes).
- cobusgreyling/loop-engineering
(MIT, local clone
D:/Git/loop-engineering) — the STANDING-loop
discipline: building blocks, production patterns, operating/safety
doctrine, and the loop-audit/loop-init/loop-cost tooling.
The five stages (run them as a cycle, not a line)
- Intent — state the desired outcome concretely and measurably.
"Improve the dashboard" cannot terminate a loop: no observation can ever
prove it done. "Reduce initial load time by deferring non-critical
charts while keeping filters unchanged" is a tight intent — it names the
user-visible behavior, what must NOT change, and implies the check that
proves completion. Write every intent as: user-visible behavior + the
constraints (what stays untouched) + the validation command/check that
proves completion.
- Context — load exactly the code, docs, logs, and constraints the
task needs. Explain how the project works; don't dump the repo into the
window. Too little context makes the agent guess; too much makes it
drift. Prefer: the target files, their adjacent callers and tests, the
project rules file, and the most recent relevant error output.
- Action — make the change as a small, reversible diff. Small diffs
are the unit of debuggability: when the loop observes a failure, a
10-line diff pinpoints the broken assumption; a 500-line diff hides it.
- Observation — gather real evidence: test results, compiler errors,
runtime output, diffs, review comments. An agent without visible
results is running blind. Never let an action pass unobserved — an
unobserved edit is a guess wearing a commit message.
- Adjustment — update the plan from the observation and iterate.
Terminate when validation passes. Hand back to the human when the
blocker is genuinely human-shaped — permissions, missing data, or a
product decision — not merely because the loop got hard.
Choosing the feedback signal (per task type)
Pick the signal BEFORE starting the loop; the signal defines "done":
| Task type | Signal | Why |
|---|
| Bug fixes, behavior changes | Test-driven — a failing test the fix must turn green (write it first if it doesn't exist) | The test is a permanent, replayable proof of the requirement |
| Migrations, refactors, API bumps | Compiler/type-driven — the compiler or type-checker error count is the progress meter | Exhaustive, zero-setup coverage of every call site |
| Style / architecture alignment | Review-driven — human or agent review comments are the signal the loop consumes and resolves | The requirement lives in judgment, not in an executable check |
| Integration / UX issues | Runtime-driven — logs, traces, screenshots, live endpoints | The failure only exists in the assembled, running system |
The four tool categories
Loop engineering is tool-agnostic; the loop shape stays the same across all
four categories of agentic coding tools:
- CLI / terminal-first — Claude Code, Codex, Gemini CLI, Aider. The
loop lives in the shell: the agent edits files and runs the validation
commands directly, so Observation is native.
- IDE-integrated — Cursor, Windsurf, Antigravity, Zed. The loop lives
in the editor; diagnostics, inline diffs, and test runners provide the
observation channel.
- Spec-driven — Kiro, Spec Kit, BMAD, OpenSpec. The Intent stage is
promoted to a first-class artifact (spec/plan/tasks) that the loop
executes against.
- Cloud / async agents — Devin, OpenHands, Jules. The loop runs
unattended; Intent and validation must be fully specified up front
because there is no human mid-loop to clarify.
The six-step implementation workflow
- Start with a narrow task. "Fix the failing tax calculation test at
checkout" beats "debug checkout". Narrow tasks have narrow signals.
- Write intent + constraints. The user-visible behavior, the affected
files, the elements that must not change, and the validation commands
that must pass.
- Load context before editing. Adjacent code, existing patterns, and
the project's rules files (
CLAUDE.md, .cursor/rules, rules/*.md).
- Specify self-validation. Test commands, endpoints, acceptance
scenarios — explicitly, so the agent doesn't stop at "code generated"
but continues to "validation passed".
- Run small loops. Small edit → targeted test → read the output →
adjust → repeat. Prefer reviewable increments over big-bang changes.
- Keep the human as judge. Automate evidence gathering and mechanical
fixes; retain product decisions, architecture calls, and final review
with the human.
Four failure modes and their fixes
- Thrashing — the loop oscillates with no progress. Root cause: vague
goals or oversized diffs. Fix: re-state a measurable intent and shrink
the change. Detector: the same file edited across consecutive iterations
with zero movement in the validation signal.
- Overfit-to-test — the signal goes green but the intent is unmet
because validation is misaligned with the real requirement. Fix: make
the tests reflect the true requirement, then re-run the loop against the
corrected signal. Never "fix" a test to make it pass unless the test is
provably wrong about the requirement.
- Context drift — the agent ignores its own prior edits or stale
assumptions. Fix: refresh and prune context between iterations and limit
loop scope; long loops need periodic re-grounding in the CURRENT file
state, not the remembered one.
- Unsafe autonomy — destructive commands, overwrites, premature
pushes. Fix: set permission boundaries and stopping rules BEFORE the
loop starts — protected paths, no-push-without-gate, and an explicit
list of human-only actions.
From one loop to standing loops — the Five Building Blocks + Memory
Everything above designs ONE task's loop. A standing loop runs on a
schedule without you: it discovers its own work, acts within limits, and
escalates the rest. Six primitives compose every standing loop
(cobusgreyling/loop-engineering, docs/primitives.md +
docs/primitives-matrix.md):
| Primitive | Job in the loop |
|---|
| Automations / Scheduling | The heartbeat — discovery + triage on a cadence (/loop [interval] <prompt>, cron, GitHub Actions). Without it you have a one-off run. |
| Worktrees | Safe parallel execution — one isolated checkout per attempt; delete on REJECT or hand-off. |
| Skills | Persistent intent — conventions, build/test commands, "we don't do it this way because of X incident". Pays down intent debt. |
| Plugins & Connectors (MCP) | Reach into real tools — tickets, PRs, chat, databases. Scope to read+comment until the loop is trusted. |
| Sub-agents (maker/checker) | The single most important structural pattern: the agent that wrote the change never grades its own work. Verifier default stance: REJECT. |
| + Memory / State | The durable spine outside any conversation — a state file/board the loop READS at start and WRITES at end, answering: what are we on, what happened last time, what waits on a human. |
A minimal viable loop = scheduling + one triage skill + a state file. Add
worktrees when it starts changing code, a verifier when it acts
autonomously, connectors when it should drive tickets/PRs. Add each
primitive only after the previous version proved its value — and its
failure modes.
Anatomy of a standing loop
Schedule/Automation → Triage skill → read+write STATE/Memory
→ isolated Worktree → Implementer sub-agent → Verifier sub-agent (tests+gates)
→ MCP/Git/Tickets → Human gate?
├─ safe/allowlisted → commit / PR / action → back to schedule
└─ risky/ambiguous → escalate to human with full context → back to schedule
The seven production patterns
(cobusgreyling/loop-engineering patterns/ + patterns/registry.yaml;
this repo's own registry maps them to local practice in
patterns/registry.yaml.)
| Pattern | Cadence | Week 1 | Token tier | Core idea |
|---|
| Daily Triage | 1d–2h | L1 report | Low | Prioritized morning scan of CI/issues/commits → STATE.md; no auto-fix in week one |
| PR Babysitter | 5–15m | L1 watch | High | Shepherd PRs through review, CI, rebase; early-exit required |
| CI Sweeper | 5–15m | L2 cautious | Very high | React to red CI: classify (flake vs regression vs infra) → minimal fix in worktree → verifier → escalate after 3 attempts |
| Dependency Sweeper | 6h–1d | L2 patch-only | Medium | Patch + low-risk CVE only for 30 days; human gate on majors |
| Changelog Drafter | 1d or tag | L1 draft | Low | Scan merges → categorized draft release notes; drafter never publishes |
| Post-Merge Cleanup | 1d–6h | L1 off-peak | Low | Follow-up debt after merges; ticket the large items |
| Issue Triage | 2h–1d | L1 propose | Low | Dedupe/score/label incoming issues; human gate on P0/security |
Phased rollout — never skip L1: L0 draft (documented intent) → L1
report-only (triage → state, 1–2 weeks, measure triage accuracy) → L2
assisted (small auto-fixes + verifier + worktree + max attempts) → L3
unattended (only with denylist, budget, run log, metrics, human gates).
The auditor caps L3 until budget + run log + LOOP.md budget section +
proven run activity exist.
Operating & safety doctrine (standing loops)
Failure-mode catalog (docs/failure-modes.md) — check these when a
loop misbehaves: infinite fix loop (cap attempts at 3 → escalate;
separate verifier), state rot (prune closed items every run; Last run
timestamp), verifier theater (verifier must RUN tests and report output;
"find reasons to reject"), notification fatigue (notify only when a
human decision is required), token burn (cheap triage pass first;
early-exit on empty watchlist; daily budget), over-reach (denylist +
smallest-possible-diff + verifier checks touched files), comprehension
debt spiral (read what the loop ships; weekly digest), cognitive
surrender (keep opinions; success = time saved WITH the quality bar
held), parallel collision (worktree isolation + acting_on locks in
state), escalation failure (connector ping + a High Priority section a
human actually reads).
Anti-patterns (docs/anti-patterns.md) — design these OUT before
enabling: same agent implements and verifies; no attempt cap; vague prose
triage output (structure it); L3 before L1 quality; shared state without
schema (one state file per pattern); MCP with write-everything scope on
day one; no kill switch; "fixing" flakes with code changes; auto-merge
without a path allowlist; no run log.
Multi-loop coordination (docs/multi-loop.md): one owner per branch;
separate state files per pattern; triage reports while action loops
execute; shared denylist across every loop; aggregate token budget;
priority when loops conflict: CI sweeper → PR babysitter → dependency
sweeper → post-merge/changelog (off-peak) → daily triage (report).
Action loops write acting_on: in state and skip items another loop owns.
Concepts (docs/concepts.md): a harness is one session's
environment (tools, context, permissions); a loop = harness + schedule +
state + verification chain. Intent debt — every session starts cold and
fills gaps with confident guesses; skills pay it down. Comprehension
debt — the gap between what the repo contains and what you understand;
loops grow it unless you read what they ship. Cognitive surrender —
using loops to avoid thinking instead of to amplify judgment. The
orchestration tax — you remain the ceiling on how many parallel loops
you can absorb.
Tooling (loop-audit / loop-init / loop-cost)
npx --yes @cobusgreyling/loop-audit . --suggest
npx --yes @cobusgreyling/loop-init . --pattern daily-triage --tool claude
npx --yes @cobusgreyling/loop-cost --pattern daily-triage --level L1
The auditor scores: state file, triage/verifier/budget/constraints skills,
LOOP.md (with safety-gate, budget, worktree, and MCP mentions),
loop-constraints.md, loop-budget.md, loop-run-log.md,
patterns/registry.yaml, AGENTS.md/CLAUDE.md, .github workflows, and REAL
run evidence (Last-run timestamps, loop-related git history). This repo
scores 100/100 (L3) with every artifact describing real practice —
keep it honest: run activity and floors, not hollow files.
This repo's standing-loop conventions
The loops that actually maintain TerranSoulApp are documented in
LOOP.md (milestone-chunk, bench never-regress, the /loop +
/workflows product engines, autonomous-session, seed-lesson sync), with:
STATE.md — thin pointer at the real spine (rules/milestones.md =
queue, rules/completion-log.md = history,
mcp-data/shared/memory-seed.sql = durable lessons).
loop-constraints.md / loop-budget.md / loop-run-log.md — binding
rules, honest caps, append-only run history.
patterns/registry.yaml — the four local patterns + upstream mapping.
.claude/skills/loop-{triage,verifier,budget,constraints} — the four
runtime skills.
TerranSoul mapping
This doctrine is already load-bearing in this repo; extend these surfaces
instead of standing up parallel ones:
src-tauri/src/coding/engine.rs's stage-gate loop IS a
loop-engineering harness. The planner → coder → reviewer → apply →
test cycle with stage gates is exactly the five stages with gates as the
validation signal. New loop behavior belongs there, not in a second loop.
rules/observability-first.md IS the Observation stage as doctrine.
Errors on the user-input → backend → result path must be captured by
structured telemetry (Tauri events, MCP observations, backend logs)
BEFORE checking screens; screenshots are the last resort. That rule is
stage 4 of this skill made mandatory.
- Reproduce-first (Principle 8 of
rules/agent-self-learning-doctrine.md) is Observation applied to
debugging. Build the sub-10-second snippet that proves the bug before
re-running the long process, loop on the snippet, then promote it to a
regression test — the loop's signal outlives the loop.
The Five Building Blocks map onto shipped TerranSoul machinery (full
matrix: docs/brain-advanced-design.md §49.30):
| Building block | TerranSoul machinery | Repo convention |
|---|
| Automations / Scheduling | scheduler::AgentScheduler + memory/loop_engine.rs (loop_defs/loop_runs, the /loop engine, §49.21) | LOOP.md cadences; session protocol |
| Worktrees | coding/worktree.rs (+ branch_overlay/branch_sync) | D:/Git/ts-*-wt worktree-per-branch |
| Skills | SkillOpt brain-resident skills (optimize_skill/fetch_skill_row) surfaced via CodingWorkflowConfig::default_skill_names | .claude/skills/* (this file's brain twin: loop-engineering-default) |
| Plugins & Connectors | MCP gateway (ai_integrations/gateway.rs, ~97 tools) + channels/ inbound-outbound | MCP tray :7423; one MCP at a time |
| Sub-agents (maker/checker) | memory/workflow_engine.rs step dispatch + coding/multi_agent.rs; coding reviewer stage | loop-verifier skill; coordinator merges |
| Memory / State | MemoryStore (SQLite memories + memory_edges) + mcp-data/shared/memory-seed.sql | STATE.md pointer; seed-lesson sync loop |
Brain-resident twin
The condensed, coding-LLM-facing twin of this skill is the
loop-engineering-default seed in mcp-data/shared/memory-seed.sql
(seed:skill-loop-engineering-default-v2 — v2 added the standing-loop
doctrine and the primitive mapping), surfaced to every coding task via
CodingWorkflowConfig::default_skill_names — the same relationship the
harness skill has to harness-engineering-default. Keep the two in
sync: durable changes to this doctrine go into the seed (SQLite is the
source of truth for agent memory), with this file as the rich
Claude-session rendering. Seed upgrades follow the SkillOpt convention:
DELETE the prior version's row only when the new version's row is absent,
then INSERT the new version guarded (double-apply converges to one row).
Credits
- "Loop Engineering" by Khoa Nguyen
(https://khoa.pl/loop-engineering.html) — the five-stage feedback cycle,
signal selection, and the four failure modes.
- cobusgreyling/loop-engineering (MIT,
https://github.com/cobusgreyling/loop-engineering) — the Five Building
Blocks + Memory, the seven production patterns, the L1→L3 rollout, the
operating/safety doctrine, the loop-audit/loop-init/loop-cost tooling,
and the LOOP.md/STATE.md/loop-constraints/budget/run-log/registry file
conventions vendored into this repo.
See CREDITS.md for the full attribution rows.