wagnerfnds/ralph-for-laravel

Runs a Ralph-style loop (100% PHP) from ralph.md or ralph.json in a Laravel project.

Maintainers

Package info

github.com/wagnerfnds/ralph-for-laravel

pkg:composer/wagnerfnds/ralph-for-laravel

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 2

Open Issues: 0

v1.0.0 2026-01-21 11:13 UTC

This package is auto-updated.

Last update: 2026-03-21 11:41:14 UTC


README

A 100% PHP, Laravel-friendly "Ralph Loop" runner that reads ralph.md or ralph.json from your project root and iteratively drives an external coding agent (CLI) to complete tasks. It keeps state in .ralph/, optionally runs checks (tests/lint), and can optionally commit changes to Git as each task passes.

No Bash required. Everything is orchestrated in PHP using Laravel + Symfony Process.

Features

  • php artisan ralph runs the loop
  • ✅ Reads tasks from project root:
    • ralph.md (Markdown checkboxes)
    • ralph.json (PRD-like JSON)
  • ✅ Keeps loop state in .ralph/:
    • .ralph/prd.json (normalized tasks + pass/fail state)
    • .ralph/progress.log (optional log file)
    • .ralph/run.lock (prevents multiple concurrent runs)
  • ✅ Calls any external agent via CLI (configured with .env / config/ralph.php)
  • ✅ Runs configurable checks (tests, lint, etc.)
  • ✅ Optional Git workflow (branch + commits per completed story)

Requirements

  • PHP 8.2+
  • Laravel 10 / 11 / 12
  • An external coding agent CLI installed on your machine/CI (e.g. claude, codex, etc.)
  • (Optional) git installed if you enable Git features

Installation

composer require wagnerfnds/ralph-for-laravel

Laravel package discovery should register the service provider automatically.

Quick Start

1) Initialize state directory and create an example ralph.md

php artisan ralph:init --gitignore

This will:

  • Create .ralph/ directory
  • Create .ralph/progress.log (empty)
  • Create an example ralph.md if it does not exist
  • Create .ralph/.gitignore so the state directory is not committed

2) Add your tasks in ralph.md

Example:

# Ralph TODO

- [ ] Create invoices migration
- [ ] Create Invoice model + casts
- [ ] Build CRUD endpoints for /api/invoices
- [ ] Add Feature tests for the CRUD

3) Configure your agent in .env

See the Environment Variables section below.

4) Run the loop

php artisan ralph

You can override iterations:

php artisan ralph --max=15

Dry-run mode (prints what it would do, no agent/checks/git):

php artisan ralph --dry-run

Disable checks:

php artisan ralph --no-checks

Disable Git actions:

php artisan ralph --no-git

Input Formats

ralph.md (Markdown)

  • Each checkbox becomes a user story.
  • Checked items ([x]) are treated as already passed (passes=true).
  • The first markdown heading (e.g., # Invoice Feature) is used to generate a friendly branch name.

Example:

# Invoice Feature

- [ ] Create invoices migration
- [ ] Create Invoice model + casts
- [ ] Build CRUD endpoints for /api/invoices
- [ ] Add Feature tests for the CRUD

This will create a branch named: ralph/invoice-feature-20250121-143022 (with timestamp to avoid conflicts)

ralph.json (PRD JSON)

If ralph.json exists in the project root, it takes precedence over ralph.md.

Example:

{
  "project": "my-laravel-app",
  "branchName": "ralph/feature-invoices",
  "description": "Invoices feature",
  "userStories": [
    {
      "id": "US-001",
      "title": "Create invoices migration",
      "description": "As a dev, I want an invoices table so we can store billing data.",
      "priority": 1,
      "passes": false
    }
  ]
}

Missing fields are normalized automatically:

  • passes defaults to false
  • priority defaults to incremental order
  • description defaults to title
  • id defaults to US-001, US-002, ...

State Directory

By default, the package stores generated state in:

.ralph/
  prd.json
  progress.log
  run.lock
  • prd.json is the normalized PRD used by the loop.
  • run.lock prevents running multiple loops concurrently.

Tip: use php artisan ralph:init --gitignore so .ralph/ is ignored by Git.

Environment Variables (.env)

Add these to your .env:

# Max attempts per story (retries if agent/checks fail)
RALPH_MAX_ITERATIONS=10

# If true, enables Git operations (branch/commit). You can still disable per-run with --no-git.
RALPH_GIT=true

# Optional: create branches prefixed with this value
RALPH_BRANCH_PREFIX=ralph/

# Optional: push branch after commits (useful in CI)
RALPH_PUSH=false

# Your external agent CLI command (must exist on PATH)
RALPH_AGENT_CMD=claude

# Optional: additional arguments for the agent CLI (space-separated)
# Examples: --verbose, --stream, --debug
RALPH_AGENT_ARGS="--verbose"

Notes:

  • RALPH_AGENT_CMD can be any executable available in your environment: claude, codex, a custom wrapper script, etc.
  • RALPH_AGENT_ARGS allows you to pass additional flags to see the agent's "thinking" process in real-time
  • The process output streams in real-time with TTY support when available

Configuration (config/ralph.php)

Publish the config:

php artisan vendor:publish --tag=ralph-config

Then edit config/ralph.php:

return [
    'inputs' => [
        'json' => base_path('ralph.json'),
        'md'   => base_path('ralph.md'),
    ],

    'state_dir' => base_path('.ralph'),

    'max_iterations' => (int) env('RALPH_MAX_ITERATIONS', 10),

    'agent' => [
        'command' => env('RALPH_AGENT_CMD', 'claude'),
        'args'    => [],
        'timeout' => null,
    ],

    'checks' => [
        // Examples:
        // ['php', 'artisan', 'test'],
        // ['php', 'artisan', 'pint', '--test'],
    ],

    'git' => [
        'enabled' => (bool) env('RALPH_GIT', true),
        'base_branch' => env('RALPH_BASE_BRANCH', null),
        'branch_prefix' => env('RALPH_BRANCH_PREFIX', 'ralph/'),
        'push' => (bool) env('RALPH_PUSH', false),
    ],
];

Checks

You can define any number of checks that run after the agent completes an iteration:

'checks' => [
  ['php', 'artisan', 'test'],
  ['php', 'artisan', 'pint', '--test'],
],

If any check fails, the loop stops and reports the failure.

Git Workflow

If Git is enabled, the runner can:

  • ensure you are inside a Git repository
  • create/switch to a branchName (from the PRD or generated)
  • commit changes after each story is marked passed

Disable Git for a single run:

php artisan ralph --no-git

Safety / Notes

  • This package executes external commands (agent CLI, checks, git) in your project directory.
  • Review changes before merging.
  • Consider running in a dedicated branch.
  • In CI, use RALPH_PUSH=true only if your credentials are configured safely.

Development (Local Testing)

During development, you can install this package into a Laravel app using a Composer path repository:

{
  "repositories": [
    { "type": "path", "url": "../ralph-for-laravel", "options": { "symlink": true } }
  ],
  "require": {
    "wagnerfnds/ralph-for-laravel": "dev-main"
  }
}

Then:

composer update wagnerfnds/ralph-for-laravel
php artisan ralph:init --gitignore
php artisan ralph

Roadmap

  • Agent adapters (Claude, Codex, etc.) via Contracts
  • Per-iteration logs (.ralph/iterations/0001.json)
  • Auto-push + PR creation (GitHub CLI)
  • Better prompt templates and context strategies

License

MIT