# How Ralph's Priority Algorithm Selects the Next User Story

> Discover how Ralph's priority algorithm selects the next user story. Learn the simple filtering and sorting process that prioritizes unfinished stories for efficient development.

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

---

**Ralph selects the next user story by filtering [`prd.json`](https://github.com/snarktank/ralph/blob/main/prd.json) for unfinished stories where `passes` is `false`, sorting them by the numeric `priority` field in ascending order (lower numbers indicate higher priority), and returning the first item in that sorted list.**

Ralph, an open-source autonomous development agent from the `snarktank/ralph` repository, uses a deterministic priority-based selection method to decide which feature to implement next. Understanding Ralph's priority algorithm for story selection is essential for teams structuring their Product Requirements Documents (PRDs) to ensure critical functionality gets built first.

## How the Priority Algorithm Works

The algorithm follows a straightforward four-step process encoded in Ralph's core instructions:

1. **Load the PRD**: Ralph reads [`prd.json`](https://github.com/snarktank/ralph/blob/main/prd.json) (or the JSON generated by the PRD skill) containing the `userStories` array.
2. **Filter incomplete work**: It filters the array to retain only entries where `"passes": false`.
3. **Sort by priority**: It sorts the remaining stories by their `priority` value in **ascending** numerical order, where a lower integer represents higher business priority.
4. **Select the winner**: It returns the first story from the sorted results—the highest-priority unfinished item.

### Handling Ties

When two stories share identical priority values, Ralph preserves JSON order and selects whichever appears first in the filtered list. This deterministic tie-breaker ensures consistent, repeatable behavior across iterations.

## Source Code Implementation

The selection logic is explicitly defined in Ralph's instruction files rather than buried in complex code:

- In **[`prompt.md`](https://github.com/snarktank/ralph/blob/main/prompt.md)**, the directive states: "Pick the **highest priority** user story where `passes: false`" (lines 10-11).
- In **[`README.md`](https://github.com/snarktank/ralph/blob/main/README.md)**, the workflow step reads: "Pick the highest priority story where `passes: false`" (lines 124-125).

These files demonstrate that Ralph treats story selection as a data-driven decision based strictly on the PRD's metadata fields, making the [`prd.json`](https://github.com/snarktank/ralph/blob/main/prd.json) structure the single source of truth for work sequencing.

## Practical Code Examples

You can replicate Ralph's selection logic locally to preview which story the agent will tackle next.

### JavaScript Implementation

```javascript
import { readFileSync } from 'fs';

// Load the PRD
const prd = JSON.parse(readFileSync('prd.json', 'utf-8'));

// Filter unfinished stories, sort by priority ascending, pick first
const nextStory = prd.userStories
  .filter(story => story.passes === false)
  .sort((a, b) => a.priority - b.priority)[0];

if (nextStory) {
  console.log(`Next: ${nextStory.title} (Priority: ${nextStory.priority})`);
} else {
  console.log('All stories have passed—Ralph is done!');
}

```

### Bash and jq One-Liner

```bash
jq -r '
  .userStories
  | map(select(.passes == false))
  | sort_by(.priority)
  | .[0]
  | "ID: \(.id)\nTitle: \(.title)\nPriority: \(.priority)"
' prd.json

```

Both snippets mirror the exact filter-then-sort-by-priority-ascending logic implemented in the `snarktank/ralph` source files.

## Summary

- Ralph reads **[`prd.json`](https://github.com/snarktank/ralph/blob/main/prd.json)** to access the `userStories` array defined in **`prd.json.example`**.
- **Unfinished stories** (where `passes: false`) are candidates for selection.
- The algorithm sorts by **ascending priority** values, meaning priority 1 outranks priority 5.
- The first item after sorting becomes the active development target.
- Ties defer to JSON document order for deterministic selection.

## Frequently Asked Questions

### Does Ralph support weighted priorities or MoSCoW classification?

No. According to the `snarktank/ralph` source code, Ralph expects simple numeric priorities where lower integers indicate higher urgency. The algorithm performs a basic ascending sort on the `priority` field without supporting textual classifications like "Must have" or "Should have."

### What happens if all user stories have `passes: true`?

If every story in [`prd.json`](https://github.com/snarktank/ralph/blob/main/prd.json) has `"passes": true`, the filter step returns an empty array. Ralph will have no candidate stories to sort or select, effectively signaling that the project is complete or awaiting new requirements in the PRD.

### Can I use negative numbers or decimals for priority values?

The algorithm performs a numeric sort, so negative numbers and decimals are technically valid. However, Ralph's documentation in [`README.md`](https://github.com/snarktank/ralph/blob/main/README.md) suggests using positive integers starting from 1 for clarity, as this matches the standard convention referenced in the priority algorithm description.

### Where is the selection logic actually executed?

While the algorithm is documented in [`prompt.md`](https://github.com/snarktank/ralph/blob/main/prompt.md) and [`README.md`](https://github.com/snarktank/ralph/blob/main/README.md), the actual execution depends on the Amp AI tool processing these instructions. The logic is prompt-based rather than hardcoded in a specific function file, making the PRD structure itself the controlling authority for Ralph's workflow.