Installs into .claude/skills of the current project.
Are you the author of Parallel Orchestration?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/pmdevsolutions-parallel-orchestration)
---
name: parallel-orchestration
description: Concurrent phase runner that dispatches independent pipeline phases in parallel, respecting dependency graphs and resource constraints
globs:
- ".claude/pipeline.config.json"
- ".claude/commands/build-from-*.md"
---
# Parallel Orchestration
## Overview
A concurrent phase scheduler that dispatches independent pipeline phases in parallel using background agents. It reads the phase dependency graph and resource constraints from `pipeline.config.json`, determines which phases can safely run concurrently, and schedules them up to the configured `maxConcurrent` limit. Phases with unmet dependencies or conflicting exclusive resources are held until their prerequisites complete and resources free up.
The scheduler produces real-time streaming output as phases start and finish, and a final batch summary with wall-clock timing, estimated sequential time, and speedup factor.
## When to Use
- **Pipeline invocation:** Called by `/build-from-figma`, `/build-from-canva`, and `/build-from-screenshot` after the sequential phases (0-3: token-sync, intake, token-lock, tdd-scaffold) complete. Phases 4+ are handed to this skill for parallel dispatch.
- **Standalone:** Invoke directly for ad-hoc parallel work by providing a list of independent tasks.
## Input
1. **Phase IDs** -- ordered list of phase IDs to execute (e.g., `["component-build", "storybook", "visual-diff", "dark-mode", "e2e-tests", "cross-browser", "quality-gate", "responsive", "report"]`).
2. **Prior context** -- artifacts from earlier sequential phases:
- `build-spec.json` (component list, appType, `renderer`, E2E flows)
- `design-tokens.lock.json` (locked token values)
- Test files from tdd-scaffold phase
3. **Pipeline config** -- `.claude/pipeline.config.json`, specifically the `orchestration` section.
4. **Renderer manifest** -- the resolved manifest for the build-spec's `renderer`, used to drop excluded phases and select the converter (see Step 0 and Step 5).
## Algorithm
### Step 0: Resolve Renderer and Exclude Phases
Before scheduling, read `renderer` from `build-spec.json` and resolve its manifest:
```bash
node scripts/renderer-registry.js resolve <renderer> --json
```
Read `manifest.phases.exclude` (an array, absent/empty for most renderers) and **drop every listed phase from the requested phase set before building the dependency graph.** Excluded phases never enter the scheduler — they are not dispatched, not tracked, and not awaited.
Example: the `expo` renderer excludes `visual-diff`, `cross-browser`, `responsive`, and `dark-mode` (no browser rendering), so those phases are removed up front and only `component-build`, `storybook`, `e2e-tests`, `quality-gate`, and `report` schedule. When a dependent phase's dependency was excluded, treat that dependency as pre-satisfied (same as a phase completed externally).
This replaces any per-framework phase-skipping logic — the manifest is the single source of truth for which phases a renderer supports.
### Step 1: Load Configuration
Read `.claude/pipeline.config.json` and extract the `orchestration` section:
- `maxConcurrent` -- maximum number of phases running at once (default: 3)
- `phases` -- dependency graph, resource declarations, blocking flags
- `qualityGateSubtasks` -- sub-tasks for the quality-gate phase
- `reporting` -- output preferences (streaming, summary, timeline)
Validate that every requested phase ID exists in `phases`. Abort with an error if any phase is unknown.
### Step 2: Build Execution State
Initialize a state tracker for all requested phases:
```
state = {
[phaseId]: {
status: "pending", // pending | running | completed | failed | skipped
startTime: null,
endTime: null,
duration: null,
result: null, // output or error message
agentId: null, // background agent identifier
blocking: <from config>,
depends: <from config>,
resources: <from config>
}
}
```
Mark any phase whose dependencies include a phase NOT in the requested set as having those dependencies pre-satisfied (assumed completed externally, e.g., phases 0-3).
### Step 3: Scheduling Loop
```
WHILE any phase has status "pending" or "running":
ready = phases WHERE status == "pending"
AND all deps have status "completed"
AND no resource conflict with currently "running" phases
available_slots = maxConcurrent - count(status == "running")
to_dispatch = ready[0..available_slots]
FOR EACH phase IN to_dispatch:
dispatch phase as background agent (see Phase Dispatch Table)
set status = "running"
record startTime and agentId
REPORT "[START] {phase} dispatched"
Wait for next completion notification
On completion of phase P:
record endTime, compute duration
If success:
set status = "completed"
REPORT "[PASS] {phase} ({duration}s)"
If failed AND phase.blocking == true:
set status = "failed"
mark all transitive dependents as "skipped"
REPORT "[FAIL] {phase} -- blocking, skipping dependents: {list}"
If failed AND phase.blocking == false:
set status = "failed"
REPORT "[WARN] {phase} failed -- non-blocking, continuing"
```
### Step 4: Resource Conflict Check
Two phases conflict if they share any **exclusive** resource. The conflict rules:
- **String resource** (e.g., `"filesystem:src"`): exclusive by default. Two running phases with the same string resource conflict.
- **Object resource** with `"mode": "shared"` (e.g., `{ "name": "port:dev-server", "mode": "shared" }`): never conflicts with any other phase holding the same resource.
- **Empty resources** `[]`: no conflicts with anything.
Implementation:
```
function hasResourceConflict(candidatePhase, runningPhases):
candidateExclusive = candidatePhase.resources
.filter(r => typeof r === "string") // strings are exclusive
FOR EACH running IN runningPhases:
runningExclusive = running.resources
.filter(r => typeof r === "string")
IF intersection(candidateExclusive, runningExclusive) is non-empty:
RETURN true
RETURN false
```
### Step 5: Phase Dispatch Table
| Phase | Dispatch Method |
|-------|----------------|
| `component-build` | **Agent:** dispatch the converter named by the resolved renderer manifest. For React renderers the calling command supplies the source-appropriate converter (figma/screenshot → figma-react-converter via the figma-to-react-workflow skill, canva → canva-react-converter); otherwise dispatch `manifest.converter` (e.g. react-native-converter for expo, future vue-converter / svelte-converter) |
| `storybook` | **Bash:** `./scripts/generate-stories.sh` |
| `visual-diff` | **Agent:** invoke visual-qa-verification skill with pixel-diff loop (max iterations from `iterationLoop.maxVisualIterations`) |
| `dark-mode` | **Bash:** `./scripts/check-dark-mode.sh http://localhost:3000` |
| `e2e-tests` | **Agent:** invoke e2e-test-generator skill with flows from build-spec.json |
| `cross-browser` | **Bash:** `./scripts/cross-browser-baseline.sh compare http://localhost:3000 --json` (diffs firefox/webkit against committed baselines with provenance checks — RFC 0002; skips with a capture hint when no baselines exist) |
| `quality-gate` | **Parallel sub-dispatch:** run all `qualityGateSubtasks` concurrently (see below) |
| `responsive` | **Bash:** `./scripts/check-responsive.sh http://localhost:3000` |
| `report` | **Agent:** generate `build-report.md` in `.claude/visual-qa/` from all collected phase results, timings, and diff images |
### Step 6: Quality Gate Sub-Parallelization
When `quality-gate` is dispatched, it internally runs its subtasks using the same scheduling algorithm with independent concurrency tracking:
| Subtask | Command |
|---------|---------|
| `coverage` | `pnpm vitest run --coverage` -- check 80% threshold |
| `typecheck` | `pnpm tsc --noEmit` |
| `build` | `pnpm build` |
| `token-verify` | `./scripts/verify-tokens.sh` |
| `lighthouse` | Lighthouse audit via Chrome DevTools MCP or CLI, check thresholds from `qualityGate.lighthouseThresholds` |
All subtasks run in parallel (respecting their resource declarations). The quality-gate phase passes only if **all** subtasks pass. If any subtask fails, quality-gate fails.
Report each subtask result inline:
```
[QUALITY-GATE] coverage: PASS (87%)
[QUALITY-GATE] typecheck: PASS (0 errors)
[QUALITY-GATE] build: PASS (3.2s)
[QUALITY-GATE] token-verify: PASS (no drift)
[QUALITY-GATE] lighthouse: PASS (perf:92 a11y:98 bp:95 seo:100)
```
## Batch Summary
After all phases resolve, output a summary:
```
=== PARALLEL ORCHESTRATION SUMMARY ===
Phases: 9 total | 7 passed | 1 failed | 1 skipped
Wall time: 47s
Sequential est: 138s
Speedup: 2.9x
Timeline:
0s [################] component-build 32s PASS
32s [#####] storybook 8s PASS
32s [###########] visual-diff 22s PASS
32s [###] dark-mode 5s WARN (non-blocking)
32s [########] quality-gate 16s PASS
32s [######] cross-browser 12s PASS
32s [####] responsive 7s PASS
54s [#######] e2e-tests 14s FAIL
-- [-------] report -- SKIPPED (dep: e2e-tests)
Failures:
e2e-tests: 2/5 flows failed (popup-interact, content-script-inject)
```
Include:
- **Total / passed / failed / skipped** counts
- **Wall time** (actual elapsed from first dispatch to last completion)
- **Sequential estimate** (sum of all phase durations)
- **Speedup factor** (sequential / wall)
- **ASCII timeline** showing each phase's start offset, duration bar, and result
- **Failures section** with details for any failed phase
## Standalone Usage
The skill can be invoked directly for ad-hoc parallel work outside the pipeline context. Provide a list of independent tasks as phase descriptors:
```
Run these tasks in parallel using parallel-orchestration:
1. Run lint: pnpm eslint .
2. Run type check: pnpm tsc --noEmit
3. Run tests: pnpm vitest run
4. Check bundle size: ./scripts/check-bundle-size.sh
```
The scheduler treats each task as a phase with no dependencies and no resource conflicts, dispatching up to `maxConcurrent` at a time and producing the same batch summary on completion.
## Error Handling
- **Agent crash or unexpected failure:** Mark the phase as `failed`. If the phase is `blocking`, mark all transitive dependents as `skipped` and report the root cause. If non-blocking, log a warning and continue.
- **Timeout:** Log a warning after 5 minutes of a phase running, but do not auto-kill. The phase may be legitimately long-running (e.g., visual-diff iteration loop). Warn again at 10 minutes.
- **Resource deadlock:** Impossible by design. The dependency graph is a DAG (acyclic), and resources are held only during phase execution. A phase releases all resources upon completion, so no circular wait can occur.
- **All phases skipped:** If every requested phase ends up skipped (due to a blocking failure cascade), report the root-cause phase prominently at the top of the summary.
- **Config validation failure:** If `pipeline.config.json` is missing or the `orchestration` section is absent, abort with a clear error message listing what is expected.
## Integration with Pipeline Commands
Pipeline commands (`/build-from-figma`, `/build-from-canva`, `/build-from-screenshot`) invoke this skill after completing the sequential phases 0-3. The handoff looks like:
```
# Phases 0-3 run sequentially (mandatory ordering)
Phase 0: token-sync -> completed
Phase 1: intake -> completed (build-spec.json written)
Phase 2: token-lock -> completed (design-tokens.lock.json written)
Phase 3: tdd-scaffold -> completed (failing tests written)
# Hand off to parallel-orchestration for phases 4+
Invoke parallel-orchestration with phases:
["component-build", "storybook", "visual-diff", "dark-mode",
"e2e-tests", "cross-browser", "quality-gate", "responsive", "report"]
Context provided:
- build-spec.json (appType, renderer, component list, E2E flows)
- design-tokens.lock.json
- Test files from phase 3
- Pipeline config
- Resolved renderer manifest (drives phase exclusion + converter selection)
```
Before scheduling, the scheduler resolves the renderer manifest and drops any phase in `manifest.phases.exclude` (Step 0). The parallel scheduler then respects the dependency graph within the remaining handed-off phases. For example, `component-build` has no unmet deps (its dep `tdd-scaffold` was completed in the sequential block), so it starts immediately. Phases like `visual-diff`, `storybook`, `dark-mode`, `quality-gate`, `cross-browser`, and `responsive` all depend on `component-build`, so they fan out once it completes. Finally, `report` waits for `quality-gate` and `e2e-tests` before running.