coder-config 0.40.16 → 0.41.2

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.
package/README.md CHANGED
@@ -16,6 +16,7 @@ One tool to configure all your AI coding assistants:
16
16
  | **Rules & Commands** | Manage project-specific guidelines |
17
17
  | **Memory** | Persistent context across sessions |
18
18
  | **Workstreams** | Group projects with shared context |
19
+ | **Ralph Loops** | Autonomous development until task completion |
19
20
 
20
21
  ## Installation
21
22
 
@@ -157,6 +158,47 @@ coder-config workstream install-hook --codex
157
158
  coder-config workstream install-hook --all
158
159
  ```
159
160
 
161
+ ### Loop Commands (Ralph Loop)
162
+
163
+ Ralph Loops enable autonomous development - Claude Code runs continuously until a task is completed.
164
+
165
+ ```bash
166
+ coder-config loop # List all loops
167
+ coder-config loop create "Task description" # Create new loop
168
+ coder-config loop create "Task" --workstream <name> # Create loop in workstream context
169
+ coder-config loop start <id> # Start/resume a loop
170
+ coder-config loop pause <id> # Pause loop at next safe point
171
+ coder-config loop resume <id> # Resume paused loop
172
+ coder-config loop cancel <id> # Cancel loop
173
+ coder-config loop delete <id> # Delete loop and its data
174
+ coder-config loop approve <id> # Approve plan (when in plan phase)
175
+ coder-config loop complete <id> # Mark loop as complete
176
+ coder-config loop status [id] # Show status (active loop if no id)
177
+ coder-config loop active # Show current active loop
178
+ coder-config loop history # Show completed loops
179
+ coder-config loop config # Show loop configuration
180
+ coder-config loop config --max-iterations 50 # Set max iterations
181
+ coder-config loop config --max-cost 10.00 # Set max cost budget
182
+ coder-config loop config --auto-approve-plan # Skip manual plan approval
183
+ ```
184
+
185
+ **Three-Phase Workflow**:
186
+ 1. **Clarify** - Claude asks questions to understand requirements
187
+ 2. **Plan** - Claude creates an implementation plan (requires approval)
188
+ 3. **Execute** - Claude implements the plan until complete
189
+
190
+ **Running a loop**:
191
+ ```bash
192
+ export CODER_LOOP_ID=<id>
193
+ claude --continue "Your task description"
194
+ ```
195
+
196
+ **Safety mechanisms**:
197
+ - Iteration limits (default: 50)
198
+ - Cost budget caps (default: $10)
199
+ - Phase gates (manual plan approval)
200
+ - Graceful pause on budget exceeded
201
+
160
202
  ### Registry Commands
161
203
 
162
204
  ```bash
package/config-loader.js CHANGED
@@ -30,6 +30,7 @@ const { envList, envSet, envUnset } = require('./lib/env');
30
30
  const { getProjectsRegistryPath, loadProjectsRegistry, saveProjectsRegistry, projectList, projectAdd, projectRemove } = require('./lib/projects');
31
31
  const { getWorkstreamsPath, loadWorkstreams, saveWorkstreams, workstreamList, workstreamCreate, workstreamUpdate, workstreamDelete, workstreamUse, workstreamActive, workstreamAddProject, workstreamRemoveProject, workstreamInject, workstreamDetect, workstreamGet, getActiveWorkstream, countWorkstreamsForProject, workstreamInstallHook, workstreamInstallHookGemini, workstreamInstallHookCodex, workstreamDeactivate, workstreamCheckPath } = require('./lib/workstreams');
32
32
  const { getActivityPath, getDefaultActivity, loadActivity, saveActivity, detectProjectRoot, activityLog, activitySummary, generateWorkstreamName, activitySuggestWorkstreams, activityClear } = require('./lib/activity');
33
+ const { getLoopsPath, loadLoops, saveLoops, loadLoopState, saveLoopState, loadHistory, saveHistory, loopList, loopCreate, loopGet, loopUpdate, loopDelete, loopStart, loopPause, loopResume, loopCancel, loopApprove, loopComplete, loopStatus, loopHistory, loopConfig, getActiveLoop, recordIteration, saveClarifications, savePlan, loadClarifications, loadPlan, loopInject, archiveLoop } = require('./lib/loops');
33
34
  const { runCli } = require('./lib/cli');
34
35
 
35
36
  class ClaudeConfigManager {
@@ -148,6 +149,37 @@ class ClaudeConfigManager {
148
149
  workstreamDeactivate() { return workstreamDeactivate(); }
149
150
  workstreamCheckPath(targetPath, silent) { return workstreamCheckPath(this.installDir, targetPath, silent); }
150
151
 
152
+ // Loops (Ralph Loop)
153
+ getLoopsPath() { return getLoopsPath(this.installDir); }
154
+ loadLoops() { return loadLoops(this.installDir); }
155
+ saveLoops(data) { return saveLoops(this.installDir, data); }
156
+ loadLoopState(loopId) { return loadLoopState(this.installDir, loopId); }
157
+ saveLoopState(loopId, state) { return saveLoopState(this.installDir, loopId, state); }
158
+ loadHistory() { return loadHistory(this.installDir); }
159
+ saveHistory(data) { return saveHistory(this.installDir, data); }
160
+ loopList() { return loopList(this.installDir); }
161
+ loopCreate(task, options) { return loopCreate(this.installDir, task, options); }
162
+ loopGet(idOrName) { return loopGet(this.installDir, idOrName); }
163
+ loopUpdate(idOrName, updates) { return loopUpdate(this.installDir, idOrName, updates); }
164
+ loopDelete(idOrName) { return loopDelete(this.installDir, idOrName); }
165
+ loopStart(idOrName) { return loopStart(this.installDir, idOrName); }
166
+ loopPause(idOrName) { return loopPause(this.installDir, idOrName); }
167
+ loopResume(idOrName) { return loopResume(this.installDir, idOrName); }
168
+ loopCancel(idOrName) { return loopCancel(this.installDir, idOrName); }
169
+ loopApprove(idOrName) { return loopApprove(this.installDir, idOrName); }
170
+ loopComplete(idOrName) { return loopComplete(this.installDir, idOrName); }
171
+ loopStatus(idOrName) { return loopStatus(this.installDir, idOrName); }
172
+ loopHistory() { return loopHistory(this.installDir); }
173
+ loopConfig(updates) { return loopConfig(this.installDir, updates); }
174
+ getActiveLoop() { return getActiveLoop(this.installDir); }
175
+ recordIteration(loopId, iteration) { return recordIteration(this.installDir, loopId, iteration); }
176
+ saveClarifications(loopId, content) { return saveClarifications(this.installDir, loopId, content); }
177
+ savePlan(loopId, content) { return savePlan(this.installDir, loopId, content); }
178
+ loadClarifications(loopId) { return loadClarifications(this.installDir, loopId); }
179
+ loadPlan(loopId) { return loadPlan(this.installDir, loopId); }
180
+ loopInject(silent) { return loopInject(this.installDir, silent); }
181
+ archiveLoop(loopId) { return archiveLoop(this.installDir, loopId); }
182
+
151
183
  // Activity
152
184
  getActivityPath() { return getActivityPath(this.installDir); }
153
185
  loadActivity() { return loadActivity(this.installDir); }
@@ -0,0 +1,96 @@
1
+ #!/bin/bash
2
+ # Ralph Loop context injection hook
3
+ # Called at the start of each Claude session to inject loop context
4
+ #
5
+ # This hook:
6
+ # 1. Checks if we're in an active loop (via CODER_LOOP_ID env var)
7
+ # 2. Reads the current loop state
8
+ # 3. Outputs loop context including task, phase, clarifications, and plan
9
+
10
+ LOOP_ID="$CODER_LOOP_ID"
11
+ if [[ -z "$LOOP_ID" ]]; then
12
+ exit 0
13
+ fi
14
+
15
+ STATE_FILE="$HOME/.coder-config/loops/$LOOP_ID/state.json"
16
+ PLAN_FILE="$HOME/.coder-config/loops/$LOOP_ID/plan.md"
17
+ CLARIFY_FILE="$HOME/.coder-config/loops/$LOOP_ID/clarifications.md"
18
+
19
+ if [[ ! -f "$STATE_FILE" ]]; then
20
+ echo "Warning: Loop state file not found: $STATE_FILE"
21
+ exit 0
22
+ fi
23
+
24
+ # Read loop state
25
+ NAME=$(jq -r '.name' "$STATE_FILE")
26
+ PHASE=$(jq -r '.phase' "$STATE_FILE")
27
+ STATUS=$(jq -r '.status' "$STATE_FILE")
28
+ CURRENT_ITER=$(jq -r '.iterations.current // 0' "$STATE_FILE")
29
+ MAX_ITER=$(jq -r '.iterations.max // 50' "$STATE_FILE")
30
+ TASK=$(jq -r '.task.original' "$STATE_FILE")
31
+ CLARIFIED_TASK=$(jq -r '.task.clarified // empty' "$STATE_FILE")
32
+
33
+ echo "<ralph-loop-context>"
34
+ echo "# Ralph Loop: $NAME"
35
+ echo ""
36
+ echo "**Phase:** $PHASE"
37
+ echo "**Status:** $STATUS"
38
+ echo "**Iteration:** $CURRENT_ITER / $MAX_ITER"
39
+ echo ""
40
+ echo "## Original Task"
41
+ echo "$TASK"
42
+ echo ""
43
+
44
+ if [[ -n "$CLARIFIED_TASK" && "$CLARIFIED_TASK" != "null" ]]; then
45
+ echo "## Clarified Task"
46
+ echo "$CLARIFIED_TASK"
47
+ echo ""
48
+ fi
49
+
50
+ if [[ -f "$CLARIFY_FILE" ]]; then
51
+ echo "## Clarifications"
52
+ cat "$CLARIFY_FILE"
53
+ echo ""
54
+ fi
55
+
56
+ if [[ -f "$PLAN_FILE" ]]; then
57
+ echo "## Implementation Plan"
58
+ cat "$PLAN_FILE"
59
+ echo ""
60
+ fi
61
+
62
+ echo "## Loop Instructions"
63
+ echo ""
64
+ echo "You are operating within a Ralph Loop - an autonomous development workflow."
65
+ echo "Your current phase is: **$PHASE**"
66
+ echo ""
67
+
68
+ case "$PHASE" in
69
+ "clarify")
70
+ echo "### Clarify Phase"
71
+ echo "- Ask questions to fully understand the requirements"
72
+ echo "- Gather any missing information needed for implementation"
73
+ echo "- Document Q&A in clarifications.md"
74
+ echo "- When requirements are clear, advance to 'plan' phase"
75
+ ;;
76
+ "plan")
77
+ echo "### Plan Phase"
78
+ echo "- Review the clarified requirements"
79
+ echo "- Create a detailed implementation plan"
80
+ echo "- Break down work into clear steps"
81
+ echo "- Save the plan to plan.md"
82
+ echo "- Wait for approval before advancing to 'execute' phase"
83
+ ;;
84
+ "execute")
85
+ echo "### Execute Phase"
86
+ echo "- Follow the implementation plan step by step"
87
+ echo "- Implement the required changes"
88
+ echo "- Test your work"
89
+ echo "- When complete, set taskComplete=true in state.json"
90
+ ;;
91
+ esac
92
+
93
+ echo ""
94
+ echo "## State File Location"
95
+ echo "$STATE_FILE"
96
+ echo "</ralph-loop-context>"
@@ -0,0 +1,101 @@
1
+ #!/bin/bash
2
+ # Ralph Loop continuation hook
3
+ # Called after each Claude response to manage loop continuation
4
+ #
5
+ # This hook:
6
+ # 1. Checks if we're in an active loop (via CODER_LOOP_ID env var)
7
+ # 2. Verifies the loop is still running
8
+ # 3. Checks budget limits (iterations and cost)
9
+ # 4. Updates iteration count
10
+ # 5. Outputs continuation prompt based on current phase
11
+
12
+ LOOP_ID="$CODER_LOOP_ID"
13
+ if [[ -z "$LOOP_ID" ]]; then
14
+ exit 0
15
+ fi
16
+
17
+ STATE_FILE="$HOME/.coder-config/loops/$LOOP_ID/state.json"
18
+ if [[ ! -f "$STATE_FILE" ]]; then
19
+ exit 0
20
+ fi
21
+
22
+ # Check if loop is still active
23
+ STATUS=$(jq -r '.status' "$STATE_FILE")
24
+ if [[ "$STATUS" != "running" ]]; then
25
+ exit 0
26
+ fi
27
+
28
+ # Check budget limits
29
+ CURRENT_ITER=$(jq -r '.iterations.current' "$STATE_FILE")
30
+ MAX_ITER=$(jq -r '.iterations.max' "$STATE_FILE")
31
+ CURRENT_COST=$(jq -r '.budget.currentCost // 0' "$STATE_FILE")
32
+ MAX_COST=$(jq -r '.budget.maxCost // 10' "$STATE_FILE")
33
+
34
+ # Check iteration limit
35
+ if (( CURRENT_ITER >= MAX_ITER )); then
36
+ echo "Loop paused: max iterations reached ($MAX_ITER)"
37
+ jq '.status = "paused" | .pauseReason = "max_iterations" | .updatedAt = (now | todate)' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
38
+ exit 0
39
+ fi
40
+
41
+ # Check cost limit (using bc for floating point comparison)
42
+ if command -v bc &> /dev/null; then
43
+ if (( $(echo "$CURRENT_COST >= $MAX_COST" | bc -l) )); then
44
+ echo "Loop paused: budget exceeded (\$$MAX_COST)"
45
+ jq '.status = "paused" | .pauseReason = "budget" | .updatedAt = (now | todate)' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
46
+ exit 0
47
+ fi
48
+ fi
49
+
50
+ # Update iteration count
51
+ NEW_ITER=$((CURRENT_ITER + 1))
52
+ jq ".iterations.current = $NEW_ITER | .updatedAt = (now | todate)" "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
53
+
54
+ # Check if task is complete (Claude sets this flag)
55
+ PHASE=$(jq -r '.phase' "$STATE_FILE")
56
+ TASK_COMPLETE=$(jq -r '.taskComplete // false' "$STATE_FILE")
57
+
58
+ if [[ "$TASK_COMPLETE" == "true" ]]; then
59
+ jq '.status = "completed" | .completedAt = (now | todate) | .updatedAt = (now | todate)' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
60
+ echo ""
61
+ echo "---"
62
+ echo "[Ralph Loop COMPLETED]"
63
+ echo "Task has been marked as complete."
64
+ echo "---"
65
+ exit 0
66
+ fi
67
+
68
+ # Continue loop - output continuation prompt based on phase
69
+ PHASE_PROMPT=""
70
+ case "$PHASE" in
71
+ "clarify")
72
+ PHASE_PROMPT="Continue clarifying requirements. Ask any remaining questions needed to fully understand the task.
73
+
74
+ If requirements are now clear:
75
+ 1. Save clarifications to ~/.coder-config/loops/$LOOP_ID/clarifications.md
76
+ 2. Update state: jq '.phase = \"plan\"' to advance to planning phase"
77
+ ;;
78
+ "plan")
79
+ PHASE_PROMPT="Continue developing the implementation plan based on clarified requirements.
80
+
81
+ When the plan is complete:
82
+ 1. Save the plan to ~/.coder-config/loops/$LOOP_ID/plan.md
83
+ 2. Wait for user approval before advancing to execute phase
84
+ 3. If auto-approve is enabled, update state: jq '.phase = \"execute\"'"
85
+ ;;
86
+ "execute")
87
+ PHASE_PROMPT="Continue executing the implementation plan.
88
+
89
+ When the task is complete:
90
+ 1. Verify all requirements have been met
91
+ 2. Run any relevant tests
92
+ 3. Update state: jq '.taskComplete = true' to mark as complete"
93
+ ;;
94
+ esac
95
+
96
+ echo ""
97
+ echo "---"
98
+ echo "[Ralph Loop iteration $NEW_ITER/$MAX_ITER - Phase: $PHASE]"
99
+ echo ""
100
+ echo "$PHASE_PROMPT"
101
+ echo "---"
package/lib/cli.js CHANGED
@@ -149,6 +149,63 @@ function runCli(manager) {
149
149
  }
150
150
  break;
151
151
 
152
+ // Loops (Ralph Loop)
153
+ case 'loop':
154
+ case 'loops':
155
+ if (args[1] === 'create' || args[1] === 'new') {
156
+ const task = args.slice(2).join(' ');
157
+ const wsIdx = args.indexOf('--workstream');
158
+ const workstreamId = wsIdx !== -1 ? args[wsIdx + 1] : null;
159
+ manager.loopCreate(task, { workstreamId });
160
+ } else if (args[1] === 'start') {
161
+ manager.loopStart(args[2]);
162
+ } else if (args[1] === 'pause') {
163
+ manager.loopPause(args[2]);
164
+ } else if (args[1] === 'resume') {
165
+ manager.loopResume(args[2]);
166
+ } else if (args[1] === 'cancel') {
167
+ manager.loopCancel(args[2]);
168
+ } else if (args[1] === 'approve') {
169
+ manager.loopApprove(args[2]);
170
+ } else if (args[1] === 'complete') {
171
+ manager.loopComplete(args[2]);
172
+ } else if (args[1] === 'delete' || args[1] === 'rm') {
173
+ manager.loopDelete(args[2]);
174
+ } else if (args[1] === 'status') {
175
+ manager.loopStatus(args[2]);
176
+ } else if (args[1] === 'history') {
177
+ manager.loopHistory();
178
+ } else if (args[1] === 'config') {
179
+ const updates = {};
180
+ const maxIterIdx = args.indexOf('--max-iterations');
181
+ if (maxIterIdx !== -1) updates.maxIterations = args[maxIterIdx + 1];
182
+ const maxCostIdx = args.indexOf('--max-cost');
183
+ if (maxCostIdx !== -1) updates.maxCost = args[maxCostIdx + 1];
184
+ if (args.includes('--auto-approve-plan')) updates.autoApprovePlan = true;
185
+ if (args.includes('--no-auto-approve-plan')) updates.autoApprovePlan = false;
186
+ if (Object.keys(updates).length > 0) {
187
+ manager.loopConfig(updates);
188
+ } else {
189
+ manager.loopConfig();
190
+ }
191
+ } else if (args[1] === 'inject') {
192
+ const silent = args.includes('--silent') || args.includes('-s');
193
+ manager.loopInject(silent);
194
+ } else if (args[1] === 'active') {
195
+ const loop = manager.getActiveLoop();
196
+ if (loop) {
197
+ console.log(`Active: ${loop.name}`);
198
+ console.log(` Phase: ${loop.phase}`);
199
+ console.log(` Status: ${loop.status}`);
200
+ console.log(` Iteration: ${loop.iterations.current}/${loop.iterations.max}`);
201
+ } else {
202
+ console.log('No active loop');
203
+ }
204
+ } else {
205
+ manager.loopList();
206
+ }
207
+ break;
208
+
152
209
  // Maintenance
153
210
  case 'update':
154
211
  manager.update(args.slice(1)).catch(err => {
@@ -232,6 +289,30 @@ Workstream Commands:
232
289
  Per-session activation (enables parallel work):
233
290
  export CODER_WORKSTREAM=<name-or-id>
234
291
 
292
+ Loop Commands (Ralph Loop - autonomous development):
293
+ loop List all loops
294
+ loop create "Task" Create new loop with task description
295
+ loop create "Task" --workstream <name> Create loop in workstream context
296
+ loop start <id> Start/resume a loop
297
+ loop pause <id> Pause loop at next safe point
298
+ loop resume <id> Resume paused loop
299
+ loop cancel <id> Cancel loop
300
+ loop delete <id> Delete loop and its data
301
+ loop approve <id> Approve plan (when in plan phase)
302
+ loop complete <id> Mark loop as complete
303
+ loop status [id] Show status (active loop if no id)
304
+ loop active Show current active loop
305
+ loop history Show completed loops
306
+ loop config Show loop configuration
307
+ loop config --max-iterations 50 Set max iterations
308
+ loop config --max-cost 10.00 Set max cost budget
309
+ loop config --auto-approve-plan Skip manual plan approval
310
+ loop inject [--silent] Output loop context (for hooks)
311
+
312
+ Running a loop with Claude Code:
313
+ export CODER_LOOP_ID=<id>
314
+ claude --continue "Your task"
315
+
235
316
  Registry Commands:
236
317
  registry List MCPs in global registry
237
318
  registry add <name> '<json>' Add MCP to global registry
package/lib/constants.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Constants and tool path configurations
3
3
  */
4
4
 
5
- const VERSION = '0.40.16';
5
+ const VERSION = '0.41.2';
6
6
 
7
7
  // Tool-specific path configurations
8
8
  const TOOL_PATHS = {