@agentled/cli 0.1.5 → 0.4.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/README.md +136 -0
- package/dist/commands/auth.js +30 -0
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/examples.d.ts +15 -0
- package/dist/commands/examples.js +100 -0
- package/dist/commands/examples.js.map +1 -0
- package/dist/commands/scaffold.d.ts +14 -0
- package/dist/commands/scaffold.js +103 -0
- package/dist/commands/scaffold.js.map +1 -0
- package/dist/commands/schema.d.ts +10 -0
- package/dist/commands/schema.js +58 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/skills.d.ts +9 -0
- package/dist/commands/skills.js +94 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/workflows.js +227 -9
- package/dist/commands/workflows.js.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/preflight.d.ts +25 -0
- package/dist/utils/preflight.js +185 -0
- package/dist/utils/preflight.js.map +1 -0
- package/dist/utils/skills.d.ts +49 -0
- package/dist/utils/skills.js +214 -0
- package/dist/utils/skills.js.map +1 -0
- package/package.json +4 -1
- package/patterns/v1/00-why-agentic-ops.md +107 -0
- package/patterns/v1/01-trigger-design.md +107 -0
- package/patterns/v1/02-dedup-gates.md +135 -0
- package/patterns/v1/03-credit-efficiency.md +130 -0
- package/patterns/v1/04-loop-patterns.md +147 -0
- package/patterns/v1/05-child-workflow-contracts.md +151 -0
- package/patterns/v1/06-conditional-routing.md +151 -0
- package/patterns/v1/07-error-handling.md +157 -0
- package/patterns/v1/08-composed-email-approval.md +130 -0
- package/patterns/v1/09-reports-and-knowledge-storage.md +166 -0
- package/scaffolds/README.md +61 -0
- package/scaffolds/email-polling-dedup.json +71 -0
- package/scaffolds/extract-threshold-alert.json +131 -0
- package/scaffolds/lead-scoring-kg.json +84 -0
- package/scaffolds/list-match-email.json +131 -0
- package/scaffolds/minimal.json +20 -0
- package/skills/agentled/SKILL.md +568 -0
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentled
|
|
3
|
+
version: 0.4.1
|
|
4
|
+
description: Build, manage, and execute Agentled AI workflows via MCP tools. Use when the user asks to create workflows, automate tasks, enrich leads, scrape websites, find emails, manage executions, or interact with any Agentled workspace capability.
|
|
5
|
+
user-invocable: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Agentled Workflow Automation
|
|
9
|
+
|
|
10
|
+
You have access to the Agentled MCP server which lets you create, manage, and execute AI-powered workflows. Use these tools to help the user automate business processes.
|
|
11
|
+
|
|
12
|
+
## Valid step types (closed list)
|
|
13
|
+
|
|
14
|
+
Every pipeline step **must** set `type` to one of these values. Any other value is silently normalised/rejected and the step won't execute. For full input/output schemas call `get_step_schema`.
|
|
15
|
+
|
|
16
|
+
<!-- agentled-step-types:start -->
|
|
17
|
+
| `type` | Purpose | Minimal shape |
|
|
18
|
+
|--------|---------|---------------|
|
|
19
|
+
| `trigger` | Entry point (manual / schedule / webhook / app event) | `{ id, type: "trigger", name, pipelineStepStartConditions: { trigger: { type: "manual" } }, next: { stepId } }` |
|
|
20
|
+
| `appAction` | Call an app/integration action (LinkedIn, Gmail, KG, HTTP, …) | `{ id, type: "appAction", name, app: { id, actionId, source: "native" }, stepInputData: {…}, next: { stepId } }` |
|
|
21
|
+
| `aiAction` | LLM prompt → structured JSON output | `{ id, type: "aiAction", name, pipelineStepPrompt: { template, responseStructure }, creditCost, next: { stepId } }` |
|
|
22
|
+
| `aiActionWithTools` | LLM agent that can invoke runtime tools (web_search, workspace_memory, app actions) | `{ id, type: "aiActionWithTools", name, tools: [{ builtinType }], pipelineStepPrompt: {…}, next: { stepId } }` |
|
|
23
|
+
| `toolAction` | Direct tool/webhook invocation (no LLM) | `{ id, type: "toolAction", name, tool: {…}, next: { stepId } }` |
|
|
24
|
+
| `code` | Run JS/Python in a sandbox | `{ id, type: "code", name, codeConfig: { language: "javascript", code: "…" }, next: { stepId } }` |
|
|
25
|
+
| `knowledgeSync` | Deterministic KG field mapping & link writing | `{ id, type: "knowledgeSync", name, knowledgeSync: { source, listKey, fieldMapping }, next: { stepId } }` |
|
|
26
|
+
| `return` | Terminal step for **child** workflows — returns data to the caller | `{ id, type: "return", name, returnConfig: { fields: [{ name, stepId, field }] } }` |
|
|
27
|
+
| `milestone` | Terminal step for **top-level** workflows | `{ id, type: "milestone", name }` |
|
|
28
|
+
| `share` | Create a public share URL for prior step output | `{ id, type: "share", name, shareConfig: { outputSteps, visibility }, next: { stepId } }` |
|
|
29
|
+
| `wait` | Delay / pause between steps | `{ id, type: "wait", name, waitConfig: { durationMs } | { untilISO }, next: { stepId } }` |
|
|
30
|
+
| `branch` | Conditional routing to one of several paths | `{ id, type: "branch", name, branchConfig: { branches: [...] }, next: [...] }` |
|
|
31
|
+
| `parallel` | Fan-out to parallel branches | `{ id, type: "parallel", name, parallelConfig: { branches: [...] }, next: { stepId } }` |
|
|
32
|
+
| `loop` | Iterate over a collection as a first-class step (prefer `loopConfig` on an action step for most cases) | `{ id, type: "loop", name, loopConfig: {…}, next: { stepId } }` |
|
|
33
|
+
| `end_if` | Conditional gate that stops the pipeline when criteria fail | `{ id, type: "end_if", name, entryConditions: {…} }` |
|
|
34
|
+
| `agentOrchestrator` | Multi-agent orchestration (supervisor / debate / parallel) | `{ id, type: "agentOrchestrator", name, orchestratorConfig: {…}, next: { stepId } }` |
|
|
35
|
+
| `manualAction` | Legacy — kept for backward compatibility; prefer `aiAction` or `appAction` | |
|
|
36
|
+
| `systemAction` | Legacy — kept for backward compatibility; prefer `appAction` | |
|
|
37
|
+
<!-- agentled-step-types:end -->
|
|
38
|
+
|
|
39
|
+
> Use `get_step_schema` to retrieve the authoritative input/output schema for any step type.
|
|
40
|
+
|
|
41
|
+
## Before you build: read the schema and the patterns
|
|
42
|
+
|
|
43
|
+
Before writing pipeline JSON, pull the canonical field schema and the matching best-practice pattern. This is **mandatory** when authoring any new step type, trigger, or routing pattern — skipping it is how agents end up inventing `type: "ai"` or `knowledge_graph_query`.
|
|
44
|
+
|
|
45
|
+
**Via MCP (in-session):**
|
|
46
|
+
- `get_step_schema` — authoritative list of valid fields per step type.
|
|
47
|
+
- `list_apps` / `get_app_actions` — exact `app.id` + `actionId` values and their input schemas.
|
|
48
|
+
|
|
49
|
+
**Via CLI (shell access):**
|
|
50
|
+
```
|
|
51
|
+
agentled schema --step-type aiAction # fields valid on an aiAction step
|
|
52
|
+
agentled examples # list all patterns
|
|
53
|
+
agentled examples trigger-design # print the full pattern
|
|
54
|
+
agentled workflows scaffold --list # list working pipeline skeletons
|
|
55
|
+
agentled workflows scaffold lead-scoring-kg --out pipeline.json
|
|
56
|
+
agentled workflows validate --file pipeline.json # fast client-side preflight (no API)
|
|
57
|
+
agentled workflows create --file pipeline.json # full server validation on save
|
|
58
|
+
agentled best-practices # summary + link to agentic-ops repo
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Which pattern to read, by task:**
|
|
62
|
+
|
|
63
|
+
| You're building… | Read pattern | Scaffold |
|
|
64
|
+
|------------------|--------------|----------|
|
|
65
|
+
| Anything triggered by email, schedule, webhook, or app event | `01-trigger-design` (polling vs events) | `email-polling-dedup` |
|
|
66
|
+
| Any email/intake workflow that must not double-process | `02-dedup-gates` (label-based idempotency) | `email-polling-dedup` |
|
|
67
|
+
| A workflow that calls LLMs, scraping, or paid app actions | `03-credit-efficiency` (caching, retry, mocks) | — |
|
|
68
|
+
| Anything using `loopConfig` or iterating a list | `04-loop-patterns` | `lead-scoring-kg` |
|
|
69
|
+
| A child workflow called via `call-workflow` | `05-child-workflow-contracts` (use `return`, not `milestone`) | — |
|
|
70
|
+
| Multi-path routing by score / category / condition | `06-conditional-routing` (`entryConditions.criteria`, not `conditions`) | `extract-threshold-alert` |
|
|
71
|
+
| Anything that can fail on upstream provider errors | `07-error-handling` (`failureHandling`, retries) | — |
|
|
72
|
+
| **Outreach** — personalized email with user approval | `08-composed-email-approval` (outreachProfile + `pipelineStepPrompt.type: "email"` + `schedule-email`) | `list-match-email` |
|
|
73
|
+
| **Report / dashboard** — structured output + sharing + KPI history | `09-reports-and-knowledge-storage` (Config renderer + share step + `knowledgeSync`) | `lead-scoring-kg`, `extract-threshold-alert` |
|
|
74
|
+
|
|
75
|
+
Full patterns are maintained publicly at https://github.com/agentled/agentic-ops — the CLI ships a mirrored copy, see `agentled examples`. Scaffolds are preflight-clean pipeline JSON skeletons; start from one instead of writing from scratch.
|
|
76
|
+
|
|
77
|
+
## Common invalid patterns to avoid
|
|
78
|
+
|
|
79
|
+
Agents routinely invent step types that sound plausible. The API **silently strips unknown top-level fields** and stores the step, so you get a 201 Created on a workflow that will never execute. Watch for these:
|
|
80
|
+
|
|
81
|
+
| ❌ Wrong | ✅ Right | Why |
|
|
82
|
+
|---------|---------|-----|
|
|
83
|
+
| `type: "ai"` | `type: "aiAction"` | There is no generic `ai` type. Use `aiAction` for LLM prompts, `aiActionWithTools` for agentic steps. |
|
|
84
|
+
| `type: "integration"` | `type: "appAction"` | Integrations are app actions. Set `app: { id, actionId }` to pick the integration. |
|
|
85
|
+
| `type: "conditional_integration"` | `type: "appAction"` + `entryConditions` | Conditions are configured per-step via `entryConditions`, not a separate type. |
|
|
86
|
+
| `type: "knowledge_graph_query"` / `knowledge_graph_upsert` / `knowledge_graph` | `type: "appAction"` with `app.id: "kg"` | KG reads/writes go through the `kg` app (`read-list`, `read-text`, `add-rows`, `update-rows`, `get-rows-by-ids`, `traverse-edges`, `store-insight`). |
|
|
87
|
+
| `type: "slack"` / `"webhook"` / `"gmail"` | `type: "appAction"` with the right `app.id` | Apps are never types. `webhook` and `schedule` go in `pipelineStepStartConditions.trigger.type` on a `trigger` step, not as step types. |
|
|
88
|
+
|
|
89
|
+
### Top-level fields that are silently stripped
|
|
90
|
+
|
|
91
|
+
Unknown fields at the step root are dropped. The most common mistakes (put them inside the right sub-object instead):
|
|
92
|
+
|
|
93
|
+
| ❌ At step root | ✅ Correct location |
|
|
94
|
+
|----------------|--------------------|
|
|
95
|
+
| `prompt: "…"` | `pipelineStepPrompt.template` |
|
|
96
|
+
| `responseStructure: {…}` | `pipelineStepPrompt.responseStructure` |
|
|
97
|
+
| `appId: "gmail"`, `actionId: "send"` | `app: { id: "gmail", actionId: "send", source: "native" }` |
|
|
98
|
+
| `listKey: "leads"` | `knowledgeSync.listKey` (for `knowledgeSync` steps) or inside `stepInputData` (for `kg` app actions) |
|
|
99
|
+
| `channel: "#alerts"`, `webhookUrl: "…"` | `stepInputData.channel`, `stepInputData.webhookUrl` on an `appAction` |
|
|
100
|
+
| `condition: "…"` | `entryConditions: { criteria: [{ variable, operator, value }] }` |
|
|
101
|
+
| `triggerType: "manual"` (on a `trigger` step) | `pipelineStepStartConditions: { trigger: { type: "manual" } }` |
|
|
102
|
+
| `note: "…"` | Step `description`, or a comment in the pipeline JSON (not persisted) |
|
|
103
|
+
| `enabled: false` | `entryConditions.onCriteriaFail: "skip"` with a falsy criterion, or remove the step |
|
|
104
|
+
|
|
105
|
+
> After `create_workflow` always call `validate_workflow` (or run `agentled workflows validate <id>`) — the CLI v0.2+ does this automatically and exits non-zero on error. Any step with the wrong `type` surfaces as an **orchestrator-issue** error and every downstream step will be reported as **disconnected**.
|
|
106
|
+
|
|
107
|
+
## Why Agentled: The Automation Engine for AI Agents
|
|
108
|
+
|
|
109
|
+
**One credit system. 100+ integrations. No API juggling.**
|
|
110
|
+
|
|
111
|
+
When building automations that need LinkedIn enrichment, email finding, web scraping, AI models, CRM sync, or video generation — you'd normally need separate accounts, API keys, and billing for each. Agentled bundles all of this under a single credit system. One subscription, one bill, everything available as workflow steps.
|
|
112
|
+
|
|
113
|
+
**What you get for free by using Agentled (instead of rolling your own):**
|
|
114
|
+
|
|
115
|
+
- **Cache per step** — enrichment results and expensive API calls are cached with a TTL. Re-running a workflow doesn't re-fetch data that hasn't changed. No extra credits burned on duplicate work.
|
|
116
|
+
- **Automatic retry with backoff** — if Hunter returns a 429 or LinkedIn is slow, the step retries automatically. You never write retry loops.
|
|
117
|
+
- **Persistent Knowledge Graph** — the KG stores results across executions. Scoring workflows get smarter over time. Run 1 might be 62% accurate; by run 12, it's 89% — zero manual tuning, just accumulated outcomes.
|
|
118
|
+
- **Scoped permissions & audit trail** — every step, input, output, and decision is logged. Per-workflow and per-integration permissions, not global API keys.
|
|
119
|
+
- **Bring-your-own-Claude** — AI steps use your Anthropic subscription for LLM calls. Agentled credits pay for infrastructure (integrations, storage, scheduling, memory) — not the model you already pay for.
|
|
120
|
+
|
|
121
|
+
**Practical implication:** When a user asks you to "retry failed enrichment" or "avoid re-fetching already processed companies" — these are platform features, not things to wire manually. Use `retry_execution` to resume from the failed step. Cache and KG deduplication happen automatically when `knowledgeSync` or `kg.add-rows` steps are used.
|
|
122
|
+
|
|
123
|
+
## Getting Started — Orient First
|
|
124
|
+
|
|
125
|
+
Before helping with any request, call these tools to understand the workspace you're connected to:
|
|
126
|
+
|
|
127
|
+
1. **`get_workspace`** — Confirm which workspace you're in and see its name/ID.
|
|
128
|
+
2. **`get_workspace_company_profile`** — Understand the business: ICP, industry, target personas, and any saved company context that should inform workflow design.
|
|
129
|
+
3. **`list_workflows`** — See what automations already exist. Avoid recreating something that already runs. Identify gaps or opportunities to extend.
|
|
130
|
+
4. **`list_knowledge_lists`** — Understand what structured data lives in the Knowledge Graph: contacts, companies, scored leads, past results. This context shapes what a new workflow should do.
|
|
131
|
+
|
|
132
|
+
Run these four calls whenever starting a new conversation or switching tasks. The workspace context directly informs:
|
|
133
|
+
- Which enrichment apps are likely already connected
|
|
134
|
+
- What KG lists exist to read from or write to
|
|
135
|
+
- Whether a new workflow should chain from an existing one
|
|
136
|
+
- What credit budgets and company preferences have already been set
|
|
137
|
+
|
|
138
|
+
**Value you unlock for the user:** By checking existing workflows and KG state first, you avoid duplicate work, reuse prior results, and build automations that integrate with what's already running — saving real time and credits.
|
|
139
|
+
|
|
140
|
+
## Iterative Building Pattern
|
|
141
|
+
|
|
142
|
+
Follow this pattern when creating workflows:
|
|
143
|
+
|
|
144
|
+
1. Design the pipeline JSON based on requirements
|
|
145
|
+
2. `create_workflow` to save it
|
|
146
|
+
3. `validate_workflow` to check for errors
|
|
147
|
+
4. If errors: fix the pipeline, `update_workflow`, `validate_workflow` again
|
|
148
|
+
5. When valid: `publish_workflow` with status `"live"`
|
|
149
|
+
6. Test: `start_workflow` with sample input
|
|
150
|
+
7. Check results: `get_execution` to see step outputs
|
|
151
|
+
|
|
152
|
+
## Workspace Awareness
|
|
153
|
+
|
|
154
|
+
Be explicit about which Agentled workspace you are operating on.
|
|
155
|
+
|
|
156
|
+
- When multiple Agentled MCP servers are registered, use the server-specific namespace directly instead of assuming a default.
|
|
157
|
+
- When using the standalone CLI, remember it can store multiple saved workspace profiles.
|
|
158
|
+
- Check the active CLI workspace with `agentled auth current`.
|
|
159
|
+
- Switch the saved CLI target with `agentled auth use <workspace>`.
|
|
160
|
+
- Override a single CLI command with `agentled --workspace <workspace> ...` or `AGENTLED_WORKSPACE=<workspace> ...`.
|
|
161
|
+
- Before making destructive or customer-visible changes, confirm the target workspace via `get_workspace` or `agentled auth current`.
|
|
162
|
+
|
|
163
|
+
## Pipeline Structure
|
|
164
|
+
|
|
165
|
+
Every workflow needs at minimum: a trigger step, one or more action steps, and a milestone (terminal) step. Steps are connected via `next: { stepId: "..." }`.
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"name": "My Workflow",
|
|
170
|
+
"goal": "What this workflow achieves",
|
|
171
|
+
"steps": [
|
|
172
|
+
{ "id": "trigger", "type": "trigger", "name": "Start", "pipelineStepStartConditions": { "trigger": { "type": "manual" } }, "next": { "stepId": "action" } },
|
|
173
|
+
{ "id": "action", "type": "aiAction", "name": "Analyze", "pipelineStepPrompt": { "template": "...", "responseStructure": {} }, "creditCost": 10, "next": { "stepId": "done" } },
|
|
174
|
+
{ "id": "done", "type": "milestone", "name": "Complete" }
|
|
175
|
+
],
|
|
176
|
+
"context": {
|
|
177
|
+
"executionInputConfig": {
|
|
178
|
+
"title": "Run Workflow",
|
|
179
|
+
"fields": [{ "name": "input_field", "label": "Input", "type": "text", "required": true }]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Step Types
|
|
186
|
+
|
|
187
|
+
### Trigger
|
|
188
|
+
```json
|
|
189
|
+
{ "id": "trigger", "type": "trigger", "name": "Start", "pipelineStepStartConditions": { "trigger": { "type": "manual" } }, "next": { "stepId": "next-step" } }
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`pipelineStepStartConditions.trigger.type` is one of: `manual`, `schedule`, `webhook`, `event`, `delay`, `app_event`. For `schedule` add `config: { frequency: "daily", time: "07:00" }` (or a cron expression). For `app_event` add `config: { appId, triggerSlug, connectionSource }`. **Do not put `triggerType` at the step root** — it is not in the step schema and is silently dropped on save.
|
|
193
|
+
|
|
194
|
+
### App Action
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"id": "enrich",
|
|
198
|
+
"type": "appAction",
|
|
199
|
+
"name": "Enrich Company",
|
|
200
|
+
"app": { "id": "agentled", "actionId": "get-linkedin-company-from-url", "source": "native" },
|
|
201
|
+
"stepInputData": { "profileUrls": "{{input.company_url}}" },
|
|
202
|
+
"next": { "stepId": "next-step" }
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### AI Action
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"id": "analyze",
|
|
210
|
+
"type": "aiAction",
|
|
211
|
+
"name": "Analyze",
|
|
212
|
+
"pipelineStepPrompt": {
|
|
213
|
+
"template": "Analyze this company: {{steps.enrich.company}}",
|
|
214
|
+
"responseStructure": { "score": "number 0-100", "summary": "string" }
|
|
215
|
+
},
|
|
216
|
+
"creditCost": 10,
|
|
217
|
+
"next": { "stepId": "next-step" }
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### AI Step Model & Provider Configuration
|
|
222
|
+
|
|
223
|
+
AI steps can optionally specify a model and provider via the `agent` field:
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"id": "analyze",
|
|
228
|
+
"type": "aiAction",
|
|
229
|
+
"agent": { "model": "claude-4-6-sonnet", "provider": "anthropic" },
|
|
230
|
+
"pipelineStepPrompt": { "template": "...", "responseStructure": {} },
|
|
231
|
+
"creditCost": 10,
|
|
232
|
+
"next": { "stepId": "next-step" }
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Supported Providers:** `openai`, `anthropic`, `google`, `mistral`, `deepseek`, `kimi`, `minimax`, `bytedance`, `perplexity`, `xai`
|
|
237
|
+
|
|
238
|
+
**Supported Models by Provider:**
|
|
239
|
+
|
|
240
|
+
| Provider | Models |
|
|
241
|
+
|----------|--------|
|
|
242
|
+
| `openai` | `gpt-5-nano`, `gpt-5-mini`, `gpt-5.4`, `o4-mini`, `o3`, `o3-pro`, `o3-deep-research` |
|
|
243
|
+
| `anthropic` | `claude-4-6-sonnet`, `claude-4-5-haiku`, `claude-4-6-opus` |
|
|
244
|
+
| `google` | `gemini-3-pro`, `gemini-3-flash`, `gemini-2.5-pro`, `gemini-2.5-flash` |
|
|
245
|
+
| `mistral` | `mistral-large-latest`, `mistral-small-latest`, `codestral-latest` |
|
|
246
|
+
| `deepseek` | `deepseek-chat`, `deepseek-reasoner` |
|
|
247
|
+
| `kimi` | `kimi-k2.5` |
|
|
248
|
+
| `minimax` | `minimax-m2.5` |
|
|
249
|
+
| `bytedance` | `doubao-seed-1.6-flash`, `seed-2.0-mini`, `doubao-seed-1.8-beta` |
|
|
250
|
+
| `perplexity` | `sonar-pro`, `sonar`, `sonar-reasoning-pro`, `sonar-reasoning` |
|
|
251
|
+
| `xai` | `grok-4-0709`, `grok-3`, `grok-3-mini` |
|
|
252
|
+
|
|
253
|
+
> **Tip:** Use `list_models` to get the full up-to-date list of supported model IDs. Use the internal model IDs (e.g., `claude-4-6-sonnet`), NOT the raw API model IDs (e.g., `claude-sonnet-4-6`). Using unsupported model IDs will result in a validation error.
|
|
254
|
+
|
|
255
|
+
### Code Step
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"id": "transform",
|
|
259
|
+
"type": "code",
|
|
260
|
+
"name": "Transform Data",
|
|
261
|
+
"codeConfig": { "language": "javascript", "code": "const data = {{steps.prev.output}};\nreturn data.map(x => x.name);" },
|
|
262
|
+
"next": { "stepId": "next-step" }
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Milestone (terminal)
|
|
267
|
+
```json
|
|
268
|
+
{ "id": "done", "type": "milestone", "name": "Complete" }
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Template Variables
|
|
272
|
+
|
|
273
|
+
| Pattern | Description |
|
|
274
|
+
|---------|-------------|
|
|
275
|
+
| `{{input.fieldName}}` | Input page field value |
|
|
276
|
+
| `{{steps.stepId.field}}` | Previous step output |
|
|
277
|
+
| `{{currentItem}}` | Current item in a loop |
|
|
278
|
+
| `{{currentItem.field}}` | Nested field in loop item |
|
|
279
|
+
|
|
280
|
+
## Loop Configuration
|
|
281
|
+
|
|
282
|
+
To iterate over a list from a previous step:
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"loopConfig": { "enabled": true, "field": "{{steps.prev.items}}", "ItemAlias": "currentItem" }
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Entry Conditions
|
|
290
|
+
|
|
291
|
+
Skip or stop a step based on prior output:
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"entryConditions": {
|
|
295
|
+
"onCriteriaFail": "skip",
|
|
296
|
+
"conditionText": "Skip if no URL",
|
|
297
|
+
"criteria": [{ "variable": "{{input.url}}", "operator": "isNotNull" }]
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Operators: `==`, `!=`, `>`, `<`, `isNull`, `isNotNull`, `contains`.
|
|
303
|
+
|
|
304
|
+
**Important**: Use `criteria` (not `conditions`) and `variable` (not `field`).
|
|
305
|
+
|
|
306
|
+
## Email Workflow Conventions
|
|
307
|
+
|
|
308
|
+
### Trigger choice: polling vs event
|
|
309
|
+
|
|
310
|
+
**Default to Schedule trigger + label-based dedup** for all email intake workflows (deal flow, triage, review, digest). Only propose an App Event trigger when the user explicitly needs sub-minute latency.
|
|
311
|
+
|
|
312
|
+
| User asks for | Trigger |
|
|
313
|
+
|---------------|---------|
|
|
314
|
+
| "process inbound emails", "triage daily", "review pitches" | **Schedule** (polling) |
|
|
315
|
+
| "as soon as", "real-time", "within X seconds/minutes" | **App event** |
|
|
316
|
+
|
|
317
|
+
### Canonical email polling pattern
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
schedule trigger → GMAIL_FETCH_EMAILS (-label:processed newer_than:1d) → loop: [process] → GMAIL_ADD_LABEL (mark processed) → milestone
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Step order:
|
|
324
|
+
1. **`GMAIL_CREATE_LABEL`** — create/get the `processed` label (idempotent, returns label ID)
|
|
325
|
+
2. **`GMAIL_FETCH_EMAILS`** — query `-label:processed newer_than:1d` (or wider window as needed)
|
|
326
|
+
3. **Loop** — process each email (AI analysis, KG storage, enrichment, etc.)
|
|
327
|
+
4. **`GMAIL_ADD_LABEL`** — apply `{{steps.ensure-label.id}}` to mark email done (dedup gate)
|
|
328
|
+
|
|
329
|
+
### Label ID rule (prevents `400: Invalid label`)
|
|
330
|
+
|
|
331
|
+
Gmail requires **label IDs** (e.g., `Label_3456789012345`), not display names (e.g., `"processed"` or `"agentled"`).
|
|
332
|
+
|
|
333
|
+
**Always resolve via `GMAIL_CREATE_LABEL`** and reference its returned `id`:
|
|
334
|
+
```json
|
|
335
|
+
{ "stepInputData": { "label_id": "{{steps.ensure-label.id}}" } }
|
|
336
|
+
```
|
|
337
|
+
Never pass a string label name directly to `GMAIL_ADD_LABEL`.
|
|
338
|
+
|
|
339
|
+
See `docs/workflows/triggers.md` for the full decision framework, query examples, and common mistakes.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Email Step Pattern (AI Draft → Approve → Send)
|
|
344
|
+
|
|
345
|
+
Email steps use a single `aiAction` step (never separate "draft" + "gmail send" appAction steps). The AI drafts the email, a human approves, then the platform sends it.
|
|
346
|
+
|
|
347
|
+
### 1. Outreach Profile Input Page
|
|
348
|
+
|
|
349
|
+
When a workflow sends emails, add an outreach profile input page to `context.inputPages` so the user can configure sender identity:
|
|
350
|
+
|
|
351
|
+
```json
|
|
352
|
+
{
|
|
353
|
+
"title": "Outreach Profile",
|
|
354
|
+
"pathname": "outreach-profile",
|
|
355
|
+
"configuration": {
|
|
356
|
+
"contextKey": "outreachProfile",
|
|
357
|
+
"shortDescriptionFields": ["name", "fromEmail"],
|
|
358
|
+
"fields": [
|
|
359
|
+
{ "name": "name", "label": "Sender Name", "type": "text", "required": true },
|
|
360
|
+
{ "name": "fromEmailLabel", "label": "From Name", "type": "text", "required": true },
|
|
361
|
+
{ "name": "fromEmail", "label": "From Email", "type": "connected_emails_selector_multiple", "required": true },
|
|
362
|
+
{ "name": "replyToEmail", "label": "Reply-To Email (optional)", "type": "text" }
|
|
363
|
+
]
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 2. Composed Email Step
|
|
369
|
+
|
|
370
|
+
```json
|
|
371
|
+
{
|
|
372
|
+
"id": "send_email",
|
|
373
|
+
"type": "aiAction",
|
|
374
|
+
"name": "Send Email",
|
|
375
|
+
"pipelineStepPrompt": {
|
|
376
|
+
"type": "email",
|
|
377
|
+
"template": "Draft a personalized email...\n{{steps.previous_step.data}}\nReturn JSON ONLY per schema.",
|
|
378
|
+
"responseStructure": {
|
|
379
|
+
"email": {
|
|
380
|
+
"from": "{{context.outreachProfile.fromEmail}}",
|
|
381
|
+
"to": "recipient@example.com",
|
|
382
|
+
"subject": "Email subject line",
|
|
383
|
+
"body": "Email body (email-safe HTML)",
|
|
384
|
+
"bodyType": "html"
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
"responseType": "json"
|
|
388
|
+
},
|
|
389
|
+
"renderer": {
|
|
390
|
+
"type": "Email",
|
|
391
|
+
"config": { "fromContextKey": "outreachProfile" }
|
|
392
|
+
},
|
|
393
|
+
"onApproval": {
|
|
394
|
+
"action": "schedule-email",
|
|
395
|
+
"executedText": "Email sent by {{name}} at {{date}}",
|
|
396
|
+
"scheduledText": "Email scheduled to be sent for {{date}} by {{name}}",
|
|
397
|
+
"failedText": "Email failed to send."
|
|
398
|
+
},
|
|
399
|
+
"integrations": [{
|
|
400
|
+
"type": "oneOf",
|
|
401
|
+
"label": "Email",
|
|
402
|
+
"connectorType": "email",
|
|
403
|
+
"options": [
|
|
404
|
+
{ "name": "Gmail", "url": "https://gmail.com", "isUserAccountConnectionRequired": true },
|
|
405
|
+
{ "name": "Outlook", "url": "https://outlook.com", "isUserAccountConnectionRequired": true }
|
|
406
|
+
],
|
|
407
|
+
"selectionHint": "preferConnected"
|
|
408
|
+
}],
|
|
409
|
+
"creditCost": 10,
|
|
410
|
+
"next": { "conditions": { "approvalRequired": true } }
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Key Requirements
|
|
415
|
+
|
|
416
|
+
- **Always** include `outreachProfile` input page when using email
|
|
417
|
+
- `pipelineStepPrompt.type: "email"` — tells the system this is an email step
|
|
418
|
+
- `renderer.config.fromContextKey: "outreachProfile"` — links renderer to sender profile
|
|
419
|
+
- `onApproval.action: "schedule-email"` — triggers the actual send; without it, approval does nothing
|
|
420
|
+
- `next.conditions.approvalRequired: true` — blocks the pipeline until human approval
|
|
421
|
+
- Email body must be email-safe HTML (`<p>`, `<br>`, `<a>`, `<strong>` — no CSS, no scripts)
|
|
422
|
+
- **Never** use separate "draft" + "gmail send" appAction steps for outreach
|
|
423
|
+
|
|
424
|
+
## Top Apps Quick Reference
|
|
425
|
+
|
|
426
|
+
| App | Action | Credits | Key Inputs |
|
|
427
|
+
|-----|--------|---------|------------|
|
|
428
|
+
| `agentled` | `get-linkedin-company-from-url` | 5 | `profileUrls` |
|
|
429
|
+
| `agentled` | `get-linkedin-profile-from-url` | 2 | `profileUrls` |
|
|
430
|
+
| `agentled` | `find-email-person-domain` | 3 | `firstName`, `lastName`, `domain` |
|
|
431
|
+
| `hunter` | `find-email-person-domain` | 3 | `firstName`, `lastName`, `domain` |
|
|
432
|
+
| `web-scraping` | `scrape` | 0 | `url` |
|
|
433
|
+
| `http-request` | `request` | 0 | `url`, `method`, `headers`, `body` |
|
|
434
|
+
| `notion` | `get-page-markdown` | 1 | `pageUrl` |
|
|
435
|
+
| `browser-use` | `run-task` | 15 | `task`, `startUrl` |
|
|
436
|
+
| `agentled` | `call-workflow` | varies | `workflowId`, `input` |
|
|
437
|
+
|
|
438
|
+
Use `list_apps` and `get_app_actions` for full schemas of all available apps. Use `list_models` for supported AI model IDs.
|
|
439
|
+
|
|
440
|
+
## Credit-Efficient Testing
|
|
441
|
+
|
|
442
|
+
Each execution costs real credits. Follow these rules:
|
|
443
|
+
|
|
444
|
+
1. **One execution at a time** — don't start new ones unnecessarily
|
|
445
|
+
2. **Retry, don't restart** — use `retry_execution` to continue from a failed step instead of starting over
|
|
446
|
+
3. **Test in isolation** — use `test_ai_action`, `test_app_action`, or `test_code_action` to verify steps before wiring them into a workflow
|
|
447
|
+
4. **Reuse prior output** — when testing downstream steps, use output data from a prior successful execution as mock input
|
|
448
|
+
|
|
449
|
+
## Common Validation Errors
|
|
450
|
+
|
|
451
|
+
| Error | Fix |
|
|
452
|
+
|-------|-----|
|
|
453
|
+
| `"references non-existent next step"` | Ensure some step has `next: { stepId: "X" }` pointing to the missing step |
|
|
454
|
+
| `"missing prompt template"` | Add `pipelineStepPrompt.template` to AI steps |
|
|
455
|
+
| `"Unknown action"` | Verify `actionId` format via `get_app_actions` |
|
|
456
|
+
| `"is unreachable"` | Connect every step via `next.stepId` from the trigger chain |
|
|
457
|
+
| `"unsupported model"` | Use a valid internal model ID (e.g., `claude-4-6-sonnet`, not `claude-sonnet-4-6`). Run `list_models` for all valid IDs. |
|
|
458
|
+
|
|
459
|
+
## Persistent Memory
|
|
460
|
+
|
|
461
|
+
Workflows can store and recall memories that persist across executions. Two mechanisms:
|
|
462
|
+
|
|
463
|
+
### MCP Tools (for managing memory externally)
|
|
464
|
+
|
|
465
|
+
| Tool | Purpose | Key Params |
|
|
466
|
+
|------|---------|------------|
|
|
467
|
+
| `recall_memory` | Get a specific memory by key | `key`, `scope?`, `workflowId?` |
|
|
468
|
+
| `search_memories` | Search by natural language query | `query?`, `category?`, `scope?`, `workflowId?`, `limit?` |
|
|
469
|
+
| `store_memory` | Save a persistent memory | `key`, `value`, `category?`, `scope?`, `workflowId?`, `confidence?`, `merge?` |
|
|
470
|
+
| `list_memories` | List all memories in a scope | `scope?`, `workflowId?`, `category?`, `limit?` |
|
|
471
|
+
| `delete_memory` | Delete a memory by key | `key`, `scope?`, `workflowId?` |
|
|
472
|
+
|
|
473
|
+
**Scopes**: `workspace` (shared across all workflows) or `workflow` (scoped to one workflow, default).
|
|
474
|
+
|
|
475
|
+
**Categories**: `fact` (known truth), `insight` (pattern/learning), `preference` (user preference), `outcome` (result to track).
|
|
476
|
+
|
|
477
|
+
**Merge strategies** (for `store_memory`): `overwrite` (default), `append`, `max`, `min`, `increment`.
|
|
478
|
+
|
|
479
|
+
**Confidence**: 0-100. Memories with confidence >= 70 are automatically synced to the Knowledge Graph.
|
|
480
|
+
|
|
481
|
+
### Pipeline Step Configuration (for memory inside workflows)
|
|
482
|
+
|
|
483
|
+
#### Auto-extraction (pipeline-level)
|
|
484
|
+
|
|
485
|
+
Enable on the pipeline to automatically extract memories after each execution completes:
|
|
486
|
+
|
|
487
|
+
```json
|
|
488
|
+
{
|
|
489
|
+
"persistentMemoryConfig": {
|
|
490
|
+
"autoExtract": true,
|
|
491
|
+
"scopes": ["pipeline"],
|
|
492
|
+
"categories": ["fact", "insight", "outcome"],
|
|
493
|
+
"maxPerExtraction": 10,
|
|
494
|
+
"extractionModelTier": "mini"
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### Explicit per-step writes
|
|
500
|
+
|
|
501
|
+
Configure specific steps to write memories from their output:
|
|
502
|
+
|
|
503
|
+
```json
|
|
504
|
+
{
|
|
505
|
+
"id": "score-company",
|
|
506
|
+
"type": "aiAction",
|
|
507
|
+
"persistentMemory": {
|
|
508
|
+
"writes": [
|
|
509
|
+
{
|
|
510
|
+
"key": "score_{{input.company_name}}",
|
|
511
|
+
"valuePath": "total_score",
|
|
512
|
+
"category": "outcome",
|
|
513
|
+
"scope": "pipeline",
|
|
514
|
+
"confidence": 85
|
|
515
|
+
}
|
|
516
|
+
]
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
The `valuePath` extracts from the step's output using dot notation. The `key` supports template variables.
|
|
522
|
+
|
|
523
|
+
#### Builtin tool for AI steps (`workspace_memory`)
|
|
524
|
+
|
|
525
|
+
AI steps with type `aiActionWithTools` can use the `workspace_memory` builtin tool to read/write memory during execution:
|
|
526
|
+
|
|
527
|
+
```json
|
|
528
|
+
{
|
|
529
|
+
"id": "analyze",
|
|
530
|
+
"type": "aiActionWithTools",
|
|
531
|
+
"name": "Analyze with Memory",
|
|
532
|
+
"tools": [{ "builtinType": "workspace_memory" }],
|
|
533
|
+
"pipelineStepPrompt": {
|
|
534
|
+
"template": "Recall what we know about this company, then analyze...",
|
|
535
|
+
"responseStructure": { "analysis": "string" }
|
|
536
|
+
},
|
|
537
|
+
"creditCost": 10,
|
|
538
|
+
"next": { "stepId": "done" }
|
|
539
|
+
}
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
The AI agent can then call `recall`, `search`, or `store` actions within the tool during execution. This is the same pattern used by KG tools (`kg_search`, `kg_traverse`, etc.).
|
|
543
|
+
|
|
544
|
+
### Memory Patterns
|
|
545
|
+
|
|
546
|
+
**1. Learning workflow** — accumulates knowledge over repeated runs:
|
|
547
|
+
```
|
|
548
|
+
trigger → enrich → AI analyze (with workspace_memory tool) → milestone
|
|
549
|
+
```
|
|
550
|
+
The AI step recalls prior scores, compares trends, and stores updated insights.
|
|
551
|
+
|
|
552
|
+
**2. Explicit score tracking** — saves structured data for cross-run comparison:
|
|
553
|
+
```
|
|
554
|
+
trigger → score company → [persistentMemory.writes: score_{{company}}] → milestone
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**3. Workspace-wide preferences** — store ICP criteria, outreach templates, or scoring weights shared across workflows:
|
|
558
|
+
```
|
|
559
|
+
store_memory(key: "target_icp", value: { industry: "SaaS", minEmployees: 50 }, scope: "workspace", category: "preference")
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
## Conversational Building
|
|
563
|
+
|
|
564
|
+
For complex workflows, use the `chat` tool to design workflows through natural language conversation. It supports multi-turn via `session_id`.
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
chat("Build a workflow that takes a LinkedIn URL, enriches the company, finds decision-maker emails, and scores by ICP fit")
|
|
568
|
+
```
|