create-merlin-brain 2.3.2 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,6 +37,12 @@ source "$SCRIPT_DIR/lib/state.sh"
37
37
  source "$SCRIPT_DIR/lib/safety.sh"
38
38
  source "$SCRIPT_DIR/lib/progress.sh"
39
39
  source "$SCRIPT_DIR/lib/context.sh"
40
+ source "$SCRIPT_DIR/lib/modes.sh"
41
+ source "$SCRIPT_DIR/lib/sights.sh" 2>/dev/null || true # Sights integration
42
+ source "$SCRIPT_DIR/lib/agents.sh" 2>/dev/null || true # Agent profiles and routing
43
+ source "$SCRIPT_DIR/lib/boot.sh" 2>/dev/null || true # Boot sequence
44
+ source "$SCRIPT_DIR/lib/session-end.sh" 2>/dev/null || true # Session end protocol
45
+ source "$SCRIPT_DIR/lib/tui.sh" 2>/dev/null || true # Interactive TUI
40
46
 
41
47
  # Defaults (can be overridden via config.json or env vars)
42
48
  MAX_ITERATIONS="${MERLIN_MAX_ITERATIONS:-50}"
@@ -46,6 +52,14 @@ RATE_LIMIT_PER_HOUR="${MERLIN_RATE_LIMIT:-100}"
46
52
  CLOUD_SYNC="${MERLIN_CLOUD_SYNC:-true}"
47
53
  NOTIFY_ON_COMPLETE="${MERLIN_NOTIFY:-true}"
48
54
 
55
+ # Loop mode configuration (auto, interactive, hybrid)
56
+ LOOP_MODE="${MERLIN_LOOP_MODE:-hybrid}"
57
+ PAUSE_INTERVAL="${MERLIN_PAUSE_INTERVAL:-5}" # Pause every N tasks in hybrid mode
58
+
59
+ # Timeout configuration
60
+ PAUSE_TIMEOUT="${MERLIN_PAUSE_TIMEOUT:-300}" # 5 minutes default
61
+ TIMEOUT_ENABLED="${MERLIN_TIMEOUT_ENABLED:-true}"
62
+
49
63
  # Native Claude Tasks integration
50
64
  # This enables cross-session task coordination - all spawned instances share task state
51
65
  # If not provided, we'll generate one based on project directory
@@ -159,11 +173,13 @@ show_launch_screen() {
159
173
  echo ""
160
174
  echo -e " ${YELLOW}${BOLD}▸ STARTING AUTONOMOUS BUILD${RESET}"
161
175
  echo ""
162
- echo -e " ${CYAN}Mode:${RESET} ${BOLD}$mode${RESET}"
176
+ echo -e " ${CYAN}Command:${RESET} ${BOLD}$mode${RESET}"
177
+ echo -e " ${CYAN}Loop Mode:${RESET} ${BOLD}$(get_mode_display)${RESET}"
163
178
  echo -e " ${CYAN}AI:${RESET} ${BOLD}$ai_cli${RESET}"
164
179
  echo -e " ${CYAN}Max Iterations:${RESET} ${BOLD}$MAX_ITERATIONS${RESET}"
165
180
  echo -e " ${CYAN}Cooldown:${RESET} ${BOLD}${COOLDOWN_SECONDS}s${RESET} between iterations"
166
181
  echo -e " ${CYAN}Circuit Breaker:${RESET}${BOLD}$CIRCUIT_BREAKER_THRESHOLD${RESET} errors to stop"
182
+ echo -e " ${CYAN}Pause Timeout:${RESET} ${BOLD}$(get_timeout_status 2>/dev/null || echo "${PAUSE_TIMEOUT}s")${RESET}"
167
183
  echo -e " ${CYAN}Cloud Sync:${RESET} ${BOLD}$CLOUD_SYNC${RESET}"
168
184
  echo -e " ${CYAN}Task List:${RESET} ${BOLD}${TASK_LIST_ID:-auto}${RESET}"
169
185
  echo ""
@@ -198,6 +214,7 @@ show_launch_screen() {
198
214
 
199
215
  init_loop() {
200
216
  mkdir -p "$LOOP_DIR"
217
+ LOOP_START_TIME=$(date +%s)
201
218
 
202
219
  # Check for existing lock (another loop running)
203
220
  if [ -f "$LOCK_FILE" ]; then
@@ -236,9 +253,95 @@ init_loop() {
236
253
  if [ "$CLOUD_SYNC" = "true" ]; then
237
254
  sync_from_cloud
238
255
  fi
256
+
257
+ # Initialize Sights (includes worker registration)
258
+ if type init_sights &> /dev/null; then
259
+ init_sights
260
+ echo -e "${GREEN}✓ Sights: Connected${RESET}"
261
+ fi
262
+
263
+ # Check for cloud checkpoint and offer restore
264
+ if type fetch_checkpoint &> /dev/null; then
265
+ local checkpoint_json
266
+ checkpoint_json=$(fetch_checkpoint 2>/dev/null || echo "")
267
+
268
+ if [ -n "$checkpoint_json" ]; then
269
+ local has_checkpoint
270
+ has_checkpoint=$(echo "$checkpoint_json" | jq -r '.checkpoint != null' 2>/dev/null || echo "false")
271
+
272
+ if [ "$has_checkpoint" = "true" ]; then
273
+ echo ""
274
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
275
+ echo -e "${BOLD}📍 Cloud Checkpoint Found${RESET}"
276
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
277
+ format_checkpoint "$checkpoint_json"
278
+ echo ""
279
+
280
+ if [ "${QUIET:-false}" != "true" ] && [ -t 0 ]; then
281
+ echo -e "${YELLOW}Resume from this checkpoint?${RESET}"
282
+ echo -e " [${BOLD}y${RESET}] Yes, continue from checkpoint"
283
+ echo -e " [${BOLD}n${RESET}] No, start fresh"
284
+ echo -ne " Choice: "
285
+ read -r choice
286
+
287
+ if [ "$choice" = "y" ] || [ "$choice" = "Y" ]; then
288
+ # Restore checkpoint state to local state
289
+ local phase task summary
290
+ phase=$(echo "$checkpoint_json" | jq -r '.checkpoint.currentPhase // empty')
291
+ task=$(echo "$checkpoint_json" | jq -r '.checkpoint.currentTask // empty')
292
+ summary=$(echo "$checkpoint_json" | jq -r '.checkpoint.summary // empty')
293
+
294
+ if [ -n "$phase" ]; then
295
+ set_state_value "plan.current_phase" "$phase"
296
+ fi
297
+ if [ -n "$task" ] && [ "$task" != "null" ]; then
298
+ set_state_value "plan.current_task" "$task"
299
+ fi
300
+
301
+ echo -e "${GREEN}✓ Checkpoint restored${RESET}"
302
+ echo ""
303
+ fi
304
+ fi
305
+ fi
306
+ fi
307
+ fi
308
+
309
+ # Start worker heartbeat in background
310
+ if type start_heartbeat &> /dev/null; then
311
+ start_heartbeat 30 # Send heartbeat every 30 seconds
312
+ echo -e "${BLUE}Worker heartbeat started${RESET}"
313
+ fi
314
+
315
+ # Check for other active workers (multi-user awareness)
316
+ if type get_active_workers &> /dev/null; then
317
+ local workers_json
318
+ workers_json=$(get_active_workers 2>/dev/null || echo "")
319
+
320
+ if [ -n "$workers_json" ]; then
321
+ local worker_count
322
+ worker_count=$(echo "$workers_json" | jq -r '.count // 0' 2>/dev/null || echo "0")
323
+
324
+ if [ "$worker_count" -gt 1 ]; then
325
+ echo ""
326
+ echo -e "${YELLOW}⚠️ ${worker_count} workers active on this repository${RESET}"
327
+ echo -e "${YELLOW} Be aware of potential task conflicts.${RESET}"
328
+ echo ""
329
+ fi
330
+ fi
331
+ fi
239
332
  }
240
333
 
241
334
  cleanup() {
335
+ # Stop worker heartbeat
336
+ if type stop_heartbeat &> /dev/null; then
337
+ stop_heartbeat
338
+ fi
339
+
340
+ # Run quick session end on cleanup (commit + checkpoint without verbose output)
341
+ if type session_end_quick &> /dev/null; then
342
+ session_end_quick "Loop stopped (cleanup)" "" 2>/dev/null || true
343
+ fi
344
+
242
345
  rm -f "$LOCK_FILE"
243
346
 
244
347
  # Final cloud sync
@@ -252,16 +355,36 @@ run_iteration() {
252
355
  local iteration="$2"
253
356
  local prompt_file="$SCRIPT_DIR/prompts/PROMPT_${mode}.md"
254
357
 
255
- echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
256
- echo -e "${BOLD}Iteration $iteration / $MAX_ITERATIONS${RESET} (mode: $mode)"
257
- echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
358
+ # Get current task info
359
+ local current_task_desc task_completed task_total
360
+ current_task_desc=$(get_state_value "plan.current_task_desc" 2>/dev/null || echo "Continue with next task")
361
+ task_completed=$(get_state_value "plan.completed_tasks" 2>/dev/null || echo "0")
362
+ task_total=$(get_state_value "plan.total_tasks" 2>/dev/null || echo "0")
363
+
364
+ # TUI: Show task header with progress bar (replaces basic echo)
365
+ if type show_task_header &> /dev/null; then
366
+ show_task_header "$iteration" "$MAX_ITERATIONS" "$current_task_desc" "${BOOT_SELECTED_AGENT:-claude}"
367
+ if [ "$task_total" -gt 0 ] && type draw_progress_bar &> /dev/null; then
368
+ draw_progress_bar "$task_completed" "$task_total" 50 " Tasks"
369
+ echo ""
370
+ fi
371
+ else
372
+ echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
373
+ echo -e "${BOLD}Iteration $iteration / $MAX_ITERATIONS${RESET} (mode: $mode)"
374
+ echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
375
+ fi
376
+
377
+ # Run Merlin Pro Boot Sequence (5 phases)
378
+ if type run_boot_sequence &> /dev/null; then
379
+ run_boot_sequence "$current_task_desc"
380
+ fi
258
381
 
259
382
  # Record iteration start
260
383
  local start_time
261
384
  start_time=$(date +%s)
262
385
  record_iteration_start "$iteration" "$mode"
263
386
 
264
- # Build the prompt with current state
387
+ # Build the prompt with current state and boot context
265
388
  local full_prompt
266
389
  full_prompt=$(build_prompt "$mode")
267
390
 
@@ -269,13 +392,25 @@ run_iteration() {
269
392
  local output
270
393
  local exit_code=0
271
394
 
272
- echo -e "${BLUE}Spawning Claude with fresh context...${RESET}"
273
- echo -e "${BLUE}Task list: ${TASK_LIST_ID}${RESET}"
395
+ # Route to the specialist agent selected by boot sequence
396
+ local agent_cli_name="merlin"
397
+ if [ -n "${BOOT_SELECTED_AGENT:-}" ] && type get_agent_cli_name &> /dev/null; then
398
+ agent_cli_name=$(get_agent_cli_name "$BOOT_SELECTED_AGENT")
399
+ fi
400
+
401
+ local agent_display_name="$agent_cli_name"
402
+ if type get_agent_display_name &> /dev/null && [ -n "${BOOT_SELECTED_AGENT:-}" ]; then
403
+ agent_display_name=$(get_agent_display_name "$BOOT_SELECTED_AGENT")
404
+ fi
405
+
406
+ echo -e "${BLUE}Spawning Claude as ${BOLD}${agent_display_name}${RESET}${BLUE}...${RESET}"
407
+ echo -e "${BLUE}Agent: --agent ${agent_cli_name} | Task list: ${TASK_LIST_ID}${RESET}"
274
408
 
275
409
  # Capture output and exit code
276
410
  # CLAUDE_CODE_TASK_LIST_ID enables cross-session task coordination
411
+ # --agent routes to the specialist selected by boot sequence
277
412
  set +e
278
- output=$(CLAUDE_CODE_TASK_LIST_ID="$TASK_LIST_ID" claude --agent merlin --output-format stream-json 2>&1 <<< "$full_prompt")
413
+ output=$(CLAUDE_CODE_TASK_LIST_ID="$TASK_LIST_ID" claude --agent "$agent_cli_name" --output-format stream-json 2>&1 <<< "$full_prompt")
279
414
  exit_code=$?
280
415
  set -e
281
416
 
@@ -288,30 +423,110 @@ run_iteration() {
288
423
 
289
424
  # Parse output for signals
290
425
  if echo "$output" | grep -q "EXIT_SIGNAL"; then
426
+ # Run session end protocol before completing
427
+ if type session_end_protocol &> /dev/null; then
428
+ session_end_protocol "$current_task_desc" "" ""
429
+ fi
291
430
  echo -e "\n${GREEN}${BOLD}EXIT_SIGNAL detected - Loop complete!${RESET}"
292
431
  return 0
293
432
  fi
294
433
 
295
- if echo "$output" | grep -q "CHECKPOINT_SIGNAL"; then
434
+ # Count tasks completed (for pause interval)
435
+ local task_count
436
+ task_count=$(get_state_value "plan.completed_tasks" 2>/dev/null || echo "0")
437
+
438
+ # Check if we should pause based on mode
439
+ if should_pause "$output" "$task_count"; then
440
+ local pause_result
441
+ handle_pause "$output" "$iteration" "$task_count"
442
+ pause_result=$?
443
+
444
+ case $pause_result in
445
+ 0) # Continue
446
+ ;;
447
+ 1) # Quit
448
+ return 0
449
+ ;;
450
+ 2) # Skip task
451
+ return 2
452
+ ;;
453
+ esac
454
+ fi
455
+
456
+ # Legacy checkpoint handling (for backward compatibility)
457
+ if echo "$output" | grep -q "CHECKPOINT_SIGNAL" && [ "$LAST_PAUSE_REASON" != "checkpoint" ]; then
296
458
  echo -e "\n${YELLOW}${BOLD}CHECKPOINT_SIGNAL detected - User input needed${RESET}"
297
459
  handle_checkpoint "$output"
298
460
  return 2 # Continue after checkpoint
299
461
  fi
300
462
 
301
463
  if [ $exit_code -ne 0 ]; then
464
+ # TUI: Show task failure
465
+ if type show_task_complete &> /dev/null; then
466
+ show_task_complete "$current_task_desc" "$duration" "error"
467
+ fi
302
468
  echo -e "\n${RED}Claude exited with error code: $exit_code${RESET}"
303
469
  record_error "$iteration" "$exit_code" "$output"
304
470
  return 1
305
471
  fi
306
472
 
473
+ # ═══════════════════════════════════════════════════════════════════════════
474
+ # MERLIN GUARANTEE: Verify Claude used Sights during iteration
475
+ # ═══════════════════════════════════════════════════════════════════════════
476
+ local sights_used=true
477
+ if ! echo "$output" | grep -qiE "merlin_get_context|merlin_search|merlin_find_files|SIGHTS|merlin_get_conventions|merlin_check_freshness|merlin_get_brief"; then
478
+ sights_used=false
479
+ echo ""
480
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
481
+ echo -e "${YELLOW}⚠️ MERLIN GUARANTEE WARNING${RESET}"
482
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
483
+ echo -e "${YELLOW}Claude did not use Merlin Sights during this iteration.${RESET}"
484
+ echo -e "${YELLOW}Output may lack codebase awareness. Proceeding with caution.${RESET}"
485
+ echo -e "${YELLOW}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
486
+ echo ""
487
+ fi
488
+
307
489
  # Update state from Claude's output
308
490
  parse_and_update_state "$output"
309
491
 
492
+ # ═══════════════════════════════════════════════════════════════════════════
493
+ # SESSION END PROTOCOL: Enforced after every iteration
494
+ # Replaces ad-hoc inline calls with the formal 5-step protocol
495
+ # ═══════════════════════════════════════════════════════════════════════════
496
+ local current_task
497
+ current_task=$(get_state_value "plan.current_task" 2>/dev/null || echo "")
498
+
499
+ if type session_end_protocol &> /dev/null; then
500
+ # Full protocol: check changes → commit → push → record to Sights → checkpoint
501
+ session_end_protocol "$current_task_desc" "$current_task" ""
502
+ else
503
+ # Fallback: ad-hoc calls if session-end.sh didn't load
504
+ if type record_last_commit &> /dev/null; then
505
+ record_last_commit "$current_task" "claude" "loop-agent" &
506
+ fi
507
+ if type save_checkpoint &> /dev/null; then
508
+ local current_phase working_files
509
+ current_phase=$(get_state_value "plan.current_phase" 2>/dev/null || echo "")
510
+ working_files=$(get_state_value "plan.working_files" 2>/dev/null || echo "[]")
511
+ save_checkpoint "Completed iteration $iteration" "$current_phase" "$current_task" "$working_files" "merlin-loop" &
512
+ fi
513
+ fi
514
+
515
+ # Update worker heartbeat with current task
516
+ if type worker_heartbeat &> /dev/null; then
517
+ worker_heartbeat "$current_task" &
518
+ fi
519
+
310
520
  # Cloud sync after each iteration
311
521
  if [ "$CLOUD_SYNC" = "true" ]; then
312
522
  sync_to_cloud_async
313
523
  fi
314
524
 
525
+ # TUI: Show task completion
526
+ if type show_task_complete &> /dev/null; then
527
+ show_task_complete "$current_task_desc" "$duration" "success"
528
+ fi
529
+
315
530
  return 2 # Continue loop
316
531
  }
317
532
 
@@ -336,6 +551,33 @@ $state
336
551
  \`\`\`
337
552
  "
338
553
 
554
+ # Inject recent changes from Sights (if available)
555
+ if type fetch_recent_changes &> /dev/null; then
556
+ local recent_changes
557
+ recent_changes=$(fetch_recent_changes 2>/dev/null || echo "")
558
+ if [ -n "$recent_changes" ] && [ "$recent_changes" != "# Recent Changes: Not available"* ]; then
559
+ prompt="$prompt
560
+
561
+ ---
562
+ $recent_changes
563
+ "
564
+ fi
565
+ fi
566
+
567
+ # Inject boot context (agent guidance, skills, trajectory)
568
+ if type get_boot_context &> /dev/null; then
569
+ local boot_context
570
+ boot_context=$(get_boot_context)
571
+ if [ -n "$boot_context" ]; then
572
+ prompt="$prompt
573
+
574
+ ---
575
+ ## Boot Context (from Merlin Pro)
576
+
577
+ $boot_context"
578
+ fi
579
+ fi
580
+
339
581
  # Inject relevant context from memory
340
582
  local context
341
583
  context=$(get_relevant_context "$mode")
@@ -419,7 +661,16 @@ main_loop() {
419
661
  case $result in
420
662
  0)
421
663
  # EXIT_SIGNAL - complete
422
- echo -e "\n${GREEN}${BOLD}Loop completed successfully after $iteration iterations${RESET}"
664
+ # TUI: Show beautiful completion banner
665
+ if type show_loop_complete &> /dev/null; then
666
+ local stats_completed stats_errors
667
+ stats_completed=$(get_state_value "plan.completed_tasks" 2>/dev/null || echo "$iteration")
668
+ stats_errors=$(get_state_value "plan.total_errors" 2>/dev/null || echo "0")
669
+ local total_elapsed=$(($(date +%s) - ${LOOP_START_TIME:-$(date +%s)}))
670
+ show_loop_complete "$stats_completed" "$total_elapsed" "$stats_errors"
671
+ else
672
+ echo -e "\n${GREEN}${BOLD}Loop completed successfully after $iteration iterations${RESET}"
673
+ fi
423
674
  if [ "$NOTIFY_ON_COMPLETE" = "true" ]; then
424
675
  send_notification "Merlin Loop Complete" "Finished after $iteration iterations"
425
676
  fi
@@ -444,6 +695,14 @@ main_loop() {
444
695
  fi
445
696
  done
446
697
 
698
+ # TUI: Show completion even on max iterations
699
+ if type show_loop_complete &> /dev/null; then
700
+ local stats_completed stats_errors
701
+ stats_completed=$(get_state_value "plan.completed_tasks" 2>/dev/null || echo "0")
702
+ stats_errors=$(get_state_value "plan.total_errors" 2>/dev/null || echo "0")
703
+ local total_elapsed=$(($(date +%s) - ${LOOP_START_TIME:-$(date +%s)}))
704
+ show_loop_complete "$stats_completed" "$total_elapsed" "$stats_errors"
705
+ fi
447
706
  echo -e "\n${YELLOW}${BOLD}Max iterations ($MAX_ITERATIONS) reached${RESET}"
448
707
  echo "Resume with: merlin-loop resume --max $((MAX_ITERATIONS + 50))"
449
708
  show_summary
@@ -478,22 +737,56 @@ usage() {
478
737
  echo " reset Reset loop state (keeps history)"
479
738
  echo ""
480
739
  echo "Options:"
740
+ echo " --mode MODE Loop mode: auto, interactive, hybrid (default: hybrid)"
741
+ echo " auto - Only pause on explicit checkpoints"
742
+ echo " interactive - Pause after every task"
743
+ echo " hybrid - Pause on decisions, low confidence, every N tasks"
744
+ echo " --pause-every N Pause every N tasks in hybrid mode (default: 5)"
745
+ echo " --timeout N Pause timeout in seconds (default: 300 = 5 min)"
746
+ echo " --no-timeout Disable timeout (pauses wait forever)"
481
747
  echo " --max N Maximum iterations (default: 50)"
482
748
  echo " --cooldown N Seconds between iterations (default: 2)"
483
749
  echo " --no-sync Disable cloud sync"
484
- echo " --afk AFK mode (stricter safety, notifications)"
750
+ echo " --afk AFK mode (stricter safety, shorter timeout, auto mode)"
485
751
  echo " --quiet Minimal output"
486
752
  echo ""
487
753
  echo "Examples:"
488
- echo " merlin-loop plan # Create implementation plan"
489
- echo " merlin-loop build # Execute plan tasks"
490
- echo " merlin-loop --max 100 build # Allow up to 100 iterations"
491
- echo " merlin-loop --afk auto # Run unattended"
754
+ echo " merlin-loop plan # Create implementation plan"
755
+ echo " merlin-loop build # Execute plan tasks (hybrid mode)"
756
+ echo " merlin-loop --mode auto build # Fully automated, no pauses"
757
+ echo " merlin-loop --mode interactive build # Pause after every task"
758
+ echo " merlin-loop --max 100 build # Allow up to 100 iterations"
759
+ echo " merlin-loop --afk auto # Run unattended (auto mode)"
492
760
  }
493
761
 
494
762
  parse_args() {
495
763
  while [[ $# -gt 0 ]]; do
496
764
  case $1 in
765
+ --mode)
766
+ if validate_mode "$2"; then
767
+ LOOP_MODE="$2"
768
+ # Interactive mode disables timeout by default
769
+ if [ "$2" = "interactive" ]; then
770
+ TIMEOUT_ENABLED="false"
771
+ fi
772
+ else
773
+ exit 1
774
+ fi
775
+ shift 2
776
+ ;;
777
+ --pause-every)
778
+ PAUSE_INTERVAL="$2"
779
+ shift 2
780
+ ;;
781
+ --timeout)
782
+ PAUSE_TIMEOUT="$2"
783
+ TIMEOUT_ENABLED="true"
784
+ shift 2
785
+ ;;
786
+ --no-timeout)
787
+ TIMEOUT_ENABLED="false"
788
+ shift
789
+ ;;
497
790
  --max)
498
791
  MAX_ITERATIONS="$2"
499
792
  shift 2
@@ -507,9 +800,11 @@ parse_args() {
507
800
  shift
508
801
  ;;
509
802
  --afk)
510
- # AFK mode: stricter limits, more safety
803
+ # AFK mode: stricter limits, auto mode, shorter timeout, more safety
511
804
  CIRCUIT_BREAKER_THRESHOLD=3
512
805
  NOTIFY_ON_COMPLETE="true"
806
+ LOOP_MODE="auto" # AFK means fully automated
807
+ PAUSE_TIMEOUT=120 # Shorter timeout for AFK (2 minutes)
513
808
  shift
514
809
  ;;
515
810
  --quiet)
@@ -0,0 +1,102 @@
1
+ # Merlin Loop - Discussion Mode
2
+
3
+ You are in **DISCUSSION MODE** - an advisor helping the user think through problems, not an implementer.
4
+
5
+ ## Your Role
6
+
7
+ You are here to:
8
+ - **Listen** and understand what the user is trying to accomplish
9
+ - **Ask clarifying questions** to fully understand the situation
10
+ - **Suggest approaches** when asked (but don't decide for them)
11
+ - **Think through trade-offs** together
12
+ - **Help refine ideas** before implementation resumes
13
+
14
+ ## What You Should NOT Do
15
+
16
+ - ❌ Do NOT write or modify code
17
+ - ❌ Do NOT run commands
18
+ - ❌ Do NOT try to implement anything
19
+ - ❌ Do NOT make decisions for the user
20
+
21
+ This is purely a **thinking and talking session**.
22
+
23
+ ## Context
24
+
25
+ **Current Task:**
26
+ {{CURRENT_TASK}}
27
+
28
+ **Recent History:**
29
+ {{RECENT_HISTORY}}
30
+
31
+ **Pending Decisions:**
32
+ {{PENDING_DECISIONS}}
33
+
34
+ **Project:**
35
+ {{PROJECT_CONTEXT}}
36
+
37
+ ## How to Have a Good Discussion
38
+
39
+ 1. **Understand first** - Ask what specifically is confusing or needs thought
40
+ 2. **Explore options** - Help think through different approaches
41
+ 3. **Surface trade-offs** - What's good/bad about each option
42
+ 4. **Let them decide** - Your job is to clarify, not choose
43
+
44
+ ## Capturing Decisions
45
+
46
+ When the user makes a decision during our discussion, mark it clearly with the `DECISION:` prefix so it can be captured and used later:
47
+
48
+ ```
49
+ DECISION: We'll use Option B because it's simpler and we don't need the extra flexibility.
50
+ ```
51
+
52
+ You can capture multiple decisions:
53
+
54
+ ```
55
+ DECISION: Database will use PostgreSQL for ACID compliance.
56
+ DECISION: API will be REST-style, not GraphQL - simpler for this use case.
57
+ DECISION: Error messages will be user-friendly, with technical details in logs only.
58
+ ```
59
+
60
+ ## Ending the Discussion
61
+
62
+ The user will say one of these to end the discussion:
63
+ - **"done"** or **"continue"** - Return to the loop
64
+ - **"quit"** - Exit the loop entirely
65
+
66
+ When they're ready to end, summarize any decisions made:
67
+
68
+ ```
69
+ Great discussion! Here's what we decided:
70
+
71
+ DECISION: [summary of decision 1]
72
+ DECISION: [summary of decision 2]
73
+
74
+ Ready to continue with the loop. Say "done" or "continue" to proceed.
75
+ ```
76
+
77
+ ## Example Discussion Flow
78
+
79
+ **User:** I'm not sure how to handle the error cases here.
80
+
81
+ **You:** What kind of errors are you seeing? Are these validation errors from user input, or unexpected system errors?
82
+
83
+ **User:** Mostly validation - users entering bad data.
84
+
85
+ **You:** Got it. There are a few approaches:
86
+ 1. **Fail fast** - Return error immediately on first invalid field
87
+ 2. **Collect all** - Validate everything, return all errors at once
88
+ 3. **Progressive** - Validate as they type, show inline errors
89
+
90
+ What matters more to you - developer simplicity or user experience?
91
+
92
+ **User:** User experience. Let's collect all errors.
93
+
94
+ **You:** Makes sense. So we'll validate all fields and return a list of errors.
95
+
96
+ DECISION: Use collect-all validation to show users all errors at once for better UX.
97
+
98
+ Anything else you want to think through?
99
+
100
+ ---
101
+
102
+ Now, what would you like to discuss?