@pageai/ralph-loop 1.12.0 β†’ 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # A Ralph Wiggum Loop implementation that worksβ„’
2
2
 
3
- Ralph is a long-running AI agent loop. Ralph automates software development tasks by iteratively working through a task list until completion.
3
+ Ralph is a long-running AI agent loop. Ralph automates software development tasks by iteratively working through a task list until completion. This allows for long running agent loops, effectively enabling AI to code for days at a time.
4
4
 
5
- This is an implementation that actually works, containing a hackable script so you can configure it to your env and favorite agentic AI CLI. It's set up by default to use Claude Code in a Docker sandbox.
5
+ This is an implementation that actually works, containing a hackable script so you can configure it to your env and favorite agentic AI CLI. It's set up by default to use Claude Code in a Docker sandbox, but supports [many other agentic AI CLIs](#running-with-a-different-agentic-cli).
6
6
 
7
- ![Ralph Wiggum Loop](https://github.com/user-attachments/assets/052d5290-7e83-4bfb-a6b5-6be761cbe890)
7
+ #### πŸ‘‰ [Watch the video](https://www.youtube.com/watch?v=3TL8Ez66I3o) for an in-depth walkthrough.
8
+
9
+ [![Ralph Wiggum Loop](https://github.com/user-attachments/assets/be94b8ba-b073-489d-b07e-d11db975a907)](https://www.youtube.com/watch?v=3TL8Ez66I3o)
8
10
 
9
11
  - [Getting Started](#getting-started)
10
12
  - [(Optional) Set up code base](#optional-set-up-code-base)
@@ -17,7 +19,6 @@ This is an implementation that actually works, containing a hackable script so y
17
19
  - [How It Works](#how-it-works)
18
20
  - [How Is This Different from Other Ralphs?](#how-is-this-different-from-other-ralphs)
19
21
  - [Steering the Agent](#steering-the-agent)
20
- - [Features](#features)
21
22
  - [Support](#support)
22
23
  - [Promise Tags](#promise-tags)
23
24
  - [Exit Codes](#exit-codes)
@@ -84,15 +85,20 @@ Requirements:
84
85
  // etc.
85
86
  ```
86
87
 
87
- Pro tips:
88
+ <details>
89
+ <summary><strong>✨ Pro tips</strong></summary>
90
+
88
91
  - mention libraries and frameworks you want to use
89
- - mention env variables, e.g. for database, 3rd party API keys, etc. Store them in a .env file that you add to **.gitignore**
92
+ - mention env variables, e.g. for DB, 3rd party API keys, etc. Store them in `.env` and add it to **.gitignore**
90
93
  - describe user flows and journeys
91
94
  - add relevant docs and UI references if applicable inside `/docs` and mention them in the requirements
92
95
  - be as descriptive as possible
93
96
  - *it's fine to write in your own language*
94
97
 
95
- Then follow the Skill's instructions and verify the PRD and then tasks.<br/>
98
+ </details>
99
+ <br/>
100
+
101
+ Then, follow the Skill's instructions and verify the PRD and then tasks.<br/>
96
102
  **It is highly recommended that you review individual task requirements before starting the loop. Review EACH TASK INDIVIDUALLY.**
97
103
 
98
104
  ### 3️⃣ Step 3: Set up the agent inside Docker sandbox
@@ -162,7 +168,7 @@ Each iteration, Ralph will:
162
168
  1. Find the highest-priority incomplete task from `.agent/tasks.json`
163
169
  2. Work through the task steps defined in `.agent/tasks/TASK-{ID}.json`
164
170
  3. Run tests, linting, and type checking
165
- 4. Update task status and commit changes
171
+ 4. Complete task, take screenshot, update task status and commit changes
166
172
  5. Repeat until all tasks pass or max iterations reached
167
173
 
168
174
  ## How Is This Different from Other Ralphs?
@@ -172,10 +178,27 @@ The script follows the original concepts of the Ralph Wiggum Loop, working with
172
178
 
173
179
  It also works generically with any task set.
174
180
 
181
+ <details>
182
+ <summary><strong>✨ Features</strong></summary>
183
+
184
+ - **PRD generation** - Creates a PRD and task list from requirements
185
+ - **Task lookup table generation** - Creates a task lookup table from the PRD
186
+ - **Task breakdown + step generation** - Breaks down each task into manageable steps
187
+ - **Iteration tracking** - Shows progress through iterations with timing
188
+ - **Stream preview** - Shows live output from the Agent
189
+ - **Step detection** - Identifies current activity (Thinking, Implementing, Testing, etc.)
190
+ - **Screenshot capture** - Captures a screenshot of the current screen
191
+ - **Notifications** - Alerts when human input is needed
192
+ - **History logging** - Saves clean output from each iteration
193
+ - **Timing** - Shows timing metrics for each iteration and total time
194
+ - **Steering** - Allows prioritizing critical work that needs to be done before the loop can continue
195
+ </details>
196
+
197
+ <br/>
175
198
  Besides that:
176
199
 
177
200
  - it allows you to dump unstructured requirements and have the agent create a PRD and task list for you.
178
- - it uses a task lookup table with individual detailed steps -> more scalable as you get 100s of tasks done.
201
+ - it uses a task lookup table with individual detailed steps β†’ more scalable as you get 100s of tasks done.
179
202
  - it's sandboxed and more secure
180
203
  - it shows progress and stats so you can keep an eye on what's been done
181
204
  - it instructs the agent to write and run automated tests and screenshots per task
@@ -189,19 +212,6 @@ While the loop is running, you can edit the `.agent/STEERING.md` file to add cri
189
212
 
190
213
  The agent will check this file each iteration and if it finds any critical work, it will skip tasks and complete the critical work first.
191
214
 
192
- ## Features
193
-
194
- - **PRD generation** - Creates a PRD and task list from requirements
195
- - **Task lookup table generation** - Creates a task lookup table from the PRD
196
- - **Task breakdown + step generation** - Breaks down each task into manageable steps
197
- - **Iteration tracking** - Shows progress through iterations with timing
198
- - **Stream preview** - Shows live output from the Agent
199
- - **Step detection** - Identifies current activity (Thinking, Implementing, Testing, etc.)
200
- - **Screenshot capture** - Captures a screenshot of the current screen
201
- - **Notifications** - Alerts when human input is needed
202
- - **History logging** - Saves clean output from each iteration
203
- - **Timing** - Shows timing metrics for each iteration and total time
204
-
205
215
  ## Support
206
216
 
207
217
  The `ralph.sh` script is designed to be hackable.
@@ -258,6 +268,8 @@ Skills are reusable agent capabilities that provide specialized knowledge and wo
258
268
  | `prd-creator` | Create PRDs and task breakdowns for Ralph |
259
269
  | `skill-creator` | Create new skills |
260
270
  | `vercel-react-best-practices` | React/Next.js performance patterns |
271
+ | `mysql` | MySQL/InnoDB schema, indexing, query tuning, and ops |
272
+ | `postgres` | PostgreSQL best practices and query optimization |
261
273
  | `web-design-guidelines` | UI/UX design principles |
262
274
 
263
275
  ### Skills Directory Structure
@@ -269,18 +281,14 @@ Skills are symlinked from `.agent/skills/` to multiple locations for cross-tool
269
281
  .agent/skills/
270
282
  β”œβ”€β”€ component-refactoring/
271
283
  β”œβ”€β”€ e2e-tester/
272
- β”œβ”€β”€ frontend-code-review/
273
- β”œβ”€β”€ frontend-testing/
274
- β”œβ”€β”€ prd-creator/
275
- β”œβ”€β”€ skill-creator/
276
- β”œβ”€β”€ vercel-react-best-practices/
277
- └── web-design-guidelines/
284
+ β”œβ”€β”€ postgres/
285
+ β”œβ”€β”€ ...
278
286
 
279
287
  # Symlinks -> .agent/skills/*
280
- .agents/skills/
281
- .claude/skills/
282
- .codex/skills/
283
- .cursor/skills/
288
+ .agents/skills/*
289
+ .claude/skills/*
290
+ .codex/skills/*
291
+ .cursor/skills/*
284
292
  ```
285
293
 
286
294
  ## Reference
@@ -324,29 +332,28 @@ export default defineConfig({
324
332
  If you are using Vitest, here is a recommended configuration:
325
333
 
326
334
  ```typescript:vitest.config.ts
327
- import { defineConfig } from 'vitest/config'
328
- import react from '@vitejs/plugin-react'
329
- import path from 'path'
335
+ import { defineConfig } from "vitest/config";
336
+ import react from "@vitejs/plugin-react";
337
+ import path from "path";
330
338
 
331
339
  export default defineConfig({
332
340
  plugins: [react()],
333
341
  test: {
334
- environment: 'jsdom',
342
+ environment: "node",
335
343
  globals: true,
336
- setupFiles: ['./vitest.setup.ts'],
337
- include: ['**/*.test.{ts,tsx}'],
338
- exclude: ['node_modules', '.next', 'tests'],
344
+ include: ["lib/**/*.test.ts", "lib/**/*.test.tsx"],
345
+ // setupFiles: ['./vitest.setup.ts'], // Include this if using Next.js
339
346
  },
340
347
  resolve: {
341
348
  alias: {
342
- '@': path.resolve(__dirname, './'),
349
+ "@": path.resolve(__dirname),
343
350
  },
344
351
  },
345
- })
352
+ });
346
353
 
347
354
  ```
348
355
 
349
- And:
356
+ If you are using Next.js, you'll also need a `vitest.setup.ts` file to mock the `next/image` and `next/link` components.
350
357
 
351
358
  ```typescript:vitest.setup.ts
352
359
  import '@testing-library/jest-dom/vitest'
@@ -388,8 +395,8 @@ docker sandbox run codex . # for Codex CLI
388
395
  docker sandbox run gemini . # for Gemini CLI
389
396
  ```
390
397
 
391
- Docker currently supports: `claude`, `codex`, `gemini`, `cagent`, `kiro`.
392
- See more in [Docker's docs](https://docs.docker.com/ai/sandboxes/migration/).
398
+ Docker currently supports: `claude`, `codex`, `opencode`,`copilot`, `gemini`, `cagent`, `kiro` and more.
399
+ See all supported agentic AI CLIs in [Docker's docs](https://docs.docker.com/ai/sandboxes/agents/).
393
400
 
394
401
  ### Starting from scratch
395
402
 
package/bin/cli.js CHANGED
@@ -8,15 +8,16 @@
8
8
 
9
9
  const fs = require('fs');
10
10
  const path = require('path');
11
- const { execSync } = require('child_process');
12
11
  const display = require('./lib/display');
13
12
  const { copyFile, copyDir, mergeDir, exists, ensureDir } = require('./lib/copy');
14
13
  const { isGitRepo, initGitRepo } = require('./lib/git');
15
14
  const { isShadcnProject, installAllComponents } = require('./lib/shadcn');
15
+ const { setupPlaywright } = require('./lib/playwright');
16
+ const { setupVitest } = require('./lib/vitest');
17
+ const { DEFAULT_APP_DIR } = require('./lib/consts');
16
18
 
17
19
  const PACKAGE_ROOT = path.resolve(__dirname, '..');
18
20
  const TARGET_DIR = process.cwd();
19
- const DEFAULT_APP_DIR = 'lib';
20
21
 
21
22
  // Directories to ensure exist (created even if source doesn't exist)
22
23
  const DIRS_TO_ENSURE = [
@@ -161,7 +162,18 @@ async function main() {
161
162
  process.exit(0);
162
163
  }
163
164
 
164
- // Prompt 3 β€” Dev server address
165
+ // Prompt 3 β€” Install Vitest
166
+ const installVitest = await clack.confirm({
167
+ message: 'Set up Vitest for unit testing?',
168
+ initialValue: true,
169
+ });
170
+
171
+ if (clack.isCancel(installVitest)) {
172
+ clack.cancel('Setup cancelled.');
173
+ process.exit(0);
174
+ }
175
+
176
+ // Prompt 4 β€” Dev server address
165
177
  const devServerRaw = await clack.text({
166
178
  message: 'Where does your dev server run?',
167
179
  placeholder: 'localhost:3000',
@@ -341,32 +353,12 @@ async function main() {
341
353
 
342
354
  // Playwright setup
343
355
  if (installPlaywright) {
344
- console.log();
345
- display.printStep('🎭', 'Playwright setup');
346
-
347
- // Copy playwright config to app directory
348
- const playwrightSrc = path.join(TARGET_DIR, 'scripts/assets/playwright.config.ts');
349
- const playwrightDest = path.join(TARGET_DIR, appDir, 'playwright.config.ts');
350
-
351
- if (exists(playwrightSrc)) {
352
- copyFile(playwrightSrc, playwrightDest);
353
- display.printSuccess(`playwright.config.ts β†’ ${appDir}/`);
354
- }
356
+ setupPlaywright(clack, TARGET_DIR, appDir);
357
+ }
355
358
 
356
- // Install Playwright browsers
357
- const s = clack.spinner();
358
- s.start('Installing Playwright browsers (chromium)...');
359
- try {
360
- execSync('npx playwright install --with-deps chromium', {
361
- cwd: path.join(TARGET_DIR, appDir),
362
- stdio: 'pipe',
363
- });
364
- s.stop('Playwright browsers installed');
365
- } catch (err) {
366
- s.stop('Playwright browser install failed');
367
- display.printWarning('Could not install Playwright browsers. Run manually:');
368
- display.printWarning(` cd ${appDir} && npx playwright install --with-deps chromium`);
369
- }
359
+ // Vitest setup
360
+ if (installVitest) {
361
+ setupVitest(clack, TARGET_DIR, appDir);
370
362
  }
371
363
 
372
364
  // Final setup steps (git init, shadcn install)
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shared constants for Ralph Loop CLI
3
+ */
4
+
5
+ const DEFAULT_APP_DIR = 'lib';
6
+
7
+ module.exports = {
8
+ DEFAULT_APP_DIR,
9
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Playwright module for Ralph Loop CLI
3
+ * Copies config and installs Playwright browsers
4
+ */
5
+
6
+ const path = require('path');
7
+ const { execSync } = require('child_process');
8
+ const { copyFile, exists } = require('./copy');
9
+ const display = require('./display');
10
+
11
+ /**
12
+ * Copies playwright.config.ts into the app directory and installs Chromium.
13
+ * @param {object} clack - @clack/prompts module (passed in because it's ESM)
14
+ * @param {string} targetDir - Project root (TARGET_DIR)
15
+ * @param {string} appDir - Relative app source directory
16
+ */
17
+ function setupPlaywright(clack, targetDir, appDir) {
18
+ console.log();
19
+ display.printStep('🎭', 'Playwright setup');
20
+
21
+ // Copy playwright config to app directory
22
+ const playwrightSrc = path.join(targetDir, 'scripts/assets/playwright.config.ts');
23
+ const playwrightDest = path.join(targetDir, appDir, 'playwright.config.ts');
24
+
25
+ if (exists(playwrightSrc)) {
26
+ copyFile(playwrightSrc, playwrightDest);
27
+ display.printSuccess(`playwright.config.ts β†’ ${appDir}/`);
28
+ }
29
+
30
+ // Install Playwright browsers
31
+ const s = clack.spinner();
32
+ s.start('Installing Playwright browsers (chromium)...');
33
+ try {
34
+ execSync('npx playwright install --with-deps chromium', {
35
+ cwd: path.join(targetDir, appDir),
36
+ stdio: 'pipe',
37
+ });
38
+ s.stop('Playwright browsers installed');
39
+ } catch (err) {
40
+ s.stop('Playwright browser install failed');
41
+ display.printWarning('Could not install Playwright browsers. Run manually:');
42
+ display.printWarning(` cd ${appDir} && npx playwright install --with-deps chromium`);
43
+ }
44
+ }
45
+
46
+ module.exports = {
47
+ setupPlaywright,
48
+ };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Vitest module for Ralph Loop CLI
3
+ * Copies config and installs Vitest dependencies
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const { execSync } = require('child_process');
9
+ const { copyFile, exists } = require('./copy');
10
+ const display = require('./display');
11
+ const { DEFAULT_APP_DIR } = require('./consts');
12
+
13
+ /**
14
+ * Copies vitest.config.ts into the app directory, patches the include
15
+ * paths to match appDir, and installs vitest + react plugin.
16
+ * @param {object} clack - @clack/prompts module (passed in because it's ESM)
17
+ * @param {string} targetDir - Project root (TARGET_DIR)
18
+ * @param {string} appDir - Relative app source directory
19
+ */
20
+ function setupVitest(clack, targetDir, appDir) {
21
+ console.log();
22
+ display.printStep('⚑', 'Vitest setup');
23
+
24
+ // Copy vitest config to app directory
25
+ const vitestSrc = path.join(targetDir, 'scripts/assets/vitest.config.ts');
26
+ const vitestDest = path.join(targetDir, appDir, 'vitest.config.ts');
27
+
28
+ if (exists(vitestSrc)) {
29
+ copyFile(vitestSrc, vitestDest);
30
+
31
+ // Patch include paths to match the user's app directory
32
+ if (appDir !== DEFAULT_APP_DIR) {
33
+ const content = fs.readFileSync(vitestDest, 'utf8');
34
+ const updated = content.replaceAll('lib/**/', `${appDir}/**/`);
35
+ fs.writeFileSync(vitestDest, updated, 'utf8');
36
+ }
37
+
38
+ display.printSuccess(`vitest.config.ts β†’ ${appDir}/`);
39
+ }
40
+
41
+ // Install Vitest dependencies
42
+ const s = clack.spinner();
43
+ s.start('Installing Vitest dependencies...');
44
+ try {
45
+ execSync('npm install --save-dev vitest @vitejs/plugin-react', {
46
+ cwd: path.join(targetDir, appDir),
47
+ stdio: 'pipe',
48
+ });
49
+ s.stop('Vitest dependencies installed');
50
+ } catch (err) {
51
+ s.stop('Vitest install failed');
52
+ display.printWarning('Could not install Vitest dependencies. Run manually:');
53
+ display.printWarning(` cd ${appDir} && npm install --save-dev vitest @vitejs/plugin-react`);
54
+ }
55
+ }
56
+
57
+ module.exports = {
58
+ setupVitest,
59
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pageai/ralph-loop",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -0,0 +1,17 @@
1
+ import { defineConfig } from "vitest/config";
2
+ import react from "@vitejs/plugin-react";
3
+ import path from "path";
4
+
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ test: {
8
+ environment: "node",
9
+ globals: true,
10
+ include: ["lib/**/*.test.ts", "lib/**/*.test.tsx"],
11
+ },
12
+ resolve: {
13
+ alias: {
14
+ "@": path.resolve(__dirname),
15
+ },
16
+ },
17
+ });