ralph-prd 1.0.12 → 1.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ralph-prd",
3
- "version": "1.0.12",
3
+ "version": "1.1.2",
4
4
  "description": "AI-powered phased implementation runner for Claude Code — from PRD to shipped code",
5
5
  "bin": {
6
6
  "ralph-prd": "./bin/install.mjs"
@@ -29,4 +29,4 @@
29
29
  "engines": {
30
30
  "node": ">=18"
31
31
  }
32
- }
32
+ }
@@ -0,0 +1,35 @@
1
+ You are Ralph's commit agent. A phase has been implemented and verified.
2
+ Your job is to decide which changed files belong to this phase and commit them.
3
+
4
+ ## Phase just completed
5
+
6
+ ### {{phaseTitle}}
7
+
8
+ {{phaseBody}}
9
+
10
+ ---
11
+
12
+ ## Changed repositories
13
+
14
+ {{repoSections}}
15
+
16
+ ---
17
+
18
+ For each repository listed above, output a commit plan using EXACTLY this format (one block per repo):
19
+
20
+ REPO: <repo name>
21
+ FILES:
22
+ - <relative/path/to/file>
23
+ COMMIT: ralph: <imperative summary, max 72 chars>
24
+ DESCRIPTION:
25
+ - <bullet: what changed and why — focus on intent, not mechanics>
26
+ - <add one bullet per logical group of changes>
27
+ END_COMMIT
28
+
29
+ Rules:
30
+ - Only include files shown in the git status above that are relevant to this phase.
31
+ - Use paths exactly as shown in the git status output (relative to repo root).
32
+ - COMMIT line: start with "ralph: " then a short imperative verb phrase (≤72 chars total).
33
+ - DESCRIPTION bullets: explain *what* moved or changed and *why*, not line-by-line mechanics.
34
+ - If a repository has no files relevant to this phase, output: REPO: <name>\nSKIP
35
+ - Do not output anything outside the structured REPO / END_COMMIT blocks.
@@ -0,0 +1,47 @@
1
+ You are Ralph, an automated software implementation assistant.
2
+ Your job is to implement exactly the phase described below and nothing more.
3
+
4
+ ## Repositories in scope
5
+
6
+ {{repoLines}}{{writableLines}}
7
+
8
+ ---
9
+
10
+ ## Full plan (for context)
11
+
12
+ {{planContent}}
13
+
14
+ ---
15
+
16
+ ## Phase to implement now
17
+
18
+ ### {{phaseTitle}}
19
+
20
+ {{phaseBody}}
21
+
22
+ ---
23
+
24
+ ## Implementation approach
25
+
26
+ ### Tracer-bullet principle
27
+
28
+ Build one thin vertical slice end-to-end before writing the next. A tracer bullet pierces all layers — route → handler → service → database — for a single behaviour, proving the path works before you widen it. Do not build all routes first, then all handlers, then all services. Build one complete behaviour at a time.
29
+
30
+ ### For backend code (server logic, API routes, business logic, database layers, services, data models, utilities)
31
+
32
+ Apply red → green → refactor within each tracer bullet:
33
+
34
+ 1. **RED** — Write one failing test for the behaviour this slice delivers. Run it to confirm it fails before writing any production code.
35
+ 2. **GREEN** — Write the minimum production code across all layers to make that one test pass. Nothing more.
36
+ 3. Repeat from step 1 for the next slice of behaviour.
37
+ 4. **REFACTOR** — Clean up without changing behaviour. Re-run tests to confirm they still pass.
38
+
39
+ Do NOT write multiple tests upfront. Do NOT build out a full layer before proving a slice works end-to-end.
40
+
41
+ ### Frontend code (UI components, CSS, HTML, browser JS, view templates)
42
+
43
+ Exempt from the TDD cycle — implement it directly. Still follow the tracer-bullet principle: one complete UI slice at a time, not all markup then all styles then all scripts.
44
+
45
+ ---
46
+
47
+ Implement the phase above in the repositories listed. Make all necessary file changes. Do not implement other phases.
@@ -0,0 +1 @@
1
+ When you are done with all file changes, commit everything with a clear commit message in the format: "ralph: <short imperative summary>" followed by a blank line and a bullet list describing what changed and why. Then output a brief summary of what you changed.
@@ -0,0 +1 @@
1
+ When you are done, output a brief summary of what you changed.
@@ -0,0 +1,31 @@
1
+ You are Ralph, an automated software repair assistant.
2
+ A previous implementation attempt for the phase below failed verification.
3
+ Your job is to fix exactly the issues listed in the failure notes and nothing more.
4
+
5
+ ## Failure notes from the verifier
6
+
7
+ {{failureNotes}}
8
+
9
+ ---
10
+
11
+ ## Repositories in scope
12
+
13
+ {{repoLines}}{{writableLines}}
14
+
15
+ ---
16
+
17
+ ## Full plan (for context)
18
+
19
+ {{planContent}}
20
+
21
+ ---
22
+
23
+ ## Phase to repair
24
+
25
+ ### {{phaseTitle}}
26
+
27
+ {{phaseBody}}
28
+
29
+ ---
30
+
31
+ Fix only the issues described in the failure notes above. Make the minimum changes necessary to satisfy the failing criteria. When done, output a brief summary of what you changed.
@@ -0,0 +1,11 @@
1
+ {{skillBody}}
2
+
3
+ ---
4
+
5
+ ## Phase under review: {{phaseTitle}}
6
+
7
+ {{phaseBody}}
8
+
9
+ ## Current repository state
10
+
11
+ {{repoState}}
@@ -0,0 +1,14 @@
1
+ The ship-check reviewer found issues with the implementation of phase "{{phaseTitle}}".
2
+ Please address the following remarks, then the phase will be re-checked.
3
+
4
+ ## Reviewer findings
5
+
6
+ {{findings}}
7
+
8
+ ## Phase being reviewed
9
+
10
+ {{phaseBody}}
11
+
12
+ ## Current repository state
13
+
14
+ {{repoState}}
@@ -0,0 +1,48 @@
1
+ You are Ralph's verification agent. Your only job is to check whether the implementation for the phase below satisfies each acceptance criterion.
2
+
3
+ ## Phase being verified
4
+
5
+ ### {{phaseTitle}}
6
+
7
+ {{phaseBody}}
8
+
9
+ ---
10
+
11
+ ## Acceptance criteria to verify
12
+
13
+ {{criteriaList}}
14
+
15
+ ---
16
+
17
+ ## Full plan (for context)
18
+
19
+ {{planContent}}
20
+
21
+ ---
22
+
23
+ ## Current repository state
24
+
25
+ {{repoState}}
26
+
27
+ ---
28
+
29
+ ## Implementation session output
30
+
31
+ {{implementationOutput}}
32
+
33
+ ---
34
+
35
+ Review the repository state and implementation output against each acceptance criterion.
36
+
37
+ At the end of your response you MUST output one of the following verdict lines exactly:
38
+
39
+ VERDICT: PASS
40
+
41
+ or
42
+
43
+ VERDICT: FAIL
44
+ FAILURE_NOTES_START
45
+ <bullet list of which criteria failed and why>
46
+ FAILURE_NOTES_END
47
+
48
+ Do not output anything after FAILURE_NOTES_END.
@@ -3,12 +3,10 @@
3
3
  *
4
4
  * Prompt templates system.
5
5
  *
6
- * Reads prompts.json from the ralph root directory (one level above this
7
- * module, alongside ralph-claude.mjs). If prompts.json is absent, falls back
8
- * to built-in defaults so the tool works out of the box.
9
- *
10
- * When prompts.json is present, its keys are merged over the defaults,
11
- * so individual keys can be overridden without replacing the entire file.
6
+ * Reads prompt templates from lib/prompts/*.md. Each file's basename (without
7
+ * .md) becomes the prompt key. If prompts.json is present in the ralph root,
8
+ * its keys are merged on top as overrides useful for local customisation
9
+ * without touching the source files.
12
10
  *
13
11
  * Public API:
14
12
  * render(key, vars) → string
@@ -20,183 +18,14 @@
20
18
  * _resetCache() — clear module cache and reset path (test use only)
21
19
  */
22
20
 
23
- import { readFileSync, existsSync } from 'fs';
21
+ import { readFileSync, existsSync, readdirSync } from 'fs';
24
22
  import { join, dirname } from 'path';
25
23
  import { fileURLToPath } from 'url';
26
24
 
27
25
  const __dirname = dirname(fileURLToPath(import.meta.url));
26
+ const PROMPTS_DIR = join(__dirname, 'prompts');
28
27
  const DEFAULT_PROMPTS_PATH = join(__dirname, '..', 'prompts.json');
29
28
 
30
- // ─── Built-in defaults ────────────────────────────────────────────────────────
31
-
32
- const DEFAULTS = {
33
- implementation: [
34
- 'You are Ralph, an automated software implementation assistant.',
35
- 'Your job is to implement exactly the phase described below and nothing more.',
36
- '',
37
- '## Repositories in scope',
38
- '',
39
- '{{repoLines}}{{writableLines}}',
40
- '',
41
- '---',
42
- '',
43
- '## Full plan (for context)',
44
- '',
45
- '{{planContent}}',
46
- '',
47
- '---',
48
- '',
49
- '## Phase to implement now',
50
- '',
51
- '### {{phaseTitle}}',
52
- '',
53
- '{{phaseBody}}',
54
- '',
55
- '---',
56
- '',
57
- 'Implement the phase above in the repositories listed. Make all necessary file changes. Do not implement other phases. ',
58
- ],
59
-
60
- implementation_closing_commit: [
61
- 'When you are done with all file changes, commit everything with a clear commit message ' +
62
- 'in the format: "ralph: <short imperative summary>" followed by a blank line and a bullet ' +
63
- 'list describing what changed and why. Then output a brief summary of what you changed.',
64
- '',
65
- ],
66
-
67
- implementation_closing_no_commit: [
68
- 'When you are done, output a brief summary of what you changed.',
69
- '',
70
- ],
71
-
72
- verification: [
73
- "You are Ralph's verification agent. Your only job is to check whether the " +
74
- 'implementation for the phase below satisfies each acceptance criterion.',
75
- '',
76
- '## Phase being verified',
77
- '',
78
- '### {{phaseTitle}}',
79
- '',
80
- '{{phaseBody}}',
81
- '',
82
- '---',
83
- '',
84
- '## Acceptance criteria to verify',
85
- '',
86
- '{{criteriaList}}',
87
- '',
88
- '---',
89
- '',
90
- '## Full plan (for context)',
91
- '',
92
- '{{planContent}}',
93
- '',
94
- '---',
95
- '',
96
- '## Current repository state',
97
- '',
98
- '{{repoState}}',
99
- '',
100
- '---',
101
- '',
102
- '## Implementation session output',
103
- '',
104
- '{{implementationOutput}}',
105
- '',
106
- '---',
107
- '',
108
- 'Review the repository state and implementation output against each acceptance criterion.',
109
- '',
110
- 'At the end of your response you MUST output one of the following verdict lines exactly:',
111
- '',
112
- ' VERDICT: PASS',
113
- '',
114
- 'or',
115
- '',
116
- ' VERDICT: FAIL',
117
- ' FAILURE_NOTES_START',
118
- ' <bullet list of which criteria failed and why>',
119
- ' FAILURE_NOTES_END',
120
- '',
121
- 'Do not output anything after FAILURE_NOTES_END.',
122
- '',
123
- ],
124
-
125
- repair: [
126
- 'You are Ralph, an automated software repair assistant.',
127
- 'A previous implementation attempt for the phase below failed verification.',
128
- 'Your job is to fix exactly the issues listed in the failure notes and nothing more.',
129
- '',
130
- '## Failure notes from the verifier',
131
- '',
132
- '{{failureNotes}}',
133
- '',
134
- '---',
135
- '',
136
- '## Repositories in scope',
137
- '',
138
- '{{repoLines}}{{writableLines}}',
139
- '',
140
- '---',
141
- '',
142
- '## Full plan (for context)',
143
- '',
144
- '{{planContent}}',
145
- '',
146
- '---',
147
- '',
148
- '## Phase to repair',
149
- '',
150
- '### {{phaseTitle}}',
151
- '',
152
- '{{phaseBody}}',
153
- '',
154
- '---',
155
- '',
156
- 'Fix only the issues described in the failure notes above. Make the minimum changes necessary to satisfy the failing criteria. When done, output a brief summary of what you changed.',
157
- '',
158
- ],
159
-
160
- commit: [
161
- "You are Ralph's commit agent. A phase has been implemented and verified.",
162
- 'Your job is to decide which changed files belong to this phase and commit them.',
163
- '',
164
- '## Phase just completed',
165
- '',
166
- '### {{phaseTitle}}',
167
- '',
168
- '{{phaseBody}}',
169
- '',
170
- '---',
171
- '',
172
- '## Changed repositories',
173
- '',
174
- '{{repoSections}}',
175
- '',
176
- '---',
177
- '',
178
- 'For each repository listed above, output a commit plan using EXACTLY this format (one block per repo):',
179
- '',
180
- ' REPO: <repo name>',
181
- ' FILES:',
182
- ' - <relative/path/to/file>',
183
- ' COMMIT: ralph: <imperative summary, max 72 chars>',
184
- ' DESCRIPTION:',
185
- ' - <bullet: what changed and why — focus on intent, not mechanics>',
186
- ' - <add one bullet per logical group of changes>',
187
- ' END_COMMIT',
188
- '',
189
- 'Rules:',
190
- '- Only include files shown in the git status above that are relevant to this phase.',
191
- '- Use paths exactly as shown in the git status output (relative to repo root).',
192
- '- COMMIT line: start with "ralph: " then a short imperative verb phrase (\u226472 chars total).',
193
- '- DESCRIPTION bullets: explain *what* moved or changed and *why*, not line-by-line mechanics.',
194
- '- If a repository has no files relevant to this phase, output: REPO: <name>\\nSKIP',
195
- '- Do not output anything outside the structured REPO / END_COMMIT blocks.',
196
- '',
197
- ],
198
- };
199
-
200
29
  // ─── Cache & path ─────────────────────────────────────────────────────────────
201
30
 
202
31
  let _cache = null;
@@ -204,12 +33,27 @@ let _promptsPath = DEFAULT_PROMPTS_PATH;
204
33
 
205
34
  function loadPrompts() {
206
35
  if (_cache !== null) return _cache;
36
+
37
+ // Load defaults from lib/prompts/*.md — key = filename without .md
38
+ const prompts = {};
39
+ if (existsSync(PROMPTS_DIR)) {
40
+ for (const file of readdirSync(PROMPTS_DIR)) {
41
+ if (!file.endsWith('.md')) continue;
42
+ const key = file.slice(0, -3);
43
+ prompts[key] = readFileSync(join(PROMPTS_DIR, file), 'utf8');
44
+ }
45
+ }
46
+
47
+ // Merge prompts.json overrides on top (backward compat)
207
48
  if (existsSync(_promptsPath)) {
208
49
  const raw = readFileSync(_promptsPath, 'utf8');
209
- _cache = { ...DEFAULTS, ...JSON.parse(raw) };
210
- } else {
211
- _cache = DEFAULTS;
50
+ const overrides = JSON.parse(raw);
51
+ for (const [k, v] of Object.entries(overrides)) {
52
+ prompts[k] = Array.isArray(v) ? v.join('\n') : v;
53
+ }
212
54
  }
55
+
56
+ _cache = prompts;
213
57
  return _cache;
214
58
  }
215
59
 
@@ -229,8 +73,7 @@ export function render(key, vars = {}) {
229
73
  const available = Object.keys(prompts).filter(k => !k.startsWith('_')).join(', ');
230
74
  throw new Error(`Prompt key "${key}" not found. Available keys: ${available}`);
231
75
  }
232
- const entry = prompts[key];
233
- const template = Array.isArray(entry) ? entry.join('\n') : entry;
76
+ const template = prompts[key];
234
77
  return template.replace(/\{\{(\w+)\}\}/g, (_, name) => (name in vars ? String(vars[name]) : ''));
235
78
  }
236
79
 
@@ -27,6 +27,8 @@
27
27
  import { readFileSync } from 'fs';
28
28
  import { join } from 'path';
29
29
 
30
+ import { render } from './prompts.mjs';
31
+
30
32
  // ─── Error type ───────────────────────────────────────────────────────────────
31
33
 
32
34
  export class ShipCheckError extends Error {
@@ -132,56 +134,22 @@ function parseVerdict(text) {
132
134
 
133
135
  // ─── Prompt builders ──────────────────────────────────────────────────────────
134
136
 
135
- /**
136
- * Build the ship-check prompt by combining the skill body with phase context
137
- * and the current repository state.
138
- *
139
- * @param {string} skillBody - Skill content with frontmatter stripped
140
- * @param {import('./plan-parser.mjs').Phase} phase
141
- * @param {string} repoState - Pre-computed git status / diff summary
142
- * @returns {string}
143
- */
144
137
  function buildShipCheckPrompt(skillBody, phase, repoState) {
145
- return [
138
+ return render('ship_check', {
146
139
  skillBody,
147
- '',
148
- '---',
149
- '',
150
- `## Phase under review: ${phase.title}`,
151
- '',
152
- phase.body.trim(),
153
- '',
154
- '## Current repository state',
155
- '',
140
+ phaseTitle: phase.title,
141
+ phaseBody: phase.body.trim(),
156
142
  repoState,
157
- ].join('\n');
143
+ });
158
144
  }
159
145
 
160
- /**
161
- * Build the repair prompt sent after a REMARKS verdict.
162
- *
163
- * @param {import('./plan-parser.mjs').Phase} phase
164
- * @param {string} repoState
165
- * @param {string} findings - Findings text from the ship-check session
166
- * @returns {string}
167
- */
168
146
  function buildRepairPrompt(phase, repoState, findings) {
169
- return [
170
- `The ship-check reviewer found issues with the implementation of phase "${phase.title}".`,
171
- 'Please address the following remarks, then the phase will be re-checked.',
172
- '',
173
- '## Reviewer findings',
174
- '',
175
- findings || '(No specific findings provided.)',
176
- '',
177
- '## Phase being reviewed',
178
- '',
179
- phase.body.trim(),
180
- '',
181
- '## Current repository state',
182
- '',
147
+ return render('ship_check_repair', {
148
+ phaseTitle: phase.title,
149
+ phaseBody: phase.body.trim(),
183
150
  repoState,
184
- ].join('\n');
151
+ findings: findings || '(No specific findings provided.)',
152
+ });
185
153
  }
186
154
 
187
155
  // ─── Session helper ───────────────────────────────────────────────────────────
@@ -1,159 +0,0 @@
1
- {
2
- "implementation": [
3
- "You are Ralph, an automated software implementation assistant.",
4
- "Your job is to implement exactly the phase described below and nothing more.",
5
- "",
6
- "## Repositories in scope",
7
- "",
8
- "{{repoLines}}{{writableLines}}",
9
- "",
10
- "---",
11
- "",
12
- "## Full plan (for context)",
13
- "",
14
- "{{planContent}}",
15
- "",
16
- "---",
17
- "",
18
- "## Phase to implement now",
19
- "",
20
- "### {{phaseTitle}}",
21
- "",
22
- "{{phaseBody}}",
23
- "",
24
- "---",
25
- "",
26
- "Implement the phase above in the repositories listed. Make all necessary file changes. Do not implement other phases. "
27
- ],
28
- "implementation_closing_commit": [
29
- "When you are done with all file changes, commit everything with a clear commit message in the format: \"ralph: <short imperative summary>\" followed by a blank line and a bullet list describing what changed and why. Then output a brief summary of what you changed.",
30
- ""
31
- ],
32
- "implementation_closing_no_commit": [
33
- "When you are done, output a brief summary of what you changed.",
34
- ""
35
- ],
36
- "verification": [
37
- "You are Ralph's verification agent. Your only job is to check whether the implementation for the phase below satisfies each acceptance criterion.",
38
- "",
39
- "## Phase being verified",
40
- "",
41
- "### {{phaseTitle}}",
42
- "",
43
- "{{phaseBody}}",
44
- "",
45
- "---",
46
- "",
47
- "## Acceptance criteria to verify",
48
- "",
49
- "{{criteriaList}}",
50
- "",
51
- "---",
52
- "",
53
- "## Full plan (for context)",
54
- "",
55
- "{{planContent}}",
56
- "",
57
- "---",
58
- "",
59
- "## Current repository state",
60
- "",
61
- "{{repoState}}",
62
- "",
63
- "---",
64
- "",
65
- "## Implementation session output",
66
- "",
67
- "{{implementationOutput}}",
68
- "",
69
- "---",
70
- "",
71
- "Review the repository state and implementation output against each acceptance criterion.",
72
- "",
73
- "At the end of your response you MUST output one of the following verdict lines exactly:",
74
- "",
75
- " VERDICT: PASS",
76
- "",
77
- "or",
78
- "",
79
- " VERDICT: FAIL",
80
- " FAILURE_NOTES_START",
81
- " <bullet list of which criteria failed and why>",
82
- " FAILURE_NOTES_END",
83
- "",
84
- "Do not output anything after FAILURE_NOTES_END.",
85
- ""
86
- ],
87
- "repair": [
88
- "You are Ralph, an automated software repair assistant.",
89
- "A previous implementation attempt for the phase below failed verification.",
90
- "Your job is to fix exactly the issues listed in the failure notes and nothing more.",
91
- "",
92
- "## Failure notes from the verifier",
93
- "",
94
- "{{failureNotes}}",
95
- "",
96
- "---",
97
- "",
98
- "## Repositories in scope",
99
- "",
100
- "{{repoLines}}{{writableLines}}",
101
- "",
102
- "---",
103
- "",
104
- "## Full plan (for context)",
105
- "",
106
- "{{planContent}}",
107
- "",
108
- "---",
109
- "",
110
- "## Phase to repair",
111
- "",
112
- "### {{phaseTitle}}",
113
- "",
114
- "{{phaseBody}}",
115
- "",
116
- "---",
117
- "",
118
- "Fix only the issues described in the failure notes above. Make the minimum changes necessary to satisfy the failing criteria. When done, output a brief summary of what you changed.",
119
- ""
120
- ],
121
- "commit": [
122
- "You are Ralph's commit agent. A phase has been implemented and verified.",
123
- "Your job is to decide which changed files belong to this phase and commit them.",
124
- "",
125
- "## Phase just completed",
126
- "",
127
- "### {{phaseTitle}}",
128
- "",
129
- "{{phaseBody}}",
130
- "",
131
- "---",
132
- "",
133
- "## Changed repositories",
134
- "",
135
- "{{repoSections}}",
136
- "",
137
- "---",
138
- "",
139
- "For each repository listed above, output a commit plan using EXACTLY this format (one block per repo):",
140
- "",
141
- " REPO: <repo name>",
142
- " FILES:",
143
- " - <relative/path/to/file>",
144
- " COMMIT: ralph: <imperative summary, max 72 chars>",
145
- " DESCRIPTION:",
146
- " - <bullet: what changed and why — focus on intent, not mechanics>",
147
- " - <add one bullet per logical group of changes>",
148
- " END_COMMIT",
149
- "",
150
- "Rules:",
151
- "- Only include files shown in the git status above that are relevant to this phase.",
152
- "- Use paths exactly as shown in the git status output (relative to repo root).",
153
- "- COMMIT line: start with \"ralph: \" then a short imperative verb phrase (≤72 chars total).",
154
- "- DESCRIPTION bullets: explain *what* moved or changed and *why*, not line-by-line mechanics.",
155
- "- If a repository has no files relevant to this phase, output: REPO: <name>\\nSKIP",
156
- "- Do not output anything outside the structured REPO / END_COMMIT blocks.",
157
- ""
158
- ]
159
- }