# How the Ralph Persistent Evolutionary Loop Survives Session Boundaries in Ouroboros

> Discover how Ouroboros' Ralph persistent evolutionary loop survives session boundaries using event sourcing and stateless architecture to reconstruct state from the EventStore.

- Repository: [Q00/ouroboros](https://github.com/Q00/ouroboros)
- Tags: internals
- Published: 2026-03-14

---

**The Ralph persistent evolutionary loop achieves cross-session durability through event sourcing and a stateless architecture that reconstructs lineage state from an append-only EventStore rather than maintaining long-running process memory.**

The Ouroboros repository implements an autonomous ontology evolution system where **Ralph** serves as the "always-on" driver that repeatedly invokes the evolutionary step function until convergence. Unlike traditional long-running daemons, Ralph’s persistent evolutionary loop is engineered to survive crashes, restarts, and manual interruptions without data loss.

## Stateless Architecture: Fresh Processes per Cycle

Ralph operates on a **stateless cycle** design where each iteration executes in a fresh Python process. The primary entry point, [`scripts/ralph.py`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph.py), contains the `connect_and_run` function which establishes a stdio connection to the MCP server and the `_call_evolve` helper that dispatches `ouroboros_evolve_step` calls.

Because the script never maintains long-lived state between iterations, it only receives the JSON result of the latest evolution step and decides whether to:

- **Continue** to the next generation
- **Retry** via `ouroboros_lateral_think` when stagnation is detected  
- **Terminate** when convergence is reached

This statelessness ensures that killing the process at any point never corrupts the evolutionary lineage.

## Event Sourcing with EventStore

All actions performed during evolution are persisted as **immutable events** in the `EventStore` located at [`src/ouroboros/persistence/event_store.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/persistence/event_store.py). The store utilizes an append-only log architecture, meaning every seed creation, tool execution, QA verdict, and evolution step becomes a permanent, timestamped record.

The `EventStore` enables **complete lineage reconstruction** through event replay. When Ralph restarts, it does not restore from a snapshot; instead, the system reads the entire event history to rebuild the current state deterministically.

## Lineage-Based Session Continuity

Each evolutionary run is identified by a unique **lineage ID** that bridges session boundaries. The persistence mechanism works as follows:

1. The first generation creates a `lineage.created` event
2. Subsequent generations append `evolve_step.completed` events  
3. The MCP tool handler in [`src/ouroboros/mcp/tools/definitions.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/mcp/tools/definitions.py) processes these events to determine the next state

When Ralph is restarted with an existing `--lineage-id`, the next `ouroboros_evolve_step` call receives the same identifier, the MCP server reads the existing events from the store, and the loop continues from the last successful generation. This design allows Ralph to "pick up where it left off" transparently after system crashes or manual restarts.

## Convergence Detection and Loop Control

The evolutionary loop terminates based on semantic similarity metrics returned by each step. The `ouroboros_evolve_step` tool returns a markdown block containing an `**Action**` field with three possible values:

- `continue` – Proceed to next generation
- `stagnated` – Trigger lateral thinking or retry logic  
- `converged` – Exit the loop with code 0

Convergence is achieved when the similarity score reaches **≥ 0.95**, indicating the ontology has stabilized across generations.

## Git Tagging and Rewind Capabilities

While the **EventStore** serves as the authoritative source of truth, [`scripts/ralph.sh`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph.sh) provides optional git tagging for human-readable checkpoints. After every successful generation, the `tag_generation` function creates a tag formatted as `ooo/{lineage_id}/gen_{N}`.

For recovery scenarios, [`scripts/ralph-rewind.py`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph-rewind.py) implements the `ouroboros_evolve_rewind` tool. This utility reads the `EventStore` to locate a target generation and can optionally checkout the corresponding git tag, enabling precise rollback to any point in the evolutionary history.

## Practical Usage Example

Initialize a persistent Ralph loop with a seed file and maximum cycle limit:

```bash
ooo ralph \
    --lineage-id my_lineage \
    --seed-file examples/dummy_seed.yaml \
    --max-cycles 50

```

During execution, [`ralph.py`](https://github.com/Q00/ouroboros/blob/main/ralph.py) prints JSON status objects to stdout. A typical mid-run response appears as:

```json
{
  "action": "continue",
  "generation": 3,
  "lineage_id": "my_lineage",
  "similarity": 0.87,
  "next_generation": 4,
  "lateral_think_applied": false,
  "qa": {"verdict":"pass","score":92.3,"error":null},
  "error": null
}

```

Upon reaching the convergence threshold, the output changes to:

```json
{
  "action": "converged",
  "generation": 7,
  "lineage_id": "my_lineage",
  "similarity": 0.96,
  "next_generation": null,
  "lateral_think_applied": false,
  "qa": {"verdict":"pass","score":95.0,"error":null},
  "error": null
}

```

If the process terminates after generation 4 and is later restarted with the same `--lineage-id`, Ralph queries the `EventStore`, reconstructs the state through generation 4, and automatically issues the next `evolve_step` call with `generation=5`.

## Summary

- **Stateless design**: Each Ralph cycle runs in a fresh process via [`scripts/ralph.py`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph.py), eliminating memory-related failure modes.
- **Event sourcing**: The `EventStore` in [`src/ouroboros/persistence/event_store.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/persistence/event_store.py) maintains an append-only log of all evolutionary events.
- **Lineage continuity**: Unique lineage IDs bind generations across sessions, with state reconstruction handled by the MCP tool in [`src/ouroboros/mcp/tools/definitions.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/mcp/tools/definitions.py).
- **Convergence criteria**: The loop exits when similarity scores reach 0.95 or higher, signaled through the `action` field in step results.
- **Recovery tools**: [`scripts/ralph-rewind.py`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph-rewind.py) and [`scripts/ralph.sh`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph.sh) provide git-based checkpointing and temporal rollback capabilities.

## Frequently Asked Questions

### How does Ralph resume after a system crash?

Ralph resumes by reconstructing state from the `EventStore` rather than restoring from memory. When restarted with the same `--lineage-id`, the `ouroboros_evolve_step` handler in [`src/ouroboros/mcp/tools/definitions.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/mcp/tools/definitions.py) replays all `lineage.created` and `evolve_step.completed` events to determine the current generation, then continues execution from that point.

### What convergence threshold stops the evolutionary loop?

The loop terminates when the `similarity` field in the step response reaches **0.95 or higher**, triggering an `action` value of `converged`. This causes [`scripts/ralph.py`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph.py) to exit with status code 0.

### Can I rewind to a specific previous generation?

Yes. Execute [`scripts/ralph-rewind.py`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph-rewind.py) with the target lineage and generation number. This script invokes the `ouroboros_evolve_rewind` MCP tool, which queries the `EventStore` to validate the generation exists and can optionally checkout the corresponding `ooo/{lineage_id}/gen_{N}` git tag created by [`scripts/ralph.sh`](https://github.com/Q00/ouroboros/blob/main/scripts/ralph.sh).

### Why does Ouroboros use event sourcing instead of a traditional database?

Event sourcing in [`src/ouroboros/persistence/event_store.py`](https://github.com/Q00/ouroboros/blob/main/src/ouroboros/persistence/event_store.py) provides immutable audit trails and deterministic replay capabilities required for reproducible ontology evolution. Unlike mutable database records, the append-only event log guarantees that any session can be reconstructed identically across different machines or after catastrophic failures, which is essential for the Ralph persistent evolutionary loop’s reliability guarantees.