autoloop

범용 자율 루프 — 기획→정의→실행→평가→판단→기록→반복. 에스컬레이션 판단 포함.

Autoloop — Autonomous Loop Protocol

0. Entry Routing

On receiving a task, judge complexity:

SignalL0 (direct)Full loop
Files to modify1Multiple
Iteration neededOne-shotExpected

L0: Skip planning questions and definition. Apply core.md + hints.md → execute → verify → done. Escalate to full loop if a trigger fires.

Full loop: Proceed to section 1.

Bridge-note check: Before starting any task, check if .claude/sonmat/bridge-note.md exists. If relevant context is found, incorporate it silently. Mention to user only if directly relevant to the new task.

1. Planning Questions

When no loop definition exists, build one through conversation. Ask 2-3 at a time, not all at once.

Required Questions

#QuestionCollects
1What is the end goal?loop.name + objective
2Which files/scope to modify?loop.modify
3How to run after modification?loop.run
4How to evaluate results?loop.evaluate
5Keep/discard/refine criteria?loop.judge
6Constraints? (off-limits files, time, preservation zones)loop.constraints
7When to stop?loop.exit

Skip rules

  • Already answered in task description → fill without asking.
  • Clearly inferable from context → fill without asking.
  • At minimum, secure modify, run, evaluate.

Confirmation

Show the loop definition YAML and get user approval before starting. For L0 tasks: one-line summary suffices — "Proceeding like this: [summary]. Object if not."

2. Loop Protocol

[Plan] → [Define] → [Execute] → [Evaluate] → [Judge] → [Record] → [Repeat/Exit]

[Plan]

  • No definition → run section 1 questions.
  • Has definition → proceed to [Define].
  • Milestone-scale planning → escalate to L3 (see below).

Brainstorming (for non-trivial planning): Don't adopt the first approach that comes to mind. Dispatch a worker (§6a) with a brainstorming prompt: generate N variations on different constraints / priorities / trade-offs, return as a list without committing to any. Main then cross-compares the variations and presents options to the user. This is a L2 worker spawn at the [Plan] phase, not at [Execute]. The worker's output goes back to main for user presentation, not directly to [Define].

Milestone planning (absorbed from plan skill): When user requests "create roadmap", "restructure milestones", or other structural changes to progress.md, escalate to L3. Planning questions:

  1. What is the end goal?
  2. Any deadlines?
  3. How large should milestones be?
  4. Anything that needs to start immediately?

Draft progress.md from answers, present for user review. Use 3-tier structure: Milestone > Phase > Task with [x]/[ ] checkboxes. Scribe handles checkbox updates after this point.

[Define]

  • Finalize loop definition YAML for this iteration.
  • Decide specifically what to modify this round.
  • First iteration: establish baseline (current test results, current metrics).

[Execute]

  • Check git tracking before modifying files.
    • Tracked: restore via git restore on discard.
    • Untracked: keep original in memory for discard recovery.
  • Modify only within loop.modify scope.
  • Check loop.constraints before modifying.
  • Run loop.run command. Collect output.

[Evaluate]

  • Measure results against loop.evaluate criteria.
  • Compare with previous iteration (or baseline if first).
  • Present evaluation with numbers and rationale.

[Judge] — 3-way decision

JudgmentConditionGit action
keeploop.judge.keep metSelf-review → guard (operational) → witness (intent-match) → commit
discardloop.judge.discard metgit restore (revert)
refinePartial improvementKeep good parts, fix bad parts, re-execute

keep pipeline — three gates in order. Each can downgrade the judgment, but they are not three equally-strong layers; they are a cheap-first ordering with honest labeling of what each gate actually provides.

  1. Self-review (main, System 1) — quick re-read of the diff by the same agent that wrote it. This is not structural isolation — it is the remnant discipline layer that the sonmat architecture admits cannot be eliminated (cf. memory/domain/discipline_forced_protocols.md §Core Tension). Its role is to catch obvious slips cheaply before spending on subagent spawns. Treat it as a noise filter, not as verification. If the loop ever relies on self-review as the only gate, the architecture is broken.
  2. Guard (main, verification checks) — pre-commit test execution, sensitive-file blocking, discipline conformance, novel-trap detection. Runs in-context. Still main-side but oriented around structural rules (file patterns, test results) rather than self-interpretation of intent. See skills/guard/SKILL.md.
  3. Witness (spawned subagent, protocol-isolated) — intent-artifact match. Spawned with user-turn cascade as the only input. Main's chain-of-thought is excluded at the spawn-prompt layer (discipline) and at the execution-context layer (harness-enforced); see agents/sonmat-witness.md §Isolation stack for the honest breakdown of what that means on current Claude Code. Whether to spawn witness for a given commit is a structural decision set in loop.yaml (witness.commit: required | optional | skip) — never a main runtime judgment call. If the loop definition is silent, default to required.

Any gate returning a blocking verdict (guard block / witness BLOCK) → judgment becomes refine, not keep. Non-blocking findings (guard warning / witness WARN) → surface to user but proceed if user confirms.

Note on witness verdict reliability: witness's comparator discipline (citing from valid sources only, source-based verdict determination, refusing strength judgment) is prompt-level, not runtime-enforced — see agents/sonmat-witness.md §Isolation stack for the honest breakdown. Early uses of witness should be sampled by a human reviewer to validate that its verdicts actually follow the specified rules. If drift is observed (e.g., verdicts without citations, strength-based WARN assignments), the agent file needs adjustment — the journal is the right place to log these events (scribe captures witness verdicts for exactly this purpose).

The three-gate order is deliberate: cheap checks first, structurally-isolated check last (because it costs a spawn). Witness is the final gate because its isolation is most valuable on content that a cheaper gate would not have caught anyway. The three gates are complementary layers of a Swiss cheese model — not redundant, not interchangeable, and definitely not substitutable. Self-review alone is the thinnest possible layer; guard + witness together is the minimum honest stack.

Preservation zones (subjective domains like writing): If refine/discard reveals "the previous version was better" for certain parts, add those to loop.constraints. Update zones each iteration with user confirmation.

Escalation check: At every judgment, self-check FOR (Feeling of Rightness) against the 4 triggers (section 5). If any trigger fires → escalate.

[Record]

  • keep: commit message includes iteration # and metric change.
  • discard: record why (prevent same mistake next iteration).
  • refine: record what to keep and what to fix.

[Repeat/Exit]

  • loop.exit met → end loop, produce final report.
  • Not met → return to [Define].
  • On exit: total iterations, metric trajectory, final state.
  • Loop Artifact: If context should carry to a follow-up loop, record: output paths, key results, constraints for next loop.

Forest-scale witness check (on exit, before scribe):

Before dispatching scribe, spawn witness at session forest scope if any of these conditions hold:

ConditionWitness scope
Session touched 3+ distinct filessession-forest
Any user turn in the session contains a scope-broadening phrase ("전체", "모든", "시스템 전반", "일관되게", "across all", etc.)principle-coverage
loop.yaml declares witness.forest: requiredAs declared

Forest-scale witness receives (a) the full session's user-turn cascade and (b) the session's accumulated git diff. Its findings route as follows:

  • PASS or WARN → continue to scribe dispatch. WARN surfaces to user verbatim; user can override.
  • BLOCK → do not dispatch scribe yet. Report BLOCK findings to user. Loop exit is paused; user decides to fix (return to [Execute]) or override (proceed with acknowledged mismatch).
  • INSUFFICIENT_GROUND_TRUTH → report to user, proceed to scribe dispatch.

This is the structural equivalent of the "forest review" that main alone cannot reliably perform at session end — a comparator running with user-turn isolation catches the multi-file partial application / dead-reference class of misses that main's chain-of-thought would rubber-stamp. See agents/sonmat-witness.md §Scope scales for the full definition.

Scribe dispatch (on exit, after forest witness):

  • keep: Dispatch scribe with mode all (bridge + journal + progress). Include loop report, git diff, and forest-witness verdict as artifacts.
  • discard: Dispatch scribe with mode journal only. Record what was tried and why it failed.
  • Scribe runs in background. Do NOT wait for it. Proceed with user interaction immediately.

Retrospective (after 3+ iterations)

  • Was the approach order optimal?
  • Where did intent diverge from result?
  • What untried approach might have been better?
  • Include 1-2 line summary in loop report.

Memory update (on loop exit)

After retrospective, check: did this loop reveal a lesson not already in sonmat memory?

  • If yes → dispatch to scribe as a novel-trap-like payload (pattern, context, catch-signal). Scribe handles the abstraction, user confirmation, and memory write. See skills/scribe/SKILL.md §Novel Trap Recording.
  • If multiple project lessons have accumulated, check if any should be promoted to universal memory (inductive review) — this is also scribe's dispatch.

3. Loop Definition Templates

Dev loop

loop:
  name: "Feature / bug fix"
  modify: "src/ relevant files"
  run: "uv run pytest tests/ -v"
  evaluate:
    metrics: ["test_pass_rate"]
  judge:
    keep: "All tests pass"
    discard: "Existing tests broken"
    refine: "New tests pass, some existing fail"
  witness:
    commit: required    # per-iteration commit gate
    forest: required    # loop-exit forest check
  exit: "All tests pass + self-review done"

Writing loop

loop:
  name: "Editing pass"
  modify: "target document"
  run: "One editing pass — show diff"
  evaluate:
    criteria: ["consistency", "flow", "conciseness"]
    require_user_confirmation: true
  judge:
    keep: "Improved over previous"
    discard: "Worse — original was better"
    refine: "Partly improved, partly over-edited"
  witness:
    commit: optional    # subjective domain — witness is advisory
    forest: required    # still worth checking at exit
  exit: "Fewer than 5 changes in a pass"

require_user_confirmation: true — for domains where automated judgment isn't reliable (writing, design). Must show changes and get approval before keep/discard.

witness field reference

Every loop definition should specify witness scopes. If omitted, commit: required and forest: required are the defaults.

FieldValuesMeaning
witness.commitrequired | optional | skipWhether the commit-gate witness runs in [Judge] keep pipeline. optional means witness runs but findings surface as advisory; skip disables entirely (use only for subjective domains where intent-match is inherently ambiguous).
witness.forestrequired | optional | skipWhether the session-forest witness runs at loop exit. Defaults to required when the session touched 3+ files or the user issued a scope-broadening directive; skip is only appropriate for explicitly single-file loops.

witness.commit: skip is the main-runtime bypass that the main agent is not allowed to grant — it must be declared in loop.yaml up-front, not decided on the fly. See agents/sonmat-witness.md §When witness is invoked for the rationale.

4. Discipline Injection

Injection order

  1. Load core.md (always)
  2. Load hints.md (always — worker applies what's relevant)
  3. Apply project CLAUDE.md overrides (if any ## sonmat section exists)
  4. Inject into System 1 processing or System 2 worker prompt

Exclusion: witness is never injected with discipline. Witness is a comparator, not a rule-follower; its own operating principles are embedded in the agent definition itself and are distinct from core.md discipline (cf. agents/sonmat-witness.md §Operating principles). The only inputs witness receives are raw user turns and the artifact — nothing else.

Project override format

## sonmat
discipline:
  add:
    - "Custom rule for this project"

Worker prompt composition (L2/L3)

[1. Role]       — 1 line. Debugger/executor/researcher/reviewer.
[2. Discipline] — core.md + hints.md + project overrides. ~30 lines.
[3. Loop context] — Loop definition YAML + current iteration state.
[4. Task]       — Specific work instructions + reporting format.

5. Escalation System

Based on dual-process theory. System 1 handles by default; escalate to System 2 when FOR (Feeling of Rightness) drops.

4 Triggers

TriggerDetectionExample
SurpriseExpected ≠ actual resultTest expected to pass but failed
ErrorSame failure 2+, fix breaks anotherSame test fails twice
Fluency breakMissing reference, unclear scopeFile/path not found
ConflictAction vs core.md rules or loop plan clashCore.md rule violation detected, or action would contradict loop.constraints

4 Levels

LevelNameAction
L0System 1Direct execution, no escalation
L1System 1 enhancedPause, check impact scope
L2System 2 spawnSpawn 1 sonmat-worker (deep analysis)
L3System 2 extendedSpawn multiple workers in parallel

Trigger → Level mapping

SituationLevel
First unexpected resultL0 → L1
Same failure 2xL1 → L2
Fix breaks something else→ L2
Missing file/pathL0 → L1 (search, retry)
Dependency missing + unclear scope→ L2
Core.md rule violation→ L1
Scope change vs existing plan→ L2
Milestone-scale planning→ L3
L2 worker can't resolve→ L3

Escalation output

⚡ [Trigger] detected
  Cause: [specific cause]
  Action: L[N] → [what will be done]
  💡 Tip: [customization suggestion] (when applicable)

Resolution output

✓ [Trigger] resolved → L[N] return ([brief explanation])

6. Subagent Dispatch & Routing

autoloop spawns two distinct subagent types, with different purposes, inputs, and routing rules. They are documented together here because the spawn-and-route pattern is common, but they are not interchangeable.

SubagentPurposeInputWhen spawned
sonmat-workerExecute deep analysis or implementation steps that exceed System 1 capacitydiscipline-injected prompt + loop context + task instructionsL2/L3 escalation during [Execute], or [Plan] brainstorming
sonmat-witnessIntent-artifact match verification in isolated contextraw user-turn cascade + artifact (git diff / files) — no discipline injection, no main CoT[Judge] keep pipeline (commit gate) + [Repeat/Exit] (session forest)

6a. Worker dispatch

L2: Single worker

Spawn sonmat-worker with the prompt from section 4 (Discipline Injection). Worker receives full discipline.

L3: Parallel workers

  • Split into independent tasks (no file overlap).
  • Same discipline, different task instructions.
  • Wait for all → check conflicts → merge or escalate to user.

Worker status → loop routing

StatusLoop action
DONEPass to [Evaluate]
DONE_WITH_CONCERNSPass to [Evaluate] + report concerns to user
NEEDS_CONTEXTProvide more context or ask user
BLOCKEDEscalate to L3 or delegate to user

If worker needs to modify files outside loop.modify, it must report the need — not modify directly. Main session asks user to expand scope.

6b. Witness dispatch

Witness is not a worker. It does not receive discipline, does not execute tasks, and does not modify state. Its only job is comparator verification in protocol isolation from main's reasoning (agents/sonmat-witness.md §Isolation stack).

How witness is actually spawned: via the Task tool with subagent_type: sonmat-witness, invoked from within autoloop's [Judge] keep pipeline and [Repeat/Exit] forest check. This is a documented, supported path — Task tool subagent delegation is the native Claude Code primitive for spawning isolated subagents. Earlier drafts of this document referred to a "PreToolUse hook → agent hook → deny" pipeline; that path turned out to be undocumented for PreToolUse specifically, and is not the path we use. The enforcement model is autoloop discipline: main must follow the [Judge] pipeline sequence, and the witness Task call is one step in that sequence. This is the same discipline-enforcement model as all other autoloop phases.

Spawn points:

  • [Judge] keep pipeline — commit-gate scope, per iteration. Gated by loop.witness.commit.
  • [Repeat/Exit] — session-forest scope, at loop exit. Gated by loop.witness.forest.

Spawn prompt composition is different from worker's:

[1. Scope]    — commit | session-forest | principle-coverage
[2. User turns] — raw, unmodified. Session cascade for forest scope; task cascade for commit.
[3. Artifact]  — git diff + file paths. No summary.
[4. Principle candidate] — (optional, principle-coverage only) literal phrase anchored to user turns

Never include: discipline/core.md, hints.md, main's chain-of-thought, main's application notes, worker reports, or commit messages as separate inputs. Comments and commit messages embedded in the artifact are visible but citation-invalid (see witness.md §Seen-but-unusable).

Witness verdict → loop routing

VerdictLoop action
PASSCommit / session-exit proceeds. Record verdict in journal (via scribe dispatch).
BLOCKCommit-scope: judgment downgraded to refine, cited mismatch becomes the next [Execute] target. Forest-scope: session-exit paused, findings reported to user, user decides fix or override. Do not retry witness on the same artifact without a real change in between.
WARNSurface to user verbatim (citation included). User confirms → proceed. User rejects → refine.
INSUFFICIENT_GROUND_TRUTHWitness could not run its checks. Report to user that the operation is proceeding without intent-match verification. Do not silently suppress.

Witness verdicts are never overridden by main's self-judgment. If main believes witness is wrong, escalate to user — never auto-bypass. This is the structural-isolation principle; bypassing it defeats the mechanism.

7. User Growth

Philosophy: "There are no bad users." Transparency in every judgment enables growth.

3 Principles

  1. Open customization surface: Loop definitions, discipline overrides, project rules — always modifiable. Actively show where.
  2. Just-in-time guidance: On escalation, suggest how to prevent it next time. Never force.
  3. Transparent judgment: Every keep/discard/refine and escalation includes "why".

Loop report format

📊 Loop Report
  N iterations | keep M | discard K | refine J
  Escalations: [summary or "none"]
  Retrospective: [1-2 lines, if 3+ iterations]
  Result: [final state]

Simple loops (1 keep, done): 📊 1 iteration. [result]. No escalation.