> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sidecars.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Automations

> List, read, draft, publish, run and pause the workspace's automations — the same objects the /automations page shows.

An automation is a **FlowPlan** — a small JSON graph of steps behind a trigger — that runs in its own session. Over MCP you write that JSON yourself: `describe_capabilities` gives the vocabulary, `draft_automation` validates it and stores a draft, `edit_automation` publishes it (or runs, dry-runs, pauses it). What you publish is a normal automation: it appears on `/automations`, approvals land in its session, and a person can edit it there afterwards. The [`sidecars-automations` skill](/skills) teaches the loop.

| Tool | Scope | Kind |
| - | - | - |
| [`list_automations`](#list_automations) | `automations:read` | read-only |
| [`read_automation`](#read_automation) | `automations:read` | read-only |
| [`describe_capabilities`](#describe_capabilities) | `automations:read` | read-only |
| [`draft_automation`](#draft_automation) | `automations:write` | write |
| [`edit_automation`](#edit_automation) | `automations:write` | write |

Both scopes arrive by step-up consent the first time a tool needing them is called. Anything you cannot open — another person's personal automation, a row in another workspace — is **not found**, never "forbidden". Changing an automation needs the same right the page needs: its creator for a personal one, a workspace admin for a `workspace` one.

## The plan

A plan is `{ "planVersion": 1, "name": "…", "description": "…", "nodes": [...], "edges": [...] }` — `name` and `description` are required — with at most 200 nodes. Node shapes — `capability`, `agent`, `transform`, `branch`, `map`, `subflow`, `approval`, `notify`, `delay` — and the transform operations are returned verbatim by `describe_capabilities`; copy them. Inputs are bound with `{"kind":"literal","value":…}`, `{"kind":"ref","node":"<upstream id>","path":"…"}` or `{"kind":"trigger","path":"…"}`. Every `write` capability must sit downstream of an `approval` node unless the draft is submitted with `write_approval: "automatic"`, in which case the plan may have no approval node at all.

The trigger on the wire:

```json theme={null}
{ "kind": "schedule", "frequency": "weekly", "weekday": 5, "hour": 16, "minute": 0, "timezone": "America/New_York" }
{ "kind": "connector_event", "provider": "granola", "event": "items_changed" }
{ "kind": "github_event", "event": "pull_request", "actions": ["closed"], "repo": "acme/web" }
```

## list\_automations

**Scope:** `automations:read` · **Kind:** read-only · **Annotations:** `readOnlyHint: true`, `destructiveHint: false`, `openWorldHint: false`

> List the automations you can see in this workspace — your personal ones and the workspace's — newest first.

### Parameters

<ParamField body="limit" type="number" default="50">Rows to return, at most 200.</ParamField>

### Returns

<ResponseField name="automations" type="array">Rows with `automation_id`, `name`, `enabled`, `degraded_reason?`, `trigger`, `scope` (`personal` | `workspace`), `can_control`, `version?`, `step_count?`, `namespaces?`, `session_id?`, `next_fire_at?`, `last_fired_at?`, `consecutive_failures`, `created_at`, `url?`.</ResponseField>
<ResponseField name="truncated" type="boolean">More rows exist than `limit` returned.</ResponseField>

## read\_automation

**Scope:** `automations:read` · **Kind:** read-only · **Annotations:** `readOnlyHint: true`, `destructiveHint: false`, `openWorldHint: false`

> Read one automation: the ask it implements, its numbered steps, what it writes to, its trigger, scope, state and live version. `include_plan` adds the plan JSON; `include_runs` the latest runs; `run_id` one run's per-node detail.

### Parameters

<ParamField body="automation_id" type="string" required>From `list_automations` or a publish.</ParamField>
<ParamField body="include_plan" type="boolean" default="false">Add `plan_json` — the live FlowPlan, the best worked example for writing or revising one.</ParamField>
<ParamField body="include_runs" type="boolean" default="false">Add the latest 20 runs (`run_id`, `status`, `dry_run`, `cause`, `error?`, timestamps) and `runs_truncated`.</ParamField>
<ParamField body="run_id" type="string">Add one run's detail: `nodes[]` with `node_id`, `status`, `attempt`, `error?`, and the run's `output?`. A run that is not this automation's reads as `null`.</ParamField>

### Returns

<ResponseField name="automation_id, name, description, tags, ask" type="…">Identity and the sentence the plan implements.</ResponseField>
<ResponseField name="steps" type="string[]">The live version's steps, numbered as the page shows them.</ResponseField>
<ResponseField name="writes" type="string[]">Capability keys the plan writes with (`linear.createIssuesFromItems`).</ResponseField>
<ResponseField name="namespaces, connectors, personal_connectors" type="string[]">Systems it touches; `personal_connectors` names the creator's own connections it depends on.</ResponseField>
<ResponseField name="trigger, scope, enabled, degraded_reason?, can_control, created_by?" type="…">State, as on the row.</ResponseField>
<ResponseField name="version, flow_version_id, write_approval" type="…">The live version. `flow_version_id` is what a schedule-only republish passes.</ResponseField>
<ResponseField name="session_id?, url?" type="string">Where its runs and approvals land.</ResponseField>
<ResponseField name="plan_json?, runs?, runs_truncated?, run?" type="…">When asked for.</ResponseField>

## describe\_capabilities

**Scope:** `automations:read` · **Kind:** read-only · **Annotations:** `readOnlyHint: true`, `destructiveHint: false`, `openWorldHint: false`

> Everything needed to write a FlowPlan: the workspace's connectors, the node, transform, binding and trigger-input forms to copy verbatim, the write-approval rule, and the capability catalogue per namespace. Call it first with `include_schemas: false`, then narrowed to the namespaces your plan needs.

### Parameters

<ParamField body="namespaces" type="string[]">Only these namespaces' capabilities. Default: every namespace the workspace may use. A namespace listed with `connected: false` exists but may not be used here.</ParamField>
<ParamField body="include_schemas" type="boolean" default="true">Include each capability's `input` and `output` JSON schema.</ParamField>

### Returns

<ResponseField name="plan_version, max_nodes" type="number">`1` and `200`.</ResponseField>
<ResponseField name="connectors" type="array">`provider`, `name`, `personal`, `namespace` for each connected system. A `workspace`-scoped automation cannot use a personal one.</ResponseField>
<ResponseField name="node_shapes, transform_ops, bindings, trigger_input, write_approval" type="string">The vocabulary, rendered from the same source the validator checks against.</ResponseField>
<ResponseField name="namespaces" type="array">`namespace`, `connected`, `capabilities[]` with `key`, `kind` (`read` | `write`), `describe`, `large?`, `async?`, `input?`, `output?`.</ResponseField>
<ResponseField name="truncated, schemas_dropped?" type="…">Past \~90 KB the tail namespaces lose their schemas; call again narrowed to them.</ResponseField>

## draft\_automation

**Scope:** `automations:write` · **Kind:** write · **Annotations:** `readOnlyHint: false`, `destructiveHint: false`, `idempotentHint: false`, `openWorldHint: false`

> Validate a FlowPlan you wrote and store it as a draft version. Nothing is scheduled until it is published.

### Parameters

<ParamField body="plan_json" type="object" required>The FlowPlan (`planVersion: 1`).</ParamField>
<ParamField body="ask" type="string" required>The request this plan implements, in one sentence; shown on the automation.</ParamField>
<ParamField body="write_approval" type="'required' | 'automatic'" default="required">`required`: every write behind an approval node. `automatic`: no approval nodes; writes run unattended.</ParamField>
<ParamField body="automation_id" type="string">Draft the next version of this automation instead of a new one. Needs the right to change it.</ParamField>

### Returns

Either a draft:

<ResponseField name="kind" type="'plan'" />

<ResponseField name="flow_version_id, flow_id, version" type="…">What `edit_automation` `publish` takes.</ResponseField>
<ResponseField name="steps, writes, namespaces, connectors, write_approval" type="…">Read these back to the person before publishing.</ResponseField>

or a failure (`isError: true`), with nothing stored:

<ResponseField name="kind" type="'failed'" />

<ResponseField name="errors" type="array">`rule` (`shape`, `dag/cycle`, `capability/not-connected`, `capability/input`, `binding/not-upstream`, …), `path` into your plan JSON (`["nodes", 2, "inputs", "issues"]`), `node_id?`, `message`. Fix exactly these and resubmit.</ResponseField>

## edit\_automation

**Scope:** `automations:write` · **Kind:** write · **Annotations:** `readOnlyHint: false`, `destructiveHint: false`, `idempotentHint: false`, `openWorldHint: false`

> One tool, three actions: `publish` a draft behind a trigger, `run` an automation now (or `dry_run` it), `set_enabled` to pause or resume. Pausing is the undo for everything; there is no delete. A paused automation refuses a real `run` but still accepts `dry_run: true`, so it can be tested without starting its schedule.

### Parameters

<ParamField body="action" type="'publish' | 'run' | 'set_enabled'" required />

<ParamField body="automation_id" type="string">Required for `run` and `set_enabled`. On `publish`, makes the draft that automation's next version; without it a new automation is created.</ParamField>
<ParamField body="flow_version_id" type="string">`publish`: the draft from `draft_automation` (or the live version, to change only the trigger).</ParamField>
<ParamField body="trigger" type="object">`publish`: see [the plan](#the-plan).</ParamField>
<ParamField body="name, description, tags" type="…">`publish`. `name` is required for a new automation.</ParamField>
<ParamField body="scope" type="'personal' | 'workspace'">`publish`. `workspace` needs an admin and cannot use personal connectors.</ParamField>
<ParamField body="notify" type="'off' | 'problems' | 'everyRun'">`publish`: when the creator is notified.</ParamField>
<ParamField body="cooldown_s" type="number">`publish`: minimum seconds between event-triggered runs.</ParamField>
<ParamField body="enabled" type="boolean">`publish`: `false` leaves it paused for review (default enabled). `set_enabled`: required.</ParamField>
<ParamField body="dry_run" type="boolean" default="false">`run`: simulate writes.</ParamField>

### Returns

<ResponseField name="action" type="string">Echoed.</ResponseField>

<ResponseField name="automation_id, session_id?, url?" type="string" />

<ResponseField name="name, version, enabled" type="…">On `publish`.</ResponseField>
<ResponseField name="dry_run, run_id?" type="…">On `run`; `run_id` is set for a dry run and readable with `read_automation(run_id)`. A normal run is queued and appears under `include_runs` moments later.</ResponseField>
<ResponseField name="enabled, next_fire_at?" type="…">On `set_enabled`.</ResponseField>

Refusals carry the page's own sentence: "Enable the automation before running it", "Only its creator can change this automation", "Only workspace admins can change this automation", "That draft is not a version of this automation".


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.