# Team Orchestration — Multi-Module Parallel Execution

> **Loaded by:** step-00 when multi-module detected (PRD_COUNT > 1)
> **Purpose:** Parallelize independent modules via Agent Teams.
> **Rule:** Single module = NO team. Only create team for 2+ modules.

---

## Mode Selection

Ralph-loop supports TWO team orchestration modes:

### 1. **Parallel Mode** (`-p` flag) — RECOMMENDED

**Architecture:** Phase 0 (entities sequential by Ralph) + Phase 1-N (teammates parallel)

**Avantages:**
- ✅ Zero EF Core ModelSnapshot conflicts (entities generated once in Phase 0)
- ✅ True parallelization on 75-85% of code (services/controllers/frontend/tests)
- ✅ Teammates have isolated contexts (no saturation)
- ✅ 2-3x faster than sequential mode
- ✅ Simple coordination (no dependency graph needed)

**When to use:**
- 2+ applications OR 5+ modules
- Complex modules with many entities
- Need guaranteed conflict-free execution

**Workflow:**
1. Ralph generates ALL entities + migration (Phase 0)
2. Ralph spawns teammates (1 per application or module)
3. Teammates generate services/controllers/frontend/tests in parallel
4. Ralph collects results + validates
5. TeamDelete

See section **Parallel Mode Protocol** below.

---

### 2. **Dependency Layer Mode** (no `-p` flag) — LEGACY

**Architecture:** Layer-by-layer execution based on dependency graph

**Avantages:**
- ✅ Respects module dependencies
- ✅ Works without `-p` flag (backward compatible)

**Inconvénients:**
- ⚠️ Requires dependency graph in feature.json
- ⚠️ EF Core ModelSnapshot conflicts possible if modules touch same entities
- ⚠️ More complex coordination

**When to use:**
- Modules have strict dependencies
- No `-p` flag specified (legacy mode)
- Single-application projects with <5 modules

See section **Dependency Layer Mode Protocol** below.

---

## Parallel Mode Protocol (if `-p` flag)

### Phase 0: Foundation (Ralph sequential)

Ralph generates ALL entities from ALL modules in ONE pass to avoid ModelSnapshot conflicts.

```javascript
// 1. Collect all entities
const allPrds = glob('.ralph/prd-*.json').map(f => readJSON(f));
const allEntities = [];
const allModules = [];

for (const prd of allPrds) {
  const entities = prd.tasks
    .filter(t => t.category === 'domain')
    .map(t => extractEntityName(t.description));

  allEntities.push(...entities);
  allModules.push({
    code: prd.project.module,
    application: prd.project.application,
    entityCount: entities.length
  });
}

console.log(`Phase 0: Generating ${allEntities.length} entities from ${allModules.length} modules`);

// 2. Invoke apex in foundation mode
// /apex --foundation -d .ralph/prd.json
//
// Apex will:
// - Generate ALL entity classes
// - Generate ALL EF configurations
// - Register ALL DbSets in DbContext
// - Create ONE migration with all entities
// - Skip services/controllers/frontend/tests

// 3. Verify build
const buildResult = bash('dotnet build');
if (buildResult.exitCode !== 0) {
  throw new Error('Phase 0 build failed');
}

// 4. Commit foundation
bash(`git add . && git commit -m "chore(foundation): entities for all modules"`);

console.log(`Phase 0 complete. ModelSnapshot contains ${allEntities.length} entities.`);
```

---

### Phase 1-N: Spawn Teammates (parallel)

Ralph creates a team and spawns teammates (1 per application OR 1 per module if app has >3 modules).

```javascript
// 1. Determine teammate granularity
const teammates = [];
const applicationsMap = {}; // group modules by application

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),
      scope: 'application'
    });
  } 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],
        scope: 'module'
      });
    }
  }
}

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

// 2. Create team
const teamName = `smartstack-${kebabCase(projectName)}`;
TeamCreate({ team_name: teamName, description: `Layer-based module orchestration for ${projectName}` });

// 3. Spawn teammates in parallel (single message, multiple Task calls)
for (const teammate of teammates) {
  const prdFiles = teammate.modules.map(m => `.ralph/prd-${m}.json`);

  Task({
    subagent_type: "apex",
    name: teammate.name,
    team_name: teamName,
    mode: "bypassPermissions",
    prompt: `
You are teammate ${teammate.name}.

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

## Phase 0 Completed (by Ralph)
ALL entity classes, EF configurations, and migrations are already created.
The ModelSnapshot is complete and the database schema is ready.

## Your Task
For each module in your scope, generate:
- Services (Application layer)
- Controllers (API layer)
- Seed data (Navigation + Permissions + RolePermissions + Business data)
- Frontend (Pages + Routes + i18n for all 4 languages)
- Tests (Unit + Integration)

## Execution
For each PRD file:
  1. INVOKE /apex -d {prdFile}
     → Apex will see existing entities and skip domain/infrastructure layers
     → Apex will generate services/controllers/seed/frontend/tests
     → Apex will run POST-CHECKs and commit per layer
  2. Verify build passes
  3. Verify tests pass

## Communication Protocol
When ALL your modules are complete:
  SendMessage({
    type: "message",
    recipient: "team-lead",
    content: "COMPLETE:${teammate.name}",
    summary: "${teammate.name} completed ${teammate.modules.join(', ')}"
  })

If you encounter a BLOCKING error:
  SendMessage({
    type: "message",
    recipient: "team-lead",
    content: "ERROR:${teammate.name}:{error_summary}",
    summary: "${teammate.name} blocked"
  })

## DO NOT
- Create new entities (already done in Phase 0)
- Create migrations (ModelSnapshot already complete)
- Modify existing entities or EF configs
    `,
    description: `${teammate.application} - ${teammate.modules.join(', ')}`
  });
}
```

---

### Collect Results

Ralph waits for all teammates to send completion messages.

```javascript
// Track completion
const expectedTeammates = teammates.length;
let completedTeammates = 0;
let errors = [];

// Messages arrive automatically via SendMessage
// When a teammate sends "COMPLETE:xxx", increment counter
// When a teammate sends "ERROR:xxx:yyy", record error

// Wait loop (teammates send messages when done)
console.log(`Waiting for ${expectedTeammates} teammates to complete...`);

// After all teammates complete (or timeout):
console.log(`Results:`);
console.log(`  ✓ Completed: ${completedTeammates}/${expectedTeammates}`);
console.log(`  ✗ Errors: ${errors.length}`);

for (const error of errors) {
  console.log(`    - ${error}`);
}
```

---

### Validation

After all teammates complete, Ralph runs global validation.

```bash
# Full solution build
dotnet build --no-restore

# Full test suite
dotnet test --no-build

# MCP validation
mcp__smartstack__validate_conventions checks=["all"]
```

---

### Cleanup

```javascript
// Shutdown teammates
for (const teammate of teammates) {
  SendMessage({
    type: "shutdown_request",
    recipient: teammate.name,
    content: "All modules complete, shutting down team"
  });
}

// Wait for shutdown confirmations, then:
TeamDelete();

console.log(`Team ${teamName} deleted. All teammates shut down.`);
```

---

## Task List Coordination (T10)

Create tasks for each module before spawning teammates:

```javascript
// Create tasks for each module before spawning teammates
for (const mod of modules) {
  TaskCreate({
    subject: `Complete ${mod.code} module`,
    description: `Generate services, controllers, frontend, and tests for ${mod.code}`,
    activeForm: `Working on ${mod.code}`
  });
}

// Teammates update task status when done
TaskUpdate({ taskId: currentTaskId, status: 'completed' });

// Team lead checks progress
TaskList(); // View all tasks and their status
```

---

## Idle State Handling (T13)

> **IMPORTANT:** Teammates go idle after every turn — this is completely normal.
> Idle simply means the teammate is waiting for input. An idle notification immediately
> after a message does NOT mean the teammate is done or has errors.
> Send a message to an idle teammate to wake it up.

---

## Team Config Discovery (T14)

```javascript
// Teammates can discover each other via team config:
// ~/.claude/teams/{team-name}/config.json
// Contains: members[] with name, agentId, agentType
// Always refer to teammates by NAME, not by UUID.
```

---

## Dependency Layer Mode Protocol (no `-p` flag — LEGACY)

### 1. Layer Detection

**For dependency layer mode only (legacy, no `-p` flag).**

Read dependency graph from master feature.json:

```javascript
const master = readJSON(MASTER_FEATURE);
const layers = master.metadata?.workflow?.dependencyGraph?.layers
            || master.dependencyGraph?.layers;

// Example layers:
// [
//   { layer: 0, modules: ["employees"], reason: "foundation" },
//   { layer: 1, modules: ["timetracking", "leavemanagement"], reason: "depends on employees" },
//   { layer: 2, modules: ["reporting"], reason: "depends on all" }
// ]

// Fallback: if no layers, treat all modules as sequential (layer 0, 1, 2...)
if (!layers) {
  const modules = queue.modules.map((m, i) => ({
    layer: i, modules: [m.code], reason: "sequential"
  }));
}
```

---

### 2. Team Setup (Legacy)

```javascript
// Create team
TeamCreate({ team_name: `ralph-${appName}`, description: `Layer-based module orchestration for ${appName}` });

// Store team context
const teamContext = {
  teamName: `ralph-${appName}`,
  layers: layers,
  currentLayer: 0,
  teammates: {}  // name → agentId mapping (populated after spawn)
};
```

---

### 3. Teammate Spawn — Per Layer (Legacy)

**For dependency layer mode only.**

For each layer, spawn teammates IN PARALLEL (single message, multiple Task calls):

```javascript
for (const layer of layers) {
  // Wait for previous layer to complete (except layer 0)
  if (layer.layer > 0) {
    // WAIT: check for MODULE_COMPLETE messages from all previous layer teammates
    // Messages are automatically delivered via SendMessage
  }

  // Spawn all modules in this layer in parallel
  for (const moduleCode of layer.modules) {
    const prdFile = `.ralph/prd-${moduleCode}.json`;
    const prdContent = readJSON(prdFile);

    Task({
      subagent_type: "general-purpose",
      team_name: `ralph-${appName}`,
      name: `mod-${moduleCode}`,
      mode: "bypassPermissions",
      prompt: TEAMMATE_PROMPT(moduleCode, prdContent),
      description: `Module ${moduleCode}`
    });
  }
}
```

---

### 4. Teammate Prompt Template (Legacy)

**For dependency layer mode only.**

Each teammate receives a self-contained prompt that delegates to `/apex`:

```
You are a Ralph Loop module worker for module "${moduleCode}".

## Your Mission
Execute ALL tasks in the PRD by delegating to /apex.
You are an ORCHESTRATOR — you NEVER generate code directly.

## PRD File
${prdFile}

## Execution
1. INVOKE `/apex -d ${prdFile}`
   → Apex handles all layers: domain → infrastructure → migration → seed data → application → api → frontend → tests
   → Apex runs POST-CHECKs, MCP validation, build verification, and commits per layer
   → Apex updates task statuses in the PRD file directly
2. After apex returns, re-read ${prdFile} to check task statuses
3. If tasks remain pending/failed, re-invoke `/apex -d ${prdFile}`

## Communication Protocol
- After apex completes and build passes:
  SendMessage({ type: "message", recipient: "team-lead", content: "LAYER_READY:${moduleCode}", summary: "${moduleCode} foundation ready" })
- When ALL tasks complete:
  SendMessage({ type: "message", recipient: "team-lead", content: "MODULE_COMPLETE:${moduleCode}", summary: "${moduleCode} complete" })
- On blocking error:
  SendMessage({ type: "message", recipient: "team-lead", content: "ERROR:${moduleCode}:{error}", summary: "${moduleCode} blocked" })

## Project Context
- Project path: ${projectPath}
- Branch: ${branch}
- Application: ${appName}
```

---

### 5. Team Lead Wait Logic (Legacy)

**For dependency layer mode only.**

After spawning a layer, the team lead waits for completion:

```javascript
// Track expected messages
const expectedMessages = layer.modules.length;
let receivedComplete = 0;
let receivedReady = 0;
let errors = [];

// Messages arrive automatically via SendMessage
// When a teammate sends "MODULE_COMPLETE:xxx", increment counter
// When a teammate sends "ERROR:xxx:yyy", record error

// For LAYER_READY: wait until all layer 0 modules signal before spawning layer 1
// For MODULE_COMPLETE: wait until all layer N modules complete before spawning layer N+1

// If error received:
//   - Log to progress.txt
//   - Decide: retry module or mark as partial
```

---

### 6. Cross-Module Verification (Legacy)

**For dependency layer mode only.**

After all layers complete, team lead runs:

```bash
# Full solution build
dotnet build --no-restore

# Full test suite
dotnet test --no-build

# MCP validation
mcp__smartstack__validate_conventions checks=["all"]
```

---

### 7. Cleanup (Legacy)

**For dependency layer mode only.**

After all modules done and report generated:

```javascript
// Shutdown all teammates
for (const [name, _] of Object.entries(teamContext.teammates)) {
  SendMessage({ type: "shutdown_request", recipient: name, content: "All modules complete" });
}

// Wait for shutdown confirmations, then:
TeamDelete();
```

---

---

## Decision Matrix

| Condition | Mode | Action |
|-----------|------|--------|
| 1 module | No team | Classic compact loop (no teams) |
| 2+ modules, `-p` flag | **Parallel Mode** | Phase 0 (Ralph entities) + spawn teammates per app/module |
| 2+ modules, no `-p`, with dependency graph | Dependency Layer Mode (legacy) | Parallel within each layer based on dependencies |
| 2+ modules, no `-p`, no dependency graph | Sequential (legacy) | Sequential layers (one module at a time) |
| Teammate error (parallel) | Continue | Log error, other teammates continue, report in step-05 |
| Teammate error (legacy) | Continue | Log, try to continue other modules |
| All modules done (parallel) | Validate + Report | Global build/test → step-05 report → TeamDelete |
| All modules done (legacy) | Validate + Report | Cross-module verify → step-05 → TeamDelete |

---

## Recommendations

| Scenario | Recommended Mode |
|----------|------------------|
| **Multi-app project** (HR + CRM + PM) | **Parallel mode** (`-p`) — 2-3x faster, zero conflicts |
| **Single-app, 5+ modules** | **Parallel mode** (`-p`) — better scalability |
| **Single-app, 2-4 modules** | Parallel mode (`-p`) OR sequential (both OK) |
| **Modules with strict dependencies** | Dependency layer mode (no `-p`) OR sequential |
| **Single module** | No teams (compact loop) |

**Default recommendation: Use `-p` for 2+ modules.**
