Files
inkreach-teable-cli/.agents/skills/inkreach-teable/guides/automation-guide.md
T
yeuimu 9ec7dcb15a docs(skill): warn --config must be flat action config
Wrapping --config in {"config":{...}} deploys a silent empty script
(succeeds in ~1ms, result {}). Document the trap + verification recipe
(workflow get --json, nodes[].config.code non-empty).
2026-08-18 07:49:51 +00:00

9.4 KiB

Automation Guide

Automations (workflows) are event-driven: a trigger fires, then actions run in topological order. inkreach-teable's automation engine is self-built — use the inkreach-teable CLI (not official teable).

Required reading before configuring triggers: trigger-types.md Required reading before writing script actions: action-types.md

Mental Model

[Trigger] → [Action 1] → [Action 2] → ... → [triggerEnd]
  • A workflow has exactly one trigger node (type trigger) and N action nodes (type action).
  • Nodes connect via edges (linear chain; each node has at most one upstream — no parallel branches).
  • Activating freezes a snapshot; execution runs against the snapshot, not the draft.
  • hasDraft: true = unactivated changes exist; re-activate to apply.

Available Commands

Command Purpose
workflow list List all workflows in the base
workflow get <id> Detail (nodes + edges + config)
workflow create --name <n> Create (auto-adds a recordCreated trigger)
workflow update <id> [--name] [--description] Rename
workflow delete <id> Soft-delete
workflow activate <id> Snapshot + register trigger + create auto-token
workflow deactivate <id> Unregister trigger
workflow test <id> Mock-input test run (no trigger, no queue)
trigger set <id> --type <T> ... Set trigger type + config
action add <id> --type <T> ... Add an action node
action update <id> <nodeId> ... Update an action node
action delete <id> <nodeId> Remove an action node
secret set/list/delete Manage script secrets
runs list/get/rerun Execution history
fire button-click/webhook Manually trigger for testing

Trigger Selection

User scenario --type Key options
React to new records recordCreated --table-id
React to record changes recordUpdated --table-id, --field-ids (empty = all)
React when a condition matches recordCondition --table-id, --conditions (required)
React to create OR update recordCreatedOrUpdated --table-id, --conditions (optional)
Form submission formSubmitted --table-id, --form-ids <csv>
Schedule (only type+interval work) scheduledTime --schedule '{"timing":{"type":"minutes","interval":5}}'
Button field click buttonClick --table-id, --field-ids
External HTTP POST webhook (none; auth backend-ignored)

Batch processing (record triggers only): add --batch '{"enabled":true,"batchWindow":2000,"batchSize":100}' to merge events within a window into a single run. The script receives an array of records.

Full config details: trigger-types.md.

Action Selection

Goal --type Key options
Run JS code (transform, call APIs, compute) script --code '<js>' or --code-file <path>, --timeout <ms>
Send email sendEmail --to, --subject, --body <html>
Call external HTTP httpRequest --url, --method, --headers <json>, --req-body <json>
Create records createRecord --target-table <id>, --records <json>
Update records updateRecord --target-table <id>, --records <json>
Query records getRecords --target-table <id>, --query <json>
Send system notification (站内信) sendNotification --to-user <usrId>, --title, --message, --severity, --path

Full config details: action-types.md.

⚠️ action update --config '<json>' takes the flat action config (e.g. {"code":"...","timeout":120000}), NOT {"config":{...}}. A wrapped config deploys an empty script that "succeeds" in ~1ms with result: {} and breaks downstream {{nodeId.result.*}} references. After any --config deploy, verify with workflow get --json that nodes[].config.code is non-empty. Details: action-types.md § script.

Creation Workflow

# 1. Gather IDs
inkreach-teable table get tblXXX        # confirm table
inkreach-teable field list tblXXX       # find field ids for triggers

# 2. Create workflow
inkreach-teable workflow create --name "My automation"
# → returns wflXXX

# 3. Set trigger
inkreach-teable trigger set wflXXX --type recordUpdated \
  --table-id tblXXX --field-ids '["fldStatus"]'

# 4. Add action(s)
inkreach-teable action add wflXXX --type script \
  --code 'return { status: triggerInput.record.fields.Status }'

# 5. (Optional) add secrets the script needs
inkreach-teable secret set wflXXX --name API_KEY --value sk_xxx

# 6. Activate
inkreach-teable workflow activate wflXXX
# → returns snapshotId

# 7. Test
inkreach-teable fire button-click tblXXX recXXX fldXXX   # for buttonClick
# or just perform the triggering action (create/update a record, POST webhook...)
inkreach-teable runs list wflXXX

Editing an Existing Workflow

# Change trigger config
inkreach-teable trigger set wflXXX --type buttonClick --table-id tblXXX --field-ids '["fldNew"]'
# Add another action
inkreach-teable action add wflXXX --type sendEmail --to a@b.com --subject Done --body '<p>ok</p>'
# Remove an action
inkreach-teable action delete wflXXX node-12345
# RE-ACTIVATE to snapshot the changes
inkreach-teable workflow activate wflXXX

trigger set / action add/update/delete internally do GET→modify→PUT the whole graph, so they're safe. But you must re-activate for changes to take effect at runtime.

Secrets

Scripts often need API keys. Never hardcode — use secrets.

inkreach-teable secret set wflXXX --name OPENAI_KEY --value sk-xxx --description "for AI calls"
inkreach-teable secret list wflXXX           # names only — value never returned
inkreach-teable secret update wflXXX secXXX --value sk-new
inkreach-teable secret delete wflXXX secXXX

In a script action, read via process.env.OPENAI_KEY. Secrets are AES-encrypted at rest.

Testing / Triggering

Most triggers fire from real events (record create/update, form submit, schedule). Two triggers are manually fireable for testing:

# Button field click
inkreach-teable fire button-click <tableId> <recordId> <fieldId>

# Webhook (no auth needed)
inkreach-teable fire webhook <baseId> <workflowId> --body '{"event":"test"}'

For other triggers, test by performing the real action (create/update a record, submit the form). Then inspect:

inkreach-teable runs list wflXXX --status failed
inkreach-teable runs get wflXXX <executionId>
# rerun a failed execution
inkreach-teable runs rerun wflXXX <executionId>

workflow test vs real fire

workflow test <id> runs actions synchronously with mock input (a fake {record:{id:'rec_test',fields:{}}, user:{...}}). It does NOT fire the trigger or use the queue. Two caveats:

  • Upstream outputs are absent in test mode — if a script reads triggerInput.record.fields.<X>, it gets {} because the mock record has no fields. Test only validates that the script runs without throwing, not that it produces correct data.
  • For data-dependent validation, do a real fire (button-click / webhook) or perform the real triggering action, then check runs list.

Variable References (cross-node data)

An action can reference upstream nodes' output in string fields via {{nodeId.path}} (or the compatible {{index.path}} positional form):

  • {{n0.record.id}} — trigger record's id (n0 = trigger node)
  • {{n0.record.fields.Status}} — trigger record's Status field
  • {{2.result}} — output of the first action (numeric index form; index = topological execution order, trigger is always 1)

Both forms resolve to the same value — {{n0.record.id}} ≡ {{1.record.id}}. Use {{nodeId.path}} in new workflows for clarity.

Empty-value semantics: if a variable resolves to an empty string, the node sees the literal empty value. For sendNotification, an empty toUserId makes the node silently skip (status succeeded, sentCount: 0) instead of failing — so a script action that returns an empty recipient implements "notify only when X" conditional patterns. An empty message still fails with Missing required fields: message.

Common Patterns

Notify on status change

inkreach-teable workflow create --name "Status→email"
inkreach-teable trigger set wflXXX --type recordUpdated --table-id tblXXX --field-ids '["fldStatus"]'
inkreach-teable action add wflXXX --type sendEmail \
  --to ops@x.com --subject 'Status changed' \
  --body '{{n0.record.fields.Status}}'
inkreach-teable workflow activate wflXXX

Daily digest

inkreach-teable trigger set wflXXX --type scheduledTime \
  --schedule '{"timing":{"type":"hours","interval":24}}'

Button → script → update another table

inkreach-teable trigger set wflXXX --type buttonClick --table-id tblA --field-ids '["fldGo"]'
inkreach-teable action add wflXXX --type script --code '
  const r = triggerInput.record;
  // call back into the instance API using the auto-injected token
  const res = await fetch(triggerInput._apiBaseUrl + "/api/table/tblB/record", {
    method: "POST",
    headers: { Authorization: "Bearer " + triggerInput._accessToken, "Content-Type": "application/json" },
    body: JSON.stringify({ fields: { Source: r.id } })
  });
  return { created: await res.json() };
'