feat: add RALPH_STATUS block parsing and circuit breaker pattern

Phase 1 Ralph enhancement implementation:
- Parse RALPH_STATUS blocks from Claude output (status, tasks, files, tests)
- Circuit breaker state machine (CLOSED → HALF_OPEN → OPEN) for stuck detection
- Dual-condition exit gate (completion indicators >= 2 AND EXIT_SIGNAL)
- Frontend: circuit breaker badge (yellow warning, red stuck), status block display
- API: circuit breaker reset endpoint, ralph status endpoint
- Notifications when circuit breaker opens or exit gate is met

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-01-27 00:29:38 +01:00
co-authored by Claude Opus 4.5
parent b896478ca6
commit 11d4666d19
8 changed files with 1699 additions and 1 deletions
+251
View File
@@ -0,0 +1,251 @@
# Ralph Loop Improvements Plan
## Overview
This plan details improvements to Claudeman's Ralph Loop system based on best practices from the Ralph Claude Code repository (https://github.com/frankbria/ralph-claude-code).
## Key Concepts to Implement
### RALPH_STATUS Block Format
Claude outputs this structured block at the end of every response for better tracking:
```
---RALPH_STATUS---
STATUS: IN_PROGRESS | COMPLETE | BLOCKED
TASKS_COMPLETED_THIS_LOOP: <number>
FILES_MODIFIED: <number>
TESTS_STATUS: PASSING | FAILING | NOT_RUN
WORK_TYPE: IMPLEMENTATION | TESTING | DOCUMENTATION | REFACTORING
EXIT_SIGNAL: false | true
RECOMMENDATION: <one line summary of what to do next>
---END_RALPH_STATUS---
```
### Dual-Condition Exit Gate
Exit requires BOTH conditions:
1. `completion_indicators >= 2` (heuristic detection from natural language patterns)
2. Claude's explicit `EXIT_SIGNAL: true` in the RALPH_STATUS block
### Circuit Breaker Pattern
Three states: CLOSED → HALF_OPEN → OPEN
| From State | Condition | To State |
|------------|-----------|----------|
| CLOSED | consecutive_no_progress >= 2 | HALF_OPEN |
| CLOSED | consecutive_no_progress >= 3 | OPEN |
| CLOSED | consecutive_same_error >= 5 | OPEN |
| HALF_OPEN | progress detected | CLOSED |
| HALF_OPEN | consecutive_no_progress >= 3 | OPEN |
| OPEN | Manual reset | CLOSED |
### @fix_plan.md Structure
```markdown
# Fix Plan
## High Priority (P0)
- [ ] Critical: Fix authentication bug
- [ ] Blocker: Database connection timeout
## Standard (P1)
- [ ] Feature: Add user profile page
## Nice to Have (P2)
- [ ] Improvement: Add dark mode
## Completed
- [x] Setup: Initialize project structure
```
---
## Phase 1: Quick Wins (1-2 days)
### 1.1 RALPH_STATUS Block Parsing
**What**: Add parsing support for the structured RALPH_STATUS block format in RalphTracker.
**Implementation**:
- Add regex pattern to detect `---RALPH_STATUS---` blocks
- Parse fields: STATUS, TASKS_COMPLETED_THIS_LOOP, FILES_MODIFIED, TESTS_STATUS, WORK_TYPE, EXIT_SIGNAL, RECOMMENDATION
- Store in extended `RalphTrackerState` type
- Emit new events: `ralphStatusUpdate`
**Files**: `ralph-tracker.ts`, `types.ts`
### 1.2 Enhanced Status Display in UI
**What**: Display RALPH_STATUS fields in the Ralph State Panel.
**Implementation**:
- Add UI elements: WORK_TYPE indicator, TESTS_STATUS badge, FILES_MODIFIED count
- Show RECOMMENDATION text in expanded view
- Color-code status (IN_PROGRESS=blue, COMPLETE=green, BLOCKED=red)
**Files**: `app.js`, `styles.css`, `index.html`
### 1.3 Prompt Template Improvements
**What**: Add specification-by-example exit scenarios to prompts.
**Implementation**:
- Add "Exit Scenarios" section to case-template.md
- Document when to continue vs. when to output completion
- Include testing limits guidance (max 20% effort on tests)
- Add RALPH_STATUS block instructions
**Files**: `case-template.md`
### 1.4 Better Wizard Validation
**What**: Add client-side validation and helpful warnings.
**Implementation**:
- Warn if task description < 50 chars
- Warn if no success criteria mentioned
- Suggest adding test requirements if none detected
- Validate completion phrase is uppercase alphanumeric
**Files**: `app.js`
---
## Phase 2: Core Improvements (3-5 days)
### 2.1 Circuit Breaker Pattern
**What**: Implement three-state circuit breaker to detect stuck loops.
**Implementation**:
- Create `CircuitBreaker` class with CLOSED, HALF_OPEN, OPEN states
- Track: files_modified, tasks_completed, error_patterns per iteration
- Triggers: N consecutive no-progress, same error M times, tests failing K iterations
- Emit events: `circuitBreakerStateChange`
**Files**: New `circuit-breaker.ts`, integrate into `ralph-tracker.ts`
### 2.2 Circuit Breaker UI
**What**: Visual indicator in Ralph panel.
**Implementation**:
- Badge: green (CLOSED), yellow (HALF_OPEN), red (OPEN)
- Warning before tripping
- Notification when circuit opens
- Manual reset button
**Files**: `app.js`, `styles.css`, `index.html`
### 2.3 @fix_plan.md Integration
**What**: Generate and track structured task plan file.
**Implementation**:
- Generate `@fix_plan.md` in working directory when loop starts
- Watch file for changes and sync with RalphTracker todos
- Parse priority levels (P0, P1, P2)
- Show priority in UI
**Files**: New `fix-plan.ts`, `ralph-tracker.ts`, `server.ts`
### 2.4 Wizard Plan Generation Step
**What**: Add third wizard step for AI-assisted plan generation.
**Implementation**:
- Step 2: "Plan Generation" between Task Setup and Launch
- Use Claude to break down task into fix plan items
- Allow edit/reorder before launch
- Generate @fix_plan.md with selected items
**Files**: `app.js`, `index.html`, `server.ts`
### 2.5 Smart Respawn Integration
**What**: Use RALPH_STATUS for respawn decisions.
**Implementation**:
- Use EXIT_SIGNAL field for respawn decisions
- If STATUS=BLOCKED, trigger circuit breaker instead of respawn
- Pass RECOMMENDATION to respawn update prompt
**Files**: `respawn-controller.ts`, `ralph-tracker.ts`
---
## Phase 3: Advanced Features (5+ days)
### 3.1 Template Library
- Bug Fix, Feature, Refactoring, Test Coverage, Documentation templates
- Template selector in wizard
- Custom templates in `~/.claudeman/templates/`
### 3.2 Tool Permissions
- Configure allowed Claude tools per loop
- Generate hook configuration
- Store in session config
### 3.3 Per-Iteration Timeout
- Max time per iteration (5-60 min)
- Auto-continue on timeout
- Log timeout events
### 3.4 Rate Limiting
- Max tokens per iteration
- Max API calls per minute
- Cooldown between iterations
### 3.5 Metrics Dashboard
- Time-series charts (files modified, tasks completed, tokens)
- Aggregate statistics
- Export to JSON/CSV
---
## Priority Matrix
| Item | Effort | Impact | Priority |
|------|--------|--------|----------|
| 1.1 RALPH_STATUS Parsing | Low | High | P0 |
| 1.2 Status Display UI | Low | Medium | P0 |
| 1.3 Prompt Templates | Low | High | P0 |
| 1.4 Wizard Validation | Low | Medium | P1 |
| 2.1 Circuit Breaker | Medium | High | P1 |
| 2.2 Circuit Breaker UI | Medium | Medium | P1 |
| 2.3 Fix Plan Integration | Medium | High | P1 |
| 2.4 Plan Generation Step | Medium | Medium | P2 |
| 2.5 Respawn Integration | Medium | High | P1 |
| 3.1 Template Selection | High | Medium | P2 |
| 3.2 Tool Permissions | High | Medium | P3 |
| 3.3 Per-Iteration Timeout | High | Medium | P2 |
| 3.4 Rate Limiting | High | Low | P3 |
| 3.5 Metrics Dashboard | High | Medium | P3 |
---
## Reference: Ralph Claude Code Best Practices
### Testing Guidelines
- LIMIT testing to ~20% of total effort per loop
- PRIORITIZE: Implementation > Documentation > Tests
- Only write tests for NEW functionality
- Do NOT refactor existing tests unless broken
### What NOT to Do
- Do NOT continue with busy work when EXIT_SIGNAL should be true
- Do NOT run tests repeatedly without implementing new features
- Do NOT refactor code that is already working
- Do NOT add features not in specifications
- Do NOT forget the status block
### Exit Scenarios (Specification by Example)
1. **Successful Completion**: All tasks done → EXIT_SIGNAL=true
2. **Test-Only Loop**: No implementation, only testing → continue but warn
3. **Stuck on Error**: Same error 5 times → circuit breaker opens
4. **No Work Remaining**: All specs done → EXIT_SIGNAL=true
5. **Making Progress**: Normal flow → continue
6. **Blocked**: Needs human intervention → STATUS=BLOCKED
+434
View File
@@ -0,0 +1,434 @@
# Ralph Tracker Phase 1 Implementation Plan
## Overview
This plan details how to enhance the existing RalphTracker with RALPH_STATUS block parsing, circuit breaker pattern, and dual-condition exit gate.
---
## 1. Current State Analysis
### What RalphTracker Already Does Well
- **Todo Detection**: Supports 5 formats (checkboxes, indicators, status in parentheses, native TodoWrite, checkmark-based)
- **Completion Phrases**: Detects `<promise>PHRASE</promise>` with occurrence-based logic (1st = store, 2nd = complete)
- **Loop State Tracking**: Tracks active/inactive, iteration counts, max iterations, elapsed hours, cycle counts
- **Auto-Enable**: Disabled by default, auto-enables when Ralph patterns detected
- **Event System**: Emits `loopUpdate`, `todoUpdate`, `completionDetected`, `enabled` events
- **SSE Integration**: Events forwarded via `session:ralphLoopUpdate`, `session:ralphTodoUpdate`, `session:ralphCompletionDetected`
- **Debouncing**: EVENT_DEBOUNCE_MS (50ms) for rapid updates to prevent UI jitter
- **Cleanup**: MAX_TODO_ITEMS (50), TODO_EXPIRY_MS (1 hour), throttled cleanup
### Current Limitations
| Feature | Status |
|---------|--------|
| RALPH_STATUS block parsing | Missing |
| Circuit breaker pattern | Missing |
| Priority-based todos (P0/P1/P2) | Missing |
| Dual-condition exit gate | Missing |
| Files modified tracking | Missing |
| Tests status tracking | Missing |
| Work type classification | Missing |
---
## 2. New Type Definitions (types.ts)
```typescript
// ========== RALPH_STATUS Block Types ==========
export type RalphStatusValue = 'IN_PROGRESS' | 'COMPLETE' | 'BLOCKED';
export type RalphTestsStatus = 'PASSING' | 'FAILING' | 'NOT_RUN';
export type RalphWorkType = 'IMPLEMENTATION' | 'TESTING' | 'DOCUMENTATION' | 'REFACTORING';
/**
* Parsed RALPH_STATUS block from Claude output.
*/
export interface RalphStatusBlock {
status: RalphStatusValue;
tasksCompletedThisLoop: number;
filesModified: number;
testsStatus: RalphTestsStatus;
workType: RalphWorkType;
exitSignal: boolean;
recommendation: string;
parsedAt: number;
}
// ========== Circuit Breaker Types ==========
export type CircuitBreakerState = 'CLOSED' | 'HALF_OPEN' | 'OPEN';
export type CircuitBreakerReason =
| 'normal_operation'
| 'no_progress_warning'
| 'no_progress_open'
| 'same_error_repeated'
| 'tests_failing_too_long'
| 'progress_detected'
| 'manual_reset';
export interface CircuitBreakerStatus {
state: CircuitBreakerState;
consecutiveNoProgress: number;
consecutiveSameError: number;
consecutiveTestsFailure: number;
lastProgressIteration: number;
reason: string;
reasonCode: CircuitBreakerReason;
lastTransitionAt: number;
lastErrorMessage: string | null;
}
// ========== Priority Todo Types ==========
export type RalphTodoPriority = 'P0' | 'P1' | 'P2' | null;
// ========== Helper Functions ==========
export function createInitialCircuitBreakerStatus(): CircuitBreakerStatus {
return {
state: 'CLOSED',
consecutiveNoProgress: 0,
consecutiveSameError: 0,
consecutiveTestsFailure: 0,
lastProgressIteration: 0,
reason: 'Initial state',
reasonCode: 'normal_operation',
lastTransitionAt: Date.now(),
lastErrorMessage: null,
};
}
```
---
## 3. New Regex Patterns (ralph-tracker.ts)
```typescript
// ---------- RALPH_STATUS Block Patterns ----------
const RALPH_STATUS_START_PATTERN = /^---RALPH_STATUS---\s*$/;
const RALPH_STATUS_END_PATTERN = /^---END_RALPH_STATUS---\s*$/;
const RALPH_STATUS_FIELD_PATTERN = /^STATUS:\s*(IN_PROGRESS|COMPLETE|BLOCKED)\s*$/i;
const RALPH_TASKS_COMPLETED_PATTERN = /^TASKS_COMPLETED_THIS_LOOP:\s*(\d+)\s*$/i;
const RALPH_FILES_MODIFIED_PATTERN = /^FILES_MODIFIED:\s*(\d+)\s*$/i;
const RALPH_TESTS_STATUS_PATTERN = /^TESTS_STATUS:\s*(PASSING|FAILING|NOT_RUN)\s*$/i;
const RALPH_WORK_TYPE_PATTERN = /^WORK_TYPE:\s*(IMPLEMENTATION|TESTING|DOCUMENTATION|REFACTORING)\s*$/i;
const RALPH_EXIT_SIGNAL_PATTERN = /^EXIT_SIGNAL:\s*(true|false)\s*$/i;
const RALPH_RECOMMENDATION_PATTERN = /^RECOMMENDATION:\s*(.+)$/i;
// ---------- Completion Indicator Patterns ----------
const COMPLETION_INDICATOR_PATTERNS = [
/all\s+(?:tasks?|items?|work)\s+(?:are\s+)?(?:completed?|done|finished)/i,
/(?:completed?|finished)\s+all\s+(?:tasks?|items?|work)/i,
/nothing\s+(?:left|remaining)\s+to\s+do/i,
/no\s+more\s+(?:tasks?|items?|work)/i,
/everything\s+(?:is\s+)?(?:completed?|done)/i,
];
// ---------- Priority Pattern ----------
const TODO_PRIORITY_PATTERN = /^\s*(?:\[.\])?\s*(?:Critical:|Blocker:|Feature:|Improvement:)?\s*\(?(P[012])\)?:?\s*/i;
```
---
## 4. New State Properties (ralph-tracker.ts)
```typescript
// Add to RalphTracker class
// Circuit breaker state tracking
private _circuitBreaker: CircuitBreakerStatus;
// RALPH_STATUS block parsing state
private _statusBlockBuffer: string[] = [];
private _inStatusBlock: boolean = false;
private _lastStatusBlock: RalphStatusBlock | null = null;
// Dual-condition exit tracking
private _completionIndicators: number = 0;
private _exitGateMet: boolean = false;
// Cumulative tracking
private _totalFilesModified: number = 0;
private _totalTasksCompleted: number = 0;
```
---
## 5. New Methods to Implement
### 5.1 RALPH_STATUS Block Parsing
```typescript
private processStatusBlockLine(line: string): void {
const trimmed = line.trim();
if (RALPH_STATUS_START_PATTERN.test(trimmed)) {
this._inStatusBlock = true;
this._statusBlockBuffer = [];
return;
}
if (this._inStatusBlock && RALPH_STATUS_END_PATTERN.test(trimmed)) {
this._inStatusBlock = false;
this.parseStatusBlock(this._statusBlockBuffer);
this._statusBlockBuffer = [];
return;
}
if (this._inStatusBlock) {
this._statusBlockBuffer.push(trimmed);
}
}
private parseStatusBlock(lines: string[]): void {
const block: Partial<RalphStatusBlock> = { parsedAt: Date.now() };
for (const line of lines) {
// Parse each field...
}
if (block.status !== undefined) {
this._lastStatusBlock = fullBlock;
this.handleStatusBlock(fullBlock);
}
}
private handleStatusBlock(block: RalphStatusBlock): void {
this._totalFilesModified += block.filesModified;
this._totalTasksCompleted += block.tasksCompletedThisLoop;
const hasProgress = block.filesModified > 0 || block.tasksCompletedThisLoop > 0;
this.updateCircuitBreaker(hasProgress, block.testsStatus, block.status);
if (block.status === 'COMPLETE') {
this._completionIndicators++;
}
if (block.exitSignal && this._completionIndicators >= 2) {
this._exitGateMet = true;
this.emit('exitGateMet', { completionIndicators: this._completionIndicators, exitSignal: true });
}
this.emit('statusBlockDetected', block);
}
```
### 5.2 Circuit Breaker Logic
```typescript
private updateCircuitBreaker(
hasProgress: boolean,
testsStatus: RalphTestsStatus,
status: RalphStatusValue
): void {
const prevState = this._circuitBreaker.state;
if (hasProgress) {
this._circuitBreaker.consecutiveNoProgress = 0;
this._circuitBreaker.lastProgressIteration = this._loopState.cycleCount;
if (this._circuitBreaker.state === 'HALF_OPEN') {
this._circuitBreaker.state = 'CLOSED';
this._circuitBreaker.reasonCode = 'progress_detected';
}
} else {
this._circuitBreaker.consecutiveNoProgress++;
if (this._circuitBreaker.state === 'CLOSED') {
if (this._circuitBreaker.consecutiveNoProgress >= 3) {
this._circuitBreaker.state = 'OPEN';
this._circuitBreaker.reasonCode = 'no_progress_open';
} else if (this._circuitBreaker.consecutiveNoProgress >= 2) {
this._circuitBreaker.state = 'HALF_OPEN';
this._circuitBreaker.reasonCode = 'no_progress_warning';
}
}
}
if (prevState !== this._circuitBreaker.state) {
this._circuitBreaker.lastTransitionAt = Date.now();
this.emit('circuitBreakerUpdate', { ...this._circuitBreaker });
}
}
resetCircuitBreaker(): void {
this._circuitBreaker = createInitialCircuitBreakerStatus();
this._circuitBreaker.reasonCode = 'manual_reset';
this.emit('circuitBreakerUpdate', { ...this._circuitBreaker });
}
```
### 5.3 Update processLine Method
```typescript
private processLine(line: string): void {
const trimmed = line.trim();
if (!trimmed) return;
// NEW: Check for RALPH_STATUS block
this.processStatusBlockLine(trimmed);
// NEW: Check for completion indicators
this.detectCompletionIndicators(trimmed);
// EXISTING: Rest of the detection methods...
this.detectCompletionPhrase(trimmed);
this.detectAllTasksComplete(trimmed);
this.detectTaskCompletion(trimmed);
this.detectLoopStatus(trimmed);
this.detectTodoItems(trimmed);
}
```
---
## 6. New Events to Add
```typescript
export interface RalphTrackerEvents {
// Existing events
loopUpdate: (state: RalphTrackerState) => void;
todoUpdate: (todos: RalphTodoItem[]) => void;
completionDetected: (phrase: string) => void;
enabled: () => void;
// New events
statusBlockDetected: (block: RalphStatusBlock) => void;
circuitBreakerUpdate: (status: CircuitBreakerStatus) => void;
exitGateMet: (data: { completionIndicators: number; exitSignal: boolean }) => void;
}
```
---
## 7. Server Integration (server.ts)
```typescript
// Add new SSE event handlers in setupSessionListeners()
session.on('ralphStatusBlockDetected', (block: RalphStatusBlock) => {
this.broadcast('session:ralphStatusUpdate', { sessionId: session.id, block });
});
session.on('ralphCircuitBreakerUpdate', (status: CircuitBreakerStatus) => {
this.broadcast('session:circuitBreakerUpdate', { sessionId: session.id, status });
});
session.on('ralphExitGateMet', (data) => {
this.broadcast('session:exitGateMet', { sessionId: session.id, ...data });
});
// Add API endpoint for circuit breaker reset
this.app.post('/api/sessions/:id/ralph-circuit-breaker/reset', async (req) => {
const session = this.sessions.get(req.params.id);
if (!session) return { success: false, error: 'Session not found' };
session.ralphTracker?.resetCircuitBreaker();
return { success: true };
});
```
---
## 8. Frontend Changes (app.js)
### New SSE Event Listeners
```javascript
this.eventSource.addEventListener('session:ralphStatusUpdate', (e) => {
const data = JSON.parse(e.data);
this.updateRalphStatusBlock(data.sessionId, data.block);
});
this.eventSource.addEventListener('session:circuitBreakerUpdate', (e) => {
const data = JSON.parse(e.data);
this.updateCircuitBreaker(data.sessionId, data.status);
});
```
### New Rendering Methods
```javascript
updateRalphStatusBlock(sessionId, block) {
// Store and render status block
}
renderRalphStatusBlock(block) {
// Render STATUS, WORK_TYPE, TESTS_STATUS, RECOMMENDATION
}
updateCircuitBreaker(sessionId, status) {
// Store and render circuit breaker state
}
renderCircuitBreaker(status) {
// Render badge: green (CLOSED), yellow (HALF_OPEN), red (OPEN)
}
```
---
## 9. Implementation Order
| Step | Task | Time |
|------|------|------|
| 1 | Add type definitions to `types.ts` | 30 min |
| 2 | Add regex patterns to `ralph-tracker.ts` | 30 min |
| 3 | Add state properties to RalphTracker class | 15 min |
| 4 | Implement RALPH_STATUS parsing methods | 1.5 hr |
| 5 | Implement circuit breaker logic | 1 hr |
| 6 | Implement completion indicators | 30 min |
| 7 | Update events interface | 15 min |
| 8 | Add server SSE handlers and API endpoint | 45 min |
| 9 | Add frontend event listeners and rendering | 1 hr |
| 10 | Add CSS styles | 30 min |
| 11 | Update HTML structure | 15 min |
| 12 | Write unit tests | 1.5 hr |
**Total: ~8 hours**
---
## 10. Files to Modify
| File | Changes |
|------|---------|
| `src/types.ts` | Add RalphStatusBlock, CircuitBreakerStatus, helper functions |
| `src/ralph-tracker.ts` | Add patterns, state, parsing methods, circuit breaker |
| `src/web/server.ts` | Add SSE handlers, circuit breaker reset endpoint |
| `src/web/public/app.js` | Add event listeners, rendering methods |
| `src/web/public/styles.css` | Add status block and circuit breaker styles |
| `src/web/public/index.html` | Add UI elements to Ralph panel |
| `test/ralph-tracker.test.ts` | Add tests for new functionality |
---
## 11. Test Cases to Add
1. **RALPH_STATUS Parsing**
- Parse valid status block with all fields
- Parse block with missing optional fields
- Ignore malformed blocks
- Handle multiple blocks in sequence
2. **Circuit Breaker State Transitions**
- CLOSED → HALF_OPEN on 2 no-progress
- HALF_OPEN → OPEN on 3 no-progress
- HALF_OPEN → CLOSED on progress
- Manual reset from OPEN
3. **Dual-Condition Exit Gate**
- Exit when indicators >= 2 AND exitSignal = true
- No exit when indicators >= 2 but exitSignal = false
- No exit when exitSignal = true but indicators < 2
4. **Integration Tests**
- SSE events broadcast correctly
- UI updates on status block detection
- Circuit breaker badge updates