agentic-loop 3.4.7 → 3.5.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/.claude/commands/idea.md +42 -252
- package/.claude/commands/prd.md +474 -71
- package/README.md +4 -1
- package/package.json +1 -1
- package/ralph/ci.sh +193 -34
- package/ralph/hooks/protect-prd.sh +12 -20
- package/ralph/loop.sh +51 -194
- package/ralph/prd.sh +5 -0
- package/ralph/setup.sh +298 -16
- package/ralph/verify/tests.sh +58 -3
- package/templates/PROMPT.md +143 -191
- package/templates/config/fullstack.json +1 -1
- package/templates/examples/CLAUDE-fullstack.md +3 -2
- package/templates/examples/CLAUDE-node.md +2 -1
- package/templates/examples/CLAUDE-react.md +2 -1
- package/templates/github/workflows/nightly.yml +9 -74
- package/templates/github/workflows/pr.yml +7 -31
- package/templates/signs.json +7 -0
package/ralph/ci.sh
CHANGED
|
@@ -38,68 +38,227 @@ install_github_workflows() {
|
|
|
38
38
|
# Create workflows directory
|
|
39
39
|
mkdir -p .github/workflows
|
|
40
40
|
|
|
41
|
-
#
|
|
42
|
-
local
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return 1
|
|
47
|
-
fi
|
|
41
|
+
# Read config values
|
|
42
|
+
local backend_dir frontend_dir test_cmd
|
|
43
|
+
backend_dir=$(get_config '.directories.backend' "")
|
|
44
|
+
frontend_dir=$(get_config '.directories.frontend' "")
|
|
45
|
+
test_cmd=$(get_config '.checks.testCommand' "")
|
|
48
46
|
|
|
49
|
-
#
|
|
47
|
+
# Generate PR workflow
|
|
50
48
|
if [[ -f ".github/workflows/pr.yml" ]]; then
|
|
51
49
|
echo " PR workflow already exists, skipping..."
|
|
52
50
|
else
|
|
53
|
-
|
|
51
|
+
generate_pr_workflow "$backend_dir" "$frontend_dir"
|
|
54
52
|
print_success "Created .github/workflows/pr.yml (fast lint checks)"
|
|
55
53
|
fi
|
|
56
54
|
|
|
57
|
-
#
|
|
55
|
+
# Generate nightly workflow
|
|
58
56
|
if [[ -f ".github/workflows/nightly.yml" ]]; then
|
|
59
57
|
echo " Nightly workflow already exists, skipping..."
|
|
60
58
|
else
|
|
61
|
-
|
|
59
|
+
generate_nightly_workflow "$backend_dir" "$frontend_dir" "$test_cmd"
|
|
62
60
|
print_success "Created .github/workflows/nightly.yml (full test suite)"
|
|
63
61
|
fi
|
|
64
62
|
|
|
65
63
|
echo ""
|
|
66
64
|
echo "Workflows installed:"
|
|
67
65
|
echo ""
|
|
68
|
-
echo "
|
|
66
|
+
echo " PR Check (.github/workflows/pr.yml)"
|
|
69
67
|
echo " Runs on: Pull requests to main/master"
|
|
70
68
|
echo " Checks: Lint, TypeScript, Build"
|
|
71
|
-
echo " Speed: Fast (~1-2 min)"
|
|
72
69
|
echo ""
|
|
73
|
-
echo "
|
|
70
|
+
echo " Nightly Tests (.github/workflows/nightly.yml)"
|
|
74
71
|
echo " Runs on: Daily at 3am UTC + manual trigger"
|
|
75
|
-
echo " Checks: Full test suite + PRD testSteps
|
|
76
|
-
echo " Speed: Comprehensive (~5-10 min)"
|
|
72
|
+
echo " Checks: Full test suite + PRD testSteps"
|
|
77
73
|
echo ""
|
|
78
|
-
|
|
79
|
-
# Check if we need to customize for monorepo
|
|
80
|
-
local backend_dir frontend_dir
|
|
81
|
-
backend_dir=$(get_config '.directories.backend' "")
|
|
82
|
-
frontend_dir=$(get_config '.directories.frontend' "")
|
|
83
|
-
|
|
84
|
-
if [[ -n "$backend_dir" ]] || [[ -n "$frontend_dir" ]]; then
|
|
85
|
-
print_warning "Monorepo detected. You may need to customize workflow paths."
|
|
86
|
-
echo ""
|
|
87
|
-
echo " Edit .github/workflows/*.yml to add:"
|
|
88
|
-
[[ -n "$backend_dir" ]] && echo " - working-directory: $backend_dir"
|
|
89
|
-
[[ -n "$frontend_dir" ]] && echo " - working-directory: $frontend_dir"
|
|
90
|
-
echo ""
|
|
91
|
-
fi
|
|
92
|
-
|
|
93
|
-
# Remind about secrets
|
|
94
74
|
echo "Next steps:"
|
|
95
75
|
echo " 1. Review and customize the workflows if needed"
|
|
96
|
-
echo " 2. Commit
|
|
97
|
-
echo " 3.
|
|
76
|
+
echo " 2. Commit: git add .github && git commit -m 'ci: Add workflows'"
|
|
77
|
+
echo " 3. Add any required secrets in GitHub repo settings"
|
|
98
78
|
echo ""
|
|
99
79
|
|
|
100
80
|
return 0
|
|
101
81
|
}
|
|
102
82
|
|
|
83
|
+
# Generate PR workflow based on project structure
|
|
84
|
+
generate_pr_workflow() {
|
|
85
|
+
local backend_dir="$1"
|
|
86
|
+
local frontend_dir="$2"
|
|
87
|
+
|
|
88
|
+
cat > .github/workflows/pr.yml << 'HEADER'
|
|
89
|
+
# Fast PR checks - lint only, no tests
|
|
90
|
+
name: PR Check
|
|
91
|
+
|
|
92
|
+
on:
|
|
93
|
+
pull_request:
|
|
94
|
+
branches: [main, master]
|
|
95
|
+
|
|
96
|
+
jobs:
|
|
97
|
+
lint:
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v4
|
|
101
|
+
HEADER
|
|
102
|
+
|
|
103
|
+
# Detect and add Python steps
|
|
104
|
+
if [[ -f "pyproject.toml" ]] || [[ -f "requirements.txt" ]] || [[ -n "$backend_dir" && -f "$backend_dir/pyproject.toml" ]]; then
|
|
105
|
+
local py_dir="${backend_dir:-.}"
|
|
106
|
+
cat >> .github/workflows/pr.yml << EOF
|
|
107
|
+
|
|
108
|
+
- name: Set up Python
|
|
109
|
+
uses: actions/setup-python@v5
|
|
110
|
+
with:
|
|
111
|
+
python-version: '3.11'
|
|
112
|
+
|
|
113
|
+
- name: Install Python dependencies
|
|
114
|
+
run: |
|
|
115
|
+
pip install ruff uv
|
|
116
|
+
cd $py_dir && uv pip install -e . --system 2>/dev/null || pip install -e . 2>/dev/null || true
|
|
117
|
+
|
|
118
|
+
- name: Ruff lint
|
|
119
|
+
run: cd $py_dir && ruff check .
|
|
120
|
+
EOF
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Detect and add Node.js steps
|
|
124
|
+
if [[ -f "package.json" ]] || [[ -n "$frontend_dir" && -f "$frontend_dir/package.json" ]]; then
|
|
125
|
+
local node_dir="${frontend_dir:-.}"
|
|
126
|
+
cat >> .github/workflows/pr.yml << EOF
|
|
127
|
+
|
|
128
|
+
- name: Set up Node.js
|
|
129
|
+
uses: actions/setup-node@v4
|
|
130
|
+
with:
|
|
131
|
+
node-version: '20'
|
|
132
|
+
|
|
133
|
+
- name: Install Node dependencies
|
|
134
|
+
run: cd $node_dir && npm ci
|
|
135
|
+
|
|
136
|
+
- name: Lint
|
|
137
|
+
run: cd $node_dir && npm run lint 2>/dev/null || true
|
|
138
|
+
|
|
139
|
+
- name: TypeScript check
|
|
140
|
+
run: cd $node_dir && npx tsc --noEmit 2>/dev/null || true
|
|
141
|
+
|
|
142
|
+
- name: Build
|
|
143
|
+
run: cd $node_dir && npm run build 2>/dev/null || true
|
|
144
|
+
EOF
|
|
145
|
+
fi
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# Generate nightly workflow based on project structure
|
|
149
|
+
generate_nightly_workflow() {
|
|
150
|
+
local backend_dir="$1"
|
|
151
|
+
local frontend_dir="$2"
|
|
152
|
+
local test_cmd="$3"
|
|
153
|
+
|
|
154
|
+
cat > .github/workflows/nightly.yml << 'HEADER'
|
|
155
|
+
# Nightly comprehensive test suite
|
|
156
|
+
name: Nightly Tests
|
|
157
|
+
|
|
158
|
+
on:
|
|
159
|
+
schedule:
|
|
160
|
+
- cron: '0 3 * * *' # 3am UTC daily
|
|
161
|
+
workflow_dispatch:
|
|
162
|
+
|
|
163
|
+
jobs:
|
|
164
|
+
test:
|
|
165
|
+
runs-on: ubuntu-latest
|
|
166
|
+
HEADER
|
|
167
|
+
|
|
168
|
+
# Add services if backend exists (likely needs DB)
|
|
169
|
+
if [[ -n "$backend_dir" ]] || [[ -f "pyproject.toml" ]]; then
|
|
170
|
+
cat >> .github/workflows/nightly.yml << 'EOF'
|
|
171
|
+
|
|
172
|
+
services:
|
|
173
|
+
postgres:
|
|
174
|
+
image: postgres:15
|
|
175
|
+
env:
|
|
176
|
+
POSTGRES_USER: test
|
|
177
|
+
POSTGRES_PASSWORD: test
|
|
178
|
+
POSTGRES_DB: test
|
|
179
|
+
ports:
|
|
180
|
+
- 5432:5432
|
|
181
|
+
options: >-
|
|
182
|
+
--health-cmd pg_isready
|
|
183
|
+
--health-interval 10s
|
|
184
|
+
--health-timeout 5s
|
|
185
|
+
--health-retries 5
|
|
186
|
+
|
|
187
|
+
env:
|
|
188
|
+
DATABASE_URL: postgresql://test:test@localhost:5432/test
|
|
189
|
+
EOF
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
cat >> .github/workflows/nightly.yml << 'EOF'
|
|
193
|
+
|
|
194
|
+
steps:
|
|
195
|
+
- uses: actions/checkout@v4
|
|
196
|
+
EOF
|
|
197
|
+
|
|
198
|
+
# Add Python setup and tests
|
|
199
|
+
if [[ -f "pyproject.toml" ]] || [[ -n "$backend_dir" && -f "$backend_dir/pyproject.toml" ]]; then
|
|
200
|
+
local py_dir="${backend_dir:-.}"
|
|
201
|
+
local py_test_cmd="${test_cmd:-pytest -v --tb=short}"
|
|
202
|
+
|
|
203
|
+
cat >> .github/workflows/nightly.yml << EOF
|
|
204
|
+
|
|
205
|
+
- name: Set up Python
|
|
206
|
+
uses: actions/setup-python@v5
|
|
207
|
+
with:
|
|
208
|
+
python-version: '3.11'
|
|
209
|
+
|
|
210
|
+
- name: Install Python dependencies
|
|
211
|
+
run: |
|
|
212
|
+
pip install uv
|
|
213
|
+
cd $py_dir && uv pip install -e ".[dev]" --system 2>/dev/null || pip install -e . 2>/dev/null || true
|
|
214
|
+
|
|
215
|
+
- name: Run migrations
|
|
216
|
+
run: cd $py_dir && alembic upgrade head 2>/dev/null || true
|
|
217
|
+
continue-on-error: true
|
|
218
|
+
|
|
219
|
+
- name: Python tests
|
|
220
|
+
run: cd $py_dir && $py_test_cmd
|
|
221
|
+
continue-on-error: true
|
|
222
|
+
EOF
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# Add Node.js setup and tests
|
|
226
|
+
if [[ -f "package.json" ]] || [[ -n "$frontend_dir" && -f "$frontend_dir/package.json" ]]; then
|
|
227
|
+
local node_dir="${frontend_dir:-.}"
|
|
228
|
+
cat >> .github/workflows/nightly.yml << EOF
|
|
229
|
+
|
|
230
|
+
- name: Set up Node.js
|
|
231
|
+
uses: actions/setup-node@v4
|
|
232
|
+
with:
|
|
233
|
+
node-version: '20'
|
|
234
|
+
|
|
235
|
+
- name: Install Node dependencies
|
|
236
|
+
run: cd $node_dir && npm ci
|
|
237
|
+
|
|
238
|
+
- name: Node tests
|
|
239
|
+
run: cd $node_dir && npm test 2>/dev/null || true
|
|
240
|
+
continue-on-error: true
|
|
241
|
+
EOF
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
# Add PRD tests
|
|
245
|
+
cat >> .github/workflows/nightly.yml << 'EOF'
|
|
246
|
+
|
|
247
|
+
- name: Run PRD tests
|
|
248
|
+
if: hashFiles('.ralph/prd.json') != ''
|
|
249
|
+
run: npx agentic-loop test prd 2>/dev/null || true
|
|
250
|
+
continue-on-error: true
|
|
251
|
+
|
|
252
|
+
notify:
|
|
253
|
+
needs: test
|
|
254
|
+
runs-on: ubuntu-latest
|
|
255
|
+
if: failure()
|
|
256
|
+
steps:
|
|
257
|
+
- name: Notify on failure
|
|
258
|
+
run: echo "Nightly tests failed!"
|
|
259
|
+
EOF
|
|
260
|
+
}
|
|
261
|
+
|
|
103
262
|
check_ci_status() {
|
|
104
263
|
echo ""
|
|
105
264
|
print_info "=== CI/CD Status ==="
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# protect-prd.sh - Protect prd.json from
|
|
2
|
+
# protect-prd.sh - Protect prd.json from marking stories as passed
|
|
3
3
|
# Hook: PreToolUse matcher: "Edit|Write"
|
|
4
4
|
#
|
|
5
|
-
# Allows:
|
|
6
|
-
#
|
|
7
|
-
# Blocks: Accidental edits during normal coding
|
|
5
|
+
# Allows: Most edits to prd.json (adding fields, fixing test steps, etc.)
|
|
6
|
+
# Blocks: Edits that mark stories as "passes": true (Ralph handles this)
|
|
8
7
|
|
|
9
8
|
set -euo pipefail
|
|
10
9
|
|
|
@@ -13,25 +12,18 @@ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path //
|
|
|
13
12
|
|
|
14
13
|
# Check if editing prd.json
|
|
15
14
|
if [[ "$FILE_PATH" == *"prd.json"* ]]; then
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
rm -f ".ralph/.prd-edit-allowed" # One-time use
|
|
19
|
-
echo '{"continue": true}'
|
|
20
|
-
exit 0
|
|
21
|
-
fi
|
|
15
|
+
# Get the new content being written
|
|
16
|
+
NEW_STRING=$(echo "$INPUT" | jq -r '.tool_input.new_string // .tool_input.content // ""')
|
|
22
17
|
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if [[ $file_age -lt 600 ]]; then # 10 minutes
|
|
28
|
-
echo '{"continue": true}'
|
|
29
|
-
exit 0
|
|
30
|
-
fi
|
|
18
|
+
# Block if trying to set passes to true (Ralph handles story completion)
|
|
19
|
+
if echo "$NEW_STRING" | grep -qE '"passes"\s*:\s*true'; then
|
|
20
|
+
echo "BLOCKED: Cannot mark stories as passed. Ralph handles this after verification." >&2
|
|
21
|
+
exit 2 # Exit code 2 = blocking error
|
|
31
22
|
fi
|
|
32
23
|
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
# Allow all other prd.json edits (adding mcp, originalContext, fixing testSteps, etc.)
|
|
25
|
+
echo '{"continue": true}'
|
|
26
|
+
exit 0
|
|
35
27
|
fi
|
|
36
28
|
|
|
37
29
|
# Allow all other edits
|
package/ralph/loop.sh
CHANGED
|
@@ -504,135 +504,11 @@ startup_checklist() {
|
|
|
504
504
|
fi
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
-
# Helper: Inject story details into prompt
|
|
508
|
-
_inject_story_context() {
|
|
509
|
-
local story_json="$1"
|
|
510
|
-
|
|
511
|
-
echo ""
|
|
512
|
-
echo "---"
|
|
513
|
-
echo ""
|
|
514
|
-
echo "## Current Story"
|
|
515
|
-
echo ""
|
|
516
|
-
echo '```json'
|
|
517
|
-
echo "$story_json"
|
|
518
|
-
echo '```'
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
# Helper: Inject file guidance into prompt
|
|
522
|
-
_inject_file_guidance() {
|
|
523
|
-
local story_json="$1"
|
|
524
|
-
|
|
525
|
-
local has_files
|
|
526
|
-
has_files=$(echo "$story_json" | jq -r '.files // empty' 2>/dev/null)
|
|
527
|
-
[[ -z "$has_files" ]] && return
|
|
528
|
-
|
|
529
|
-
echo ""
|
|
530
|
-
echo "### File Guidance for This Story"
|
|
531
|
-
echo ""
|
|
532
|
-
echo "**Create these files:**"
|
|
533
|
-
echo "$story_json" | jq -r '.files.create[]? // empty' | sed 's/^/- /'
|
|
534
|
-
echo ""
|
|
535
|
-
echo "**Modify these files:**"
|
|
536
|
-
echo "$story_json" | jq -r '.files.modify[]? // empty' | sed 's/^/- /'
|
|
537
|
-
echo ""
|
|
538
|
-
echo "**Reuse/import from:**"
|
|
539
|
-
echo "$story_json" | jq -r '.files.reuse[]? // empty' | sed 's/^/- /'
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
# Helper: Inject scalability guidance for story
|
|
543
|
-
_inject_story_scale() {
|
|
544
|
-
local story_json="$1"
|
|
545
|
-
|
|
546
|
-
local has_scale
|
|
547
|
-
has_scale=$(echo "$story_json" | jq -r '.scale // empty' 2>/dev/null)
|
|
548
|
-
[[ -z "$has_scale" ]] && return
|
|
549
|
-
|
|
550
|
-
echo ""
|
|
551
|
-
echo "### Scalability Requirements for This Story"
|
|
552
|
-
echo ""
|
|
553
|
-
echo "$story_json" | jq -r '.scale | to_entries[] | "- **\(.key):** \(.value)"' 2>/dev/null
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
# Helper: Inject styleguide reference for frontend stories
|
|
557
|
-
_inject_styleguide() {
|
|
558
|
-
local story_json="$1"
|
|
559
|
-
|
|
560
|
-
local story_type
|
|
561
|
-
story_type=$(echo "$story_json" | jq -r '.type // "frontend"' 2>/dev/null)
|
|
562
|
-
local styleguide_path
|
|
563
|
-
styleguide_path=$(get_config '.styleguide' "")
|
|
564
|
-
|
|
565
|
-
if [[ "$story_type" == "frontend" && -n "$styleguide_path" && -f "$styleguide_path" ]]; then
|
|
566
|
-
echo ""
|
|
567
|
-
echo "### Styleguide"
|
|
568
|
-
echo ""
|
|
569
|
-
echo "**FIRST:** Read the project styleguide at \`$styleguide_path\` before implementing."
|
|
570
|
-
echo "Use existing components, colors, and patterns from the styleguide."
|
|
571
|
-
fi
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
# Helper: Inject feature-level context
|
|
575
|
-
_inject_feature_context() {
|
|
576
|
-
echo ""
|
|
577
|
-
echo "## Feature Context"
|
|
578
|
-
echo ""
|
|
579
|
-
echo '```json'
|
|
580
|
-
jq '{feature: .feature, metadata: .metadata}' "$RALPH_DIR/prd.json"
|
|
581
|
-
echo '```'
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
# Helper: Inject scalability requirements
|
|
585
|
-
_inject_scalability() {
|
|
586
|
-
local has_scalability
|
|
587
|
-
has_scalability=$(jq -r '.scalability // empty' "$RALPH_DIR/prd.json" 2>/dev/null)
|
|
588
|
-
[[ -z "$has_scalability" ]] && return
|
|
589
|
-
|
|
590
|
-
echo ""
|
|
591
|
-
echo "## Scalability Requirements"
|
|
592
|
-
echo ""
|
|
593
|
-
echo "**IMPORTANT:** Follow these scalability rules."
|
|
594
|
-
echo ""
|
|
595
|
-
echo '```json'
|
|
596
|
-
jq '.scalability' "$RALPH_DIR/prd.json"
|
|
597
|
-
echo '```'
|
|
598
|
-
echo ""
|
|
599
|
-
echo "### Key Rules:"
|
|
600
|
-
echo "- Always paginate list endpoints (never return unbounded arrays)"
|
|
601
|
-
echo "- Avoid N+1 queries - eager load relationships"
|
|
602
|
-
echo "- Add database indexes for frequently queried fields"
|
|
603
|
-
echo "- Implement caching strategy as specified"
|
|
604
|
-
echo "- Add rate limiting to public endpoints"
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
# Helper: Inject architecture guidelines
|
|
608
|
-
_inject_architecture() {
|
|
609
|
-
local has_architecture
|
|
610
|
-
has_architecture=$(jq -r '.architecture // empty' "$RALPH_DIR/prd.json" 2>/dev/null)
|
|
611
|
-
[[ -z "$has_architecture" ]] && return
|
|
612
|
-
|
|
613
|
-
echo ""
|
|
614
|
-
echo "## Architecture Guidelines"
|
|
615
|
-
echo ""
|
|
616
|
-
echo "**IMPORTANT:** Follow these architecture rules strictly."
|
|
617
|
-
echo ""
|
|
618
|
-
echo '```json'
|
|
619
|
-
jq '.architecture' "$RALPH_DIR/prd.json"
|
|
620
|
-
echo '```'
|
|
621
|
-
echo ""
|
|
622
|
-
echo "### Key Rules:"
|
|
623
|
-
echo "- Put files in the specified directories"
|
|
624
|
-
echo "- Reuse existing components listed in 'patterns.reuse'"
|
|
625
|
-
echo "- Do NOT create anything in 'doNotCreate'"
|
|
626
|
-
echo "- Keep files under $(jq -r '.architecture.principles.maxFileLines // 300' "$RALPH_DIR/prd.json") lines"
|
|
627
|
-
echo "- Scripts go in scripts/, docs go in docs/"
|
|
628
|
-
}
|
|
629
|
-
|
|
630
507
|
# Helper: Build delta prompt for continuing session
|
|
631
|
-
# Minimal context - just
|
|
508
|
+
# Minimal context - just story ID + any failure info
|
|
632
509
|
_build_delta_prompt() {
|
|
633
510
|
local story="$1"
|
|
634
|
-
local
|
|
635
|
-
local failure_context="${3:-}"
|
|
511
|
+
local failure_context="${2:-}"
|
|
636
512
|
|
|
637
513
|
echo ""
|
|
638
514
|
echo "---"
|
|
@@ -642,8 +518,10 @@ _build_delta_prompt() {
|
|
|
642
518
|
if [[ -n "$failure_context" ]]; then
|
|
643
519
|
echo "## Retry: Fix the errors below"
|
|
644
520
|
echo ""
|
|
521
|
+
echo "Read \`.ralph/last_failure.txt\` for full error details."
|
|
522
|
+
echo ""
|
|
645
523
|
echo '```'
|
|
646
|
-
echo "$failure_context"
|
|
524
|
+
echo "$failure_context" | head -50
|
|
647
525
|
echo '```'
|
|
648
526
|
echo ""
|
|
649
527
|
else
|
|
@@ -651,100 +529,79 @@ _build_delta_prompt() {
|
|
|
651
529
|
local completed_count
|
|
652
530
|
completed_count=$(jq '[.stories[] | select(.passes==true)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
653
531
|
if [[ "$completed_count" -gt 0 ]]; then
|
|
654
|
-
echo "## Previous
|
|
532
|
+
echo "## Previous story complete. Moving to next."
|
|
655
533
|
echo ""
|
|
656
|
-
# Suggest compact if we've done several stories
|
|
657
|
-
if [[ "$completed_count" -ge 3 ]]; then
|
|
658
|
-
echo "*Consider running /compact if context feels heavy.*"
|
|
659
|
-
echo ""
|
|
660
|
-
fi
|
|
661
534
|
fi
|
|
662
535
|
fi
|
|
663
536
|
|
|
664
|
-
echo "## Current Story"
|
|
665
|
-
echo ""
|
|
666
|
-
echo '```json'
|
|
667
|
-
echo "$story_json"
|
|
668
|
-
echo '```'
|
|
669
|
-
|
|
670
|
-
# Include file guidance for the new story
|
|
671
|
-
_inject_file_guidance "$story_json"
|
|
672
|
-
_inject_story_scale "$story_json"
|
|
673
|
-
_inject_styleguide "$story_json"
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
# Helper: Inject failure context from previous iteration
|
|
677
|
-
_inject_failure_context() {
|
|
678
|
-
local failure_context="$1"
|
|
679
|
-
[[ -z "$failure_context" ]] && return
|
|
680
|
-
|
|
537
|
+
echo "## Current Story: $story"
|
|
681
538
|
echo ""
|
|
682
|
-
echo "
|
|
683
|
-
echo ""
|
|
684
|
-
echo "Fix the errors below. If a PRD test step is broken, you can fix it in .ralph/prd.json."
|
|
685
|
-
echo ""
|
|
686
|
-
echo '```'
|
|
687
|
-
echo "$failure_context"
|
|
688
|
-
echo '```'
|
|
539
|
+
echo "Read full story details from \`.ralph/prd.json\`"
|
|
689
540
|
}
|
|
690
541
|
|
|
691
|
-
# Helper: Inject signs (learned patterns)
|
|
542
|
+
# Helper: Inject signs (learned patterns) - ALWAYS inject these
|
|
692
543
|
_inject_signs() {
|
|
693
|
-
|
|
694
|
-
echo "## Signs (Learned Patterns)"
|
|
695
|
-
echo ""
|
|
696
|
-
echo "Apply these lessons from previous sessions:"
|
|
697
|
-
echo ""
|
|
698
|
-
if [[ -f "$RALPH_DIR/signs.json" ]]; then
|
|
699
|
-
jq -r '.signs[] | "- [\(.category)] \(.pattern)"' "$RALPH_DIR/signs.json" 2>/dev/null || echo "(none yet)"
|
|
700
|
-
else
|
|
701
|
-
echo "(none yet)"
|
|
702
|
-
fi
|
|
703
|
-
}
|
|
544
|
+
[[ ! -f "$RALPH_DIR/signs.json" ]] && return
|
|
704
545
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
[[
|
|
546
|
+
local sign_count
|
|
547
|
+
sign_count=$(jq '.signs | length' "$RALPH_DIR/signs.json" 2>/dev/null || echo "0")
|
|
548
|
+
[[ "$sign_count" == "0" ]] && return
|
|
708
549
|
|
|
709
550
|
echo ""
|
|
710
|
-
echo "##
|
|
551
|
+
echo "## Signs (Learned Patterns) - FOLLOW THESE"
|
|
711
552
|
echo ""
|
|
712
|
-
|
|
713
|
-
echo ""
|
|
714
|
-
cat "$HOME/.claude/DNA.md"
|
|
553
|
+
jq -r '.signs[] | "- [\(.category)] \(.pattern)"' "$RALPH_DIR/signs.json" 2>/dev/null
|
|
715
554
|
}
|
|
716
555
|
|
|
717
|
-
# Build the prompt
|
|
556
|
+
# Build the prompt - LEAN version
|
|
557
|
+
# Claude reads context from prd.json, we just provide the story ID and signs
|
|
718
558
|
# Usage: build_prompt <story_id> [failure_context] [is_continuation]
|
|
719
559
|
build_prompt() {
|
|
720
560
|
local story="$1"
|
|
721
561
|
local failure_context="${2:-}"
|
|
722
562
|
local is_continuation="${3:-false}"
|
|
723
563
|
|
|
724
|
-
# Get story JSON once
|
|
725
|
-
local story_json
|
|
726
|
-
story_json=$(jq --arg id "$story" '.stories[] | select(.id==$id)' "$RALPH_DIR/prd.json")
|
|
727
|
-
|
|
728
564
|
if [[ "$is_continuation" == "true" ]]; then
|
|
729
|
-
# Delta prompt for continuing session
|
|
730
|
-
_build_delta_prompt "$story" "$
|
|
565
|
+
# Delta prompt for continuing session
|
|
566
|
+
_build_delta_prompt "$story" "$failure_context"
|
|
731
567
|
return
|
|
732
568
|
fi
|
|
733
569
|
|
|
734
|
-
# Full prompt for fresh session
|
|
570
|
+
# Full prompt for fresh session - LEAN
|
|
735
571
|
cat "$PROMPT_FILE"
|
|
736
572
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
573
|
+
echo ""
|
|
574
|
+
echo "---"
|
|
575
|
+
echo ""
|
|
576
|
+
echo "## Current Story: $story"
|
|
577
|
+
echo ""
|
|
578
|
+
echo "Read full story details from \`.ralph/prd.json\` - it contains everything you need:"
|
|
579
|
+
echo "- \`story.files\` - which files to create/modify"
|
|
580
|
+
echo "- \`story.acceptanceCriteria\` - what must be true"
|
|
581
|
+
echo "- \`story.testSteps\` - verification commands"
|
|
582
|
+
echo "- \`story.contextFiles\` - idea files, styleguides to read"
|
|
583
|
+
echo "- \`story.mcp\` - browser tools for verification"
|
|
584
|
+
echo "- \`story.skills\` - relevant skills to reference"
|
|
585
|
+
echo ""
|
|
586
|
+
echo "Also read:"
|
|
587
|
+
echo "- \`prd.techStack\` - technologies in use"
|
|
588
|
+
echo "- \`prd.globalConstraints\` - rules for all stories"
|
|
589
|
+
echo "- \`.ralph/config.json\` - URLs and directories"
|
|
590
|
+
|
|
591
|
+
# Failure context if retrying
|
|
592
|
+
if [[ -n "$failure_context" ]]; then
|
|
593
|
+
echo ""
|
|
594
|
+
echo "## Previous Iteration Failed"
|
|
595
|
+
echo ""
|
|
596
|
+
echo "Read \`.ralph/last_failure.txt\` for details. Key error:"
|
|
597
|
+
echo ""
|
|
598
|
+
echo '```'
|
|
599
|
+
echo "$failure_context" | head -30
|
|
600
|
+
echo '```'
|
|
601
|
+
fi
|
|
602
|
+
|
|
603
|
+
# Signs are critical - always inject to prevent repeated mistakes
|
|
746
604
|
_inject_signs
|
|
747
|
-
_inject_developer_dna
|
|
748
605
|
}
|
|
749
606
|
|
|
750
607
|
# Print story completion summary
|
package/ralph/prd.sh
CHANGED
|
@@ -96,6 +96,7 @@ ralph_prd() {
|
|
|
96
96
|
printf '%s\n' ' "branch": "feature/feature-name",' >> "$prompt_file"
|
|
97
97
|
printf '%s\n' ' "status": "pending"' >> "$prompt_file"
|
|
98
98
|
printf '%s\n' ' },' >> "$prompt_file"
|
|
99
|
+
printf '%s\n' ' "originalContext": "PASTE THE FULL ORIGINAL NOTES/DESCRIPTION HERE - this preserves intent for Claude during implementation",' >> "$prompt_file"
|
|
99
100
|
printf '%s\n' ' "metadata": {' >> "$prompt_file"
|
|
100
101
|
printf '%s\n' ' "security": ["list of security requirements"],' >> "$prompt_file"
|
|
101
102
|
printf '%s\n' ' "scaling": ["list of scaling concerns"],' >> "$prompt_file"
|
|
@@ -185,6 +186,10 @@ ralph_prd() {
|
|
|
185
186
|
printf '%s\n' '- If complexity is "high" AND > 5 stories, MUST split' >> "$prompt_file"
|
|
186
187
|
printf '%s\n' "- Each story should be completable in one Claude session (~10 min)" >> "$prompt_file"
|
|
187
188
|
printf '\n%s\n' "If splitting is needed, generate ONLY phase 1 and note deferred items." >> "$prompt_file"
|
|
189
|
+
printf '\n%s\n' "## Original Context - IMPORTANT" >> "$prompt_file"
|
|
190
|
+
printf '\n%s\n' "Copy the FULL original feature notes into the 'originalContext' field verbatim." >> "$prompt_file"
|
|
191
|
+
printf '%s\n' "This preserves the user's original intent for Claude during implementation." >> "$prompt_file"
|
|
192
|
+
printf '%s\n' "Do NOT summarize - include the complete text." >> "$prompt_file"
|
|
188
193
|
printf '\n%s\n' "## Output" >> "$prompt_file"
|
|
189
194
|
printf '\n%s\n' "After questions are answered, output the prd.json content between these exact markers:" >> "$prompt_file"
|
|
190
195
|
printf '%s\n' "--- BEGIN PRD.JSON ---" >> "$prompt_file"
|