Navigator Loop Skill
Execute tasks iteratively until completion with structured signals, stagnation detection, and dual-condition exit gates.
Why This Exists
Traditional AI coding requires manual "keep going" prompts. Navigator Loop provides:
- Structured completion signals (NAVIGATOR_STATUS block)
- Dual-condition exit gate (heuristics + explicit signal)
- Stagnation detection (circuit breaker for stuck loops)
- Progress visibility (phases: INIT → RESEARCH → IMPL → VERIFY → COMPLETE)
Based on Ralph's autonomous loop innovations, adapted for Navigator's context-efficient architecture.
When to Invoke
Auto-invoke when:
- User says "run until done", "keep going until complete"
- User says "iterate until finished", "autonomous mode"
- User says "loop mode", "don't stop until done"
- Task document has
loop_mode: true
DO NOT invoke if:
- Single-step task (no iteration needed)
- User says "just do this once"
- Already in loop mode (prevent nested loops)
- User explicitly disabled loop mode
Configuration
Loop mode settings in .agent/.nav-config.json:
json{ "loop_mode": { "enabled": false, "max_iterations": 5, "stagnation_threshold": 3, "exit_requires_explicit_signal": true, "show_status_block": true, "iteration_approval": "none", "periodic_interval": 3, "never_pause_on_stagnation": false, "stagnation_diversify_strategy": "combine" } }
Core options:
enabled: Default state for new tasksmax_iterations: Hard cap to prevent infinite loops (1-20)stagnation_threshold: Same-state count before pause (2-5)exit_requires_explicit_signal: Require EXIT_SIGNAL alongside heuristicsshow_status_block: Render NAVIGATOR_STATUS each iteration
Autonomous / overnight options (v6.2.2+):
iteration_approval: When to prompt the user for accept/reject between iterations."none"(default) — never prompt; loop runs uninterrupted"strict"— prompt after every iteration"periodic"— prompt every N iterations (where N =periodic_interval, default 3)
periodic_interval: Wheniteration_approval == "periodic", the cadence of prompts. Default 3 (every 3rd iteration). Set higher for less frequent check-ins on long overnight runs (e.g., 5 or 10).never_pause_on_stagnation: Iftrue, stagnation triggers auto-diversification instead of anAskUserQuestionpause. Required for true overnight runs. Inspired by karpathy/autoresearch's NEVER STOP directive.stagnation_diversify_strategy: Which recovery to attempt whennever_pause_on_stagnationfires."combine"— combine previous near-misses / partially-met indicators"radical"— try a substantially different approach (re-architect, swap library)"reread"— re-read the in-scope task/system docs for missed signals
Safety guard: Setting never_pause_on_stagnation: true REQUIRES max_iterations to be set explicitly (the default of 5 is fine; the point is — no infinite default). Without a max, an autonomous loop can spin forever on a fundamentally broken task.
Execution Steps
Step 1: Initialize Loop State
Load configuration:
bashpython3 functions/phase_detector.py --init
Initialize tracking variables:
iteration = 1 max_iterations = config.loop_mode.max_iterations or 5 stagnation_threshold = config.loop_mode.stagnation_threshold or 3 hash_history = [] phase = "INIT"
Display loop start:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ LOOP MODE ACTIVATED ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Task: {TASK_DESCRIPTION} Max iterations: {max_iterations} Stagnation threshold: {stagnation_threshold} Starting iteration 1... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Step 2: Execute Iteration
Perform task work based on current phase:
| Phase | Actions |
|---|---|
| INIT | Load context, understand requirements |
| RESEARCH | Explore codebase, find patterns |
| IMPL | Write code, make changes |
| VERIFY | Run tests, validate functionality, simplify code |
| COMPLETE | All indicators met, ready to exit |
Track changes during iteration:
- Files read (for RESEARCH detection)
- Files changed (for IMPL detection)
- Tests run (for VERIFY detection)
- Commits made (for completion indicator)
Step 3: Generate Status Block
After each iteration, generate NAVIGATOR_STATUS:
bashpython3 functions/status_generator.py \ --phase "{phase}" \ --iteration "{iteration}" \ --max-iterations "{max_iterations}" \ --indicators "{indicators_json}" \ --state-hash "{current_hash}" \ --prev-hash "{previous_hash}" \ --stagnation-count "{stagnation_count}"
Display status block:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ NAVIGATOR_STATUS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Phase: {PHASE} Iteration: {N}/{MAX} Progress: {PERCENT}% Completion Indicators: [{x or space}] Code changes committed [{x or space}] Tests passing [{x or space}] Code simplified [{x or space}] Documentation updated [{x or space}] Ticket closed [{x or space}] Marker created Exit Conditions: Heuristics: {MET}/{TOTAL} (need 2+) EXIT_SIGNAL: {true/false} State Hash: {HASH} Previous Hash: {PREV_HASH} Stagnation: {COUNT}/{THRESHOLD} Next Action: {NEXT_ACTION} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Step 3.5: Per-Iteration Approval Gate (optional)
Skip this step if config.loop_mode.iteration_approval == "none" (default).
Run this step if the user wants oversight between iterations — for risky changes, learning the loop's behavior, or sanity-checking before a long run.
| Setting | Behavior |
|---|---|
"none" | Never prompt. Loop continues to Step 4. |
"strict" | Prompt after every iteration. |
"periodic" | Prompt every Nth iteration. N defaults to 3; configurable via loop_mode.periodic_interval. |
When prompting, use AskUserQuestion immediately after the status block:
Question: "Accept iteration {N} and continue?" Options: 1. [Continue] - Iteration accepted, proceed to next 2. [Adjust] - Provide feedback, incorporate into next iteration 3. [Abort] - End loop, create partial-completion marker
Decision handling:
- Continue: Proceed to Step 4 normally.
- Adjust: Capture the user's feedback into a transient note, do NOT advance hash history (so the next iteration is judged as fresh progress), continue to Step 4.
- Abort: Jump to Step 8 (Cleanup) with
status: "user_aborted".
This gate runs BEFORE stagnation detection so that a rejected iteration doesn't accidentally accumulate stagnation count.
Step 4: Check Stagnation
Calculate state hash:
bashpython3 functions/stagnation_detector.py \ --phase "{phase}" \ --indicators "{indicators_json}" \ --files-changed "{files_json}" \ --history "{hash_history_json}"
If stagnation detected (same hash for N iterations), the response depends on never_pause_on_stagnation.
Default behavior (never_pause_on_stagnation: false)
Prompt the user:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ STAGNATION DETECTED ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Same state detected for {N} consecutive iterations. Current State: Phase: {PHASE} Indicators: {MET}/{TOTAL} Last Action: {LAST_ACTION} Possible causes: 1. Blocked by external dependency 2. Unclear requirements 3. Test failures preventing progress 4. Missing context or permissions Options: 1. [Continue] - Try one more iteration 2. [Clarify] - Explain what's blocking 3. [Abort] - End loop, manual intervention ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Use AskUserQuestion for choice:
- Continue: Reset stagnation counter, continue loop
- Clarify: User explains blocker, incorporate and continue
- Abort: Exit loop with partial completion marker
Autonomous behavior (never_pause_on_stagnation: true)
The loop is running unattended (overnight, CI, etc.). Do NOT prompt — auto-diversify based on stagnation_diversify_strategy:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ STAGNATION → AUTO-DIVERSIFY ({STRATEGY}) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Same state for {N} iterations. Auto-recovery: {STRATEGY} Stagnation counter reset. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
| Strategy | What to attempt next iteration |
|---|---|
combine | Re-examine partially-met indicators; combine 2 near-miss approaches from previous iterations |
radical | Discard the current approach; try a substantially different design (different library, different architecture, different algorithm) |
reread | Re-read the in-scope task doc + relevant system docs; look for a missed signal or constraint |
After diversifying:
- Reset stagnation counter to 0
- Record the diversification in the iteration's notes (so the next status block reflects it)
- Continue to Step 5
Hard stop: Even in autonomous mode, the loop still terminates on max_iterations. If diversification has been triggered ≥3 times within a single run, escalate to the abort path (creates a loop-aborted marker and exits) — repeated diversification is itself a signal that the task is fundamentally stuck.
Inspired by karpathy/autoresearch's NEVER STOP directive: "If you run out of ideas, think harder — read papers, re-read in-scope files for new angles, try combining previous near-misses, try more radical architectural changes."
Step 5: Check Exit Conditions
Evaluate dual-condition gate:
bashpython3 functions/exit_gate.py \ --indicators "{indicators_json}" \ --exit-signal "{exit_signal}" \ --require-explicit "{config.exit_requires_explicit_signal}"
Exit conditions:
- Heuristics: At least 2 completion indicators met
- EXIT_SIGNAL: Explicit signal that task is complete
Completion indicators (mapped from autonomous protocol):
code_committed: Changes committed to gittests_passing: Test suite passes (exit code 0)code_simplified: Code simplified for clarity (v5.4.0+)docs_updated: Documentation files changedticket_closed: PM tool ticket marked donemarker_created: Completion marker exists
Exit decision logic:
IF heuristics >= 2 AND exit_signal == true: → EXIT: Task complete ELIF heuristics >= 2 AND exit_signal == false: → CONTINUE: Awaiting explicit completion signal ELIF exit_signal == true AND heuristics < 2: → BLOCKED: Cannot exit with insufficient indicators ELSE: → CONTINUE: More work needed
Step 6: Handle Max Iterations
If iteration >= max_iterations:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MAX ITERATIONS REACHED ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Completed {MAX} iterations without full completion. Current State: Phase: {PHASE} Indicators: {MET}/{TOTAL} EXIT_SIGNAL: {true/false} Progress made: - {PROGRESS_ITEM_1} - {PROGRESS_ITEM_2} Options: 1. [Extend] - Add 3 more iterations 2. [Complete] - Accept current state as done 3. [Abort] - Exit without completion ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Step 7: Complete Loop
When exit conditions met, emit the exit signal in JSON format and display completion:
pilot{"v":2,"type":"exit","success":true,"reason":"All criteria met"}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ LOOP COMPLETE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Task: {TASK_DESCRIPTION} Iterations: {FINAL_COUNT}/{MAX} Final Phase: COMPLETE Completion Indicators: [x] Code changes committed [x] Tests passing [x] Code simplified [x] Documentation updated [ ] Ticket closed (skipped - no PM tool) [x] Marker created Exit Conditions: Heuristics: 4/5 (passed) EXIT_SIGNAL: true (passed) Summary: - {KEY_CHANGE_1} - {KEY_CHANGE_2} - {KEY_CHANGE_3} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Execute autonomous completion protocol:
- Commit changes (if not already)
- Archive task documentation
- Close ticket (if PM configured)
- Create completion marker (with loop state)
- Suggest compact
Setting EXIT_SIGNAL
The EXIT_SIGNAL is set explicitly by Claude when:
- All primary task requirements are met
- Code is functional and tested
- No obvious remaining work
How to signal completion (v2 JSON format):
pilot{"v":2,"type":"exit","success":true,"reason":"All requirements met"}
The JSON format in a pilot-signal code block ensures unambiguous detection by Pilot automation. The reason field should briefly describe why the task is complete.
Signal fields:
v: Version (always2)type: Signal type (always"exit"for completion)success: Whether task completed successfully (true/false)reason: Brief explanation of completion state
This explicit declaration prevents premature exits when heuristics are met but work remains.
Phase Detection
Phases auto-detected based on context:
pythondef detect_phase(context): # COMPLETE: Exit conditions met if indicators_met >= 4 and exit_signal: return "COMPLETE" # VERIFY: Tests running or recently run if context.tests_running or context.test_exit_code is not None: return "VERIFY" # IMPL: Files being modified if context.files_changed: return "IMPL" # RESEARCH: Reading files, searching if context.files_read and not context.files_changed: return "RESEARCH" # INIT: Default starting state return "INIT"
Integration with Navigator
With Autonomous Completion
Loop mode enhances (not replaces) the autonomous protocol:
- Completion indicators map to autonomous steps
- EXIT_SIGNAL triggers autonomous completion
- Marker includes loop state for restoration
With nav-simplify (v5.4.0+)
Simplification runs during VERIFY phase:
- After tests pass, before committing
- Configurable via
simplification.enabledin .nav-config.json - Adds
code_simplifiedcompletion indicator - Skip if no code changes (docs-only tasks)
With nav-diagnose
Stagnation triggers nav-diagnose quality check:
- 3 same-state loops = potential quality issue
- nav-diagnose helps identify root cause
- Re-anchoring can resolve stuck loops
With nav-marker
Markers capture loop state:
- Current iteration and max
- Phase at time of marker
- State hash for continuity
- Completion indicators status
With ToM Features
Loop mode respects ToM configuration:
- Verification checkpoints still apply in VERIFY phase
- Profile preferences affect communication style
- Belief anchors can help clarify stuck states
Predefined Functions
functions/status_generator.py
Generates formatted NAVIGATOR_STATUS block.
functions/exit_gate.py
Evaluates dual-condition exit (heuristics + explicit signal).
functions/stagnation_detector.py
Calculates state hash and detects consecutive same-states.
functions/phase_detector.py
Auto-detects current task phase from context.
Error Handling
Config not found:
Loop mode config not found in .nav-config.json. Using defaults: max_iterations=5, stagnation_threshold=3
Function execution fails:
- Fall back to manual evaluation
- Log error but don't interrupt loop
- Continue with best-effort phase detection
User aborts mid-loop:
- Create partial completion marker
- Document progress made
- List remaining work
Success Criteria
Loop mode succeeds when:
- Task completes within max_iterations
- No stagnation pauses (or resolved quickly)
- EXIT_SIGNAL + heuristics both satisfied
- Completion marker includes loop state
- User sees clear progress each iteration
Examples
Example 1: Simple Feature
User: "Run until done: add isPrime function with tests" Iteration 1 (INIT → RESEARCH): - Read existing math utils - Found test patterns Iteration 2 (IMPL): - Created isPrime function - Created test file Iteration 3 (VERIFY): - Ran tests: PASS - Committed changes
pilot{"v":2,"type":"exit","success":true,"reason":"isPrime function implemented and tests passing"}
→ Loop complete in 3 iterations
Example 2: Stagnation Recovery
User: "Run until done: fix authentication bug" Iteration 1-3 (IMPL): - Same changes attempted - Tests still failing - State hash unchanged → STAGNATION DETECTED User: "The test needs a mock for the auth service" Iteration 4 (IMPL): - Added mock - Tests pass
pilot{"v":2,"type":"exit","success":true,"reason":"Auth bug fixed with mock service"}
→ Loop complete in 4 iterations
Limitations
Cannot handle:
- External blockers (waiting for API, permissions)
- Subjective completion criteria ("make it look nice")
- Tasks requiring human judgment mid-loop
Should not use for:
- Quick fixes (single iteration sufficient)
- Exploratory work (no clear completion state)
- Tasks with security implications (need human review)
This skill provides Ralph-style "run until done" capability while maintaining Navigator's context efficiency and ToM integration.

