Skip to main content

flow-automation

Flow automation — triggers, operations, data chains, event hooks, webhooks, schedules. This skill should be used when the user asks to create automation flows, set up triggers, configure operations, build event-driven workflows, schedule tasks, or trigger flows programmatically in Directus.

Source facts

Repository
Agents-Store/opencode-plugins
Last source activity
October 4, 2026 at 20:44
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
4 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
flow-automation
description
Flow automation — triggers, operations, data chains, event hooks, webhooks, schedules. This skill should be used when the user asks to create automation flows, set up triggers, configure operations, build event-driven workflows, schedule tasks, or trigger flows programmatically in Directus.
# Flow Automation Complete reference for the `flows`, `operations`, and `trigger-flow` MCP tools. ## Concepts - **Flow** = Trigger + Chain of Operations - Each flow has ONE trigger and a series of operations forming a data chain - Operations connect via `resolve` (success) and `reject` (failure) paths - Data passes through the chain using `{{ operation_key }}` variables ## Trigger Types | Trigger | When It Fires | Key Options | |---------|---------------|-------------| | `event` | On item CRUD (hook) | `type` (filter/action), `scope` (items.create, items.update, items.delete), `collections` | | `webhook` | HTTP request to flow URL | `method` (GET/POST), `async` | | `schedule` | Cron expression | `cron` (e.g., `"0 9 * * 1"` = Monday 9am) | | `operation` | Called by another flow | — | | `manual` | User triggers from app | `collections`, `requireSelection`, `fields` | ## Creating a Flow ```text Tool: flows Input: { "action": "create", "data": { "name": "Notify on New Post", "trigger": "event", "status": "active", "accountability": "all", "icon": "notifications", "color": "#FF9800", "description": "Send notification when a new post is created", "options": { "type": "action", "scope": ["items.create"], "collections": ["posts"] } } } ``` ### Trigger Options by Type **Event trigger:** ```jsonc "options": { "type": "action", "scope": ["items.create", "items.update"], "collections": ["posts"] } ``` - `type: "filter"` — runs before the operation (can block it) - `type: "action"` — runs after the operation **Schedule trigger:** ```jsonc "options": { "cron": "0 */6 * * *" } ``` **Manual trigger:** ```jsonc "options": { "collections": ["posts"], "requireSelection": true, "fields": [ { "field": "reason", "type": "string", "name": "Reason" } ] } ``` **Webhook trigger:** ```jsonc "options": { "method": "POST", "async": false } ``` ## Operation Types | Type | Description | Key Options | |------|-------------|-------------| | `condition` | If/else branching | `filter` (condition rules) | | `item-create` | Create items | `collection`, `payload` | | `item-read` | Read items | `collection`, `query` | | `item-update` | Update items | `collection`, `payload`, `key` or `query` (see below) | | `item-delete` | Delete items | `collection`, `key` or `query` (see below) | | `mail` | Send email | `to`, `subject`, `body` | | `notification` | In-app notification | `recipient`, `subject`, `message` | | `request` | HTTP request | `url`, `method`, `headers`, `body` | | `sleep` | Wait/delay | `milliseconds` | | `log` | Log to console | `message` | | `exec` | Run custom code | `code` | | `transform` | Transform data | `json` | | `trigger` | Chain to another flow | `flow` | | `json-web-token` | Sign, verify or decode a JWT | `operation` (`sign`/`verify`/`decode`), `payload`, `token`, `secret`, `options` | | `throw-error` | Fail the flow with a custom error | `code`, `status`, `message` | ### Targeting in `item-update` and `item-delete` (Directus 12.3.0+) Target items with **either** `key` (one primary key or an array) **or** `query`, never both: - Empty or missing `key` and `query` (including `"query": {}`) return `null` and change nothing. Before 12.3.0 they affected every item in the collection. - To update or delete **all** items, say so explicitly with `"query": { "limit": -1 }`. - `key` together with `query` fails the operation with `INVALID_PAYLOAD` ("Cannot use both key and query"). `item-update` with a batch (array) payload together with `key` or `query` throws too, because a batch payload carries its own keys. - 12.4.0+: update and delete by `query` apply the **read** permissions of the operation's accountability. The role needs read on the primary key, and only readable items are touched. Fields used in `filter` and `sort` must be readable. - Both operations also take `emitEvents` (fire hooks and flows for the change) and `permissions` (`$trigger`, `$full`, `$public` or a role UUID) to choose whose permissions apply. ```text Tool: operations Input: { "action": "create", "data": { "flow": "FLOW_UUID", "key": "archive_old_drafts", "type": "item-update", "name": "Archive old drafts", "options": { "collection": "posts", "payload": { "status": "archived" }, "query": { "filter": { "date_created": { "_lt": "$NOW(-90 days)" }, "status": { "_eq": "draft" } }, "limit": -1 } }, "position_x": 40, "position_y": 1 } } ``` A `query` without a `limit` is capped at `QUERY_LIMIT_DEFAULT` (100 unless configured), so a bulk change over more matches needs `"limit": -1` as above (bounded by `QUERY_LIMIT_MAX` when that is set). With the `filter` this still targets only old drafts. A bare `{"limit": -1}` with no `filter` means the whole collection, so use it only on purpose. ## Creating Operations ```text Tool: operations Input: { "action": "create", "data": { "flow": "flow-uuid-here", "key": "check_status", "type": "condition", "name": "Check if Published", "options": { "filter": { "$trigger": { "payload": { "status": { "_eq": "published" } } } } }, "position_x": 20, "position_y": 1, "resolve": "next-op-uuid-or-null", "reject": null } } ``` ## Connecting Operations Operations form a chain through `resolve` and `reject` UUIDs: 1. Create all operations first (with `resolve: null`, `reject: null`) 2. Update each operation with the correct `resolve`/`reject` UUIDs 3. Update the flow with `operation: "first-op-uuid"` to set the entry point ```text Tool: flows Input: { "action": "update", "key": "flow-uuid", "data": { "operation": "first-operation-uuid" } } ``` ## Data Chain Variables Access data from triggers and previous operations: | Variable | Source | |----------|--------| | `{{ $trigger }}` | Trigger data (payload, keys, collection) | | `{{ $trigger.payload }}` | Item data that triggered the flow | | `{{ $trigger.keys }}` | Primary keys of items | | `{{ $trigger.collection }}` | Collection name | | `{{ $trigger.body }}` | Webhook/manual trigger body | | `{{ operation_key }}` | Output of a specific operation (use the `key` you set) | | `{{ $accountability }}` | User who triggered the flow | ### Critical Syntax Rules 1. **Condition filters** — Use nested objects, NOT dot notation: ```jsonc // CORRECT { "$trigger": { "payload": { "status": { "_eq": "published" } } } } // WRONG { "$trigger.payload.status": { "_eq": "published" } } ``` 2. **Request headers** — Array of `{header, value}` objects, NOT key-value: ```jsonc // CORRECT "headers": [ { "header": "Content-Type", "value": "application/json" }, { "header": "Authorization", "value": "Bearer token" } ] // WRONG "headers": { "Content-Type": "application/json" } ``` 3. **Request body** — Stringified JSON, NOT native objects: ```jsonc // CORRECT "body": "{\"message\": \"{{ $trigger.payload.title }}\"}" // WRONG "body": { "message": "{{ $trigger.payload.title }}" } ``` 4. **Data chain references** — Use explicit operation keys: ```jsonc // CORRECT (using operation key) "{{ read_user.email }}" // AVOID "{{ $last }}" ``` ## Complete Flow Example ### "Send Slack Notification on New Published Post" **Step 1: Create the flow:** ```text Tool: flows Input: { "action": "create", "data": { "name": "Notify Slack on Publish", "trigger": "event", "status": "active", "options": { "type": "action", "scope": ["items.create", "items.update"], "collections": ["posts"] } } } ``` **Step 2: Create condition operation:** ```text Tool: operations Input: { "action": "create", "data": { "flow": "FLOW_UUID", "key": "is_published", "type": "condition", "name": "Is Published?", "options": { "filter": { "$trigger": { "payload": { "status": { "_eq": "published" } } } } }, "position_x": 20, "position_y": 1 } } ``` **Step 3: Create HTTP request operation:** ```text Tool: operations Input: { "action": "create", "data": { "flow": "FLOW_UUID", "key": "send_slack", "type": "request", "name": "Send to Slack", "options": {
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub