@agentled/cli 0.7.7 → 0.7.8

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agentled
3
- version: 0.6.0
3
+ version: 0.7.0
4
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
5
  user-invocable: false
6
6
  ---
@@ -9,6 +9,32 @@ user-invocable: false
9
9
 
10
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
11
 
12
+ This file is a **router**. It carries the always-needed core (orientation, the
13
+ closed list of step types, the invalid-pattern guards, the build loop). The deep
14
+ reference material lives in `references/` and the tactical playbooks in the
15
+ pattern library — load them on demand rather than reading everything up front.
16
+
17
+ ## Reference index — load on demand
18
+
19
+ When a task matches a row below, read that file before authoring. Don't preload
20
+ them; that defeats the point.
21
+
22
+ | When you're… | Read |
23
+ |--------------|------|
24
+ | Writing any step's JSON (field shapes, model IDs, loop/entry-condition syntax) | `references/step-schemas.md` (or `get_step_schema`) |
25
+ | Editing an existing/live workflow (merge model, `update_step` / `update_workflow_context`, drafts) | `references/editing-workflows.md` |
26
+ | Building anything that reads or sends email | `references/email-workflows.md` |
27
+ | Sourcing/collecting entities to act on later | `references/entity-pipeline.md` |
28
+ | Adding cross-execution memory | `references/persistent-memory.md` |
29
+ | Designing outbound / sales / investor / lead-gen at scale | `references/outreach-and-scale.md` |
30
+ | Producing local artifacts, or seeding a templated workspace's sidebar | `references/workspace-folder.md` |
31
+ | Picking apps, testing credit-efficiently, decoding a validation error | `references/credits-apps-and-errors.md` |
32
+
33
+ Tactical, shape-specific playbooks (triggers, dedup, loops, routing, reports,
34
+ workflow groups, …) live in the **pattern library** — list with
35
+ `agentled examples` and print one with `agentled examples <name>`. The
36
+ "which pattern to read" table is below under *Before you build*.
37
+
12
38
  ## Goal and bottleneck first
13
39
 
14
40
  Before designing any workflow, determine what the user is actually trying to achieve and where the real bottleneck is. Agents that skip this step build the wrong system.
@@ -20,49 +46,36 @@ Before designing any workflow, determine what the user is actually trying to ach
20
46
  **The design loop:**
21
47
  1. Orient — inspect the workspace (identity, KG lists, connected apps, existing workflows, existing agents).
22
48
  2. Infer — determine the likely goal and bottleneck from workspace context.
23
- 3. Ask — if the business direction is genuinely ambiguous, ask a few targeted questions.
49
+ 3. Ask — if the business direction is genuinely ambiguous, ask a few targeted questions (see `references/outreach-and-scale.md` for what to ask and what not to).
24
50
  4. Brief — produce a short build brief (goal, assumptions, assets to reuse, KG lists, workflow group, risks, cost hotspots, build order).
25
51
  5. Build — create workflows incrementally from the brief.
26
52
 
27
53
  > For multi-workflow systems, produce a group manifest before touching live workflow state. See `agentled group-manifest --help` and `docs/GROUP_MANIFEST.md`.
28
54
 
29
- ## What to ask — and what not to ask
55
+ ## Orient Before Designing
30
56
 
31
- After orientation, ask **at most three to five** targeted questions. Focus only on what the workspace inspection cannot answer.
57
+ Before helping with any request, inspect the workspace. Use `agentled workspace inspect` (CLI) or call these MCP tools individually:
32
58
 
33
- **Good questions:**
34
- - "What is the primary goal: source more paying leads, run each event smoothly, or report pipeline health?"
35
- - "Where is the bottleneck today: finding leads, getting replies, converting to paid, or operational follow-up?"
36
- - "What is the system of record for payments/bookings right now: Stripe webhook, a booking page, a manual form, or a KG list?"
37
- - "Which actions must be approval-gated: customer emails, status changes, or all customer-facing messages?"
38
- - "What success metric should this optimize: conversions per week, leads contacted, confirmations, fill rate, or operator time saved?"
59
+ 1. **`get_workspace`** — Confirm workspace identity (name, ID), team members, pending invitations, and knowledge-list schemas.
60
+ 2. **`get_workspace_company_profile`** — Business context: ICP, industry, target personas, saved preferences that should shape workflow design.
61
+ 3. **`list_workflows`** — Existing automations: avoid recreating, identify reuse opportunities, note gaps.
62
+ 4. **`list_knowledge_lists`** — KG lists: contacts, companies, scored leads, status machines. Shapes what a new workflow reads from or writes to.
63
+ 5. **`list_connections`** — Connected apps and integrations: know which enrichment, CRM, or email providers are already authed before designing steps that depend on them.
64
+ 6. **`list_agents`** — Existing agents and routines: understand what is already running autonomously before adding new agents.
39
65
 
40
- **Do not ask:**
41
- - Step type names, app action names, schema syntax, or implementation details — discover these from the workspace and CLI.
42
- - Every possible future integration question before the first useful slice is designed.
43
- - Anything answerable by running `agentled workspace inspect`.
66
+ The workspace inspection directly informs which integrations are connected, what KG lists exist, whether new workflows should chain from or replace existing ones, and what existing agents already cover.
44
67
 
45
- ## Outreach scale and segmentation
68
+ > **Shortcut:** `agentled workspace inspect --json` returns all six contexts as one consolidated response. Use it at session start to load the full picture in a single call.
46
69
 
47
- For outbound, sales, investor, founder, or lead-generation workflows, classify the motion before designing the workflow. See `docs/OUTREACH_SCALE_GUIDANCE.md`.
70
+ ### MCP-connected but no local scaffold: expected behavior
48
71
 
49
- **Core diagnostic:**
50
- - PCPL = prospects contacted / positive replies over the last 30 days. PCPL at or below 250 is a scalable winner; above 250 means diagnose deliverability, then copy, then offer-audience match.
51
- - Daily volume = last 30 days sent / 22 working days.
52
- - TAM = total reachable prospects in the CRM, KG list, enrichment tool, or target account universe.
53
- - Reply ops = whether positive replies are handled quickly and followed up persistently.
72
+ If MCP tools are already connected and working, **do not block** on missing local folders.
54
73
 
55
- **Tier guidance:**
56
- - Tier 1 (~100/day, a few thousand prospects): enrich every account, route by strongest signal, use high-touch multi-channel outreach. This is the default for most small Agentled Ops / AngelHive-style motions.
57
- - Tier 2 (~1,000/day, 50K-100K prospects): split into top 200-500 home-run accounts with Tier 1 treatment plus segmented automation for the long tail.
58
- - Tier 3 (~10K/day, hundreds of thousands): test angle x offer x segment, generate script variations, keep tests running in parallel, and track PCPL per combination.
59
- - Tier 4 (50K-100K/day, millions): require provider segmentation, live monitoring, sender reserve capacity, hourly testing cadence, and reply-handling SLAs before increasing volume.
74
+ - Continue with MCP operations immediately.
75
+ - Add a brief, non-blocking hint once per session: `You're connected via MCP. If you want local drafts/fixtures/tests, run "agentled init" in your project directory (or "agentled setup" for full onboarding).`
76
+ - Do **not** imply setup is required for read/write API operations through MCP.
60
77
 
61
- **Workflow implications:**
62
- - Small TAM problems are usually segmentation and signal-enrichment problems, not copy-only problems.
63
- - Store `outreachAngle`, `offer`, `segment`, `campaignVariant`, `channelUsed`, `sender`, `contactedAt`, `replyStatus`, `meetingStatus`, and `positiveReplyAt` when the KG schema allows it.
64
- - Configure business metrics for prospects contacted, positive replies, PCPL, meetings/bookings/paid confirmations, bounce/failed-send count, and segment/angle performance. These are `analyticsConfig` business metrics, not ROI assumptions.
65
- - Literal PCPL should use `type: "ratio"` with `ratioMode: "raw"`. Use the default percentage ratio behavior for rates such as `positive_replies / prospects_contacted`.
78
+ `agentled setup` is the full first-run path (auth, workspace folder scaffold, MCP config, skill install, knowledge probe). `agentled init` is the targeted local scaffold when they only want the local workspace folder and cache.
66
79
 
67
80
  ## Valid step types (closed list)
68
81
 
@@ -92,7 +105,7 @@ Every pipeline step **must** set `type` to one of these values. Any other value
92
105
  | `systemAction` | Legacy — kept for backward compatibility; prefer `appAction` | |
93
106
  <!-- agentled-step-types:end -->
94
107
 
95
- > Use `get_step_schema` to retrieve the authoritative input/output schema for any step type.
108
+ > Use `get_step_schema` to retrieve the authoritative input/output schema for any step type. Common shapes and template-variable syntax are in `references/step-schemas.md`.
96
109
 
97
110
  ## Before you build: read the schema and the patterns
98
111
 
@@ -137,21 +150,6 @@ agentled best-practices # summary + link to agentic-
137
150
 
138
151
  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.
139
152
 
140
- ## Business metrics vs ROI (must not be conflated)
141
-
142
- Treat these as **two separate surfaces**:
143
-
144
- - **Business metrics (`pipeline.analyticsConfig`)** = customer/workflow outcome stats extracted from step outputs (volume, conversions, approvals, rates, SLA-ish KPIs), aggregated into dashboard business-metric snapshots.
145
- - **ROI (`pipeline.metadata.roi`)** = economic assumptions + rollups (minutes saved per unit, hourly rate, benchmark units/week, measured vs benchmark mode) used for ROI/time-saved reporting.
146
-
147
- ### Required wording for agent outputs
148
-
149
- - If only `analyticsConfig` changes: say **"business metrics configured"**.
150
- - If only `metadata.roi` changes: say **"ROI assumptions configured"**.
151
- - If both change: report each section separately; never label analytics metrics as ROI metrics.
152
-
153
- This distinction applies to MCP and CLI users equally because both surfaces call the same external workflow API and return the same pipeline shape.
154
-
155
153
  ## Common invalid patterns to avoid
156
154
 
157
155
  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:
@@ -182,45 +180,6 @@ Unknown fields at the step root are dropped. The most common mistakes (put them
182
180
 
183
181
  > 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**.
184
182
 
185
- ## Platform capabilities (background reading)
186
-
187
- Agentled provides caching per step, automatic retry with backoff, a persistent Knowledge Graph, scoped permissions, and a unified credit system across 100+ integrations. For the full rationale, see `skills/agentled/WHY-AGENTLED.md`.
188
-
189
- **Practical implication:** "retry failed enrichment" and "avoid re-fetching already processed companies" are platform features. Use `retry_execution` to resume from a failed step; per-step caching is automatic. For cross-run row dedup, use `kg.upsert-rows` with a `userKey`.
190
-
191
- ## Orient Before Designing
192
-
193
- Before helping with any request, inspect the workspace. Use `agentled workspace inspect` (CLI) or call these MCP tools individually:
194
-
195
- 1. **`get_workspace`** — Confirm workspace identity (name, ID).
196
- 2. **`get_workspace_company_profile`** — Business context: ICP, industry, target personas, saved preferences that should shape workflow design.
197
- 3. **`list_workflows`** — Existing automations: avoid recreating, identify reuse opportunities, note gaps.
198
- 4. **`list_knowledge_lists`** — KG lists: contacts, companies, scored leads, status machines. Shapes what a new workflow reads from or writes to.
199
- 5. **`list_connections`** — Connected apps and integrations: know which enrichment, CRM, or email providers are already authed before designing steps that depend on them.
200
- 6. **`list_agents`** — Existing agents and routines: understand what is already running autonomously before adding new agents.
201
-
202
- The workspace inspection directly informs:
203
- - Which app integrations are already connected (and which are missing auth)
204
- - What KG lists exist to read from or write to
205
- - Whether new workflows should chain from existing ones or replace them
206
- - What existing agents already cover, so you don't duplicate
207
-
208
- > **Shortcut:** `agentled workspace inspect --json` returns all six contexts as one consolidated response. Use it at session start to load the full picture in a single call.
209
-
210
- ## MCP-connected but no local scaffold: expected behavior
211
-
212
- If MCP tools are already connected and working, **do not block** on missing local folders.
213
-
214
- - Continue with MCP operations immediately.
215
- - Add a brief, non-blocking hint once per session:
216
- - `You're connected via MCP. If you want local drafts/fixtures/tests, run "agentled init" in your project directory (or "agentled setup" for full onboarding).`
217
- - Do **not** imply setup is required for read/write API operations through MCP.
218
-
219
- Use this when users ask "did anything get created locally?" or "why is there no workspace folder?"
220
-
221
- - `agentled setup` is the full first-run path (auth, workspace folder scaffold, MCP config, skill install, knowledge probe, restart prompt).
222
- - `agentled init` is the targeted local scaffold command when they only want the local workspace folder and cache.
223
-
224
183
  ## Incremental Authoring (recommended)
225
184
 
226
185
  Build workflows **one step at a time**. This catches errors per-step instead of dumping a full JSON blob and getting 10+ errors at once.
@@ -266,690 +225,37 @@ The full-pipeline `steps` array on `create_workflow` / `update_workflow` is supp
266
225
 
267
226
  Internal testing: **0 errors with incremental vs 13 errors with bulk JSON** on the same pipeline.
268
227
 
269
- ### Editing existing workflows
270
-
271
- For live workflows, prefer per-step tools over bulk updates:
272
-
273
- - `update_step(workflowId, stepId, updates)` — change one step (prompt, inputs, next, etc.)
274
- - `add_step(workflowId, step, insertAfter?)` — insert a new step
275
- - `remove_step(workflowId, stepId)` — delete a step and re-wire neighbors
276
- - After edits: `validate_workflow` → `publish_workflow` (or `promote_draft` for live workflows)
277
-
278
- ### Editing existing workflows: merge model
279
-
280
- `update_step` accepts three explicit operations on the same call. At least one must be non-empty.
281
-
282
- - **`updates`** — partial step patch, **deep-merged ONE LEVEL deep**. Top-level scalars are replaced; nested objects (e.g. `pipelineStepPrompt`, `stepInputData`) get their direct keys merged with the stored value's keys. Keys nested two levels deep are overwritten as a unit, not merged.
283
- - **`replace: string[]`** — dot-paths whose values from `updates` are assigned **wholesale**, skipping the deep-merge. Use this for **dictionary-shaped fields where keys are user data** (not config) — patching one inner key with `updates` alone silently wipes the others.
284
- - **`unset: string[]`** — dot-paths to delete. Each path must currently exist on the step (validated against the original — you cannot unset something you just created in the same call).
285
-
286
- **Read-before-write for dictionary fields.** Before editing `stepInputData.fieldUpdates`, `pipelineStepPrompt.responseStructure`, `knowledgeSync.fieldMapping`, or any field where keys are user data: call `get_step({ workflowId, stepId })`, modify locally, send the full new object back via `replace[]`. Cheap (~1KB) and avoids the "patched one key, silently wiped the others" trap.
287
-
288
- **Diff in the response.** Every `update_step` returns `diff: { addedPaths, changedPaths, removedPaths }` and `warnings[]`. If the merge silently removed ≥6 fields without an explicit `unset`, a warning fires. Read it.
289
-
290
- #### What to use where
291
-
292
- | Path / field | API | How to edit | Notes |
293
- |---|---|---|---|
294
- | `name`, `goal`, `description`, `pipelineStepPrompt.template`, `creditCost` | `update_step` | `updates` | Plain scalar; safe to send alone. |
295
- | `next`, `loopConfig`, `entryConditions` (full block) | `update_step` | `updates` | Direct nested config; sending the new value wholesale is fine — these are config, not user-data dictionaries. |
296
- | `tools`, `integrations` | `update_step` | `updates` | Arrays are replaced wholesale by design. To append, fetch with `get_step`, splice locally, send the full new array. |
297
- | `stepInputData.fieldUpdates` (kg.update-rows / kg.upsert-rows) | `update_step` | `get_step` → `updates` (full dict) + `replace: ["stepInputData.fieldUpdates"]` | Keys are user data; default one-level merge replaces this dict and can drop sibling mappings. |
298
- | `pipelineStepPrompt.responseStructure` | `update_step` | `get_step` → `updates` (full struct) + `replace: ["pipelineStepPrompt.responseStructure"]` | Output-shape dictionary; treat as user data. |
299
- | `knowledgeSync.fieldMapping` | `update_step` | `get_step` → `updates` (full mapping) + `replace: ["knowledgeSync.fieldMapping"]` | Source→target dict; same trap as `fieldUpdates`. |
300
- | `renderer.config` (when preserving sibling keys matters) | `update_step` | `updates` (full `renderer.config`) + `replace: ["renderer.config"]` | ⚠ `replace: ["renderer.config.layout"]` does NOT protect `renderer.config`'s siblings — the one-level deep-merge runs first on `updates.renderer`. Replace at the parent level. |
301
- | `entryConditions.criteria` (when preserving the rest of `entryConditions`) | `update_step` | `updates: { entryConditions: {...full block...} }` | Send the full `entryConditions` block; one-level merge already does the right thing for direct children. |
302
- | Removing a step input or stale field | `update_step` | `unset: ["stepInputData.oldKey"]` | Cleanest way to remove. Path must exist on the original. |
303
- | `context.inputPages`, `context.outputPages`, `context.executionInputConfig` | `update_workflow_context` | Three explicit verbs (`updates` / `replace` / `unset`) on workflow-relative paths, OR legacy `{ contextKey, value }` for wholesale per-key replacement | **Workflow-level, not step-level.** `update_step` cannot reach `context.*`. See workflow-level merge model below. |
304
- | `metadata` | `update_workflow_context` | Same three verbs on `metadata.*` paths; one-level shallow-merge under `updates.metadata` | Workflow-level. Metadata edits bypass the draft snapshot (write direct to Pipeline row even on live workflows). |
305
-
306
- **Type changes.** `step.type` is technically mutable but stale type-specific fields (`pipelineStepPrompt`, `app`, `tools`, `orchestratorConfig`) persist unless you `unset` them. For clean conversions, prefer `remove_step` + `add_step`. If editing in place, list the incompatible fields under `unset`.
307
-
308
- **Live workflows.** Edits are routed to a draft snapshot. Response includes `editingDraft: true`. Inspect via `get_draft`, ship via `promote_draft`, throw away via `discard_draft`. For high-stakes edits, `create_snapshot` first as a manual checkpoint.
309
-
310
- **Draft staleness.** When a draft already exists, every `update_step` / `get_step` response carries a `draft` summary:
311
-
312
- ```jsonc
313
- "draft": {
314
- "exists": true,
315
- "draftCreatedAt": "...",
316
- "liveUpdatedAt": "...",
317
- "stale": true, // live advanced past draft.createdAt
318
- "modifiedStepIds": ["step-x"], // step IDs whose JSON differs between draft and live
319
- "modifiedFields": ["steps"] // top-level config keys that differ
320
- }
321
- ```
322
-
323
- If `draft.stale === true`, the live workflow has been touched (template upgrade, UI edit, deploy) since the draft was forked. Promoting the draft will land its values for fields you didn't touch in this session — those values may be older than current live. Recovery: `discard_draft` and re-apply your edit, or call `get_draft` to inspect what's pending. The `update_step` response also pushes a staleness string into `warnings[]`.
324
-
325
- **Never** send a full `steps[]` array via `update_workflow`. Use `update_step`, `add_step`, `remove_step` instead.
326
-
327
- #### Workflow-level merge model (`update_workflow_context`)
328
-
329
- `update_workflow_context` is the workflow-level analog of `update_step` — same three verbs, but on **workflow-relative paths** (`context.executionInputConfig.fields`, `metadata.tags`, …). Step-relative paths like `pipelineStepPrompt.template` are rejected here, and conversely `update_step` rejects `context.*` / `metadata.*` paths. The boundary is hard.
228
+ > **Editing an existing or live workflow?** The per-step merge model (`update_step` / `update_workflow_context`, the read-before-write rule for dictionary fields, drafts and staleness) is its own topic — read `references/editing-workflows.md` before touching a live workflow.
330
229
 
331
- Allowed path prefixes for `replace[]` / `unset[]`:
332
-
333
- - `context.inputPages`
334
- - `context.outputPages`
335
- - `context.executionInputConfig`
336
- - `metadata`
337
-
338
- Out-of-scope paths (e.g. `steps`, `name`) → `PATH_OUT_OF_SCOPE` (400). Other typed errors mirror `update_step`: `EMPTY_PAYLOAD`, `INVALID_PATH`, `REPLACE_VALUE_MISSING`, `UNSET_PATH_NOT_FOUND`. The response includes `diff: { addedPaths, changedPaths, removedPaths }` and `warnings[]` (≥6 silent removals fires the warning).
339
-
340
- Recipes:
341
-
342
- ```jsonc
343
- // Flip executionInputConfig.internal — same merge-order trap as update_step.
344
- // Fetch (get_workflow), merge locally, replace at the parent level:
345
- {
346
- "updates": { "context": { "executionInputConfig": {...full merged executionInputConfig with internal: true...} } },
347
- "replace": ["context.executionInputConfig"]
348
- }
349
-
350
- // Replace inputPages wholesale:
351
- {
352
- "updates": { "context": { "inputPages": [...new pages...] } },
353
- "replace": ["context.inputPages"]
354
- }
355
-
356
- // Add a metadata tag (one-level shallow-merge — siblings preserved):
357
- { "updates": { "metadata": { "tags": ["beta"] } } }
358
-
359
- // Delete an obsolete metadata key:
360
- { "unset": ["metadata.legacyFlag"] }
361
- ```
362
-
363
- Live workflows: context edits route to the draft snapshot. Metadata is NOT part of the snapshot config — it always writes direct to the Pipeline row, immediately and on the live workflow.
364
-
365
- ⚠ **Mixed metadata + context in one call** is the sharp edge: metadata is applied immediately while context becomes pending in the draft. `discard_draft` reverts the pending context changes but **does NOT revert metadata** — metadata never went to the draft. If you need a single atomic checkpoint covering both, `create_snapshot` first or split the call into two.
366
-
367
- A legacy `{ contextKey, value }` body shape is still accepted as a **compatibility shape** for one-shot wholesale replacement of a single root context key. It can't edit metadata, doesn't return `diff` / `warnings`, and is not the recommended path for new code — prefer the three-verb shape above.
368
-
369
- ### Post-authoring
370
-
371
- 6. Test: `start_workflow` with sample input
372
- 7. Check results: `get_execution` to see step outputs
373
-
374
- ## Workspace Surfaces
230
+ ## Business metrics vs ROI (must not be conflated)
375
231
 
376
- The workspace home and sidebar carry workspace-level UI state on `Workspace.metadata`. These surfaces are read-only via the MCP today (most tooling does not need to write them), but agents authoring templated workspaces should know they exist:
232
+ Treat these as **two separate surfaces**:
377
233
 
378
- ### Pinned outputs (sidebar shortcuts)
234
+ - **Business metrics (`pipeline.analyticsConfig`)** = customer/workflow outcome stats extracted from step outputs (volume, conversions, approvals, rates, SLA-ish KPIs), aggregated into dashboard business-metric snapshots.
235
+ - **ROI (`pipeline.metadata.roi`)** = economic assumptions + rollups (minutes saved per unit, hourly rate, benchmark units/week, measured vs benchmark mode) used for ROI/time-saved reporting.
379
236
 
380
- `Workspace.metadata.pinnedOutputs[]` lists output pages that appear in the sidebar **after Knowledge & Data**, always visible regardless of which workflow is currently open. Operators set these manually from each output page's configuration sheet (toggle: *"Pin to workspace home"*). Pin sparingly: only pin output pages that are useful as direct workspace-level destinations, such as a recurring report, scoring dashboard, or canonical results list. Do not pin every output page, implementation detail, approval surface, or one-off execution artifact; normal workflow output pages remain accessible from the workflow itself. Each entry:
237
+ **Required wording for agent outputs:**
238
+ - If only `analyticsConfig` changes: say **"business metrics configured"**.
239
+ - If only `metadata.roi` changes: say **"ROI assumptions configured"**.
240
+ - If both change: report each section separately; never label analytics metrics as ROI metrics.
381
241
 
382
- ```json
383
- {
384
- "pipelineId": "wfl_abc123",
385
- "pipelinePathname": "deal-flow",
386
- "outputPagePathname": "weekly-report",
387
- "label": "Weekly Investor Report",
388
- "iconName": "FileText",
389
- "pipelineName": "Deal Sourcing",
390
- "colorTextClass": "text-emerald-700 dark:text-emerald-400",
391
- "pinnedAt": "2026-05-09T10:00:00Z"
392
- }
393
- ```
242
+ This distinction applies to MCP and CLI users equally because both surfaces call the same external workflow API and return the same pipeline shape.
394
243
 
395
- All snapshot fields capture the source values at pin time and do not auto-update if the workflow or page is later renamed or restyled. To refresh, the operator unpins and re-pins.
244
+ ## Platform capabilities (background)
396
245
 
397
- Sidebar rendering uses each field directly:
398
- - `label` is the primary line.
399
- - `pipelineName` renders in small muted text below the label, so two pins with the same `label` from different workflows are distinguishable.
400
- - `iconName` resolves to a lucide icon (defaults to `Pin` if missing or unknown).
401
- - `colorTextClass` is applied as a Tailwind class on the icon, mirroring the source workflow's accent. Use the same shape produced by the workflow style picker (e.g. `text-emerald-700 dark:text-emerald-400`).
402
- - The pin row renders as **active** when the operator's current URL matches the pin's target.
246
+ Agentled provides caching per step, automatic retry with backoff, a persistent Knowledge Graph, scoped permissions, and a unified credit system across 100+ integrations. For the full rationale, see `WHY-AGENTLED.md` (in this skill folder).
403
247
 
404
- When seeding a workspace via templates, pre-populate `pinnedOutputs[]` only for the curated artifacts the operator should access directly from the workspace sidebar on day one. Supply `pipelineName` and `colorTextClass` for the proper rendering (otherwise they fall back to the muted default, which still works but loses the visual cue). Pin entries reference output pages that exist on workflows in the same workspace; entries pointing at deleted or renamed pipelines still render — the URL just resolves to a 404 page until the pin is removed.
248
+ **Practical implication:** "retry failed enrichment" and "avoid re-fetching already processed companies" are platform features. Use `retry_execution` to resume from a failed step; per-step caching is automatic. For cross-run row dedup, use `kg.upsert-rows` with a `userKey`.
405
249
 
406
250
  ## Workspace Awareness
407
251
 
408
252
  Be explicit about which Agentled workspace you are operating on.
409
253
 
410
254
  - When multiple Agentled MCP servers are registered, use the server-specific namespace directly instead of assuming a default.
411
- - When using the standalone CLI, remember it can store multiple saved workspace profiles.
412
- - Check the active CLI workspace with `agentled auth current`.
413
- - Switch the saved CLI target with `agentled auth use <workspace>`.
414
- - Override a single CLI command with `agentled --workspace <workspace> ...` or `AGENTLED_WORKSPACE=<workspace> ...`.
255
+ - The standalone CLI can store multiple saved workspace profiles. Check the active one with `agentled auth current`; switch with `agentled auth use <workspace>`; override a single command with `agentled --workspace <workspace> ...` or `AGENTLED_WORKSPACE=<workspace> ...`.
415
256
  - Before making destructive or customer-visible changes, confirm the target workspace via `get_workspace` or `agentled auth current`.
416
257
 
417
- ## Local Workspace Folder — `agentled_<workspace-slug>/`
418
-
419
- When working on Agentled tasks for a user (sourcing kits, workflow design, debugging executions, anything that spans more than a single tool call), **organize all local artifacts under a per-workspace folder named `agentled_<workspace-slug>/`** in the user's current working directory. The slug comes from the active workspace alias (e.g. `agentled_acme/`, `agentled_my-company/`) so a user with multiple workspaces never mixes their data. Resolve the slug from `agentled auth current` (use the alias if set, otherwise the workspace ID). Create the folder on first use; never scatter notes, JSON drafts, or transcripts at the repo root or under a generic `agentled_workspace/` name.
420
-
421
- **Required structure (replace `<slug>` with the actual workspace slug):**
422
-
423
- ```
424
- agentled_<slug>/
425
- README.md # what this folder is, current active workspace, last sync to KG
426
- decisions/ # one file per non-trivial decision (theme, schema, source list, etc.)
427
- YYYY-MM-DD-<slug>.md # context · options considered · decision · rationale · revisit-when
428
- workflows/ # local drafts and copies of pipeline JSON before push
429
- <workflow-id>.json # snapshot of the live workflow (use get_workflow → write file)
430
- <slug>.draft.json # work-in-progress before create_workflow
431
- groups/ # WorkflowGroup specs (see WG-001) — one file per group
432
- <group-slug>.kit.json
433
- kg/ # local mirrors / drafts of KG content
434
- lists/<listKey>.schema.json
435
- text/<key>.md # workspace company profile, theme docs, etc., before upserting
436
- executions/ # debug bundles for failed runs
437
- <executionId>/timeline.json, step-outputs/, notes.md
438
- worklog.md # append-only chronological log of what was done, in 1-2 lines per entry
439
- ```
440
-
441
- **Why a local folder at all when the KG already stores state?**
442
- - KG is *workspace truth* — durable, structured, queryable. The local folder is *agent scratch* — drafts, decision rationale, raw debug data, transcripts. Mixing them pollutes the KG and loses local iteration history.
443
- - Decisions ("we chose theme X for next edition", "we picked OpenVC + Crunchbase as initial sources") need a paper trail with reasoning. KG entries should carry the *outcome*, not the deliberation.
444
- - Workflow drafts often go through 3-5 iterations before push — keep them local until ready.
445
-
446
- **Sync rule:** at the end of any meaningful working session — and explicitly when the user says "save", "wrap up", "we're done for now" — summarize what's *durable and reusable* (final decisions, current themes, active sources, workflow purpose statements) and write it to the workspace KG via `upsert_knowledge_text` (for narrative docs) or `upsert_knowledge_rows` (for structured data). Use stable, predictable keys: `decisions.current-theme`, `groups.<slug>.spec`, `workflows.<id>.purpose`. For any group of workflows that forms a client-facing workspace pipeline, also create or update a client-readable KG text guide such as `<workspace-or-pipeline>.design`, `groups.<slug>.guide`, or `pipelines.<slug>.design`. Put the client explanation first (what it does, how it works, where data comes from, how approvals/sync/reporting work), then put workflow IDs, caveats, and debug details under "Operator Notes." Append a one-line entry to `worklog.md` recording what was synced and when.
447
-
448
- **Don't sync:** raw debug bundles, full execution timelines, abandoned drafts, transcripts. Those stay local. Sync only what a future session — or another agent — will actually need to pick up the work.
449
-
450
- **On session start:** if `agentled_<slug>/` for the active workspace already exists, read `README.md` and the most recent `decisions/` and `worklog.md` entries before proposing anything new. If it doesn't exist, ask the user once whether they want you to create it for this project, then proceed. If the user has multiple workspaces, only act on the folder matching the currently active workspace from `agentled auth current` — never operate on a sibling folder.
451
-
452
- ## Pipeline Structure
453
-
454
- Every workflow needs at minimum: a trigger step, one or more action steps, and a milestone (terminal) step. Steps are connected via `next: { stepId: "..." }`.
455
-
456
- ```json
457
- {
458
- "name": "My Workflow",
459
- "goal": "What this workflow achieves",
460
- "steps": [
461
- { "id": "trigger", "type": "trigger", "name": "Start", "pipelineStepStartConditions": { "trigger": { "type": "manual" } }, "next": { "stepId": "action" } },
462
- { "id": "action", "type": "aiAction", "name": "Analyze", "pipelineStepPrompt": { "template": "...", "responseStructure": {} }, "creditCost": 10, "next": { "stepId": "done" } },
463
- { "id": "done", "type": "milestone", "name": "Complete" }
464
- ],
465
- "context": {
466
- "executionInputConfig": {
467
- "title": "Run Workflow",
468
- "fields": [{ "name": "input_field", "label": "Input", "type": "text", "required": true }]
469
- }
470
- }
471
- }
472
- ```
473
-
474
- ## Step Types
475
-
476
- ### Trigger
477
- ```json
478
- { "id": "trigger", "type": "trigger", "name": "Start", "pipelineStepStartConditions": { "trigger": { "type": "manual" } }, "next": { "stepId": "next-step" } }
479
- ```
480
-
481
- `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.
482
-
483
- ### App Action
484
- ```json
485
- {
486
- "id": "enrich",
487
- "type": "appAction",
488
- "name": "Enrich Company",
489
- "app": { "id": "agentled", "actionId": "agentled.get-linkedin-company-from-url", "source": "native" },
490
- "stepInputData": { "profileUrls": "{{input.company_url}}" },
491
- "next": { "stepId": "next-step" }
492
- }
493
- ```
494
-
495
- ### AI Action
496
- ```json
497
- {
498
- "id": "analyze",
499
- "type": "aiAction",
500
- "name": "Analyze",
501
- "pipelineStepPrompt": {
502
- "template": "Analyze this company: {{steps.enrich.company}}",
503
- "responseStructure": { "score": "number 0-100", "summary": "string" }
504
- },
505
- "creditCost": 10,
506
- "next": { "stepId": "next-step" }
507
- }
508
- ```
509
-
510
- ### AI Step Model & Provider Configuration
511
-
512
- AI steps can optionally specify a model and provider via the `agent` field:
513
-
514
- ```json
515
- {
516
- "id": "analyze",
517
- "type": "aiAction",
518
- "agent": { "model": "claude-4-6-sonnet", "provider": "anthropic" },
519
- "pipelineStepPrompt": { "template": "...", "responseStructure": {} },
520
- "creditCost": 10,
521
- "next": { "stepId": "next-step" }
522
- }
523
- ```
524
-
525
- **Supported Providers:** `openai`, `anthropic`, `google`, `mistral`, `deepseek`, `kimi`, `minimax`, `bytedance`, `perplexity`, `xai`
526
-
527
- **Supported Models by Provider:**
528
-
529
- | Provider | Models |
530
- |----------|--------|
531
- | `openai` | `gpt-5-nano`, `gpt-5-mini`, `gpt-5.4`, `o4-mini`, `o3`, `o3-pro`, `o3-deep-research` |
532
- | `anthropic` | `claude-4-6-sonnet`, `claude-4-5-haiku`, `claude-4-6-opus` |
533
- | `google` | `gemini-3-pro`, `gemini-3-flash`, `gemini-2.5-pro`, `gemini-2.5-flash` |
534
- | `mistral` | `mistral-large-latest`, `mistral-small-latest`, `codestral-latest` |
535
- | `deepseek` | `deepseek-chat`, `deepseek-reasoner` |
536
- | `kimi` | `kimi-k2.5` |
537
- | `minimax` | `minimax-m2.5` |
538
- | `bytedance` | `doubao-seed-1.6-flash`, `seed-2.0-mini`, `doubao-seed-1.8-beta` |
539
- | `perplexity` | `sonar-pro`, `sonar`, `sonar-reasoning-pro`, `sonar-reasoning` |
540
- | `xai` | `grok-4.3`, `grok-3-mini` |
541
-
542
- > **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.
543
-
544
- ### Code Step
545
- ```json
546
- {
547
- "id": "transform",
548
- "type": "code",
549
- "name": "Transform Data",
550
- "codeConfig": { "language": "javascript", "code": "const data = {{steps.prev.output}};\nreturn data.map(x => x.name);" },
551
- "next": { "stepId": "next-step" }
552
- }
553
- ```
554
-
555
- ### Milestone (terminal)
556
- ```json
557
- { "id": "done", "type": "milestone", "name": "Complete" }
558
- ```
559
-
560
- ## Template Variables
561
-
562
- | Pattern | Description |
563
- |---------|-------------|
564
- | `{{input.fieldName}}` | Input page field value |
565
- | `{{steps.stepId.field}}` | Previous step output |
566
- | `{{currentItem}}` | Current item in a loop |
567
- | `{{currentItem.field}}` | Nested field in loop item |
568
-
569
- ## Loop Configuration
570
-
571
- To iterate over a list from a previous step:
572
- ```json
573
- {
574
- "loopConfig": { "enabled": true, "field": "{{steps.prev.items}}", "ItemAlias": "currentItem" }
575
- }
576
- ```
577
-
578
- ## Entry Conditions
579
-
580
- Skip or stop a step based on prior output:
581
- ```json
582
- {
583
- "entryConditions": {
584
- "onCriteriaFail": "skip",
585
- "conditionText": "Skip if no URL",
586
- "criteria": [{ "variable": "{{input.url}}", "operator": "isNotNull" }]
587
- }
588
- }
589
- ```
590
-
591
- Operators: `==`, `!=`, `>`, `<`, `isNull`, `isNotNull`, `contains`.
592
-
593
- **Important**: Use `criteria` (not `conditions`) and `variable` (not `field`).
594
-
595
- ## Email Workflow Conventions
596
-
597
- ### Trigger choice: polling vs event
598
-
599
- **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.
600
-
601
- | User asks for | Trigger |
602
- |---------------|---------|
603
- | "process inbound emails", "triage daily", "review pitches" | **Schedule** (polling) |
604
- | "as soon as", "real-time", "within X seconds/minutes" | **App event** |
605
-
606
- ### Canonical email polling pattern
607
-
608
- ```
609
- schedule trigger → GMAIL_FETCH_EMAILS (-label:processed newer_than:1d) → loop: [process] → GMAIL_ADD_LABEL (mark processed) → milestone
610
- ```
611
-
612
- Step order:
613
- 1. **`GMAIL_CREATE_LABEL`** — create/get the `processed` label (idempotent, returns label ID)
614
- 2. **`GMAIL_FETCH_EMAILS`** — query `-label:processed newer_than:1d` (or wider window as needed)
615
- 3. **Loop** — process each email (AI analysis, KG storage, enrichment, etc.)
616
- 4. **`GMAIL_ADD_LABEL`** — apply `{{steps.ensure-label.id}}` to mark email done (dedup gate)
617
-
618
- ### Label ID rule (prevents `400: Invalid label`)
619
-
620
- Gmail requires **label IDs** (e.g., `Label_3456789012345`), not display names (e.g., `"processed"` or `"agentled"`).
621
-
622
- **Always resolve via `GMAIL_CREATE_LABEL`** and reference its returned `id`:
623
- ```json
624
- { "stepInputData": { "label_id": "{{steps.ensure-label.id}}" } }
625
- ```
626
- Never pass a string label name directly to `GMAIL_ADD_LABEL`.
627
-
628
- See `docs/workflows/triggers.md` for the full decision framework, query examples, and common mistakes.
629
-
630
- ---
631
-
632
- ## Email Step Pattern (AI Draft → Approve → Send)
633
-
634
- 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.
635
-
636
- ### 1. Outreach Profile Input Page
637
-
638
- When a workflow sends emails, add an outreach profile input page to `context.inputPages` so the user can configure sender identity:
639
-
640
- ```json
641
- {
642
- "title": "Outreach Profile",
643
- "pathname": "outreach-profile",
644
- "configuration": {
645
- "contextKey": "outreachProfile",
646
- "shortDescriptionFields": ["name", "fromEmail"],
647
- "fields": [
648
- { "name": "name", "label": "Sender Name", "type": "text", "required": true },
649
- { "name": "fromEmailLabel", "label": "From Name", "type": "text", "required": true },
650
- { "name": "fromEmail", "label": "From Email", "type": "connected_emails_selector_multiple", "required": true },
651
- { "name": "replyToEmail", "label": "Reply-To Email (optional)", "type": "text" }
652
- ]
653
- }
654
- }
655
- ```
656
-
657
- ### 2. Composed Email Step
658
-
659
- ```json
660
- {
661
- "id": "send_email",
662
- "type": "aiAction",
663
- "name": "Send Email",
664
- "pipelineStepPrompt": {
665
- "type": "email",
666
- "template": "Draft a personalized email...\n{{steps.previous_step.data}}\nReturn JSON ONLY per schema.",
667
- "responseStructure": {
668
- "email": {
669
- "from": "{{context.outreachProfile.fromEmail}}",
670
- "to": "recipient@example.com",
671
- "subject": "Email subject line",
672
- "body": "Email body (email-safe HTML)",
673
- "bodyType": "html"
674
- }
675
- },
676
- "responseType": "json"
677
- },
678
- "renderer": {
679
- "type": "Email",
680
- "config": { "fromContextKey": "outreachProfile" }
681
- },
682
- "onApproval": {
683
- "action": "schedule-email",
684
- "executedText": "Email sent by {{name}} at {{date}}",
685
- "scheduledText": "Email scheduled to be sent for {{date}} by {{name}}",
686
- "failedText": "Email failed to send."
687
- },
688
- "integrations": [{
689
- "type": "oneOf",
690
- "label": "Email",
691
- "connectorType": "email",
692
- "options": [
693
- { "name": "Gmail", "url": "https://gmail.com", "isUserAccountConnectionRequired": true },
694
- { "name": "Outlook", "url": "https://outlook.com", "isUserAccountConnectionRequired": true }
695
- ],
696
- "selectionHint": "preferConnected"
697
- }],
698
- "creditCost": 10,
699
- "next": { "conditions": { "approvalRequired": true } }
700
- }
701
- ```
702
-
703
- ### Key Requirements
704
-
705
- - **Always** include `outreachProfile` input page when using email
706
- - `pipelineStepPrompt.type: "email"` — tells the system this is an email step
707
- - `renderer.config.fromContextKey: "outreachProfile"` — links renderer to sender profile
708
- - `onApproval.action: "schedule-email"` — triggers the actual send; without it, approval does nothing
709
- - `next.conditions.approvalRequired: true` — blocks the pipeline until human approval
710
- - Email body must be email-safe HTML (`<p>`, `<br>`, `<a>`, `<strong>` — no CSS, no scripts)
711
- - **Never** use separate "draft" + "gmail send" appAction steps for outreach
712
- - Set an output page `displayConfig.executionNameTemplate` that names the entity and the outreach state. For single-entity outreach, use `{{entityName}} - Email Drafted` before approval and `{{entityName}} - Email Sent` or `{{entityName}} - Contacted` after the post-send status step, e.g. `Joe Dan - VC Firm Name - Email Drafted`; add `{{today}}` only when a short date helps. For batch runs, summarize counts instead, e.g. `26 May - 4 sourced - 3 contacted`.
713
-
714
- ## Entity Pipeline Pattern (Source → KG → Process)
715
-
716
- When a user asks about **finding leads, sourcing companies, collecting contacts, or discovering any entities they want to act on later**, propose this two-workflow architecture instead of a single monolithic workflow.
717
-
718
- ### Why
719
-
720
- Sourcing and processing have different cadences and costs. Decoupling them lets you:
721
- - Source from many places (LinkedIn, web scrape, Crunchbase, email, webhooks) into one canonical list
722
- - Process (enrich, score, outreach) only new entities, on a schedule, without re-processing already-handled ones
723
- - Retry or re-run either phase independently without touching the other
724
-
725
- ### Workflow 1 — Sourcing (runs on trigger or schedule)
726
-
727
- Finds entities from one or more sources and writes them into a shared KG list with `status: "new"`. Uses `kg.upsert-rows` with a caller-supplied `userKey` on each row so re-runs dedup (O(1), no table scan).
728
-
729
- ```json
730
- // Step: write sourced entities to KG
731
- {
732
- "id": "save-to-kg",
733
- "type": "appAction",
734
- "name": "Save to KG",
735
- "app": { "id": "kg", "actionId": "kg.upsert-rows", "source": "native" },
736
- "stepInputData": {
737
- "listKey": "sourced-startups",
738
- // rows must be [{ userKey, rowData }, ...] — userKey is the dedup contract.
739
- // Use any stable caller-defined id: URL, domain, LinkedIn URL, etc.
740
- "rows": "{{steps.extract.items}}",
741
- "mergeStrategy": "merge", // preserve fields added downstream (scores, notes)
742
- "status": "new"
743
- },
744
- "next": { "stepId": "done" }
745
- }
746
- ```
747
-
748
- **Key rules:**
749
- - Always include a `status` on sourcing writes (default `"new"`) so the processing workflow can filter on it
750
- - Give every row a stable `userKey` (URL, domain, LinkedIn URL — any caller-defined id that won't change). Same `userKey` in the same list = same DynamoDB row, forever
751
- - Use `mergeStrategy: "merge"` so downstream-added fields (scores, status updates) survive re-upserts from the source
752
- - Multiple sourcing workflows can write to the same `listKey` — they converge into one canonical list
753
- - Use `kg.add-rows` only for one-shot, never-re-run writes where duplicates are acceptable
754
-
755
- ### Workflow 2 — Processing (runs on schedule, e.g. weekly)
756
-
757
- Reads only `status: "new"` rows, processes them (enrich, score, outreach, etc.), then updates status to `"processed"` (or `"scored"`, `"outreached"`, etc.) so they're never picked up again.
758
-
759
- ```json
760
- // Step 1: read new entities
761
- {
762
- "id": "read-new",
763
- "type": "appAction",
764
- "name": "Read New Entities",
765
- "app": { "id": "kg", "actionId": "kg.read-list", "source": "native" },
766
- "stepInputData": {
767
- "listKey": "sourced-startups",
768
- "filters": "{\"status\": \"new\"}",
769
- "limit": "50"
770
- },
771
- "next": { "stepId": "process-loop" }
772
- }
773
-
774
- // Step 2: loop → enrich / score / outreach each entity
775
- // ... your enrichment and scoring steps here, using {{currentItem.url}} etc. ...
776
-
777
- // Step N: mark as processed
778
- {
779
- "id": "mark-processed",
780
- "type": "appAction",
781
- "name": "Mark Processed",
782
- "app": { "id": "kg", "actionId": "kg.update-rows", "source": "native" },
783
- "stepInputData": {
784
- "listKey": "sourced-startups",
785
- "rowIds": "{{steps.process-loop.processedIds}}",
786
- "fieldUpdates": "{\"status\": \"processed\"}"
787
- },
788
- "next": { "stepId": "done" }
789
- }
790
- ```
791
-
792
- ### Status values (suggested convention)
793
-
794
- | Value | Meaning |
795
- |-------|---------|
796
- | `new` | Sourced, not yet processed |
797
- | `scored` | Enriched and scored, not yet outreached |
798
- | `outreached` | Outreach sent |
799
- | `rejected` | Filtered out during scoring |
800
- | `processed` | Generic "done" for non-outreach pipelines |
801
-
802
- Use whatever values make sense for the use case — the pattern is the same.
803
-
804
- ### When to propose this pattern
805
-
806
- Suggest it whenever the user says any of:
807
- - "find leads / companies / contacts"
808
- - "source startups / investors / candidates"
809
- - "collect entities from multiple sources"
810
- - "build a list I can act on later"
811
- - "score / enrich / outreach to a list"
812
- - "run this once a week on new items"
813
-
814
- The default answer is **two workflows**: one that sources into KG, one that processes from KG. A single do-everything workflow is only appropriate when the user has a fixed one-shot input and no recurring need.
815
-
816
- ## Top Apps Quick Reference
817
-
818
- | App | Action | Credits | Key Inputs |
819
- |-----|--------|---------|------------|
820
- | `agentled` | `get-linkedin-company-from-url` | 5 | `profileUrls` |
821
- | `agentled` | `get-linkedin-profile-from-url` | 2 | `profileUrls` |
822
- | `agentled` | `find-email-person-domain` | 3 | `firstName`, `lastName`, `domain` |
823
- | `hunter` | `find-email-person-domain` | 3 | `firstName`, `lastName`, `domain` |
824
- | `web-scraping` | `scrape` | 0 | `url` |
825
- | `http-request` | `request` | 0 | `url`, `method`, `headers`, `body` |
826
- | `notion` | `get-page-markdown` | 1 | `pageUrl` |
827
- | `browser-use` | `run-task` | 15 | `task`, `startUrl` |
828
- | `agentled` | `call-workflow` | varies | `workflowId`, `input` |
829
-
830
- Use `list_apps` and `get_app_actions` for full schemas of all available apps. Use `list_models` for supported AI model IDs.
831
-
832
- ## Credit-Efficient Testing
833
-
834
- Each execution costs real credits. Follow these rules:
835
-
836
- 1. **One execution at a time** — don't start new ones unnecessarily
837
- 2. **Retry, don't restart** — use `retry_execution` to continue from a failed step instead of starting over
838
- 3. **Test in isolation** — use `test_ai_action`, `test_app_action`, or `test_code_action` to verify steps before wiring them into a workflow
839
- 4. **Reuse prior output** — when testing downstream steps, use output data from a prior successful execution as mock input
840
-
841
- ## Common Validation Errors
842
-
843
- | Error | Fix |
844
- |-------|-----|
845
- | `"references non-existent next step"` | Ensure some step has `next: { stepId: "X" }` pointing to the missing step |
846
- | `"missing prompt template"` | Add `pipelineStepPrompt.template` to AI steps |
847
- | `"Unknown action"` | Verify `actionId` format via `get_app_actions` |
848
- | `"is unreachable"` | Connect every step via `next.stepId` from the trigger chain |
849
- | `"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. |
850
-
851
- ## Persistent Memory
852
-
853
- Workflows can store and recall memories that persist across executions. Two mechanisms:
854
-
855
- ### MCP Tools (for managing memory externally)
856
-
857
- | Tool | Purpose | Key Params |
858
- |------|---------|------------|
859
- | `recall_memory` | Get a specific memory by key | `key`, `scope?`, `workflowId?` |
860
- | `search_memories` | Search by natural language query | `query?`, `category?`, `scope?`, `workflowId?`, `limit?` |
861
- | `store_memory` | Save a persistent memory | `key`, `value`, `category?`, `scope?`, `workflowId?`, `confidence?`, `merge?` |
862
- | `list_memories` | List all memories in a scope | `scope?`, `workflowId?`, `category?`, `limit?` |
863
- | `delete_memory` | Delete a memory by key | `key`, `scope?`, `workflowId?` |
864
-
865
- **Scopes**: `workspace` (shared across all workflows) or `workflow` (scoped to one workflow, default).
866
-
867
- **Categories**: `fact` (known truth), `insight` (pattern/learning), `preference` (user preference), `outcome` (result to track).
868
-
869
- **Merge strategies** (for `store_memory`): `overwrite` (default), `append`, `max`, `min`, `increment`.
870
-
871
- **Confidence**: 0-100. Memories with confidence >= 70 are automatically synced to the Knowledge Graph.
872
-
873
- ### Pipeline Step Configuration (for memory inside workflows)
874
-
875
- #### Auto-extraction (pipeline-level)
876
-
877
- Enable on the pipeline to automatically extract memories after each execution completes:
878
-
879
- ```json
880
- {
881
- "persistentMemoryConfig": {
882
- "autoExtract": true,
883
- "scopes": ["pipeline"],
884
- "categories": ["fact", "insight", "outcome"],
885
- "maxPerExtraction": 10,
886
- "extractionModelTier": "mini"
887
- }
888
- }
889
- ```
890
-
891
- #### Explicit per-step writes
892
-
893
- Configure specific steps to write memories from their output:
894
-
895
- ```json
896
- {
897
- "id": "score-company",
898
- "type": "aiAction",
899
- "persistentMemory": {
900
- "writes": [
901
- {
902
- "key": "score_{{input.company_name}}",
903
- "valuePath": "total_score",
904
- "category": "outcome",
905
- "scope": "pipeline",
906
- "confidence": 85
907
- }
908
- ]
909
- }
910
- }
911
- ```
912
-
913
- The `valuePath` extracts from the step's output using dot notation. The `key` supports template variables.
914
-
915
- #### Builtin tool for AI steps (`workspace_memory`)
916
-
917
- AI steps with type `aiActionWithTools` can use the `workspace_memory` builtin tool to read/write memory during execution:
918
-
919
- ```json
920
- {
921
- "id": "analyze",
922
- "type": "aiActionWithTools",
923
- "name": "Analyze with Memory",
924
- "tools": [{ "builtinType": "workspace_memory" }],
925
- "pipelineStepPrompt": {
926
- "template": "Recall what we know about this company, then analyze...",
927
- "responseStructure": { "analysis": "string" }
928
- },
929
- "creditCost": 10,
930
- "next": { "stepId": "done" }
931
- }
932
- ```
933
-
934
- 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.).
935
-
936
- ### Memory Patterns
937
-
938
- **1. Learning workflow** — accumulates knowledge over repeated runs:
939
- ```
940
- trigger → enrich → AI analyze (with workspace_memory tool) → milestone
941
- ```
942
- The AI step recalls prior scores, compares trends, and stores updated insights.
943
-
944
- **2. Explicit score tracking** — saves structured data for cross-run comparison:
945
- ```
946
- trigger → score company → [persistentMemory.writes: score_{{company}}] → milestone
947
- ```
948
-
949
- **3. Workspace-wide preferences** — store ICP criteria, outreach templates, or scoring weights shared across workflows:
950
- ```
951
- store_memory(key: "target_icp", value: { industry: "SaaS", minEmployees: 50 }, scope: "workspace", category: "preference")
952
- ```
258
+ For organizing local artifacts (drafts, decisions, debug bundles) under a per-workspace folder, see `references/workspace-folder.md`.
953
259
 
954
260
  ## Conversational Building
955
261