# Design: multi-plan program DAG (`run-program`)

audience: AI coding agents first. Status: **SUPERSEDED / DEFERRED — do NOT build.** Superseded 2026-06-27 by intra-plan DAG parallelism (`docs/specs/2026-06-27-run-plan-dag-parallel-design.md`): with one-PR integration, a program-of-separate-plans is redundant with making `run-plan` execute its task DAG in parallel. This program layer pays off ONLY if separate PRs / separate repos per module are ever required — revive it then, not before. No current consumer.

## Problem

`run-plan` executes ONE plan: one slug → one `docs/plans/<slug>.jsonl` → one wave sequence → one branch/PR. Cross-wave dependencies WITHIN that plan are already handled by the engine (sorts waves, checks per-task `deps`, HALTs on unmet dep / `BLOCKED` — `run-plan.js:341-352`).

Not handled: a **program/epic** = MULTIPLE plans (e.g. one per module), each its own slug + JSONL + branch/PR, with dependencies BETWEEN plans, and independent plans eligible to run in PARALLEL. Example: a session plans modules A,B,C; specs land; A,B independent → run concurrently; C `needs` A,B → runs after both.

## Model — DAG of plans (industry standard: CI `needs:`, Airflow)

- **Node** = one plan (existing single-plan `run-plan` unit). Unchanged.
- **Edge** = `needs` dependency between nodes.
- **Scheduler** = a program-level Workflow. Independent nodes run in `parallel()`; dependency edges become pipeline barriers; each node is `workflow('run-plan', {slug})`.

NEVER hand-roll "launch background → await notification → resume inline" in skill prose. The Workflow primitives (`parallel`/`pipeline`/`workflow`) own dependency ordering + concurrency natively; prose-driven notification-waiting is the fragile path.

## Nesting — VERIFIED LEGAL

Workflow nesting is one level deep (`workflow()` inside a child throws). A program-Workflow calling `workflow('run-plan', {slug})` is one level — legal ONLY because `run-plan.js` itself makes ZERO `workflow()` calls (uses `agent()`/`parallel()`/`sub()` only; confirmed by grep 2026-06-27). **Invariant to preserve: `run-plan.js` must never call `workflow()`** — doing so breaks program nesting.

## Schema extension (required — no current field expresses this)

A new top-level **program file** `docs/plans/<program-slug>.program.jsonl` (distinct suffix; never confused with a plan file). Records:

- `meta`: `{ type:"program", slug, created, kind:"program/v1" }`.
- `node`: one per module plan — `{ type:"node", id, slug, needs:[<node-id>...] }` where `slug` points at that module's own plan JSONL. `needs` = node ids that MUST complete (PR landed) first.
- Reuse existing `goal`/`intent`/`direction`/`session_memory` record types for program-level context.

Do NOT overload the per-task `wave`/`deps` fields for inter-plan deps — those are intra-plan and owned by `run-plan`. Inter-plan deps live ONLY in `node.needs`. Keep the two layers strictly separate (task→wave→plan = `run-plan`; plan→program = `run-program`).

## Engine sketch — `~/.claude/workflows/run-program.js`

```js
// reads <program-slug>.program.jsonl; runs the node DAG.
// independent nodes parallel; needs-edges sequence via pipeline barrier.
// each node => workflow('run-plan', {slug: node.slug}) => its own branch/PR.
// resume-safe: re-run reconciles each node's plan against git (run-plan already does), skips landed nodes.
```

Scheduling: topological layering — compute nodes whose `needs` are all satisfied, `parallel()` that layer (capped by the workflow concurrency limit), barrier, recompute, repeat. A node fails-closed (its `run-plan` HALTs) → do NOT start its dependents; report the partial DAG state.

## Launcher

New skill `run-program` (mirrors `run-plan`): thin launcher, templates the per-run script (bake program-slug into `meta.name`), `Workflow({scriptPath, args:{slug}})` in background. `resume-plan` is NOT extended for this — a multi-plan program is its own command, not a resume mode.

## Build trigger

Build when a real session first needs >1 plan with inter-plan deps. At that point: treat as a feature → `brainstorm` → `plan` → implement (schema + `run-program.js` + `run-program` skill + teach `brainstorm`/`fix-rot` to emit the program file). Until then this doc is the single source of truth; do not pre-build.
