@pageai/ralph-loop 1.1.0 → 1.4.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/.agent/PROMPT.md CHANGED
@@ -4,7 +4,7 @@ You are implementing the project described in @.agent/prd/SUMMARY.md
4
4
 
5
5
  ## Required Setup
6
6
 
7
- Run `npm run dev` (as background process).
7
+ Run `npm run dev` (as background process) in `src` directory.
8
8
  App will be running at http://localhost:3000
9
9
 
10
10
  ## Before Starting
@@ -29,7 +29,7 @@ Tasks are listed in @.agent/tasks.json
29
29
  8. All tests must pass. Broke unrelated test? Fix it before proceeding.
30
30
  9. When tests pass, set `passes: true` in `tasks.json` for the task you completed.
31
31
  10. Log entry → `.agent/logs/LOG.md` (date, brief summary, screenshot path)
32
- 11. Update `.agent/STRUCTURE.md` if dirs changed
32
+ 11. Update `.agent/STRUCTURE.md` if dirs changed. Exclude dotfiles, tests and config.
33
33
  12. Commit changes, using the Conventional Commit format.
34
34
 
35
35
  ## Rules
@@ -42,15 +42,15 @@ Tasks are listed in @.agent/tasks.json
42
42
  ## Help Tags
43
43
 
44
44
  Try solving tasks yourself first.
45
- Only use when truly stuck.
45
+ When stuck after all possible solutions exhausted, output one of the following tags:
46
46
 
47
- **BLOCKED** — technical issues: Playwright broken, deps won't install, env issues, no network, service outages, invalid credentials. Output:
47
+ 1. **BLOCKED** — technical issues: Playwright broken, dev server not working, deps won't install, env issues, no network, service outages, invalid/missing credentials. Output:
48
48
 
49
49
  ```
50
50
  <promise>BLOCKED:brief description</promise>
51
51
  ```
52
52
 
53
- **DECIDE** — need human input: lib choices, architecture, unclear requirements, breaking changes. Output:
53
+ 2. **DECIDE** — need human input: lib choices, architecture, unclear requirements, breaking changes. Output:
54
54
 
55
55
  ```
56
56
  <promise>DECIDE:question (Option A vs B)</promise>
@@ -1,3 +1,5 @@
1
1
  # **Critical Steering Work**
2
2
 
3
- No critical work pending. All issues resolved.
3
+ Go to the source code directory and install dependencies.
4
+
5
+ Check that Playwright is running by starting the dev server and taking a screenshot. Save the screenshot to the .agent/screenshots directory.
@@ -546,7 +546,7 @@ Acceptance criteria must be verifiable, not vague. "Works correctly" is bad. "Bu
546
546
  For any story with UI changes: Always include "Verify in browser using playwright" as acceptance criteria. This ensures visual verification of frontend work.
547
547
 
548
548
  **Important:**
549
- Tasks cannot be end to end tests or unit tests. These should be individual steps (verification criteria) in a task, if needed.
549
+ End to end tests or unit tests are individual steps (verification criteria) in a task, but *CANNOT* be tasks themselves.
550
550
 
551
551
  ### Initialize All Tasks to `"passes": false`
552
552
 
@@ -580,6 +580,12 @@ Save the complete task list as `PROJECT_ROOT/.agent/tasks.json`:
580
580
  ]
581
581
  ```
582
582
 
583
+ **Important:**
584
+ When outputting tasks, create them, sequentially. Output them one by one so the user can review each.
585
+ *DO NOT* output in parallel.
586
+ *DO NOT* use background agents.
587
+ *DO NOT* use subagents.
588
+
583
589
  ## After Generation
584
590
 
585
591
  Present the tasks to the user:
@@ -10,6 +10,8 @@ Help beginner-level developers transform software ideas into comprehensive PRD.m
10
10
  4. Keep tone friendly and supportive, use plain language
11
11
  5. Track assumptions throughout - they'll go in the PRD
12
12
 
13
+ **Important**: Grill the user for information to make sure you have all the required details in order to implement the PRD.
14
+
13
15
  ## Topics to Cover
14
16
 
15
17
  Gather information on these aspects:
@@ -1,54 +1,43 @@
1
1
  {
2
- "permissions": {
3
- "deny": [
4
- "Read(*.env)",
5
- "Bash(sudo *)",
6
- "Read(~/.ssh/**)",
7
- "Read(.agent/history/**)"
8
- ],
9
- "allow": [
10
- "**"
2
+ "permissions": {
3
+ "deny": ["Read(.agent/history/**)"],
4
+ "allow": ["**"]
5
+ },
6
+ "defaultMode": "acceptEdits",
7
+ "enableAllProjectMcpServers": true,
8
+ "enabledMcpjsonServers": ["playwright", "context7", "sequential-thinking"],
9
+ "hooks": {
10
+ "UserPromptSubmit": [
11
+ {
12
+ "hooks": [
13
+ {
14
+ "type": "command",
15
+ "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/pre-tool-use.js"
16
+ }
11
17
  ]
12
- },
13
- "defaultMode": "acceptEdits",
14
- "enableAllProjectMcpServers": true,
15
- "enabledMcpjsonServers": [
16
- "playwright",
17
- "context7",
18
- "sequential-thinking"
18
+ }
19
19
  ],
20
- "hooks": {
21
- "UserPromptSubmit": [
22
- {
23
- "hooks": [
24
- {
25
- "type": "command",
26
- "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/pre-tool-use.js"
27
- }
28
- ]
29
- }
30
- ],
31
- "PreToolUse": [
32
- {
33
- "matcher": "Edit|Write|Bash",
34
- "hooks": [
35
- {
36
- "type": "command",
37
- "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/pre-tool-use.js"
38
- }
39
- ]
40
- }
41
- ],
42
- "Notification": [
43
- {
44
- "matcher": "",
45
- "hooks": [
46
- {
47
- "type": "command",
48
- "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/play-sound.js notification"
49
- }
50
- ]
51
- }
20
+ "PreToolUse": [
21
+ {
22
+ "matcher": "Edit|Write|Bash",
23
+ "hooks": [
24
+ {
25
+ "type": "command",
26
+ "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/pre-tool-use.js"
27
+ }
52
28
  ]
53
- }
29
+ }
30
+ ],
31
+ "Notification": [
32
+ {
33
+ "matcher": "",
34
+ "hooks": [
35
+ {
36
+ "type": "command",
37
+ "command": "node $CLAUDE_PROJECT_DIR/.claude/hooks/play-sound.js notification"
38
+ }
39
+ ]
40
+ }
41
+ ]
42
+ }
54
43
  }
package/AGENTS.md CHANGED
@@ -41,4 +41,4 @@ Verify written code by:
41
41
  - Checking for type errors
42
42
  - Checking for lint errors
43
43
  - Smoke testing and checking for runtime errors with Playwright
44
- - Takins screenshots and verifying the UI is as expected
44
+ - Taking screenshots and verifying the UI is as expected
package/README.md CHANGED
@@ -7,12 +7,13 @@ This is an implementation that actually works, containing a hackable script so y
7
7
  ![Ralph Wiggum Loop](https://github.com/user-attachments/assets/052d5290-7e83-4bfb-a6b5-6be761cbe890)
8
8
 
9
9
  - [Getting Started](#getting-started)
10
- - [Step 1: Install Ralph](#step-1-install-ralph)
11
- - [Step 2: Create a PRD + task list](#step-2-create-a-prd--task-list)
12
- - [Step 3: Set up the agent inside Docker sandbox](#step-3-set-up-the-agent-inside-docker-sandbox)
13
- - [Step 4: Run Ralph](#step-4-run-ralph)
14
- - [(optional) Adjusting to your language/framework](#optional-adjusting-to-your-languageframework)
10
+ - [(Optional) Set up code base](#optional-set-up-code-base)
11
+ - [1️⃣ Step 1: Install Ralph](#1️⃣-step-1-install-ralph)
12
+ - [2️⃣ Step 2: Create a PRD + task list](#2️⃣-step-2-create-a-prd--task-list)
13
+ - [3️⃣ Step 3: Set up the agent inside Docker sandbox](#3️⃣-step-3-set-up-the-agent-inside-docker-sandbox)
14
+ - [4️⃣ Step 4: Run Ralph](#4️⃣-step-4-run-ralph)
15
15
  - [Run the loop](#run-the-loop)
16
+ - [(Optional) Adjusting to your language/framework](#optional-adjusting-to-your-languageframework)
16
17
  - [How It Works](#how-it-works)
17
18
  - [How Is This Different from Other Ralphs?](#how-is-this-different-from-other-ralphs)
18
19
  - [Steering the Agent](#steering-the-agent)
@@ -27,11 +28,27 @@ This is an implementation that actually works, containing a hackable script so y
27
28
  - [Reference](#reference)
28
29
  - [Playwright configuration](#playwright-configuration)
29
30
  - [Vitest configuration](#vitest-configuration)
31
+ - [Running with a different agentic CLI](#running-with-a-different-agentic-cli)
32
+ - [Starting from scratch](#starting-from-scratch)
30
33
  - [License](#license)
31
34
 
35
+ ---------------------------------
36
+
32
37
  ## Getting Started
33
38
 
34
- ### Step 1: Install Ralph
39
+ ### (Optional) Set up code base
40
+
41
+ I recommend using a CLI to bootstrap your project with the necessary tools and dependencies, e.g.:
42
+
43
+ ```bash
44
+ npx create-vite@latest src --template react-ts
45
+ # or
46
+ npx create-next-app@latest src
47
+ ```
48
+
49
+ > If you must start from a blank slate, which is not recommended, see [Starting from scratch](#starting-from-scratch).
50
+
51
+ ### 1️⃣ Step 1: Install Ralph
35
52
 
36
53
  Run this in your project's directory to install Ralph.
37
54
 
@@ -39,13 +56,17 @@ Run this in your project's directory to install Ralph.
39
56
  npx @pageai/ralph-loop
40
57
  ```
41
58
 
42
- ### Step 2: Create a PRD + task list
59
+ ### 2️⃣ Step 2: Create a PRD + task list
43
60
 
44
61
  Use the `prd-creator` skill to generate a PRD from your requirements.<br/>
45
62
  Open up Claude Code and prompt it with **your requirements**. Like so:
46
63
 
47
64
  ```
48
- Use the prd-creator skill to help me create a PRD and task list for these requirements:
65
+ Use the prd-creator skill to help me create a PRD and task list for the below requirements.
66
+
67
+ An app is already set up with Next.js, Tailwind CSS and TypeScript.
68
+
69
+ Requirements:
49
70
 
50
71
  - A SaaS product that helps users manage their finances.
51
72
  - Target audience: Small business owners and freelancers.
@@ -57,16 +78,26 @@ Use the prd-creator skill to help me create a PRD and task list for these requir
57
78
  - Connect to bank accounts and credit cards.
58
79
  - Connect to accounting software.
59
80
  - Connect to payment processors.
60
- - Next.js web app with Tailwind CSS and TypeScript.
61
81
  - Use the shadcn/ui library for components.
82
+ - Integrate with Stripe for payments.
83
+ - Use Supabase for database.
84
+ - You can find env variables in the .env.example file: SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, STRIPE_SECRET_KEY, etc. are available in the runtime.
62
85
 
63
86
  // etc.
64
87
  ```
65
88
 
89
+ Pro tips:
90
+ - mention libraries and frameworks you want to use
91
+ - mention env variables, e.g. for database, 3rd party API keys, etc. Store them in a .env file that you add to **.gitignore**
92
+ - describe user flows and journeys
93
+ - add relevant docs and UI references if applicable inside `/docs` and mention them in the requirements
94
+ - be as descriptive as possible
95
+ - *it's fine to write in your own language*
96
+
66
97
  Then follow the Skill's instructions and verify the PRD and then tasks.<br/>
67
98
  **It is highly recommended that you review individual task requirements before starting the loop. Review EACH TASK INDIVIDUALLY.**
68
99
 
69
- ### Step 3: Set up the agent inside Docker sandbox
100
+ ### 3️⃣ Step 3: Set up the agent inside Docker sandbox
70
101
 
71
102
  Authenticate inside the Docker sandbox before running Ralph. Run:
72
103
 
@@ -76,48 +107,16 @@ docker sandbox run claude .
76
107
 
77
108
  And follow the instructions to log in into Claude Code.
78
109
 
79
- > Answer "Yes" to "Bypass Permissions mode", that's the exact reason why you are using the Docker sandbox.
80
-
81
- ### Step 4: Run Ralph
110
+ 👉 Answer "Yes" to `Bypass Permissions mode`, that's the exact reason why you are using the Docker sandbox.
82
111
 
83
- ```bash
84
- ./ralph.sh -n 50 # Run Ralph Loop with 50 iterations
85
- ```
112
+ > If you want to use a different agentic CLI, see [Running with a different agentic CLI](#running-with-a-different-agentic-cli).
86
113
 
87
- ### (optional) Adjusting to your language/framework
88
-
89
- This script assumes the following are installed:
90
- - [Playwright](https://playwright.dev/) for e2e testing
91
- - [Vitest](https://vitest.dev/) for unit testing
92
- - [TypeScript](https://www.typescriptlang.org/) for type checking
93
- - [ESLint](https://eslint.org/) for linting
94
- - [Prettier](https://prettier.io/) for formatting
95
-
96
- I recommend using a CLI to bootstrap your project with the necessary tools and dependencies, e.g.:
114
+ ### 4️⃣ Step 4: Run Ralph
97
115
 
98
116
  ```bash
99
- npx create-vite@latest app --template react-ts
100
- # or
101
- npx create-next-app@latest app
102
- ```
103
-
104
- If you must start from a blank slate, which is not recommended, you can use the following commands to install the necessary tools and dependencies:
105
-
106
- Install with:
107
-
108
- ```bash
109
- npm i @playwright/test vitest jsdom typescript eslint prettier -D
110
-
111
- # If using React, also recommend installing:
112
- npm i @vitejs/plugin-react @testing-library/dom @testing-library/jest-dom @testing-library/react @testing-library/user-event -D
117
+ ./ralph.sh -n 50 # Run Ralph Loop with 50 iterations
113
118
  ```
114
119
 
115
- --------------------------------
116
-
117
- ⚠️ If you are using a different language or testing framework, please adjust `.agent/PROMPT.md` to reflect your setup, server ports and startup commands etc.
118
-
119
- ⚠️ The default "mode" is "implementation". Depending on your use case, you might want to change `.agent/PROMPT.md` to a different mode, e.g. "refactor", "review", "test" etc.
120
-
121
120
  ## Run the loop
122
121
 
123
122
  ```bash
@@ -138,6 +137,25 @@ npm i @vitejs/plugin-react @testing-library/dom @testing-library/jest-dom @testi
138
137
 
139
138
  > NB: you might need to run `chmod +x ralph.sh` to make the script executable.
140
139
 
140
+ > ⚠️ The default "mode" is "implementation". Depending on your use case, you might want to change `.agent/PROMPT.md` to a different mode, e.g. "refactor", "review", "test" etc.
141
+
142
+ ⚠️ If you want to use a different language or testing framework, see below.
143
+
144
+ ### (Optional) Adjusting to your language/framework
145
+
146
+ This script assumes the following are installed:
147
+ - [Playwright](https://playwright.dev/) for e2e testing
148
+ - [Vitest](https://vitest.dev/) for unit testing
149
+ - [TypeScript](https://www.typescriptlang.org/) for type checking
150
+ - [ESLint](https://eslint.org/) for linting
151
+ - [Prettier](https://prettier.io/) for formatting
152
+
153
+ If you'd like to use a different language, testing framework etc. please adjust `.agent/PROMPT.md` to reflect your setup, server ports and startup commands etc.
154
+
155
+ 👉 The loop is controlled by this prompt, which will be sent to the agent each iteration.
156
+
157
+ ---------------------------------
158
+
141
159
  ## How It Works
142
160
 
143
161
  Each iteration, Ralph will:
@@ -189,7 +207,7 @@ The agent will check this file each iteration and if it finds any critical work,
189
207
  The `ralph.sh` script is designed to be hackable.
190
208
  It is configured to use Claude Code in a Docker sandbox by default, but with a one-liner change you can change it to use any other agentic AI CLI.
191
209
 
192
- Check the `ralph.sh` script around `# 👉 This is the main command loop.` for the main command loop.
210
+ Check the `ralph.sh` script around `# This is the main command loop.` for the main command loop.
193
211
 
194
212
  > NB: skills are supported by all major agentic AI CLIs via symlinks.
195
213
 
@@ -265,8 +283,8 @@ Skills are symlinked from `.agent/skills/` to multiple locations for cross-tool
265
283
  .cursor/skills/
266
284
  ```
267
285
 
268
-
269
286
  ## Reference
287
+
270
288
  ### Playwright configuration
271
289
 
272
290
  If you are using Playwright, here is a recommended configuration:
@@ -279,28 +297,19 @@ import { defineConfig, devices } from '@playwright/test';
279
297
  */
280
298
  export default defineConfig({
281
299
  testDir: './tests',
282
- /* Total timeout for the entire test run (30 minutes) */
283
- globalTimeout: 30 * 60 * 1000,
284
- /* Run tests in files in parallel */
285
300
  fullyParallel: true,
286
- /* Fail the build on CI if you accidentally left test.only in the source code. */
301
+ globalTimeout: 30 * 60 * 1000,
287
302
  forbidOnly: !!process.env.CI,
288
- /* Retry on failure - 2 on CI, 1 locally */
289
303
  retries: process.env.CI ? 2 : 1,
290
- /* Number of parallel workers */
291
- workers: process.env.CI ? 1 : 6,
292
- /* Reporter to use. See https://playwright.dev/docs/test-reporters */
304
+ workers: process.env.CI ? 3 : 6,
293
305
  reporter: 'html',
294
- /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
295
306
  use: {
296
- /* Base URL to use in actions like `await page.goto('')`. */
297
307
  baseURL: 'http://localhost:3000',
298
-
299
- /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
300
308
  trace: 'on-first-retry',
301
309
  },
302
310
 
303
- // NB: Only test in Desktop Chrome and nothing else.
311
+
312
+ // NB: only chromium will run in Docker (arm64).
304
313
  projects: [
305
314
  {
306
315
  name: 'chromium',
@@ -366,6 +375,39 @@ vi.mock('next/link', () => ({
366
375
  }))
367
376
  ```
368
377
 
378
+ ### Running with a different agentic CLI
379
+
380
+ If you want to use a different agentic CLI, you can adjust the `ralph.sh` script to reflect your CLI of choice.
381
+
382
+ Check the `ralph.sh` script around `# This is the main command loop.` for the main command loop.
383
+
384
+ Replace `docker sandbox run claude . --` with the your favorite CLI. Remember to also update the options after the `--`.
385
+
386
+ ```
387
+ docker sandbox run codex . # for Codex CLI
388
+ docker sandbox run gemini . # for Gemini CLI
389
+ ```
390
+
391
+ Docker currently supports: `claude`, `codex`, `gemini`, `cagent`, `kiro`.
392
+ See more in [Docker's docs](https://docs.docker.com/ai/sandboxes/migration/).
393
+
394
+ ### Starting from scratch
395
+
396
+ For AI to actually verify its implementation and for the loop to work, you need a way to verify it.
397
+
398
+ To that end, at the minimum you need an end-to-end test framework and a unit test framework.
399
+
400
+ For example, you can use the following commands to install Playwright and Vitest:
401
+
402
+ ```bash
403
+ npm i @playwright/test vitest jsdom typescript eslint prettier -D
404
+
405
+ # If using React, also recommend installing:
406
+ npm i @vitejs/plugin-react @testing-library/dom @testing-library/jest-dom @testing-library/react @testing-library/user-event -D
407
+ ```
408
+
409
+ It is recommended that you add skills for your specific language and framework. See [skills.sh](https://skills.sh) to discover existing skills.
410
+
369
411
  ## License
370
412
 
371
413
  MIT
package/bin/cli.js CHANGED
@@ -14,16 +14,29 @@ const { copyFile, copyDir, mergeDir, exists, ensureDir } = require('./lib/copy')
14
14
 
15
15
  const PACKAGE_ROOT = path.resolve(__dirname, '..');
16
16
  const TARGET_DIR = process.cwd();
17
+ const DEFAULT_APP_DIR = 'src';
17
18
 
18
19
  // Directories to ensure exist (created even if source doesn't exist)
19
20
  const DIRS_TO_ENSURE = [
20
21
  '.agent/history',
22
+ '.agent/logs',
23
+ '.agent/prd',
24
+ '.agent/screenshots',
25
+ '.agent/tasks',
21
26
  '.agents/skills',
22
27
  '.claude/skills',
23
28
  '.codex/skills',
24
29
  '.cursor/skills',
25
30
  ];
26
31
 
32
+ // Directories that should have a .gitkeep file
33
+ const DIRS_WITH_GITKEEP = [
34
+ '.agent/logs',
35
+ '.agent/prd',
36
+ '.agent/screenshots',
37
+ '.agent/tasks',
38
+ ];
39
+
27
40
  // Symlinks to create in skills directories (relative to each skills dir)
28
41
  const SKILL_SYMLINKS = [
29
42
  { name: 'component-refactoring', target: '../../.agent/skills/component-refactoring/' },
@@ -91,12 +104,9 @@ async function main() {
91
104
 
92
105
  // Prompt 1 — App source directory
93
106
  const appDir = await clack.text({
94
- message: 'Where does your app source code live?',
95
- placeholder: 'app',
96
- defaultValue: 'app',
97
- validate(value) {
98
- if (!value.trim()) return 'Directory name cannot be empty';
99
- },
107
+ message: 'Where does your app source code live? (e.g. src, public, etc.)',
108
+ placeholder: DEFAULT_APP_DIR,
109
+ defaultValue: DEFAULT_APP_DIR,
100
110
  });
101
111
 
102
112
  if (clack.isCancel(appDir)) {
@@ -203,38 +213,43 @@ async function main() {
203
213
  }
204
214
  }
205
215
 
206
- // Ensure required directories exist and create symlinks
207
- console.log();
208
- display.printStep('🔧', 'Ensuring directories & symlinks');
216
+ // Ensure required directories exist and create markers
209
217
  for (const dir of DIRS_TO_ENSURE) {
210
218
  const dest = path.join(TARGET_DIR, dir);
211
219
  ensureDir(dest);
212
220
 
213
- // Create symlinks for skills directories
214
- if (dir.endsWith('/skills')) {
215
- for (const link of SKILL_SYMLINKS) {
216
- const linkPath = path.join(dest, link.name);
217
- if (!exists(linkPath)) {
218
- try {
219
- fs.symlinkSync(link.target, linkPath);
220
- } catch {
221
- // Symlink might fail on some systems, that's ok
222
- }
223
- }
224
- }
225
- display.printSuccess(`${dir}/ (with symlinks)`);
226
- } else if (dir === '.agent/history') {
227
- // Create .gitignore for history folder
221
+ if (dir === '.agent/history') {
228
222
  const gitignorePath = path.join(dest, '.gitignore');
229
223
  if (!exists(gitignorePath)) {
230
224
  fs.writeFileSync(gitignorePath, '*\n!.gitignore\n');
231
225
  }
232
- display.printSuccess(`${dir}/ (with .gitignore)`);
233
- } else {
234
- display.printSuccess(`${dir}/`);
226
+ } else if (DIRS_WITH_GITKEEP.includes(dir)) {
227
+ const gitkeepPath = path.join(dest, '.gitkeep');
228
+ if (!exists(gitkeepPath)) {
229
+ fs.writeFileSync(gitkeepPath, '');
230
+ }
235
231
  }
236
232
  }
237
233
 
234
+ // Create symlinks for AI config skills directories
235
+ console.log();
236
+ display.printStep('🔗', 'AI config symlinks');
237
+ for (const dir of DIRS_TO_ENSURE) {
238
+ if (!dir.endsWith('/skills')) continue;
239
+ const dest = path.join(TARGET_DIR, dir);
240
+ for (const link of SKILL_SYMLINKS) {
241
+ const linkPath = path.join(dest, link.name);
242
+ if (!exists(linkPath)) {
243
+ try {
244
+ fs.symlinkSync(link.target, linkPath);
245
+ } catch {
246
+ // Symlink might fail on some systems, that's ok
247
+ }
248
+ }
249
+ }
250
+ display.printSuccess(`${dir}/`);
251
+ }
252
+
238
253
  // Copy extra files from directories (with exclusions)
239
254
  console.log();
240
255
  display.printStep('📋', 'Extra config files');
@@ -275,6 +290,19 @@ async function main() {
275
290
  }
276
291
  }
277
292
 
293
+ // Replace app directory in PROMPT.md if different from default
294
+ if (appDir !== DEFAULT_APP_DIR) {
295
+ const promptFile = path.join(TARGET_DIR, '.agent/PROMPT.md');
296
+ if (exists(promptFile)) {
297
+ console.log();
298
+ display.printStep('📂', 'App directory');
299
+ const content = fs.readFileSync(promptFile, 'utf8');
300
+ const updated = content.replaceAll('`src`', `\`${appDir}\``);
301
+ fs.writeFileSync(promptFile, updated, 'utf8');
302
+ display.printSuccess(`.agent/PROMPT.md → ${appDir}`);
303
+ }
304
+ }
305
+
278
306
  // Playwright setup
279
307
  if (installPlaywright) {
280
308
  console.log();
@@ -28,11 +28,16 @@ function formatCatchphrase(text) {
28
28
  const suffix = '■▒▒▓■';
29
29
  const contentWidth = LINE_WIDTH - prefix.length - suffix.length; // 52 chars for content
30
30
 
31
- const padding = contentWidth - text.length;
31
+ if (text.length === 0) {
32
+ return prefix + '▒'.repeat(contentWidth) + suffix;
33
+ }
34
+
35
+ const textWithSpaces = ' ' + text + ' ';
36
+ const padding = contentWidth - textWithSpaces.length;
32
37
  const leftPad = Math.floor(padding / 2);
33
38
  const rightPad = padding - leftPad;
34
39
 
35
- return prefix + '▒'.repeat(leftPad) + text + '▒'.repeat(rightPad) + suffix;
40
+ return prefix + '▒'.repeat(leftPad) + textWithSpaces + '▒'.repeat(rightPad) + suffix;
36
41
  }
37
42
 
38
43
  // Catchphrases (text only, will be formatted)
@@ -77,7 +82,7 @@ ${Y}██████╗ █████╗ ██╗ ██████
77
82
  ╚══════╝ ╚═════╝ ╚═════╝ ╚═╝${R}
78
83
 
79
84
  ${D}${emptyLine}${R}
80
- ${Y}${catchphrase}${R}
85
+ ${D}${catchphrase}${R}
81
86
  ${D}${emptyLine}${R}
82
87
  ${D}═══════════════════════════════════════════════════════════${R}
83
88
  ${C}Ralph Wiggum Loop${R} ${D}・${R} Long-running AI agents
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pageai/ralph-loop",
3
- "version": "1.1.0",
3
+ "version": "1.4.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -53,19 +53,19 @@ show_ralph() {
53
53
 
54
54
  local catchphrases=(
55
55
  "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
56
- "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm helping!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
57
- "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm doing my best!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
58
- "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm in danger!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
59
- "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm learnding!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
60
- "■▒▒▒▒▒▒▒My cat's breath smells like cat food.▒▒▒▒▒▒▒▒▒■▒▒▓■"
61
- "■▒▒▒▒▒▒▒▒Me fail English? That's unpossible!▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
62
- "■▒▒▒▒▒▒▒▒▒I'm asking Claude to cook pasta!▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
63
- "■▒▒▒▒▒▒▒▒▒▒I found a moon rock in my nose!▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
64
- "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒It tastes like burning!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
65
- "■▒▒▒▒▒▒When I grow up, I want to be a computer!▒▒▒▒▒▒▒■▒▒▓■"
66
- "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm a develotron!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
67
- "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm helpding AI!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
68
- "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒I'm essential!▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
56
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ I'm helping! ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
57
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ I'm doing my best! ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
58
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ I'm in danger! ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
59
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ I'm learnding! ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
60
+ "■▒▒▒▒▒▒▒ My cat's breath smells like cat food. ▒▒▒▒▒▒▒■▒▒▓■"
61
+ "■▒▒▒▒▒▒▒▒ Me fail English? That's unpossible! ▒▒▒▒▒▒▒▒■▒▒▓■"
62
+ "■▒▒▒▒▒▒▒▒▒▒ I'm asking Claude to cook pasta! ▒▒▒▒▒▒▒▒▒■▒▒▓■"
63
+ "■▒▒▒▒▒▒▒▒▒▒ I found a moon rock in my nose! ▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
64
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒ It tastes like burning! ▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
65
+ "■▒▒▒▒▒▒ When I grow up, I want to be a computer! ▒▒▒▒▒■▒▒▓■"
66
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ I'm a develotron! ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
67
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ I'm helpding AI! ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
68
+ "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ I'm essential! ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
69
69
  "■▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒■▒▒▓■"
70
70
  )
71
71