This is page 2 of 2. Use http://codebase.md/ghuntley/how-to-ralph-wiggum?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .gitignore
├── .vscode
│ └── settings.json
├── files
│ ├── AGENTS.md
│ ├── IMPLEMENTATION_PLAN.md
│ ├── loop.sh
│ ├── PROMPT_build.md
│ └── PROMPT_plan.md
├── index.html
├── README.md
└── references
├── nah.png
├── ralph-diagram.png
└── sandbox-environments.md
```
# Files
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
```html
1 | <!DOCTYPE html>
2 | <html lang="en">
3 | <head>
4 | <meta charset="UTF-8" />
5 | <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 | <title>The Ralph Playbook</title>
7 | <meta
8 | name="description"
9 | content="A comprehensive guide to running AI coding loops with Geoff Huntley's Ralph methodology."
10 | />
11 |
12 | <!-- Fonts -->
13 | <link rel="preconnect" href="https://fonts.googleapis.com" />
14 | <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
15 | <link
16 | href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
17 | rel="stylesheet"
18 | />
19 |
20 | <style>
21 | /* ==========================================================================
22 | CSS Custom Properties
23 | ========================================================================== */
24 | :root {
25 | /* Font Families */
26 | --font-heading: "Space Grotesk", sans-serif;
27 | --font-body: "Plus Jakarta Sans", sans-serif;
28 | --font-mono: "JetBrains Mono", monospace;
29 |
30 | /* Type Scale (Minor Third ~1.2) */
31 | --text-xs: 0.75rem; /* 12-13px */
32 | --text-sm: 0.875rem; /* 14-15px */
33 | --text-base: 1rem; /* 16-17px body */
34 | --text-lg: 1.125rem; /* 18-19px leads */
35 | --text-xl: 1.3rem; /* ~22px h4 */
36 | --text-2xl: 1.55rem; /* ~26px h3 */
37 | --text-3xl: 1.875rem; /* ~32px h2 */
38 | --text-4xl: 2.25rem; /* ~38px h1 */
39 |
40 | /* Line Heights - Calibrated Per Size */
41 | --leading-tight: 1.15; /* display headings */
42 | --leading-snug: 1.25; /* subheadings h3-h4 */
43 | --leading-normal: 1.55; /* body text */
44 | --leading-relaxed: 1.65; /* lead paragraphs */
45 | --leading-code: 1.5;
46 |
47 | /* Spacing */
48 | --space-xs: 0.25rem;
49 | --space-sm: 0.5rem;
50 | --space-md: 1rem;
51 | --space-lg: 1.5rem;
52 | --space-xl: 2rem;
53 | --space-2xl: 2.5rem;
54 | --space-3xl: 4rem;
55 | --space-4xl: 6rem;
56 |
57 | /* Colors - Near monochrome with muted green accent */
58 | --color-text: #333;
59 | --color-text-muted: #555;
60 | --color-text-faint: #888;
61 | --color-heading: #1a1a1a;
62 | --color-link: #2d5a27;
63 | --color-link-hover: #1e3d1a;
64 | --color-accent: #2d5a27;
65 | --color-accent-light: #e8f0e7;
66 | --color-bg: #ffffff;
67 | --color-bg-subtle: #fafaf9;
68 | --color-bg-code: #1e1e1e;
69 | --color-border: #e5e5e3;
70 | --color-border-strong: #d1d1cf;
71 |
72 | /* Callout Colors - Desaturated/Lighter */
73 | --color-note-bg: #f5f8fb;
74 | --color-note-border: #5588bb;
75 | --color-warning-bg: #fdfaf4;
76 | --color-warning-border: #b89a50;
77 | --color-danger-bg: #fdf7f7;
78 | --color-danger-border: #b85555;
79 | --color-tip-bg: #f6faf7;
80 | --color-tip-border: #5a9a6a;
81 |
82 | /* Content Width */
83 | --content-width: 720px;
84 | --content-width-wide: 900px;
85 | --toc-width: 220px;
86 | }
87 |
88 | /* ==========================================================================
89 | Base Styles
90 | ========================================================================== */
91 | *,
92 | *::before,
93 | *::after {
94 | box-sizing: border-box;
95 | }
96 |
97 | html {
98 | font-size: 15px;
99 | scroll-behavior: smooth;
100 | }
101 |
102 | @media (min-width: 640px) {
103 | html {
104 | font-size: 15px;
105 | }
106 | }
107 |
108 | @media (min-width: 1024px) {
109 | html {
110 | font-size: 15px;
111 | }
112 | }
113 |
114 | body {
115 | font-family: var(--font-body);
116 | font-size: var(--text-base);
117 | font-weight: 400;
118 | line-height: 1.65;
119 | font-optical-sizing: auto;
120 | color: var(--color-text);
121 | background: var(--color-bg);
122 | margin: 0;
123 | padding: 0;
124 | -webkit-font-smoothing: antialiased;
125 | -moz-osx-font-smoothing: grayscale;
126 | font-feature-settings: "kern" 1, "liga" 1;
127 | letter-spacing: 0;
128 | text-rendering: optimizeLegibility;
129 | }
130 |
131 | /* Hyphenation control */
132 | p,
133 | li {
134 | hyphens: auto;
135 | text-wrap: pretty;
136 | }
137 |
138 | h1,
139 | h2,
140 | h3,
141 | h4,
142 | h5,
143 | h6,
144 | code,
145 | pre {
146 | hyphens: none;
147 | }
148 |
149 | :target {
150 | scroll-margin-top: 2rem;
151 | }
152 |
153 | @media (prefers-reduced-motion: reduce) {
154 | html {
155 | scroll-behavior: auto;
156 | }
157 | * {
158 | transition-duration: 0ms !important;
159 | }
160 | }
161 |
162 | /* ==========================================================================
163 | Layout
164 | ========================================================================== */
165 | .page-wrapper {
166 | display: flex;
167 | justify-content: center;
168 | min-height: 100vh;
169 | }
170 |
171 | .content-wrapper {
172 | display: flex;
173 | max-width: 1200px;
174 | width: 100%;
175 | padding: 0 var(--space-lg);
176 | }
177 |
178 | .main-content {
179 | flex: 1;
180 | min-width: 0;
181 | max-width: var(--content-width);
182 | padding: var(--space-xl) 0;
183 | }
184 |
185 | @media (min-width: 1024px) {
186 | .main-content {
187 | padding: var(--space-4xl) var(--space-xl);
188 | }
189 | }
190 |
191 | /* Sidebar TOC */
192 | .toc-sidebar {
193 | display: none;
194 | }
195 |
196 | @media (min-width: 960px) {
197 | .toc-sidebar {
198 | display: block;
199 | width: var(--toc-width);
200 | flex-shrink: 0;
201 | padding-left: var(--space-2xl);
202 | }
203 |
204 | .toc-nav {
205 | position: sticky;
206 | top: var(--space-4xl);
207 | max-height: calc(100vh - var(--space-4xl));
208 | overflow-y: auto;
209 | padding-right: var(--space-md);
210 | }
211 | }
212 |
213 | .toc-title {
214 | font-size: var(--text-sm);
215 | font-weight: 500;
216 | letter-spacing: 0.01em;
217 | color: var(--color-text-faint);
218 | margin-bottom: var(--space-md);
219 | }
220 |
221 | .toc-list {
222 | list-style: none;
223 | padding: 0;
224 | margin: 0;
225 | }
226 |
227 | .toc-link {
228 | display: block;
229 | padding: var(--space-xs) 0;
230 | padding-left: var(--space-sm);
231 | font-size: var(--text-sm);
232 | color: var(--color-text-faint);
233 | text-decoration: none;
234 | border-left: 2px solid transparent;
235 | transition: all 150ms ease;
236 | }
237 |
238 | .toc-link:hover {
239 | color: var(--color-text-muted);
240 | }
241 |
242 | .toc-link.active {
243 | color: var(--color-text-muted);
244 | border-left-color: var(--color-border-strong);
245 | font-weight: 500;
246 | }
247 |
248 | .toc-link--nested {
249 | padding-left: var(--space-lg);
250 | font-size: var(--text-xs);
251 | }
252 |
253 | /* ==========================================================================
254 | Typography - Headings
255 | ========================================================================== */
256 | .article-header {
257 | margin-bottom: var(--space-3xl);
258 | }
259 |
260 | .article-title {
261 | font-family: var(--font-heading);
262 | font-size: var(--text-4xl);
263 | font-weight: 700;
264 | line-height: var(--leading-tight);
265 | letter-spacing: -0.025em;
266 | color: var(--color-heading);
267 | margin: 0 0 var(--space-lg);
268 | text-wrap: balance;
269 | }
270 |
271 | .article-subtitle {
272 | text-wrap: balance;
273 | font-size: var(--text-lg);
274 | font-weight: 400;
275 | line-height: var(--leading-relaxed);
276 | color: var(--color-text-muted);
277 | margin: 0;
278 | }
279 |
280 | .article-meta {
281 | margin-top: var(--space-lg);
282 | font-size: var(--text-sm);
283 | color: var(--color-text-faint);
284 | }
285 |
286 | h2 {
287 | font-family: var(--font-heading);
288 | font-size: var(--text-3xl);
289 | font-weight: 600;
290 | line-height: var(--leading-tight);
291 | letter-spacing: -0.02em;
292 | color: var(--color-heading);
293 | margin-top: 3.5rem;
294 | margin-bottom: 1.25rem;
295 | padding-top: var(--space-lg);
296 | border-top: 1px solid var(--color-border);
297 | text-wrap: balance;
298 | }
299 |
300 | h2:first-of-type {
301 | margin-top: 0;
302 | padding-top: 0;
303 | border-top: none;
304 | }
305 |
306 | h3 {
307 | font-family: var(--font-heading);
308 | font-size: var(--text-2xl);
309 | font-weight: 600;
310 | line-height: var(--leading-snug);
311 | letter-spacing: -0.015em;
312 | color: var(--color-heading);
313 | margin-top: var(--space-2xl);
314 | text-wrap: balance;
315 | }
316 |
317 | h4 {
318 | font-family: var(--font-heading);
319 | font-size: var(--text-xl);
320 | font-weight: 500;
321 | line-height: var(--leading-snug);
322 | letter-spacing: -0.01em;
323 | color: var(--color-heading);
324 | margin-top: var(--space-xl);
325 | text-wrap: balance;
326 | }
327 |
328 | h5 {
329 | font-family: var(--font-heading);
330 | font-size: var(--text-base);
331 | font-weight: 500;
332 | line-height: var(--leading-normal);
333 | color: var(--color-heading);
334 | margin-top: var(--space-lg);
335 | margin-bottom: var(--space-md);
336 | text-wrap: balance;
337 | }
338 |
339 | /* ==========================================================================
340 | Typography - Body
341 | ========================================================================== */
342 | p {
343 | margin: 0 0 1.25rem;
344 | }
345 |
346 | .lead {
347 | font-size: var(--text-lg);
348 | line-height: var(--leading-relaxed);
349 | color: var(--color-text-muted);
350 | margin-bottom: var(--space-xl);
351 | text-wrap: balance;
352 | }
353 |
354 | a {
355 | color: var(--color-link);
356 | text-decoration: underline;
357 | text-decoration-thickness: 1px;
358 | text-underline-offset: 2px;
359 | transition: color 150ms ease;
360 | }
361 |
362 | a:hover {
363 | color: var(--color-link-hover);
364 | }
365 |
366 | strong,
367 | b {
368 | font-weight: 600;
369 | }
370 |
371 | em {
372 | font-style: italic;
373 | }
374 |
375 | small {
376 | font-size: var(--text-sm);
377 | }
378 |
379 | /* ==========================================================================
380 | TL;DR Box
381 | ========================================================================== */
382 | .tldr {
383 | background: var(--color-accent-light);
384 | border-radius: 3px;
385 | border-left: 3px solid var(--color-accent);
386 | padding: var(--space-lg) var(--space-xl);
387 | margin-bottom: var(--space-3xl);
388 | }
389 |
390 | .tldr-title {
391 | font-size: var(--text-sm);
392 | font-weight: 500;
393 | text-transform: uppercase;
394 | letter-spacing: 0.06em;
395 | color: var(--color-accent);
396 | margin-bottom: var(--space-sm);
397 | }
398 |
399 | .tldr p:last-child {
400 | margin-bottom: 0;
401 | }
402 |
403 | /* ==========================================================================
404 | Code
405 | ========================================================================== */
406 | code {
407 | font-family: var(--font-mono);
408 | font-size: 0.85em;
409 | background: var(--color-bg-subtle);
410 | padding: 0.15em 0.4em;
411 | border-radius: 3px;
412 | color: var(--color-text);
413 | }
414 |
415 | pre {
416 | font-family: var(--font-mono);
417 | font-size: 0.875rem;
418 | line-height: var(--leading-code);
419 | background: var(--color-bg-code);
420 | color: #d4d4d4;
421 | padding: var(--space-lg);
422 | border-radius: 4px;
423 | overflow-x: auto;
424 | margin: var(--space-xl) 0;
425 | }
426 |
427 | pre code {
428 | background: none;
429 | padding: 0;
430 | color: inherit;
431 | font-size: 0.8125rem;
432 | border-radius: 0;
433 | }
434 |
435 | .code-block {
436 | position: relative;
437 | margin: var(--space-xl) 0;
438 | }
439 |
440 | .code-block-header {
441 | display: flex;
442 | justify-content: space-between;
443 | align-items: center;
444 | background: #2d2d2d;
445 | padding: var(--space-sm) var(--space-md);
446 | border-radius: 4px 4px 0 0;
447 | font-size: var(--text-sm);
448 | color: #999;
449 | }
450 |
451 | .code-block-header + pre {
452 | margin-top: 0;
453 | border-radius: 0 0 4px 4px;
454 | }
455 |
456 | .copy-btn {
457 | background: transparent;
458 | border: 1px solid #555;
459 | color: #999;
460 | padding: var(--space-xs) var(--space-sm);
461 | border-radius: 4px;
462 | font-size: var(--text-xs);
463 | cursor: pointer;
464 | transition: all 150ms ease;
465 | }
466 |
467 | .copy-btn:hover {
468 | background: #555;
469 | color: #fff;
470 | }
471 |
472 | /* Syntax highlighting (minimal) */
473 | .token-comment {
474 | color: #6a9955;
475 | }
476 | .token-string {
477 | color: #ce9178;
478 | }
479 | .token-keyword {
480 | color: #569cd6;
481 | }
482 | .token-function {
483 | color: #dcdcaa;
484 | }
485 | .token-variable {
486 | color: #9cdcfe;
487 | }
488 |
489 | /* ==========================================================================
490 | Lists
491 | ========================================================================== */
492 | ul,
493 | ol {
494 | margin: 0 0 var(--space-lg);
495 | padding-left: var(--space-lg);
496 | }
497 |
498 | li {
499 | margin-bottom: var(--space-sm);
500 | line-height: var(--leading-normal);
501 | }
502 |
503 | li > ul,
504 | li > ol {
505 | margin: var(--space-sm) 0 0;
506 | }
507 |
508 | /* ==========================================================================
509 | Tables
510 | ========================================================================== */
511 | .table-wrapper {
512 | overflow-x: auto;
513 | margin: var(--space-xl) 0;
514 | border-radius: 4px;
515 | border: 1px solid var(--color-border);
516 | }
517 |
518 | table {
519 | width: 100%;
520 | border-collapse: collapse;
521 | font-size: var(--text-sm);
522 | font-feature-settings: "tnum" 1, "lnum" 1;
523 | }
524 |
525 | thead {
526 | border-bottom: 2px solid var(--color-border);
527 | }
528 |
529 | th {
530 | text-align: left;
531 | padding: var(--space-sm) var(--space-md);
532 | background: var(--color-bg-subtle);
533 | font-weight: 600;
534 | font-size: var(--text-xs);
535 | text-transform: uppercase;
536 | letter-spacing: 0.04em;
537 | color: var(--color-text-muted);
538 | text-wrap: pretty;
539 | }
540 |
541 | td {
542 | padding: var(--space-sm) var(--space-md);
543 | border-bottom: 1px solid var(--color-border);
544 | vertical-align: top;
545 | text-wrap: pretty;
546 | }
547 |
548 | tr:last-child td {
549 | border-bottom: none;
550 | }
551 |
552 | td:first-child {
553 | font-weight: 500;
554 | }
555 |
556 | td code {
557 | font-size: 0.85em;
558 | }
559 |
560 | /* ==========================================================================
561 | Blockquotes & Callouts
562 | ========================================================================== */
563 | blockquote {
564 | margin: var(--space-xl) 0;
565 | padding: 0 0 0 var(--space-lg);
566 | border-left: 2px solid var(--color-border-strong);
567 | color: var(--color-text-muted);
568 | font-style: italic;
569 | }
570 |
571 | blockquote p:last-child {
572 | margin-bottom: 0;
573 | }
574 |
575 | .callout {
576 | margin: var(--space-xl) 0;
577 | padding: var(--space-lg) var(--space-xl);
578 | border-radius: 2px;
579 | border-left: 2px solid;
580 | }
581 |
582 | .callout > *:last-child {
583 | margin-bottom: 0;
584 | }
585 |
586 | .callout-title {
587 | font-weight: 600;
588 | /* font-size: var(--text-sm); */
589 | margin-bottom: 1rem;
590 | display: flex;
591 | align-items: center;
592 | gap: var(--space-sm);
593 | }
594 |
595 | .callout-note {
596 | background: var(--color-note-bg);
597 | border-color: var(--color-note-border);
598 | }
599 | .callout-note .callout-title {
600 | color: var(--color-note-border);
601 | }
602 |
603 | .callout-warning {
604 | background: var(--color-warning-bg);
605 | border-color: var(--color-warning-border);
606 | }
607 | .callout-warning .callout-title {
608 | color: var(--color-warning-border);
609 | }
610 |
611 | .callout-danger {
612 | background: var(--color-danger-bg);
613 | border-color: var(--color-danger-border);
614 | }
615 | .callout-danger .callout-title {
616 | color: var(--color-danger-border);
617 | }
618 |
619 | .callout-tip {
620 | background: var(--color-tip-bg);
621 | border-color: var(--color-tip-border);
622 | }
623 | .callout-tip .callout-title {
624 | color: var(--color-tip-border);
625 | }
626 |
627 | /* ==========================================================================
628 | Figures & Images
629 | ========================================================================== */
630 | figure {
631 | margin: var(--space-xl) 0;
632 | }
633 |
634 | figure img {
635 | max-width: 100%;
636 | height: auto;
637 | border-radius: 4px;
638 | border: 1px solid var(--color-border);
639 | }
640 |
641 | figcaption {
642 | margin-top: var(--space-sm);
643 | font-size: var(--text-sm);
644 | font-weight: 450;
645 | letter-spacing: 0.01em;
646 | color: var(--color-text-faint);
647 | text-align: left;
648 | }
649 |
650 | small,
651 | .text-sm {
652 | font-weight: 450;
653 | letter-spacing: 0.01em;
654 | }
655 |
656 | /* ==========================================================================
657 | Horizontal Rules
658 | ========================================================================== */
659 | hr {
660 | border: none;
661 | border-top: 1px solid var(--color-border);
662 | margin: var(--space-3xl) 0;
663 | }
664 |
665 | /* ==========================================================================
666 | Section Headers with Emoji Icons
667 | ========================================================================== */
668 | .section-icon {
669 | margin-right: var(--space-sm);
670 | }
671 |
672 | /* ==========================================================================
673 | Collapsible Sections (Details/Summary)
674 | ========================================================================== */
675 | details {
676 | margin: var(--space-lg) 0;
677 | border: 1px solid var(--color-border);
678 | border-radius: 3px;
679 | background: var(--color-bg);
680 | }
681 |
682 | summary {
683 | padding: var(--space-md) var(--space-lg);
684 | padding-right: calc(var(--space-lg) + 1.5rem);
685 | cursor: pointer;
686 | font-weight: 500;
687 | list-style: none;
688 | display: flex;
689 | position: relative;
690 | user-select: none;
691 | }
692 |
693 | summary::-webkit-details-marker {
694 | display: none;
695 | }
696 |
697 | summary::after {
698 | content: "+";
699 | font-size: 1.25rem;
700 | color: var(--color-text-muted);
701 | font-weight: 400;
702 | position: absolute;
703 | right: var(--space-lg);
704 | top: var(--space-md);
705 | }
706 |
707 | details[open] summary::after {
708 | content: "−";
709 | color: #fff;
710 | }
711 |
712 | details[open] summary {
713 | border-bottom: 1px solid var(--color-border);
714 | background: var(--color-heading);
715 | color: #fff;
716 | }
717 |
718 | details[open] summary .summary-desc {
719 | color: rgba(255, 255, 255, 0.7);
720 | }
721 |
722 | .details-content {
723 | padding: var(--space-lg);
724 | }
725 |
726 | .details-content > *:last-child {
727 | margin-bottom: 0;
728 | }
729 |
730 | /* Summary with title and description */
731 | summary {
732 | flex-wrap: wrap;
733 | }
734 |
735 | .summary-title {
736 | flex: 1 1 100%;
737 | display: block;
738 | }
739 |
740 | .summary-desc {
741 | flex: 1 1 100%;
742 | display: block;
743 | font-size: var(--text-sm);
744 | font-weight: 400;
745 | color: var(--color-text-muted);
746 | margin-top: var(--space-xs);
747 | }
748 |
749 | /* Expanded panels (non-collapsible, same appearance as details) */
750 | .expanded-panel {
751 | margin: var(--space-lg) 0;
752 | border: 1px solid var(--color-border);
753 | border-radius: 3px;
754 | background: var(--color-bg);
755 | }
756 |
757 | .expanded-panel-header {
758 | padding: var(--space-md) var(--space-lg);
759 | font-weight: 500;
760 | border-bottom: 1px solid var(--color-border);
761 | }
762 |
763 | /* Colored check/x marks */
764 | .mark-pass {
765 | color: #2d7a3a;
766 | }
767 |
768 | .mark-fail {
769 | color: #c53030;
770 | }
771 |
772 | /* ==========================================================================
773 | Enhancement Section (Experimental)
774 | ========================================================================== */
775 | .enhancements-section {
776 | background: var(--color-bg-subtle);
777 | border-radius: 4px;
778 | padding: var(--space-xl);
779 | margin-top: var(--space-3xl);
780 | }
781 |
782 | .experimental-badge {
783 | display: inline-flex;
784 | align-items: center;
785 | gap: var(--space-xs);
786 | background: var(--color-warning-bg);
787 | color: var(--color-warning-border);
788 | padding: var(--space-xs) var(--space-sm);
789 | border-radius: 3px;
790 | font-size: var(--text-xs);
791 | font-weight: 500;
792 | text-transform: uppercase;
793 | letter-spacing: 0.04em;
794 | margin-bottom: var(--space-md);
795 | }
796 |
797 | .enhancements-section h2 {
798 | margin-top: 0;
799 | padding-top: 0;
800 | border-top: none;
801 | }
802 |
803 | /* ==========================================================================
804 | Inline TOC (Mobile)
805 | ========================================================================== */
806 | .inline-toc {
807 | background: var(--color-bg-subtle);
808 | border-radius: 4px;
809 | padding: var(--space-lg);
810 | margin-bottom: var(--space-xl);
811 | }
812 |
813 | @media (min-width: 960px) {
814 | .inline-toc {
815 | display: none;
816 | }
817 | }
818 |
819 | .inline-toc-title {
820 | font-size: var(--text-sm);
821 | font-weight: 600;
822 | margin-bottom: var(--space-md);
823 | color: var(--color-text-muted);
824 | }
825 |
826 | .inline-toc ul {
827 | margin: 0;
828 | padding-left: var(--space-lg);
829 | }
830 |
831 | .inline-toc li {
832 | margin-bottom: var(--space-xs);
833 | }
834 |
835 | .inline-toc a {
836 | font-size: var(--text-sm);
837 | text-decoration: none;
838 | }
839 |
840 | .inline-toc a:hover {
841 | text-decoration: underline;
842 | }
843 |
844 | /* ==========================================================================
845 | Footer
846 | ========================================================================== */
847 | .article-footer {
848 | margin-top: var(--space-4xl);
849 | padding-top: var(--space-xl);
850 | border-top: 1px solid var(--color-border);
851 | font-size: var(--text-sm);
852 | color: var(--color-text-faint);
853 | }
854 |
855 | /* ==========================================================================
856 | Print Styles
857 | ========================================================================== */
858 | @media print {
859 | .toc-sidebar,
860 | .copy-btn,
861 | .inline-toc {
862 | display: none !important;
863 | }
864 |
865 | details {
866 | display: block !important;
867 | }
868 |
869 | details[open] summary::after {
870 | display: none;
871 | }
872 |
873 | .main-content {
874 | max-width: 100%;
875 | }
876 | }
877 | </style>
878 | </head>
879 | <body>
880 | <!--
881 | =====================================================================
882 | SYNC GUIDE FOR CLAUDE
883 | =====================================================================
884 |
885 | This HTML mirrors README.md content with styled presentation.
886 |
887 | SOURCE OF TRUTH: README.md
888 |
889 | SYNC RULES:
890 | - Content inside !-- HTML-ONLY: description --
891 | blocks is NOT in README → Preserve these blocks exactly when syncing - All
892 | other content should match README.md → Update to match README when syncing -
893 | Preserve HTML structure/styling (classes, wrappers) while syncing text
894 | HTML-ONLY CONTENT TYPES: - TL;DR summary box - Lead paragraphs (.lead class)
895 | under major section headings - Article header/subtitle/meta - Inline TOC
896 | (mobile) - Figure captions - Files table with "Modified By" column - Styled
897 | callout wrappers (content comes from README, styling is HTML-only) TO SYNC:
898 | "Update index.html to match README.md - preserve HTML-ONLY blocks"
899 | ===================================================================== -->
900 | <div class="page-wrapper">
901 | <div class="content-wrapper">
902 | <main class="main-content">
903 | <!-- HTML-ONLY: Article header with subtitle and source link -->
904 | <header id="intro" class="article-header">
905 | <h1 class="article-title">The Ralph Playbook</h1>
906 | <p class="article-subtitle">
907 | A comprehensive guide to running autonomous AI coding loops.
908 | </p>
909 | <div class="article-meta">
910 | <p style="margin-bottom: .5rem;">
911 | Thought up by
912 | <a href="https://x.com/GeoffreyHuntley">Geoff Huntley</a> · Regurgitated by
913 | <a href="https://x.com/ClaytonFarr">Clayton Farr</a>
914 | </p>
915 | <p>
916 | Original source -
917 | <a href="https://ghuntley.com/ralph/">ghuntley.com/ralph</a>
918 | </p>
919 | </div>
920 | </header>
921 | <!-- /HTML-ONLY -->
922 |
923 | <!-- HTML-ONLY: TL;DR summary box -->
924 | <div class="tldr">
925 | <div class="tldr-title">TL;DR</div>
926 | <p>
927 | <strong>Ralph</strong> is an autonomous coding methodology that
928 | runs Claude in a continuous loop, using file-based state to
929 | maintain context across iterations. Each loop: read plan → pick
930 | task → implement → test → commit → clear context → repeat.
931 | </p>
932 | <p>
933 | <strong>Why it works:</strong> Fresh context each iteration keeps
934 | the AI in its "smart zone." File-based memory (specs, plan, agents
935 | file) persists learnings. Backpressure (utilities, tests, builds)
936 | forces self-correction.
937 | </p>
938 | <p>
939 | <strong>Key files:</strong> <code>PROMPT.md</code> (instructions)
940 | + <code>AGENTS.md</code> (operational guide) +
941 | <code>IMPLEMENTATION_PLAN.md</code> (task list) +
942 | <code>specs/*</code> (requirements)
943 | </p>
944 | </div>
945 | <!-- /HTML-ONLY -->
946 |
947 | <!-- HTML-ONLY: Inline TOC for mobile -->
948 | <nav class="inline-toc" aria-label="Table of contents">
949 | <div class="inline-toc-title">On This Page</div>
950 | <ul>
951 | <li><a href="#workflow">Workflow</a></li>
952 | <li><a href="#key-principles">Key Principles</a></li>
953 | <li><a href="#loop-mechanics">Loop Mechanics</a></li>
954 | <li><a href="#files">Files</a></li>
955 | <li><a href="#enhancements">Enhancements?</a></li>
956 | </ul>
957 | </nav>
958 | <!-- /HTML-ONLY -->
959 |
960 | <!-- Introduction -->
961 | <section>
962 | <p>
963 | December 2025 boiled
964 | <a href="https://ghuntley.com/ralph/">Ralph's</a> powerful yet
965 | dumb little face to the top of most AI-related timelines.
966 | </p>
967 |
968 | <p>
969 | I try to pay attention to the crazy-smart insights
970 | <a href="https://x.com/GeoffreyHuntley">@GeoffreyHuntley</a>
971 | shares, but I can't say Ralph really clicked for me this summer.
972 | Now, all of the recent hubbub has made it hard to ignore.
973 | </p>
974 |
975 | <p>
976 | <a href="https://x.com/mattpocockuk/status/2008200878633931247"
977 | >@mattpocockuk</a
978 | >
979 | and
980 | <a href="https://x.com/ryancarson/status/2008548371712135632"
981 | >@ryancarson</a
982 | >'s overviews helped a lot – right until Geoff came in and
983 | <a href="https://x.com/GeoffreyHuntley/status/2008731415312236984"
984 | >said 'nah'</a
985 | >.
986 | </p>
987 |
988 | <figure>
989 | <img
990 | src="https://raw.githubusercontent.com/ClaytonFarr/ralph-playbook/main/references/nah.png"
991 | alt="Geoff Huntley responding 'nah' to various Ralph interpretations"
992 | width="500"
993 | />
994 | </figure>
995 |
996 | <h3>So what is the optimal way to Ralph?</h3>
997 |
998 | <p>
999 | Many folks seem to be getting good results with various shapes –
1000 | but I wanted to read the tea leaves as closely as possible from
1001 | the person who not only captured this approach but also has had
1002 | the most ass-time in the seat putting it through its paces.
1003 | </p>
1004 |
1005 | <p>
1006 | So I dug in to really <em>RTFM</em> on
1007 | <a href="https://www.youtube.com/watch?v=O2bBWDoxO4s"
1008 | >recent videos</a
1009 | >
1010 | and Geoff's
1011 | <a href="https://ghuntley.com/ralph/">original post</a> to try and
1012 | untangle for myself what works best.
1013 | </p>
1014 |
1015 | <p>
1016 | Below is the result – a (likely OCD-fueled) Ralph Playbook that
1017 | organizes the miscellaneous details for putting this all into
1018 | practice w/o hopefully neutering it in the process.
1019 | </p>
1020 |
1021 | <div class="callout callout-note">
1022 | <div class="callout-title">Note</div>
1023 | <p>
1024 | Digging into all of this has also brought to mind some possibly
1025 | valuable <a href="#enhancements">additional enhancements</a> to
1026 | the core approach that aim to stay aligned with the guidelines
1027 | that make Ralph work so well.
1028 | </p>
1029 | </div>
1030 | </section>
1031 |
1032 | <p>Hope this helps you out - <a href="https://x.com/ClaytonFarr">Clayton</a></p>
1033 |
1034 | <hr />
1035 |
1036 | <!-- Workflow -->
1037 | <section id="workflow">
1038 | <h2>Workflow</h2>
1039 |
1040 | <p>
1041 | A picture is worth a thousand tweets and an hour-long video.
1042 | Geoff's
1043 | <a href="https://ghuntley.com/ralph/">overview here</a> (sign up
1044 | to his newsletter to see full article) really helped clarify the
1045 | workflow details for moving from 1) idea → 2) individual
1046 | JTBD-aligned specs → 3) comprehensive implementation plan → 4)
1047 | Ralph work loops.
1048 | </p>
1049 |
1050 | <figure>
1051 | <a
1052 | href="https://raw.githubusercontent.com/ClaytonFarr/ralph-playbook/main/references/ralph-diagram.png"
1053 | target="_blank"
1054 | rel="noopener"
1055 | >
1056 | <img
1057 | src="https://raw.githubusercontent.com/ClaytonFarr/ralph-playbook/main/references/ralph-diagram.png"
1058 | alt="Ralph workflow diagram showing the three phases"
1059 | />
1060 | </a>
1061 | <!-- HTML-ONLY: Figure caption -->
1062 | <figcaption>
1063 | The Ralph Process: From idea to implementation through specs,
1064 | planning, and building loops
1065 | </figcaption>
1066 | <!-- /HTML-ONLY -->
1067 | </figure>
1068 |
1069 | <h3>
1070 | <span class="section-icon">🗘</span> Three Phases, Two Prompts, One
1071 | Loop
1072 | </h3>
1073 |
1074 | <h4>Phase 1: Define Requirements (LLM conversation)</h4>
1075 | <ul>
1076 | <li>Discuss project ideas → identify Jobs to Be Done (JTBD)</li>
1077 | <li>Break individual JTBD into topic(s) of concern</li>
1078 | <li>Use subagents to load info from URLs into context</li>
1079 | <li>
1080 | LLM understands JTBD topic of concern: subagent writes
1081 | <code>specs/FILENAME.md</code> for each topic
1082 | </li>
1083 | </ul>
1084 |
1085 | <h4>Phase 2 / 3: Run Ralph Loop</h4>
1086 | <p>
1087 | Same loop mechanism, different prompts for different objectives:
1088 | </p>
1089 |
1090 | <div class="table-wrapper">
1091 | <table>
1092 | <thead>
1093 | <tr>
1094 | <th>Mode</th>
1095 | <th>When to use</th>
1096 | <th>Prompt focus</th>
1097 | </tr>
1098 | </thead>
1099 | <tbody>
1100 | <tr>
1101 | <td><em>PLANNING</em></td>
1102 | <td>No plan exists, or plan is stale/wrong</td>
1103 | <td>
1104 | Generate/update <code>IMPLEMENTATION_PLAN.md</code> only
1105 | </td>
1106 | </tr>
1107 | <tr>
1108 | <td><em>BUILDING</em></td>
1109 | <td>Plan exists</td>
1110 | <td>
1111 | Implement from plan, commit, update plan as side effect
1112 | </td>
1113 | </tr>
1114 | </tbody>
1115 | </table>
1116 | </div>
1117 |
1118 | <h5>Prompt differences per mode:</h5>
1119 | <ul>
1120 | <li>
1121 | <strong>PLANNING</strong> prompt does gap analysis (specs vs
1122 | code) and outputs a prioritized TODO list – no implementation,
1123 | no commits.
1124 | </li>
1125 | <li>
1126 | <strong>BUILDING</strong> prompt assumes plan exists, picks
1127 | tasks from it, implements, runs tests (backpressure), commits.
1128 | </li>
1129 | </ul>
1130 |
1131 | <h5>Why use the loop for both modes?</h5>
1132 | <ul>
1133 | <li>
1134 | <strong>BUILDING requires it:</strong> inherently iterative
1135 | (many tasks × fresh context = isolation)
1136 | </li>
1137 | <li>
1138 | <strong>PLANNING uses it for consistency:</strong> same
1139 | execution model, though often completes in 1-2 iterations
1140 | </li>
1141 | <li>
1142 | <strong>Flexibility:</strong> if plan needs refinement, loop
1143 | allows multiple passes reading its own output
1144 | </li>
1145 | <li>
1146 | <strong>Simplicity:</strong> one mechanism for everything; clean
1147 | file I/O; easy stop/restart
1148 | </li>
1149 | </ul>
1150 |
1151 | <p>
1152 | <strong>Context loaded each iteration:</strong>
1153 | <code>PROMPT.md</code> + <code>AGENTS.md</code>
1154 | </p>
1155 |
1156 | <div class="expanded-panel">
1157 | <div class="expanded-panel-header">
1158 | PLANNING mode loop lifecycle
1159 | </div>
1160 | <div class="details-content">
1161 | <ol>
1162 | <li>
1163 | Subagents study <code>specs/*</code> and existing
1164 | <code>/src</code>
1165 | </li>
1166 | <li>Compare specs against code (gap analysis)</li>
1167 | <li>
1168 | Create/update <code>IMPLEMENTATION_PLAN.md</code> with
1169 | prioritized tasks
1170 | </li>
1171 | <li>No implementation</li>
1172 | </ol>
1173 | </div>
1174 | </div>
1175 |
1176 | <div class="expanded-panel">
1177 | <div class="expanded-panel-header">
1178 | BUILDING mode loop lifecycle
1179 | </div>
1180 | <div class="details-content">
1181 | <ol>
1182 | <li>
1183 | <strong>Orient</strong> – subagents study
1184 | <code>specs/*</code> (requirements)
1185 | </li>
1186 | <li>
1187 | <strong>Read plan</strong> – study
1188 | <code>IMPLEMENTATION_PLAN.md</code>
1189 | </li>
1190 | <li>
1191 | <strong>Select</strong> – pick the most important task
1192 | </li>
1193 | <li>
1194 | <strong>Investigate</strong> – subagents study relevant
1195 | <code>/src</code> ("don't assume not implemented")
1196 | </li>
1197 | <li>
1198 | <strong>Implement</strong> – N subagents for file operations
1199 | </li>
1200 | <li>
1201 | <strong>Validate</strong> – 1 subagent for build/tests
1202 | (backpressure)
1203 | </li>
1204 | <li>
1205 | <strong>Update <code>IMPLEMENTATION_PLAN.md</code></strong>
1206 | – mark task done, note discoveries/bugs
1207 | </li>
1208 | <li>
1209 | <strong>Update <code>AGENTS.md</code></strong> – if
1210 | operational learnings
1211 | </li>
1212 | <li><strong>Commit</strong></li>
1213 | <li>
1214 | <strong>Loop ends</strong> → context cleared → next
1215 | iteration starts fresh
1216 | </li>
1217 | </ol>
1218 | </div>
1219 | </div>
1220 |
1221 | <h3>Concepts</h3>
1222 |
1223 | <div class="table-wrapper">
1224 | <table>
1225 | <thead>
1226 | <tr>
1227 | <th>Term</th>
1228 | <th>Definition</th>
1229 | </tr>
1230 | </thead>
1231 | <tbody>
1232 | <tr>
1233 | <td><em>Job to be Done (JTBD)</em></td>
1234 | <td>High-level user need or outcome</td>
1235 | </tr>
1236 | <tr>
1237 | <td><em>Topic of Concern</em></td>
1238 | <td>A distinct aspect/component within a JTBD</td>
1239 | </tr>
1240 | <tr>
1241 | <td><em>Spec</em></td>
1242 | <td>
1243 | Requirements doc for one topic of concern
1244 | (<code>specs/FILENAME.md</code>)
1245 | </td>
1246 | </tr>
1247 | <tr>
1248 | <td><em>Task</em></td>
1249 | <td>Unit of work derived from comparing specs to code</td>
1250 | </tr>
1251 | </tbody>
1252 | </table>
1253 | </div>
1254 |
1255 | <p><strong>Relationships:</strong></p>
1256 | <ul>
1257 | <li>1 JTBD → multiple topics of concern</li>
1258 | <li>1 topic of concern → 1 spec</li>
1259 | <li>1 spec → multiple tasks (specs are larger than tasks)</li>
1260 | </ul>
1261 |
1262 | <div class="expanded-panel">
1263 | <div class="expanded-panel-header">Example: JTBD breakdown</div>
1264 | <div class="details-content">
1265 | <ul>
1266 | <li>
1267 | <strong>JTBD:</strong> "Help designers create mood boards"
1268 | </li>
1269 | <li>
1270 | <strong>Topics:</strong> image collection, color extraction,
1271 | layout, sharing
1272 | </li>
1273 | <li><strong>Each topic</strong> → one spec file</li>
1274 | <li>
1275 | <strong>Each spec</strong> → many tasks in implementation
1276 | plan
1277 | </li>
1278 | </ul>
1279 | </div>
1280 | </div>
1281 |
1282 | <div class="callout callout-tip">
1283 | <div class="callout-title">Topic Scope Test</div>
1284 | <p>
1285 | <strong>"One Sentence Without 'And'"</strong> – Can you describe
1286 | the topic of concern in one sentence without conjoining
1287 | unrelated capabilities?
1288 | </p>
1289 | <ul>
1290 | <li>
1291 | <span class="mark-pass">✓</span> "The color extraction system
1292 | analyzes images to identify dominant colors"
1293 | </li>
1294 | <li>
1295 | <span class="mark-fail">✗</span> "The user system handles
1296 | authentication, profiles, and billing" → 3 topics
1297 | </li>
1298 | </ul>
1299 | <p>
1300 | If you need "and" to describe what it does, it's probably
1301 | multiple topics.
1302 | </p>
1303 | </div>
1304 | </section>
1305 |
1306 | <hr />
1307 |
1308 | <!-- Key Principles -->
1309 | <section id="key-principles">
1310 | <h2>Key Principles</h2>
1311 |
1312 | <!-- HTML-ONLY: Section lead paragraph -->
1313 | <p class="lead">
1314 | Four principles drive Ralph's effectiveness: constrained context,
1315 | backpressure, autonomous action, and human oversight over the loop
1316 | - not in it.
1317 | </p>
1318 | <!-- /HTML-ONLY -->
1319 |
1320 | <h3>
1321 | <span class="section-icon">⏳</span> Context Is
1322 | <em>Everything</em>
1323 | </h3>
1324 |
1325 | <ul>
1326 | <li>When 200K+ tokens advertised = ~176K truly usable</li>
1327 | <li>And 40-60% context utilization for "smart zone"</li>
1328 | <li>
1329 | Tight tasks + 1 task per loop =
1330 | <strong>100% smart zone context utilization</strong>
1331 | </li>
1332 | </ul>
1333 |
1334 | <p>This informs and drives everything else:</p>
1335 |
1336 | <ul>
1337 | <li>
1338 | <strong>Use the main agent/context as a scheduler</strong> –
1339 | Don't allocate expensive work to main context; spawn subagents
1340 | whenever possible instead
1341 | </li>
1342 | <li>
1343 | <strong>Use subagents as memory extension</strong> – Each
1344 | subagent gets ~156kb that's garbage collected. Fan out to avoid
1345 | polluting main context
1346 | </li>
1347 | <li>
1348 | <strong>Simplicity and brevity win</strong> – Applies to number
1349 | of parts in system, loop config, and content. Verbose inputs
1350 | degrade determinism
1351 | </li>
1352 | <li>
1353 | <strong>Prefer Markdown over JSON</strong> – To define and track
1354 | work, for better token efficiency
1355 | </li>
1356 | </ul>
1357 |
1358 | <h3>
1359 | <span class="section-icon">🧭</span> Steering Ralph: Patterns +
1360 | Backpressure
1361 | </h3>
1362 |
1363 | <p>
1364 | Creating the right signals & gates to steer Ralph's successful
1365 | output is <strong>critical</strong>. You can steer from two
1366 | directions:
1367 | </p>
1368 |
1369 | <h5>Steer upstream</h5>
1370 | <ul>
1371 | <li>
1372 | Ensure deterministic setup:
1373 | <ul>
1374 | <li>Allocate first ~5,000 tokens for specs</li>
1375 | <li>
1376 | Every loop's context is allocated with the same files so
1377 | model starts from known state (<code>PROMPT.md</code> +
1378 | <code>AGENTS.md</code>)
1379 | </li>
1380 | </ul>
1381 | </li>
1382 | <li>Your existing code shapes what gets used and generated</li>
1383 | <li>
1384 | If Ralph is generating wrong patterns, add/update utilities and
1385 | existing code patterns to steer it toward correct ones
1386 | </li>
1387 | </ul>
1388 |
1389 | <h5>Steer downstream</h5>
1390 | <ul>
1391 | <li>Create backpressure to reject invalid work</li>
1392 | <li>
1393 | Wire in whatever validates your code: tests, typechecks, lints,
1394 | builds, etc.
1395 | </li>
1396 | <li>
1397 | Prompt says "run tests" generically.
1398 | <code>AGENTS.md</code> specifies actual commands to make
1399 | backpressure project-specific
1400 | </li>
1401 | <li>
1402 | Backpressure can extend beyond code validation: some acceptance
1403 | criteria resist programmatic checks - creative quality,
1404 | aesthetics, UX feel. LLM-as-judge tests can provide backpressure
1405 | for subjective criteria with binary pass/fail. (<a
1406 | href="#non-deterministic-backpressure"
1407 | >More detailed thoughts below</a
1408 | >
1409 | on how to approach this with Ralph.)
1410 | </li>
1411 | </ul>
1412 |
1413 | <div class="callout callout-note">
1414 | <div class="callout-title">
1415 | Remind Ralph in Prompt.md to use backpressure:
1416 | </div>
1417 | <p>
1418 | "Important: When authoring documentation, capture the why -
1419 | tests and implementation importance."
1420 | </p>
1421 | </div>
1422 |
1423 | <h3><span class="section-icon">🙏</span> Let Ralph Ralph</h3>
1424 |
1425 | <p>
1426 | Ralph's effectiveness comes from how much you trust it do the
1427 | right thing (eventually) and engender its ability to do so.
1428 | </p>
1429 |
1430 | <h5>Let Ralph Ralph</h5>
1431 | <ul>
1432 | <li>
1433 | Lean into LLM's ability to self-identify, self-correct and
1434 | self-improve.
1435 | </li>
1436 | <li>
1437 | Applies to implementation plan, task definition and
1438 | prioritization.
1439 | </li>
1440 | <li>Eventual consistency achieved through iteration.</li>
1441 | </ul>
1442 |
1443 | <h5>
1444 | Use Protection (<span style="color: var(--color-danger-border)"
1445 | >Really</span
1446 | >)
1447 | </h5>
1448 | <ul>
1449 | <li>
1450 | To operate autonomously, Ralph requires
1451 | <code>--dangerously-skip-permissions</code> - asking for
1452 | approval on every tool call would break the loop. This bypasses
1453 | Claude's permission system entirely - so a sandbox becomes your
1454 | only security boundary.
1455 | </li>
1456 | <li>
1457 | <em>Philosophy</em> - "It's not if it gets popped, it's when.
1458 | And what is the blast radius?"
1459 | </li>
1460 | <li>
1461 | Running without a sandbox exposes credentials, browser cookies,
1462 | SSH keys, and access tokens on your machine.
1463 | </li>
1464 | <li>
1465 | Run in isolated environments with minimum viable access:
1466 | <ul>
1467 | <li>Only the API keys and deploy keys needed for the task</li>
1468 | <li>No access to private data beyond requirements</li>
1469 | <li>Restrict network connectivity where possible</li>
1470 | </ul>
1471 | </li>
1472 | <li>
1473 | <em>Options</em> - Docker sandboxes (local), Fly
1474 | Sprites/E2B/etc. (remote/production).
1475 | <a href="references/sandbox-environments.md"
1476 | >Additional notes on options.</a
1477 | >
1478 | </li>
1479 | <li>
1480 | <em>Additional escape hatches</em> - Ctrl+C stops the loop;
1481 | <code>git reset --hard</code> reverts uncommitted changes;
1482 | regenerate plan if trajectory goes wrong.
1483 | </li>
1484 | </ul>
1485 |
1486 | <h3><span class="section-icon">🚦</span> Move Outside the Loop</h3>
1487 |
1488 | <p>
1489 | To get the most out of Ralph, you need to get out of his way.
1490 | Ralph should be doing <em>all</em> of the work, including decided
1491 | which planned work to implement next and how to implement it. Your
1492 | job is now to sit on the loop, not in it – to engineer the setup
1493 | and environment that will allow Ralph to succeed.
1494 | </p>
1495 |
1496 | <p>
1497 | <strong>Observe and course correct</strong> – especially early on,
1498 | sit and watch. What patterns emerge? Where does Ralph go wrong?
1499 | What signs does he need? The prompts you start with won't be the
1500 | prompts you end with – they evolve through observed failure
1501 | patterns.
1502 | </p>
1503 |
1504 | <p>
1505 | <strong>Tune it like a guitar</strong> – instead of prescribing
1506 | everything upfront, observe and adjust reactively. When Ralph
1507 | fails a specific way, add a sign to help him next time.
1508 | </p>
1509 |
1510 | <p>
1511 | But signs aren't just prompt text. They're <em>anything</em> Ralph
1512 | can discover:
1513 | </p>
1514 | <ul>
1515 | <li>
1516 | <strong>Prompt guardrails</strong> – explicit instructions like
1517 | "don't assume not implemented"
1518 | </li>
1519 | <li>
1520 | <strong><code>AGENTS.md</code></strong> – operational learnings
1521 | about how to build/test
1522 | </li>
1523 | <li>
1524 | <strong>Utilities in your codebase</strong> – when you add a
1525 | pattern, Ralph discovers it and follows it
1526 | </li>
1527 | <li>Other discoverable, relevant inputs…</li>
1528 | </ul>
1529 |
1530 | <div class="callout callout-tip">
1531 | <div class="callout-title">The plan is designed to be disposable…</div>
1532 | <ul>
1533 | <li>If it's wrong, throw it out and start over</li>
1534 | <li>
1535 | Regeneration cost is one Planning loop; cheap compared to
1536 | Ralph going in circles
1537 | </li>
1538 | <li>
1539 | Regenerate when:
1540 | <ul>
1541 | <li>
1542 | Ralph is going off track (implementing wrong things,
1543 | duplicating work)
1544 | </li>
1545 | <li>Plan feels stale or doesn't match current state</li>
1546 | <li>Too much clutter from completed items</li>
1547 | <li>You've made significant spec changes</li>
1548 | <li>You're confused about what's actually done</li>
1549 | </ul>
1550 | </li>
1551 | </ul>
1552 | </div>
1553 | </section>
1554 |
1555 | <hr />
1556 |
1557 | <!-- Loop Mechanics -->
1558 | <section id="loop-mechanics">
1559 | <h2>Loop Mechanics</h2>
1560 |
1561 | <!-- HTML-ONLY: Section lead paragraph -->
1562 | <p class="lead">
1563 | The mechanical details of how the outer bash loop and inner task
1564 | execution work together.
1565 | </p>
1566 | <!-- /HTML-ONLY -->
1567 |
1568 | <h3><span class="section-icon">🔄</span> Outer Loop Control</h3>
1569 |
1570 | <p>Geoff's initial minimal form of `loop.sh` script:</p>
1571 |
1572 | <div class="code-block">
1573 | <div class="code-block-header">
1574 | <span>bash</span>
1575 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
1576 | </div>
1577 | <pre><code>while :; do cat PROMPT.md | claude ; done</code></pre>
1578 | </div>
1579 |
1580 | <p>
1581 | <em>Note:</em> The same approach can be used with other CLIs; e.g.
1582 | <code>amp</code>, <code>codex</code>, <code>opencode</code>, etc.
1583 | </p>
1584 |
1585 | <h4>What controls task continuation?</h4>
1586 |
1587 | <p>The continuation mechanism is elegantly simple:</p>
1588 | <ol>
1589 | <li>
1590 | <strong>Bash loop runs</strong> → feeds
1591 | <code>PROMPT.md</code> to claude
1592 | </li>
1593 | <li>
1594 | <strong>PROMPT.md instructs</strong> → "Study
1595 | IMPLEMENTATION_PLAN.md and choose the most important thing"
1596 | </li>
1597 | <li>
1598 | <strong>Agent completes one task</strong> → updates
1599 | IMPLEMENTATION_PLAN.md on disk, commits, exits
1600 | </li>
1601 | <li>
1602 | <strong>Bash loop restarts immediately</strong> → fresh context
1603 | window
1604 | </li>
1605 | <li>
1606 | <strong>Agent reads updated plan</strong> → picks next most
1607 | important thing
1608 | </li>
1609 | </ol>
1610 |
1611 | <div class="callout callout-note">
1612 | <div class="callout-title">Key insight</div>
1613 | <p>
1614 | The IMPLEMENTATION_PLAN.md file persists on disk between
1615 | iterations and acts as shared state between otherwise isolated
1616 | loop executions. Each iteration deterministically loads the same
1617 | files (<code>PROMPT.md</code> + <code>AGENTS.md</code> +
1618 | <code>specs/*</code>) and reads the current state from disk.
1619 | </p>
1620 | <p>
1621 | No sophisticated orchestration needed – just a dumb bash loop
1622 | that keeps restarting the agent, and the agent figures out what
1623 | to do next by reading the plan file each time.
1624 | </p>
1625 | </div>
1626 |
1627 | <h3>Inner Loop Control (Task Execution)</h3>
1628 |
1629 | <p>
1630 | A single task execution has no hard technical limit. Control
1631 | relies on:
1632 | </p>
1633 | <ul>
1634 | <li>
1635 | <strong>Scope discipline</strong> – PROMPT.md instructs "one
1636 | task" and "commit when tests pass"
1637 | </li>
1638 | <li>
1639 | <strong>Backpressure</strong> – tests/build failures force the
1640 | agent to fix issues before committing
1641 | </li>
1642 | <li>
1643 | <strong>Natural completion</strong> – agent exits after
1644 | successful commit
1645 | </li>
1646 | </ul>
1647 |
1648 | <p>
1649 | <strong
1650 | >Ralph can go in circles, ignore instructions, or take wrong
1651 | directions</strong
1652 | >
1653 | – this is expected and part of the tuning process. When Ralph
1654 | "tests you" by failing in specific ways, you add guardrails to the
1655 | prompt or adjust backpressure mechanisms. The nondeterminism is
1656 | manageable through observation and iteration.
1657 | </p>
1658 |
1659 | <h3>Enhanced Loop Code Example</h3>
1660 |
1661 | <p>
1662 | Wraps core loop with mode selection (plan/build), max-iterations
1663 | support, and git push after each iteration.
1664 | </p>
1665 |
1666 | <p><em>This enhancement uses two saved prompt files:</em></p>
1667 | <ul>
1668 | <li>
1669 | <code>PROMPT_plan.md</code> – Planning mode (gap analysis,
1670 | generates/updates plan)
1671 | </li>
1672 | <li>
1673 | <code>PROMPT_build.md</code> – Building mode (implements from
1674 | plan)
1675 | </li>
1676 | </ul>
1677 |
1678 | <details>
1679 | <summary>Enhanced `loop.sh` script</summary>
1680 | <div class="details-content">
1681 | <div class="code-block">
1682 | <div class="code-block-header">
1683 | <span>loop.sh</span>
1684 | <button class="copy-btn" onclick="copyCode(this)">
1685 | Copy
1686 | </button>
1687 | </div>
1688 | <pre><code><span class="token-comment">#!/bin/bash</span>
1689 | <span class="token-comment"># Usage: ./loop.sh [plan] [max_iterations]</span>
1690 | <span class="token-comment"># Examples:</span>
1691 | <span class="token-comment"># ./loop.sh # Build mode, unlimited iterations</span>
1692 | <span class="token-comment"># ./loop.sh 20 # Build mode, max 20 iterations</span>
1693 | <span class="token-comment"># ./loop.sh plan # Plan mode, unlimited iterations</span>
1694 | <span class="token-comment"># ./loop.sh plan 5 # Plan mode, max 5 iterations</span>
1695 |
1696 | <span class="token-comment"># Parse arguments</span>
1697 | <span class="token-keyword">if</span> [ <span class="token-string">"$1"</span> = <span class="token-string">"plan"</span> ]; <span class="token-keyword">then</span>
1698 | <span class="token-comment"># Plan mode</span>
1699 | MODE=<span class="token-string">"plan"</span>
1700 | PROMPT_FILE=<span class="token-string">"PROMPT_plan.md"</span>
1701 | MAX_ITERATIONS=<span class="token-variable">${2:-0}</span>
1702 | <span class="token-keyword">elif</span> [[ <span class="token-string">"$1"</span> =~ ^[0-9]+$ ]]; <span class="token-keyword">then</span>
1703 | <span class="token-comment"># Build mode with max iterations</span>
1704 | MODE=<span class="token-string">"build"</span>
1705 | PROMPT_FILE=<span class="token-string">"PROMPT_build.md"</span>
1706 | MAX_ITERATIONS=$1
1707 | <span class="token-keyword">else</span>
1708 | <span class="token-comment"># Build mode, unlimited</span>
1709 | MODE=<span class="token-string">"build"</span>
1710 | PROMPT_FILE=<span class="token-string">"PROMPT_build.md"</span>
1711 | MAX_ITERATIONS=0
1712 | <span class="token-keyword">fi</span>
1713 |
1714 | ITERATION=0
1715 | CURRENT_BRANCH=$(<span class="token-function">git branch --show-current</span>)
1716 |
1717 | <span class="token-function">echo</span> <span class="token-string">"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"</span>
1718 | <span class="token-function">echo</span> <span class="token-string">"Mode: $MODE"</span>
1719 | <span class="token-function">echo</span> <span class="token-string">"Prompt: $PROMPT_FILE"</span>
1720 | <span class="token-function">echo</span> <span class="token-string">"Branch: $CURRENT_BRANCH"</span>
1721 | [ $MAX_ITERATIONS -gt 0 ] && <span class="token-function">echo</span> <span class="token-string">"Max: $MAX_ITERATIONS iterations"</span>
1722 | <span class="token-function">echo</span> <span class="token-string">"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"</span>
1723 |
1724 | <span class="token-comment"># Verify prompt file exists</span>
1725 | <span class="token-keyword">if</span> [ ! -f <span class="token-string">"$PROMPT_FILE"</span> ]; <span class="token-keyword">then</span>
1726 | <span class="token-function">echo</span> <span class="token-string">"Error: $PROMPT_FILE not found"</span>
1727 | exit 1
1728 | <span class="token-keyword">fi</span>
1729 |
1730 | <span class="token-keyword">while</span> true; <span class="token-keyword">do</span>
1731 | <span class="token-keyword">if</span> [ $MAX_ITERATIONS -gt 0 ] && [ $ITERATION -ge $MAX_ITERATIONS ]; <span class="token-keyword">then</span>
1732 | <span class="token-function">echo</span> <span class="token-string">"Reached max iterations: $MAX_ITERATIONS"</span>
1733 | <span class="token-keyword">break</span>
1734 | <span class="token-keyword">fi</span>
1735 |
1736 | <span class="token-comment"># Run Ralph iteration with selected prompt</span>
1737 | <span class="token-comment"># -p: Headless mode (non-interactive, reads from stdin)</span>
1738 | <span class="token-comment"># --dangerously-skip-permissions: Auto-approve all tool calls (YOLO mode)</span>
1739 | <span class="token-comment"># --output-format=stream-json: Structured output for logging/monitoring</span>
1740 | <span class="token-comment"># --model opus: Primary agent uses Opus for complex reasoning (task selection, prioritization)</span>
1741 | <span class="token-comment"># Can use 'sonnet' in build mode for speed if plan is clear and tasks well-defined</span>
1742 | <span class="token-comment"># --verbose: Detailed execution logging</span>
1743 | <span class="token-function">cat</span> <span class="token-string">"$PROMPT_FILE"</span> | claude -p \
1744 | --dangerously-skip-permissions \
1745 | --output-format=stream-json \
1746 | --model opus \
1747 | --verbose
1748 |
1749 | <span class="token-comment"># Push changes after each iteration</span>
1750 | <span class="token-function">git push</span> origin <span class="token-string">"$CURRENT_BRANCH"</span> || {
1751 | <span class="token-function">echo</span> <span class="token-string">"Failed to push. Creating remote branch..."</span>
1752 | <span class="token-function">git push</span> -u origin <span class="token-string">"$CURRENT_BRANCH"</span>
1753 | }
1754 |
1755 | ITERATION=$((ITERATION + 1))
1756 | <span class="token-function">echo</span> -e <span class="token-string">"\n\n======================== LOOP $ITERATION ========================\n"</span>
1757 | <span class="token-keyword">done</span></code></pre>
1758 | </div>
1759 | </div>
1760 | </details>
1761 |
1762 | <h4>Mode Selection</h4>
1763 | <ul>
1764 | <li>
1765 | No keyword → Uses <code>PROMPT_build.md</code> for building
1766 | (implementation)
1767 | </li>
1768 | <li>
1769 | <code>plan</code> keyword → Uses <code>PROMPT_plan.md</code> for
1770 | planning (gap analysis, plan generation)
1771 | </li>
1772 | </ul>
1773 |
1774 | <h4>Max-Iterations</h4>
1775 | <ul>
1776 | <li>
1777 | Limits the <em>outer loop</em> (number of tasks attempted; NOT
1778 | tool calls within a single task)
1779 | </li>
1780 | <li>
1781 | Each iteration = one fresh context window = one task from
1782 | IMPLEMENTATION_PLAN.md = one commit
1783 | </li>
1784 | <li>
1785 | <code>./loop.sh</code> runs unlimited (manual stop with Ctrl+C)
1786 | </li>
1787 | <li>
1788 | <code>./loop.sh 20</code> runs max 20 iterations then stops
1789 | </li>
1790 | </ul>
1791 |
1792 | <h4>Claude CLI Flags Explained</h4>
1793 | <ul>
1794 | <li>
1795 | <code>-p</code> (headless mode): Enables non-interactive
1796 | operation, reads prompt from stdin
1797 | </li>
1798 | <li>
1799 | <code>--dangerously-skip-permissions</code>: Bypasses all
1800 | permission prompts for fully automated runs
1801 | </li>
1802 | <li>
1803 | <code>--output-format=stream-json</code>: Outputs structured
1804 | JSON for logging/monitoring/visualization
1805 | </li>
1806 | <li>
1807 | <code>--model opus</code>: Primary agent uses Opus for task
1808 | selection, prioritization, and coordination (can use
1809 | <code>sonnet</code> for speed if tasks are clear)
1810 | </li>
1811 | <li>
1812 | <code>--verbose</code>: Provides detailed execution logging
1813 | </li>
1814 | </ul>
1815 | </section>
1816 |
1817 | <hr />
1818 |
1819 | <!-- Files -->
1820 | <section id="files">
1821 | <h2><span class="section-icon">📁</span> Files</h2>
1822 |
1823 | <!-- HTML-ONLY: Section lead paragraph -->
1824 | <p class="lead">
1825 | The file structure and templates that make Ralph work.
1826 | </p>
1827 | <!-- /HTML-ONLY -->
1828 |
1829 | <div class="code-block">
1830 | <div class="code-block-header">
1831 | <span>structure</span>
1832 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
1833 | </div>
1834 | <pre><code>project-root/
1835 | ├── loop.sh <span class="token-comment"># Ralph loop script</span>
1836 | ├── PROMPT_build.md <span class="token-comment"># Build mode instructions</span>
1837 | ├── PROMPT_plan.md <span class="token-comment"># Plan mode instructions</span>
1838 | ├── AGENTS.md <span class="token-comment"># Operational guide loaded each iteration</span>
1839 | ├── IMPLEMENTATION_PLAN.md <span class="token-comment"># Prioritized task list (generated/updated by Ralph)</span>
1840 | ├── specs/ <span class="token-comment"># Requirement specs (one per JTBD topic)</span>
1841 | │ ├── [jtbd-topic-a].md
1842 | │ └── [jtbd-topic-b].md
1843 | ├── src/ <span class="token-comment"># Application source code</span>
1844 | └── src/lib/ <span class="token-comment"># Shared utilities & components</span></code></pre>
1845 | </div>
1846 |
1847 | <!-- HTML-ONLY: Files table with Modified By column -->
1848 | <div class="table-wrapper">
1849 | <table>
1850 | <thead>
1851 | <tr>
1852 | <th>File</th>
1853 | <th>Purpose</th>
1854 | <th>Modified By</th>
1855 | </tr>
1856 | </thead>
1857 | <tbody>
1858 | <tr>
1859 | <td><code>loop.sh</code></td>
1860 | <td>Outer loop orchestration</td>
1861 | <td>You (setup)</td>
1862 | </tr>
1863 | <tr>
1864 | <td><code>PROMPT_*.md</code></td>
1865 | <td>Instructions per mode</td>
1866 | <td>You (tuning)</td>
1867 | </tr>
1868 | <tr>
1869 | <td><code>AGENTS.md</code></td>
1870 | <td>Operational guide</td>
1871 | <td>Ralph + You</td>
1872 | </tr>
1873 | <tr>
1874 | <td><code>IMPLEMENTATION_PLAN.md</code></td>
1875 | <td>Prioritized task list</td>
1876 | <td>Ralph</td>
1877 | </tr>
1878 | <tr>
1879 | <td><code>specs/*</code></td>
1880 | <td>Requirements per topic</td>
1881 | <td>You + Ralph</td>
1882 | </tr>
1883 | </tbody>
1884 | </table>
1885 | </div>
1886 | <!-- /HTML-ONLY -->
1887 |
1888 | <h3><code>loop.sh</code></h3>
1889 | <p>The outer loop script that orchestrates Ralph iterations.</p>
1890 | <p>
1891 | See <a href="#loop-mechanics">Loop Mechanics</a> section for
1892 | detailed implementation examples and configuration options.
1893 | </p>
1894 | <p><em>Setup:</em> Make the script executable before first use:</p>
1895 | <div class="code-block">
1896 | <div class="code-block-header">
1897 | <span>bash</span>
1898 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
1899 | </div>
1900 | <pre><code>chmod +x loop.sh</code></pre>
1901 | </div>
1902 | <p>
1903 | <em>Core function:</em> Continuously feeds prompt file to claude,
1904 | manages iteration limits, and pushes changes after each task
1905 | completion.
1906 | </p>
1907 |
1908 | <h3>PROMPTS</h3>
1909 |
1910 | <p style="text-wrap: balance">
1911 | The instruction set for each loop iteration. Swap between PLANNING
1912 | and BUILDING versions as needed.
1913 | </p>
1914 |
1915 | <h4>Prompt Structure</h4>
1916 |
1917 | <div class="table-wrapper">
1918 | <table>
1919 | <thead>
1920 | <tr>
1921 | <th>Section</th>
1922 | <th>Purpose</th>
1923 | </tr>
1924 | </thead>
1925 | <tbody>
1926 | <tr>
1927 | <td>Phase 0 (0a, 0b, 0c)</td>
1928 | <td>Orient: study specs, source location, current plan</td>
1929 | </tr>
1930 | <tr>
1931 | <td>Phase 1-4</td>
1932 | <td>Main instructions: task, validation, commit</td>
1933 | </tr>
1934 | <tr>
1935 | <td>999... numbering</td>
1936 | <td>
1937 | Guardrails/invariants (higher number = more critical)
1938 | </td>
1939 | </tr>
1940 | </tbody>
1941 | </table>
1942 | </div>
1943 |
1944 | <h4>Key Language Patterns (Geoff's specific phrasing)</h4>
1945 | <ul>
1946 | <li>"study" (not "read" or "look at")</li>
1947 | <li>
1948 | "don't assume not implemented" (critical – the Achilles' heel)
1949 | </li>
1950 | <li>"using parallel subagents" / "up to N subagents"</li>
1951 | <li>"only 1 subagent for build/tests" (backpressure control)</li>
1952 | <li>"Think extra hard" (now "Ultrathink")</li>
1953 | <li>"capture the why"</li>
1954 | <li>"keep it up to date"</li>
1955 | <li>
1956 | "if functionality is missing then it's your job to add it"
1957 | </li>
1958 | <li>"resolve them or document them"</li>
1959 | </ul>
1960 |
1961 | <h4><code>PROMPT_*.md</code> Templates</h4>
1962 |
1963 | <p><em>Notes:</em></p>
1964 | <ul>
1965 | <li>Update [project-specific goal] placeholder below.</li>
1966 | <li>Current subagents names presume using Claude.</li>
1967 | </ul>
1968 |
1969 | <details>
1970 | <summary>PROMPT_plan.md Template</summary>
1971 | <div class="details-content">
1972 | <div class="code-block">
1973 | <div class="code-block-header">
1974 | <span>PROMPT_plan.md</span>
1975 | <button class="copy-btn" onclick="copyCode(this)">
1976 | Copy
1977 | </button>
1978 | </div>
1979 | <pre><code>0a. Study `specs/*` with up to 250 parallel Sonnet subagents to learn the application specifications.
1980 | 0b. Study @IMPLEMENTATION_PLAN.md (if present) to understand the plan so far.
1981 | 0c. Study `src/lib/*` with up to 250 parallel Sonnet subagents to understand shared utilities & components.
1982 | 0d. For reference, the application source code is in `src/*`.
1983 |
1984 | 1. Study @IMPLEMENTATION_PLAN.md (if present; it may be incorrect) and use up to 500 Sonnet subagents to study existing source code in `src/*` and compare it against `specs/*`. Use an Opus subagent to analyze findings, prioritize tasks, and create/update @IMPLEMENTATION_PLAN.md as a bullet point list sorted in priority of items yet to be implemented. Ultrathink. Consider searching for TODO, minimal implementations, placeholders, skipped/flaky tests, and inconsistent patterns. Study @IMPLEMENTATION_PLAN.md to determine starting point for research and keep it up to date with items considered complete/incomplete using subagents.
1985 |
1986 | IMPORTANT: Plan only. Do NOT implement anything. Do NOT assume functionality is missing; confirm with code search first. Treat `src/lib` as the project's standard library for shared utilities and components. Prefer consolidated, idiomatic implementations there over ad-hoc copies.
1987 |
1988 | ULTIMATE GOAL: We want to achieve [project-specific goal]. Consider missing elements and plan accordingly. If an element is missing, search first to confirm it doesn't exist, then if needed author the specification at specs/FILENAME.md. If you create a new element then document the plan to implement it in @IMPLEMENTATION_PLAN.md using a subagent.</code></pre>
1989 | </div>
1990 | </div>
1991 | </details>
1992 |
1993 | <details>
1994 | <summary>PROMPT_build.md Template</summary>
1995 | <div class="details-content">
1996 | <div class="code-block">
1997 | <div class="code-block-header">
1998 | <span>PROMPT_build.md</span>
1999 | <button class="copy-btn" onclick="copyCode(this)">
2000 | Copy
2001 | </button>
2002 | </div>
2003 | <pre><code>0a. Study `specs/*` with up to 500 parallel Sonnet subagents to learn the application specifications.
2004 | 0b. Study @IMPLEMENTATION_PLAN.md.
2005 | 0c. For reference, the application source code is in `src/*`.
2006 |
2007 | 1. Your task is to implement functionality per the specifications using parallel subagents. Follow @IMPLEMENTATION_PLAN.md and choose the most important item to address. Before making changes, search the codebase (don't assume not implemented) using Sonnet subagents. You may use up to 500 parallel Sonnet subagents for searches/reads and only 1 Sonnet subagent for build/tests. Use Opus subagents when complex reasoning is needed (debugging, architectural decisions).
2008 | 2. After implementing functionality or resolving problems, run the tests for that unit of code that was improved. If functionality is missing then it's your job to add it as per the application specifications. Ultrathink.
2009 | 3. When you discover issues, immediately update @IMPLEMENTATION_PLAN.md with your findings using a subagent. When resolved, update and remove the item.
2010 | 4. When the tests pass, update @IMPLEMENTATION_PLAN.md, then `git add -A` then `git commit` with a message describing the changes. After the commit, `git push`.
2011 |
2012 | 99999. Important: When authoring documentation, capture the why – tests and implementation importance.
2013 | 999999. Important: Single sources of truth, no migrations/adapters. If tests unrelated to your work fail, resolve them as part of the increment.
2014 | 9999999. As soon as there are no build or test errors create a git tag. If there are no git tags start at 0.0.0 and increment patch by 1 for example 0.0.1 if 0.0.0 does not exist.
2015 | 99999999. You may add extra logging if required to debug issues.
2016 | 999999999. Keep @IMPLEMENTATION_PLAN.md current with learnings using a subagent – future work depends on this to avoid duplicating efforts. Update especially after finishing your turn.
2017 | 9999999999. When you learn something new about how to run the application, update @AGENTS.md using a subagent but keep it brief. For example if you run commands multiple times before learning the correct command then that file should be updated.
2018 | 99999999999. For any bugs you notice, resolve them or document them in @IMPLEMENTATION_PLAN.md using a subagent even if it is unrelated to the current piece of work.
2019 | 999999999999. Implement functionality completely. Placeholders and stubs waste efforts and time redoing the same work.
2020 | 9999999999999. When @IMPLEMENTATION_PLAN.md becomes large periodically clean out the items that are completed from the file using a subagent.
2021 | 99999999999999. If you find inconsistencies in the specs/* then use an Opus 4.5 subagent with 'ultrathink' requested to update the specs.
2022 | 999999999999999. IMPORTANT: Keep @AGENTS.md operational only – status updates and progress notes belong in `IMPLEMENTATION_PLAN.md`. A bloated AGENTS.md pollutes every future loop's context.</code></pre>
2023 | </div>
2024 | </div>
2025 | </details>
2026 |
2027 | <h3><code>AGENTS.md</code></h3>
2028 |
2029 | <p>
2030 | Single, canonical "heart of the loop" – a concise, operational
2031 | "how to run/build" guide.
2032 | </p>
2033 |
2034 | <ul>
2035 | <li><strong>NOT</strong> a changelog or progress diary</li>
2036 | <li>Describes how to build/run the project</li>
2037 | <li>Captures operational learnings that improve the loop</li>
2038 | <li>Keep brief (~60 lines)</li>
2039 | </ul>
2040 |
2041 | <p>
2042 | Status, progress, and planning belong in
2043 | <code>IMPLEMENTATION_PLAN.md</code>, not here.
2044 | </p>
2045 |
2046 | <h5>Loopback / Immediate Self-Evaluation</h5>
2047 | <p>
2048 | AGENTS.md should contain the project-specific commands that enable
2049 | loopback – the ability for Ralph to immediately evaluate his work
2050 | within the same loop. This includes:
2051 | </p>
2052 | <ul>
2053 | <li>Build commands</li>
2054 | <li>Test commands (targeted and full suite)</li>
2055 | <li>Typecheck/lint commands</li>
2056 | <li>Any other validation tools</li>
2057 | </ul>
2058 | <p>
2059 | The BUILDING prompt says "run tests" generically; AGENTS.md
2060 | specifies the actual commands. This is how backpressure gets wired
2061 | in per-project.
2062 | </p>
2063 |
2064 | <details>
2065 | <summary>AGENTS.md Example Structure</summary>
2066 | <div class="details-content">
2067 | <div class="code-block">
2068 | <div class="code-block-header">
2069 | <span>AGENTS.md</span>
2070 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2071 | </div>
2072 | <pre><code>## Build & Run
2073 |
2074 | Succinct rules for how to BUILD the project:
2075 |
2076 | ## Validation
2077 |
2078 | Run these after implementing to get immediate feedback:
2079 |
2080 | - Tests: `[test command]`
2081 | - Typecheck: `[typecheck command]`
2082 | - Lint: `[lint command]`
2083 |
2084 | ## Operational Notes
2085 |
2086 | Succinct learnings about how to RUN the project:
2087 |
2088 | ...
2089 |
2090 | ### Codebase Patterns
2091 |
2092 | ...</code></pre>
2093 | </div>
2094 | </div>
2095 | </details>
2096 |
2097 | <h3><code>IMPLEMENTATION_PLAN.md</code></h3>
2098 |
2099 | <p>
2100 | Prioritized bullet-point list of tasks derived from gap analysis
2101 | (specs vs code) – generated by Ralph.
2102 | </p>
2103 |
2104 | <ul>
2105 | <li><strong>Created</strong> via PLANNING mode</li>
2106 | <li>
2107 | <strong>Updated</strong> during BUILDING mode (mark complete,
2108 | add discoveries, note bugs)
2109 | </li>
2110 | <li>
2111 | <strong>Can be regenerated</strong> – Geoff: "I have deleted the
2112 | TODO list multiple times" → switch to PLANNING mode
2113 | </li>
2114 | <li>
2115 | <strong>Self-correcting</strong> – BUILDING mode can even create
2116 | new specs if missing
2117 | </li>
2118 | </ul>
2119 |
2120 | <p>
2121 | The circularity is intentional: eventual consistency through
2122 | iteration.
2123 | </p>
2124 |
2125 | <p>
2126 | <em>No pre-specified template</em> – let Ralph/LLM dictate and
2127 | manage format that works best for it.
2128 | </p>
2129 |
2130 | <h3><code>specs/*</code></h3>
2131 |
2132 | <p>
2133 | One markdown file per topic of concern. These are the source of
2134 | truth for what should be built.
2135 | </p>
2136 |
2137 | <ul>
2138 | <li>
2139 | Created during Requirements phase (human + LLM conversation)
2140 | </li>
2141 | <li>Consumed by both PLANNING and BUILDING modes</li>
2142 | <li>
2143 | Can be updated if inconsistencies discovered (rare, use
2144 | subagent)
2145 | </li>
2146 | </ul>
2147 |
2148 | <p>
2149 | <em>No pre-specified template</em> – let Ralph/LLM dictate and
2150 | manage format that works best for it.
2151 | </p>
2152 |
2153 | <h3><code>src/</code> and <code>src/lib/</code></h3>
2154 | <p>Application source code and shared utilities/components.</p>
2155 | <p>
2156 | Referenced in <code>PROMPT.md</code> templates for orientation
2157 | steps.
2158 | </p>
2159 | </section>
2160 |
2161 | <hr />
2162 |
2163 | <!-- Enhancements -->
2164 | <section id="enhancements" class="enhancements-section">
2165 | <h2>Enhancements?</h2>
2166 |
2167 | <!-- HTML-ONLY: Section lead paragraph -->
2168 | <p class="lead">
2169 | Clayton: I'm still determining the value/viability of these, but
2170 | the opportunities sound promising:
2171 | </p>
2172 | <!-- /HTML-ONLY -->
2173 |
2174 | <details>
2175 | <summary>
2176 | <span class="summary-title"
2177 | >Use Claude's AskUserQuestionTool for Planning</span
2178 | >
2179 | <span class="summary-desc"
2180 | >Use Claude's built-in interview tool to systematically
2181 | clarify JTBD, edge cases, and acceptance criteria for
2182 | specs.</span
2183 | >
2184 | </summary>
2185 | <div class="details-content">
2186 | <p>
2187 | During Phase 1 (Define Requirements), use Claude's built-in
2188 | <code>AskUserQuestionTool</code> to systematically explore
2189 | JTBD, topics of concern, edge cases, and acceptance criteria
2190 | through structured interview before writing specs.
2191 | </p>
2192 |
2193 | <p>
2194 | <strong>When to use:</strong> Minimal/vague initial
2195 | requirements, need to clarify constraints, or multiple valid
2196 | approaches exist.
2197 | </p>
2198 |
2199 | <p>
2200 | <strong>Invoke:</strong> "Interview me using AskUserQuestion
2201 | to understand [JTBD/topic/acceptance criteria/...]"
2202 | </p>
2203 |
2204 | <p>
2205 | Claude will ask targeted questions to clarify requirements and
2206 | ensure alignment before producing
2207 | <code>specs/*.md</code> files.
2208 | </p>
2209 |
2210 | <p><strong>Flow:</strong></p>
2211 | <ol>
2212 | <li>Start with known information →</li>
2213 | <li>Claude interviews via AskUserQuestion →</li>
2214 | <li>Iterate until clear →</li>
2215 | <li>Claude writes specs with acceptance criteria →</li>
2216 | <li>Proceed to planning/building</li>
2217 | </ol>
2218 |
2219 | <p>
2220 | No code or prompt changes needed – this simply enhances Phase
2221 | 1 using existing Claude Code capabilities.
2222 | </p>
2223 |
2224 | <p>
2225 | <em>Inspiration</em> -
2226 | <a href="https://x.com/trq212/status/2005315275026260309"
2227 | >Thariq's X post</a
2228 | >
2229 | </p>
2230 | </div>
2231 | </details>
2232 |
2233 | <details>
2234 | <summary>
2235 | <span class="summary-title"
2236 | >Acceptance-Driven Backpressure</span
2237 | >
2238 | <span class="summary-desc"
2239 | >Derive test requirements during planning from acceptance
2240 | criteria. Prevents "cheating" - can't claim done without
2241 | appropriate tests passing.</span
2242 | >
2243 | </summary>
2244 | <div class="details-content">
2245 | <p>
2246 | Geoff's Ralph <em>implicitly</em> connects specs →
2247 | implementation → tests through emergent iteration. This
2248 | enhancement would make that connection <em>explicit</em> by
2249 | deriving test requirements during planning, creating a direct
2250 | line from "what success looks like" to "what verifies it."
2251 | </p>
2252 |
2253 | <p>
2254 | This enhancement connects acceptance criteria (in specs)
2255 | directly to test requirements (in implementation plan),
2256 | improving backpressure quality by:
2257 | </p>
2258 | <ul>
2259 | <li>
2260 | <strong>Preventing "no cheating"</strong> – Can't claim done
2261 | without required tests derived from acceptance criteria
2262 | </li>
2263 | <li>
2264 | <strong>Enabling TDD workflow</strong> – Test requirements
2265 | known before implementation starts
2266 | </li>
2267 | <li>
2268 | <strong>Improving convergence</strong> – Clear completion
2269 | signal (required tests pass) vs ambiguous ("seems done?")
2270 | </li>
2271 | <li>
2272 | <strong>Maintaining determinism</strong> – Test requirements
2273 | in plan (known state) not emergent (probabilistic)
2274 | </li>
2275 | </ul>
2276 |
2277 | <h5>Compatibility with Core Philosophy</h5>
2278 | <div class="table-wrapper">
2279 | <table>
2280 | <thead>
2281 | <tr>
2282 | <th>Principle</th>
2283 | <th>Maintained?</th>
2284 | <th>How</th>
2285 | </tr>
2286 | </thead>
2287 | <tbody>
2288 | <tr>
2289 | <td>Monolithic operation</td>
2290 | <td>✅ Yes</td>
2291 | <td>One agent, one task, one loop at a time</td>
2292 | </tr>
2293 | <tr>
2294 | <td>Backpressure critical</td>
2295 | <td>✅ Yes</td>
2296 | <td>
2297 | Tests are the mechanism, just derived explicitly now
2298 | </td>
2299 | </tr>
2300 | <tr>
2301 | <td>Context efficiency</td>
2302 | <td>✅ Yes</td>
2303 | <td>
2304 | Planning decides tests once vs building rediscovering
2305 | </td>
2306 | </tr>
2307 | <tr>
2308 | <td>Deterministic setup</td>
2309 | <td>✅ Yes</td>
2310 | <td>
2311 | Test requirements in plan (known state) not emergent
2312 | </td>
2313 | </tr>
2314 | <tr>
2315 | <td>Let Ralph Ralph</td>
2316 | <td>✅ Yes</td>
2317 | <td>
2318 | Ralph still prioritizes and chooses implementation
2319 | approach
2320 | </td>
2321 | </tr>
2322 | <tr>
2323 | <td>Plan is disposable</td>
2324 | <td>✅ Yes</td>
2325 | <td>Wrong test requirements? Regenerate plan</td>
2326 | </tr>
2327 | <tr>
2328 | <td>"Capture the why"</td>
2329 | <td>✅ Yes</td>
2330 | <td>
2331 | Test intent documented in plan before implementation
2332 | </td>
2333 | </tr>
2334 | <tr>
2335 | <td>No cheating</td>
2336 | <td>✅ Yes</td>
2337 | <td>
2338 | Required tests prevent placeholder implementations
2339 | </td>
2340 | </tr>
2341 | </tbody>
2342 | </table>
2343 | </div>
2344 |
2345 | <h5>The Prescriptiveness Balance</h5>
2346 |
2347 | <p><em>The critical distinction:</em></p>
2348 | <p>
2349 | Acceptance criteria (in specs) = Behavioral outcomes,
2350 | observable results
2351 | </p>
2352 | <ul>
2353 | <li>
2354 | ✓ "Extracts 5-10 dominant colors from any uploaded image"
2355 | </li>
2356 | <li>✓ "Processes images <5MB in <100ms"</li>
2357 | <li>
2358 | ✓ "Handles edge cases: grayscale, single-color, transparent
2359 | backgrounds"
2360 | </li>
2361 | </ul>
2362 |
2363 | <p>
2364 | Test requirements (in plan) = Verification points derived from
2365 | acceptance criteria
2366 | </p>
2367 | <ul>
2368 | <li>
2369 | ✓ "Required tests: Extract 5-10 colors, Performance
2370 | <100ms"
2371 | </li>
2372 | </ul>
2373 |
2374 | <p>
2375 | Implementation approach (up to Ralph) = Technical decisions
2376 | </p>
2377 | <ul>
2378 | <li>✗ "Use K-means clustering with 3 iterations"</li>
2379 | </ul>
2380 |
2381 | <p>
2382 | <em>
2383 | <strong>The key:</strong> Specify WHAT to verify (outcomes),
2384 | not HOW to implement (approach).</em
2385 | >
2386 | </p>
2387 |
2388 | <p>
2389 | This maintains "Let Ralph Ralph" principle - Ralph decides
2390 | implementation details while having clear success signals.
2391 | </p>
2392 |
2393 | <h5>Architecture: Three-Phase Connection</h5>
2394 | <div class="code-block">
2395 | <div class="code-block-header">
2396 | <span>diagram</span>
2397 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2398 | </div>
2399 | <pre><code>Phase 1: Requirements Definition
2400 | specs/*.md + Acceptance Criteria
2401 | ↓
2402 | Phase 2: Planning (derives test requirements)
2403 | IMPLEMENTATION_PLAN.md + Required Tests
2404 | ↓
2405 | Phase 3: Building (implements with tests)
2406 | Implementation + Tests → Backpressure</code></pre>
2407 | </div>
2408 |
2409 | <h5>Phase 1: Requirements Definition</h5>
2410 | <p>During the human + LLM conversation that produces specs:</p>
2411 | <ul>
2412 | <li>Discuss JTBD and break into topics of concern</li>
2413 | <li>Use subagents to load external context as needed</li>
2414 | <li>
2415 | <em>Discuss and define acceptance criteria</em> – what
2416 | observable, verifiable outcomes indicate success
2417 | </li>
2418 | <li>
2419 | Keep criteria behavioral (outcomes), not implementation (how
2420 | to build it)
2421 | </li>
2422 | <li>
2423 | LLM writes specs including acceptance criteria however makes
2424 | most sense for the spec
2425 | </li>
2426 | <li>
2427 | Acceptance criteria become the foundation for deriving test
2428 | requirements in planning phase
2429 | </li>
2430 | </ul>
2431 |
2432 | <h5>Phase 2: Planning Mode Enhancement</h5>
2433 | <p>
2434 | Modify <code>PROMPT_plan.md</code> instruction 1 to include
2435 | test derivation. Add after the first sentence:
2436 | </p>
2437 | <div class="code-block">
2438 | <div class="code-block-header">
2439 | <span>instruction</span>
2440 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2441 | </div>
2442 | <pre><code>For each task in the plan, derive required tests from acceptance criteria in specs - what specific outcomes need verification (behavior, performance, edge cases). Tests verify WHAT works, not HOW it's implemented. Include as part of task definition.</code></pre>
2443 | </div>
2444 |
2445 | <h5>Phase 3: Building Mode Enhancement</h5>
2446 | <p>Modify <code>PROMPT_build.md</code> instructions:</p>
2447 | <p>
2448 | <em>Instruction 1:</em> Add after "choose the most important
2449 | item to address":
2450 | </p>
2451 | <div class="code-block">
2452 | <div class="code-block-header">
2453 | <span>instruction</span>
2454 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2455 | </div>
2456 | <pre><code>Tasks include required tests - implement tests as part of task scope.</code></pre>
2457 | </div>
2458 | <p>
2459 | <em>Instruction 2:</em> Replace "run the tests for that unit
2460 | of code" with:
2461 | </p>
2462 | <div class="code-block">
2463 | <div class="code-block-header">
2464 | <span>instruction</span>
2465 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2466 | </div>
2467 | <pre><code>run all required tests specified in the task definition. All required tests must exist and pass before the task is considered complete.</code></pre>
2468 | </div>
2469 | <p><em>Prepend new guardrail</em> (in the 9s sequence):</p>
2470 | <div class="code-block">
2471 | <div class="code-block-header">
2472 | <span>instruction</span>
2473 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2474 | </div>
2475 | <pre><code>999. Required tests derived from acceptance criteria must exist and pass before committing. Tests are part of implementation scope, not optional. Test-driven development approach: tests can be written first or alongside implementation.</code></pre>
2476 | </div>
2477 | </div>
2478 | </details>
2479 |
2480 | <details>
2481 | <summary>
2482 | <span class="summary-title"
2483 | >Non-Deterministic Backpressure</span
2484 | >
2485 | <span class="summary-desc"
2486 | >Using LLM-as-judge for tests against subjective tasks (tone,
2487 | aesthetics, UX). Binary pass/fail reviews that iterate until
2488 | pass.</span
2489 | >
2490 | </summary>
2491 | <div class="details-content">
2492 | <p>Some acceptance criteria resist programmatic validation:</p>
2493 | <ul>
2494 | <li>
2495 | <strong>Creative quality</strong> – Writing tone, narrative
2496 | flow, engagement
2497 | </li>
2498 | <li>
2499 | <strong>Aesthetic judgments</strong> – Visual harmony,
2500 | design balance, brand consistency
2501 | </li>
2502 | <li>
2503 | <strong>UX quality</strong> – Intuitive navigation, clear
2504 | information hierarchy
2505 | </li>
2506 | <li>
2507 | <strong>Content appropriateness</strong> – Context-aware
2508 | messaging, audience fit
2509 | </li>
2510 | </ul>
2511 |
2512 | <p>
2513 | <strong>Solution:</strong> Add LLM-as-Judge tests as
2514 | backpressure with binary pass/fail.
2515 | </p>
2516 |
2517 | <p>
2518 | LLM reviews are non-deterministic (same artifact may receive
2519 | different judgments across runs). This aligns with Ralph
2520 | philosophy: "deterministically bad in an undeterministic
2521 | world." The loop provides eventual consistency through
2522 | iteration–reviews run until pass, accepting natural variance.
2523 | </p>
2524 |
2525 | <h5>What Needs to Be Created (First Step)</h5>
2526 |
2527 | <p>Create two files in <code>src/lib/</code>:</p>
2528 | <div class="code-block">
2529 | <div class="code-block-header">
2530 | <span>structure</span>
2531 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2532 | </div>
2533 | <pre><code>src/lib/
2534 | llm-review.ts # Core fixture - single function, clean API
2535 | llm-review.test.ts # Reference examples showing the pattern (Ralph learns from these)</code></pre>
2536 | </div>
2537 |
2538 | <h5>
2539 | <code>llm-review.ts</code> - Binary pass/fail API Ralph
2540 | discovers:
2541 | </h5>
2542 |
2543 | <div class="code-block">
2544 | <div class="code-block-header">
2545 | <span>llm-review.ts</span>
2546 | </div>
2547 | <pre><code>interface ReviewResult {
2548 | pass: boolean;
2549 | feedback?: string; // Only present when pass=false
2550 | }
2551 |
2552 | function createReview(config: {
2553 | criteria: string; // What to evaluate
2554 | artifact: string; // Text content OR screenshot path
2555 | intelligence?: "fast" | "smart";
2556 | }): Promise<ReviewResult>;</code></pre>
2557 | </div>
2558 |
2559 | <p>
2560 | <strong>Multimodal support:</strong> Both intelligence levels
2561 | use multimodal models (text + vision). Artifact type detection
2562 | is automatic:
2563 | </p>
2564 | <ul>
2565 | <li>
2566 | Text evaluation:
2567 | <code>artifact: "Your content here"</code> → Routes as text
2568 | input
2569 | </li>
2570 | <li>
2571 | Vision evaluation:
2572 | <code>artifact: "./tmp/screenshot.png"</code> → Routes as
2573 | vision input (detects .png, .jpg, .jpeg extensions)
2574 | </li>
2575 | </ul>
2576 |
2577 | <p>
2578 | <strong>Intelligence levels</strong> (quality of judgment, not
2579 | capability type):
2580 | </p>
2581 | <ul>
2582 | <li>
2583 | <code>fast</code> (default): Quick, cost-effective models
2584 | for straightforward evaluations (e.g., Gemini 3.0 Flash)
2585 | </li>
2586 | <li>
2587 | <code>smart</code>: Higher-quality models for nuanced
2588 | aesthetic/creative judgment (e.g., GPT 5.1)
2589 | </li>
2590 | </ul>
2591 | <p>
2592 | The fixture implementation selects appropriate models.
2593 | (Examples are current options, not requirements.)
2594 | </p>
2595 |
2596 | <h5>
2597 | <code>llm-review.test.ts</code> - Shows Ralph how to use it
2598 | (text and vision examples):
2599 | </h5>
2600 | <div class="code-block">
2601 | <div class="code-block-header">
2602 | <span>llm-review.test.ts examples</span>
2603 | </div>
2604 | <pre><code>import { createReview } from "@/lib/llm-review";
2605 |
2606 | // Example 1: Text evaluation
2607 | test("welcome message tone", async () => {
2608 | const message = generateWelcomeMessage();
2609 | const result = await createReview({
2610 | criteria: "Message uses warm, conversational tone appropriate for design professionals while clearly conveying value proposition",
2611 | artifact: message, // Text content
2612 | });
2613 | expect(result.pass).toBe(true);
2614 | });
2615 |
2616 | // Example 2: Vision evaluation (screenshot path)
2617 | test("dashboard visual hierarchy", async () => {
2618 | await page.screenshot({ path: "./tmp/dashboard.png" });
2619 | const result = await createReview({
2620 | criteria: "Layout demonstrates clear visual hierarchy with obvious primary action",
2621 | artifact: "./tmp/dashboard.png", // Screenshot path
2622 | });
2623 | expect(result.pass).toBe(true);
2624 | });
2625 |
2626 | // Example 3: Smart intelligence for complex judgment
2627 | test("brand visual consistency", async () => {
2628 | await page.screenshot({ path: "./tmp/homepage.png" });
2629 | const result = await createReview({
2630 | criteria: "Visual design maintains professional brand identity suitable for financial services while avoiding corporate sterility",
2631 | artifact: "./tmp/homepage.png",
2632 | intelligence: "smart", // Complex aesthetic judgment
2633 | });
2634 | expect(result.pass).toBe(true);
2635 | });</code></pre>
2636 | </div>
2637 |
2638 | <p>
2639 | <em>Ralph learns from these examples:</em> Both text and
2640 | screenshots work as artifacts. Choose based on what needs
2641 | evaluation. The fixture handles the rest internally.
2642 | </p>
2643 |
2644 | <p>
2645 | <em>Future extensibility:</em> Current design uses single
2646 | <code>artifact: string</code> for simplicity. Can expand to
2647 | <code>artifact: string | string[]</code> if clear patterns
2648 | emerge requiring multiple artifacts (before/after comparisons,
2649 | consistency across items, multi-perspective evaluation).
2650 | Composite screenshots or concatenated text could handle most
2651 | multi-item needs.
2652 | </p>
2653 |
2654 | <h5>Integration with Ralph Workflow</h5>
2655 | <p>
2656 | <em>Planning Phase</em> - Update <code>PROMPT_plan.md</code>:
2657 | </p>
2658 | <p>
2659 | After "...Study @IMPLEMENTATION_PLAN.md to determine starting
2660 | point for research and keep it up to date with items
2661 | considered complete/incomplete using subagents." insert:
2662 | </p>
2663 | <div class="code-block">
2664 | <div class="code-block-header">
2665 | <span>instruction</span>
2666 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2667 | </div>
2668 | <pre><code>When deriving test requirements from acceptance criteria, identify whether verification requires programmatic validation (measurable, inspectable) or human-like judgment (perceptual quality, tone, aesthetics). Both types are equally valid backpressure mechanisms. For subjective criteria that resist programmatic validation, explore src/lib for non-deterministic evaluation patterns.</code></pre>
2669 | </div>
2670 | <p>
2671 | <em>Building Phase</em> - Update <code>PROMPT_build.md</code>:
2672 | </p>
2673 | <p>Prepend new guardrail (in the 9s sequence):</p>
2674 | <div class="code-block">
2675 | <div class="code-block-header">
2676 | <span>instruction</span>
2677 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2678 | </div>
2679 | <pre><code>9999. Create tests to verify implementation meets acceptance criteria and include both conventional tests (behavior, performance, correctness) and perceptual quality tests (for subjective criteria, see src/lib patterns).</code></pre>
2680 | </div>
2681 | <p>
2682 | <em>Discovery, not documentation:</em> Ralph learns LLM review
2683 | patterns from <code>llm-review.test.ts</code> examples during
2684 | <code>src/lib</code> exploration (Phase 0c). No AGENTS.md
2685 | updates needed - the code examples are the documentation.
2686 | </p>
2687 |
2688 | <h5>Compatibility with Core Philosophy</h5>
2689 | <div class="table-wrapper">
2690 | <table>
2691 | <thead>
2692 | <tr>
2693 | <th>Principle</th>
2694 | <th>Maintained?</th>
2695 | <th>How</th>
2696 | </tr>
2697 | </thead>
2698 | <tbody>
2699 | <tr>
2700 | <td>Backpressure critical</td>
2701 | <td>✅ Yes</td>
2702 | <td>
2703 | Extends backpressure to non-programmatic acceptance
2704 | </td>
2705 | </tr>
2706 | <tr>
2707 | <td>Deterministic setup</td>
2708 | <td>⚠️ Partial</td>
2709 | <td>
2710 | Criteria in plan (deterministic), evaluation
2711 | non-deterministic but converges through iteration
2712 | </td>
2713 | </tr>
2714 | <tr>
2715 | <td>Context efficiency</td>
2716 | <td>✅ Yes</td>
2717 | <td>
2718 | Fixture reused via src/lib, small test definitions
2719 | </td>
2720 | </tr>
2721 | <tr>
2722 | <td>Let Ralph Ralph</td>
2723 | <td>✅ Yes</td>
2724 | <td>
2725 | Ralph discovers pattern, chooses when to use, writes
2726 | criteria
2727 | </td>
2728 | </tr>
2729 | <tr>
2730 | <td>Plan is disposable</td>
2731 | <td>✅ Yes</td>
2732 | <td>
2733 | Review requirements part of plan, regenerate if wrong
2734 | </td>
2735 | </tr>
2736 | <tr>
2737 | <td>Simplicity wins</td>
2738 | <td>✅ Yes</td>
2739 | <td>
2740 | Single function, binary result, no scoring complexity
2741 | </td>
2742 | </tr>
2743 | <tr>
2744 | <td>Add signs for Ralph</td>
2745 | <td>✅ Yes</td>
2746 | <td>
2747 | Light prompt additions, learning from code exploration
2748 | </td>
2749 | </tr>
2750 | </tbody>
2751 | </table>
2752 | </div>
2753 | </div>
2754 | </details>
2755 |
2756 | <details>
2757 | <summary>
2758 | <span class="summary-title">Ralph-Friendly Work Branches</span>
2759 | <span class="summary-desc"
2760 | >Asking Ralph to "filter to feature X" at runtime is
2761 | unreliable. Instead, create scoped plan per branch
2762 | upfront.</span
2763 | >
2764 | </summary>
2765 | <div class="details-content">
2766 | <p>
2767 | <strong>The Critical Principle:</strong> Geoff's Ralph works
2768 | from a single, disposable plan where Ralph picks "most
2769 | important." To use branches with Ralph while maintaining this
2770 | pattern, you must scope at plan creation, not at task
2771 | selection.
2772 | </p>
2773 |
2774 | <ul>
2775 | <li>
2776 | ❌ <em> Wrong Approach:</em> Create full plan, then
2777 | ask Ralph to "filter" tasks at runtime → unreliable
2778 | (70-80%), violates determinism
2779 | </li>
2780 | <li>
2781 | ✓ <em>Right Approach:</em> Create a scoped plan
2782 | upfront for each work branch → deterministic, simple,
2783 | maintains "plan is disposable"
2784 | </li>
2785 | </ul>
2786 |
2787 | <p>
2788 | <strong>Solution:</strong> Add a <code>plan-work</code> mode
2789 | to create a work-scoped <code>IMPLEMENTATION_PLAN.md</code> on
2790 | the current branch. User creates work branch, then runs
2791 | <code>plan-work</code> with a natural language description of
2792 | the work focus. The LLM uses this description to scope the
2793 | plan. Post planning, Ralph builds from this already-scoped
2794 | plan with zero semantic filtering – just picks "most
2795 | important" as always.
2796 | </p>
2797 |
2798 | <p>
2799 | "Work" is intentionally a broad term – it can describe
2800 | features, topics of concern, refactoring efforts,
2801 | infrastructure changes, bug fixes, or any coherent body of
2802 | related changes. The work description you pass to
2803 | <code>plan-work</code> is natural language for the LLM – it
2804 | can be prose, not constrained by git branch naming rules.
2805 | </p>
2806 |
2807 | <h5>Design Principles</h5>
2808 | <ul>
2809 | <li>
2810 | ✅
2811 | <em>Each Ralph session operates monolithically</em> on ONE
2812 | body of work per branch
2813 | </li>
2814 | <li>
2815 | ✅ <em>User creates branches manually</em> - full control
2816 | over naming conventions and strategy (e.g. worktrees)
2817 | </li>
2818 | <li>
2819 | ✅ <em>Natural language work descriptions</em> - pass prose
2820 | to LLM, unconstrained by git naming rules
2821 | </li>
2822 | <li>
2823 | ✅ <em>Scoping at plan creation</em> (deterministic) not
2824 | task selection (probabilistic)
2825 | </li>
2826 | <li>
2827 | ✅ <em>Single plan per branch</em> - one
2828 | IMPLEMENTATION_PLAN.md per branch
2829 | </li>
2830 | <li>
2831 | ✅ <em>Plan remains disposable</em> - regenerate scoped plan
2832 | when wrong/stale for a branch
2833 | </li>
2834 | <li>✅ No dynamic branch switching within a loop session</li>
2835 | <li>✅ Maintains simplicity and determinism</li>
2836 | <li>✅ Optional - main branch workflow still works</li>
2837 | <li>
2838 | ✅ No semantic filtering at build time - Ralph just picks
2839 | "most important"
2840 | </li>
2841 | </ul>
2842 |
2843 | <p><strong>Workflow:</strong></p>
2844 | <ol>
2845 | <li>
2846 | <p><em>Full Planning (on main branch)</em></p>
2847 | <div class="code-block">
2848 | <div class="code-block-header">
2849 | <span>bash</span>
2850 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2851 | </div>
2852 | <pre><code>./loop.sh plan
2853 | # Generate full IMPLEMENTATION_PLAN.md for entire project</code></pre>
2854 | </div>
2855 | </li>
2856 | <li>
2857 | <p><em>Create Work Branch</em></p>
2858 | <p>User performs:</p>
2859 | <div class="code-block">
2860 | <div class="code-block-header">
2861 | <span>bash</span>
2862 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2863 | </div>
2864 | <pre><code>git checkout -b ralph/user-auth-oauth
2865 | # Create branch with whatever naming convention you prefer
2866 | # Suggestion: ralph/* prefix for work branches</code></pre>
2867 | </div>
2868 | </li>
2869 | <li>
2870 | <p><em>Scoped Planning (on work branch)</em></p>
2871 | <div class="code-block">
2872 | <div class="code-block-header">
2873 | <span>bash</span>
2874 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2875 | </div>
2876 | <pre><code>./loop.sh plan-work "user authentication system with OAuth and session management"
2877 | # Pass natural language description - LLM uses this to scope the plan
2878 | # Creates focused IMPLEMENTATION_PLAN.md with only tasks for this work</code></pre>
2879 | </div>
2880 | </li>
2881 | <li>
2882 | <p><em>Build from Plan (on work branch)</em></p>
2883 | <div class="code-block">
2884 | <div class="code-block-header">
2885 | <span>bash</span>
2886 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2887 | </div>
2888 | <pre><code>./loop.sh
2889 | # Ralph builds from scoped plan (no filtering needed)
2890 | # Picks most important task from already-scoped plan</code></pre>
2891 | </div>
2892 | </li>
2893 | <li>
2894 | <p><em>PR Creation (when work complete)</em></p>
2895 | <p>User performs:</p>
2896 | <div class="code-block">
2897 | <div class="code-block-header">
2898 | <span>bash</span>
2899 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2900 | </div>
2901 | <pre><code>gh pr create --base main --head ralph/user-auth --fill</code></pre>
2902 | </div>
2903 | </li>
2904 | </ol>
2905 |
2906 | <h5>Work-Scoped <code>loop.sh</code></h5>
2907 | <p>
2908 | Extends the base enhanced loop script to add work branch
2909 | support with scoped planning:
2910 | </p>
2911 | <div class="code-block">
2912 | <div class="code-block-header">
2913 | <span>loop.sh</span>
2914 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2915 | </div>
2916 | <pre><code>#!/bin/bash
2917 | set -euo pipefail
2918 |
2919 | # Usage:
2920 | # ./loop.sh [plan] [max_iterations] # Plan/build on current branch
2921 | # ./loop.sh plan-work "work description" # Create scoped plan on current branch
2922 |
2923 | # Parse arguments
2924 | MODE="build"
2925 | PROMPT_FILE="PROMPT_build.md"
2926 |
2927 | if [ "$1" = "plan" ]; then
2928 | MODE="plan"
2929 | PROMPT_FILE="PROMPT_plan.md"
2930 | MAX_ITERATIONS=${2:-0}
2931 | elif [ "$1" = "plan-work" ]; then
2932 | if [ -z "$2" ]; then
2933 | echo "Error: plan-work requires a work description"
2934 | exit 1
2935 | fi
2936 | MODE="plan-work"
2937 | WORK_DESCRIPTION="$2"
2938 | PROMPT_FILE="PROMPT_plan_work.md"
2939 | MAX_ITERATIONS=${3:-5}
2940 | elif [[ "$1" =~ ^[0-9]+$ ]]; then
2941 | MAX_ITERATIONS=$1
2942 | else
2943 | MAX_ITERATIONS=0
2944 | fi
2945 |
2946 | # ... (see README for full script)</code></pre>
2947 | </div>
2948 |
2949 | <h5><code>PROMPT_plan_work.md</code> Template</h5>
2950 |
2951 | <p>
2952 | <em>Note:</em> Identical to <code>PROMPT_plan.md</code> but
2953 | with scoping instructions and <code>WORK_SCOPE</code>
2954 | env var substituted (automatically by the loop script).
2955 | </p>
2956 | <div class="code-block">
2957 | <div class="code-block-header">
2958 | <span>PROMPT_plan_work.md</span>
2959 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
2960 | </div>
2961 | <pre><code>0a. Study `specs/*` with up to 250 parallel Sonnet subagents to learn the application specifications.
2962 | 0b. Study @IMPLEMENTATION_PLAN.md (if present) to understand the plan so far.
2963 | 0c. Study `src/lib/*` with up to 250 parallel Sonnet subagents to understand shared utilities & components.
2964 | 0d. For reference, the application source code is in `src/*`.
2965 |
2966 | 1. You are creating a SCOPED implementation plan for work: "${WORK_SCOPE}". Study @IMPLEMENTATION_PLAN.md (if present; it may be incorrect) and use up to 500 Sonnet subagents to study existing source code in `src/*` and compare it against `specs/*`. Use an Opus subagent to analyze findings, prioritize tasks, and create/update @IMPLEMENTATION_PLAN.md as a bullet point list sorted in priority of items yet to be implemented. Ultrathink. Consider searching for TODO, minimal implementations, placeholders, skipped/flaky tests, and inconsistent patterns. Study @IMPLEMENTATION_PLAN.md to determine starting point for research and keep it up to date with items considered complete/incomplete using subagents.
2967 |
2968 | IMPORTANT: This is SCOPED PLANNING for "${WORK_SCOPE}" only. Create a plan containing ONLY tasks directly related to this work scope. Be conservative - if uncertain whether a task belongs to this work, exclude it. The plan can be regenerated if too narrow. Plan only. Do NOT implement anything. Do NOT assume functionality is missing; confirm with code search first. Treat `src/lib` as the project's standard library for shared utilities and components. Prefer consolidated, idiomatic implementations there over ad-hoc copies.
2969 |
2970 | ULTIMATE GOAL: We want to achieve the scoped work "${WORK_SCOPE}". Consider missing elements related to this work and plan accordingly. If an element is missing, search first to confirm it doesn't exist, then if needed author the specification at specs/FILENAME.md. If you create a new element then document the plan to implement it in @IMPLEMENTATION_PLAN.md using a subagent.</code></pre>
2971 | </div>
2972 |
2973 | <h5>Compatibility with Core Philosophy</h5>
2974 | <div class="table-wrapper">
2975 | <table>
2976 | <thead>
2977 | <tr>
2978 | <th>Principle</th>
2979 | <th>Maintained?</th>
2980 | <th>How</th>
2981 | </tr>
2982 | </thead>
2983 | <tbody>
2984 | <tr>
2985 | <td>Monolithic operation</td>
2986 | <td>✅ Yes</td>
2987 | <td>
2988 | Ralph still operates as single process within branch
2989 | </td>
2990 | </tr>
2991 | <tr>
2992 | <td>One task per loop</td>
2993 | <td>✅ Yes</td>
2994 | <td>Unchanged</td>
2995 | </tr>
2996 | <tr>
2997 | <td>Fresh context</td>
2998 | <td>✅ Yes</td>
2999 | <td>Unchanged</td>
3000 | </tr>
3001 | <tr>
3002 | <td>Deterministic</td>
3003 | <td>✅ Yes</td>
3004 | <td>
3005 | Scoping at plan creation (deterministic), not runtime
3006 | </td>
3007 | </tr>
3008 | <tr>
3009 | <td>Simple</td>
3010 | <td>✅ Yes</td>
3011 | <td>Optional enhancement, main workflow still works</td>
3012 | </tr>
3013 | <tr>
3014 | <td>Plan-driven</td>
3015 | <td>✅ Yes</td>
3016 | <td>One IMPLEMENTATION_PLAN.md per branch</td>
3017 | </tr>
3018 | <tr>
3019 | <td>Single source of truth</td>
3020 | <td>✅ Yes</td>
3021 | <td>
3022 | One plan per branch – scoped plan replaces full plan
3023 | on branch
3024 | </td>
3025 | </tr>
3026 | <tr>
3027 | <td>Plan is disposable</td>
3028 | <td>✅ Yes</td>
3029 | <td>
3030 | Regenerate scoped plan anytime:
3031 | <code>./loop.sh plan-work "work description"</code>
3032 | </td>
3033 | </tr>
3034 | <tr>
3035 | <td>Markdown over JSON</td>
3036 | <td>✅ Yes</td>
3037 | <td>Still markdown plans</td>
3038 | </tr>
3039 | <tr>
3040 | <td>Let Ralph Ralph</td>
3041 | <td>✅ Yes</td>
3042 | <td>
3043 | Ralph picks "most important" from already-scoped plan
3044 | – no filter
3045 | </td>
3046 | </tr>
3047 | </tbody>
3048 | </table>
3049 | </div>
3050 | </div>
3051 | </details>
3052 |
3053 | <details>
3054 | <summary>
3055 | <span class="summary-title"
3056 | >JTBD → Story Map → SLC Release</span
3057 | >
3058 | <span class="summary-desc"
3059 | >Push the power of "Letting Ralph Ralph" to connect JTBD's
3060 | audience and activities to Simple/Lovable/Complete
3061 | releases.</span
3062 | >
3063 | </summary>
3064 | <div class="details-content">
3065 | <h5>Topics of Concern → Activities</h5>
3066 | <p>
3067 | Geoff's
3068 | <a
3069 | href="https://ghuntley.com/content/images/size/w2400/2025/07/The-ralph-Process.png"
3070 | >suggested workflow</a
3071 | >
3072 | already aligns planning with Jobs-to-be-Done – breaking JTBDs
3073 | into topics of concern, which in turn become specs. I think
3074 | there's an opportunity to lean further into the product
3075 | benefits this approach affords by reframing
3076 | <em>topics of concern</em> as <em>activities</em>.
3077 | </p>
3078 | <p>
3079 | Activities are verbs in a journey ("upload photo", "extract
3080 | colors") rather than capabilities ("color extraction system").
3081 | They're naturally scoped by user intent.
3082 | </p>
3083 | <blockquote>
3084 | <p style="margin-bottom: 0.5rem">
3085 | Topics: "color extraction", "layout engine" →
3086 | capability-oriented
3087 | </p>
3088 | <p>
3089 | Activities: "upload photo", "see extracted colors", "arrange
3090 | layout" → journey-oriented
3091 | </p>
3092 | </blockquote>
3093 | <h5>Activities → User Journey</h5>
3094 | <p>
3095 | Activities – and their constituent steps – sequence naturally
3096 | into a user flow, creating a <em>journey structure</em> that
3097 | makes gaps and dependencies visible. A
3098 | <a href="https://www.nngroup.com/articles/user-story-mapping/"
3099 | >User Story Map</a
3100 | >
3101 | organizes activities as columns (the journey backbone) with
3102 | capability depths as rows – the full space of what
3103 | <em>could</em> be built:
3104 | </p>
3105 | <div class="code-block">
3106 | <div class="code-block-header">
3107 | <span>diagram</span>
3108 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
3109 | </div>
3110 | <pre><code>UPLOAD → EXTRACT → ARRANGE → SHARE
3111 |
3112 | basic auto manual export
3113 | bulk palette templates collab
3114 | batch AI themes auto-layout embed</code></pre>
3115 | </div>
3116 |
3117 | <h5>User Journey → Release Slices</h5>
3118 | <p>
3119 | Horizontal slices through the map become candidate releases.
3120 | Not every activity needs new capability in every release —
3121 | some cells stay empty, and that's fine if the slice is still
3122 | coherent:
3123 | </p>
3124 | <div class="code-block">
3125 | <div class="code-block-header">
3126 | <span>diagram</span>
3127 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
3128 | </div>
3129 | <pre><code> UPLOAD → EXTRACT → ARRANGE → SHARE
3130 |
3131 | Release 1: basic auto export
3132 | ───────────────────────────────────────────────────
3133 | Release 2: palette manual
3134 | ───────────────────────────────────────────────────
3135 | Release 3: batch AI themes templates embed</code></pre>
3136 | </div>
3137 |
3138 | <h5>Release Slices → SLC Releases</h5>
3139 | <p>
3140 | The story map gives you <em>structure</em> for slicing. Jason
3141 | Cohen's
3142 | <a href="https://longform.asmartbear.com/slc/"
3143 | >Simple, Lovable, Complete (SLC)</a
3144 | >
3145 | gives you <em>criteria</em> for what makes a slice good:
3146 | </p>
3147 | <ul>
3148 | <li>
3149 | <em>Simple</em> – Narrow scope you can ship fast. Not every
3150 | activity, not every depth.
3151 | </li>
3152 | <li>
3153 | <em>Complete</em> – Fully accomplishes a job within that
3154 | scope. Not a broken preview.
3155 | </li>
3156 | <li>
3157 | <em>Lovable</em> – People actually want to use it.
3158 | Delightful within its boundaries.
3159 | </li>
3160 | </ul>
3161 |
3162 | <p>
3163 | <strong>Why SLC over MVP?</strong> MVPs optimize for learning
3164 | at the customer's expense – "minimum" often means broken or
3165 | frustrating. SLC flips this: learn in-market
3166 | <em>while</em> delivering real value. If it succeeds, you have
3167 | optionality. If it fails, you still treated users well.
3168 | </p>
3169 |
3170 | <p>
3171 | Each slice can become a release with a clear value and
3172 | identity:
3173 | </p>
3174 | <div class="code-block">
3175 | <div class="code-block-header">
3176 | <span>diagram</span>
3177 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
3178 | </div>
3179 | <pre><code> UPLOAD → EXTRACT → ARRANGE → SHARE
3180 |
3181 | Palette Picker: basic auto export
3182 | ───────────────────────────────────────────────────
3183 | Mood Board: palette manual
3184 | ───────────────────────────────────────────────────
3185 | Design Studio: batch AI themes templates embed</code></pre>
3186 | </div>
3187 | <ul>
3188 | <li>
3189 | <em>Palette Picker</em> – Upload, extract, export. Instant
3190 | value from day one.
3191 | </li>
3192 | <li>
3193 | <em>Mood Board</em> – Adds arrangement. Creative expression
3194 | enters the journey.
3195 | </li>
3196 | <li>
3197 | <em>Design Studio</em> – Professional features: batch
3198 | processing, AI themes, embeddable output.
3199 | </li>
3200 | </ul>
3201 |
3202 | <h5>Operationalizing with Ralph</h5>
3203 | <p>
3204 | The concepts above – activities, story maps, SLC releases –
3205 | are the <em>thinking tools</em>. How do we translate them into
3206 | Ralph's workflow?
3207 | </p>
3208 |
3209 | <p><em>Default Ralph approach:</em></p>
3210 | <ol>
3211 | <li>
3212 | <em>Define Requirements</em>: Human + LLM define JTBD topics
3213 | of concern → <code>specs/*.md</code>
3214 | </li>
3215 | <li>
3216 | <em>Create Tasks Plan</em>: LLM analyzes all specs + current
3217 | code → <code>IMPLEMENTATION_PLAN.md</code>
3218 | </li>
3219 | <li><em>Build</em>: Ralph builds against full scope</li>
3220 | </ol>
3221 |
3222 | <p>
3223 | This works well for capability-focused work (features,
3224 | refactors, infrastructure). But it doesn't naturally produce
3225 | valuable (SLC) product releases – it produces "whatever the
3226 | specs describe".
3227 | </p>
3228 |
3229 | <p><em>Activities → SLC Release approach:</em></p>
3230 | <p>
3231 | To get SLC releases, we need to ground activities in audience
3232 | context. Audience defines WHO has the JTBDs, which in turn
3233 | informs WHAT activities matter and what "lovable" means.
3234 | </p>
3235 | <div class="code-block">
3236 | <div class="code-block-header">
3237 | <span>diagram</span>
3238 | <button class="copy-btn" onclick="copyCode(this)">Copy</button>
3239 | </div>
3240 | <pre><code>Audience (who)
3241 | └── has JTBDs (why)
3242 | └── fulfilled by Activities (how)</code></pre>
3243 | </div>
3244 |
3245 | <h5>Workflow</h5>
3246 | <p><em>I. Requirements Phase (2 steps):</em></p>
3247 | <p>
3248 | Still performed in LLM conversations with the human, similar
3249 | to the default Ralph approach.
3250 | </p>
3251 | <ol>
3252 | <li>
3253 | <em>Define audience and their JTBDs</em> – WHO are we
3254 | building for and what OUTCOMES do they want?
3255 | <ul>
3256 | <li>
3257 | Human + LLM discuss and determine the audience(s) and
3258 | their JTBDs (outcomes they want)
3259 | </li>
3260 | <li>
3261 | May contain multiple connected audiences (e.g.
3262 | "designer" creates, "client" reviews)
3263 | </li>
3264 | <li>Generates <code>AUDIENCE_JTBD.md</code></li>
3265 | </ul>
3266 | </li>
3267 | <li>
3268 | <em>Define activities</em> – WHAT do users do to accomplish
3269 | their JTBDs?
3270 | <ul>
3271 | <li>Informed by <code>AUDIENCE_JTBD.md</code></li>
3272 | <li>
3273 | For each JTBD, identify activities necessary to
3274 | accomplish it
3275 | </li>
3276 | <li>
3277 | For each activity, determine:
3278 | <ul>
3279 | <li>
3280 | Capability depths (basic → enhanced) – levels of
3281 | sophistication
3282 | </li>
3283 | <li>
3284 | Desired outcome(s) at each depth – what does success
3285 | look like?
3286 | </li>
3287 | </ul>
3288 | </li>
3289 | <li>
3290 | Generates <code>specs/*.md</code> (one per activity)
3291 | </li>
3292 | </ul>
3293 | </li>
3294 | </ol>
3295 | <p>
3296 | The discrete steps within activities are implicit and LLM can
3297 | infer them during planning.
3298 | </p>
3299 |
3300 | <p><em>II. Planning Phase:</em></p>
3301 | <p>
3302 | Performed in Ralph loop with <em>updated</em> planning prompt.
3303 | </p>
3304 | <ul>
3305 | <li>
3306 | LLM analyzes:
3307 | <ul>
3308 | <li>
3309 | <code>AUDIENCE_JTBD.md</code> (who, desired outcomes)
3310 | </li>
3311 | <li><code>specs/*</code> (what could be built)</li>
3312 | <li>Current code state (what exists)</li>
3313 | </ul>
3314 | </li>
3315 | <li>
3316 | LLM determines next SLC slice (which activities, at what
3317 | capability depths) and plans tasks for that slice
3318 | </li>
3319 | <li>LLM generates <code>IMPLEMENTATION_PLAN.md</code></li>
3320 | <li>
3321 | <em>Human verifies</em> plan before building:
3322 | <ul>
3323 | <li>Does the scope represent a coherent SLC release?</li>
3324 | <li>
3325 | Are the right activities included at the right depths?
3326 | </li>
3327 | <li>
3328 | If wrong → re-run planning loop to regenerate plan,
3329 | optionally updating inputs or planning prompt
3330 | </li>
3331 | <li>If right → proceed to building</li>
3332 | </ul>
3333 | </li>
3334 | </ul>
3335 |
3336 | <p>
3337 | <em>III. Building Phase:</em> Performed in Ralph loop with
3338 | standard building prompt.
3339 | </p>
3340 |
3341 | <h5>Updated <code></code>PROMPT_plan_slc.md</code> Template</h5>
3342 | <p>
3343 | Variant of <code>PROMPT_plan.md</code> that adds audience
3344 | context and SLC-oriented slice recommendation.
3345 | </p>
3346 | <p>
3347 | <em>Notes:</em>
3348 | <ul>
3349 | <li>Unlike the default template, this does not
3350 | have a <code>[project-specific goal]</code> placeholder –
3351 | the goal is implicit: recommend the most valuable next
3352 | release for the audience.
3353 | </li>
3354 | <li>
3355 | Current subagents names presume using Claude.
3356 | </li>
3357 | </ul>
3358 | </p>
3359 | <div class="code-block">
3360 | <div class="code-block-header">
3361 | <span>PROMPT_plan_slc.md</span>
3362 | <button class="copy-btn" onclick="copyCode(this)">
3363 | Copy
3364 | </button>
3365 | </div>
3366 | <pre><code>0a. Study @AUDIENCE_JTBD.md to understand who we're building for and their Jobs to Be Done.
3367 | 0b. Study `specs/*` with up to 250 parallel Sonnet subagents to learn JTBD activities.
3368 | 0c. Study @IMPLEMENTATION_PLAN.md (if present) to understand the plan so far.
3369 | 0d. Study `src/lib/*` with up to 250 parallel Sonnet subagents to understand shared utilities & components.
3370 | 0e. For reference, the application source code is in `src/*`.
3371 |
3372 | 1. Sequence the activities in `specs/*` into a user journey map for the audience in @AUDIENCE_JTBD.md. Consider how activities flow into each other and what dependencies exist.
3373 |
3374 | 2. Determine the next SLC release. Use up to 500 Sonnet subagents to compare `src/*` against `specs/*`. Use an Opus subagent to analyze findings. Ultrathink. Given what's already implemented recommend which activities (at what capability depths) form the most valuable next release. Prefer thin horizontal slices - the narrowest scope that still delivers real value. A good slice is Simple (narrow, achievable), Lovable (people want to use it), and Complete (fully accomplishes a meaningful job, not a broken preview).
3375 |
3376 | 3. Use an Opus subagent (ultrathink) to analyze and synthesize the findings, prioritize tasks, and create/update @IMPLEMENTATION_PLAN.md as a bullet point list sorted in priority of items yet to be implemented for the recommended SLC release. Begin plan with a summary of the recommended SLC release (what's included and why), then list prioritized tasks for that scope. Consider TODOs, placeholders, minimal implementations, skipped tests - but scoped to the release. Note discoveries outside scope as future work.
3377 |
3378 | IMPORTANT: Plan only. Do NOT implement anything. Do NOT assume functionality is missing; confirm with code search first. Treat `src/lib` as the project's standard library for shared utilities and components. Prefer consolidated, idiomatic implementations there over ad-hoc copies.
3379 |
3380 | ULTIMATE GOAL: We want to achieve the most valuable next release for the audience in @AUDIENCE_JTBD.md. Consider missing elements and plan accordingly. If an element is missing, search first to confirm it doesn't exist, then if needed author the specification at specs/FILENAME.md. If you create a new element then document the plan to implement it in @IMPLEMENTATION_PLAN.md using a subagent.</code></pre>
3381 | </div>
3382 |
3383 | <h5>Notes</h5>
3384 | <p>
3385 | <em
3386 | >Why <code>AUDIENCE_JTBD.md</code> as a separate
3387 | artifact:</em
3388 | >
3389 | </p>
3390 | <ul>
3391 | <li>Single source of truth – prevents drift across specs</li>
3392 | <li>
3393 | Enables holistic reasoning: "What does this audience need
3394 | MOST?"
3395 | </li>
3396 | <li>
3397 | JTBDs captured alongside audience (the "why" lives with the
3398 | "who")
3399 | </li>
3400 | <li>
3401 | Referenced twice: during spec creation AND SLC planning
3402 | </li>
3403 | <li>
3404 | Keeps activity specs focused on WHAT, not repeating WHO
3405 | </li>
3406 | </ul>
3407 |
3408 | <p><em>Cardinalities:</em></p>
3409 | <ul>
3410 | <li>
3411 | One audience → many JTBDs ("Designer" has "capture space",
3412 | "explore concepts", "present to client")
3413 | </li>
3414 | <li>
3415 | One JTBD → many activities ("capture space" includes upload,
3416 | measurements, room detection)
3417 | </li>
3418 | <li>
3419 | One activity → can serve multiple JTBDs ("upload photo"
3420 | serves both "capture" and "gather inspiration")
3421 | </li>
3422 | </ul>
3423 | </div>
3424 | </details>
3425 | </section>
3426 |
3427 | <!-- Footer -->
3428 | <footer class="article-footer">
3429 | <p>
3430 | View source on
3431 | <a href="https://github.com/ClaytonFarr/ralph-playbook">GitHub</a
3432 | >.
3433 | </p>
3434 | </footer>
3435 | </main>
3436 |
3437 | <!-- Sidebar TOC -->
3438 | <aside class="toc-sidebar">
3439 | <nav class="toc-nav" aria-label="Table of contents">
3440 | <ul class="toc-list">
3441 | <li><a href="#intro" class="toc-link">Intro</a></li>
3442 | <li><a href="#workflow" class="toc-link">Workflow</a></li>
3443 | <li>
3444 | <a href="#key-principles" class="toc-link">Key Principles</a>
3445 | </li>
3446 | <li>
3447 | <a href="#loop-mechanics" class="toc-link">Loop Mechanics</a>
3448 | </li>
3449 | <li><a href="#files" class="toc-link">Files</a></li>
3450 | <li>
3451 | <a href="#enhancements" class="toc-link">Enhancements?</a>
3452 | </li>
3453 | </ul>
3454 | </nav>
3455 | </aside>
3456 | </div>
3457 | </div>
3458 |
3459 | <script>
3460 | // Copy to clipboard functionality
3461 | function copyCode(button) {
3462 | const codeBlock = button
3463 | .closest(".code-block")
3464 | .querySelector("pre code");
3465 | const text = codeBlock.textContent;
3466 |
3467 | navigator.clipboard.writeText(text).then(() => {
3468 | const originalText = button.textContent;
3469 | button.textContent = "Copied!";
3470 | button.style.color = "#00aa44";
3471 | setTimeout(() => {
3472 | button.textContent = originalText;
3473 | button.style.color = "";
3474 | }, 2000);
3475 | });
3476 | }
3477 |
3478 | // Highlight current TOC item on scroll
3479 | const tocLinks = document.querySelectorAll(".toc-link");
3480 | const sections = document.querySelectorAll("section[id], header[id]");
3481 |
3482 | function updateTocHighlight() {
3483 | const scrollPos = window.scrollY + 100;
3484 | let activeSet = false;
3485 |
3486 | // Check if we're at the very top (intro section)
3487 | if (scrollPos < 200) {
3488 | tocLinks.forEach((link) => {
3489 | link.classList.remove("active");
3490 | if (link.getAttribute("href") === "#intro") {
3491 | link.classList.add("active");
3492 | }
3493 | });
3494 | return;
3495 | }
3496 |
3497 | sections.forEach((section) => {
3498 | const sectionTop = section.offsetTop;
3499 | const sectionHeight = section.offsetHeight;
3500 | const sectionId = section.getAttribute("id");
3501 |
3502 | if (
3503 | scrollPos >= sectionTop &&
3504 | scrollPos < sectionTop + sectionHeight
3505 | ) {
3506 | tocLinks.forEach((link) => {
3507 | link.classList.remove("active");
3508 | if (link.getAttribute("href") === "#" + sectionId) {
3509 | link.classList.add("active");
3510 | activeSet = true;
3511 | }
3512 | });
3513 | }
3514 | });
3515 | }
3516 |
3517 | window.addEventListener("scroll", updateTocHighlight);
3518 | updateTocHighlight();
3519 | </script>
3520 | </body>
3521 | </html>
3522 |
```