@novasoft/ralph-cli
v1.0.5
Published
Portable AI controller for executing reviewed frontend implementation plans
Downloads
75
Readme
Ralph CLI
Ralph is a small, cross-platform controller for executing a human-reviewed AI implementation plan. It runs on Windows, macOS, Linux, and WSL with Node.js 20 or newer.
How it works
ralph initselects Codex or OpenCode and either initializes the current directory or creates a separate Git worktree.ralph plan .ralph/SPEC.mdasks the configured agent to create.ralph/PLAN.json.- A human reviews and edits
.ralph/PLAN.json, including every verification command. ralph approveapproves the exact plan contents. Any later edit invalidates the approval.ralph runimplements and verifies one task, orralph run --allruns the remaining plan.- Runtime progress is saved in
.ralph/state.json, so an interrupted run can be resumed. - A completed plan produces
.ralph/RESULT.mdwith a merge request description, verification summary, active execution time, token usage, and provider-reported cost.
Ralph never commits, resets, reverts, or discards repository changes automatically.
Live terminal progress
In an interactive terminal, Ralph shows an animated loader while an agent or verification command is running. OpenCode and Codex JSON events are rendered as concise live action lines for tool calls, commands, file changes, searches, and final agent messages. Planning shows actions without printing the generated plan payload before it is validated and saved.
Loaders use terminal control sequences only when stderr is a TTY, so redirected output and CI logs remain stable. Action summaries are built from a small allowlist of fields, strip control characters, redact common secret-bearing command arguments, and omit full tool output and arbitrary provider metadata.
Security model
Ralph is an automation controller, not a sandbox. The configured agent runs with the current user's filesystem, environment, and network permissions. Planner and reviewer prompts request read-only behavior, but Ralph cannot enforce that guarantee for an arbitrary agent CLI.
Approved verification entries are executed as shell commands because project checks may contain pipes, redirections, or command chaining. Review the complete plan and use Ralph only with trusted repositories, specifications, plans, verification commands, and agent configurations. Never approve commands you do not understand.
Requirements
- Node.js 20 or newer
- npm, which is included with Node.js
- Git
- A supported agent CLI on
PATH: Codex CLI or OpenCode
Building Ralph from this repository additionally requires pnpm 10. The repository pins the expected pnpm version in its root package.json.
Check the local tools before installing Ralph:
node --version
npm --version
git --versionInstall from npm
After @novasoft/ralph-cli has been published to npm, install the latest stable release globally:
npm install --global @novasoft/ralph-cli@latestThe package provides the global ralph executable. Verify the installation from a new terminal:
ralph --version
ralph --helpAll commands are now available from any directory as ralph init, ralph plan, ralph run, and so on. Run ralph doctor inside the Git repository where Ralph will be used to check Node.js, Git, project configuration, and the configured agent.
To install a specific published version instead of the latest release:
npm install --global @novasoft/[email protected]Installing another version globally replaces the currently installed global version.
Update a stable installation
Install the latest npm release over the existing version:
npm install --global @novasoft/ralph-cli@latest
ralph --versionTo see the latest published version before updating:
npm view @novasoft/ralph-cli versionUpdating the CLI does not modify .ralph/ files in existing projects. Review the release notes before updating across breaking major versions.
Install a commit build
From the repository root, install dependencies and create an installable package for the current Git commit. Commit all intended changes first: build:commit refuses to create an archive when the Git worktree is dirty, ensuring the archive version identifies its exact contents.
pnpm install
pnpm build:commitThe build is written to releases/novasoft-ralph-cli-<version>-commit.g<sha>.tgz. Its commit suffix gives each commit a distinct package version without changing the tracked package.json. Use the exact archive filename printed by build:commit.
Install the generated archive globally, replacing <version> and <sha> with the values in the filename printed by build:commit:
npm install --global ./releases/novasoft-ralph-cli-<version>-commit.g<sha>.tgz
ralph --versionUpdate a commit build
Pull the new commit, commit any intended local changes, create its archive, and install that archive over the previous version:
git pull
pnpm install
pnpm build:commit
npm install --global ./releases/novasoft-ralph-cli-<version>-commit.g<sha>.tgz
ralph --versionUse the exact filename printed by build:commit. To return from a commit build to the latest stable npm release, run:
npm install --global @novasoft/ralph-cli@latestDevelopment install
Use a global link when changing the CLI locally and testing each rebuild without creating an archive:
pnpm install
pnpm build
pnpm add --global .
ralph --versionAfter changing or pulling the source, rebuild it:
pnpm buildThe global link continues to point to the local package, so it does not need to be recreated after every build. Remove it before returning to a stable npm release:
pnpm remove --global @novasoft/ralph-cli
npm install --global @novasoft/ralph-cli@latestUninstall
Remove the global npm installation:
npm uninstall --global @novasoft/ralph-cliIf Ralph was installed as a pnpm development link, remove it with:
pnpm remove --global @novasoft/ralph-cliUninstalling Ralph does not delete .ralph/ directories or results from existing projects.
Installation troubleshooting
If ralph is not found after installation, open a new terminal and check npm's global prefix:
npm config get prefixOn macOS and Linux, <prefix>/bin must be on PATH. On Windows, <prefix> must be on PATH. A Node.js version manager such as fnm, nvm, or Volta is recommended when npm reports permission errors during global installation; avoid running npm with sudo.
If the reported version is not the one just installed, check for multiple executables:
# macOS, Linux, and WSL
which -a ralph
# Windows Command Prompt or PowerShell
where.exe ralphRemove the older global installation or correct the order of entries on PATH, then open a new terminal and run ralph --version again.
If Ralph reports a stale .ralph/run.lock, first confirm that no ralph run, ralph plan, ralph approve, or ralph review process is active. Only then remove .ralph/run.lock manually and retry the command.
Supported failure matrix
Ralph covers controlled process, filesystem, state, agent, verification, and Git boundaries. This is a deliberately bounded fault model, not a promise to enumerate or survive physically every possible failure. For example, hardware failure, kernel or filesystem corruption, abrupt power loss at every possible instruction, and behavior of arbitrary third-party agent or shell code cannot be exhaustively simulated. The tests below exercise the controller behavior at the boundary Ralph can observe and control.
Run pnpm build before an individual compiled test command. The recovery classes used in the matrix are distinct:
- Automatic rollback restores the last consistent Ralph-managed snapshot and removes a stale or incomplete result; retry only after correcting the original cause.
- Safe stop prevents false completion and leaves diagnostics and recoverable state, but does not undo repository changes made by an agent or command.
- Manual recovery requires a person to inspect or repair files or Git resources before retrying. Ralph never commits, resets, reverts, discards changes, or force-removes a worktree as part of recovery.
| Boundary and simulated failure | Reproduce | Expected state and behavior | Diagnostic | Recovery |
| --- | --- | --- | --- | --- |
| process: command launch failure, timeout, cancellation, or a spawned process tree that does not exit | node --test dist/git.test.js | Safe stop. The command settles as failed or aborted, bounded output is retained, and timeout or abort terminates the controlled process tree. No success is reported. | The result distinguishes launch failure, timed out, and aborted; retained stdout and stderr indicate truncation when bounded. | Correct the executable, working directory, permissions, or hung command. For a run interrupted through ralph abort, confirm no child mutation remains and use ralph resume or ralph resume --all. |
| filesystem: publication of PLAN.json, state.json, or RESULT.md fails partway | node --test --test-name-pattern="every run persistence operation rolls back" dist/worker.test.js | Automatic rollback. Previous plan and state bytes and the approved hash are restored, a stale or incomplete result is removed, and completion is not published. | The error starts with Cannot persist run progress or Cannot persist the new plan and identifies the failed persistence step; rollback errors are reported separately. | Fix disk space, permissions, path type, or the unavailable filesystem and retry. If rollback itself failed, this becomes manual recovery: inspect PLAN.json, state.json, and RESULT.md, then run ralph approve before ralph resume. |
| state: malformed JSON, contradictory lifecycle fields, or a PLAN-first interruption | node --test --test-name-pattern="PLAN-first crash recovery requires approval before resume" dist/worker.test.js | Safe stop. Ralph refuses to claim completed verification or continue an unapproved plan. A consistent interrupted active task is normalized by ralph resume; a changed plan is not normalized automatically. | The message names the damaged file or lifecycle contradiction, or says the plan is not approved or has changed; ralph status reports Verification: NOT COMPLETE. | Inspect the exact PLAN.json and state.json bytes. Restore malformed data from a trusted backup or repair it to a valid, consistent lifecycle; if the plan hash changed, review it and run ralph approve, then ralph resume or ralph resume --all. |
| agent: missing executable, provider error, nonzero exit, timeout, abort, or oversized structured response | node --test --test-name-pattern="agent modes distinguish launch, provider, timeout, and abort failures" dist/agent.test.js | Safe stop. Planning and review do not publish replacement state on agent failure. During implementation the task and run become failed (or aborted after an abort), the active task ID is cleared, and no completion result is written. | A bounded, redacted message identifies launch, provider, timeout, abort, output-limit, or exit failure without exposing raw provider payloads. | Restore the agent executable or authentication, resolve the provider/timeout/output issue, inspect repository changes left by the agent, and run ralph resume or ralph resume --all. Re-plan instead if planning never produced an approved plan. |
| verification: command cannot start, exits nonzero, times out, is aborted, or fails the final pass | node --test --test-name-pattern="runAll automatically retries a task with verification output" dist/worker.test.js | Automatic retry, followed by a safe stop at maxIterations. The failed command and bounded output are saved in state.lastError and passed to the repair attempt; persistent failure leaves task and run failed, never completed. | Verification failed or Final verification failed includes the failed command and bounded, redacted stdout/stderr. Exhaustion reports Maximum iterations reached (<n>). | Let the automatic repair continue while iterations remain. After exhaustion, fix the implementation or verification environment, or deliberately increase maxIterations, then run ralph resume --all; edit and reapprove the plan first if a verification command must change. |
| Git: unavailable Git, non-repository directory, dirty worktree, invalid/missing/existing branch, target collision, or git worktree add refusal | node --test --test-name-pattern="worktree preflight failures are actionable" dist/init.test.js | Safe stop before mutation when preflight fails. If Git may have partially created a branch or worktree, Ralph performs manual recovery and preserves the path for inspection instead of force-cleaning it. | The error states the failed precondition and actionable commands such as git worktree list and git branch --list; ralph diff reports Git subprocess failure without changing Ralph state. | Install or repair Git, enter the intended repository, commit or stash work, fetch/create the base branch, choose a free branch/path, and retry. After a partial add, inspect git worktree list, the target path, and git branch --list; remove only resources you have verified are safe to remove. |
Publish a release
Use this checklist for every stable release:
- Update
versioninpackage.jsonto a version that has not already been published. - Commit all release changes, then confirm
git status --shortproduces no output. Do not publish changes that are not represented by the current commit. - Confirm the npm identity and Novasoft organization access that will perform the release:
npm login
npm whoami --registry=https://registry.npmjs.org/
npm org ls novasoft- Confirm that the npm account has two-factor authentication enabled and satisfies the Novasoft organization's publishing policy. Account and organization security settings cannot be validated from this repository.
- With Node.js 20 active, run the release gate from the repository root and inspect the package without publishing:
npm run prepublishOnly
npm publish --dry-run- If either command changes or reveals a needed fix, make the fix, rerun the checks, commit it, and verify the worktree is clean again before publishing.
- Publish to the explicitly configured public npm registry:
npm publish- After npm reports success, verify the registry and install the exact version in a clean Node.js 20 environment:
npm view @novasoft/ralph-cli@<version> version --registry=https://registry.npmjs.org/
npm install --global @novasoft/ralph-cli@<version> --registry=https://registry.npmjs.org/
ralph --version
ralph --helpThe prepublishOnly release gate checks repository cleanliness before and after linting, typechecking, a clean build, and the compiled tests. The prepack script performs another clean build before npm creates the package. GitHub Actions runs the same checks across Node.js 20, 22, and 24 on Linux, macOS, and Windows, then installs the packed CLI in a clean smoke-test job. These manual publishing instructions do not claim package provenance; only enable provenance after a CI trusted publisher has been configured and verified.
Commands
ralph init
ralph init --agent <opencode|codex> --current
ralph init --agent <opencode|codex> --worktree --branch <name> [--base-branch <name>]
ralph doctor
ralph plan [spec]
ralph approve
ralph run
ralph run --all
ralph status
ralph diff
ralph review
ralph resume [--all]
ralph abortInitialize a workspace
Run ralph init in an interactive terminal for the built-in setup quiz. It asks for the agent in this order:
- Codex
- OpenCode
It then asks whether to create a separate Git worktree. Current mode creates .ralph/config.json and .ralph/SPEC.md in the current directory. Worktree mode also asks for a new branch name and the local branch to create it from. The base-branch prompt shows main as its default; press Enter without typing to use it. Ralph creates a sibling directory named <repository>-<branch-slug> and initializes .ralph there. For example, branch feature/add-search from /work/shop creates /work/shop-feature-add-search.
The worktree flow requires the command to run inside a Git worktree whose entire worktree is clean, including untracked files. Ralph validates both branch names with git check-ref-format --branch, requires the selected base to exist as a local branch, rejects an existing sibling path, captures the selected base branch's commit, and creates the new branch from that exact commit.
If the base branch already tracks .ralph, Ralph starts a fresh plan by running git rm -r -- .ralph only inside the newly created worktree. Git removes only tracked files and refuses modified tracked content without --force. Hook-created, concurrent, untracked, and ignored files are never recursively removed; if any keep .ralph present, initialization stops and preserves the worktree and branch for manual inspection. Ralph never automatically force-removes the worktree.
Ralph prints the new absolute path and a quoted cd command, or a PowerShell Set-Location command on Windows. A CLI process cannot change the working directory of its parent shell, so run the printed command before continuing.
To skip the quiz, provide a complete explicit selection:
# Use the current directory
ralph init --agent opencode --current
# Create a sibling worktree and new branch
ralph init --agent codex --worktree --branch feature/add-search --base-branch mainExactly one of --worktree and --current is required for explicit initialization. Worktree mode requires --branch; --base-branch is optional and defaults to main. Current mode rejects both branch flags. In an interactive terminal Ralph asks only for omitted settings. With non-TTY input or output, missing settings produce an error listing the required flags instead of waiting for input.
Plan lifecycle
ralph plan never replaces unfinished work. If .ralph/PLAN.json exists, every task must have completed status and .ralph/state.json must also have completed status before a new plan can be generated. This invariant prevents accidental loss of pending, active, failed, aborted, or incompletely finalized work in both current and worktree modes. No override is available.
After a plan is complete, update .ralph/SPEC.md as needed and run ralph plan normally to replace the completed plan. The new plan still requires review and ralph approve before execution.
Review changes
ralph review compares the current repository diff with the exact approved plan. Tracked and staged changes are included in the supplied prompt, but untracked files are listed by name without Ralph reading or embedding their contents; stage a new file only after inspecting it locally if its contents should be reviewed. As described in the security model, the configured agent still runs in the repository with the current user's filesystem permissions and must be trusted not to inspect unrelated files. If .ralph/PLAN.json was edited after approval, review stops before invoking the agent or updating metrics and .ralph/RESULT.md; inspect the plan and run ralph approve again. A clean repository produces a no-op message without invoking the configured agent.
Review findings are advisory and are printed to the terminal. They do not change task status or replace the approved verification commands.
Worktree completion
Ralph does not commit, push, create a merge request, or remove a worktree automatically. When a worktree plan completes, it writes .ralph/RESULT.md and prints manual next steps equivalent to:
git status --short
git branch --show-current
git remote -v
git diff
git add --all
git diff --cached
git commit
git push -u REMOTE_NAME '<branch>'Review the status, unstaged diff, and every untracked file before staging. Review git diff --cached after staging and before committing. Then create a merge request from <branch> to the recorded base branch and use .ralph/RESULT.md as its description. Ralph intentionally does not invoke gh, glab, or another hosting CLI. Remove the linked worktree manually only after the branch is safely integrated and no longer needed.
Configuration
The generated .ralph/config.json records the selected agent and workspace mode. An OpenCode current-mode configuration is:
{
"agent": {
"preset": "opencode",
"command": "opencode",
"args": ["run"]
},
"maxIterations": 25,
"workspace": {
"mode": "current"
}
}A worktree configuration stores only portable branch metadata, never an absolute path:
{
"agent": {
"preset": "opencode",
"command": "opencode",
"args": ["run"]
},
"maxIterations": 25,
"workspace": {
"mode": "worktree",
"branch": "feature/add-search",
"baseBranch": "main"
}
}Configs created by older Ralph versions remain valid when workspace is absent.
Codex CLI preset
Install and authenticate Codex CLI, then select it while initializing a project:
npm install --global @openai/codex
codex login
ralph init --agent codex --current
ralph doctorThe generated agent configuration is:
{
"agent": {
"preset": "codex",
"command": "codex",
"args": []
},
"maxIterations": 25,
"workspace": {
"mode": "current"
}
}Ralph runs Codex non-interactively with ephemeral JSONL output. Planning and review use the read-only sandbox; implementation uses workspace-write. Prompts are passed through standard input with the - sentinel. The model can be selected through agent.args:
{
"agent": {
"preset": "codex",
"command": "codex",
"args": ["--model", "YOUR_CODEX_MODEL"]
},
"maxIterations": 25,
"workspace": {
"mode": "current"
}
}For safety, the Codex preset accepts only --model/-m, --oss, and --local-provider arguments. Ralph manages all execution, output, working-directory, and sandbox options. Use a custom agent configuration only when advanced Codex flags are required and their security implications are understood. Codex reports token usage but not monetary cost through its JSONL events, so Ralph records its cost as unavailable.
Custom agent
agent.command must be available on PATH. A custom agent receives the generated prompt through standard input and must run non-interactively:
{
"agent": {
"preset": "custom",
"command": "my-agent",
"args": ["run"]
},
"maxIterations": 25,
"workspace": {
"mode": "current"
}
}Custom agents use plain stdout and do not report token or cost metrics unless a dedicated preset is added.
maxIterations limits implementation agent calls across the entire plan, including initial task attempts and automatic repair attempts. When task or final verification fails, Ralph records the failing command and bounded stdout/stderr, passes that diagnostic context to the next agent invocation, and retries the failed task until verification passes or the limit is reached. Agent execution failures still stop immediately.
.ralph/PLAN.json
Each task has an ID, implementation description, acceptance criteria, verification commands, and one of these statuses: pending, active, completed, or failed. Verification commands are project-specific shell commands generated from the repository, such as pnpm test or npm run typecheck.
Ralph validates the relationship between task statuses and .ralph/state.json before running or reviewing work. A running state must identify exactly one active task, a completed state requires every task to be completed, and stable ready or failed states cannot retain an active task. ralph status reports a consistency warning instead of showing verification as passed when these files disagree.
Failed verification is recorded in .ralph/state.json and automatically starts another repair iteration while the configured limit permits. When maxIterations is exhausted, fix the implementation or increase the configured limit and run ralph resume --all. If you edit PLAN.json, inspect every task and command, run ralph approve again, then run ralph resume --all.
After a hard interruption, first confirm that no Ralph mutation is still active and remove run.lock only if it is stale. Inspect PLAN.json and state.json; if the current plan is still approved, ralph resume safely resets active tasks to pending, clears stale active task IDs, and continues. If an interrupted PLAN write changed the plan hash before state was saved, Ralph refuses automatic recovery; approve the inspected current plan explicitly before resuming.
