@mudlab/create-workflow 1.0.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.
@@ -0,0 +1,947 @@
1
+ You operate within a 3-layer architecture that separates concerns to maximize reliability. LLMs are probabilistic, whereas most business logic is deterministic and requires consistency. This system fixes that mismatch.
2
+
3
+ ## The 3-Layer Architecture
4
+
5
+ **Layer 1: Directive (What to do)**
6
+ - SOPs written in Markdown, live in `directives/`
7
+ - Define the goals, inputs, tools/scripts to use, outputs, and edge cases
8
+ - Natural language instructions, like you'd give a mid-level employee
9
+
10
+ **Layer 2: Orchestration (Decision making)**
11
+ - This is you. Your job: intelligent routing.
12
+ - Read directives, call execution tools in the right order, handle errors, ask for clarification, update directives with learnings
13
+ - You're the glue between intent and execution
14
+
15
+ **Layer 3: Execution (Doing the work)**
16
+ - Deterministic Node.js scripts in `execution/`
17
+ - Environment variables, API tokens, etc. stored in `.env`
18
+ - Handle API calls, data processing, file operations
19
+ - Reliable, testable, fast. Use scripts instead of manual work.
20
+
21
+ **Why this works:** if you do everything yourself, errors compound. 90% accuracy per step = 59% success over 5 steps. Push complexity into deterministic code so you can focus on decision-making.
22
+
23
+ ## Operating Principles
24
+
25
+ **1. Check directives first, then tools**
26
+ Before doing ANYTHING manually, check `directives/` for an SOP that covers the request. The directive tells you which tools to run and in what order.
27
+
28
+ - User asks to "add a lead"? Check `directives/new_lead.md` for the workflow steps.
29
+ - User asks to send an email? Check if there's a directive, then find the tool.
30
+ - User asks about capabilities? Check what directives and tools exist.
31
+
32
+ **Execution flow:**
33
+ 1. Find the relevant directive (SOP) in `directives/`
34
+ 2. Read the ENTIRE directive — identify ALL steps and ALL required inputs
35
+ 3. Before executing anything, check if you have all required inputs for ALL steps
36
+ 4. If any required input is missing, ask the user for it upfront
37
+ 5. Execute ALL steps in order, running each tool locally with Node.js from `execution/tools/`
38
+ 6. If no directive exists, check `execution/tools/` for a standalone tool
39
+ 7. Only use manual approaches (curl, direct API calls) if no tool exists
40
+
41
+ **Critical:** Never execute a partial workflow. If a directive has 3 steps, you must complete all 3. If you can't complete a step due to missing information, ask before starting — don't do half the job and stop.
42
+
43
+ **Important:** Do NOT read `execution/workflows/*.json` files when executing tasks. Workflow JSON files are **only** for creating and pushing workflows to Mudlab. For local execution, you only need:
44
+ - `directives/` — to understand what to do
45
+ - `execution/tools/` — to run the actual code
46
+
47
+ **2. Self-anneal when things break**
48
+ - Read error message and stack trace
49
+ - Fix the script and test it again (unless it uses paid tokens/credits—check w/ user first)
50
+ - Update the directive with what you learned (API limits, timing, edge cases)
51
+
52
+ **3. Update directives as you learn**
53
+ Directives are living documents. When you discover API constraints, better approaches, common errors—update the directive. But don't create or overwrite directives without asking unless explicitly told to.
54
+
55
+ ## Self-annealing Loop
56
+
57
+ Errors are learning opportunities. When something breaks:
58
+ 1. Fix it
59
+ 2. Update the tool
60
+ 3. Test tool, make sure it works
61
+ 4. Validate output compliance (see checklist below)
62
+ 5. Update directive to include new flow
63
+ 6. **If it's a structural change (new patterns, schema changes, conventions), update CLAUDE.md**
64
+ 7. System is now stronger
65
+
66
+ **Update Checklist — ALWAYS update ALL connected files:**
67
+
68
+ When you change ANY part of a workflow, you MUST update ALL of these:
69
+
70
+ | If you change... | Also update... |
71
+ |------------------|----------------|
72
+ | Tool code (`execution/tools/*.js`) | Tool directive, workflow JSON (outputs), workflow directive |
73
+ | Tool inputs/outputs | Workflow JSON (inputs, outputs, config), workflow directive (Inputs table, Example) |
74
+ | Workflow step config | Workflow directive (Trigger, Inputs, Example sections) |
75
+ | Workflow JSON | Workflow directive (must match exactly) |
76
+
77
+ **Connected files for each workflow:**
78
+ 1. `execution/tools/<tool>.js` — the actual code
79
+ 2. `execution/tools_directives/<tool>.md` — AI usage instructions for the tool
80
+ 3. `execution/workflows/<workflow>.json` — workflow package (inputs, steps, config)
81
+ 4. `directives/<workflow>.md` — user-facing documentation (Trigger, Inputs, Example)
82
+
83
+ **Critical rule:** The workflow directive's Trigger/Inputs/Example sections must EXACTLY match what the workflow JSON expects. If they don't match, the frontend will break.
84
+
85
+ **Tool Output Validation Checklist:**
86
+ When testing tools, verify each one follows the output object rules:
87
+ - [ ] Tool definition has `running_message` - shown during execution (e.g., `"Sending email to $input.to..."`)
88
+ - [ ] Returns an object (not primitive like `true`, `"success"`, `null`)
89
+ - [ ] Includes action taken (e.g., `action: "sent"`, `action: "inserted"`)
90
+ - [ ] Includes `message` - human-readable success message for logging (e.g., `"Sent email to john@example.com"`)
91
+ - [ ] Includes relevant identifiers (IDs, timestamps, message IDs)
92
+ - [ ] Summarizes what was affected (records, fields, recipients)
93
+ - [ ] Errors include context about what failed and why
94
+
95
+ **When to update CLAUDE.md:**
96
+ - New structural patterns emerge (directive sections, tool conventions)
97
+ - Schema changes (input types, workflow fields)
98
+ - New integrations or API endpoints
99
+ - Process improvements discovered through use
100
+
101
+ ## File Organization
102
+
103
+ **Directory structure:**
104
+ - `.tmp/` - Intermediate files (temp data, exports). Never commit, always regenerated.
105
+ - `execution/` - Node.js scripts (the deterministic tools)
106
+ - `execution/tools/` - Individual tool functions for Mudlab
107
+ - `execution/tools_directives/` - Markdown files with AI usage instructions for tools
108
+ - `execution/workflows/` - Workflow package definitions (JSON)
109
+ - `directives/` - Markdown files: SOPs (for orchestrator) and workflow directives (pushed to Mudlab UI)
110
+ - `.env` - Environment variables and API keys
111
+ - `assets/` - Static assets (logos, templates)
112
+
113
+ **Key principle:** Local files are for processing. Deliverables live in cloud services or your Mudlab application.
114
+
115
+ ## Directive Structure
116
+
117
+ Every workflow directive (`directives/*.md`) should include these sections:
118
+
119
+ ```markdown
120
+ # Workflow Name
121
+
122
+ Brief description of what the workflow does.
123
+
124
+ ## Prerequisites
125
+
126
+ Step-by-step setup instructions to complete BEFORE pushing/testing the workflow:
127
+ - API key acquisition (with links to where to get them)
128
+ - External service configuration (database setup, integration permissions, etc.)
129
+ - Environment variables to add to Mudlab
130
+
131
+ This section ensures the user has everything ready before testing.
132
+
133
+ ## Trigger
134
+
135
+ How to call this workflow via webhook:
136
+
137
+ \`\`\`
138
+ POST https://mudlab.io/api/webhooks/{webhook_id}
139
+ Content-Type: application/json
140
+
141
+ {
142
+ "field1": "value1",
143
+ "field2": "value2"
144
+ }
145
+ \`\`\`
146
+
147
+ ## Inputs
148
+
149
+ | Field | Type | Label | Source | Default | Description |
150
+ |-------|------|-------|--------|---------|-------------|
151
+ | `field1` | string | Field 1 | input | - | Description |
152
+
153
+ ## Workflow Steps
154
+
155
+ | Step | Tool | Required Inputs | Description |
156
+ |------|------|-----------------|-------------|
157
+ | 1. Step Name | `tool_name` | field1, field2 | What this step does |
158
+ | 2. Step Name | `other_tool` | field3, (step1.output) | What this step does |
159
+
160
+ **Note:** Steps are executed in order. If a step uses output from a previous step, indicate it with `(stepN.output)`.
161
+
162
+ ## Outputs
163
+
164
+ | Field | Description |
165
+ |-------|-------------|
166
+ | `step1.action` | Action taken |
167
+ | `step1.result` | The result data |
168
+
169
+ ## Example
170
+
171
+ **Request:**
172
+ \`\`\`
173
+ POST https://mudlab.io/api/webhooks/wh_abc123
174
+ Content-Type: application/json
175
+
176
+ { ... }
177
+ \`\`\`
178
+
179
+ **Response:**
180
+ \`\`\`json
181
+ { ... }
182
+ \`\`\`
183
+ ```
184
+
185
+ **Required sections:**
186
+ - **Workflow Scope** - Clear boundaries defining what this workflow is and is NOT for (see below)
187
+ - **Prerequisites** - Step-by-step setup: API keys, external service config, env vars (complete BEFORE testing)
188
+ - **Trigger** - Show the webhook URL pattern and expected request body
189
+ - **Inputs** - Table of all input fields with types and sources
190
+ - **Workflow Steps** - Table listing each step, its tool, required inputs, and description
191
+ - **Outputs** - Table of output fields returned by the workflow
192
+ - **Example** - Full request/response example
193
+
194
+ ## Workflow Scope (Required Section)
195
+
196
+ Every workflow directive MUST include a **Workflow Scope** section immediately after the description. This section prevents workflow scope creep and ensures the AI uses workflows only for their intended purpose.
197
+
198
+ **Why this matters:** AI can creatively reinterpret workflow purposes. A "New Lead" workflow might get used for bug reports, feedback, or test data if boundaries aren't explicit. Each workflow has ONE business function — enforce it.
199
+
200
+ ### Required Subsections
201
+
202
+ ```markdown
203
+ ## Workflow Scope
204
+
205
+ ### What This Workflow Is For
206
+
207
+ This workflow is **exclusively** for [SPECIFIC PURPOSE]:
208
+
209
+ - [Specific use case 1]
210
+ - [Specific use case 2]
211
+ - [Specific use case 3]
212
+
213
+ [Brief explanation of what qualifies as valid input for this workflow]
214
+
215
+ ### What This Workflow Is NOT For
216
+
217
+ **Do NOT use this workflow for:**
218
+
219
+ | Invalid Use Case | Why It's Wrong | What To Use Instead |
220
+ |------------------|----------------|---------------------|
221
+ | [Invalid use 1] | [Explanation] | [Alternative workflow] |
222
+ | [Invalid use 2] | [Explanation] | [Alternative workflow] |
223
+
224
+ ### Consequences of Misuse
225
+
226
+ If you route invalid data through this workflow:
227
+ - [Consequence 1 - e.g., database pollution]
228
+ - [Consequence 2 - e.g., wasted team effort]
229
+ - [Consequence 3 - e.g., broken metrics]
230
+
231
+ ### Proper vs Improper Usage
232
+
233
+ **CORRECT** — Use this workflow when:
234
+ \`\`\`json
235
+ // [Description of valid input]
236
+ { "field": "valid_value" }
237
+ \`\`\`
238
+
239
+ **INCORRECT** — Do NOT use this workflow when:
240
+ \`\`\`json
241
+ // [Description of invalid input] (use [alternative] instead)
242
+ { "field": "invalid_value" }
243
+ \`\`\`
244
+
245
+ **AI Instruction:** [Clear directive for AI behavior when encountering edge cases]
246
+ ```
247
+
248
+ ### Key Principles
249
+
250
+ 1. **Be explicit about purpose** — Don't just say "captures leads." Say "captures SALES leads — potential customers who might buy from you."
251
+
252
+ 2. **List what it's NOT for** — The table format forces you to think through common misuse cases and provide alternatives.
253
+
254
+ 3. **Show consequences** — Explain what goes wrong when the workflow is misused (database pollution, wasted effort, broken metrics).
255
+
256
+ 4. **Provide examples** — Concrete JSON examples of valid vs invalid inputs remove ambiguity.
257
+
258
+ 5. **Include AI instructions** — Tell the AI explicitly what to do when it encounters edge cases: "If the data doesn't represent a genuine sales prospect, reject the request and suggest the appropriate workflow."
259
+
260
+ ### Example: New Lead Workflow Scope
261
+
262
+ ```markdown
263
+ ## Workflow Scope
264
+
265
+ ### What This Workflow Is For
266
+
267
+ This workflow is **exclusively** for capturing **sales leads** — potential customers who have expressed interest in your product:
268
+
269
+ - Contact forms on landing pages
270
+ - "Request a demo" submissions
271
+ - Newsletter signups from prospects
272
+
273
+ A sales lead is someone who **might buy from you**.
274
+
275
+ ### What This Workflow Is NOT For
276
+
277
+ | Invalid Use Case | Why It's Wrong | What To Use Instead |
278
+ |------------------|----------------|---------------------|
279
+ | Bug reports | Not a sales lead | Bug tracking workflow |
280
+ | Customer support | Existing customers, not prospects | Support ticket workflow |
281
+ | Test data | Pollutes leads database | Use sandbox environment |
282
+
283
+ ### Consequences of Misuse
284
+
285
+ - Leads database polluted with non-sales entries
286
+ - Sales team wastes time on irrelevant items
287
+ - Conversion metrics become meaningless
288
+
289
+ ### Proper vs Improper Usage
290
+
291
+ **CORRECT:**
292
+ \`\`\`json
293
+ { "name": "Jane Smith", "email": "jane@acme.com", "phone": "+1-555-1234" }
294
+ \`\`\`
295
+
296
+ **INCORRECT:**
297
+ \`\`\`json
298
+ { "name": "Bug Report", "email": "user@example.com", "phone": "Login broken" }
299
+ \`\`\`
300
+
301
+ **AI Instruction:** If the data doesn't represent a sales prospect, reject and suggest the correct workflow.
302
+ ```
303
+
304
+ ## Running Tools Locally
305
+
306
+ When the user asks you to perform an action, **run tools directly with Node.js**—do NOT call the Mudlab API.
307
+
308
+ ```javascript
309
+ node -e "
310
+ const { run } = require('./execution/tools/tool_name.js');
311
+ run({
312
+ input: { /* tool inputs + env vars from .env */ },
313
+ env: {},
314
+ context: {}
315
+ }).then(r => console.log(JSON.stringify(r, null, 2)))
316
+ .catch(e => console.error('Error:', e.message));
317
+ "
318
+ ```
319
+
320
+ - Load credentials from `.env` and pass them in the `input` object (tools expect env vars in `input`, not `env`)
321
+ - Follow the directive's workflow steps, running each tool in sequence
322
+ - This is how you test and execute workflows locally
323
+
324
+ ## Mudlab Integration
325
+
326
+ Mudlab is for **pushing only**—you push tools and workflows so they can run in production via webhooks. Do NOT call the Mudlab API to execute workflows locally.
327
+
328
+ **When to use Mudlab API:** Only when the user explicitly says "push this workflow to Mudlab"
329
+
330
+ ### Tool Structure
331
+
332
+ Tools are Node.js functions that follow this signature:
333
+
334
+ ```javascript
335
+ async function run({ input, env, context }) {
336
+ // input = data from previous steps or trigger
337
+ // env = decrypted environment variables
338
+ // context = { user_id, client_id, workflow_id, step_id }
339
+
340
+ return {
341
+ // named output fields
342
+ };
343
+ }
344
+
345
+ module.exports = { run };
346
+ ```
347
+
348
+ ### Accessing Environment Variables in Tools
349
+
350
+ When a tool input has `source: "env"`, Mudlab resolves the user's selected env var and passes it into the `input` object (not just `env`). Tools must access env vars from `input` first, with a fallback to `env` for backwards compatibility.
351
+
352
+ **Pattern:**
353
+ ```javascript
354
+ async function run({ input, env, context }) {
355
+ // Destructure env vars from input alongside regular inputs
356
+ const { name, email, MY_API_KEY, MY_SECRET } = input;
357
+
358
+ // Fall back to raw env object for backwards compatibility
359
+ const apiKey = MY_API_KEY || env.MY_API_KEY;
360
+ const secret = MY_SECRET || env.MY_SECRET;
361
+
362
+ if (!apiKey) {
363
+ throw new Error("Missing MY_API_KEY - ensure it is selected in the tool's env var dropdown");
364
+ }
365
+ // ...
366
+ }
367
+ ```
368
+
369
+ **Why this matters:**
370
+ - Inputs with `source: "env"` are resolved by Mudlab before execution
371
+ - The resolved value is placed in `input`, not `env`
372
+ - Accessing only `env.VAR_NAME` will fail because the UI dropdown selection isn't reflected there
373
+ - Error messages should guide users to check the env var dropdown in the UI
374
+
375
+ **Workflow JSON must define env var inputs:**
376
+ ```json
377
+ {
378
+ "inputs": [
379
+ {
380
+ "name": "MY_API_KEY",
381
+ "type": "string",
382
+ "label": "API Key",
383
+ "source": "env",
384
+ "required": true
385
+ }
386
+ ]
387
+ }
388
+ ```
389
+
390
+ ### Tool Output Requirements
391
+
392
+ Every tool MUST return structured data for the execution terminal display. The terminal shows Input, Output, and Error for each tool execution in real-time.
393
+
394
+ **Rules:**
395
+ - Always return an output object - even for side-effect tools (sending email, posting to Slack, writing to database)
396
+ - Output should be informative - include details that confirm the action succeeded and what was affected
397
+ - Errors must be descriptive - include context about what failed and why
398
+
399
+ **Output Format Guidelines:**
400
+ - Return objects, not primitives (no bare `true`, `"success"`, etc.)
401
+ - Include `message` - a human-readable success message for logging (required)
402
+ - Include identifiers (IDs, timestamps, message IDs)
403
+ - Summarize what was done (action taken, records affected)
404
+ - For fetches/reads, return the relevant data
405
+ - Keep outputs concise but complete
406
+
407
+ **The `message` field:**
408
+ Every tool output MUST include a `message` field with a human-readable success message. This is used for logging and helps users understand what the tool accomplished.
409
+
410
+ - Use present tense, active voice (e.g., "Sent email to..." not "Email was sent to...")
411
+ - Include key identifiers from the operation (names, emails, IDs)
412
+ - Keep it concise but informative (one sentence)
413
+
414
+ Examples:
415
+ - `"Added lead 'John Doe' to Notion database"`
416
+ - `"Sent email to john@example.com"`
417
+ - `"Generated random number 42 between 1 and 100"`
418
+
419
+ **Examples:**
420
+
421
+ Bad (email tool):
422
+ ```javascript
423
+ await sendEmail(to, subject, body)
424
+ // Returns nothing
425
+ ```
426
+
427
+ Good (email tool):
428
+ ```javascript
429
+ await sendEmail(to, subject, body)
430
+ return {
431
+ action: "sent",
432
+ message: `Sent email to ${to}`,
433
+ sent_to: to,
434
+ subject: subject,
435
+ timestamp: new Date().toISOString(),
436
+ message_id: response.id
437
+ }
438
+ ```
439
+
440
+ Bad (database write):
441
+ ```javascript
442
+ await db.insert(record)
443
+ // No return
444
+ ```
445
+
446
+ Good (database write):
447
+ ```javascript
448
+ const result = await db.insert(record)
449
+ return {
450
+ action: "inserted",
451
+ message: `Inserted record ${result.id} into users table`,
452
+ table: "users",
453
+ id: result.id,
454
+ fields_updated: Object.keys(record)
455
+ }
456
+ ```
457
+
458
+ ### Workflow Package
459
+
460
+ A workflow package bundles tools + workflow definition. Every workflow **must** have an associated directive file that explains what the workflow does (shown in Mudlab UI).
461
+
462
+ ```json
463
+ {
464
+ "id": null,
465
+ "name": "My Workflow",
466
+ "description": "What it does",
467
+ "running_message": "Processing '$trigger.input.name'...",
468
+ "success_message": "Completed action for '$trigger.input.name'",
469
+ "directive_file": "directives/my_workflow.md",
470
+ "tools": [
471
+ {
472
+ "id": null,
473
+ "tool_id": "my_tool",
474
+ "name": "My Tool",
475
+ "description": "What the tool does",
476
+ "directive_file": "execution/tools_directives/my_tool.md",
477
+ "running_message": "Updating records for '$input.field1'...",
478
+ "success_message": "Updated records for '$input.field1'",
479
+ "code_file": "execution/tools/my_tool.js",
480
+ "inputs": [
481
+ {
482
+ "name": "field1",
483
+ "type": "string",
484
+ "label": "Field 1",
485
+ "placeholder": "Enter value",
486
+ "description": "What this field does",
487
+ "source": "input",
488
+ "required": true
489
+ }
490
+ ],
491
+ "outputs": ["result", "message"]
492
+ }
493
+ ],
494
+ "steps": [
495
+ {
496
+ "step_id": "step1",
497
+ "tool_id": "my_tool",
498
+ "depends_on": [],
499
+ "config": { "field1": "$trigger.input.data" }
500
+ }
501
+ ]
502
+ }
503
+ ```
504
+
505
+ **ID Fields:**
506
+ - `id` (workflow and each tool) starts as `null`
507
+ - After first push, the API returns UUIDs which are written back to the JSON
508
+ - On subsequent pushes, existing `id` values trigger updates instead of creates
509
+ - `tool_id` is a human-readable unique identifier (e.g., `"random_number"`) - different from the UUID `id`
510
+
511
+ **Running Message (Workflow):**
512
+ Every workflow MUST have a `running_message` field - displayed while the workflow is executing. This field supports template variables using `$trigger.input.field`:
513
+
514
+ Examples:
515
+ - `"Creating lead '$trigger.input.name'..."`
516
+ - `"Generating random number..."`
517
+ - `"Processing order $trigger.input.order_id..."`
518
+
519
+ **Running Message (Tool):**
520
+ Every tool definition MUST have a `running_message` field - displayed while the tool is executing. This field supports template variables using `$input.field` (referencing the tool's inputs):
521
+
522
+ Examples:
523
+ - `"Adding lead '$input.name' to Notion..."`
524
+ - `"Sending email to $input.to..."`
525
+ - `"Generating number between $input.min and $input.max..."`
526
+
527
+ **Directive (Tool):**
528
+ Tools have an optional `directive_file` field that points to a Markdown file containing usage instructions for the AI orchestrator. This is separate from `description` (which explains what the tool does) — the directive explains **how to use it properly**.
529
+
530
+ | Field | Purpose | Example |
531
+ |-------|---------|---------|
532
+ | `description` | Brief explanation of what the tool does | "Sends an email via Resend API" |
533
+ | `directive_file` | Path to Markdown file with usage instructions | `"execution/tools_directives/send_email_resend.md"` |
534
+
535
+ Tool directives live in `execution/tools_directives/` and follow the same pattern as workflow directives — the push script reads the file and sends the content to the API.
536
+
537
+ **When to add a directive:**
538
+ **Always create a tool directive when creating or updating a workflow.** Every tool should have a corresponding directive file in `execution/tools_directives/`. Include:
539
+ - **Input constraints** — validation rules, required formats, value ranges
540
+ - **Output details** — what gets returned and when
541
+ - **Formatting requirements** — plain text vs HTML vs markdown (for content tools)
542
+ - **Best practices** — tone, structure, common mistakes to avoid
543
+ - **Edge cases** — what to do when certain inputs are missing
544
+ - **Common use cases** — help the AI understand when to use this tool
545
+
546
+ **Example directive file (`execution/tools_directives/send_email_resend.md`):**
547
+
548
+ ```markdown
549
+ ## Formatting
550
+ - Body supports HTML but not Markdown syntax
551
+ - Do not use emojis unless the user explicitly requests them
552
+ - Write in flowing prose, not bullet points (unless the user asks for bullets)
553
+
554
+ ## Subject Lines
555
+ - Keep under 60 characters
556
+ - Be specific and actionable
557
+
558
+ ## Common Mistakes
559
+ - Don't use **bold** or *italic* markdown — these render as literal asterisks in plain text
560
+ - If using HTML, use proper tags like <strong> and <em>
561
+ ```
562
+
563
+ **How it works:**
564
+ When the workflow is pushed, the push script reads each tool's `directive_file` and includes the content in the API payload. The directive is stored in the database and injected into the AI's system prompt under a "Tool Usage Guidelines" section.
565
+
566
+ **Success Message (Workflow):**
567
+ Every workflow MUST have a `success_message` field - a human-readable message logged when the workflow completes successfully. This field supports template variables:
568
+
569
+ | Pattern | Description |
570
+ |---------|-------------|
571
+ | `$trigger.input.field` | Input from workflow trigger |
572
+ | `$step_id.output.field` | Output from a completed step |
573
+
574
+ Examples:
575
+ - `"Created lead '$trigger.input.name' and sent notification"`
576
+ - `"Generated random number $generate.output.number"`
577
+ - `"Processed order $trigger.input.order_id for $trigger.input.customer_name"`
578
+
579
+ **Success Message (Tool):**
580
+ Every tool definition MUST have a `success_message` field - a human-readable message logged when the tool completes successfully. This field supports template variables using `$input.field` (referencing the tool's inputs):
581
+
582
+ Examples:
583
+ - `"Added lead '$input.name' to Notion"`
584
+ - `"Sent email to $input.to"`
585
+ - `"Generated random number between $input.min and $input.max"`
586
+
587
+ Additionally, every tool output MUST include a `message` field in the return object (see Tool Output Requirements above). The `success_message` template is used for consistent logging, while the returned `message` provides runtime-specific details.
588
+
589
+ ### Pushing Workflows
590
+
591
+ ```bash
592
+ # Single workflow
593
+ node execution/push_workflow.js execution/workflows/my_workflow.json
594
+
595
+ # Multiple workflows (bulk mode - single API call)
596
+ node execution/push_workflow.js execution/workflows/workflow_a.json execution/workflows/workflow_b.json
597
+
598
+ # All workflows via glob
599
+ node execution/push_workflow.js execution/workflows/*.json
600
+ ```
601
+
602
+ This will:
603
+ 1. Read each tool's code from `code_file`
604
+ 2. Read directive markdown from `directive_file`
605
+ 3. For each tool: check if `id` exists → update or create
606
+ 4. For workflow: check if `id` exists → update or create
607
+ 5. Write returned UUIDs back to the JSON file(s)
608
+ 6. Log results to `.tmp/pushed_workflows.json`
609
+
610
+ **Single vs Bulk:**
611
+ - Single file: sends object payload, returns `{ success, workflow, tools }`
612
+ - Multiple files: sends array payload, returns bulk response format (see below)
613
+ - Bulk mode uses a single API call with parallel processing (Promise.allSettled)
614
+
615
+ **Bulk Response Format:**
616
+ ```json
617
+ {
618
+ "success": false,
619
+ "results": [
620
+ { "success": true, "workflow": { "id": "...", "name": "Workflow A" }, "tools": [...] },
621
+ { "success": false, "workflow_name": "Workflow B", "error": "Tool missing code", "details": "..." }
622
+ ],
623
+ "summary": { "total": 2, "succeeded": 1, "failed": 1 },
624
+ "workflows": [ /* only successes - convenience array */ ],
625
+ "errors": [ /* only failures with workflow_name, error, details */ ]
626
+ }
627
+ ```
628
+
629
+ **HTTP Status Codes (bulk):**
630
+ - `200` - All workflows succeeded
631
+ - `207 Multi-Status` - Partial success (some failed, some succeeded)
632
+ - `400/500` - Request or server error
633
+
634
+ **Behavior:**
635
+ - All workflows processed in parallel (independent - one failure doesn't affect others)
636
+ - `errors` array makes it easy to see what failed and why
637
+
638
+ **First push** (all `id` fields are `null`):
639
+ - Creates new tools and workflow in the database
640
+ - Writes UUIDs back to your JSON file
641
+
642
+ **Subsequent pushes** (with `id` values):
643
+ - Updates existing tools and workflow
644
+ - Increments version numbers automatically
645
+
646
+ ### API Endpoints
647
+
648
+ | Action | Endpoint | Description |
649
+ |--------|----------|-------------|
650
+ | Push Workflow | `POST /api/push-workflow` | Bulk create/update tools + workflow (preferred) |
651
+ | Get Tool | `GET /api/tools/:id` | Check if tool exists by UUID |
652
+ | Create Tool | `POST /api/tools` | Create a single tool |
653
+ | Update Tool | `PUT /api/tools/:id` | Update existing tool (auto-versions) |
654
+ | Get Workflow | `GET /api/workflows/:id` | Check if workflow exists by UUID |
655
+ | Create Workflow | `POST /api/workflows` | Create workflow from steps |
656
+ | Update Workflow | `PUT /api/workflows/:id` | Update existing workflow |
657
+ | Run Workflow | `POST /api/run` | Execute a workflow |
658
+
659
+ ### Input Schema
660
+
661
+ Tool inputs use structured objects so the frontend can auto-generate forms:
662
+
663
+ ```json
664
+ {
665
+ "name": "string", // Variable name used in code (snake_case)
666
+ "type": "string", // "string" | "number" | "boolean" | "object" | "array"
667
+ "label": "string", // User-readable label for UI (e.g., "Stripe API Key")
668
+ "placeholder"?: "string", // Input placeholder hint (e.g., "sk_live_xxxx...")
669
+ "description"?: "string", // Help text explaining what this input is for
670
+ "source": "input" | "env", // Where the value comes from:
671
+ // - "input": User provides value directly (default)
672
+ // - "env": Value comes from environment variable dropdown
673
+ "required": "boolean", // Whether this input must be provided (always specify)
674
+ "default"?: "any" // Default value if not provided (only when required: false)
675
+ }
676
+ ```
677
+
678
+ | Field | Required | Description |
679
+ |-------|----------|-------------|
680
+ | `name` | Yes | Variable name used in code (snake_case) |
681
+ | `type` | Yes | `string`, `number`, `boolean`, `object`, `array` |
682
+ | `label` | Yes | User-readable label for UI |
683
+ | `source` | Yes | `input` (user provides) or `env` (environment variable dropdown) |
684
+ | `required` | Yes | Always set explicitly - UI fields start empty, so this controls validation |
685
+ | `placeholder` | No | Input hint text (e.g., "sk_live_...") |
686
+ | `description` | No | Help text shown in UI |
687
+ | `default` | No | Default value - only use when `required: false` |
688
+
689
+ **Required vs Default:**
690
+ - If `required: true` → user must provide a value, no default needed
691
+ - If `required: false` → consider adding a `default` so the tool has a fallback
692
+ - Never use both `required: true` and `default` together - they're mutually exclusive
693
+
694
+ **Source Rules:**
695
+ - Use `"source": "env"` for sensitive values (API keys, secrets, tokens)
696
+ - Use `"source": "input"` for regular parameters (amounts, names, options)
697
+
698
+ **Example - Stripe charge tool:**
699
+
700
+ ```json
701
+ {
702
+ "tool_id": "stripe_charge",
703
+ "name": "Stripe Charge",
704
+ "inputs": [
705
+ {
706
+ "name": "stripe_api_key",
707
+ "type": "string",
708
+ "label": "Stripe API Key",
709
+ "placeholder": "sk_live_...",
710
+ "description": "Your Stripe secret key from the dashboard",
711
+ "source": "env",
712
+ "required": true
713
+ },
714
+ {
715
+ "name": "amount",
716
+ "type": "number",
717
+ "label": "Amount",
718
+ "placeholder": "1000",
719
+ "description": "Amount in cents (e.g., 1000 = $10.00)",
720
+ "source": "input",
721
+ "required": true
722
+ },
723
+ {
724
+ "name": "currency",
725
+ "type": "string",
726
+ "label": "Currency",
727
+ "placeholder": "usd",
728
+ "description": "Three-letter ISO currency code",
729
+ "source": "input",
730
+ "required": false,
731
+ "default": "usd"
732
+ }
733
+ ]
734
+ }
735
+ ```
736
+
737
+ This schema enables the UI to:
738
+ - Show text inputs for `source: "input"`
739
+ - Show env var dropdowns for `source: "env"`
740
+ - Display the `label` as the field name
741
+ - Show `placeholder` as hint text
742
+ - Show `description` as help text
743
+
744
+ ### Config Mapping
745
+
746
+ Reference data from previous steps:
747
+
748
+ | Pattern | Description |
749
+ |---------|-------------|
750
+ | `$trigger.input.field` | Input from workflow trigger |
751
+ | `$step_id.output.field` | Output from a previous step |
752
+
753
+ ### Template Variables
754
+
755
+ When configuring workflow steps that generate content (emails, PDFs, documents, messages), use template variables for dynamic content. These variables are automatically substituted at runtime.
756
+
757
+ **Syntax:** Always use double curly braces: `{{variable}}`
758
+
759
+ **Available Variables:**
760
+
761
+ Variables come from two sources:
762
+
763
+ 1. **Workflow inputs** - Values passed when the workflow is triggered
764
+ - `{{name}}`, `{{email}}`, `{{phone}}`, etc.
765
+
766
+ 2. **Previous step outputs** - Values returned by earlier steps
767
+ - `{{page_url}}`, `{{record_id}}`, `{{file_path}}`, etc.
768
+
769
+ **Variable Name Mappings:**
770
+
771
+ The system recognizes common variations:
772
+
773
+ | Variation | Maps to |
774
+ |-----------|---------|
775
+ | `{{lead_name}}` | `{{name}}` |
776
+ | `{{lead_email}}` | `{{email}}` |
777
+ | `{{lead_phone}}` | `{{phone}}` |
778
+ | `{{notion_url}}` | `{{page_url}}` |
779
+
780
+ **Best Practice:** Use simple variable names that match workflow input names directly.
781
+
782
+ **Example step config:**
783
+
784
+ ```json
785
+ {
786
+ "step_id": "notify",
787
+ "tool_id": "send_email_resend",
788
+ "config": {
789
+ "to": "$trigger.input.notification_email",
790
+ "subject": "New Lead: {{name}}",
791
+ "body": "<h2>New Lead</h2><p>Name: {{name}}</p><p>Email: {{email}}</p><p><a href=\"{{page_url}}\">View in Notion</a></p>"
792
+ }
793
+ }
794
+ ```
795
+
796
+ ### Workflow Context System
797
+
798
+ Workflows have two layers of configuration:
799
+
800
+ 1. **Directive (workflows.directive)** — The base workflow definition. This is **immutable from AI chat**. It defines what the workflow CAN do.
801
+
802
+ 2. **Context (workflow_contexts table)** — Per-user customizations. The AI chat CAN update this to customize workflow behavior within the boundaries defined by the directive.
803
+
804
+ **Key principle:** The directive defines capabilities. Context customizes within those boundaries. If a user requests something the workflow doesn't support, acknowledge it and suggest an alternative workflow if one exists.
805
+
806
+ #### workflow_contexts Schema
807
+
808
+ ```sql
809
+ workflow_contexts (
810
+ id uuid,
811
+ workflow_id uuid, -- Links to workflows table
812
+ context text, -- The customization content (MUST be Markdown)
813
+ context_for uuid, -- The user this context applies to
814
+ context_key text, -- Identifies what aspect is being customized (e.g., "email_template", "notification_preferences")
815
+ created_at timestamp,
816
+ updated_at timestamp
817
+ )
818
+ ```
819
+
820
+ **Unique constraint:** `(workflow_id, context_for, context_key)` — One context entry per workflow, per user, per key.
821
+
822
+ #### Context Format: Markdown Only
823
+
824
+ The `context` field **MUST always be written in Markdown**. Never use:
825
+ - Raw HTML (use Markdown syntax instead)
826
+ - Plain text without formatting
827
+ - JSON (unless embedded in a Markdown code block for reference)
828
+
829
+ **Why Markdown:**
830
+ - Consistent parsing across the system
831
+ - Human-readable in database and logs
832
+ - Easily rendered in UI
833
+ - Supports structured content (headers, lists, code blocks)
834
+
835
+ **Examples:**
836
+
837
+ **CORRECT** — Markdown format:
838
+ ```markdown
839
+ # Email Template
840
+
841
+ ## Subject
842
+ New Lead: {{name}}
843
+
844
+ ## Body
845
+ Hello team,
846
+
847
+ A new lead just came in:
848
+
849
+ - **Name:** {{name}}
850
+ - **Email:** {{email}}
851
+ - **Phone:** {{phone}}
852
+
853
+ [View in Notion]({{page_url}})
854
+ ```
855
+
856
+ **INCORRECT** — Raw HTML:
857
+ ```html
858
+ <h1>Email Template</h1>
859
+ <p>Hello team, A new lead: <strong>{{name}}</strong></p>
860
+ ```
861
+
862
+ **INCORRECT** — Plain text:
863
+ ```
864
+ Email Template
865
+ Subject: New Lead
866
+ Body: Hello team, a new lead came in.
867
+ ```
868
+
869
+ For email bodies that need HTML rendering, write the content structure in Markdown and let the system convert it, or use a Markdown code block to document the desired HTML output:
870
+
871
+ ```markdown
872
+ # Email Body
873
+
874
+ The email should render as:
875
+
876
+ \`\`\`html
877
+ <h2>New Lead</h2>
878
+ <p>Name: {{name}}</p>
879
+ \`\`\`
880
+ ```
881
+
882
+ #### What Can Be Customized via Context
883
+
884
+ | Context Key | What It Customizes | Example |
885
+ |-------------|-------------------|---------|
886
+ | `email_template` | Email body/subject for notifications | Custom HTML template with branding |
887
+ | `notification_preferences` | Who receives notifications, when | Different email for high-priority leads |
888
+ | `field_mappings` | How input fields map to outputs | Custom field names for CRM sync |
889
+ | `tone_preferences` | AI-generated content style | "Professional and formal" vs "Friendly" |
890
+
891
+ #### What CANNOT Be Customized
892
+
893
+ These are defined by the directive and are immutable:
894
+
895
+ - **Workflow purpose** — A lead capture workflow cannot become a support ticket workflow
896
+ - **Core tools/steps** — The sequence of tools that execute
897
+ - **Required inputs** — What data the workflow needs to run
898
+ - **Database targets** — Which Notion databases are written to
899
+ - **API integrations** — Which services are called
900
+
901
+ #### AI Chat Behavior
902
+
903
+ When a user requests a change via AI chat:
904
+
905
+ 1. **If customizable** — Update workflow_contexts with the new preference
906
+ ```
907
+ User: "Change my lead notification email to include our company logo"
908
+ AI: Updates context_key="email_template" with new HTML template
909
+ ```
910
+
911
+ 2. **If not supported by this workflow** — Acknowledge and suggest alternatives
912
+ ```
913
+ User: "Can you also create a support ticket when a lead comes in?"
914
+ AI: "The New Lead workflow is specifically for sales leads. Creating support tickets
915
+ is a different workflow. Would you like me to help you set up a Support Ticket
916
+ workflow that could be triggered separately?"
917
+ ```
918
+
919
+ 3. **If no workflow exists** — Offer to create one
920
+ ```
921
+ User: "I want to track bug reports too"
922
+ AI: "There isn't a bug tracking workflow yet. Would you like me to create one?
923
+ It would be separate from lead capture to keep your data clean."
924
+ ```
925
+
926
+ **Never** try to repurpose a workflow beyond its defined scope. Acknowledge the limitation, then help the user find or create the right solution.
927
+
928
+ #### Context Priority
929
+
930
+ At runtime, the system checks for context in this order:
931
+ 1. User-specific context (workflow_contexts where context_for = current_user)
932
+ 2. Step config defaults (from workflow JSON)
933
+ 3. Tool defaults (from tool definition)
934
+
935
+ Content fields in step configs serve as defaults. User context takes priority when present.
936
+
937
+ ### Environment Variables
938
+
939
+ Required in `.env`:
940
+ - `MUDLAB_API_URL` - Base URL for Mudlab API
941
+ - `MUDLAB_API_KEY` - API key for authentication (X-API-Key header)
942
+
943
+ ## Summary
944
+
945
+ You sit between human intent (directives) and deterministic execution (Node.js scripts pushed to Mudlab). Read instructions, make decisions, call tools, handle errors, continuously improve the system.
946
+
947
+ Be pragmatic. Be reliable. Self-anneal.