ralph-scaffold 1.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.
- package/bin/cli.js +67 -0
- package/package.json +30 -0
- package/scripts/ralph/prd.json +17 -0
- package/scripts/ralph/prompt.md +44 -0
- package/scripts/ralph/ralph-usage-guide.md +183 -0
- package/scripts/ralph/ralph.sh +28 -0
package/bin/cli.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
|
|
10
|
+
// The source 'scripts' directory inside the package
|
|
11
|
+
const sourceDir = path.resolve(__dirname, '../scripts');
|
|
12
|
+
// The destination 'scripts' directory in the user's project
|
|
13
|
+
const targetDir = path.resolve(process.cwd(), 'scripts');
|
|
14
|
+
console.log(`\nYou can read ralph-usage-guide.md for more info.`)
|
|
15
|
+
console.log(`\nš Scaffolding Ralph scripts...`);
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
if (!fs.existsSync(sourceDir)) {
|
|
19
|
+
console.error(`Error: Source directory not found at ${sourceDir}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Use fs.cpSync if available (Node.js 16.7.0+), otherwise fallback or manually copy
|
|
24
|
+
// Since we want to be broadly compatible, let's just implement a simple recursive copy
|
|
25
|
+
// or use fs.cpSync if it is available. Use cpSync for simplicity as it covers 'recursive'.
|
|
26
|
+
if (fs.cpSync) {
|
|
27
|
+
fs.cpSync(sourceDir, targetDir, { recursive: true });
|
|
28
|
+
} else {
|
|
29
|
+
// Fallback for older Node versions
|
|
30
|
+
copyRecursiveSync(sourceDir, targetDir);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(`ā
'scripts/ralph' has been created in ${process.cwd()}`);
|
|
34
|
+
|
|
35
|
+
// Make the shell script executable
|
|
36
|
+
const scriptPath = path.join(targetDir, 'ralph', 'ralph.sh');
|
|
37
|
+
if (fs.existsSync(scriptPath)) {
|
|
38
|
+
try {
|
|
39
|
+
fs.chmodSync(scriptPath, '755');
|
|
40
|
+
} catch (e) {
|
|
41
|
+
console.warn(`ā ļø Warning: Could not make ${scriptPath} executable. You may need to run 'chmod +x ${scriptPath}' manually.`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log(`\nYou can now use the Ralph scripts in your workflow.`);
|
|
46
|
+
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error('ā Error scaffolding files:', err);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function copyRecursiveSync(src, dest) {
|
|
53
|
+
const exists = fs.existsSync(src);
|
|
54
|
+
const stats = exists && fs.statSync(src);
|
|
55
|
+
const isDirectory = exists && stats.isDirectory();
|
|
56
|
+
|
|
57
|
+
if (isDirectory) {
|
|
58
|
+
if (!fs.existsSync(dest)) {
|
|
59
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
fs.readdirSync(src).forEach((childItemName) => {
|
|
62
|
+
copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
fs.copyFileSync(src, dest);
|
|
66
|
+
}
|
|
67
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ralph-scaffold",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "scripts to get you started using Ralph workflow",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ralph"
|
|
7
|
+
],
|
|
8
|
+
"homepage": "https://github.com/rickvian/ralph-scaffold#readme",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/rickvian/ralph-scaffold/issues"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/rickvian/ralph-scaffold.git"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "Rcikvian",
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "index.js",
|
|
20
|
+
"bin": {
|
|
21
|
+
"ralph-scaffold": "./bin/cli.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"bin",
|
|
25
|
+
"scripts"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"branchName": "ralph/feature",
|
|
3
|
+
"userStories": [
|
|
4
|
+
{
|
|
5
|
+
"id": "US-001",
|
|
6
|
+
"title": "Add login form",
|
|
7
|
+
"acceptanceCriteria": [
|
|
8
|
+
"Email/password fields",
|
|
9
|
+
"Validates email format",
|
|
10
|
+
"typecheck passes"
|
|
11
|
+
],
|
|
12
|
+
"priority": 1,
|
|
13
|
+
"passes": false,
|
|
14
|
+
"notes": ""
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Ralph Agent Instructions
|
|
2
|
+
|
|
3
|
+
## Your Task
|
|
4
|
+
|
|
5
|
+
1. Read `scripts/ralph/prd.json`
|
|
6
|
+
2. Read `scripts/ralph/progress.txt`
|
|
7
|
+
(check Codebase Patterns first)
|
|
8
|
+
3. Check you're on the correct branch
|
|
9
|
+
4. Pick highest priority story
|
|
10
|
+
where `passes: false`
|
|
11
|
+
5. Implement that ONE story
|
|
12
|
+
6. Run typecheck and tests
|
|
13
|
+
7. Update AGENTS.md files with learnings
|
|
14
|
+
8. Commit: `feat: [ID] - [Title]`
|
|
15
|
+
9. Update prd.json: `passes: true`
|
|
16
|
+
10. Append learnings to progress.txt
|
|
17
|
+
|
|
18
|
+
## Progress Format
|
|
19
|
+
|
|
20
|
+
APPEND to progress.txt:
|
|
21
|
+
|
|
22
|
+
## [Date] - [Story ID]
|
|
23
|
+
- What was implemented
|
|
24
|
+
- Files changed
|
|
25
|
+
- **Learnings:**
|
|
26
|
+
- Patterns discovered
|
|
27
|
+
- Gotchas encountered
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Codebase Patterns
|
|
31
|
+
|
|
32
|
+
Add reusable patterns to the TOP
|
|
33
|
+
of progress.txt:
|
|
34
|
+
|
|
35
|
+
## Codebase Patterns
|
|
36
|
+
- Migrations: Use IF NOT EXISTS
|
|
37
|
+
- React: useRef<Timeout | null>(null)
|
|
38
|
+
|
|
39
|
+
## Stop Condition
|
|
40
|
+
|
|
41
|
+
If ALL stories pass, reply:
|
|
42
|
+
<promise>COMPLETE</promise>
|
|
43
|
+
|
|
44
|
+
Otherwise end normally.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
This ralph setup is based on https://x.com/ryancarson/status/2008548371712135632
|
|
2
|
+
|
|
3
|
+
This is guide for human and AI agent should ignore this file.
|
|
4
|
+
|
|
5
|
+
### How It Works
|
|
6
|
+
A bash loop that:
|
|
7
|
+
Pipes a prompt into your AI agent
|
|
8
|
+
Agent picks the next story from prd.json
|
|
9
|
+
Agent implements it
|
|
10
|
+
Agent runs typecheck + tests
|
|
11
|
+
Agent commits if passing
|
|
12
|
+
Agent marks story done
|
|
13
|
+
Agent logs learnings
|
|
14
|
+
Loop repeats until done
|
|
15
|
+
|
|
16
|
+
### Memory persists only through:
|
|
17
|
+
Git commits
|
|
18
|
+
progress.txt (learnings)
|
|
19
|
+
prd.json (task status)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
scripts/ralph/
|
|
24
|
+
āāā ralph.sh
|
|
25
|
+
āāā prompt.md
|
|
26
|
+
āāā prd.json
|
|
27
|
+
āāā progress.txt
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## ralph.sh
|
|
31
|
+
|
|
32
|
+
The loop:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
#!/bin/bash
|
|
36
|
+
set -e
|
|
37
|
+
|
|
38
|
+
MAX_ITERATIONS=${1:-10}
|
|
39
|
+
SCRIPT_DIR="$(cd "$(dirname \
|
|
40
|
+
"${BASH_SOURCE[0]}")" && pwd)"
|
|
41
|
+
|
|
42
|
+
echo "š Starting Ralph"
|
|
43
|
+
|
|
44
|
+
for i in $(seq 1 $MAX_ITERATIONS); do
|
|
45
|
+
echo "āāā Iteration $i āāā"
|
|
46
|
+
|
|
47
|
+
OUTPUT=$(cat "$SCRIPT_DIR/prompt.md" \
|
|
48
|
+
| claude --dangerously-skip-permissions 2>&1 \
|
|
49
|
+
| tee /dev/stderr) || true
|
|
50
|
+
|
|
51
|
+
if echo "$OUTPUT" | \
|
|
52
|
+
grep -q "<promise>COMPLETE</promise>"
|
|
53
|
+
then
|
|
54
|
+
echo "ā
Done!"
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
sleep 2
|
|
59
|
+
done
|
|
60
|
+
|
|
61
|
+
echo "ā ļø Max iterations reached"
|
|
62
|
+
exit 1
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Make executable:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
chmod +x scripts/ralph/ralph.sh
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## prompt.md
|
|
73
|
+
Instructions for each iteration:
|
|
74
|
+
|
|
75
|
+
```markdown
|
|
76
|
+
# Ralph Agent Instructions
|
|
77
|
+
|
|
78
|
+
## Your Task
|
|
79
|
+
|
|
80
|
+
1. Read `scripts/ralph/prd.json`
|
|
81
|
+
2. Read `scripts/ralph/progress.txt`
|
|
82
|
+
(check Codebase Patterns first)
|
|
83
|
+
3. Check you're on the correct branch
|
|
84
|
+
4. Pick highest priority story
|
|
85
|
+
where `passes: false`
|
|
86
|
+
5. Implement that ONE story
|
|
87
|
+
6. Run typecheck and tests
|
|
88
|
+
7. Update AGENTS.md files with learnings
|
|
89
|
+
8. Commit: `feat: [ID] - [Title]`
|
|
90
|
+
9. Update prd.json: `passes: true`
|
|
91
|
+
10. Append learnings to progress.txt
|
|
92
|
+
|
|
93
|
+
## Progress Format
|
|
94
|
+
|
|
95
|
+
APPEND to progress.txt:
|
|
96
|
+
|
|
97
|
+
## [Date] - [Story ID]
|
|
98
|
+
- What was implemented
|
|
99
|
+
- Files changed
|
|
100
|
+
- **Learnings:**
|
|
101
|
+
- Patterns discovered
|
|
102
|
+
- Gotchas encountered
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Codebase Patterns
|
|
106
|
+
|
|
107
|
+
Add reusable patterns to the TOP
|
|
108
|
+
of progress.txt:
|
|
109
|
+
|
|
110
|
+
## Codebase Patterns
|
|
111
|
+
- Migrations: Use IF NOT EXISTS
|
|
112
|
+
- React: useRef<Timeout | null>(null)
|
|
113
|
+
|
|
114
|
+
## Stop Condition
|
|
115
|
+
|
|
116
|
+
If ALL stories pass, reply:
|
|
117
|
+
<promise>COMPLETE</promise>
|
|
118
|
+
|
|
119
|
+
Otherwise end normally.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## prd.json
|
|
123
|
+
Your task list:
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"branchName": "ralph/feature",
|
|
127
|
+
"userStories": [
|
|
128
|
+
{
|
|
129
|
+
"id": "US-001",
|
|
130
|
+
"title": "Add login form",
|
|
131
|
+
"acceptanceCriteria": [
|
|
132
|
+
"Email/password fields",
|
|
133
|
+
"Validates email format",
|
|
134
|
+
"typecheck passes"
|
|
135
|
+
],
|
|
136
|
+
"priority": 1,
|
|
137
|
+
"passes": false,
|
|
138
|
+
"notes": ""
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Key fields:
|
|
145
|
+
`branchName` ā branch to use
|
|
146
|
+
`priority` ā lower = first
|
|
147
|
+
`passes` ā set true when done
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
## progress.txt
|
|
151
|
+
Start with context:
|
|
152
|
+
|
|
153
|
+
```markdown
|
|
154
|
+
# Ralph Progress Log
|
|
155
|
+
Started: 2024-01-15
|
|
156
|
+
|
|
157
|
+
## Codebase Patterns
|
|
158
|
+
- Migrations: IF NOT EXISTS
|
|
159
|
+
- Types: Export from actions.ts
|
|
160
|
+
|
|
161
|
+
## Key Files
|
|
162
|
+
- db/schema.ts
|
|
163
|
+
- app/auth/actions.ts
|
|
164
|
+
---
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
Ralph appends after each story.
|
|
169
|
+
Patterns accumulate across iterations.
|
|
170
|
+
|
|
171
|
+
## Running Ralph
|
|
172
|
+
|
|
173
|
+
run the ralph script with 25 iterations
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
./scripts/ralph/ralph.sh 25
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Ralph will:
|
|
180
|
+
- Create the feature branch
|
|
181
|
+
- Complete stories one by one
|
|
182
|
+
- Commit after each
|
|
183
|
+
- Stop when all pass
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
MAX_ITERATIONS=${1:-10}
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname \
|
|
6
|
+
"${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
|
|
8
|
+
echo "š Starting Ralph"
|
|
9
|
+
|
|
10
|
+
for i in $(seq 1 $MAX_ITERATIONS); do
|
|
11
|
+
echo "āāā Iteration $i āāā"
|
|
12
|
+
|
|
13
|
+
OUTPUT=$(cat "$SCRIPT_DIR/prompt.md" \
|
|
14
|
+
| amp --dangerously-allow-all 2>&1 \
|
|
15
|
+
| tee /dev/stderr) || true
|
|
16
|
+
|
|
17
|
+
if echo "$OUTPUT" | \
|
|
18
|
+
grep -q "<promise>COMPLETE</promise>"
|
|
19
|
+
then
|
|
20
|
+
echo "ā
Done!"
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
sleep 2
|
|
25
|
+
done
|
|
26
|
+
|
|
27
|
+
echo "ā ļø Max iterations reached"
|
|
28
|
+
exit 1
|