Authoring deliverables in workflows

A workflow job becomes "deliverable-producing" the moment it sets with.deliverableSpecRef. There's no second declaration — that one field is the contract.


Literal form

yaml
1jobs:
2  requirements:
3    uses: xema/agent
4    with:
5      agentRef: requirements
6      deliverableSpecRef: requirements-standard
7      agentContext:
8        prompt: ${{ inputs.request }}

The compiler resolves the spec ref against the registry at compile time. A typo or a missing spec fails with DSL_UNKNOWN_DELIVERABLE_SPEC — fast, clear, no runtime surprise.

Expression form

When the spec depends on runtime data — typically a clarification step's output — author the ref as a ${{ … }} expression.

yaml
1jobs:
2  build:
3    needs: [clarify]
4    strategy:
5      dynamic:
6        from: ${{ needs.clarify.outputs.targets }}
7        as: target
8        keyBy: name
9        maxEntries: 32
10    uses: xema/agent
11    with:
12      agentRef: builder
13      deliverableSpecRef: ${{ target.specRef }}
14      agentContext:
15        prompt: ${{ target.prompt }}

The ref resolves at dispatch time, when the matrix iteration's binding is materialized. The runtime fetches the spec, validates the harvest, and surfaces the canonical envelope.

Authors who supply expression-shaped refs accept that the compiler can't pre-validate the ref — the runtime fail-fasts on unknown specs with a typed RENDER_FAILED error naming the offending value.

Variable count, mixed kinds

The matrix mechanism is the single answer to "produce a different number of deliverables based on user intent." The upstream clarification step decides how many targets the user asked for, of which kinds, and emits a typed array. Each matrix iteration:

  • Resolves its own deliverableSpecRef from the matrix entry.
  • Drives its own agent session with the entry's prompt.
  • Harvests + validates against that spec.
  • Surfaces its result under byKey[<name>].deliverable.content.<...> for downstream jobs.
yaml
1clarify:
2  uses: xema/agent
3  with:
4    agentRef: clarification-coordinator
5    deliverableSpecRef: handoff-package
6    agentContext:
7      prompt: Clarify the request and emit a typed handoff package.
8  outputs:
9    targets: ${{ job.outputs.deliverable.content.value.targets }}
10
11build:
12  needs: [clarify]
13  strategy:
14    dynamic:
15      from: ${{ needs.clarify.outputs.targets }}
16      as: target
17      keyBy: name
18  uses: xema/agent
19  with:
20    agentRef: builder
21    deliverableSpecRef: ${{ target.specRef }}
22    agentContext:
23      prompt: ${{ target.prompt }}

A user asking for "five microservices and one frontend" produces a clarification output with six targets (five specRef: microservice-template, one specRef: frontend-template). The matrix expands to six concurrent agent runs. Zero deliverables = empty array = zero iterations.

What you don't need to declare

  • No output-key mapping. Workflow expressions read deliverable.content.<...> directly.
  • No validation flag on the producing job. Validation is a job of its own — add xema/validate-deliverables downstream when you want a verdict to gate on. See 04 Validation.

Action version

yaml
1uses: xema/[email protected]

Previous: ← Concepts Next: Output Envelope →