Skip to main content
Anything wrapped in {{ }} inside a workflow string (like task_template) is a template variable. You do not invent their values at write time — Cadence fills them at dispatch. This page is the complete contract.

Resolution order (exactly four steps)

When Cadence renders a template string it resolves each {{name}} in this order — first match wins: Variable names match [a-zA-Z0-9_.-]+. Scalar fields also support an inline fallback: {{model | default: 'claude-opus-4-7'}}.

The fixed slots, demystified

{{workflow_id}} — the id: from your own frontmatter (e.g. my-first-workflow). Format: the kebab-case string you wrote. You “get” it by writing it; Cadence echoes it back so the agent always knows which policy file governs it. {{issue_ref}} — the reference of the ticket/issue that triggered this run (e.g. a Beam issue like BEAM-42). Comes from the dispatch event; empty when a run isn’t ticket-driven. {{ticket.id}} — the underlying ticket identifier from the dispatch payload. Where they go afterwards (analytics): these same values are stamped on every harness event in the session ledger (run ids, workflow id, lane slug, usage, cost). That means the {{workflow_id}} you chose is your join key across runs, costs, and evidence — pick meaningful ids.

Declaring your own variables

Add typed arguments at the top level; callers supply values at dispatch, Cadence coerces and validates:
Types: string, int, number/float, bool/boolean. A missing required argument fails dispatch loudly — it will never silently render as empty. A declared argument always beats a same-named payload field.

Rules of thumb

See also