ralph-tool 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/Dockerfile +40 -0
- package/README.md +148 -0
- package/bin/ralph.js +357 -0
- package/docker-compose.yaml +40 -0
- package/helpers/constants.sh +22 -0
- package/helpers/cost_helpers.sh +73 -0
- package/helpers/display_helpers.sh +312 -0
- package/helpers/extract_subagent_map.jq +32 -0
- package/helpers/iteration_helpers.sh +69 -0
- package/helpers/output_formatting.jq +294 -0
- package/package.json +48 -0
- package/scripts/check_feature_completion.sh +116 -0
- package/scripts/cleanup.sh +179 -0
- package/scripts/clear.sh +38 -0
- package/scripts/git_feature_complete.sh +133 -0
- package/scripts/loop.sh +206 -0
- package/scripts/plan-loop.sh +233 -0
- package/scripts/postinstall.js +155 -0
- package/scripts/review.sh +90 -0
- package/scripts/sandbox.sh +15 -0
- package/scripts/start.sh +25 -0
- package/scripts/status.sh +108 -0
- package/templates/AGENT.md +27 -0
- package/templates/feature-spec-template.md +115 -0
- package/templates/plan-cleanup-prompt.md +61 -0
- package/templates/plan-prompt.md +114 -0
- package/templates/pr-review-prompt.md +14 -0
- package/templates/prd.json +22 -0
- package/templates/prompt.md +124 -0
- package/templates/roles/ralph-helper.md +73 -0
- package/templates/roles/ralph-plan-feature.md +74 -0
- package/templates/roles/ralph-plan-vision.md +46 -0
- package/templates/testing-harness.md +42 -0
- package/templates/vision.md +43 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
// ── Make all bash scripts executable ──
|
|
8
|
+
|
|
9
|
+
const scriptsDir = path.join(__dirname);
|
|
10
|
+
const helpersDir = path.join(__dirname, '..', 'helpers');
|
|
11
|
+
|
|
12
|
+
function makeExecutable(dir) {
|
|
13
|
+
if (!fs.existsSync(dir)) return;
|
|
14
|
+
const files = fs.readdirSync(dir);
|
|
15
|
+
for (const file of files) {
|
|
16
|
+
if (file.endsWith('.sh')) {
|
|
17
|
+
try {
|
|
18
|
+
fs.chmodSync(path.join(dir, file), '755');
|
|
19
|
+
} catch (e) {}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
makeExecutable(scriptsDir);
|
|
25
|
+
makeExecutable(helpersDir);
|
|
26
|
+
|
|
27
|
+
// ── Dependency checks ──
|
|
28
|
+
|
|
29
|
+
const platform = process.platform; // 'darwin' | 'linux'
|
|
30
|
+
|
|
31
|
+
function hasBin(name) {
|
|
32
|
+
try {
|
|
33
|
+
execSync(`command -v ${name}`, { stdio: 'ignore' });
|
|
34
|
+
return true;
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function tryInstall(name, { brew, apt, npm: npmPkg } = {}) {
|
|
41
|
+
// Try brew on macOS
|
|
42
|
+
if (platform === 'darwin' && brew && hasBin('brew')) {
|
|
43
|
+
try {
|
|
44
|
+
console.log(` Installing ${name} via brew...`);
|
|
45
|
+
execSync(`brew install ${brew}`, { stdio: 'inherit' });
|
|
46
|
+
return true;
|
|
47
|
+
} catch { return false; }
|
|
48
|
+
}
|
|
49
|
+
// Try apt on Linux
|
|
50
|
+
if (platform === 'linux' && apt && hasBin('apt-get')) {
|
|
51
|
+
try {
|
|
52
|
+
console.log(` Installing ${name} via apt...`);
|
|
53
|
+
execSync(`sudo apt-get install -y ${apt}`, { stdio: 'inherit' });
|
|
54
|
+
return true;
|
|
55
|
+
} catch { return false; }
|
|
56
|
+
}
|
|
57
|
+
// Try npm
|
|
58
|
+
if (npmPkg) {
|
|
59
|
+
try {
|
|
60
|
+
console.log(` Installing ${name} via npm...`);
|
|
61
|
+
execSync(`npm install -g ${npmPkg}`, { stdio: 'inherit' });
|
|
62
|
+
return true;
|
|
63
|
+
} catch { return false; }
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Dependencies: what ralph needs on the host for `ralph loop`
|
|
69
|
+
const deps = [
|
|
70
|
+
{
|
|
71
|
+
bin: 'jq',
|
|
72
|
+
label: 'jq (JSON processor)',
|
|
73
|
+
required: true,
|
|
74
|
+
install: { brew: 'jq', apt: 'jq' },
|
|
75
|
+
manual: 'brew install jq OR apt-get install jq',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
bin: 'bc',
|
|
79
|
+
label: 'bc (calculator)',
|
|
80
|
+
required: true,
|
|
81
|
+
install: { brew: 'bc', apt: 'bc' },
|
|
82
|
+
manual: 'brew install bc OR apt-get install bc',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
bin: 'claude',
|
|
86
|
+
label: 'Claude Code CLI',
|
|
87
|
+
required: true,
|
|
88
|
+
install: { npm: '@anthropic-ai/claude-code' },
|
|
89
|
+
manual: 'npm install -g @anthropic-ai/claude-code',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
bin: 'gh',
|
|
93
|
+
label: 'GitHub CLI (for PR features)',
|
|
94
|
+
required: false,
|
|
95
|
+
install: { brew: 'gh', apt: 'gh' },
|
|
96
|
+
manual: 'brew install gh OR https://cli.github.com',
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
console.log('');
|
|
101
|
+
console.log('Checking dependencies...');
|
|
102
|
+
console.log('');
|
|
103
|
+
|
|
104
|
+
const missing = [];
|
|
105
|
+
|
|
106
|
+
for (const dep of deps) {
|
|
107
|
+
if (hasBin(dep.bin)) {
|
|
108
|
+
console.log(` ✓ ${dep.label}`);
|
|
109
|
+
} else {
|
|
110
|
+
console.log(` ✗ ${dep.label} — not found, attempting install...`);
|
|
111
|
+
const installed = tryInstall(dep.bin, dep.install);
|
|
112
|
+
if (installed && hasBin(dep.bin)) {
|
|
113
|
+
console.log(` ✓ ${dep.label} — installed`);
|
|
114
|
+
} else {
|
|
115
|
+
missing.push(dep);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log('');
|
|
121
|
+
|
|
122
|
+
if (missing.length > 0) {
|
|
123
|
+
const required = missing.filter(d => d.required);
|
|
124
|
+
const optional = missing.filter(d => !d.required);
|
|
125
|
+
|
|
126
|
+
if (required.length > 0) {
|
|
127
|
+
console.log('⚠ Missing required dependencies (ralph loop will not work without these):');
|
|
128
|
+
console.log('');
|
|
129
|
+
for (const dep of required) {
|
|
130
|
+
console.log(` ${dep.label}`);
|
|
131
|
+
console.log(` → ${dep.manual}`);
|
|
132
|
+
}
|
|
133
|
+
console.log('');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (optional.length > 0) {
|
|
137
|
+
console.log('ℹ Missing optional dependencies:');
|
|
138
|
+
console.log('');
|
|
139
|
+
for (const dep of optional) {
|
|
140
|
+
console.log(` ${dep.label}`);
|
|
141
|
+
console.log(` → ${dep.manual}`);
|
|
142
|
+
}
|
|
143
|
+
console.log('');
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log('Ralph tool installed successfully!');
|
|
148
|
+
console.log('');
|
|
149
|
+
console.log('Usage:');
|
|
150
|
+
console.log(' ralph init - Initialize Ralph in current directory');
|
|
151
|
+
console.log(' ralph start - Start Ralph in Docker sandbox');
|
|
152
|
+
console.log(' ralph loop - Run Ralph loop directly');
|
|
153
|
+
console.log(' ralph status - Check task status');
|
|
154
|
+
console.log(' ralph --help - Show all commands');
|
|
155
|
+
console.log('');
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Ralph Review - PR Summary & Merge Automation
|
|
5
|
+
# Environment: PROJECT_RALPH_DIR
|
|
6
|
+
|
|
7
|
+
PROJECT_RALPH_DIR="${PROJECT_RALPH_DIR:?PROJECT_RALPH_DIR not set}"
|
|
8
|
+
PROMPT_FILE="${PROJECT_RALPH_DIR}/config/pr-review-prompt.md"
|
|
9
|
+
|
|
10
|
+
# Colors
|
|
11
|
+
RED='\033[0;31m'
|
|
12
|
+
GREEN='\033[0;32m'
|
|
13
|
+
YELLOW='\033[1;33m'
|
|
14
|
+
LIGHT_BLUE='\033[1;36m'
|
|
15
|
+
NC='\033[0m'
|
|
16
|
+
|
|
17
|
+
echo ""
|
|
18
|
+
echo -e "${LIGHT_BLUE}Ralph Review - PR Summary & Merge${NC}"
|
|
19
|
+
echo ""
|
|
20
|
+
|
|
21
|
+
# Verify prompt file exists
|
|
22
|
+
if [[ ! -f "$PROMPT_FILE" ]]; then
|
|
23
|
+
echo -e "${RED}Error: Prompt file not found at ${PROMPT_FILE}${NC}"
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# 1. Get latest open PR
|
|
28
|
+
echo "[1/5] Checking for open PRs..."
|
|
29
|
+
PR_JSON=$(gh pr list --state open --limit 1 --json number,title,body)
|
|
30
|
+
PR_NUMBER=$(echo "$PR_JSON" | jq -r '.[0].number // empty')
|
|
31
|
+
|
|
32
|
+
if [[ -z "$PR_NUMBER" ]]; then
|
|
33
|
+
echo -e "${RED}No open PRs found${NC}"
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
PR_TITLE=$(echo "$PR_JSON" | jq -r '.[0].title')
|
|
38
|
+
PR_BODY=$(echo "$PR_JSON" | jq -r '.[0].body')
|
|
39
|
+
echo -e " ${GREEN}✓${NC} Found PR #${PR_NUMBER}: ${PR_TITLE}"
|
|
40
|
+
|
|
41
|
+
# 2. Get PR diff
|
|
42
|
+
echo "[2/5] Fetching PR diff..."
|
|
43
|
+
PR_DIFF=$(gh pr diff "$PR_NUMBER")
|
|
44
|
+
echo -e " ${GREEN}✓${NC} Diff fetched"
|
|
45
|
+
|
|
46
|
+
# 3. Generate summary via Claude
|
|
47
|
+
echo "[3/5] Generating PR summary via Claude..."
|
|
48
|
+
PR_CONTEXT="PR #${PR_NUMBER}: ${PR_TITLE}
|
|
49
|
+
|
|
50
|
+
## PR Description
|
|
51
|
+
${PR_BODY}
|
|
52
|
+
|
|
53
|
+
## Diff
|
|
54
|
+
${PR_DIFF}"
|
|
55
|
+
|
|
56
|
+
PROMPT=$(cat "$PROMPT_FILE")
|
|
57
|
+
|
|
58
|
+
# Call Claude and capture output
|
|
59
|
+
SUMMARY=$(echo "$PR_CONTEXT" | claude --dangerously-skip-permissions --print -p "$PROMPT" 2>&1) || {
|
|
60
|
+
echo -e "${RED}Claude failed to generate summary${NC}"
|
|
61
|
+
exit 1
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
echo ""
|
|
65
|
+
echo "==============================================================================="
|
|
66
|
+
echo -e "${LIGHT_BLUE}PR #${PR_NUMBER} Summary${NC}"
|
|
67
|
+
echo "==============================================================================="
|
|
68
|
+
echo ""
|
|
69
|
+
echo "$SUMMARY"
|
|
70
|
+
echo ""
|
|
71
|
+
echo "==============================================================================="
|
|
72
|
+
echo ""
|
|
73
|
+
|
|
74
|
+
# 4. Merge PR
|
|
75
|
+
echo "[4/5] Merging PR #${PR_NUMBER}..."
|
|
76
|
+
if ! gh pr merge "$PR_NUMBER" --squash --delete-branch; then
|
|
77
|
+
echo -e "${RED}Merge failed - check for conflicts${NC}"
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
echo -e " ${GREEN}✓${NC} PR merged and branch deleted"
|
|
81
|
+
|
|
82
|
+
# 5. Update local
|
|
83
|
+
echo "[5/5] Updating local main branch..."
|
|
84
|
+
git checkout main
|
|
85
|
+
git pull
|
|
86
|
+
echo -e " ${GREEN}✓${NC} Local main updated"
|
|
87
|
+
|
|
88
|
+
echo ""
|
|
89
|
+
echo -e "${GREEN}Review complete!${NC}"
|
|
90
|
+
echo ""
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Open interactive Docker sandbox environment
|
|
3
|
+
# Environment: RALPH_HOME, PROJECT_DIR
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
RALPH_HOME="${RALPH_HOME:?RALPH_HOME not set}"
|
|
8
|
+
PROJECT_DIR="${PROJECT_DIR:?PROJECT_DIR not set}"
|
|
9
|
+
|
|
10
|
+
# Run interactive bash in Docker container
|
|
11
|
+
docker compose -f "${RALPH_HOME}/docker-compose.yaml" run --rm \
|
|
12
|
+
-v "${PROJECT_DIR}:/workspace:rw" \
|
|
13
|
+
-e PROJECT_DIR=/workspace \
|
|
14
|
+
-e PROJECT_RALPH_DIR=/workspace/.ralph \
|
|
15
|
+
ai bash
|
package/scripts/start.sh
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Combined script to start sandbox and run Ralph loop inside container
|
|
3
|
+
# Environment: RALPH_HOME, PROJECT_DIR, PROJECT_RALPH_DIR
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
MAX_ITERS="${1:-6}"
|
|
8
|
+
MODEL="${2:-}"
|
|
9
|
+
|
|
10
|
+
RALPH_HOME="${RALPH_HOME:?RALPH_HOME not set}"
|
|
11
|
+
PROJECT_DIR="${PROJECT_DIR:?PROJECT_DIR not set}"
|
|
12
|
+
|
|
13
|
+
# Build ralph command with optional model parameter
|
|
14
|
+
RALPH_CMD="ralph loop"
|
|
15
|
+
[[ -n "$MODEL" ]] && RALPH_CMD="$RALPH_CMD --model $MODEL"
|
|
16
|
+
RALPH_CMD="$RALPH_CMD --max ${MAX_ITERS}"
|
|
17
|
+
[[ "${RALPH_LOCAL:-}" == "1" ]] && RALPH_CMD="$RALPH_CMD --local"
|
|
18
|
+
|
|
19
|
+
# Run the ralph loop command inside the Docker container
|
|
20
|
+
# Mount the project directory to /workspace
|
|
21
|
+
docker compose -f "${RALPH_HOME}/docker-compose.yaml" run --rm \
|
|
22
|
+
-v "${PROJECT_DIR}:/workspace:rw" \
|
|
23
|
+
-e PROJECT_DIR=/workspace \
|
|
24
|
+
-e PROJECT_RALPH_DIR=/workspace/.ralph \
|
|
25
|
+
ai bash -c "${RALPH_CMD}"
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# Ralph Status - Concise status for agent consumption
|
|
5
|
+
# Environment: PROJECT_RALPH_DIR
|
|
6
|
+
|
|
7
|
+
PROJECT_RALPH_DIR="${PROJECT_RALPH_DIR:?PROJECT_RALPH_DIR not set}"
|
|
8
|
+
PRD_FILE="${PROJECT_RALPH_DIR}/tasks/prd.json"
|
|
9
|
+
|
|
10
|
+
# Color support (only if TTY)
|
|
11
|
+
if [[ -t 1 ]]; then
|
|
12
|
+
BOLD="\033[1m"
|
|
13
|
+
CYAN="\033[36m"
|
|
14
|
+
GREEN="\033[32m"
|
|
15
|
+
YELLOW="\033[33m"
|
|
16
|
+
BLUE="\033[34m"
|
|
17
|
+
DIM="\033[2m"
|
|
18
|
+
RESET="\033[0m"
|
|
19
|
+
else
|
|
20
|
+
BOLD=""
|
|
21
|
+
CYAN=""
|
|
22
|
+
GREEN=""
|
|
23
|
+
YELLOW=""
|
|
24
|
+
BLUE=""
|
|
25
|
+
DIM=""
|
|
26
|
+
RESET=""
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# Check if prd.json exists
|
|
30
|
+
if [[ ! -f "$PRD_FILE" ]]; then
|
|
31
|
+
echo "ERROR: prd.json not found"
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# Find current feature (first incomplete feature)
|
|
36
|
+
CURRENT_FEATURE_ID=$(jq -r '.features[] | select(.feature_completed == false) | .id' "$PRD_FILE" 2>/dev/null | head -1)
|
|
37
|
+
|
|
38
|
+
if [[ -z "$CURRENT_FEATURE_ID" ]]; then
|
|
39
|
+
echo "All features completed!"
|
|
40
|
+
echo ""
|
|
41
|
+
jq -r '.features[] | " [DONE] \(.id): \(.name)"' "$PRD_FILE" 2>/dev/null
|
|
42
|
+
exit 0
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Get current feature details
|
|
46
|
+
CURRENT_FEATURE_NAME=$(jq -r --arg id "$CURRENT_FEATURE_ID" '.features[] | select(.id == $id) | .name' "$PRD_FILE" 2>/dev/null)
|
|
47
|
+
CURRENT_FEATURE_NUM=$(jq -r --arg id "$CURRENT_FEATURE_ID" '[.features[].id] | to_entries | .[] | select(.value == $id) | .key + 1' "$PRD_FILE" 2>/dev/null)
|
|
48
|
+
|
|
49
|
+
# Count tasks in current feature
|
|
50
|
+
TOTAL_TASKS=$(jq --arg id "$CURRENT_FEATURE_ID" '.features[] | select(.id == $id) | .tasks | length' "$PRD_FILE" 2>/dev/null)
|
|
51
|
+
COMPLETED_TASKS=$(jq --arg id "$CURRENT_FEATURE_ID" '.features[] | select(.id == $id) | [.tasks[] | select(.completed == true)] | length' "$PRD_FILE" 2>/dev/null)
|
|
52
|
+
PENDING_TASKS=$((TOTAL_TASKS - COMPLETED_TASKS))
|
|
53
|
+
|
|
54
|
+
# Count total features
|
|
55
|
+
TOTAL_FEATURES=$(jq '.features | length' "$PRD_FILE" 2>/dev/null)
|
|
56
|
+
COMPLETED_FEATURES=$(jq '[.features[] | select(.feature_completed == true)] | length' "$PRD_FILE" 2>/dev/null)
|
|
57
|
+
|
|
58
|
+
# Calculate border width
|
|
59
|
+
header="Current Feature: $CURRENT_FEATURE_NAME (Feature $CURRENT_FEATURE_NUM of $TOTAL_FEATURES)"
|
|
60
|
+
header_len=${#header}
|
|
61
|
+
border_len=$((header_len > 60 ? header_len + 4 : 64))
|
|
62
|
+
|
|
63
|
+
# Build border
|
|
64
|
+
border="╔"
|
|
65
|
+
for ((i=0; i<border_len-2; i++)); do border+="═"; done
|
|
66
|
+
border+="╗"
|
|
67
|
+
|
|
68
|
+
bottom_border="╚"
|
|
69
|
+
for ((i=0; i<border_len-2; i++)); do bottom_border+="═"; done
|
|
70
|
+
bottom_border+="╝"
|
|
71
|
+
|
|
72
|
+
# Human-readable output
|
|
73
|
+
printf "%b\n" "${BOLD}${CYAN}${border}${RESET}"
|
|
74
|
+
printf "%b\n" "${BOLD}${CYAN}║${RESET} ${BOLD}Current Feature:${RESET} ${YELLOW}${CURRENT_FEATURE_NAME}${RESET} ${DIM}(Feature ${CURRENT_FEATURE_NUM} of ${TOTAL_FEATURES})${RESET}"
|
|
75
|
+
printf "%b\n" "${BOLD}${CYAN}║${RESET} ${BOLD}Status:${RESET} ${GREEN}${COMPLETED_TASKS}${RESET}/${TOTAL_TASKS} tasks completed, ${YELLOW}${PENDING_TASKS}${RESET} pending"
|
|
76
|
+
printf "%b\n" "${BOLD}${CYAN}${bottom_border}${RESET}"
|
|
77
|
+
echo ""
|
|
78
|
+
|
|
79
|
+
# List all tasks in current feature
|
|
80
|
+
printf "%b\n" "${BOLD}Tasks:${RESET}"
|
|
81
|
+
jq -r --arg id "$CURRENT_FEATURE_ID" '.features[] | select(.id == $id) | .tasks[] | " \(if .completed then "[DONE]" else "[TODO]" end) \(.id): \(.name)"' "$PRD_FILE" 2>/dev/null | while IFS= read -r line; do
|
|
82
|
+
if [[ "$line" =~ ^\s*\[DONE\] ]]; then
|
|
83
|
+
printf "%b\n" "${DIM}${line}${RESET}"
|
|
84
|
+
else
|
|
85
|
+
printf "%b\n" "${BOLD}${line}${RESET}"
|
|
86
|
+
fi
|
|
87
|
+
done
|
|
88
|
+
|
|
89
|
+
# Show next incomplete task details
|
|
90
|
+
echo ""
|
|
91
|
+
NEXT_TASK=$(jq -r --arg id "$CURRENT_FEATURE_ID" '.features[] | select(.id == $id) | .tasks[] | select(.completed == false) | .id' "$PRD_FILE" 2>/dev/null | head -1)
|
|
92
|
+
if [[ -n "$NEXT_TASK" ]]; then
|
|
93
|
+
printf "%b\n" "${BOLD}${BLUE}Next task: ${NEXT_TASK}${RESET}"
|
|
94
|
+
jq -r --arg fid "$CURRENT_FEATURE_ID" --arg tid "$NEXT_TASK" '.features[] | select(.id == $fid) | .tasks[] | select(.id == $tid) | " Name: \(.name)\n Spec: \(.specFile // "none")\n Requirements: \(.requirements | join(", "))"' "$PRD_FILE" 2>/dev/null
|
|
95
|
+
else
|
|
96
|
+
printf "%b\n" "${BOLD}${GREEN}All tasks in current feature completed - ready for feature completion!${RESET}"
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# Show feature overview
|
|
100
|
+
echo ""
|
|
101
|
+
printf "%b\n" "${BOLD}All Features:${RESET}"
|
|
102
|
+
jq -r '.features[] | " \(if .feature_completed then "[DONE]" else "[TODO]" end) \(.id): \(.name)"' "$PRD_FILE" 2>/dev/null | while IFS= read -r line; do
|
|
103
|
+
if [[ "$line" =~ ^\s*\[DONE\] ]]; then
|
|
104
|
+
printf "%b\n" "${DIM}${line}${RESET}"
|
|
105
|
+
else
|
|
106
|
+
printf "%b\n" "${BOLD}${line}${RESET}"
|
|
107
|
+
fi
|
|
108
|
+
done
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Ralph Agent Knowledge Base
|
|
2
|
+
|
|
3
|
+
This file contains persistent learnings and patterns discovered across Ralph iterations.
|
|
4
|
+
Each iteration should update this file with new patterns, gotchas, and architectural insights
|
|
5
|
+
only if something new and relevant has been discovered.
|
|
6
|
+
|
|
7
|
+
**Progress Management:**
|
|
8
|
+
- Within feature: progress.txt accumulates task summaries
|
|
9
|
+
- Between features: progress.txt archives to `logs/progress/{feature-name}-progress-{timestamp}.txt`
|
|
10
|
+
- AGENT.md persists across all features (never cleared)
|
|
11
|
+
- NOTE: Do not create explainer documents or other documentation unless specifically asked to.
|
|
12
|
+
|
|
13
|
+
## CRITICAL: Code Reuse Philosophy
|
|
14
|
+
|
|
15
|
+
**NEVER ASSUME FUNCTIONALITY DOESN'T EXIST**
|
|
16
|
+
- Always search for existing implementations before creating new ones
|
|
17
|
+
- Check for utility functions that might already do what you need
|
|
18
|
+
- Look for similar patterns in other parts of the codebase
|
|
19
|
+
- Reuse existing services, stores, and API endpoints when possible
|
|
20
|
+
|
|
21
|
+
## Known Patterns
|
|
22
|
+
|
|
23
|
+
<!-- Add project-specific patterns here as you discover them -->
|
|
24
|
+
|
|
25
|
+
## Known Gotchas
|
|
26
|
+
|
|
27
|
+
<!-- Add project-specific gotchas here as you discover them -->
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Feature Spec: [Feature Name]
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
**What user-visible change should exist when done?**
|
|
6
|
+
|
|
7
|
+
[1-2 lines describing the user-facing outcome]
|
|
8
|
+
|
|
9
|
+
**Success Criteria:**
|
|
10
|
+
- [How you'll know it worked - specific requirement that must be met]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## Non-goals
|
|
14
|
+
|
|
15
|
+
**Explicitly list what NOT to do (prevents scope creep):**
|
|
16
|
+
- [Out of scope item 1]
|
|
17
|
+
- [Out of scope item 2]
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Implementation Tasks
|
|
22
|
+
|
|
23
|
+
**Subtask 1: [Layer/Component Name]**
|
|
24
|
+
- **Requirements:**
|
|
25
|
+
- [Specific requirement 1]
|
|
26
|
+
- [Specific requirement 2]
|
|
27
|
+
- **Done when:** [Completion criteria]
|
|
28
|
+
- **Files:** [List of files to modify/create]
|
|
29
|
+
|
|
30
|
+
**Subtask 2: [Layer/Component Name]**
|
|
31
|
+
- **Requirements:**
|
|
32
|
+
- [Specific requirement 1]
|
|
33
|
+
- [Specific requirement 2]
|
|
34
|
+
- **Done when:** [Completion criteria]
|
|
35
|
+
- **Files:** [List of files to modify/create]
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Current State
|
|
40
|
+
|
|
41
|
+
**Where this lives:**
|
|
42
|
+
- Files/folders: `[path/to/relevant/files]`
|
|
43
|
+
- Related domains: `[domain1, domain2]`
|
|
44
|
+
|
|
45
|
+
**How it works today:**
|
|
46
|
+
- [Brief description of current behavior]
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Proposed Behavior
|
|
51
|
+
|
|
52
|
+
**Write as bullet rules, not prose:**
|
|
53
|
+
|
|
54
|
+
**Primary flow:**
|
|
55
|
+
- If [condition X], then [action Y]
|
|
56
|
+
- If [condition Z], then [action W]
|
|
57
|
+
|
|
58
|
+
**Edge cases:**
|
|
59
|
+
- When [edge case 1], [behavior]
|
|
60
|
+
- Error handling: [what happens on errors]
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## UX / UI (if relevant)
|
|
65
|
+
|
|
66
|
+
**Screens/components affected:**
|
|
67
|
+
- `[component/path/file.tsx]` - [what changes]
|
|
68
|
+
|
|
69
|
+
**States to handle:**
|
|
70
|
+
- Empty state: [what shows when no data]
|
|
71
|
+
- Loading state: [what shows while loading]
|
|
72
|
+
- Error state: [what shows on error]
|
|
73
|
+
- Success state: [what shows on success]
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Data + APIs (if relevant)
|
|
78
|
+
|
|
79
|
+
**API endpoints:**
|
|
80
|
+
- `POST /api/[path]` - [description]
|
|
81
|
+
- Request: `{ [field]: [type], ... }`
|
|
82
|
+
- Response: `{ [field]: [type], ... }`
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Files to Touch
|
|
87
|
+
|
|
88
|
+
**Most likely files (Ralph should start here):**
|
|
89
|
+
- `path/to/file1.ts`
|
|
90
|
+
- `path/to/file2.tsx`
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Patterns and helpers
|
|
95
|
+
|
|
96
|
+
Reuse existing files where possible. Follow existing patterns in the project.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Notes
|
|
101
|
+
|
|
102
|
+
**Additional context for Ralph:**
|
|
103
|
+
- [Any special considerations]
|
|
104
|
+
- [Dependencies on other features]
|
|
105
|
+
- [Known gotchas]
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## How to Use This Template
|
|
110
|
+
|
|
111
|
+
1. Fill in all sections with specific requirements
|
|
112
|
+
2. Organize subtasks logically
|
|
113
|
+
3. Be specific in requirements and completion criteria
|
|
114
|
+
4. Omit sections that don't apply
|
|
115
|
+
5. Update prd.json with the task linking to this spec file
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Ralph Plan Cleanup - REVIEW & CONSOLIDATION MODE
|
|
2
|
+
|
|
3
|
+
## YOUR ROLE
|
|
4
|
+
|
|
5
|
+
You are reviewing and cleaning up the planning output from previous iterations. Your job is to ensure quality, remove redundancy, fix ordering, and verify complete vision coverage.
|
|
6
|
+
|
|
7
|
+
## Instructions
|
|
8
|
+
|
|
9
|
+
### Step 1: Read Everything
|
|
10
|
+
|
|
11
|
+
Read ALL of these files:
|
|
12
|
+
1. `.ralph/config/vision.md` — The project vision
|
|
13
|
+
2. `.ralph/config/AGENT.md` — Accumulated learnings
|
|
14
|
+
3. `.ralph/tasks/prd.json` — All planned features and tasks
|
|
15
|
+
4. ALL spec files in `.ralph/tasks/1_new_tasks/` — Read every spec file referenced in prd.json
|
|
16
|
+
5. `.ralph/tasks/progress.txt` — Planning history
|
|
17
|
+
|
|
18
|
+
### Step 2: Audit Against Vision
|
|
19
|
+
|
|
20
|
+
For each section/area of the vision:
|
|
21
|
+
- Is there a corresponding feature in prd.json?
|
|
22
|
+
- Are the tasks specific enough for automated implementation?
|
|
23
|
+
- Do the spec files have actionable details (file paths, component names, behavior rules)?
|
|
24
|
+
|
|
25
|
+
Flag any gaps — areas of the vision not yet covered by features.
|
|
26
|
+
|
|
27
|
+
### Step 3: Clean Up
|
|
28
|
+
|
|
29
|
+
Review all features and tasks for:
|
|
30
|
+
- **Duplicates**: Merge features/tasks that overlap or cover the same ground
|
|
31
|
+
- **Irrelevant tasks**: Remove tasks that don't align with the current vision
|
|
32
|
+
- **Ordering issues**: Reorder features so dependencies come first (e.g., data models before UI)
|
|
33
|
+
- **Spec quality**: Improve specs that are too vague for implementation — add specifics
|
|
34
|
+
- **Task granularity**: Split tasks that are too large (multi-day work), merge tasks that are too small (trivial one-liners)
|
|
35
|
+
|
|
36
|
+
Make changes directly to prd.json and spec files.
|
|
37
|
+
|
|
38
|
+
### Step 4: Update Progress
|
|
39
|
+
|
|
40
|
+
Append to `.ralph/tasks/progress.txt`:
|
|
41
|
+
- What was cleaned up, reordered, or removed
|
|
42
|
+
- Any gaps identified that still need planning
|
|
43
|
+
|
|
44
|
+
Update `.ralph/config/AGENT.md` with any new learnings.
|
|
45
|
+
|
|
46
|
+
### Step 5: Completion Check
|
|
47
|
+
|
|
48
|
+
After cleanup, assess vision coverage:
|
|
49
|
+
- If ALL areas of the vision have detailed features, well-ordered tasks, and actionable spec files: output `<promise>COMPLETE</promise>`
|
|
50
|
+
- If there are still gaps: output "Cleanup complete. Gaps remaining: [list areas]. Exiting for next iteration."
|
|
51
|
+
|
|
52
|
+
EXIT IMMEDIATELY after this assessment.
|
|
53
|
+
|
|
54
|
+
## CLEANUP RULES
|
|
55
|
+
|
|
56
|
+
1. **BE RUTHLESS**: Remove tasks that don't serve the vision
|
|
57
|
+
2. **PRESERVE INTENT**: When merging/reordering, keep the original requirements intact
|
|
58
|
+
3. **NO NEW FEATURES**: Only clean up existing plans — creating new features is for the plan prompt
|
|
59
|
+
4. **FIX ORDERING**: Features should flow naturally for sequential implementation
|
|
60
|
+
5. **IMPROVE SPECS**: If a spec is too vague, add details from your codebase analysis
|
|
61
|
+
6. **ALWAYS EXIT**: After cleanup, exit for fresh iteration
|