ralph.rb 1.2.4355354345 → 2.0.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.
- checksums.yaml +4 -4
- data/.github/workflows/gem-push.yml +2 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +53 -0
- data/lib/ralph/cli.rb +67 -186
- data/lib/ralph/display.rb +105 -0
- data/lib/ralph/events.rb +117 -0
- data/lib/ralph/loop.rb +113 -170
- data/lib/ralph/metrics.rb +88 -0
- data/lib/ralph/opencode.rb +66 -0
- data/lib/ralph/version.rb +1 -1
- data/lib/ralph.rb +0 -3
- data/plans/00-complete-implementation.md +120 -0
- data/plans/01-cli-implementation.md +53 -0
- data/plans/02-loop-implementation.md +78 -0
- data/plans/03-agents-implementation.md +76 -0
- data/plans/04-metrics-implementation.md +98 -0
- data/plans/README.md +63 -0
- data/specs/README.md +4 -15
- data/specs/__templates__/API_TEMPLATE.md +0 -0
- data/specs/__templates__/AUTOMATION_ACTION_TEMPLATE.md +0 -0
- data/specs/__templates__/AUTOMATION_TRIGGER_TEMPLATE.md +0 -0
- data/specs/__templates__/CONTROLLER_TEMPLATE.md +32 -0
- data/specs/__templates__/INTEGRATION_TEMPLATE.md +0 -0
- data/specs/__templates__/MODEL_TEMPLATE.md +0 -0
- data/specs/agents.md +426 -120
- data/specs/cli.md +11 -218
- data/specs/lib/todo_item.rb +144 -0
- data/specs/log +15 -0
- data/specs/loop.md +42 -0
- data/specs/metrics.md +51 -0
- metadata +23 -39
- data/lib/ralph/agents/base.rb +0 -132
- data/lib/ralph/agents/claude_code.rb +0 -24
- data/lib/ralph/agents/codex.rb +0 -25
- data/lib/ralph/agents/open_code.rb +0 -30
- data/lib/ralph/agents.rb +0 -24
- data/lib/ralph/config.rb +0 -40
- data/lib/ralph/git/file_snapshot.rb +0 -60
- data/lib/ralph/helpers.rb +0 -76
- data/lib/ralph/iteration.rb +0 -220
- data/lib/ralph/output/active_loop_error.rb +0 -13
- data/lib/ralph/output/banner.rb +0 -29
- data/lib/ralph/output/completion_deferred.rb +0 -12
- data/lib/ralph/output/completion_detected.rb +0 -17
- data/lib/ralph/output/config_summary.rb +0 -31
- data/lib/ralph/output/context_consumed.rb +0 -11
- data/lib/ralph/output/iteration.rb +0 -45
- data/lib/ralph/output/max_iterations_reached.rb +0 -16
- data/lib/ralph/output/no_plugin_warning.rb +0 -14
- data/lib/ralph/output/nonzero_exit_warning.rb +0 -11
- data/lib/ralph/output/plugin_error.rb +0 -12
- data/lib/ralph/output/status.rb +0 -176
- data/lib/ralph/output/struggle_warning.rb +0 -18
- data/lib/ralph/output/task_completion.rb +0 -12
- data/lib/ralph/output/tasks_file_created.rb +0 -11
- data/lib/ralph/prompt_template.rb +0 -183
- data/lib/ralph/storage/context.rb +0 -58
- data/lib/ralph/storage/history.rb +0 -117
- data/lib/ralph/storage/state.rb +0 -178
- data/lib/ralph/storage/tasks.rb +0 -244
- data/lib/ralph/threads/heartbeat.rb +0 -44
- data/lib/ralph/threads/stream_reader.rb +0 -50
- data/original/bin/ralph.js +0 -13
- data/original/ralph.ts +0 -1706
- data/specs/iteration.md +0 -173
- data/specs/output.md +0 -104
- data/specs/storage/local-data-structure.md +0 -246
- data/specs/tasks.md +0 -295
data/specs/iteration.md
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
# Iteration Class Specification
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
The `Iteration` class is responsible for executing a single AI agent iteration and collecting metrics. It handles the low-level execution details while delegating business logic decisions to the caller.
|
|
6
|
-
|
|
7
|
-
## Location
|
|
8
|
-
|
|
9
|
-
`lib/ralph/iteration.rb`
|
|
10
|
-
|
|
11
|
-
## Dependencies
|
|
12
|
-
|
|
13
|
-
```ruby
|
|
14
|
-
require_relative "types"
|
|
15
|
-
require_relative "helpers"
|
|
16
|
-
require_relative "state"
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Class Interface
|
|
20
|
-
|
|
21
|
-
### Constructor
|
|
22
|
-
|
|
23
|
-
```ruby
|
|
24
|
-
def initialize(loop)
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
**Parameters:**
|
|
28
|
-
- `loop` - `Ralph::Loop` instance. Provides access to:
|
|
29
|
-
- `loop.config` - `Ralph::Config` instance with all execution options (model, stream_output, verbose_tools, allow_all_permissions, disable_plugins, completion_promise, etc.)
|
|
30
|
-
- `loop.agent_config` - `Ralph::Agents::Base` instance providing command, build_args, build_env, etc. (see [agents.md](./agents.md))
|
|
31
|
-
|
|
32
|
-
### Main Method
|
|
33
|
-
|
|
34
|
-
```ruby
|
|
35
|
-
def call(prompt, iteration_start:)
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
**Parameters:**
|
|
39
|
-
- `prompt` - String containing the prompt to send to the agent
|
|
40
|
-
- `iteration_start` - Integer timestamp (ms) when the iteration started
|
|
41
|
-
|
|
42
|
-
**Returns:**
|
|
43
|
-
- `IterationResult` struct with execution data
|
|
44
|
-
|
|
45
|
-
## Result Type
|
|
46
|
-
|
|
47
|
-
```ruby
|
|
48
|
-
IterationResult = Struct.new(
|
|
49
|
-
:duration_ms, # Integer - execution duration in milliseconds
|
|
50
|
-
:exit_code, # Integer - agent process exit code
|
|
51
|
-
:stdout_text, # String - agent stdout output
|
|
52
|
-
:stderr_text, # String - agent stderr output
|
|
53
|
-
:tool_counts, # Hash<String, Integer> - tool usage counts
|
|
54
|
-
:files_modified, # Array<String> - list of files changed during iteration
|
|
55
|
-
:completion_detected, # Boolean - whether completion promise was found
|
|
56
|
-
:errors, # Array<String> - extracted errors from output
|
|
57
|
-
:success # Boolean - overall success (no crashes, exit_code == 0)
|
|
58
|
-
)
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Internal Responsibilities
|
|
62
|
-
|
|
63
|
-
### 1. Agent Execution
|
|
64
|
-
- Build agent command using `agent_config.build_args` and `agent_config.build_env`
|
|
65
|
-
- Execute agent (streaming or buffered based on options)
|
|
66
|
-
- Capture stdout, stderr, exit code, and tool usage data
|
|
67
|
-
- Handle agent process lifecycle
|
|
68
|
-
|
|
69
|
-
### 2. Metrics Collection
|
|
70
|
-
- Calculate execution duration from `iteration_start`
|
|
71
|
-
- Extract tool counts from agent output using `agent_config.parse_tool_output`
|
|
72
|
-
- Capture file snapshots before/after execution using `State.capture_file_snapshot`
|
|
73
|
-
- Detect files modified via `State.modified_files_since_snapshot`
|
|
74
|
-
|
|
75
|
-
### 3. Data Extraction
|
|
76
|
-
- Combine stdout/stderr for analysis
|
|
77
|
-
- Detect completion promise using `::Ralph::Helpers.check_completion`
|
|
78
|
-
- Extract errors from combined output using `::Ralph::Helpers.extract_errors`
|
|
79
|
-
- Determine overall success status
|
|
80
|
-
|
|
81
|
-
### 4. Result Packaging
|
|
82
|
-
- Assemble all collected data into `IterationResult`
|
|
83
|
-
- Return structured result to caller
|
|
84
|
-
|
|
85
|
-
## External Dependencies (Provided by Caller)
|
|
86
|
-
|
|
87
|
-
The class expects the caller to handle:
|
|
88
|
-
- **Prompt Building** - Creating the prompt text using `PromptBuilder`
|
|
89
|
-
- **Output Display** - Showing iteration summaries, warnings, etc.
|
|
90
|
-
- **History Management** - Recording iteration data in `RalphHistory`
|
|
91
|
-
- **State Updates** - Managing loop state, iteration counters
|
|
92
|
-
- **Completion Decisions** - Determining whether to continue or break loop
|
|
93
|
-
- **Error Handling** - Deciding how to respond to iteration errors
|
|
94
|
-
- **Post-Processing** - Auto-committing changes, consuming context
|
|
95
|
-
|
|
96
|
-
## Error Handling
|
|
97
|
-
|
|
98
|
-
The `Iteration` class handles:
|
|
99
|
-
- Process execution errors (captures in result)
|
|
100
|
-
- Stream processing errors (captures in result)
|
|
101
|
-
- File operation errors for snapshots (gracefully degrades)
|
|
102
|
-
- Agent process cleanup if errors occur
|
|
103
|
-
|
|
104
|
-
It does NOT:
|
|
105
|
-
- Display error messages (caller responsibility)
|
|
106
|
-
- Modify loop state (caller responsibility)
|
|
107
|
-
- Make retry decisions (caller responsibility)
|
|
108
|
-
|
|
109
|
-
## Usage Example
|
|
110
|
-
|
|
111
|
-
```ruby
|
|
112
|
-
# In Loop class (Loop exposes attr_reader :config, :agent_config)
|
|
113
|
-
iteration = Iteration.new(self)
|
|
114
|
-
|
|
115
|
-
result = iteration.call(full_prompt, iteration_start: start_time)
|
|
116
|
-
|
|
117
|
-
# Caller processes result
|
|
118
|
-
Output::IterationSummary.call(
|
|
119
|
-
iteration: @state.iteration,
|
|
120
|
-
elapsed_ms: result.duration_ms,
|
|
121
|
-
tool_counts: result.tool_counts,
|
|
122
|
-
exit_code: result.exit_code,
|
|
123
|
-
completion_detected: result.completion_detected
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
# Caller updates history
|
|
127
|
-
record_iteration_in_history(result)
|
|
128
|
-
|
|
129
|
-
# Caller decides what to do next
|
|
130
|
-
if result.completion_detected && @state.iteration >= @min_iterations
|
|
131
|
-
# Handle completion
|
|
132
|
-
end
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Implementation Notes
|
|
136
|
-
|
|
137
|
-
### Thread Safety
|
|
138
|
-
The class holds a reference to the parent `Loop` instance and mutable streaming state. It is not intended for concurrent use across multiple loops.
|
|
139
|
-
|
|
140
|
-
### Performance Considerations
|
|
141
|
-
- File snapshot operations should be efficient (git-based)
|
|
142
|
-
- Stream processing should handle large outputs without memory issues
|
|
143
|
-
- Tool counting should be done efficiently via line-by-line processing
|
|
144
|
-
|
|
145
|
-
### Extensibility
|
|
146
|
-
New config values are automatically available to `Iteration` via `@loop.config` without constructor changes.
|
|
147
|
-
The `IterationResult` struct can be extended with additional fields as needed.
|
|
148
|
-
|
|
149
|
-
## Testing Strategy
|
|
150
|
-
|
|
151
|
-
### Unit Tests
|
|
152
|
-
- Mock `Open3` to test agent execution logic
|
|
153
|
-
- Mock `State` methods to test file snapshot logic
|
|
154
|
-
- Test completion detection with various output formats
|
|
155
|
-
- Test error extraction from different types of output
|
|
156
|
-
- Test tool counting with different agent output formats
|
|
157
|
-
|
|
158
|
-
### Integration Tests
|
|
159
|
-
- Test with actual agent binaries (if available in test environment)
|
|
160
|
-
- Test file snapshot operations with git repositories
|
|
161
|
-
- Test streaming vs buffered output modes
|
|
162
|
-
- Test error scenarios (agent crashes, git operations fail)
|
|
163
|
-
|
|
164
|
-
## Migration Path
|
|
165
|
-
|
|
166
|
-
1. Create the new `Iteration` class with this interface
|
|
167
|
-
2. Update `Loop` class to use `Iteration` for agent execution
|
|
168
|
-
3. Move iteration-related private methods from `Loop` to `Iteration`
|
|
169
|
-
4. Update `Loop` to process `IterationResult` instead of handling execution directly
|
|
170
|
-
5. Remove redundant code from `Loop` class
|
|
171
|
-
6. Add tests for the new `Iteration` class
|
|
172
|
-
|
|
173
|
-
This refactoring will improve separation of concerns, testability, and maintainability of the iteration execution logic.
|
data/specs/output.md
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
# Output Specification
|
|
2
|
-
|
|
3
|
-
All terminal output in Ralph is structured as callable output classes under the `Ralph::Output` namespace. Each class encapsulates a single output concern — a banner, a warning, a summary — and exposes a `self.call` class method as its only public interface.
|
|
4
|
-
|
|
5
|
-
## Namespace & File Layout
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
lib/ralph/output/
|
|
9
|
-
no_plugin_warning.rb # Ralph::Output::NoPluginWarning
|
|
10
|
-
banner.rb # Ralph::Output::Banner
|
|
11
|
-
iteration.rb # Ralph::Output::Iteration::Header
|
|
12
|
-
# Ralph::Output::Iteration::Summary
|
|
13
|
-
# Ralph::Output::Iteration::Error
|
|
14
|
-
...
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Each file defines one or more classes inside `module Ralph; module Output; ... end; end`.
|
|
18
|
-
|
|
19
|
-
When several output classes share a common concern (e.g. iteration lifecycle), they are grouped under a nested module in a single file. The submodule acts as a namespace — it contains only classes, no logic of its own.
|
|
20
|
-
|
|
21
|
-
## Interface: The Callable Object Pattern
|
|
22
|
-
|
|
23
|
-
Every output class follows the same shape:
|
|
24
|
-
|
|
25
|
-
```ruby
|
|
26
|
-
module Ralph
|
|
27
|
-
module Output
|
|
28
|
-
class ExampleWarning
|
|
29
|
-
def self.call(thing:, count:)
|
|
30
|
-
warn "Warning: #{thing} happened #{count} times"
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Rules
|
|
38
|
-
|
|
39
|
-
| Rule | Detail |
|
|
40
|
-
|------|--------|
|
|
41
|
-
| **Entry point** | `self.call` — a class method, never instantiated |
|
|
42
|
-
| **Arguments** | All inputs passed as **keyword arguments** for clarity at the call site |
|
|
43
|
-
| **Return value** | None expected. These are fire-and-forget side-effect methods |
|
|
44
|
-
| **Single responsibility** | One output concern per class. If a method prints a banner, that's one class. If it prints an iteration summary, that's another |
|
|
45
|
-
| **Grouping** | Related output classes may be grouped under a nested module in a single file (e.g. `Output::Iteration::Header`, `Output::Iteration::Summary`, `Output::Iteration::Error` all live in `iteration.rb`) |
|
|
46
|
-
| **No base class** | Plain `Object` inheritance. No shared superclass or included module required |
|
|
47
|
-
|
|
48
|
-
## Output Channels
|
|
49
|
-
|
|
50
|
-
Use the appropriate channel based on the nature of the output:
|
|
51
|
-
|
|
52
|
-
| Channel | Ruby method | When to use |
|
|
53
|
-
|---------|-------------|-------------|
|
|
54
|
-
| **stdout** | `puts` | Informational output: banners, summaries, progress, status |
|
|
55
|
-
| **stderr** | `warn` or `$stderr.puts` | Warnings, errors, and diagnostics that should not pollute stdout |
|
|
56
|
-
|
|
57
|
-
`warn` is preferred over `$stderr.puts` for single-line warnings because it respects Ruby's `-W` flag and is idiomatic.
|
|
58
|
-
|
|
59
|
-
## Requiring & Usage
|
|
60
|
-
|
|
61
|
-
Output classes are required where they are used, not auto-loaded:
|
|
62
|
-
|
|
63
|
-
```ruby
|
|
64
|
-
require_relative "output/no_plugin_warning"
|
|
65
|
-
|
|
66
|
-
# Later, at the call site:
|
|
67
|
-
Output::NoPluginWarning.call(chosen_agent: @agent_config.type)
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
There is no `lib/ralph/output.rb` barrel file. Each class is required individually by the code that needs it.
|
|
71
|
-
|
|
72
|
-
## Reference Implementation
|
|
73
|
-
|
|
74
|
-
`lib/ralph/output/no_plugin_warning.rb` is the canonical example:
|
|
75
|
-
|
|
76
|
-
```ruby
|
|
77
|
-
module Ralph
|
|
78
|
-
module Output
|
|
79
|
-
class NoPluginWarning
|
|
80
|
-
def self.call(chosen_agent:)
|
|
81
|
-
case chosen_agent
|
|
82
|
-
when :claude_code
|
|
83
|
-
warn "Warning: --no-plugins has no effect with Claude Code agent"
|
|
84
|
-
when :codex
|
|
85
|
-
warn "Warning: --no-plugins has no effect with Codex agent"
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Key things to note:
|
|
94
|
-
|
|
95
|
-
- The class decides **what** to print based on its arguments (the `case` on `chosen_agent`).
|
|
96
|
-
- The caller does not need to know the message text — it passes data, and the output class formats it.
|
|
97
|
-
- The caller (`Loop#call` in `lib/ralph/loop.rb`) reads as `Output::NoPluginWarning.call(chosen_agent: ...)` — intent is clear at the call site.
|
|
98
|
-
|
|
99
|
-
## Formatting Conventions
|
|
100
|
-
|
|
101
|
-
- **Box-drawing characters** (`═`, `║`, `╔`, `╗`, `╚`, `╝`, `─`) are used for prominent banners and completion boxes.
|
|
102
|
-
- **Unicode symbols** (checkmarks, warning signs, emoji) are used sparingly for status indicators.
|
|
103
|
-
- **Line width** is 68 characters for horizontal rules and box borders.
|
|
104
|
-
- Formatting logic lives inside the output class, not at the call site.
|
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
# Ralph Storage Architecture Specification
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
The Ralph autonomous agent maintains persistent state across sessions through a modular storage system. All state is stored in the `.ralph/` directory within the project root, providing persistence for autonomous coding sessions, iteration history, context management, and task tracking.
|
|
6
|
-
|
|
7
|
-
## File Structure
|
|
8
|
-
|
|
9
|
-
### Root Directory Layout
|
|
10
|
-
```
|
|
11
|
-
.ralph/
|
|
12
|
-
├── ralph-loop.state.json # Main loop state
|
|
13
|
-
├── ralph-history.json # Complete iteration history
|
|
14
|
-
├── ralph-context.md # Persistent AI context
|
|
15
|
-
├── ralph-tasks.md # Task management
|
|
16
|
-
└── ralph-opencode.config.json # OpenCode plugin configuration
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Storage Module Architecture
|
|
20
|
-
|
|
21
|
-
### Directory Structure
|
|
22
|
-
```
|
|
23
|
-
lib/ralph/storage/
|
|
24
|
-
├── history.rb # Ralph::Storage::History class
|
|
25
|
-
├── state.rb # Ralph::Storage::State class
|
|
26
|
-
├── context.rb # Ralph::Storage::Context class
|
|
27
|
-
├── tasks.rb # Ralph::Storage::Tasks class + Task/Tasks models
|
|
28
|
-
└── . # Main storage module file
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Module Organization
|
|
32
|
-
|
|
33
|
-
#### Ralph::Storage::History
|
|
34
|
-
**Purpose**: Manages complete iteration history across Ralph sessions.
|
|
35
|
-
|
|
36
|
-
**Responsibilities**:
|
|
37
|
-
- Save/load iteration history to `.ralph/ralph-history.json`
|
|
38
|
-
- Track struggle indicators and performance metrics
|
|
39
|
-
- Maintain chronology of all iterations
|
|
40
|
-
- Provide history analytics
|
|
41
|
-
|
|
42
|
-
**Data Structure**:
|
|
43
|
-
```ruby
|
|
44
|
-
RalphHistory = Struct.new(
|
|
45
|
-
:iterations, # Array<IterationHistory>
|
|
46
|
-
:total_duration_ms, # Integer
|
|
47
|
-
:struggle_indicators, # StruggleIndicators
|
|
48
|
-
keyword_init: true
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
IterationHistory = Struct.new(
|
|
52
|
-
:iteration, # Integer
|
|
53
|
-
:started_at, # String (ISO 8601)
|
|
54
|
-
:ended_at, # String (ISO 8601)
|
|
55
|
-
:duration_ms, # Integer
|
|
56
|
-
:tools_used, # Hash<String, Integer>
|
|
57
|
-
:files_modified, # Array<String>
|
|
58
|
-
:exit_code, # Integer
|
|
59
|
-
:completion_detected, # Boolean
|
|
60
|
-
:errors # Array<String>
|
|
61
|
-
)
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
**File Format**: JSON with iteration data, total duration, and struggle indicators.
|
|
65
|
-
|
|
66
|
-
#### Ralph::Storage::State
|
|
67
|
-
**Purpose**: Manages the active loop state for current Ralph session.
|
|
68
|
-
|
|
69
|
-
**Responsibilities**:
|
|
70
|
-
- Save/load loop state to `.ralph/ralph-loop.state.json`
|
|
71
|
-
- Track session metadata (iteration count, timing, configuration)
|
|
72
|
-
- Handle session lifecycle (start, stop, resume)
|
|
73
|
-
- File change detection via git snapshots
|
|
74
|
-
- OpenCode configuration management
|
|
75
|
-
|
|
76
|
-
**Data Structure**:
|
|
77
|
-
```ruby
|
|
78
|
-
RalphState = Struct.new(
|
|
79
|
-
:active, # Boolean
|
|
80
|
-
:iteration, # Integer
|
|
81
|
-
:min_iterations, # Integer
|
|
82
|
-
:max_iterations, # Integer
|
|
83
|
-
:completion_promise, # String
|
|
84
|
-
:tasks_mode, # Boolean
|
|
85
|
-
:task_promise, # String
|
|
86
|
-
:prompt, # String
|
|
87
|
-
:started_at, # String (ISO 8601)
|
|
88
|
-
:model, # String
|
|
89
|
-
:agent, # String
|
|
90
|
-
keyword_init: true
|
|
91
|
-
)
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**File Format**: JSON with loop configuration and session state.
|
|
95
|
-
|
|
96
|
-
**Additional Features**:
|
|
97
|
-
- `capture_file_snapshot()` - Git-based file state tracking
|
|
98
|
-
- `modified_files_since_snapshot()` - Change detection
|
|
99
|
-
- `ensure_ralph_config()` - OpenCode plugin configuration
|
|
100
|
-
- `load_plugins_from_config()` - Plugin discovery from config files
|
|
101
|
-
|
|
102
|
-
#### Ralph::Storage::Context
|
|
103
|
-
**Purpose**: Manages persistent AI context for maintaining conversational continuity.
|
|
104
|
-
|
|
105
|
-
**Responsibilities**:
|
|
106
|
-
- Load context from `.ralph/ralph-context.md`
|
|
107
|
-
- Clear context when sessions end
|
|
108
|
-
- Provide context for AI prompt building
|
|
109
|
-
|
|
110
|
-
**File Format**: Markdown file with structured context sections.
|
|
111
|
-
|
|
112
|
-
#### Ralph::Storage::Tasks
|
|
113
|
-
**Purpose**: Manages task tracking and workflow coordination.
|
|
114
|
-
|
|
115
|
-
**Responsibilities**:
|
|
116
|
-
- Save/load tasks to `.ralph/ralph-tasks.md`
|
|
117
|
-
- Parse and render task lists in markdown format
|
|
118
|
-
- Track task status (todo, in_progress, complete)
|
|
119
|
-
- Handle subtasks and task hierarchy
|
|
120
|
-
- Provide task analytics and display methods
|
|
121
|
-
|
|
122
|
-
**Data Structures**:
|
|
123
|
-
```ruby
|
|
124
|
-
Task = Struct.new(
|
|
125
|
-
:text, # String
|
|
126
|
-
:status, # Symbol (:todo, :in_progress, :complete)
|
|
127
|
-
:subtasks, # Array<Task>
|
|
128
|
-
:original_line, # String (for round-trip preservation)
|
|
129
|
-
keyword_init: true
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
Tasks = Enumerable collection of Task objects
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
**File Format**: Markdown with checkbox syntax:
|
|
136
|
-
```markdown
|
|
137
|
-
# Ralph Tasks
|
|
138
|
-
|
|
139
|
-
- [ ] Task 1 description
|
|
140
|
-
- [/] Task 2 in progress
|
|
141
|
-
- [ ] Subtask 2.1
|
|
142
|
-
- [x] Subtask 2.2
|
|
143
|
-
- [x] Task 3 complete
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## State Persistence Patterns
|
|
147
|
-
|
|
148
|
-
### Atomic Operations
|
|
149
|
-
All write operations use atomic file writing to prevent corruption:
|
|
150
|
-
- Write to temporary file first
|
|
151
|
-
- Rename/replace original file atomically
|
|
152
|
-
- Handle filesystem errors gracefully
|
|
153
|
-
|
|
154
|
-
### Error Handling
|
|
155
|
-
- All load operations handle missing files gracefully
|
|
156
|
-
- JSON parsing errors return empty/default states
|
|
157
|
-
- Filesystem errors are caught and logged
|
|
158
|
-
- State corruption recovery with fallback to empty state
|
|
159
|
-
|
|
160
|
-
### Directory Management
|
|
161
|
-
- `.ralph/` directory created automatically when needed
|
|
162
|
-
- Directory permissions set appropriately
|
|
163
|
-
- Cleanup operations preserve important state files
|
|
164
|
-
|
|
165
|
-
## Configuration Integration
|
|
166
|
-
|
|
167
|
-
### OpenCode Configuration
|
|
168
|
-
Storage::State manages OpenCode plugin configuration through:
|
|
169
|
-
- `.ralph/ralph-opencode.config.json` - Generated config file
|
|
170
|
-
- User config discovery: `~/.config/opencode/opencode.json`
|
|
171
|
-
- Project config discovery: `.ralph/opencode.json` or `.opencode/opencode.json`
|
|
172
|
-
- Plugin filtering and permission management
|
|
173
|
-
|
|
174
|
-
### Config File Format
|
|
175
|
-
```json
|
|
176
|
-
{
|
|
177
|
-
"$schema": "https://opencode.ai/config.json",
|
|
178
|
-
"plugin": ["auth-plugin"],
|
|
179
|
-
"permission": {
|
|
180
|
-
"read": "allow",
|
|
181
|
-
"edit": "allow",
|
|
182
|
-
// ... all tool permissions
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## Migration Strategy
|
|
188
|
-
|
|
189
|
-
### Backward Compatibility
|
|
190
|
-
The original `State` module in `lib/ralph/state.rb` remains as a thin wrapper:
|
|
191
|
-
- Requires the new Storage module
|
|
192
|
-
- Delegates all existing methods to appropriate Storage classes
|
|
193
|
-
- Maintains identical public interface
|
|
194
|
-
- No functional changes to existing code
|
|
195
|
-
|
|
196
|
-
### Update Dependencies
|
|
197
|
-
Files requiring state management will need minimal updates:
|
|
198
|
-
- Add `require_relative "storage"` where needed
|
|
199
|
-
- All existing `State.method` calls continue to work unchanged
|
|
200
|
-
- Gradual migration to use Storage classes directly is optional
|
|
201
|
-
|
|
202
|
-
## Data Lifecycle
|
|
203
|
-
|
|
204
|
-
### Session Start
|
|
205
|
-
1. Load existing state from `.ralph/ralph-loop.state.json`
|
|
206
|
-
2. Check for active sessions (prevent concurrent loops)
|
|
207
|
-
3. Load history and context
|
|
208
|
-
4. Initialize new session state if needed
|
|
209
|
-
5. Create task file if tasks mode enabled
|
|
210
|
-
|
|
211
|
-
### During Session
|
|
212
|
-
1. Update state after each iteration
|
|
213
|
-
2. Append to history with iteration results
|
|
214
|
-
3. Track file changes via git snapshots
|
|
215
|
-
4. Update context as needed
|
|
216
|
-
|
|
217
|
-
### Session End
|
|
218
|
-
1. Clear active state flag
|
|
219
|
-
2. Save final history and state
|
|
220
|
-
3. Optionally clear context (based on configuration)
|
|
221
|
-
4. Cleanup temporary files
|
|
222
|
-
|
|
223
|
-
### Error Recovery
|
|
224
|
-
1. Automatic state clearing on crashes/interrupts
|
|
225
|
-
2. History preservation through graceful degradation
|
|
226
|
-
3. Context recovery from last good state
|
|
227
|
-
4. Task file preservation across all scenarios
|
|
228
|
-
|
|
229
|
-
## Security Considerations
|
|
230
|
-
|
|
231
|
-
### File Permissions
|
|
232
|
-
- `.ralph/` directory permissions restricted to owner
|
|
233
|
-
- Sensitive configuration files protected appropriately
|
|
234
|
-
- No world-readable state files
|
|
235
|
-
|
|
236
|
-
### Data Sanitization
|
|
237
|
-
- JSON validation on all loaded data
|
|
238
|
-
- Markdown sanitization for context/tasks
|
|
239
|
-
- Plugin configuration validation
|
|
240
|
-
- Safe handling of file paths and content
|
|
241
|
-
|
|
242
|
-
### Integrity Checks
|
|
243
|
-
- JSON schema validation for structured data
|
|
244
|
-
- File content checksums where appropriate
|
|
245
|
-
- Consistency checks between related files
|
|
246
|
-
- Recovery procedures for corrupted state
|