Skip to content

Artifact bundle

Every orchestration attempt writes a bundle of durable artifacts under .lumenflow/artifacts/orchestration/<INIT-ID>/attempt-<N>/. The bundle is what lets humans, local agents, and compatible remote orchestration surfaces resume the same initiative without trading emails or screenshots.

.lumenflow/artifacts/orchestration/
└── INIT-001/
    ├── attempt-0/
    │   ├── plan.json
    │   ├── launch.json
    │   ├── status.json
    │   └── handoffs/
    │       ├── WU-101.md
    │       └── WU-103.md
    └── attempt-1/
        ├── plan.json
        ├── launch.json
        ├── status.json
        └── handoffs/
            └── WU-101.md

Attempts are monotonic — once an attempt-N directory exists, the next invocation writes attempt-(N+1). The attempt number maps 1:1 to the launch_attempt field every receipt records. The one exception is a withheld attempt (see below): because it launches nothing and holds no receipts, a consecutive gated poll rewrites it in place rather than reserving a new number, so repeated polling on a held initiative cannot grow the tree without bound.

{
  "initiative": "INIT-001",
  "launch_attempt": 1,
  "logical_waves": [0, 1, 2],
  "waves": [
    {
      "planned_wave": 0,
      "logical_wave": 0,
      "logical_waves": [0],
      "wus": [{ "id": "WU-101", "lane": "Framework: ControlPlaneSdk", "logical_wave": 0 }]
    }
  ]
}
  • logical_wave is the dependency distance from a root. It does not change unless the graph changes.
  • planned_wave is the orchestrator’s launch grouping — normally equal to logical_wave but a single planned wave can contain multiple logical waves if capacity or lane limits cluster them.
{
  "initiative": "INIT-001",
  "launch_attempt": 1,
  "logical_waves": [0],
  "handoffs": [
    {
      "wu_id": "WU-101",
      "lane": "Framework: ControlPlaneSdk",
      "logical_wave": 0,
      "launch_attempt": 1,
      "handoff_artifact_path": ".lumenflow/artifacts/orchestration/INIT-001/attempt-1/handoffs/WU-101.md",
      "handoff_format": "markdown",
      "orchestration_state": "handoff_emitted",
      "emitted_at": "2026-04-17T10:00:00.000Z"
    }
  ]
}

Every handoff becomes a row in launch.json. Emitting a handoff is not launching a worker — it just records that the orchestrator prepared the artifact. Downstream evidence (worktree, delegation pickup, stamp) is what promotes a WU past handoff_emitted.

A withheld attempt adds "launch_withheld": true alongside an empty handoffs list. An attempt that launched nothing is not evidence that nothing was ever launched, so consumers reading launch receipts must fall back to the newest attempt that actually carries them. Reading only the highest-numbered attempt would drop every in-flight WU back to eligible on the poll after a gated one — re-emitting a handoff for work already in flight and blinding stall detection, which treats a launch receipt as its proof that the WU was ever delegated. status.json carries the same marker.

status.json — reconciled initiative state

Section titled “status.json — reconciled initiative state”
{
  "initiative": "INIT-001",
  "launch_attempt": 1,
  "logical_waves": [0, 1, 2],
  "available_capacity": 2,
  "max_active_workers": 3,
  "blocked_by_integrity": false,
  "next_safe_actions": [
    { "type": "launch_wu", "wu_id": "WU-103", "reason": "Ready to launch.", "logical_wave": 1 },
    {
      "type": "wait",
      "wu_id": "WU-102",
      "reason": "Waiting for WU-101 to complete.",
      "logical_wave": 1
    }
  ],
  "wus": [
    {
      "wu_id": "WU-101",
      "orchestration_state": "done",
      "yaml_status": "done",
      "logical_wave": 0,
      "launch_attempt": 1,
      "contamination_paths": [],
      "queued_by_capacity": false
    }
  ]
}

This file is the machine-readable truth. Every CLI / MCP / remote surface renders a projection of it. The schema is enforced by the control-plane SDK via parseOrchestrationStatusDocument().

phase_exit — the reconciled phase projection

Section titled “phase_exit — the reconciled phase projection”

When the initiative declares phases, status.json also carries the phase-exit and progress projection the CLI printed, so a remote consumer never has to re-derive it (or derive it differently):

{
  "phase_exit": {
    "current_phase": 1,
    "current_phase_status": "blocked",
    "blocking_reason": "exit criterion 'phase-1-wus-done' (Every WU assigned to phase 1 is done) unsatisfied: waiting on WU-101 (blocked); evidence: WU-101",
    "phases": [
      {
        "phase_id": 1,
        "title": "Foundation",
        "declared_status": "in_progress",
        "status": "blocked",
        "status_overridden": false,
        "wu_ids": ["WU-101"],
        "exit_criteria": [
          {
            "id": "phase-1-wus-done",
            "kind": "phase_wus_done",
            "description": "Every WU assigned to phase 1 is done",
            "derived": true,
            "satisfied": false,
            "evidence": ["WU-101"],
            "unsatisfied_evidence": ["WU-101"],
            "blocking_reason": "waiting on WU-101 (blocked)"
          }
        ],
        "unsatisfied_criterion_ids": ["phase-1-wus-done"]
      }
    ],
    "wu_state_counts": { "done": 0, "in_progress": 0, "blocked": 1, "ready": 1 },
    "last_progress_delta": {
      "wu_id": "WU-101",
      "state": "in_progress",
      "at": "2026-09-02T10:00:00.000Z",
      "evidence": "WU-101.claimed_at"
    },
    "secondary": { "done": 0, "total": 2, "percentage": 0 }
  }
}

The field is additive and optional: bundles written before it, and bundles for initiatives that declare no phases, simply omit it and still parse. derived: true marks a criterion the reconciler implied from phase membership rather than one the initiative declared. last_progress_delta names the canonical record field that carries the transition, so “progress” can always be traced back to evidence rather than to a status someone typed. See State machine for the phase exit states and criterion kinds.

A wave that launches nothing still writes a bundle

Section titled “A wave that launches nothing still writes a bundle”

An orchestration attempt in which nothing may launch — every WU withheld by a phase exit, a dependency, lane limits, worker capacity, or an integrity hold — writes plan.json, launch.json, and status.json exactly as a launching wave does, with an empty launch set and launch_withheld: true. That is the moment an operator most needs durable evidence, so the artifact carries the phase_exit projection, the reconciled WU states, and the next_safe_actions that explain the hold; the alternative was a bundle that existed only when it had the least to say.

Because a withheld attempt carries no receipts and no handoff files, the next withheld attempt reuses the same directory. Attempts that did launch work are never reused: their receipts are the durable record that the launch happened.

One file per emitted handoff. The file extension reflects the handoff_format:

  • .xml for Claude Code (Task invocations).
  • .md for Codex / Gemini / generic markdown clients.

These files are the durable handoff source for launch-mode orchestration:

  • orchestrate:initiative -c and continuous mode print the file paths by default instead of inlining the payload bodies.
  • --print-handoffs replays the stored artifact content inline for manual copy/paste.
  • Supported clients receive the same load-bearing handoff contract as wu:brief; orchestration reads from the stored artifact instead of assembling a second prompt shape for stdout.

Humans can copy these into their agent manually; cloud launchers ship them over the wire automatically.

Two orthogonal concepts that people used to conflate:

logical_wavelaunch_attempt
Changes when…The dependency graph changes.Every time you invoke orchestrate:initiative -c.
Source of truthThe initiative’s WU YAML deps.The next free attempt-N dir.
Filename usageField inside plan / launch / status.The directory name itself.
Meaning”This WU is in wave 2 of the DAG.""This is the 3rd time we tried to launch.”

Older manifests under .lumenflow/artifacts/waves/ used wave-N to mean both. That path has been retired; every new orchestration attempt writes a bundle under orchestration/<INIT>/attempt-N/ instead.

  • Lifecycle — which phase writes what.
  • Control-plane SDKOrchestrationPlanDocument, OrchestrationLaunchDocument, OrchestrationStatusDocument, OrchestrationPhaseExitProjection types + parsers.
  • State machine — the phase exit states and exit-criterion kinds phase_exit reports.