# What Is the `<promise>COMPLETE</promise>` Signal in Ralph and How Does It End the Loop?

> Understand the COMPLETE signal in Ralph, an AI-emitted token that concludes iteration loops with exit status 0 once all user stories are done. Learn how Ralph manages loop termination.

- Repository: [Ryan Carson/ralph](https://github.com/snarktank/ralph)
- Tags: internals
- Published: 2026-04-13

---

**The `<promise>COMPLETE</promise>` token is an XML-style signal that the AI emits when all user stories are marked complete, causing the [`ralph.sh`](https://github.com/snarktank/ralph/blob/main/ralph.sh) orchestration script to terminate the iteration loop with exit status 0.**

Ralph is an autonomous AI-agent loop that repeatedly invokes coding tools like Amp or Claude Code until every user story in the Product Requirements Document (PRD) satisfies the condition `passes: true`. The `<promise>COMPLETE</promise>` string serves as the deterministic handshake between the AI's generated output and the shell orchestration, eliminating ambiguity about when the autonomous run should conclude.

## Understanding the `<promise>COMPLETE</promise>` Signal

### Definition and Purpose

The **completion signal** is a literal XML-style token that the AI must output verbatim once it determines that zero user stories remain incomplete. Unlike implicit state flags or external API calls, this signal lives purely in the stdout text stream generated by the coding tool. It acts as an explicit assertion from the AI that its task list is fully satisfied and no further iterations are necessary.

According to the Ralph source code, this design choice keeps the orchestration stateless and tool-agnostic—the shell script does not parse JSON or maintain databases; it simply scans text for a unique, unlikely-to-occur-accidentally string.

### Where It Is Defined (prompt.md)

The behavior is enforced in [`prompt.md`](https://github.com/snarktank/ralph/blob/main/prompt.md) (lines 94–100), which contains the system instructions telling the AI exactly when and how to emit the token:

```markdown

## Stop Condition

After completing a user story, check if ALL stories have `passes: true`.

If ALL stories are complete and passing, reply with:
<promise>COMPLETE</promise>

```

This prompt section effectively hard-codes the stop condition into the AI's context window. The AI evaluates its ownprogress after each story, and only when the aggregate status shows every story passing does it append the magic token to its final output.

## How the Signal Ends the Ralph Loop

### Detection Logic in ralph.sh (Lines 98–103)

The orchestration logic resides in [`ralph.sh`](https://github.com/snarktank/ralph/blob/main/ralph.sh), the main Bash entry point that manages the iteration lifecycle. After each invocation of the underlying tool (Amp or Claude Code), the script captures stdout and searches for the completion token using `grep`:

```bash

# Run the tool and capture output while preserving visibility

OUTPUT=$(cat "$SCRIPT_DIR/prompt.md" | amp --dangerously-allow-all 2>&1 | tee /dev/stderr)

# Detect completion signal

if echo "$OUTPUT" | grep -q "<promise>COMPLETE</promise>"; then
  echo "Ralph completed all tasks!"
  exit 0
fi

```

The `grep -q` test performs a silent match. If the token is absent, the script falls through to the next iteration of the `for` loop, up to a configurable maximum limit.

### The Exit Condition

When the `<promise>COMPLETE</promise>` string is detected, the script immediately:

1. Prints a confirmation message to stderr/stdout
2. Calls `exit 0`, which terminates the entire Ralph process with a success status
3. Skips all remaining iterations of the loop

If the token is never found, the loop continues until the hard-coded iteration ceiling is reached, at which point Ralph exits with a non-zero or timeout status to indicate incomplete work.

## Code Examples

### Example 1: Prompt Instruction Defining Emission Criteria

This excerpt from the system prompt establishes the contract with the AI:

```markdown

## Stop Condition

After completing a user story, check if ALL stories have `passes: true`.

If ALL stories are complete and passing, reply with:
<promise>COMPLETE</promise>

```

*Source: [`prompt.md`](https://github.com/snarktank/ralph/blob/main/prompt.md), lines 94–100*

### Example 2: Bash Implementation of Signal Detection

The concrete implementation in the orchestration script:

```bash
#!/usr/bin/env bash

for i in $(seq 1 $MAX_ITERATIONS); do
  echo "--- Iteration $i ---"

  # Pipe prompt to tool and capture full output

  OUTPUT=$(cat "$SCRIPT_DIR/prompt.md" | amp --dangerously-allow-all 2>&1 | tee /dev/stderr)

  # Terminate loop if AI signals completion

  if echo "$OUTPUT" | grep -q "<promise>COMPLETE</promise>"; then
    echo "Ralph completed all tasks!"
    exit 0
  fi

  # Otherwise continue to next iteration

done

echo "Reached maximum iterations without completion signal"
exit 1

```

*Source: [`ralph.sh`](https://github.com/snarktank/ralph/blob/main/ralph.sh), lines 98–103*

### Example 3: AI Output That Triggers Termination

A typical stdout fragment that would cause the loop to exit:

```text
Successfully implemented user story #5: Add input validation.

All user stories have passed their tests.

<promise>COMPLETE</promise>

```

When [`ralph.sh`](https://github.com/snarktank/ralph/blob/main/ralph.sh) scans this output, the `grep` match succeeds, the script hits `exit 0`, and the autonomous run concludes cleanly.

## Summary

- **`<promise>COMPLETE</promise>`** is an XML-style token that acts as an explicit completion signal between the AI agent and the Ralph orchestrator.
- The signal is defined in **[`prompt.md`](https://github.com/snarktank/ralph/blob/main/prompt.md)** (lines 94–100), which instructs the AI to emit the token only when every user story has `passes: true`.
- **[`ralph.sh`](https://github.com/snarktank/ralph/blob/main/ralph.sh)** (lines 98–103) detects the token using `grep` and terminates the Bash loop with `exit 0` upon detection.
- The mechanism is stateless and requires no external databases or APIs—only stdout text parsing.
- Failure to emit the token results in the loop continuing until the maximum iteration limit is exhausted.

## Frequently Asked Questions

### What happens if the AI forgets to emit the `<promise>COMPLETE</promise>` token?

If the AI omits the token, [`ralph.sh`](https://github.com/snarktank/ralph/blob/main/ralph.sh) will not trigger the early exit condition and will continue looping until it reaches the maximum iteration count defined by the user. Once the ceiling is hit, the script exits with an error status, alerting the user that the task list may be incomplete despite the AI finishing its code generation.

### Can I change the completion signal to a different string?

Yes, although it requires modifying two files. You must update the instruction in **[`prompt.md`](https://github.com/snarktank/ralph/blob/main/prompt.md)** (lines 94–100) to tell the AI the new token format, and simultaneously update the **`grep`** pattern in [`ralph.sh`](https://github.com/snarktank/ralph/blob/main/ralph.sh) (lines 98–103) to match the new string. The token is not configurable via environment variables in the current implementation.

### Why use an XML-style tag instead of a JSON object?

The Ralph authors chose a simple XML-style tag because it is easy to `grep` for and unlikely to appear accidentally in code diffs or natural language explanations. JSON would require parsing logic (e.g., `jq`) and could be fragmented across multiple lines of output, whereas the literal string `<promise>COMPLETE</promise>` is atomic and unambiguous in a text stream.

### Does the `<promise>COMPLETE</promise>` token get written to any log files?

The token appears in the stdout of the AI tool, which [`ralph.sh`](https://github.com/snarktank/ralph/blob/main/ralph.sh) tees to stderr during execution via the `tee /dev/stderr` command. This means it appears in your terminal output and any shell redirections you have configured, but Ralph does not explicitly append it to a separate log file unless you redirect the script's output manually.