# Step Schemas & Template Variables

> Loaded on demand from the Agentled skill. `get_step_schema` (MCP) and
> `agentled schema --step-type <type>` (CLI) are the **authoritative** sources —
> this file is a fast reference for the common shapes.

## Pipeline Structure

Every workflow needs at minimum: a trigger step, one or more action steps, and a milestone (terminal) step. Steps are connected via `next: { stepId: "..." }`.

```json
{
  "name": "My Workflow",
  "goal": "What this workflow achieves",
  "steps": [
    { "id": "trigger", "type": "trigger", "name": "Start", "pipelineStepStartConditions": { "trigger": { "type": "manual" } }, "next": { "stepId": "action" } },
    { "id": "action", "type": "aiAction", "name": "Analyze", "pipelineStepPrompt": { "template": "...", "responseStructure": {} }, "creditCost": 10, "next": { "stepId": "done" } },
    { "id": "done", "type": "milestone", "name": "Complete" }
  ],
  "context": {
    "executionInputConfig": {
      "title": "Run Workflow",
      "fields": [{ "name": "input_field", "label": "Input", "type": "text", "required": true }]
    }
  }
}
```

## Step Types

### Trigger
```json
{ "id": "trigger", "type": "trigger", "name": "Start", "pipelineStepStartConditions": { "trigger": { "type": "manual" } }, "next": { "stepId": "next-step" } }
```

`pipelineStepStartConditions.trigger.type` is one of: `manual`, `schedule`, `webhook`, `event`, `delay`, `app_event`. For `schedule` add `config: { frequency: "daily", time: "07:00" }` (or a cron expression). For `app_event` add `config: { appId, triggerSlug, connectionSource }`. **Do not put `triggerType` at the step root** — it is not in the step schema and is silently dropped on save.

### App Action
```json
{
  "id": "enrich",
  "type": "appAction",
  "name": "Enrich Company",
  "app": { "id": "agentled", "actionId": "agentled.get-linkedin-company-from-url", "source": "native" },
  "stepInputData": { "profileUrls": "{{input.company_url}}" },
  "next": { "stepId": "next-step" }
}
```

### AI Action
```json
{
  "id": "analyze",
  "type": "aiAction",
  "name": "Analyze",
  "pipelineStepPrompt": {
    "template": "Analyze this company: {{steps.enrich.company}}",
    "responseStructure": { "score": "number 0-100", "summary": "string" }
  },
  "creditCost": 10,
  "next": { "stepId": "next-step" }
}
```

### AI Step Model & Provider Configuration

AI steps can optionally specify a model and provider via the `agent` field:

```json
{
  "id": "analyze",
  "type": "aiAction",
  "agent": { "model": "claude-4-6-sonnet", "provider": "anthropic" },
  "pipelineStepPrompt": { "template": "...", "responseStructure": {} },
  "creditCost": 10,
  "next": { "stepId": "next-step" }
}
```

**Supported Providers:** `openai`, `anthropic`, `google`, `mistral`, `deepseek`, `kimi`, `minimax`, `bytedance`, `perplexity`, `xai`

**Supported Models by Provider:**

| Provider | Models |
|----------|--------|
| `openai` | `gpt-5-nano`, `gpt-5-mini`, `gpt-5.4`, `o4-mini`, `o3`, `o3-pro`, `o3-deep-research` |
| `anthropic` | `claude-4-6-sonnet`, `claude-4-5-haiku`, `claude-4-6-opus` |
| `google` | `gemini-3-pro`, `gemini-3-flash`, `gemini-2.5-pro`, `gemini-2.5-flash` |
| `mistral` | `mistral-large-latest`, `mistral-small-latest`, `codestral-latest` |
| `deepseek` | `deepseek-v4-flash`, `deepseek-v4-pro` (`deepseek-chat` and `deepseek-reasoner` are legacy aliases retiring 2026-07-24) |
| `kimi` | `kimi-k2.5` |
| `minimax` | `minimax-m2.5` |
| `bytedance` | `doubao-seed-1.6-flash`, `seed-2.0-mini`, `doubao-seed-1.8-beta` |
| `perplexity` | `sonar-pro`, `sonar`, `sonar-reasoning-pro`, `sonar-reasoning` |
| `xai` | `grok-4.3`, `grok-3-mini` |

> **Tip:** Use `list_models` to get the full up-to-date list of supported model IDs. Use the internal model IDs (e.g., `claude-4-6-sonnet`), NOT the raw API model IDs (e.g., `claude-sonnet-4-6`). Using unsupported model IDs will result in a validation error.

### Code Step
```json
{
  "id": "transform",
  "type": "code",
  "name": "Transform Data",
  "codeConfig": { "language": "javascript", "code": "const data = {{steps.prev.output}};\nreturn data.map(x => x.name);" },
  "next": { "stepId": "next-step" }
}
```

### Milestone (terminal)
```json
{ "id": "done", "type": "milestone", "name": "Complete" }
```

## Template Variables

| Pattern | Description |
|---------|-------------|
| `{{input.fieldName}}` | Input page field value |
| `{{steps.stepId.field}}` | Previous step output |
| `{{currentItem}}` | Current item in a loop |
| `{{currentItem.field}}` | Nested field in loop item |

## Loop Configuration

To iterate over a list from a previous step:
```json
{
  "loopConfig": { "enabled": true, "field": "{{steps.prev.items}}", "ItemAlias": "currentItem" }
}
```

## Entry Conditions

Skip or stop a step based on prior output:
```json
{
  "entryConditions": {
    "onCriteriaFail": "skip",
    "conditionText": "Skip if no URL",
    "criteria": [{ "variable": "{{input.url}}", "operator": "isNotNull" }]
  }
}
```

Operators: `==`, `!=`, `>`, `<`, `isNull`, `isNotNull`, `contains`.

**Important**: Use `criteria` (not `conditions`) and `variable` (not `field`).
