@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.
- package/README.md +78 -0
- package/bin/create.js +84 -0
- package/package.json +31 -0
- package/template/.env.example +11 -0
- package/template/CLAUDE.md +947 -0
- package/template/README.md +49 -0
- package/template/assets/.gitkeep +3 -0
- package/template/directives/.gitkeep +12 -0
- package/template/execution/push_workflow.js +396 -0
- package/template/execution/tools/.gitkeep +18 -0
- package/template/execution/tools_directives/.gitkeep +12 -0
- package/template/execution/workflows/.gitkeep +10 -0
- package/template/package.json +12 -0
|
@@ -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.
|