Source: https://docs.sogni.ai/sogni-intelligence/workflow-templates/

# Workflow Templates

Workflow templates are saved, parameterized creative-agent recipes. Use them when your builder UI or agent wants to create reusable workflows with typed inputs, then start durable `/v1/creative-agent/workflows` runs from those saved definitions.

`compose_workflow_template` can draft a template from a natural-language brief. If your app already knows it wants that planner, call it directly through `/v1/creative-agent/tools/execute`; use `/v1/chat/completions` with `sogni_tools: "creative-agent"` when the LLM should choose the tool. The same planner also accepts an `existing_template` argument carrying the prior template JSON — pass it when the user asks to edit a saved template ("change my saved storyboard to 16:9", "add a music step to wf\_X", "swap the model in my saved template") and the planner will preserve stage ids and bump only the requested change. The REST template endpoints below persist, list, edit, fork, and delete those drafts.

## [#](https://docs.sogni.ai/sogni-intelligence/workflow-templates/#template-endpoints)Template Endpoints

| Endpoint | Method | Use |
| --- | --- | --- |
| `/v1/creative-agent/workflows/templates` | `POST` | Create a workflow template. |
| `/v1/creative-agent/workflows/templates` | `GET` | List accessible templates. |
| `/v1/creative-agent/workflows/templates/:id` | `GET` | Read one template. |
| `/v1/creative-agent/workflows/templates/:id` | `PATCH` | Update an owned template. |
| `/v1/creative-agent/workflows/templates/:id` | `DELETE` | Delete an owned template. |
| `/v1/creative-agent/workflows/templates/:id/fork` | `POST` | Copy an accessible template into the caller's private templates. |

All template routes require authentication. Private templates are only visible to their owner. Public templates are readable and forkable by any authenticated caller. Update and delete treat "not owned" the same as "not found" so private template IDs cannot be probed.

## [#](https://docs.sogni.ai/sogni-intelligence/workflow-templates/#template-shape)Template Shape

| Field | Use |
| --- | --- |
| `id` | Optional caller-supplied template ID. If omitted, the API mints one from the template name. |
| `version` | Optional semantic version. Defaults to `0.0.1`; updates bump the patch version. |
| `name` | Required display name. |
| `description` | Optional description. |
| `brief` | Optional source brief or authoring prompt. |
| `category` | Optional category: `portrait`, `video-social`, `makeover`, `cinematic`, `music`, `analysis`, `custom`, or `other`. Defaults to `custom`. |
| `stability` | Optional `production`, `beta`, or `experimental`. Defaults to `experimental`. |
| `author` | Optional `system` or `{ "userId": "...", "displayName": "..." }`. |
| `visibility` | Optional `private` or `public`. Defaults to `private`. |
| `inputs` | Typed input declarations used when compiling the template. |
| `stages` | Fixed, interactive, or batch stages that compile into workflow steps. |
| `graph` | Optional visual builder layout. |
| `previewArtifacts` | Optional image/video preview metadata for galleries. |
| `estimatedCapacityUnits` | Optional `{ "min": number, "max": number }` estimate. |
| `exposeToLLM` | Optional boolean for template discovery surfaces. Defaults to `false`. |
| `llmPriority` | Optional ranking hint for LLM-facing template selection. |
| `tags`, `metadata` | Optional app-specific metadata. |

Templates are validated by the shared creative-agent validator. Invalid create or update requests return `422` with `data.validation.issues`.

## [#](https://docs.sogni.ai/sogni-intelligence/workflow-templates/#binding-syntax-in-stage-args)Binding Syntax In Stage Args

Stage `args` values use binding placeholders to pull from the run context. Two forms are supported:

-   **Pure binding** — the entire string is `$root.path` (e.g. `"$inputs.duration"`, `"$artifacts.script.items[0].selectedVersion.content"`). The resolver returns the value at its original type: a number stays a number, an array stays an array, a selected `ArtifactVersion` stays the object.
-   **Embedded binding** — `$root.path` patterns inside a longer string (e.g. `"Render in $inputs.aspect_ratio for $inputs.duration seconds."`) are interpolated inline. Each match is stringified and substituted. Embedded paths that resolve to `undefined` throw a `BindingError` so typos surface during validation rather than shipping `$inputs.foo` text to a model.
-   **Wildcard expansion** — `items[*]` returns the full list. Example: `"$artifacts.angles.items[*].selectedVersion.url"` returns `string[]`.

Roots: `$inputs`, `$artifacts`, `$item` (batch stage), `$runtime`, `$run`.

Convenience accessors on artifacts: `.items[N].selectedVersion` resolves to the currently-selected version of an `ArtifactItem` (the canonical way to pull a generated URL from a prior stage).

## [#](https://docs.sogni.ai/sogni-intelligence/workflow-templates/#workflow-primitives)Workflow Primitives

`@sogni-ai/sogni-intelligence-client/workflows` exposes a `primitives` namespace of pure helpers (prompt builders, parsers, predicate evaluators) that runtimes use to implement `wf:*`\-prefixed workflow stage tools. Primitives are NOT chat tools — they are stage-only utilities that compose with the `condition` field on a stage to enable automated validate-and-regenerate loops.

| Primitive | Purpose |
| --- | --- |
| `wf:validate_with_rubric` | LLM judge with strict `__PASS__` / `__FAIL__: <reason>` token protocol. Returns `ToolErr` with `WORKFLOW_VALIDATION_FAILED` on fail so a downstream stage with `condition: { type: 'if_error_in', stageId: 'validate_X' }` fires a retry. Supports text and image artifacts. The `artifactUrl` argument is checked against an allow-list before any HTTP fetch — loopback, private, and link-local addresses are rejected. |
| `wf:retry_until_condition` | Wraps another tool with a bounded retry loop until a predicate passes. Predicate kinds: `metadata_field_truthy`, `metadata_field_equals`, `metadata_field_gte`, `metadata_field_lte` over a dot-path into the wrapped tool's result. Preserves the wrapped tool's `output_assets` so downstream bindings continue to resolve. |
| `wf:expand_storyboard_script` | LLM expands a brief into a numbered `TITLE` / `TOTAL_DURATION` / `BEATS` script with structural validation (sum-of-seconds drift within 20%, every beat has `VISUAL` and `ACTION` fields, sequential numbering). |
| `wf:fit_dialogue_to_duration` | LLM rewrites dialogue to fit a target spoken duration at a configurable words-per-minute rate. Enforces `mustKeep` verbatim phrases. |

All four `wf:*` primitives now run durably on the hosted backend (`POST /v1/creative-agent/workflows`) as well as in client-side runtimes — the executor short-circuits `wf:*` steps to a server-side primitive service (pure compute for `wf:fit_dialogue_to_duration`, server-side LLM for `wf:expand_storyboard_script` / `wf:validate_with_rubric`, and a durable loop marker for `wf:retry_until_condition`). `wf:validate_with_rubric` enforces an SSRF allow-list on `artifactUrl` (loopback / private / link-local rejected) and maps a blocked input to `WORKFLOW_VALIDATION_FAILED` without echoing the raw URL.

## [#](https://docs.sogni.ai/sogni-intelligence/workflow-templates/#create-a-template)Create A Template

```
curl https://api.sogni.ai/v1/creative-agent/workflows/templates \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Two-shot product teaser",
    "description": "Generate a product keyframe and animate it.",
    "category": "video-social",
    "visibility": "private",
    "inputs": [
      {
        "name": "brief",
        "type": "text",
        "required": true,
        "description": "Product and visual direction"
      }
    ],
    "stages": [
      {
        "id": "keyframe",
        "type": "fixed",
        "tool": "generate_image",
        "args": {
          "prompt": "$inputs.brief",
          "model": "qwen-2512",
          "width": 1024,
          "height": 576
        }
      },
      {
        "id": "clip",
        "type": "fixed",
        "tool": "generate_video",
        "args": {
          "prompt": "Slow cinematic product push-in",
          "duration": 5
        }
      }
    ],
    "exposeToLLM": false
  }'
```

Representative response:

```
{
  "status": "success",
  "data": {
    "template": {
      "id": "wf_two-shot-product-teaser_a1b2c3d4",
      "version": "0.0.1",
      "name": "Two-shot product teaser",
      "visibility": "private",
      "inputs": [],
      "stages": []
    }
  }
}
```

## [#](https://docs.sogni.ai/sogni-intelligence/workflow-templates/#list-and-read)List And Read

```
curl "https://api.sogni.ai/v1/creative-agent/workflows/templates?visibility=all&limit=20&offset=0" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

`visibility` can be:

| Value | Result |
| --- | --- |
| `all` | Caller-owned templates plus public templates. Default. |
| `own` | Only caller-owned templates. |
| `public` | Only public templates. |

Pagination uses `offset` and `limit`; `limit` is capped at 100. Responses return `data.templates` and `data.next`, where `next` is the next offset or `null`.

Read one template:

```
curl https://api.sogni.ai/v1/creative-agent/workflows/templates/wf_two-shot-product-teaser_a1b2c3d4 \
  -H "Authorization: Bearer YOUR_API_KEY"
```

## [#](https://docs.sogni.ai/sogni-intelligence/workflow-templates/#update-delete-fork)Update, Delete, Fork

Patch an owned template:

```
curl -X PATCH https://api.sogni.ai/v1/creative-agent/workflows/templates/wf_two-shot-product-teaser_a1b2c3d4 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "visibility": "public", "tags": ["product", "video"] }'
```

Delete an owned template:

```
curl -X DELETE https://api.sogni.ai/v1/creative-agent/workflows/templates/wf_two-shot-product-teaser_a1b2c3d4 \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Fork a public or owned template into a new private template:

```
curl -X POST https://api.sogni.ai/v1/creative-agent/workflows/templates/wf_source_template/fork \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "My product teaser variant" }'
```

Forked templates reset to version `0.0.1`, are private by default, and include `clonedFromTemplateId`.

## [#](https://docs.sogni.ai/sogni-intelligence/workflow-templates/#run-from-a-template)Run From A Template

Start a durable workflow from a saved template by sending `workflow_id` and `inputs` to `/v1/creative-agent/workflows`. Do not send `input.steps` in the same request.

```
curl https://api.sogni.ai/v1/creative-agent/workflows \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: template-run-001" \
  -d '{
    "workflow_id": "wf_two-shot-product-teaser_a1b2c3d4",
    "inputs": {
      "brief": "A translucent speaker on a glossy black table, neon rim light"
    },
    "token_type": "spark",
    "confirm_cost": true
  }'
```

The API compiles the template with the provided inputs. Compile failures return `422` with `compileErrors` and `compileWarnings`. A successful template start authorizes cost first: it persists the compiled workflow and returns **HTTP 202** with `{ workflow, waitingForCostApproval: true, preview }` in a `cost_approval_required` pause — release it with [`POST /:id/confirm-cost`](https://docs.sogni.ai/sogni-intelligence/creative-agent-workflows/#confirm-cost) before any step dispatches. See [Creative-Agent Workflows → Run From A Template](https://docs.sogni.ai/sogni-intelligence/creative-agent-workflows/#run-from-a-template).
