# Parallel Execution Mode (Agent Teams)

> **Reference for:** step-02-execute.md section 3a
> **Trigger:** `-p` flag OR `{parallel_mode} == true`
> **Applicability:** Multi-module only (2+ modules)

---

## Overview

When Ralph detects 2+ modules with `-p` flag:

1. **Phase 0 (Ralph sequential):** Generate ALL entities from ALL modules + ONE migration
2. **Phase 1-N (Teams parallel):** Spawn teammates per application/module for services/controllers/frontend/tests
3. **Cleanup:** Collect results, validate, TeamDelete

---

## Phase 0: Foundation (Sequential)

### 1. Collect All Entities

```javascript
const allEntities = [];
const allModules = [];
for (const prdFile of glob('.ralph/prd-*.json')) {
  const modulePrd = readJSON(prdFile);
  const moduleEntities = modulePrd.tasks
    .filter(t => t.category === 'domain')
    .map(t => extractEntityName(t.description));
  allEntities.push(...moduleEntities);
  allModules.push({
    code: modulePrd.project.module,
    application: modulePrd.project.application,
    prdFile: prdFile,
    entityCount: moduleEntities.length
  });
}

console.log(`PARALLEL MODE: Phase 0 — Foundation`);
console.log(`  Generating ${allEntities.length} entities from ${allModules.length} modules`);
console.log(`  Entities: ${allEntities.join(', ')}`);
```

### 2. Invoke /apex --foundation

Ralph invokes `/apex --foundation -d .ralph/prd.json` which:
- Generates ALL entity classes
- Generates ALL EF configurations
- Registers ALL DbSets in DbContext
- Creates ONE migration with all entities
- **SKIPS** services/controllers/frontend/tests

```bash
/apex --foundation -d .ralph/prd.json
```

### 3. Commit Foundation

```bash
git add .
git commit -m "chore(foundation): entities for all modules

$(allModules.map(m => m.code).join(' + ')) — ${allEntities.length} entities

Co-Authored-By: Claude AI <noreply@anthropic.com>"
```

Result: ModelSnapshot contains all entities. Database ready for application layers.

---

## Phase 1-N: Parallel Teams

### 1. Determine Teammate Granularity

Applications can have 1-N modules. Teammate strategy:

```javascript
const teammates = [];
const applicationsMap = {}; // { appName: [module1, module2, ...] }

for (const mod of allModules) {
  if (!applicationsMap[mod.application]) {
    applicationsMap[mod.application] = [];
  }
  applicationsMap[mod.application].push(mod);
}

for (const [appName, modules] of Object.entries(applicationsMap)) {
  if (modules.length <= 3) {
    // 1 teammate per APPLICATION
    teammates.push({
      name: `apex-${kebabCase(appName)}`,
      application: appName,
      modules: modules.map(m => m.code),
      prdFiles: modules.map(m => m.prdFile)
    });
  } else {
    // Application has >3 modules → 1 teammate per MODULE
    for (const mod of modules) {
      teammates.push({
        name: `apex-${kebabCase(appName)}-${kebabCase(mod.code)}`,
        application: appName,
        modules: [mod.code],
        prdFiles: [mod.prdFile]
      });
    }
  }
}

console.log(`Spawning ${teammates.length} teammates:`);
for (const t of teammates) {
  console.log(`  - ${t.name}: ${t.modules.join(', ')}`);
}
```

### 2. Create Team

```javascript
TeamCreate({
  team_name: `smartstack-${kebabCase(prd.project.name || 'project')}`,
  description: `Parallel development for ${teammates.length} modules`
});
```

### 3. Spawn Teammates

```javascript
for (const teammate of teammates) {
  Task({
    subagent_type: "apex",
    name: teammate.name,
    team_name: `smartstack-${kebabCase(prd.project.name || 'project')}`,
    prompt: `
You are teammate ${teammate.name}.

CONTEXT:
- Application: ${teammate.application}
- Modules: ${teammate.modules.join(', ')}
- PRD files: ${teammate.prdFiles.join(', ')}

ENTITIES ALREADY EXIST (Phase 0 completed):
All entity classes, EF configurations, and migrations are complete.
The ModelSnapshot is complete and the database is ready.
DO NOT attempt to create entities or migrations.

YOUR TASK:
For each module in ${teammate.modules}, generate:
- Services (Application layer)
- Controllers (API layer)
- Seed data (Navigation + Permissions + Business data)
- Frontend (Pages + Routes + i18n for all 4 languages)
- Tests (Unit + Integration)

DO NOT:
- Create new entities (already done in Phase 0)
- Create migrations (ModelSnapshot already complete)
- Modify DbContext (already done in Phase 0)

EXECUTE:
For each PRD file:
**INVOKE `/apex -d {prdFile}`**
Apex will detect existing entities and skip domain/infrastructure layers.

When done, send a message to team lead with results:
{
  "type": "completion",
  "teammate": "${teammate.name}",
  "status": "complete" | "failed",
  "modules": ${JSON.stringify(teammate.modules)},
  "summary": "Brief summary of what was generated"
}
    `
  });
}
```

### 4. Wait for Teammates

Ralph waits for all teammates to send completion messages via `TaskOutput`.

> **How messaging works in Claude Code Agent Teams:**
> - Teammates communicate by calling `SendMessage({ recipient: "team-lead", content: ... })`
> - Ralph (team lead) receives messages automatically — there is NO polling loop
> - Each message delivery triggers a new turn for Ralph
> - Ralph stays idle between messages — this is normal behavior (not a hang)
> - An idle notification does NOT mean the teammate has finished or failed

```javascript
// Track expected completions (set before spawning)
const expectedCount = teammates.length;
const results = []; // populated as SendMessage notifications arrive

// Ralph's response to each incoming message:
// - Parse content: "complete" | "failed"
// - Push to results[]
// - If results.length === expectedCount → proceed to section 5
// - If "failed": log error, continue waiting for other teammates

// If a teammate goes silent > 30 min:
// → Send it a wake-up message (idle is normal, silence is not)
// → If no response after 2 retries: mark as "timed-out" and continue

console.log(`Waiting for ${expectedCount} teammates...`);
// (Ralph is idle here — woken up by each incoming SendMessage)
```

### 5. Collect & Validate Results

```javascript
const completedTeammates = teamMateResults.filter(r => r.status === 'complete').length;
const failedTeammates = teamMateResults.filter(r => r.status === 'failed').length;

console.log(`Phase 1-N completed:`);
console.log(`  ✅ ${completedTeammates} teammates succeeded`);
console.log(`  ❌ ${failedTeammates} teammates failed`);
console.log(`  ⏱ ${teammates.length - teamMateResults.length} teammates did not respond`);
```

### 6. Cleanup Team

```javascript
TeamDelete();
```

---

## Fallback (Non-Parallel)

If `-p` flag NOT set OR only 1 module detected:

- **Single module:** Ralph executes compact loop normally (no teams)
- **Multi-module (no -p):** Check for dependency graph in feature.json
  - If graph exists → Classic Agent Teams (layered approach)
  - If no graph → Sequential compact loop per module

---

## Rules

- **Phase 0 is sequential:** Ralph must complete foundation first
- **Phase 1-N is parallel:** Teammates execute in parallel
- **No entity duplication:** Phase 1 teammates skip domain/infrastructure
- **Timeout:** 1 hour per phase (configurable)
- **Partial success OK:** If some teammates fail, continue validation
