@withone/cli 1.12.2 → 1.12.3
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.
- package/dist/index.js +434 -140
- package/package.json +3 -2
- package/skills/one-actions/SKILL.md +151 -0
- package/skills/one-flow/SKILL.md +603 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: one-flow
|
|
3
|
+
description: |
|
|
4
|
+
Build and execute multi-step API workflows that chain actions across platforms — like n8n/Zapier but file-based. Workflows are JSON files stored at `.one/flows/<key>.flow.json`.
|
|
5
|
+
|
|
6
|
+
TRIGGER when the user wants to:
|
|
7
|
+
- Create a multi-step workflow or automation (e.g., "create a workflow that looks up a customer in Stripe and sends them an email")
|
|
8
|
+
- Chain multiple API actions together across platforms
|
|
9
|
+
- Build a pipeline or sequence of API calls
|
|
10
|
+
- Execute, validate, or manage existing workflows
|
|
11
|
+
- Automate a process involving multiple connected platforms
|
|
12
|
+
- Schedule or orchestrate a series of actions
|
|
13
|
+
|
|
14
|
+
DO NOT TRIGGER for:
|
|
15
|
+
- Single action execution (use one-actions skill instead)
|
|
16
|
+
- Setting up One or installing MCP (that's `one init`)
|
|
17
|
+
- Adding new connections (that's `one connection add`)
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# One Workflows — Multi-Step API Workflows
|
|
21
|
+
|
|
22
|
+
You have access to the One CLI's workflow engine, which lets you create and execute multi-step API workflows as JSON files. Workflows chain actions across platforms — e.g., look up a Stripe customer, then send them a welcome email via Gmail.
|
|
23
|
+
|
|
24
|
+
## 1. Overview
|
|
25
|
+
|
|
26
|
+
- Workflows are JSON files stored at `.one/flows/<key>.flow.json`
|
|
27
|
+
- All dynamic values (including connection keys) are declared as **inputs**
|
|
28
|
+
- Each workflow has a unique **key** used to reference and execute it
|
|
29
|
+
- Executed via `one --agent flow execute <key> -i name=value`
|
|
30
|
+
|
|
31
|
+
## 2. Building a Workflow — Step-by-Step Process
|
|
32
|
+
|
|
33
|
+
**You MUST follow this process to build a correct workflow:**
|
|
34
|
+
|
|
35
|
+
### Step 1: Discover connections
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
one --agent connection list
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Find out which platforms are connected and get their connection keys.
|
|
42
|
+
|
|
43
|
+
### Step 2: For EACH API action needed, get the knowledge
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Find the action ID
|
|
47
|
+
one --agent actions search <platform> "<query>" -t execute
|
|
48
|
+
|
|
49
|
+
# Read the full docs — REQUIRED before adding to a workflow
|
|
50
|
+
one --agent actions knowledge <platform> <actionId>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**CRITICAL:** You MUST call `one actions knowledge` for every action you include in the workflow. The knowledge output tells you the exact request body structure, required fields, path variables, and query parameters. Without this, your workflow JSON will have incorrect data shapes.
|
|
54
|
+
|
|
55
|
+
### Step 3: Construct the workflow JSON
|
|
56
|
+
|
|
57
|
+
Using the knowledge gathered, build the workflow JSON with:
|
|
58
|
+
- All inputs declared (connection keys + user parameters)
|
|
59
|
+
- Each step with the correct actionId, platform, and data structure (from knowledge)
|
|
60
|
+
- Data wired between steps using `$.input.*` and `$.steps.*` selectors
|
|
61
|
+
|
|
62
|
+
### Step 4: Write the workflow file
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
one --agent flow create <key> --definition '<json>'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or write directly to `.one/flows/<key>.flow.json`.
|
|
69
|
+
|
|
70
|
+
### Step 5: Validate
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
one --agent flow validate <key>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Step 6: Execute
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
one --agent flow execute <key> -i connectionKey=xxx -i param=value
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 3. Workflow JSON Schema Reference
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"key": "welcome-customer",
|
|
87
|
+
"name": "Welcome New Customer",
|
|
88
|
+
"description": "Look up a Stripe customer and send them a welcome email via Gmail",
|
|
89
|
+
"version": "1",
|
|
90
|
+
"inputs": {
|
|
91
|
+
"stripeConnectionKey": {
|
|
92
|
+
"type": "string",
|
|
93
|
+
"required": true,
|
|
94
|
+
"description": "Stripe connection key from one connection list",
|
|
95
|
+
"connection": { "platform": "stripe" }
|
|
96
|
+
},
|
|
97
|
+
"gmailConnectionKey": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"required": true,
|
|
100
|
+
"description": "Gmail connection key from one connection list",
|
|
101
|
+
"connection": { "platform": "gmail" }
|
|
102
|
+
},
|
|
103
|
+
"customerEmail": {
|
|
104
|
+
"type": "string",
|
|
105
|
+
"required": true,
|
|
106
|
+
"description": "Customer email to look up"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"steps": [
|
|
110
|
+
{
|
|
111
|
+
"id": "stepId",
|
|
112
|
+
"name": "Human-readable label",
|
|
113
|
+
"type": "action",
|
|
114
|
+
"action": {
|
|
115
|
+
"platform": "stripe",
|
|
116
|
+
"actionId": "the-action-id-from-search",
|
|
117
|
+
"connectionKey": "$.input.stripeConnectionKey",
|
|
118
|
+
"data": {},
|
|
119
|
+
"pathVars": {},
|
|
120
|
+
"queryParams": {},
|
|
121
|
+
"headers": {}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Input declarations
|
|
129
|
+
|
|
130
|
+
| Field | Type | Description |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `type` | string | `string`, `number`, `boolean`, `object`, `array` |
|
|
133
|
+
| `required` | boolean | Whether this input must be provided (default: true) |
|
|
134
|
+
| `default` | any | Default value if not provided |
|
|
135
|
+
| `description` | string | Human-readable description |
|
|
136
|
+
| `connection` | object | Connection metadata: `{ "platform": "gmail" }` — enables auto-resolution |
|
|
137
|
+
|
|
138
|
+
**Connection inputs** have a `connection` field. If the user has exactly one connection for that platform, the workflow engine auto-resolves it.
|
|
139
|
+
|
|
140
|
+
## 4. Selector Syntax Reference
|
|
141
|
+
|
|
142
|
+
| Pattern | Resolves To |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `$.input.gmailConnectionKey` | Input value (including connection keys) |
|
|
145
|
+
| `$.input.customerEmail` | Any input parameter |
|
|
146
|
+
| `$.steps.stepId.response` | Full API response from a step |
|
|
147
|
+
| `$.steps.stepId.response.data[0].email` | Nested field with array index |
|
|
148
|
+
| `$.steps.stepId.response.data[*].id` | Wildcard — maps array to field |
|
|
149
|
+
| `$.env.MY_VAR` | Environment variable |
|
|
150
|
+
| `$.loop.item` | Current loop item |
|
|
151
|
+
| `$.loop.i` | Current loop index |
|
|
152
|
+
| `"Hello {{$.steps.getUser.response.data.name}}"` | String interpolation |
|
|
153
|
+
|
|
154
|
+
**Rules:**
|
|
155
|
+
- A value that is purely `$.xxx` resolves to the raw type (object, array, number)
|
|
156
|
+
- A string containing `{{$.xxx}}` does string interpolation (stringifies objects)
|
|
157
|
+
- Selectors inside objects/arrays are resolved recursively
|
|
158
|
+
|
|
159
|
+
## 5. Step Types Reference
|
|
160
|
+
|
|
161
|
+
### `action` — Execute a One API action
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"id": "findCustomer",
|
|
166
|
+
"name": "Search Stripe customers",
|
|
167
|
+
"type": "action",
|
|
168
|
+
"action": {
|
|
169
|
+
"platform": "stripe",
|
|
170
|
+
"actionId": "conn_mod_def::xxx::yyy",
|
|
171
|
+
"connectionKey": "$.input.stripeConnectionKey",
|
|
172
|
+
"data": {
|
|
173
|
+
"query": "email:'{{$.input.customerEmail}}'"
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### `transform` — Transform data with a JS expression
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"id": "extractNames",
|
|
184
|
+
"name": "Extract customer names",
|
|
185
|
+
"type": "transform",
|
|
186
|
+
"transform": {
|
|
187
|
+
"expression": "$.steps.findCustomer.response.data.map(c => c.name)"
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The expression is evaluated with the full flow context as `$`.
|
|
193
|
+
|
|
194
|
+
### `code` — Run multi-line JavaScript
|
|
195
|
+
|
|
196
|
+
Unlike `transform` (single expression, implicit return), `code` runs a full function body with explicit `return`. Use it when you need variables, loops, try/catch, or `await`.
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"id": "processData",
|
|
201
|
+
"name": "Process and enrich data",
|
|
202
|
+
"type": "code",
|
|
203
|
+
"code": {
|
|
204
|
+
"source": "const customers = $.steps.listCustomers.response.data;\nconst enriched = customers.map(c => ({\n ...c,\n tier: c.spend > 1000 ? 'gold' : 'silver'\n}));\nreturn enriched;"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The `source` field contains a JS function body. The flow context is available as `$`. The function is async, so you can use `await`. The return value is stored as the step result.
|
|
210
|
+
|
|
211
|
+
### `condition` — If/then/else branching
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"id": "checkFound",
|
|
216
|
+
"name": "Check if customer was found",
|
|
217
|
+
"type": "condition",
|
|
218
|
+
"condition": {
|
|
219
|
+
"expression": "$.steps.findCustomer.response.data.length > 0",
|
|
220
|
+
"then": [
|
|
221
|
+
{ "id": "sendEmail", "name": "Send welcome email", "type": "action", "action": { "..." : "..." } }
|
|
222
|
+
],
|
|
223
|
+
"else": [
|
|
224
|
+
{ "id": "logNotFound", "name": "Log not found", "type": "transform", "transform": { "expression": "'Customer not found'" } }
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### `loop` — Iterate over an array
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"id": "processOrders",
|
|
235
|
+
"name": "Process each order",
|
|
236
|
+
"type": "loop",
|
|
237
|
+
"loop": {
|
|
238
|
+
"over": "$.steps.listOrders.response.data",
|
|
239
|
+
"as": "order",
|
|
240
|
+
"indexAs": "i",
|
|
241
|
+
"maxIterations": 1000,
|
|
242
|
+
"maxConcurrency": 5,
|
|
243
|
+
"steps": [
|
|
244
|
+
{
|
|
245
|
+
"id": "createInvoice",
|
|
246
|
+
"name": "Create invoice for order",
|
|
247
|
+
"type": "action",
|
|
248
|
+
"action": {
|
|
249
|
+
"platform": "quickbooks",
|
|
250
|
+
"actionId": "...",
|
|
251
|
+
"connectionKey": "$.input.qbConnectionKey",
|
|
252
|
+
"data": { "amount": "$.loop.order.total" }
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
- `maxConcurrency` (optional): When set > 1, loop iterations run in parallel batches of that size. Default is sequential (1).
|
|
261
|
+
|
|
262
|
+
### `parallel` — Run steps concurrently
|
|
263
|
+
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"id": "parallelLookups",
|
|
267
|
+
"name": "Look up in parallel",
|
|
268
|
+
"type": "parallel",
|
|
269
|
+
"parallel": {
|
|
270
|
+
"maxConcurrency": 5,
|
|
271
|
+
"steps": [
|
|
272
|
+
{ "id": "getStripe", "name": "Get Stripe data", "type": "action", "action": { "...": "..." } },
|
|
273
|
+
{ "id": "getHubspot", "name": "Get HubSpot data", "type": "action", "action": { "...": "..." } }
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### `file-read` — Read from filesystem
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"id": "readConfig",
|
|
284
|
+
"name": "Read config file",
|
|
285
|
+
"type": "file-read",
|
|
286
|
+
"fileRead": { "path": "./data/config.json", "parseJson": true }
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### `file-write` — Write to filesystem
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"id": "writeResults",
|
|
295
|
+
"name": "Save results",
|
|
296
|
+
"type": "file-write",
|
|
297
|
+
"fileWrite": {
|
|
298
|
+
"path": "./output/results.json",
|
|
299
|
+
"content": "$.steps.transform.output",
|
|
300
|
+
"append": false
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## 6. Error Handling
|
|
306
|
+
|
|
307
|
+
### `onError` strategies
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"id": "riskyStep",
|
|
312
|
+
"name": "Might fail",
|
|
313
|
+
"type": "action",
|
|
314
|
+
"onError": {
|
|
315
|
+
"strategy": "retry",
|
|
316
|
+
"retries": 3,
|
|
317
|
+
"retryDelayMs": 1000
|
|
318
|
+
},
|
|
319
|
+
"action": { "...": "..." }
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
| Strategy | Behavior |
|
|
324
|
+
|---|---|
|
|
325
|
+
| `fail` | Stop the flow immediately (default) |
|
|
326
|
+
| `continue` | Mark step as failed, continue to next step |
|
|
327
|
+
| `retry` | Retry up to N times with delay |
|
|
328
|
+
| `fallback` | On failure, execute a different step |
|
|
329
|
+
|
|
330
|
+
### Conditional execution
|
|
331
|
+
|
|
332
|
+
Skip a step based on previous results:
|
|
333
|
+
|
|
334
|
+
```json
|
|
335
|
+
{
|
|
336
|
+
"id": "sendEmail",
|
|
337
|
+
"name": "Send email only if customer found",
|
|
338
|
+
"type": "action",
|
|
339
|
+
"if": "$.steps.findCustomer.response.data.length > 0",
|
|
340
|
+
"action": { "...": "..." }
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## 7. Updating Existing Workflows
|
|
345
|
+
|
|
346
|
+
To modify an existing workflow:
|
|
347
|
+
|
|
348
|
+
1. Read the workflow JSON file at `.one/flows/<key>.flow.json`
|
|
349
|
+
2. Understand its current structure
|
|
350
|
+
3. Use `one --agent actions knowledge <platform> <actionId>` for any new actions
|
|
351
|
+
4. Modify the JSON (add/remove/update steps, change data mappings, add inputs)
|
|
352
|
+
5. Write back the updated workflow file
|
|
353
|
+
6. Validate: `one --agent flow validate <key>`
|
|
354
|
+
|
|
355
|
+
## 8. Complete Examples
|
|
356
|
+
|
|
357
|
+
### Example 1: Simple 2-step — Search Stripe customer, send Gmail email
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"key": "welcome-customer",
|
|
362
|
+
"name": "Welcome New Customer",
|
|
363
|
+
"description": "Look up a Stripe customer and send them a welcome email",
|
|
364
|
+
"version": "1",
|
|
365
|
+
"inputs": {
|
|
366
|
+
"stripeConnectionKey": {
|
|
367
|
+
"type": "string",
|
|
368
|
+
"required": true,
|
|
369
|
+
"description": "Stripe connection key",
|
|
370
|
+
"connection": { "platform": "stripe" }
|
|
371
|
+
},
|
|
372
|
+
"gmailConnectionKey": {
|
|
373
|
+
"type": "string",
|
|
374
|
+
"required": true,
|
|
375
|
+
"description": "Gmail connection key",
|
|
376
|
+
"connection": { "platform": "gmail" }
|
|
377
|
+
},
|
|
378
|
+
"customerEmail": {
|
|
379
|
+
"type": "string",
|
|
380
|
+
"required": true,
|
|
381
|
+
"description": "Customer email to look up"
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
"steps": [
|
|
385
|
+
{
|
|
386
|
+
"id": "findCustomer",
|
|
387
|
+
"name": "Search for customer in Stripe",
|
|
388
|
+
"type": "action",
|
|
389
|
+
"action": {
|
|
390
|
+
"platform": "stripe",
|
|
391
|
+
"actionId": "STRIPE_SEARCH_CUSTOMERS_ACTION_ID",
|
|
392
|
+
"connectionKey": "$.input.stripeConnectionKey",
|
|
393
|
+
"data": {
|
|
394
|
+
"query": "email:'{{$.input.customerEmail}}'"
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"id": "sendWelcome",
|
|
400
|
+
"name": "Send welcome email via Gmail",
|
|
401
|
+
"type": "action",
|
|
402
|
+
"if": "$.steps.findCustomer.response.data && $.steps.findCustomer.response.data.length > 0",
|
|
403
|
+
"action": {
|
|
404
|
+
"platform": "gmail",
|
|
405
|
+
"actionId": "GMAIL_SEND_EMAIL_ACTION_ID",
|
|
406
|
+
"connectionKey": "$.input.gmailConnectionKey",
|
|
407
|
+
"data": {
|
|
408
|
+
"to": "{{$.input.customerEmail}}",
|
|
409
|
+
"subject": "Welcome, {{$.steps.findCustomer.response.data[0].name}}!",
|
|
410
|
+
"body": "Thank you for being a customer. We're glad to have you!"
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
]
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Example 2: Conditional — Check if HubSpot contact exists, create or update
|
|
419
|
+
|
|
420
|
+
```json
|
|
421
|
+
{
|
|
422
|
+
"key": "sync-hubspot-contact",
|
|
423
|
+
"name": "Sync Contact to HubSpot",
|
|
424
|
+
"description": "Check if a contact exists in HubSpot, create if new or update if existing",
|
|
425
|
+
"version": "1",
|
|
426
|
+
"inputs": {
|
|
427
|
+
"hubspotConnectionKey": {
|
|
428
|
+
"type": "string",
|
|
429
|
+
"required": true,
|
|
430
|
+
"connection": { "platform": "hub-spot" }
|
|
431
|
+
},
|
|
432
|
+
"email": { "type": "string", "required": true },
|
|
433
|
+
"firstName": { "type": "string", "required": true },
|
|
434
|
+
"lastName": { "type": "string", "required": true }
|
|
435
|
+
},
|
|
436
|
+
"steps": [
|
|
437
|
+
{
|
|
438
|
+
"id": "searchContact",
|
|
439
|
+
"name": "Search for existing contact",
|
|
440
|
+
"type": "action",
|
|
441
|
+
"action": {
|
|
442
|
+
"platform": "hub-spot",
|
|
443
|
+
"actionId": "HUBSPOT_SEARCH_CONTACTS_ACTION_ID",
|
|
444
|
+
"connectionKey": "$.input.hubspotConnectionKey",
|
|
445
|
+
"data": {
|
|
446
|
+
"filterGroups": [{ "filters": [{ "propertyName": "email", "operator": "EQ", "value": "$.input.email" }] }]
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"id": "createOrUpdate",
|
|
452
|
+
"name": "Create or update contact",
|
|
453
|
+
"type": "condition",
|
|
454
|
+
"condition": {
|
|
455
|
+
"expression": "$.steps.searchContact.response.total > 0",
|
|
456
|
+
"then": [
|
|
457
|
+
{
|
|
458
|
+
"id": "updateContact",
|
|
459
|
+
"name": "Update existing contact",
|
|
460
|
+
"type": "action",
|
|
461
|
+
"action": {
|
|
462
|
+
"platform": "hub-spot",
|
|
463
|
+
"actionId": "HUBSPOT_UPDATE_CONTACT_ACTION_ID",
|
|
464
|
+
"connectionKey": "$.input.hubspotConnectionKey",
|
|
465
|
+
"pathVars": { "contactId": "$.steps.searchContact.response.results[0].id" },
|
|
466
|
+
"data": {
|
|
467
|
+
"properties": { "firstname": "$.input.firstName", "lastname": "$.input.lastName" }
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
],
|
|
472
|
+
"else": [
|
|
473
|
+
{
|
|
474
|
+
"id": "createContact",
|
|
475
|
+
"name": "Create new contact",
|
|
476
|
+
"type": "action",
|
|
477
|
+
"action": {
|
|
478
|
+
"platform": "hub-spot",
|
|
479
|
+
"actionId": "HUBSPOT_CREATE_CONTACT_ACTION_ID",
|
|
480
|
+
"connectionKey": "$.input.hubspotConnectionKey",
|
|
481
|
+
"data": {
|
|
482
|
+
"properties": { "email": "$.input.email", "firstname": "$.input.firstName", "lastname": "$.input.lastName" }
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
]
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
]
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Example 3: Loop — Iterate over Shopify orders, create invoices
|
|
494
|
+
|
|
495
|
+
```json
|
|
496
|
+
{
|
|
497
|
+
"key": "shopify-to-invoices",
|
|
498
|
+
"name": "Shopify Orders to Invoices",
|
|
499
|
+
"description": "Fetch recent Shopify orders and create an invoice for each",
|
|
500
|
+
"version": "1",
|
|
501
|
+
"inputs": {
|
|
502
|
+
"shopifyConnectionKey": {
|
|
503
|
+
"type": "string",
|
|
504
|
+
"required": true,
|
|
505
|
+
"connection": { "platform": "shopify" }
|
|
506
|
+
},
|
|
507
|
+
"qbConnectionKey": {
|
|
508
|
+
"type": "string",
|
|
509
|
+
"required": true,
|
|
510
|
+
"connection": { "platform": "quick-books" }
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
"steps": [
|
|
514
|
+
{
|
|
515
|
+
"id": "listOrders",
|
|
516
|
+
"name": "List recent Shopify orders",
|
|
517
|
+
"type": "action",
|
|
518
|
+
"action": {
|
|
519
|
+
"platform": "shopify",
|
|
520
|
+
"actionId": "SHOPIFY_LIST_ORDERS_ACTION_ID",
|
|
521
|
+
"connectionKey": "$.input.shopifyConnectionKey",
|
|
522
|
+
"queryParams": { "status": "any", "limit": "50" }
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
"id": "createInvoices",
|
|
527
|
+
"name": "Create invoice for each order",
|
|
528
|
+
"type": "loop",
|
|
529
|
+
"loop": {
|
|
530
|
+
"over": "$.steps.listOrders.response.orders",
|
|
531
|
+
"as": "order",
|
|
532
|
+
"indexAs": "i",
|
|
533
|
+
"steps": [
|
|
534
|
+
{
|
|
535
|
+
"id": "createInvoice",
|
|
536
|
+
"name": "Create QuickBooks invoice",
|
|
537
|
+
"type": "action",
|
|
538
|
+
"onError": { "strategy": "continue" },
|
|
539
|
+
"action": {
|
|
540
|
+
"platform": "quick-books",
|
|
541
|
+
"actionId": "QB_CREATE_INVOICE_ACTION_ID",
|
|
542
|
+
"connectionKey": "$.input.qbConnectionKey",
|
|
543
|
+
"data": {
|
|
544
|
+
"Line": [
|
|
545
|
+
{
|
|
546
|
+
"Amount": "$.loop.order.total_price",
|
|
547
|
+
"Description": "Shopify Order #{{$.loop.order.order_number}}"
|
|
548
|
+
}
|
|
549
|
+
]
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
]
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
"id": "summary",
|
|
558
|
+
"name": "Generate summary",
|
|
559
|
+
"type": "transform",
|
|
560
|
+
"transform": {
|
|
561
|
+
"expression": "({ totalOrders: $.steps.listOrders.response.orders.length, processed: $.steps.createInvoices.output.length })"
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
## CLI Commands Reference
|
|
569
|
+
|
|
570
|
+
```bash
|
|
571
|
+
# Create a workflow
|
|
572
|
+
one --agent flow create <key> --definition '<json>'
|
|
573
|
+
|
|
574
|
+
# List all workflows
|
|
575
|
+
one --agent flow list
|
|
576
|
+
|
|
577
|
+
# Validate a workflow
|
|
578
|
+
one --agent flow validate <key>
|
|
579
|
+
|
|
580
|
+
# Execute a workflow
|
|
581
|
+
one --agent flow execute <key> -i connectionKey=value -i param=value
|
|
582
|
+
|
|
583
|
+
# Execute with dry run (validate only)
|
|
584
|
+
one --agent flow execute <key> --dry-run -i connectionKey=value
|
|
585
|
+
|
|
586
|
+
# Execute with verbose output
|
|
587
|
+
one --agent flow execute <key> -v -i connectionKey=value
|
|
588
|
+
|
|
589
|
+
# List workflow runs
|
|
590
|
+
one --agent flow runs [flowKey]
|
|
591
|
+
|
|
592
|
+
# Resume a paused/failed run
|
|
593
|
+
one --agent flow resume <runId>
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
## Important Notes
|
|
597
|
+
|
|
598
|
+
- **Always use `--agent` flag** for structured JSON output
|
|
599
|
+
- **Always call `one actions knowledge`** before adding an action step to a workflow
|
|
600
|
+
- Platform names are **kebab-case** (e.g., `hub-spot`, not `HubSpot`)
|
|
601
|
+
- Connection keys are **inputs**, not hardcoded — makes workflows portable and shareable
|
|
602
|
+
- Use `$.input.*` for input values, `$.steps.*` for step results
|
|
603
|
+
- Action IDs in examples (like `STRIPE_SEARCH_CUSTOMERS_ACTION_ID`) are placeholders — always use `one actions search` to find the real IDs
|