Skills nocobase-workflow

Guide AI to create NocoBase workflows — triggers, conditions, data operations, SQL, scheduling

install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
OpenClaw · Install into ~/.openclaw/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/alexander-lq/work-fllows" ~/.openclaw/skills/openclaw-skills-nocobase-workflow && rm -rf "$T"
manifest: skills/alexander-lq/work-fllows/skill.md
source content

NocoBase Workflow Building

You are guiding the user to create automated workflows in NocoBase.

Key Concepts

Trigger Types

TypeDescriptionMode
collection
Data change trigger1=create, 2=update, 3=create+update, 4=delete
schedule
Time-based trigger0=cron, 1=date field
action
Manual button trigger

Node Types

TypeDescription
condition
If/else branch (basic engine or math.js)
update
Update existing records
create
Create new records
query
Query records for use in downstream nodes
sql
Execute raw SQL
request
HTTP request (webhooks, external APIs)
loop
Iterate over array data
end
Terminate workflow (1=success, 0=failure)

Node Linking Model

  • Nodes form a linked list:
    upstreamId
    downstreamId
  • Branch nodes (condition, loop) use
    branchIndex
    :
    • 1
      = true branch (condition) or loop body (loop)
    • 0
      = false branch (condition)
    • null
      = main line continuation

Variable System

VariableDescription
{{$context.data.field}}
Field from the trigger record
{{$context.data.id}}
ID of the trigger record
{{$jobsMapByNodeKey.<key>.field}}
Result from a previous node
{{$scopes.<key>.item}}
Current item in a loop

Workflow Patterns

Pattern 1: Auto-numbering (on create)

Generate sequential IDs like

PR-2026-001
:

# Step 1: Create workflow
nb_create_workflow("Auto Purchase Number", "collection",
    '{"mode": 1, "collection": "purchase_requests", "appends": [], "condition": {"$and": []}}')

# Step 2: Add SQL node
nb_add_node(wf_id, "sql", "Generate Number",
    '{"dataSource": "main", "sql": "UPDATE purchase_requests SET request_no = \'PR-\' || TO_CHAR(NOW(), \'YYYY\') || \'-\' || LPAD((SELECT COALESCE(MAX(CAST(SUBSTRING(request_no FROM \'[0-9]+$\') AS INT)),0)+1 FROM purchase_requests WHERE request_no LIKE \'PR-\' || TO_CHAR(NOW(), \'YYYY\') || \'-%\')::TEXT, 3, \'0\') WHERE id = {{$context.data.id}}"}')

# Step 3: Enable
nb_enable_workflow(wf_id)

Pattern 2: Status Sync (on create)

Set default status when a record is created:

nb_create_workflow("Default Status", "collection",
    '{"mode": 1, "collection": "orders", "appends": [], "condition": {"$and": []}}')

nb_add_node(wf_id, "update", "Set Draft Status",
    '{"collection": "orders", "params": {"filter": {"id": "{{$context.data.id}}"}, "values": {"status": "draft"}}}')

nb_enable_workflow(wf_id)

Pattern 3: Conditional Branch (on create)

Different actions based on field value:

nb_create_workflow("Transfer Type Handler", "collection",
    '{"mode": 1, "collection": "transfers", "appends": [], "condition": {"$and": []}}')

# Condition node
cond = nb_add_node(wf_id, "condition", "Is Transfer?",
    '{"rejectOnFalse": false, "engine": "basic", "calculation": {"group": {"type": "and", "calculations": [{"calculator": "equal", "operands": ["{{$context.data.type}}", "transfer"]}]}}}')

# True branch: update status to "transferred"
nb_add_node(wf_id, "update", "Mark Transferred",
    '{"collection": "assets", "params": {"filter": {"id": "{{$context.data.asset_id}}"}, "values": {"status": "transferred"}}}',
    upstream_id=cond_id, branch_index=1)

# False branch: update status to "borrowed"
nb_add_node(wf_id, "update", "Mark Borrowed",
    '{"collection": "assets", "params": {"filter": {"id": "{{$context.data.asset_id}}"}, "values": {"status": "borrowed"}}}',
    upstream_id=cond_id, branch_index=0)

nb_enable_workflow(wf_id)

Pattern 4: Field Change Trigger (on update)

React when specific fields change:

nb_create_workflow("Disposal Complete", "collection",
    '{"mode": 2, "collection": "disposals", "changed": ["status"], "condition": {"status": {"$eq": "disposed"}}, "appends": []}')

nb_add_node(wf_id, "update", "Update Asset Status",
    '{"collection": "assets", "params": {"filter": {"id": "{{$context.data.asset_id}}"}, "values": {"status": "disposed"}}}')

nb_enable_workflow(wf_id)

Pattern 5: Date-based Schedule

Trigger N days before a date field:

# Trigger 30 days before insurance expiry
nb_create_workflow("Insurance Expiry Warning", "schedule",
    '{"mode": 1, "collection": "insurance", "startsOn": {"field": "end_date", "offset": -30, "unit": 86400000}, "repeat": null, "appends": []}')

nb_add_node(wf_id, "sql", "Mark Expiring",
    '{"dataSource": "main", "sql": "UPDATE insurance SET remark = \'expiring soon\' WHERE id = {{$context.data.id}}"}')

nb_enable_workflow(wf_id)

Pattern 6: Cron Schedule

# Run every weekday at 9 AM
nb_create_workflow("Daily Report", "schedule",
    '{"mode": 0, "startsOn": "2026-01-01T00:00:00.000Z", "repeat": "0 9 * * 1-5"}')

Pattern 7: Multi-node Chain

Chain multiple nodes on the main line:

nb_create_workflow("Complex Flow", "collection",
    '{"mode": 1, "collection": "orders", "appends": [], "condition": {"$and": []}}')

# Node 1 (first node, no upstream_id needed)
n1 = nb_add_node(wf_id, "query", "Get Customer",
    '{"collection": "customers", "multiple": false, "params": {"filter": {"id": "{{$context.data.customer_id}}"}}}')

# Node 2 (chains after node 1)
n2 = nb_add_node(wf_id, "update", "Update Order",
    '{"collection": "orders", "params": {"filter": {"id": "{{$context.data.id}}"}, "values": {"customer_name": "{{$jobsMapByNodeKey.NODE_KEY.name}}"}}}',
    upstream_id=n1_id)

nb_enable_workflow(wf_id)

Workflow

Phase 1: Plan

Before creating workflows, identify:

  1. Trigger: What event starts the workflow? (record created/updated/deleted, schedule, manual)
  2. Collection: Which table triggers it?
  3. Logic: What conditions and actions are needed?
  4. Target: What data gets modified?

Phase 2: Create

  1. Create workflow with trigger config
  2. Add nodes in order (first node auto-links, subsequent need
    upstream_id
    )
  3. For branches: add condition node, then true/false branch nodes with
    branch_index

Phase 3: Enable & Verify

  1. Enable the workflow
  2. List workflows to confirm:
    nb_list_workflows()
  3. Inspect with:
    nb_get_workflow(wf_id)

Best Practices

  1. Title convention: Use prefixes for grouping, e.g. "AM-WF01 Auto Number"
  2. One workflow per concern: Don't combine unrelated logic
  3. Idempotent SQL: Write SQL that's safe to run multiple times
  4. Test before enable: Create all nodes first, then enable
  5. Batch cleanup: Use
    nb_delete_workflows_by_prefix("AM-")
    to clean up
  6. Duplicate prevention: Check
    nb_list_workflows()
    before creating — duplicate titles cause confusion
  7. Variable references: Always use double braces
    {{$context.data.field}}
    — single braces won't work