May 21, 2026·5 min read·
#agentic-development#claude-code#synthex#software-delivery#ai-engineering

🔁Native Looping in Synthex: Why I Stopped Using the Ralph Plugin

I just shipped native looping in Synthex, and it's already a noticeable improvement to my loop-based workflows.

For the past few months I've been using Geoffrey Huntley's Ralph Wiggum Loop — the pattern of do $PROMPT until ($DONE_SIGNAL=true) — to drive long autonomous runs. The pattern is brilliant: when your project, prompting, and guardrails are mature enough, you can start a loop, walk away, and come back to a finished plan. It's the baker model of software delivery — set the right ingredients, set a timer, taste before serving — rather than the farmer model where you're hand-watering every row. There's an official Claude Code plugin for it, and Synthex has supported it since v0.3.6.

But over the past few weeks — especially as I leaned harder on Opus 4.7 at higher effort levels — Ralph and Synthex weren't playing as nicely together as I'd have liked. So this past weekend, I built native looping directly into Synthex.

Where Ralph Started Getting in My Way

Two failure modes kept showing up.

Ralph's stop-hook re-entry collided with Synthex's internal review loops. Ralph re-injects the prompt into a fresh agent every iteration — elegant for simple prompts, but Synthex commands like next-priority already run their own internal review loops and milestone gates. The interaction caused stalls, occasional double-execution, and missed completion signals.

Two sessions on the same project couldn't both loop. Ralph keeps state in a single .claude/ralph-loop.local.md file. No way to run, say, one autonomous build and one targeted refinement at the same time on the same repo.

I'd come back from coffee to find a loop that had broken (or hadn't broken when it should have), and the cause was almost always somewhere in that re-entry handoff.

The Design

The whole point of Synthex's orchestration layer is to know what each command is doing — a loop framework that doesn't know that is forever playing catch-up. So native looping runs inside the command: pass --loop, and the command's own instructions wrap its workflow in a tight outer loop. Single agent thread. No external coordinator. State lives at .synthex/loops/<loop-id>.json — one file per loop.

Each iteration does the same four things: check the boundary, increment-and-persist, run the real workflow, then scan its own output for a <promise>X</promise> signal to decide whether to exit or go around again.

Rendering diagram...

Because there's no second process re-injecting prompts, there's nothing to collide with the command's own review loops — the thing that was tripping up the Ralph integration simply can't happen anymore.

The state file is deliberately boring. Roughly:

json
{
"id": "release-1",
"command": "next-priority",
"iteration": 7,
"maxIterations": 30,
"completionPromise": "ALLDONE",
"status": "running",
"updatedAt": "2026-05-21T14:32:08Z"
}

That single JSON file per loop is what makes the rest of the features fall out for free.

Ralph vs. native looping

Ralph pluginSynthex native looping
Iteration mechanismStop hook re-injects the prompt into a fresh agentCommand wraps its own workflow in an outer loop
Process modelExternal coordinatorSingle in-process agent thread
StateOne shared .claude/ralph-loop.local.mdOne .synthex/loops/<id>.json per loop
Concurrent loops per repoNoYes
Aware of command internalsNoYes

What Fell Out of It

A few capabilities I'd been wanting independently were essentially free once the foundation was right:

  • Concurrent loops on the same project. Two sessions, two loop IDs, two state files. One can run next-priority --loop for an autonomous build while another runs team-review --loop against a specific change. /synthex:list-loops and /synthex:cancel-loop round out the management surface.
  • Crash-safe resume. Close your laptop or kill Claude Code mid-iteration — state persists. --resume <name> picks up where you left off; --resume-last grabs the most-recently-running loop if you don't remember the name.
  • Auto-compaction safety. State on disk, iteration work in your artifact, short iteration markers in chat. When Claude Code's auto-compaction fires, the loop survives.

Because each loop is just a named JSON file, concurrency is the natural consequence rather than a feature I had to bolt on:

Rendering diagram...

In practice:

bash
/synthex:next-priority --loop \
--completion-promise "ALLDONE" \
--max-iterations 30 \
--name release-1

next-priority does its thing — pick unblocked tasks, spin up worktrees, delegate, merge, mark done, repeat — until every task is done and the command emits <promise>ALLDONE</promise>.

What's Still Rough

Opus 4.7 still tries to be too clever. Even with native looping owning the iteration semantics, it occasionally breaks itself out of a loop to fish for a pat on the back, or because it decides I probably wouldn't have wanted it to keep going. Annoying, but I haven't had any truly broken loops since the switch. A --force or --keep-going flag is almost certainly in its future.

The full spec is in the docs — state schema, iteration loop pseudocode, the lot. If you're already using Synthex, --loop is available on the loopable commands today. If you're not, the getting started guide is the right place to start.

You'll feel the baker/farmer distinction in your bones after the first overnight run.

🔧

Synthex

Part of the LumenAI plugin marketplace

15 specialized AI agents. 11 commands. Full delivery lifecycle coverage — from brainstorming your first idea to shipping validated, reviewed, production-ready code.

Open SourceFreeClaude Code Plugin
Claude Code
1/plugin marketplace add bluminal/lumenai
2/synthex:init
3/synthex:next-priority
Try it on your next feature — you'll be surprised how fast you go from idea to working code.
👨‍💻

AJ Brown

20 years of building things for the internet. Currently making education smarter with AI at McGraw Hill. Previously securing the world's open source supply chain at Sonatype.