@agentled/cli
Version:
CLI for Agentled — manage workflows, apps, and knowledge from the command line. Zero context-window cost for AI agents.
478 lines (363 loc) • 32.1 kB
Markdown
---
name: agentled
version: 0.7.2
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.
user-invocable: false
---
# Agentled Workflow Automation
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.
This file is a **router**. It carries the always-needed core (orientation, the
closed list of step types, the invalid-pattern guards, the build loop). The deep
reference material lives in `references/` and the tactical playbooks in the
pattern library — load them on demand rather than reading everything up front.
## Reference index — load on demand
When a task matches a row below, read that file before authoring. Don't preload
them; that defeats the point.
| When you're… | Read |
|--------------|------|
| Writing any step's JSON (field shapes, model IDs, loop/entry-condition syntax) | `references/step-schemas.md` (or `get_step_schema`) |
| Editing an existing/live workflow (merge model, `update_step` / `update_workflow_context`, drafts) | `references/editing-workflows.md` |
| Building anything that reads or sends email | `references/email-workflows.md` |
| Configuring a provider write, its approval flow, or a provider status receipt | `docs/PROVIDER_WRITE_POLICY.md` |
| Sourcing/collecting entities to act on later | `references/entity-pipeline.md` |
| Adding cross-execution memory | `references/persistent-memory.md` |
| Designing outbound / sales / investor / lead-gen at scale | `references/outreach-and-scale.md` |
| Designing a saved view of a list, funnel, queue, approvals surface, or multi-source workspace cockpit | `docs/WORKSPACE_VIEWS.md` |
| Producing local artifacts, or seeding a templated workspace's sidebar | `references/workspace-folder.md` |
| Picking apps, testing credit-efficiently, decoding a validation error | `references/credits-apps-and-errors.md` |
Tactical, shape-specific playbooks (triggers, dedup, loops, routing, reports,
workflow groups, …) live in the **pattern library** — list with
`agentled examples` and print one with `agentled examples <name>`. The
"which pattern to read" table is below under *Before you build*.
## Goal and bottleneck first
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.
**Two common failure modes:**
- Building a full operating system when the user needed one workflow (wrong scope).
- Optimizing for theme curation or content quality when the bottleneck is paid conversion or reply handling (wrong objective).
**The design loop:**
1. Orient — inspect the workspace (identity, KG lists, connected apps, existing workflows, existing agents).
2. Infer — determine the likely goal and bottleneck from workspace context.
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).
4. Brief — produce a short build brief (goal, assumptions, assets to reuse, KG lists, workflow group, risks, cost hotspots, build order).
5. Build — create workflows incrementally from the brief.
> For multi-workflow systems, produce a group manifest before touching live workflow state. See `agentled group-manifest --help` and `docs/GROUP_MANIFEST.md`.
## Orient Before Designing
Before helping with any request, inspect the workspace. Use `agentled workspace inspect` (CLI) or call these MCP tools individually:
1. **`get_workspace`** — Confirm workspace identity (name, ID), team members, pending invitations, and knowledge-list schemas.
2. **`get_workspace_company_profile`** — Business context: ICP, industry, target personas, saved preferences that should shape workflow design.
3. **`list_workflows`** — Existing automations: avoid recreating, identify reuse opportunities, note gaps.
4. **`list_knowledge_lists`** — KG lists: contacts, companies, scored leads, status machines. Shapes what a new workflow reads from or writes to.
5. **`list_connections`** — Connected apps and integrations: know which enrichment, CRM, or email providers are already authed before designing steps that depend on them.
6. **`list_agents`** — Existing agents and routines: understand what is already running autonomously before adding new agents.
7. **`list_workspace_views`** — Saved operating surfaces: reuse or update a view before creating another dashboard/list/queue.
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.
When referring to KG lists or text entries in user-facing replies, include both the human-readable name/title and the stable key/id, not just the id. Example: `VC Contacts (gtm_vc_contacts)`.
For existing workflow work, map the workflow back to its use case before making claims or edits: run `agentled workflows get <workflowId> --format json`, inspect `useCaseContext`, then run `agentled use-cases get <key-or-workflowGraphId> --format json` and read each `operatingGuides` knowledge text with the provided read command. If `agentGuidance.warnings` includes `MISSING_USE_CASE_OPERATING_GUIDE`, say the use-case README is missing and create/update the linked knowledge text before treating the context as complete.
When the use case has `config.onboardingGoal`, inspect and mutate its typed
contract through the dedicated surface:
| Operation | CLI | MCP |
|---|---|---|
| Read normalized goal + live safeguards | `agentled use-cases goal get <id>` | `get_use_case_goal({ id })` |
| Set desired policy | `agentled use-cases goal set-policy <id> --requirement <reqId> --desired <automatic\|approval_required\|disabled> [--confirm]` | `set_use_case_goal_policy({ id, requirementId, desired, confirm? })` |
| Add enforcement pointer | `agentled use-cases goal bind <id> --requirement <reqId> --kind <kind> <kind flags>` | `bind_use_case_goal_requirement({ id, requirementId, binding })` |
| Remove enforcement pointer | `agentled use-cases goal unbind <id> --requirement <reqId> --kind <kind> <kind flags> [--confirm]` | `unbind_use_case_goal_requirement({ id, requirementId, binding, confirm? })` |
| Set declared finish line | `agentled use-cases goal set-finish-line <id> --milestone <find\|qualify\|prepare\|operate>` | `set_use_case_goal_finish_line({ id, milestone })` |
| Set Goal Brief pointer | `agentled use-cases goal set-goal-brief <id> --key <knowledgeTextKey>` | `set_use_case_goal_brief({ id, goalBriefKey })` |
| Bind skill reference | `agentled use-cases goal bind-skill <id> --skill-id <skillId> --agent-id <agentId> --role <role>` | `bind_use_case_goal_skill({ id, binding })` |
| Remove skill reference | `agentled use-cases goal unbind-skill <id> --skill-id <skillId> --agent-id <agentId>` | `unbind_use_case_goal_skill({ id, skillId, agentId })` |
| Set primary CRM reference | `agentled use-cases goal set-primary-crm <id> --app-id <appId> --label <label>` | `set_use_case_goal_primary_crm({ id, appId, label })` |
Binding kinds and flags are: `workflow-step` with `--workflow-id` and
`--step-id`; `agent-action` with `--agent-id`, `--app-id`, and `--action-id`;
`workspace-channel` with `--channel <email|linkedin|whatsapp>`; and
`routine-action` with `--routine-id`, `--app-id`, and `--action-id`. MCP passes
the same fields inside `binding`.
Never patch `config.onboardingGoal.approvalRequirements` through raw
`use-cases update` / `update_use_case`; the server rejects it so all typed
writes reuse the Safeguards UI validator. Weakening a `send`, `write`, or
`delete` policy, or unbinding one of its paths, requires CLI `--confirm` or MCP
`confirm: true`. Every successful
mutation returns an actor-attributed audit ID. Goal mutations change desired
config only: they do not change live enforcement, decide approvals, advance
runtime evidence, run workflows/routines, call providers, spend credits, send
messages, or write CRM data. Re-read the goal afterward and trust
`approvalResolutions`, not desired policy text, for effective enforcement.
Setting the Goal Brief changes only its Knowledge Text pointer. Skill bindings
do not assign skills or grant tools/app permissions, and the primary CRM
reference does not connect credentials or write CRM data.
> **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.
### Workspace views
When the user asks for a reusable view of a KG list, funnel, action queue,
approval inbox, workflow report, agent/routine state, or combined operating
surface, use `WorkspaceView`. It is a saved manifest over live workspace data,
not a KG-only report and not an action executor.
- Inspect existing views first: `list_workspace_views` or `agentled views list`.
- Create/update only the manifest: data sources, filters/transforms,
`ConfigLayout` layout, actions, refresh/safety metadata.
- Use `name` for the full view page title and `navLabel` for short sidebar
copy. Use `placement` to attach pinned views to a use case or workflow group.
- Creating a view must not read providers, run workflows, mutate KG rows, send
messages, make approval decisions, or spend credits.
- Mark write/send/destructive actions with `approvalRequired: true` and use the
normal approval-aware tool when the user later asks to execute them.
- Prefer `draft` unless the user clearly approved the view becoming active or
pinned.
### MCP-connected but no local scaffold: expected behavior
If MCP tools are already connected and working, **do not block** on missing local folders.
- Continue with MCP operations immediately.
- 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).`
- Do **not** imply setup is required for read/write API operations through MCP.
`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.
### CLI freshness
Use the latest `@agentled/cli` for setup, local scaffolds, fixtures, tests, and
builder-work CLI commands. Prefer `npx -y @agentled/cli@latest ...` for one-off
setup commands. If using a global `agentled` install, run `agentled --version`
or any CLI command and follow the update notice when it reports a newer version.
Do not block a working MCP-only task just because the local CLI is absent or old.
Only update/install the CLI when the task needs CLI-backed setup, local files,
fixtures, tests, or builder-work commands.
### Tool discovery and multi-workspace use
Codex does not always preload the full Agentled MCP surface. If a tool seems
"missing", search for the exact tool name before assuming the server or plugin
is missing it. Common examples:
- `get_knowledge_rows`
- `get_knowledge_rows_by_ids`
- `query_kg_edges`
When this repo is used against multiple workspaces, prefer the
workspace-specific MCP namespace for live work, for example
`mcp__agentled_angelhive.*`, instead of relying on the generic `mcp__agentled`
namespace.
The generic stdio MCP server follows the CLI's active workspace from
`~/.agentled/config.json`, and the current MCP session may cache that client.
If you switch with `agentled auth use <workspace>`, reconnect or restart the AI
client before expecting `mcp__agentled.*` to point at the new workspace.
For CLI commands, make workspace targeting explicit when needed:
```bash
agentled auth current
agentled auth use angelhive
agentled --workspace angelhive workspace inspect
AGENTLED_WORKSPACE=angelhive agentled workflows list
```
### CLI chat workflow handoffs
The web UI can call `monitorWorkflowExecution`, poll the resulting job, and
continue the assistant turn after the workflow becomes terminal. A CLI agent
must perform that continuation itself.
If `agentled chat` or `agentled chat-result` says a workflow was started, do
not treat the completed chat turn as the completed user request. Capture the
returned `sessionId`, `workflowId`, `executionId` or `executionInputId`, then:
1. Resolve the execution with `agentled executions list <workflowId>` when
necessary.
2. Poll `agentled executions get <workflowId> <executionId>` until `completed`,
`failed`, `stopped`, or `canceled`.
3. Inspect the relevant output using `agentled executions step-output`.
4. Continue the original conversation with `agentled chat --session-id
<sessionId> "...terminal result context..."` so the assistant reports the
verified result and does not restart the workflow.
Never resend the original request while its durable chat turn or workflow is
still running. A response such as `Run started` is a workflow handoff, not the
final answer.
### External builder setup
When this session is acting as an external AI builder for Agentled work items,
register or refresh the builder identity before listing, claiming, or submitting
builder work. This links the current API key to a visible builder profile in
Developer settings and lets business agents attribute work correctly.
- If MCP is available, call `upsert_ai_builder_profile` once per API key with
the provider (`codex`, `claude`, `openclaw`, `herms`, or `custom`), a clear
display name, and optional metadata such as capabilities or setup state.
- If only shell/CLI access is available, run:
```bash
agentled builders profile upsert --provider codex --name "Codex"
```
After the profile exists, use `list_builder_work_items` / `agentled builders
work-items list` according to the polling cadence in the MCP tool description.
If a builder-work command returns `Call upsert_ai_builder_profile...`, do that
setup step and retry; do not ask the user to create the profile manually.
### First-run setup: choose the target AI client
When helping a user connect Agentled to a specific AI client, tell the CLI which
client to configure. Do this even if auto-detection would probably work; many
developer machines have several clients installed and the wrong MCP config can
be updated.
Use the matching command:
```bash
npx -y @agentled/cli setup --mcp-client codex
npx -y @agentled/cli setup --mcp-client claude-code
npx -y @agentled/cli setup --mcp-client cursor
npx -y @agentled/cli setup --mcp-client windsurf
npx -y @agentled/cli setup --mcp-client claude-desktop
```
OpenClaw and Hermes are skill-install targets, not MCP auto-config targets yet.
For those clients, authenticate once, install the matching skill bundle, then
configure MCP in the client's native MCP settings:
```bash
npx -y @agentled/cli auth login
npx -y @agentled/cli skills install --target openclaw
npx -y @agentled/cli skills install --target hermes
```
For workspace switching or failed browser auth recovery, add `--reauth`, for
example:
```bash
npx -y @agentled/cli setup --reauth --mcp-client codex
```
After successful setup, restart or reconnect the AI client so it launches a new
Agentled MCP server process with the new credentials. If the browser step fails,
record whether the failing page is `https://www.agentled.app/en/cli/authorize...`
or `http://127.0.0.1:<port>/callback...`; those indicate different failure
surfaces.
## Valid step types (closed list)
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`.
<!-- agentled-step-types:start -->
| `type` | Purpose | Minimal shape |
|--------|---------|---------------|
| `trigger` | Entry point (manual / schedule / webhook / app event) | `{ id, type: "trigger", name, pipelineStepStartConditions: { trigger: { type: "manual" } }, next: { stepId } }` |
| `appAction` | Call an app/integration action (LinkedIn, Gmail, KG, HTTP, …) | `{ id, type: "appAction", name, app: { id, actionId, source: "native" }, stepInputData: {…}, next: { stepId } }` |
| `aiAction` | LLM prompt → structured JSON output | `{ id, type: "aiAction", name, pipelineStepPrompt: { template, responseStructure }, creditCost, next: { stepId } }` |
| `aiActionWithTools` | LLM agent that can invoke runtime tools (web_search, workspace_memory, app actions) | `{ id, type: "aiActionWithTools", name, tools: [{ builtinType }], pipelineStepPrompt: {…}, next: { stepId } }` |
| `toolAction` | Direct tool/webhook invocation (no LLM) | `{ id, type: "toolAction", name, tool: {…}, next: { stepId } }` |
| `code` | Run JS/Python in a sandbox | `{ id, type: "code", name, codeConfig: { language: "javascript", code: "…", responseStructure?: { field: "type" } }, next: { stepId } }` |
| `setVariables` | Deterministic expression → named output mapping (branch convergence, no LLM/credits) | `{ id, type: "setVariables", name, setVariablesConfig: { variables: [{ name, expression }] }, next: { stepId } }` |
| `knowledgeSync` | Deterministic KG field mapping & link writing | `{ id, type: "knowledgeSync", name, knowledgeSync: { source, listKey, fieldMapping }, next: { stepId } }` |
| `return` | Terminal step for **child** workflows — returns data to the caller | `{ id, type: "return", name, returnConfig: { fields: [{ name, stepId, field }] } }` |
| `milestone` | Terminal step for **top-level** workflows | `{ id, type: "milestone", name }` |
| `share` | Create a public share URL for prior step output | `{ id, type: "share", name, shareConfig: { outputSteps, visibility }, next: { stepId } }` |
| `wait` | Delay / pause between steps | `{ id, type: "wait", name, waitConfig: { durationMs } | { untilISO }, next: { stepId } }` |
| `branch` | Conditional routing to one of several paths | `{ id, type: "branch", name, branchConfig: { branches: [...] }, next: [...] }` |
| `parallel` | Fan-out to parallel branches | `{ id, type: "parallel", name, parallelConfig: { branches: [...] }, next: { stepId } }` |
| `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 } }` |
| `end_if` | Conditional gate that stops the pipeline when criteria fail | `{ id, type: "end_if", name, entryConditions: {…} }` |
| `agentOrchestrator` | Multi-agent orchestration (supervisor / debate / parallel) | `{ id, type: "agentOrchestrator", name, orchestratorConfig: {…}, next: { stepId } }` |
| `manualAction` | Legacy — kept for backward compatibility; prefer `aiAction` or `appAction` | |
| `systemAction` | Legacy — kept for backward compatibility; prefer `appAction` | |
<!-- agentled-step-types:end -->
> 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`.
## Before you build: read the schema and the patterns
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`.
**Via MCP (in-session):**
- `get_step_schema` — authoritative list of valid fields per step type.
- `list_apps` / `get_app_actions` — exact `app.id` + `actionId` values and their input schemas.
**Via CLI (shell access):**
```
agentled schema --step-type aiAction # fields valid on an aiAction step
agentled schema --context # valid input-page / context field types (MCP-029)
agentled tools builtins # valid aiActionWithTools builtinType values (MCP-030)
agentled examples # list all patterns
agentled examples trigger-design # print the full pattern
agentled workflows scaffold --list # list working pipeline skeletons
agentled workflows scaffold lead-scoring-kg --out pipeline.json
agentled workflows scaffold ai-with-tools --out pipeline.json # aiActionWithTools starter
agentled workflows validate --file pipeline.json # fast client-side preflight (no API)
agentled workflows create --file pipeline.json # full server validation on save
agentled best-practices # summary + link to agentic-ops repo
```
> **Silent-strip failures caught by preflight:** invalid `type` on a context / input-page field (e.g. `"multi-select"`, `"checkbox"`, `"number"`) and invalid `builtinType` on an `aiActionWithTools` tool (e.g. `"web-search"`, `"memory"`) both get silently stripped by the runtime — `workflows validate` now flags them with a "did you mean" fix.
### Prompt caching for repeated AI steps
Provider prompt caching reduces cost/latency by reusing the identical prompt prefix; it does not cache or replay the AI answer. For high-volume `aiAction`, `aiActionWithTools`, and looped AI steps, put stable role, task, rubric, examples, output schema, and formatting rules before the first `{{...}}` variable.
Use this layout:
```text
[stable role and task]
[stable rubric / scoring dimensions]
[stable output JSON schema]
[stable examples or decision rules]
Runtime inputs:
{{currentItem}}
{{steps.previous.output}}
{{input.field}}
```
Avoid starting prompts with `INPUTS`, `{{currentItem}}`, `{{steps.*}}`, `{{input.*}}`, `{{execution.id}}`, `{{now}}`, or `{{today}}`. In batch workflows like investor matching, keep the long scoring rubric first and put the startup/investor payload at the end so OpenAI/Anthropic can cache the shared prefix.
**Which pattern to read, by task:**
| You're building… | Read pattern | Scaffold |
|------------------|--------------|----------|
| Anything triggered by email, schedule, webhook, or app event | `01-trigger-design` (polling vs events) | `email-polling-dedup` |
| Any email/intake workflow that must not double-process | `02-dedup-gates` (label-based idempotency) | `email-polling-dedup` |
| A workflow that calls LLMs, scraping, or paid app actions | `03-credit-efficiency` (caching, retry, mocks) | — |
| Anything using `loopConfig` or iterating a list | `04-loop-patterns` | `lead-scoring-kg` |
| A child workflow called via `call-workflow` | `05-child-workflow-contracts` (use `return`, not `milestone`) | — |
| Multi-path routing by score / category / condition | `06-conditional-routing` (`entryConditions.criteria`, not `conditions`) | `extract-threshold-alert` |
| Anything that can fail on upstream provider errors | `07-error-handling` (`failureHandling`, retries) | — |
| **Outreach** — personalized email with user approval | `08-composed-email-approval` (outreachProfile + `pipelineStepPrompt.type: "email"` + `schedule-email`) | `list-match-email` |
| **Report / dashboard** — structured output + sharing + KPI history | `09-reports-and-knowledge-storage` (Config renderer + share step + `knowledgeSync`) | `lead-scoring-kg`, `extract-threshold-alert` |
| **Multi-workflow system** — workflows sharing KG state and status transitions | `12-event-driven-workflow-groups` (group manifest, state machines, build order) | — |
| **Entity pipeline group** — sourcing → score/qualify → find contact → outreach → scheduled orchestrator | `13-entity-pipeline-lifecycle` | `source-from-platform`, `lead-scoring-kg`, `list-match-email`, `funnel-orchestrator` |
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.
For delegated agent approval on outreach, use the composed email approval pattern plus
`approvalPolicy.mode: "agent-delegated"` and read `docs/DELEGATED_APPROVAL.md` in the main
repo before editing. The draft step must emit top-level `recipient.email` and
`delegatedApprovalReview.reviewerAgentEntityId` with the literal AgentEntity id. Daily caps,
first-human gates, deterministic audit sampling, and the `disabled` kill switch are enforced
by the runtime; sampled or capped drafts stay pending for human review.
## Common invalid patterns to avoid
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:
| ❌ Wrong | ✅ Right | Why |
|---------|---------|-----|
| `type: "ai"` | `type: "aiAction"` | There is no generic `ai` type. Use `aiAction` for LLM prompts, `aiActionWithTools` for agentic steps. |
| `type: "integration"` | `type: "appAction"` | Integrations are app actions. Set `app: { id, actionId }` to pick the integration. |
| `type: "conditional_integration"` | `type: "appAction"` + `entryConditions` | Conditions are configured per-step via `entryConditions`, not a separate type. |
| `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`). |
| `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. |
### Top-level fields that are silently stripped
Unknown fields at the step root are dropped. The most common mistakes (put them inside the right sub-object instead):
| ❌ At step root | ✅ Correct location |
|----------------|--------------------|
| `prompt: "…"` | `pipelineStepPrompt.template` |
| `responseStructure: {…}` | `pipelineStepPrompt.responseStructure` |
| `appId: "gmail"`, `actionId: "send"` | `app: { id: "gmail", actionId: "send", source: "native" }` |
| `listKey: "leads"` | `knowledgeSync.listKey` (for `knowledgeSync` steps) or inside `stepInputData` (for `kg` app actions) |
| `channel: "#alerts"`, `webhookUrl: "…"` | `stepInputData.channel`, `stepInputData.webhookUrl` on an `appAction` |
| `condition: "…"` | `entryConditions: { criteria: [{ variable, operator, value }] }` |
| `triggerType: "manual"` (on a `trigger` step) | `pipelineStepStartConditions: { trigger: { type: "manual" } }` |
| `note: "…"` | Step `description`, or a comment in the pipeline JSON (not persisted) |
| `enabled: false` | `entryConditions.onCriteriaFail: "skip"` with a falsy criterion, or remove the step |
> 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**.
## Incremental Authoring (recommended)
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.
### Via MCP tools
```
create_workflow({ name, goal }) → empty shell, returns workflowId
add_step({ workflowId, step: { type: "trigger", ... } }) → returns validation per-step
add_step({ workflowId, step: { type: "aiAction", ... }, insertAfter: "trigger-id" })
→ validates template variables, model IDs, app action inputs immediately
... repeat for each step ...
validate_workflow(workflowId) → full graph-level check (reachability, cycles)
publish_workflow(workflowId, "live")
```
### Via CLI
```bash
agentled wf create --pipeline '{"name":"My Workflow","goal":"..."}' --skip-validate
# → returns workflowId (no steps yet)
agentled wf add-step <wfId> --step '{"id":"start","type":"trigger","name":"Start",...}'
# → returns per-step validation
agentled wf add-step <wfId> --insert-after start --rewire-next \
--step '{"id":"extract","type":"aiAction","name":"Extract",...}'
# → bad variable refs, wrong model ID, or unknown app action caught HERE
# ... repeat ...
agentled wf validate <wfId> # full graph check
agentled wf publish <wfId> --status live
```
### Why not bulk JSON?
The full-pipeline `steps` array on `create_workflow` / `update_workflow` is supported for **imports, templates, and export→edit→re-import round-trips**. Agents authoring from scratch should not use it:
- No per-step feedback — a bad `type`, model ID, or variable ref on step 2 cascades into 10+ errors on steps 3-8.
- No variable discovery — `{{input.X}}` vs `{{steps.trigger-id.X}}` is a common agent mistake that only surfaces after the full blob is submitted.
- Agents invent step types (`"ai"`, `"integration"`, `"knowledge_graph_query"`) that are silently accepted but never execute.
Internal testing: **0 errors with incremental vs 13 errors with bulk JSON** on the same pipeline.
> **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.
## Business metrics vs ROI (must not be conflated)
Treat these as **two separate surfaces**:
- **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.
- **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.
**Required wording for agent outputs:**
- If only `analyticsConfig` changes: say **"business metrics configured"**.
- If only `metadata.roi` changes: say **"ROI assumptions configured"**.
- If both change: report each section separately; never label analytics metrics as ROI metrics.
This distinction applies to MCP and CLI users equally because both surfaces call the same external workflow API and return the same pipeline shape.
## Platform Skills And Guarantees (background)
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).
**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`.
## Workspace Awareness
Be explicit about which Agentled workspace you are operating on.
- When multiple Agentled MCP servers are registered, use the server-specific namespace directly instead of assuming a default.
- 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> ...`.
- Before making destructive or customer-visible changes, confirm the target workspace via `get_workspace` or `agentled auth current`.
For organizing local artifacts (drafts, decisions, debug bundles) under a per-workspace folder, see `references/workspace-folder.md`.
## Conversational Building
For complex workflows, use the `chat` tool to design workflows through natural language conversation. It supports multi-turn via `session_id`.
```
chat("Build a workflow that takes a LinkedIn URL, enriches the company, finds decision-maker emails, and scores by ICP fit")
```