# AIWG Flows Metalanguage (core primitive)

`apiVersion: flow.aiwg.io/v1` (forward) — `workflow.aiwg.io/v1` accepted for back-compat

> **Naming (#1536):** this declarative spec defines **Flows** (pre-established,
> authored sequences). The complementary **dynamic** orchestration concept is a
> **Mission** (`mc` mission-control). "Workflow" was the original name and
> collides with provider `/workflow` commands, so AIWG uses **Flows + Missions**.
> Wire identifiers are dual-recognized — `flow.aiwg.io/v1` + `Flow*` kinds are
> the forward spelling; `workflow.aiwg.io/v1` + `Workflow*` remain valid (mirrors
> the existing `ops.aiwg.io/v1` alias). No authored document breaks; the
> `workflow.*` spelling is deprecated for removal no earlier than the release
> after this alias ships. See `.aiwg/architecture/adr-workflow-naming.md`.

A declarative YAML spec for composing automation work. Any AIWG framework, addon, or extension can author workflows in this language and route them through the shared executor. The metalanguage is a **core utility primitive** — it ships in `aiwg-utils` so every install has access to it, regardless of which frameworks are deployed.

## What this replaces

This metalanguage was originally authored as `ops.aiwg.io/v1` under `ops-complete`. The shape — capability + playbook + inventory + target + gate — is generic; the `Ops` label was a packaging artifact. Lifting the spec to `aiwg-utils` makes it usable by any domain (release validation, content production, research orchestration, CI/CD) without forcing the consumer to depend on ops-complete.

`ops.aiwg.io/v1` documents still parse via apiVersion alias (see `docs/migration-from-ops.md`); no existing playbook breaks.

## The 7 kinds

| Kind | Purpose | Schema |
|---|---|---|
| **WorkflowCapability** | A reusable named verb with declared inputs, outputs, verification command, and executor agent | [schemas/workflow-capability.schema.json](schemas/workflow-capability.schema.json) |
| **WorkflowPlaybook** | A DAG of capability invocations against a target inventory, with retry / depends_on / gates | [schemas/workflow-playbook.schema.json](schemas/workflow-playbook.schema.json) |
| **WorkflowInventory** | Declarative target set (hosts, providers, environments, anything addressable) | [schemas/workflow-inventory.schema.json](schemas/workflow-inventory.schema.json) |
| **WorkflowTarget** | A single addressable resource referenced from inventory | [schemas/workflow-target.schema.json](schemas/workflow-target.schema.json) |
| **WorkflowGate** | A pause point for human-in-the-loop authorization or judgment | [schemas/workflow-gate.schema.json](schemas/workflow-gate.schema.json) |
| **WorkflowRole** | A bundle of capabilities scoped to a role identity for permission boundaries | [schemas/workflow-role.schema.json](schemas/workflow-role.schema.json) |
| **WorkflowExtension** | A domain-specific extension declaring its own apiVersion namespace, kinds, and capability bundle | [schemas/workflow-extension.schema.json](schemas/workflow-extension.schema.json) |

## Authoring model

Three layers from most reusable to most specific:

```
[ core metalanguage ]   apiVersion: workflow.aiwg.io/v1     ← lives in aiwg-utils (this spec)
        ↑
[ domain extension ]    apiVersion: <domain>.workflow.aiwg.io/v1   ← e.g. ops, validation, research
        ↑
[ user instance  ]      a specific Capability or Playbook in a project    ← lives in .aiwg/workflow/
```

The core metalanguage defines the *shape* of capabilities, playbooks, inventories, etc. A domain extension declares its own `apiVersion` namespace and contributes its own capability library. A user instance is a single capability or playbook file in a project's `.aiwg/workflow/` directory.

## Where files live

| Layer | Location |
|---|---|
| Core schemas (this addon) | `agentic/code/addons/aiwg-utils/workflow/schemas/` |
| Core docs | `agentic/code/addons/aiwg-utils/workflow/docs/` |
| Domain extension (e.g. `ops`) | `agentic/code/frameworks/ops-complete/capabilities/` |
| Domain extension (e.g. `validation`) | `agentic/code/frameworks/validation-complete/capabilities/` |
| User instance (per project) | `.aiwg/workflow/capabilities/` and `.aiwg/workflow/playbooks/` |

## Executor contract

A single agent satisfies the executor contract for every workflow kind, regardless of domain. Today that agent is `ops-runbook-executor` (under ops-complete) — it will be renamed/lifted to `workflow-executor` as part of the lift (see migration plan).

The contract:

1. **Resolve**: load the playbook, resolve every `capability:` reference, validate each capability against its schema.
2. **Plan**: build the step DAG from `depends_on` edges; reject cycles.
3. **Bind**: bind playbook `vars` and per-step `inputs` into capability inputs; resolve `from: <step-id>.<output>` references after step completion.
4. **Execute**: for each ready step, dispatch to the capability's `agent`. Capture stdout/stderr/exit-status. If `verification.command` is present, run it and compare against `verification.expect`.
4a. **Fan-out** (`fanout` step, #1547): when a step carries a `fanout` block instead of a `capability`, dispatch each `fanout.agents[*]` capability — concurrently for `strategy: parallel` (a review panel), or chained (each agent sees the prior output) for `strategy: pipeline`. Await all panel agents, collect their structured outputs, then dispatch `fanout.synthesize` with the panel outputs as input; the synthesis result is the step's output for downstream `from:`/`depends_on` consumers. The retained-ownership invariant applies **across the whole panel**: audit every panel agent + the synthesis (step 7), honor gates/authorization, and apply best-output selection over the panel. This is the declarative spelling of the multi-agent documentation pattern (Primary → Parallel Reviewers → Synthesizer); see `.aiwg/architecture/adr-flow-agentic-steps.md`. A step MUST NOT set both `capability` and `fanout`.
5. **Gate**: when a `kind: gate` step is reached, pause; surface the gate's `description` and `inputs` to the human; resume when the gate is acknowledged.
6. **Retry**: respect each step's `retry.limit` and `retry.on` policy.
7. **Audit**: append every step outcome (start, end, verification result, outputs, gate decisions) to `.aiwg/workflow/runs/<run-id>/audit.jsonl`.
8. **Report**: at playbook completion, emit a structured report to `.aiwg/workflow/runs/<run-id>/report.md`.

The executor MUST NOT mutate the playbook or its capabilities. It MUST honor `idempotent: true` (re-runs against the same target produce the same outcome). It MUST refuse to execute capabilities whose `target_requirements` are unmet (missing OS, missing binary, missing access).

## Cross-stack Missions (#1546)

A **Mission** (dynamic orchestration) can fan worker cycles across *heterogeneous agentic stacks* — e.g. a Claude-conductor Mission dispatching a worker (or a `fanout` panel agent) to a **Codex** executor, or a single Mission spanning multiple stacks under one durable conductor. This needs **no new transport**: the `serve` executor registry already routes by capability.

- **Convention:** an executor advertises its stack via the established `runtime:<name>` capability — `runtime:codex`, `runtime:claude-code` (already in the `serve` fixtures). Do **not** invent a parallel `stack:<name>` token.
- **Dispatch:** the conductor selects a worker's stack with an `executor_filter` on that capability; `src/serve/agent-router.ts` `routeMission()` / `ExecutorRegistry.pickByFilter()` pick a connected executor advertising **all** filtered capabilities. A `fanout` step's panel agents may each target a different `runtime:<name>` — the YAML `fanout` is the cross-stack authoring surface.
- **Invariant (across stacks):** the conductor retains activity-log, human-authorization/threat gates, best-output selection, checkpoint/resume durability, reproducibility, and cost — regardless of which stack each worker ran on. The per-stack executor drives the *worker mechanism* only.

See `.aiwg/architecture/adr-workflow-routing.md` (cross-stack amendment).

### Conductor + per-stack adapters (landed)

The conductor and adapter layer are implemented on the substrate above:

- **`src/serve/mission-conductor.ts`** — `MissionConductor.conduct(plan, pool[, resumeFrom])` decomposes a `MissionPlan` (goal + completion criterion + `WorkerCycle[]`, each with a `runtime`) and dispatches each cycle to an executor of the chosen stack via `routeMission`. It returns a `MissionLedger` that holds the **retained-ownership bookkeeping** — `activityLog`, `totalCost` (aggregated across stacks), `bestOutput` (REF-015 selection, scorer-injectable), `checkpoint` (`completed`/`pending`/`failed` for crash-resilient resume), and `runtimesUsed`. Every field is populated identically regardless of which stack ran each worker; unroutable/unassigned/errored cycles are **recorded, never silently dropped**.
- **`src/serve/stack-adapters.ts`** — `StackAdapter` maps a worker cycle onto a stack's native primitive and owns its `runtime:<name>` token. Built-ins: `codexAdapter` (drives `/goal` / `/aiwg-mission` #1544) and `claudeCodeAdapter` (drives the Workflow tool / subagents). `StackAdapterRegistry` is open-ended — operators register additional stacks (e.g. `runtime:opencode`) without new transport.
- **Worker-execution seam:** `MissionConductor`'s `runWorker` option is where the live `aiwg serve` dispatch-router + WS event stream plugs in; the default is plan-only (routes + books without executing), so the conductor is honest about what is wired vs. pending live transport.
- **Tests:** `test/unit/serve/mission-conductor.test.ts` proves cross-stack dispatch under one conductor, the identical-bookkeeping invariant across stacks, best-output selection, no-silent-drop, and checkpoint resume.

## Apiversion aliasing

For backward compatibility, the executor accepts the following apiVersion equivalences:

| Legacy | Resolves to |
|---|---|
| `ops.aiwg.io/v1` | `workflow.aiwg.io/v1` |
| `sys.ops.aiwg.io/v1` | `sys.workflow.aiwg.io/v1` |
| `it.ops.aiwg.io/v1` | `it.workflow.aiwg.io/v1` |
| `dev.ops.aiwg.io/v1` | `dev.workflow.aiwg.io/v1` |
| `stream.ops.aiwg.io/v1` | `stream.workflow.aiwg.io/v1` |

Equivalence is bidirectional for the v1 line. The aliasing layer is removed when `ops` and its extensions are migrated to native `workflow.*` apiVersions (target: release after the lift ships).

## Why this lives in aiwg-utils

- **Universal**: every AIWG install carries `aiwg-utils`; the workflow metalanguage is available without installing a domain framework first.
- **No domain bias**: the schemas describe shape only — they say nothing about hosts, services, certs, or providers. Domain semantics live in domain extensions.
- **One executor, many domains**: ops, validation, and any future domain share the same DAG runner, the same audit format, the same gate semantics.

## What's NOT in scope

- The executor implementation. The agent that runs playbooks lives outside the spec (currently `ops-runbook-executor`, lifted later).
- Domain-specific capability libraries. Each domain authors its own. This addon ships zero capabilities — only the spec.
- Per-language SDKs / bindings. The spec is the authoritative contract; bindings can be written but aren't required.

## See also

- `docs/overview.md` — narrative tour of the metalanguage with worked examples
- `docs/migration-from-ops.md` — how existing `ops.aiwg.io/v1` documents migrate
- `examples/` — minimal authored examples for each kind
- ops-complete (`agentic/code/frameworks/ops-complete/`) — the first domain consumer; will be migrated to native `workflow.*` apiVersion in a follow-up
