Skip to main content

Manifests and artifacts

Worker, step, and saga manifests are how you declare workflows — they deploy to Postgres. Artifacts are the on-disk files your manifests reference: Jinja prompts, CEL policies, JSON Schema, and compensation YAML under *_ROOT paths.

Now that you've run the basic demos, this guide helps you write your own workflows. We'll cover how manifests deploy, how artifact paths resolve, and the order to build your first real configuration. Examples match the GitHub MCP demo when you want a full walkthrough.

Deploy and identity​

warden deploy -f <file> sends your manifest to the engine, which validates and saves it. Warden tracks each definition by a unique combo of namespace, name, and version. If you leave out namespace in your YAML, the engine defaults to "default". You can deploy new versions without affecting running sagas; each run tracks trace_id, not manifest names.

See Component identity for how identity fields line up across deploy, start, steps, and runtime.

Prompts, policies, schemas, and compensation files must be visible to both engine and worker at the same *_ROOT paths — see Artifact paths below and Configuration → Disk artifact roots for host vs container mounts.

Deploy order matters​

Deploy workers → steps → sagas. At deploy time, Warden checks every worker pin on a step definition, and every use: + version on a saga, against what's already in Postgres. Missing or mistyped names fail at deploy instead of at runtime.

Workers declare LLM and MCP capacity. Step manifests declare reusable capabilities (prompt, tools, policy, input ports). Sagas compose those steps into a workflow; deploy link-checks refs and start freezes hydrated steps on the instance:

warden deploy -f config/worker.github-demo.yaml
warden deploy -f config/step.github-triage.yaml
warden deploy -f config/step.github-post-comment.yaml
warden deploy -f config/saga.github-demo.yaml

What's in each manifest type​

ManifestStored inDefines
kind: workerworker_definitionsLLM provider, model, system prompt, MCP tool sources
kind: stepstep_definitionsReusable capability: step_kind, inputs, worker pin, tools/prompt/policy/HITL
kind: sagasaga_definitionsComposition via use: + version + with + when (authoring AST; hydrate at start)

Everything else — Jinja prompts, skill playbooks, CEL policies, JSON Schema, compensation YAML — is referenced by path from step or worker fields (and validated when those manifests deploy) and resolved from disk at register / saga start. Details and examples are in Artifact paths.

Artifact paths​

Step and worker manifests point at on-disk files by path relative to a *_ROOT directory. Subdirectories are allowed; do not use .. or absolute paths.

Manifest fieldRoot env varManifest exampleResolved path
promptPROMPTS_ROOTgithub-triage.j2{root}/github-triage.j2
skills.allowSKILLS_ROOTname: triage{root}/<worker>/triage.md
policyPOLICIES_ROOTgithub-issue-comment.yaml{root}/github-issue-comment.yaml
output_schemaSCHEMAS_ROOTgithub-triage-output.json{root}/github-triage-output.json
compensationCOMPENSATIONS_ROOTdisburse_undo.yaml{root}/disburse_undo.yaml

Always use paths with file extensions as shown in the table (skill ids map to {id}.md). Subdirectories are allowed (teams/marketing/gate.yaml). How the engine resolves *_ROOT on the host vs in Compose: Configuration → Disk artifact roots.

When you deploy a step (or a saga that link-checks those fields), the engine checks that referenced prompt, policy, schema, skill, and compensation files exist on disk. At saga start, the engine freezes prompts, skills, policies, schemas, and compensation into the instance; workers execute against those embeds.

Authoring pipeline​

Here's the order we recommend:

  1. Worker manifests — Set up your LLM provider, MCP tool sources, and base system prompts.
  2. Step manifests — Declare reusable reason/commit capabilities and input ports.
  3. Saga manifests — Compose catalog steps with use:, with, and when.
  4. Prompts — Write Jinja templates for reason steps.
  5. MCP and tools — Configure transports, tool allowlists, and resource reads.
  6. Conditional branching (when.cel) — Skip steps based on prior output or tool facts.
  7. Loop blocks (until) — Bounded do-while over nested catalog step refs.
  8. Child sagas (spawn_sagas / join_sagas) — Fan out to child saga instances and wait-all join.
  9. Policies — CEL guardrails at after_reason and before_commit.
  10. Compensation — Undo paths when a run fails.

After authoring, use Observability to inspect runs in Postgres and Jaeger, then the CLI to operate sagas day to day.