---
name: step-01-task
description: Load or create tasks from prd.json (v3 unified or v2 legacy)
next_step: steps/step-02-execute.md
---

# Step 1: Load Task

> **MODULE TRANSITION CHECK:** Before "Only Read Once" rule, check for module transition:

```javascript
if (fileExists('.ralph/module-changed.json')) {
  const t = readJSON('.ralph/module-changed.json');
  console.log(`Module transition: ${t.fromModule} → ${t.toModule}`);
  deleteFile('.ralph/module-changed.json');
  // PROCEED (exception to "Only Read Once" rule)
}
```

> **CONTEXT OPTIMIZATION:** Read ONCE per module (first iteration).
> Iterations > 1 within same module → use COMPACT LOOP in step-04.
> Re-read ONLY on module transition (module-changed.json detected above).

## YOUR TASK:

Load task from prd.json or create initial task breakdown with categories, dependencies, and acceptance criteria.

---

## 0. Multi-Module Queue Check

```javascript
const queuePath = '.ralph/modules-queue.json';
if (fileExists(queuePath)) {
  const queue = readJSON(queuePath);
  const currentModule = queue.modules[queue.currentIndex];
  console.log(`Multi-module: ${currentModule.code} (${queue.currentIndex + 1}/${queue.totalModules})`);

  {modules_queue} = queue;
  {current_module} = currentModule.code;

  // Verify PRD matches current module
  const currentPrd = readJSON('.ralph/prd.json');
  if (currentPrd.metadata?.moduleCode !== currentModule.code) {
    const modulePrd = readJSON(currentModule.prdFile);

    // v3 FAST PATH: unified PRD from ss derive-prd (tasks pre-computed)
    if (modulePrd.$version === '3.0.0') {
      // Inject runtime fields and use directly
      modulePrd.status = 'in_progress';
      modulePrd.feature = `${modulePrd.project?.module || currentModule.code} (${modulePrd.project?.application || 'app'})`;
      modulePrd.created = modulePrd.created || new Date().toISOString();
      modulePrd.updated_at = new Date().toISOString();
      modulePrd.config = modulePrd.config || { max_iterations: {max_iterations}, completion_promise: "{completion_promise}", current_iteration: 1 };
      modulePrd.metadata.branch = modulePrd.metadata.branch || getCurrentBranch();
      modulePrd.metadata.project_path = modulePrd.metadata.project_path || process.cwd();
      modulePrd.metadata.mcp_servers = modulePrd.metadata.mcp_servers || { smartstack: true, context7: true };
      modulePrd.history = modulePrd.history || [];
      writeJSON('.ralph/prd.json', modulePrd);
    }
    // LEGACY: FORMAT A (no $version) — transform + warning
    else if (modulePrd.project && modulePrd.requirements && !modulePrd.$version) {
      console.warn('⚠ DEPRECATED: FORMAT A prd.json detected. Re-run `ss derive-prd` to generate v3 format.');
      writeJSON('.ralph/prd.json', transformPrdJsonToRalphV2(modulePrd, currentModule.code));
    }
    // v2 legacy or already runtime format
    else {
      writeJSON('.ralph/prd.json', modulePrd);
    }
  }
} else {
  {modules_queue} = null;
  {current_module} = null;
}
```

## PrdJson → Ralph v2 Transformation (DEPRECATED)

> **DEPRECATED:** This transformation is a fallback for old FORMAT A PRDs (pre-v3.9.0).
> New PRDs generated by `ss derive-prd` use unified v3 format with pre-computed tasks.
> This function will be removed in a future release.

See [references/task-transform-legacy.md](../references/task-transform-legacy.md) for the full `transformPrdJsonToRalphV2()` function including:
- Layer-ordered task generation (domain → infra → app → api → frontend → seedData → tests)
- Consolidated frontend + i18n tasks
- Guardrails 1d-1j (inject missing infrastructure, API, frontend, tests, seed data, migration)

---

## 1. Check for Existing prd.json

If `.ralph/prd.json` exists:
1. Read the PRD
2. **v3 FAST PATH:** If `$version === "3.0.0"` AND `tasks[]` exists:
   - Inject runtime fields if missing (status, config, feature, created, updated_at, history)
   - Write back to `.ralph/prd.json`
   - Skip directly to section 5 (find next task)
3. **v2 legacy:** If `$version === "2.0.0"` → find next eligible task (section 5), skip to section 5
4. **FORMAT A (deprecated):** If `.project && .requirements && !.$version` → run `transformPrdJsonToRalphV2()` → section 5

If `.ralph/prd.json` does not exist: continue to section 2.

## 2. Analyze Task Description

Check for BA handoff source (priority):
1. Per-module PRD files (handled by section 0)
2. Single prd.json already present
3. Markdown handoff: `find . -path "*development-handoff*" -name "*.md"`
4. Direct task from `{task_description}`

Generate **3-30 subtasks** by category (domain → infrastructure → application → api → frontend → i18n → test → validation).

## 3. Create prd.json

Write `.ralph/prd.json` with all tasks (every task MUST have: id, description, status, category, dependencies, acceptance_criteria, started_at, completed_at, iteration, commit_hash, files_changed, validation, error).

Initialize `.ralph/progress.txt`:
```markdown
# Ralph Loop Progress
## Task: {task_description}
## Started: {timestamp}
## Schema: v3.0.0
```

## 4. Validate Task Integrity

- All tasks have required fields
- Dependency references are valid (exist, no forward/circular)
- Task count 3-30

## 5. Find Current Task

```javascript
function findNextTask(tasks) {
  for (const task of tasks) {
    if (task.status !== 'pending') continue;
    const depsBlocked = task.dependencies.some(d => {
      const dep = tasks.find(t => t.id === d);
      return dep && (dep.status === 'failed' || dep.status === 'blocked');
    });
    if (depsBlocked) { task.status = 'blocked'; task.error = 'Blocked by failed dependency'; continue; }
    const depsOk = task.dependencies.every(d => tasks.find(t => t.id === d)?.status === 'completed');
    if (depsOk) return task;
  }
  return null;
}
```

If no eligible task: all completed → step-05, all blocked → step-05, else STOP.

## 6. Show Task Status

```
[{iteration}/{max}] {completed}/{total} done | Task [{id}] {description} ({category})
-> Executing...
```

---

## NEXT STEP:

After task loaded, proceed to `./step-02-execute.md`
