api/src/ai/tools/operations/prompt.md
Perform CRUD on Directus Operations within Flows. Operations are individual actions that execute sequentially in a flow, processing and transforming data through the data chain.
<key_concepts>
key that identifies it in the data chainresolve (success) and reject (failure) paths<uuid_vs_keys>
UUIDs (System identifiers): "abc-123-def-456"
resolve, reject, flow, operation key field in CRUDKeys (Human-readable names): "send_email", "check_status"
{{ operation_key }}<critical_syntax>
Condition Filters: Use nested objects, NEVER dot notation
"$trigger.payload.status"{"$trigger": {"payload": {"status": {"_eq": "published"}}}}Request Headers: Array of objects, NOT simple objects
{"Authorization": "Bearer token"}[{"header": "Authorization", "value": "Bearer token"}]Request Body: Stringified JSON, NOT native objects
"body": {"data": "value"}"body": "{\"data\": \"value\"}"Data Chain Variables: Use operation keys, avoid $last
{{ $last }} (breaks when reordered){{ operation_key }} (reliable) </critical_syntax><required_fields>
All Operations:
flow - UUID of parent flowkey - Unique operation identifiertype - Operation typeposition_x, position_y - Grid coordinatesresolve, reject - Next operation UUIDs (null initially) </required_fields><available_operations> Core operations available in Directus:
If user has installed extensions from the Directus Marketplace, there may be more operations available than this. You can read existing operations to see if they are using extensions operations. </available_operations>
<crud_actions>
read - List Flow Operations{
"action": "read",
"query": {
"fields": ["id", "name", "key", "type", "flow", "resolve", "reject"],
"filter": { "flow": { "_eq": "flow-uuid" } },
"sort": ["position_x", "position_y"]
}
}
create - Add Operation to Flow{
"action": "create",
"data": {
"flow": "flow-uuid", // Required: Flow this operation belongs to
"key": "notify_user", // Required: Unique key for this operation
"type": "notification", // Required: Operation type
"name": "Send Notification", // Optional: Display name
"position_x": 19, // Required: Grid X position (use 19, 37, 55, 73...)
"position_y": 1, // Required: Grid Y position (use 1, 19, 37...)
"options": {
// Optional: Type-specific configuration (default: {})
// Configuration based on operation type
},
"resolve": null, // Required: UUID of next operation on success (null initially)
"reject": null // Required: UUID of next operation on failure (null initially)
}
}
update - Modify Operation{
"action": "update",
"key": "operation-uuid",
"data": {
"options": {
// Updated configuration
},
"resolve": "operation-uuid-here"
}
}
delete - Remove Operation{
"action": "delete",
"key": "operation-uuid"
}
</crud_actions>
<workflow_creation>
Critical Order: Create flow first → Create operations with null resolve/reject → Link operations via UUIDs → Update flow entry point.
See flows tool for complete workflow example with detailed steps. </workflow_creation>
<positioning_system>
Rules: 14x14 units, spacing every 18 units (example 19/37/55/73). Never (0,0). Start position_y: 1.
Patterns: Linear (19,1)→(37,1)→(55,1). Branching: success (37,1), error (37,19). </positioning_system>
<operation_examples> condition - Evaluates filter rules
{ "type": "condition", "options": { "filter": { "$trigger": { "payload": { "status": { "_eq": "published" } } } } } }
// Multiple: {"_and": [{"status": {"_eq": "published"}}, {"featured": {"_eq": true}}]}
item-create/read/update/delete - CRUD operations
{"type": "item-create", "options": {"collection": "notifications", "permissions": "$trigger", "payload": {"title": "{{ $trigger.payload.title }}"}}}
{"type": "item-read", "options": {"collection": "products", "query": {"filter": {"status": {"_eq": "active"}}}}}
{"type": "item-update", "options": {"collection": "orders", "key": "{{ $trigger.payload.id }}", "payload": {"status": "processed"}}}
{"type": "item-delete", "options": {"collection": "temp_data", "key": ["{{ read_items[0].id }}"]}}
exec - Custom JavaScript/TypeScript (sandboxed, no file/network access)
{
"type": "exec",
"options": {
"code": "module.exports = async function(data) {\n const result = data.$trigger.payload.value * 2;\n return { result, processed: true };\n}"
}
}
mail - Send email (markdown/wysiwyg/template)
{
"type": "mail",
"options": {
"to": ["[email protected]"],
"subject": "Order Confirmation",
"body": "Order {{ $trigger.payload.order_id }}"
}
}
// Template: {"type": "template", "template": "welcome-email", "data": {"username": "{{ $trigger.payload.name }}"}}
notification - In-app notifications
{
"type": "notification",
"options": { "recipient": ["{{ $accountability.user }}"], "subject": "Task Complete", "message": "Export ready" }
}
request - HTTP requests (headers must be array of objects, body as stringified JSON)
{
"type": "request",
"options": {
"method": "POST",
"url": "https://api.example.com/webhook",
"headers": [{ "header": "Authorization", "value": "Bearer {{ $env.API_TOKEN }}" }],
"body": "{\"data\": \"{{ process_data }}\"}"
}
}
json-web-token - Sign/verify/decode JWT
{
"type": "json-web-token",
"options": {
"operation": "sign",
"payload": { "userId": "{{ $trigger.payload.user }}" },
"secret": "{{ $env.JWT_SECRET }}",
"options": { "expiresIn": "1h" }
}
}
// Verify: {"operation": "verify", "token": "{{ $trigger.payload.token }}", "secret": "{{ $env.JWT_SECRET }}"}
transform - Create custom JSON payloads
{
"type": "transform",
"options": { "json": { "combined": { "user": "{{ $accountability.user }}", "items": "{{ read_items }}" } } }
}
trigger - Execute another flow
{
"type": "trigger",
"options": { "flow": "flow-uuid", "payload": { "data": "{{ transform_result }}" }, "iterationMode": "parallel" }
}
sleep/log/throw-error - Utilities
{"type": "sleep", "options": {"milliseconds": 5000}}
{"type": "log", "options": {"message": "Processing {{ $trigger.payload.id }}"}}
{"type": "throw-error", "options": {"code": "CUSTOM_ERROR", "status": "400", "message": "Invalid data"}}
</operation_examples>
<data_chain_variables> Data Chain: Use {{ operation_key }} to access results, {{ $trigger.payload }} for trigger
data. Avoid {{ $last }} (breaks when reordered). See flows tool for complete syntax. </data_chain_variables>
<permission_options> For operations that support permissions:
$trigger - Use permissions from the triggering context (default)$public - Use public role permissions$full - Use full system permissionsrole-uuid - Use specific role's permissions </permission_options><common_mistakes>
request operation - code in exec operations)$NOW variable - use exec operation: return { now: new Date().toISOString() }; </common_mistakes>