Skip to content

Commit 3a53a11

Browse files
Kasper Jungeclaude
authored andcommitted
refactor: extract _exit_error helper to deduplicate CLI error handling
Six call sites in cli.py repeated the same rprint("[red]...") + raise typer.Exit(1) pattern. Extracting into _exit_error() reduces each validation block by one line and makes the intent immediately clear from the function name. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 651658f commit 3a53a11

2 files changed

Lines changed: 46 additions & 12 deletions

File tree

docs/index.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,40 @@ Iteration 2 broke a test. Iteration 3 automatically received the failure output
7878

7979
---
8080

81+
## Why ralph loops?
82+
83+
A single agent conversation fills up its context window, slows down, and eventually loses the plot. Ralph loops solve this by resetting every iteration — the agent always starts fresh.
84+
85+
<div class="grid cards" markdown>
86+
87+
- :material-refresh:{ .lg .middle } **Fresh context, no decay**
88+
89+
---
90+
91+
Each iteration starts with a clean context window. No conversation bloat, no hallucinated memories, no degradation over time. The agent reads the current state of the codebase every loop.
92+
93+
- :material-shield-check-outline:{ .lg .middle } **Self-healing feedback**
94+
95+
---
96+
97+
Checks validate the agent's work after each iteration. When something breaks, the failure output feeds into the next iteration automatically — the agent fixes its own mistakes without you stepping in.
98+
99+
- :material-pencil-outline:{ .lg .middle } **Steer while it runs**
100+
101+
---
102+
103+
The prompt is re-read every iteration. Edit `RALPH.md` while the loop runs and the agent follows your new rules on the next cycle. When it does something dumb, add a sign.
104+
105+
- :material-git:{ .lg .middle } **Progress lives in git**
106+
107+
---
108+
109+
Every iteration commits to git. If something goes wrong, `git log` shows exactly what happened and `git reset` rolls it back. No opaque internal state to debug or lose.
110+
111+
</div>
112+
113+
---
114+
81115
## Three primitives
82116

83117
Ralphify extends the basic loop with three building blocks that live in the `.ralphify/` directory:

src/ralphify/cli.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
app = typer.Typer()
3838

3939

40+
def _exit_error(msg: str) -> None:
41+
"""Print an error in red and exit with code 1."""
42+
rprint(f"[red]{msg}[/red]")
43+
raise typer.Exit(1)
44+
45+
4046
BANNER_LINES = [
4147
"██████╗░░█████╗░██╗░░░░░██████╗░██╗░░██╗██╗███████╗██╗░░░██╗",
4248
"██╔══██╗██╔══██╗██║░░░░░██╔══██╗██║░░██║██║██╔════╝╚██╗░██╔╝",
@@ -99,8 +105,7 @@ def _load_config() -> dict:
99105
"""Load and return the ralph.toml config, exiting if not found."""
100106
config_path = Path(CONFIG_FILENAME)
101107
if not config_path.exists():
102-
rprint(f"[red]{CONFIG_FILENAME} not found. Run 'ralph init' first.[/red]")
103-
raise typer.Exit(1)
108+
_exit_error(f"{CONFIG_FILENAME} not found. Run 'ralph init' first.")
104109
with open(config_path, "rb") as f:
105110
return tomllib.load(f)
106111

@@ -142,14 +147,12 @@ def new(
142147
try:
143148
agent_name, agent_path = detect_agent()
144149
except RuntimeError as e:
145-
rprint(f"[red]{e}[/red]")
146-
raise typer.Exit(1)
150+
_exit_error(str(e))
147151

148152
try:
149153
install_skill("new-ralph", agent_name)
150154
except RuntimeError as e:
151-
rprint(f"[red]{e}[/red]")
152-
raise typer.Exit(1)
155+
_exit_error(str(e))
153156

154157
cmd = build_agent_command(agent_name, "new-ralph", name)
155158
os.execvp(cmd[0], cmd)
@@ -182,16 +185,13 @@ def run(
182185
toml_ralph=agent.get("ralph", "RALPH.md"),
183186
)
184187
except ValueError as e:
185-
rprint(f"[red]{e}[/red]")
186-
raise typer.Exit(1)
188+
_exit_error(str(e))
187189

188190
if not Path(ralph_file_path).exists():
189-
rprint(f"[red]Prompt file '{ralph_file_path}' not found.[/red]")
190-
raise typer.Exit(1)
191+
_exit_error(f"Prompt file '{ralph_file_path}' not found.")
191192

192193
if not shutil.which(command):
193-
rprint(f"[red]Agent command '{command}' not found on PATH.[/red]")
194-
raise typer.Exit(1)
194+
_exit_error(f"Agent command '{command}' not found on PATH.")
195195

196196
if log_dir:
197197
rprint(f"[dim]Logging output to {log_dir}/[/dim]")

0 commit comments

Comments
 (0)