@unstable-dev/unmeshed-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +64 -0
  2. package/dist/auth.d.ts +6 -0
  3. package/dist/auth.js +11 -0
  4. package/dist/client.d.ts +46 -0
  5. package/dist/client.js +97 -0
  6. package/dist/config.d.ts +10 -0
  7. package/dist/config.js +31 -0
  8. package/dist/get-docs.d.ts +8 -0
  9. package/dist/get-docs.js +64 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +35 -0
  12. package/dist/server.d.ts +4 -0
  13. package/dist/server.js +203 -0
  14. package/knowledge/README.md +16 -0
  15. package/knowledge/SKILL.md +359 -0
  16. package/knowledge/assets/patterns.md +637 -0
  17. package/knowledge/execution/debugging-guide.md +18 -0
  18. package/knowledge/execution/process-run.schema.md +24 -0
  19. package/knowledge/execution/step-run.schema.md +21 -0
  20. package/knowledge/process-definition.schema.md +36 -0
  21. package/knowledge/references/integrations.md +914 -0
  22. package/knowledge/references/steps-knowledge.md +834 -0
  23. package/knowledge/step-definition.schema.md +140 -0
  24. package/knowledge/step-output-paths.md +45 -0
  25. package/knowledge/steps/DECISION_ENGINE.md +248 -0
  26. package/knowledge/steps/DEPENDSON.md +296 -0
  27. package/knowledge/steps/EXIT.md +220 -0
  28. package/knowledge/steps/FAIL.md +198 -0
  29. package/knowledge/steps/FLOW_GATEWAY.md +405 -0
  30. package/knowledge/steps/FOREACH.md +250 -0
  31. package/knowledge/steps/HTTP.md +183 -0
  32. package/knowledge/steps/JAVASCRIPT.md +192 -0
  33. package/knowledge/steps/JQ.md +189 -0
  34. package/knowledge/steps/LIST.md +279 -0
  35. package/knowledge/steps/NOOP.md +165 -0
  36. package/knowledge/steps/PARALLEL.md +366 -0
  37. package/knowledge/steps/PYTHON.md +206 -0
  38. package/knowledge/steps/SEND_RESPONSE.md +301 -0
  39. package/knowledge/steps/SQLITE.md +301 -0
  40. package/knowledge/steps/SUB_PROCESS.md +296 -0
  41. package/knowledge/steps/SWITCH.md +369 -0
  42. package/knowledge/steps/UPDATE_STEP.md +257 -0
  43. package/knowledge/steps/WAIT.md +218 -0
  44. package/knowledge/steps/WHILE.md +328 -0
  45. package/knowledge/steps/WORKER.md +233 -0
  46. package/knowledge/system-prompt.md +274 -0
  47. package/package.json +39 -0
@@ -0,0 +1,359 @@
1
+ ---
2
+ name: unmeshed-workflow
3
+ description: >
4
+ Generate valid Unmeshed process workflow JSON definitions. Use this skill
5
+ whenever the user says "create a workflow", "build a workflow", "generate a
6
+ workflow", "design a workflow", or describes any automation, orchestration,
7
+ or multi-step process they want to run in Unmeshed. Also trigger when the
8
+ user asks to add steps to an existing workflow, modify an existing workflow
9
+ JSON, or convert a business process description into an Unmeshed-compatible
10
+ JSON. This skill must be used any time Unmeshed workflow generation or
11
+ editing is involved — even if the user's phrasing is indirect, like "I want
12
+ to automate X using Unmeshed" or "how would I build X in Unmeshed".
13
+ ---
14
+
15
+ # Unmeshed Workflow Generator
16
+
17
+ Converts plain-language process descriptions into valid Unmeshed
18
+ `API_ORCHESTRATION` workflow JSON, following the exact schema and conventions
19
+ derived from real Unmeshed workflow samples.
20
+
21
+ Always read `references/step-types.md` and `references/integrations.md` before
22
+ generating any workflow. Also read `assets/patterns.md` for ready-to-use
23
+ scaffolds.
24
+
25
+ ---
26
+
27
+ ## Clarification Rules (ALWAYS follow before generating)
28
+
29
+ Before generating any workflow JSON, ask the user for any missing answers to:
30
+
31
+ 1. **Workflow name** — a kebab-case identifier (e.g. `send-welcome-email`)
32
+ 2. **Namespace** — defaults to `"default"` if not specified
33
+ 3. **Description** — a one-sentence summary of what it does
34
+ 4. **Trigger / entry point** — what starts this workflow? (API call, form submission, schedule, another workflow, etc.)
35
+ 5. **Steps** — what should each step do, in order?
36
+ 6. **Integrations needed** — which external services are involved? (Google Sheets, Drive, Slack, LLM Claude, Notion, PostgreSQL, HTTP APIs, etc.)
37
+ 7. **Branching logic** — are there any if/else conditions, switch branches, or parallel paths?
38
+ 8. **Data flow** — what data passes from step to step? Ask about key field names if unclear.
39
+ 9. **Error handling** — should any steps retry on failure, or exit cleanly with a FAILED status?
40
+ 10. **Caching** — are any expensive integration calls (e.g. LLM) safe to cache? If so, what's the cache key?
41
+
42
+ Do NOT generate JSON until you have enough answers to produce a correct workflow.
43
+ If a question is not critical (e.g. description), use a sensible default and note it.
44
+
45
+ ---
46
+
47
+ ## Output Format
48
+
49
+ Always output a single, complete, valid JSON object. Follow the top-level schema:
50
+
51
+ ```json
52
+ {
53
+ "orgId": 1,
54
+ "namespace": "<namespace>",
55
+ "name": "<kebab-case-name>",
56
+ "version": 1,
57
+ "type": "API_ORCHESTRATION",
58
+ "description": "<description or null>",
59
+ "configuration": null,
60
+ "steps": [
61
+ /* array of step objects */
62
+ ],
63
+ "defaultInput": null,
64
+ "defaultOutput": null,
65
+ "outputMapping": null,
66
+ "signature": null,
67
+ "metadata": null,
68
+ "tags": null,
69
+ "dependencies": null,
70
+ "dependents": null
71
+ }
72
+ ```
73
+
74
+ **Top-level optional fields:**
75
+
76
+ - `defaultInput`: provide a JSON object as an example payload for testing (useful for workflows with complex inputs)
77
+ - `outputMapping`: a JQ expression string that reshapes the final workflow output; use when the consumer expects a specific response shape
78
+ - `tags`: always `null` — do not populate this field
79
+
80
+ After the JSON, always add a **Workflow Summary** section explaining:
81
+
82
+ - What each step does in plain English
83
+ - The data flow between steps
84
+ - Any assumptions made
85
+ - Any placeholders the user must replace (e.g. connection names, spreadsheet IDs, folder IDs)
86
+
87
+ ---
88
+
89
+ ## Step Construction Rules
90
+
91
+ Every step — at every nesting level — must include this full structure:
92
+
93
+ ```json
94
+ {
95
+ "orgId": 1,
96
+ "namespace": "<same as workflow>",
97
+ "name": "<snake_case_name>",
98
+ "type": "<STEP_TYPE>",
99
+ "ref": "<unique_ref_id>",
100
+ "optional": false,
101
+ "createdBy": "system",
102
+ "updatedBy": "system",
103
+ "description": "<string or null>",
104
+ "label": null,
105
+ "created": 1700000000000,
106
+ "updated": 1700000000000,
107
+ "configuration": {
108
+ /* standard config block */
109
+ },
110
+ "children": [],
111
+ "input": {
112
+ /* step-specific input */
113
+ },
114
+ "output": null
115
+ }
116
+ ```
117
+
118
+ **Standard `configuration` block** (use for every step unless noted):
119
+
120
+ ```json
121
+ {
122
+ "errorPolicyName": null,
123
+ "useCache": false,
124
+ "cacheKey": null,
125
+ "cacheTimeoutSeconds": 0,
126
+ "stream": false,
127
+ "streamAllStatuses": false,
128
+ "preExecutionScript": null,
129
+ "constructInputFromScript": false,
130
+ "scriptLanguage": null,
131
+ "jqTransformer": null,
132
+ "rateLimitMaxRequests": 0,
133
+ "rateLimitWindowSeconds": 0
134
+ }
135
+ ```
136
+
137
+ **Configuration field guidance:**
138
+
139
+ - `errorPolicyName`: set to a named error policy string (e.g. `"retry-3x"`) if the step should retry on failure; otherwise `null`
140
+ - `useCache`: set to `true` to cache step output; pair with a `cacheKey` and `cacheTimeoutSeconds`
141
+ - `cacheKey`: a string key (can include `{{...}}` template variables) — e.g. `"llm-classify-{{steps.map_input.output.result.category}}"`
142
+ - `cacheTimeoutSeconds`: how long to keep the cached result (e.g. `3600` = 1 hour); only meaningful when `useCache: true`
143
+ - `stream` / `streamAllStatuses`: set `true` for LLM streaming responses (advanced use)
144
+ - `jqTransformer`: a JQ expression to post-process the raw step output before it is stored
145
+ - `rateLimitMaxRequests` / `rateLimitWindowSeconds`: set both to non-zero to throttle a step (e.g. `10` requests per `60` seconds)
146
+
147
+ **`ref` naming convention**: Use `<name>_<index>` for integrations/stateful steps (e.g. `google_sheets_1`, `llm_claude_1`). Use the plain `name` value for script/logic steps (e.g. `preprocessing`, `format_resume_link`).
148
+
149
+ **Variable references** between steps must use the producer step's output shape:
150
+
151
+ - Native `HTTP`: `{{steps.<ref>.output.response.<field>}}` or `steps.<ref>.output.response` in scripts
152
+ - Native `HTTP` status code: `{{steps.<ref>.output.statusCode}}`
153
+ - `JAVASCRIPT`: `{{steps.<ref>.output.result.<field>}}` or `steps.<ref>.output.result` in scripts
154
+ - `PYTHON`: `{{steps.<ref>.output.result.<field>}}` or `steps.<ref>.output.result` in scripts
155
+ - `NOOP`: `{{steps.<ref>.output.<field>}}` (not wrapped in `result`)
156
+ - `INTEGRATION`: use the integration-specific documented path, commonly `output.result` or `output.results`
157
+
158
+ Never reference a native `HTTP` step as `steps.<http_ref>.output.result`.
159
+ For example, after an `HTTP` step with ref `fetch_posts_1`, use:
160
+
161
+ ```javascript
162
+ (steps, context) => {
163
+ const posts = steps.fetch_posts_1.output.response || [];
164
+ return { count: Array.isArray(posts) ? posts.length : 0 };
165
+ }
166
+ ```
167
+
168
+ ---
169
+
170
+ ## Step Types Reference
171
+
172
+ Read `references/step-types.md` for full details on all step types.
173
+ Read `references/integrations.md` for integration `input` schemas.
174
+
175
+ ### Quick Reference
176
+
177
+ | Type | Use when |
178
+ | ----------------- | --------------------------------------------------------------------------------------------------------------- |
179
+ | `JAVASCRIPT` | Data mapping, transformation, normalization, assertions |
180
+ | `PYTHON` | File processing, filesystem access, binary/base64 ops |
181
+ | `NOOP` | Static config/constants passed as output |
182
+ | `INTEGRATION` | Calling external services (Google, Slack, LLM, MongoDB, Redis, Airtable, Jira, Outlook, Notion, HTTP, DB, etc.) |
183
+ | `HTTP` | Direct HTTP calls with optional polling/repeat-until support |
184
+ | `WAIT` | Pause execution for N seconds (e.g. wait for email delivery) |
185
+ | `FOREACH` | Iterate over an array, running child steps per element |
186
+ | `WHILE` | Loop while a condition is true; use `whileloop.iteration` counter |
187
+ | `DECISION_ENGINE` | Rule-table based routing |
188
+ | `SWITCH` | Conditional branching (if/else, multi-branch, rate-limit handling) |
189
+ | `LIST` | Sequential group of steps — branch body inside SWITCH or PARALLEL |
190
+ | `PARALLEL` | Run multiple LIST branches or SUB_PROCESS steps simultaneously |
191
+ | `SUB_PROCESS` | Invoke another named workflow |
192
+ | `PERSISTED_STATE` | Read/write persistent key-value state |
193
+ | `EXIT` | Terminate workflow with a status and message |
194
+ | `FAIL` | Immediately fail the workflow/branch with a reason |
195
+ | `DEPENDSON` | Wait for an external process or step to reach a target status (cross-workflow sync) |
196
+ | `UPDATE_STEP` | Programmatically update the status/output of a step in another running workflow (callbacks, approvals) |
197
+ | `SQLITE` | Execute SQL (SELECT/INSERT/UPDATE/DELETE/DDL) against a named SQLite datastore |
198
+
199
+ ---
200
+
201
+ ## Common Patterns
202
+
203
+ Read `assets/patterns.md` for full scaffolds. Quick reference:
204
+
205
+ ### Pattern A — Linear pipeline
206
+
207
+ `NOOP (config) → JAVASCRIPT (preprocess) → INTEGRATION → JAVASCRIPT (format) → INTEGRATION`
208
+
209
+ ### Pattern B — LLM classification then routing
210
+
211
+ `JAVASCRIPT (map fields) → INTEGRATION (llm-claude) → DECISION_ENGINE`
212
+
213
+ ### Pattern C — State-gated branch (create or reuse resource)
214
+
215
+ `PERSISTED_STATE (read) → SWITCH → [LIST branch new, LIST branch existing]`
216
+
217
+ ### Pattern D — Parallel sub-process fan-out
218
+
219
+ `SWITCH (gate check) → PARALLEL (children: SUB_PROCESS steps)`
220
+
221
+ ### Pattern E — Classify → Store always → Conditionally notify
222
+
223
+ `JAVASCRIPT → INTEGRATION (llm) → DECISION_ENGINE → JAVASCRIPT (format) → INTEGRATION (sheets) → SWITCH (notify?)`
224
+
225
+ ### Pattern F — HTTP API Call → Normalize → Store
226
+
227
+ `JAVASCRIPT (build payload) → HTTP → JAVASCRIPT (normalize) → INTEGRATION (db/sheets)`
228
+
229
+ ### Pattern G — Error-Aware Exit Branches
230
+
231
+ `JAVASCRIPT (validate) → SWITCH → [EXIT on invalid, LIST on valid]`
232
+
233
+ ### Pattern H — WAIT for Async Side Effect
234
+
235
+ `SUB_PROCESS (trigger action) → WAIT (N seconds) → INTEGRATION (verify) → JAVASCRIPT (assert)`
236
+
237
+ ### Pattern I — FOREACH Loop
238
+
239
+ `FOREACH (inputArray, concurrency) → LIST → [steps] → JAVASCRIPT (collect results) → JAVASCRIPT (assert)`
240
+
241
+ ### Pattern J — PARALLEL with inline LIST branches
242
+
243
+ `PARALLEL → [LIST branch_1, LIST branch_2, ...]` — branches are inline, not sub-processes
244
+
245
+ ### Pattern K — Rate-Limit Aware Integration
246
+
247
+ `INTEGRATION (optional:true, retry) → SWITCH (check for 429 error) → [skip branch, main branch]`
248
+
249
+ ### Pattern L — WHILE Loop with State Counter
250
+
251
+ `WHILE (iteration < N) → LIST → [WAIT (throttle), JAVASCRIPT (__statePut)]`
252
+
253
+ ### Pattern M — Error Policy Retry Check
254
+
255
+ `STEP (optional:true, errorPolicyName) → JAVASCRIPT (assert executionList.length or check output.error)`
256
+
257
+ ### Pattern N — Variables and Secrets in HTTP
258
+
259
+ Use `{{variables.*}}` for base URLs/config and `{{secrets.*}}` for tokens — never hardcode
260
+
261
+ ### Pattern O — Cross-Branch Synchronisation with DEPENDSON
262
+
263
+ `PARALLEL → [LIST (WAIT → HTTP), LIST (WAIT → DEPENDSON waits for HTTP)]` — use DEPENDSON to sync across sibling PARALLEL branches
264
+
265
+ ### Pattern P — Guard with FAIL
266
+
267
+ `JAVASCRIPT (validate) → SWITCH → [LIST (happy path), FAIL (error path)]` — FAIL terminates the branch/process immediately
268
+
269
+ ### Pattern Q — External Callback with UPDATE_STEP
270
+
271
+ `Workflow A: HTTP → WAIT (paused)` ... `Workflow B: UPDATE_STEP (completes WAIT in A with callback data)`
272
+
273
+ ### Pattern R — Human Task Approval with UPDATE_STEP
274
+
275
+ `INTEGRATION (send approval email) → WAIT (paused)` ... `Approval workflow: UPDATE_STEP (BY_COMPLETION_TOKEN, completes WAIT)`
276
+
277
+ ### Pattern S — SQLITE CRUD Pipeline
278
+
279
+ `SQLITE (create table) → SQLITE (insert row) → SQLITE (select) → JAVASCRIPT (process rows)`
280
+
281
+ ---
282
+
283
+ ## Key Rules
284
+
285
+ - `name` fields are `snake_case` or `kebab-case` consistently within the workflow
286
+ - `ref` values must be **unique** across the entire workflow including nested children
287
+ - `optional: true` on a step allows the workflow to continue even if that step fails — use for best-effort steps or rate-limit-prone integrations
288
+ - SWITCH `children` can be **any step type** — `LIST`, `INTEGRATION`, `NOOP`, `EXIT`, `JAVASCRIPT`. Do NOT wrap single-step branches in LIST unnecessarily.
289
+ - SWITCH `input.responseMapping` must have a `defaultBranch: true` entry
290
+ - PARALLEL children can be **LIST steps** (inline multi-step branches) OR **SUB_PROCESS steps** (sub-workflow fan-out) — not just SUB_PROCESS
291
+ - PARALLEL `input` must include `"failIfAnyBranchFails": true` (strict) or `false` (lenient)
292
+ - FOREACH `input` requires `inputArray` and `concurrency`; access iteration outputs as `steps["<ref>[N]"].output`
293
+ - WHILE `input.script` returns a boolean; use `whileloop.iteration` for the loop counter; always include a WAIT inside the loop body
294
+ - WAIT inside a WHILE loop: use `steps.<while_ref>.updated + N` as the base time (not `steps.__self.startTime`)
295
+ - `context.state.<key>` — read mutable in-run state; write via returning `{ "__statePut": { key: value } }` from any JAVASCRIPT step
296
+ - `{{variables.<name>}}` and `{{secrets.<name>}}` — inject env vars and secrets in HTTP URLs, headers, params, body
297
+ - `steps.__self.executionList.length` — number of retry attempts so far (populated by error policies)
298
+ - `steps.<ref>.output.error` — error message string from a failed optional step; check with `.includes()`
299
+ - `steps.<ref>.input.<field>` — access a prior step's INPUT (not output) from a later step; e.g. `steps.http_step.input.body.content.userId`
300
+ - WAIT `input.script` must return `{ waitUntil: steps.__self.startTime + (N * 1000) }`
301
+ - HTTP (native step type, uppercase) supports `repeatUntilEnabled` polling; use for internal API calls with retry logic
302
+ - SUB_PROCESS `input` must include `processName` and `waitForCompletion`
303
+ - PERSISTED_STATE `input` must include `operation` (`READ` or `UPSERT`), `name`, and `path`
304
+ - EXIT `input` must include `message` and `status` (`"COMPLETED"` or `"FAILED"`)
305
+ - FAIL `input` must include `reason` (string) — always produces a `FAILED` status; use for error branches, guard failures
306
+ - FAIL vs EXIT: FAIL always fails and uses `reason`; EXIT supports both `COMPLETED`/`FAILED` and uses `message` + `status`
307
+ - DEPENDSON `input` must include `dependsOnStatement` (SQL-style expression) and `intervalSeconds` (polling interval)
308
+ - DEPENDSON statement syntax: `STEP('process-name', 'step-ref', 'STATUS')` or `PROCESS('process-name', 'STATUS')` — combine with `AND` / `OR`
309
+ - DEPENDSON output: check `steps.<ref>.output.__repeatConditionMatched` (bool) and `steps.<ref>.output.__dependsOnOutput.result` (bool)
310
+ - DECISION_ENGINE `input` must include `decisionTable`, `decisionContext`, `decisionRuleStrategy` (`FIRST_MATCH` or `ALL_MATCH`), and `decisionOutputColumns`
311
+ - DECISION_ENGINE output: `FIRST_MATCH` returns `steps.<ref>.output.result.<column>` (single object); `ALL_MATCH` returns `steps.<ref>.output.result` as an array
312
+ - UPDATE_STEP `input` must include `inputMatchType` (`BY_PROCESS_ID_REF`, `BY_CORRELATION_ID_REF`, `BY_REQUEST_ID_REF`, `BY_STEP_ID`, `BY_COMPLETION_TOKEN`)
313
+ - UPDATE_STEP: `stepStatus` must be `COMPLETED`, `FAILED`, or `RUNNING` (defaults to `COMPLETED`); `output` is merged into the target step's output
314
+ - UPDATE_STEP: `maxWaitSeconds` (default 24h) controls how long the step polls before failing; engine polls every 30s
315
+ - UPDATE_STEP: target steps must be in an updatable status (SCHEDULED, RUNNING) — already terminal steps cannot be updated
316
+ - SQLITE `input` must include `storeName` (database name) and `sql` (SQL statement ending with `;`)
317
+ - SQLITE uses `:#paramName` parameter binding syntax — never interpolate values into SQL strings
318
+ - SQLITE SELECT output: `steps.<ref>.output.result.rows` (array of row objects), `steps.<ref>.output.result.rowsAffected` (always 0 for SELECT)
319
+ - SQLITE INSERT/UPDATE/DELETE output: `steps.<ref>.output.result.rowsAffected` (count), `steps.<ref>.output.result.rows` (empty `[]`)
320
+ - SQLITE `parameters` must be a flat key-value object — each key matches a `:#key` placeholder in `sql`
321
+ - LLM Claude output is under `.results` (plural) — always defensively read: `steps.<ref>.output.results || steps.<ref>.output.result || {}`
322
+ - MongoDB output is under `.results.<field>` (directly on results, not nested in `.result`)
323
+ - Redis GET of a JSON object exposes fields directly on `.results` (e.g. `.results.name`, `.results.age`)
324
+ - Slack `input.type` is `"slack-messaging"` — build message string in a preceding JAVASCRIPT step
325
+ - Notion operations all go in `messageBody.operation`; `publishProperties` is `{}`
326
+ - Jira operations all go in `publishProperties.action`; `messageBody` is `{}`
327
+ - Airtable `pageSize` and `maxRecords` are strings: `"100"` not `100`
328
+ - Outlook `receivedFromMinutesAgo` is a string: `"60"` not `60`; attachments land at `/app/files/_outlook_attachments_/`
329
+ - Always add WAIT after SUB_PROCESS when the sub-process triggers async effects (emails, webhooks) before reading results
330
+ - When a step should always run (e.g. log/store), put it **before** a SWITCH — the SWITCH only handles conditional paths after
331
+ - Always list placeholders in the Workflow Summary (connection names, IDs, folder IDs, etc.)
332
+
333
+ ---
334
+
335
+ ## Data Flow Cheatsheet
336
+
337
+ ```
338
+ context.input.<field> ← workflow API input
339
+ steps.<ref>.output.response.<field> ← native HTTP response body
340
+ steps.<ref>.output.statusCode ← native HTTP status code
341
+ steps.<ref>.output.result.<field> ← JAVASCRIPT / PYTHON / most INTEGRATION output
342
+ steps.<ref>.output.results.<field> ← LLM Claude output (note: results plural)
343
+ steps.<ref>.output.<field> ← NOOP output (no .result wrapper)
344
+ steps.<ref>.output.spreadsheetId ← Google Sheets CREATE output
345
+ steps.<ref>.output.result.rows ← PostgreSQL / MySQL SELECT output
346
+ steps.<ref>.output.id ← Google Drive upload output (file ID)
347
+ steps.<ref>.output.webViewLink ← Google Drive upload output (share URL)
348
+ steps.<ref>.output.result.<column> ← DECISION_ENGINE FIRST_MATCH output
349
+ steps.<ref>.output.result[N].<column> ← DECISION_ENGINE ALL_MATCH output (array)
350
+ steps.<ref>.output.__dependsOnOutput.result ← DEPENDSON boolean result (true/false)
351
+ steps.<ref>.output.__repeatConditionMatched ← DEPENDSON matched before cancel (true/false)
352
+ steps.<ref>.output.reason ← FAIL step reason string
353
+ steps.<ref>.output.__updateStepResults ← UPDATE_STEP map of processId:stepId → status message
354
+ steps.<ref>.output.__updateStepMetadata ← UPDATE_STEP array of update detail objects
355
+ steps.<ref>.output.result.rows ← SQLITE SELECT row data
356
+ steps.<ref>.output.result.rowsAffected ← SQLITE write affected count
357
+ steps.__self.id ← current step ID (inside scripts)
358
+ context.id ← workflow process/run ID
359
+ ```