UNPKG

@agentled/cli

Version:

CLI for Agentled — manage workflows, apps, and knowledge from the command line. Zero context-window cost for AI agents.

31 lines (30 loc) 23 kB
/** * Bundled docs written into `~/.agentled/docs/` on `agentled setup` runs. * * Embedded as string constants so they ship with the CLI release (same * pattern as GOTCHAS.md in workspace-folder.ts). * * **`docs/` is CLI-managed.** Treat the bundled files as read-only — they * are unconditionally rewritten when `HOME_CONTENT_VERSION` advances * past the on-disk marker. Anyone who wants to edit local notes should * put them in `~/.agentled/docs/local/` (never touched by the bootstrap) * or in the per-workspace `agentled_<slug>/` folder. * * `HOME_CONTENT_VERSION` is intentionally **decoupled from the CLI * package version** — it is an opaque integer that bumps only when one * of the constants below changes. A CLI patch bump that touches no doc * content does not refresh `~/.agentled/`. */ /** * Bump this every time any HOME_README_MD / WORKFLOW_SHAPE_MD / * GETTING_STARTED_MD / GOTCHAS_MD / PATTERNS_MD constant changes. * * Do NOT pin to the CLI semver — that bumps for unrelated reasons and * causes spurious doc rewrites on every patch release. */ export declare const HOME_CONTENT_VERSION = "3"; export declare const HOME_README_MD = "# AgentLed\n\nYou've installed the AgentLed CLI. Your AI agent (Claude Code, Codex, Cursor, Claude Desktop, Windsurf) can now build and run workflows for you.\n\n## Talk to your agent\n\nOnce `agentled setup` is done and you've restarted your MCP client, just describe what you want. The agent has access to AgentLed's MCP tools, your workspace's knowledge graph, and 100+ integrations.\n\nTry one:\n- \"Source fintech CTOs in Europe via search and LinkedIn, score by ICP fit, email me the top 10 daily.\"\n- \"Qualify inbound form submissions and route the high-score ones to a Slack channel.\"\n- \"Pull competitor pricing pages weekly, summarize changes, send a diff report.\"\n\n## What lives here\n\n- `config.json` \u2014 saved workspace profiles (managed by `agentled auth`).\n- `docs/` \u2014 brief design guide your agent reads on session start. **CLI-managed: treat as read-only.** Files here are rewritten when the bundled doc version advances.\n- `docs/local/` \u2014 your own notes. **Never overwritten by the CLI.** Put any edits or additions here.\n- `examples/scaffolds/` \u2014 preflight-clean pipeline templates your agent adapts to your intent. Also CLI-managed.\n\nPer-workspace artifacts (logs, dryruns, decisions, drafts) live in `agentled_<workspace-slug>/` in your project directory \u2014 one folder per workspace.\n\n## CLI commands\n\n```\nagentled --help # list commands\nagentled auth current # active workspace\nagentled workflows list # workflows in your workspace\nagentled examples # browse pattern templates\n```\n\n## Open patterns reference\n\nFor extended workflow patterns and anti-patterns beyond the bundled scaffolds, see the public agentic-ops repo: https://github.com/Agentled/agentic-ops. Optional reading \u2014 the bundled `docs/` and `examples/scaffolds/` are sufficient for first-workflow building.\n"; export declare const WORKFLOW_SHAPE_MD = "# Workflow shape \u2014 source \u2192 list \u2192 orchestrator \u2192 outreach\n\nThe canonical AgentLed workflow shape, optimized for re-runnable, dedup-safe pipelines.\n\n## The list is the spine\n\nA KG list (e.g. `kg.list.leads`) holds every entity your business cares about. Multiple sourcing workflows write into the same list. One orchestrator workflow reads from it, processes, and transitions row state.\n\nTwo indexes make this efficient:\n\n1. **`userKey`** \u2014 caller-supplied dedup index. Use a stable identifier per row (domain, LinkedIn URL, email hash). `kg.upsert-rows` with the same `userKey` writes to the same row, every time, forever. No table scan, no duplicate explosion.\n2. **`status`** \u2014 the queue marker. New rows start at `status: \"new\"`. The orchestrator filters by status, processes only rows in the relevant state, and transitions status as it goes (`scored`, `qualified`, `contacted`, `rejected`).\n\n## Sourcing workflows (1+)\n\nEach sourcing workflow has one job: find entities, write them with a `userKey` and `status: \"new\"`. Use `mergeStrategy: \"merge\"` so downstream-added fields (scores, notes) survive a re-source. Many sourcing workflows can write to the same list.\n\n```json\n{\n \"id\": \"save-to-list\",\n \"type\": \"appAction\",\n \"app\": { \"id\": \"kg\", \"actionId\": \"kg.upsert-rows\", \"source\": \"native\" },\n \"stepInputData\": {\n \"listKey\": \"leads\",\n \"rows\": \"{{steps.extract.items}}\",\n \"mergeStrategy\": \"merge\",\n \"status\": \"new\"\n }\n}\n```\n\n> Note: pass `rows` directly as the template variable \u2014 do NOT wrap it in `JSON.stringify` or quote-escape the array. The serializer inlines the raw value (see GOTCHAS.md #12). The `filters` field on `kg.read-list` (below) is the exception \u2014 it expects a JSON-string body, not an array, so the escaped object literal is correct there.\n\n## Orchestrator workflow (1)\n\nSchedule trigger \u2192 `kg.read-list` filtered by `status: \"new\"` \u2192 loop \u2192 score / qualify / route \u2192 `kg.update-rows` to transition status.\n\n```json\n// Step 1: read pending rows\n{\n \"id\": \"read-pending\",\n \"type\": \"appAction\",\n \"app\": { \"id\": \"kg\", \"actionId\": \"kg.read-list\", \"source\": \"native\" },\n \"stepInputData\": { \"listKey\": \"leads\", \"filters\": \"{\\\"status\\\": \\\"new\\\"}\", \"limit\": \"50\" }\n}\n\n// Step N: transition status\n{\n \"id\": \"mark-scored\",\n \"type\": \"appAction\",\n \"app\": { \"id\": \"kg\", \"actionId\": \"kg.update-rows\", \"source\": \"native\" },\n \"stepInputData\": {\n \"listKey\": \"leads\",\n \"rowIds\": \"{{steps.score.processedIds}}\",\n \"fieldUpdates\": \"{\\\"status\\\": \\\"scored\\\"}\"\n }\n}\n```\n\n## Outreach workflow (1, optional)\n\nOften folded into the orchestrator. When separate: schedule trigger \u2192 `kg.read-list` filtered by `status: \"qualified\"` \u2192 compose email (with approval gate) \u2192 `schedule-email` \u2192 mark `status: \"contacted\"`.\n\nWhy separate: outreach has different cadence (e.g. daily, batch-limited) than scoring (continuous), and you may want different approval gates per channel.\n\n## Status conventions\n\n| Value | Meaning |\n|-------|---------|\n| `new` | Sourced, not yet processed |\n| `scored` | Enriched + scored, awaiting routing |\n| `qualified` | Passes ICP / threshold, ready for outreach |\n| `rejected` | Failed scoring criteria |\n| `contacted` | Outreach sent |\n| `replied` | Reply received (set by an inbound workflow) |\n\nUse whatever values fit your domain. The pattern is: sourcing always sets one status, the orchestrator transitions through \u22651 status, reads always filter by status.\n\n## Why the spine matters\n\n- Multiple sourcing channels converge \u2014 one canonical list, no fan-out logic in each producer.\n- Re-running a source is idempotent \u2014 `userKey` dedup.\n- Re-running the orchestrator is idempotent \u2014 status filter excludes done rows.\n- Each phase has its own cadence \u2014 sourcing daily, orchestrator hourly, outreach business hours.\n- Failures are scoped \u2014 a bad source doesn't pollute scoring; a bad scorer doesn't break sourcing.\n\n## Pausing for human input \u2014 decouple via the list\n\nWhen a workflow needs human input partway through (e.g., \"meeting done, capture the outcome and transcript URL, then continue scoring\"), **don't try to pause inside one workflow**. Split it across the KG list spine \u2014 same shape as everything else.\n\n```\nWorkflow A (the producer)\n \u2026 reaches the point that needs human input \u2026\n \u2192 kg.update-rows: status = \"needs-meeting-outcome\"\n \u2192 milestone (A is done; row sits in the list)\n\nWorkflow B (user-triggered, manual)\n \u2192 trigger: manual, with input page asking for:\n - meeting_outcome (text)\n - transcript_url (url)\n \u2192 kg.update-rows: status = \"input-received\", fieldUpdates = { outcome, transcript }\n \u2192 milestone\n\nWorkflow C (the consumer, scheduled)\n \u2192 kg.read-list filtered by status = \"input-received\"\n \u2192 \u2026 continue scoring / qualifying using outcome + transcript \u2026\n \u2192 kg.update-rows: status = \"scored\"\n```\n\nWhy decouple:\n- Each workflow has its own cadence and trigger \u2014 the producer runs on schedule, the user-triggered B runs whenever the user has the data, the consumer runs on schedule. None blocks the other.\n- The KG row carries the state. If the user fills in the form a week later, it just works \u2014 nothing was hanging in memory waiting.\n- A new agent (or a teammate) can act on rows in any state at any time \u2014 the substrate is shared.\n- You can have multiple producers, multiple human-input forms (different roles, different channels), and one consumer. Or any other shape that fits.\n\nIn-workflow pause-with-input is possible in some cases via `milestone` with a configured input page, but the AgentLed-native approach for human-in-the-loop is the decoupled pattern above. Reach for it first.\n\n## Where to put what\n\n| You want to\u2026 | Use |\n|--------------|-----|\n| Capture per-execution input from a user | `context.inputPages` on the workflow |\n| Capture per-execution input from a public form / unauthed user | a workflow with a public form trigger and a public-form share configuration |\n| Reference workspace-wide context (ICP, tone, products, brand voice) | `knowledge.* text` (read via `kg.read-text`, written via `kg.upsert-text`) \u2014 shared across workflows and agents |\n| Hand a result back to the user as a viewable report | `aiAction` (structured output) \u2192 renderer config on that step \u2192 `share` step (creates URL) \u2192 email notification with the URL |\n| Pause one workflow until a human provides extra data | Split into two workflows + a status transition on the KG row (see \"Pausing for human input\" above) |\n| Track business value once a workflow is validated | `metadata.roi` + `eventSummary` per run + an `entryConditions` gate that skips the run when inputs wouldn't move the needle |\n\n### Report-and-share-back sequence\n\nThe canonical \"give me a report and email me a link\" sequence:\n\n```json\n// Step 1: aiAction with structured output the renderer can read\n{\n \"id\": \"compose-report\",\n \"type\": \"aiAction\",\n \"pipelineStepPrompt\": {\n \"template\": \"\u2026 build the report here \u2026\",\n \"responseStructure\": { \"title\": \"string\", \"sections\": [{ \"heading\": \"string\", \"body\": \"string\" }] }\n },\n \"renderer\": { \"type\": \"Config\", \"config\": { \"layout\": \"report\" } },\n \"creditCost\": 20,\n \"next\": { \"stepId\": \"make-share\" }\n}\n\n// Step 2: share step \u2192 mints a public URL pointing at compose-report's output\n{\n \"id\": \"make-share\",\n \"type\": \"share\",\n \"shareConfig\": { \"outputSteps\": [\"compose-report\"], \"visibility\": \"link\" },\n \"next\": { \"stepId\": \"notify\" }\n}\n\n// Step 3: email notification with the share URL inlined\n{\n \"id\": \"notify\",\n \"type\": \"aiAction\",\n \"pipelineStepPrompt\": {\n \"type\": \"email\",\n \"template\": \"Draft a 2-line email letting the user know their report is ready. Include the link.\",\n \"responseStructure\": {\n \"email\": {\n \"from\": \"{{context.outreachProfile.fromEmail}}\",\n \"to\": \"{{input.recipient_email}}\",\n \"subject\": \"Your report is ready\",\n \"body\": \"<p>Your report: <a href=\\\"{{steps.make-share.url}}\\\">view it here</a>.</p>\",\n \"bodyType\": \"html\"\n }\n }\n },\n \"onApproval\": { \"action\": \"schedule-email\" },\n \"next\": { \"stepId\": \"done\" }\n}\n```\n\n### Public input pattern\n\nFor workflows triggered by user-submitted forms (no auth required), use a public-form trigger and a share configuration that exposes the form at a stable slug. The form's submission payload becomes the workflow input. Same workflow shape applies; only the trigger differs.\n\n### Post-validation: ROI + business metrics\n\nOnce a workflow is validated and running:\n\n1. **ROI tracking** \u2014 add an `metadata.roi` block with hours saved per run, dollar value, conversion lift. Surfaces in the workflow header and the workspace metrics dashboard.\n2. **Per-run `eventSummary`** \u2014 emit a small structured log: count processed, count qualified, total credits, success rate. Powers the metrics dashboard and lets agents reason about workflow health from the KG.\n3. **`entryConditions` gate** \u2014 skip the run when its inputs wouldn't actually move the needle (e.g., `kg.read-list` returned 0 new rows, or upstream signal is below threshold). Avoids credit waste on no-op runs and produces cleaner ROI numbers.\n\nFull pattern reference (step types, schemas, all gotchas) is in the AgentLed skill loaded into your AI agent on session start.\n"; export declare const GETTING_STARTED_MD = "# Your first end-to-end workflow\n\nFive minutes from \"I have an idea\" to \"my agent built it\".\n\n## 1. Describe intent in one sentence\n\nGood prompts look like:\n\n- \"Source 50 fintech startups in Europe via search, write them to a leads list, score by ICP fit, and email me the top 10 weekly.\"\n- \"When a form is submitted, qualify against my ICP knowledge and post the high-score ones to #sales-qualified in Slack.\"\n\nBad prompts look like:\n\n- \"Build me a CRM.\" (Too broad \u2014 the agent doesn't know what to start with.)\n- \"Use aiAction with workspace_memory tool.\" (Too prescriptive \u2014 you're authoring the pipeline, not the agent.)\n\n## 2. Let the agent orient\n\nThe agent will run `workspace inspect` (or the equivalent MCP tools) to look at:\n\n- Your existing KG lists (so it can reuse rather than create duplicates).\n- Connected apps (LinkedIn, Hunter, Gmail, Slack \u2014 only what's authed will work).\n- Existing workflows (it won't recreate one you already have).\n- Existing agents and routines.\n\nThis usually triggers 1-3 short questions back. Answer them and move on.\n\n## 3. Build incrementally\n\nThe agent will start from a scaffold (one of `~/.agentled/examples/scaffolds/*.json`), adapt it to your intent, and add steps one at a time. Per-step validation catches type mismatches, bad model IDs, and template-variable typos before the full workflow is saved.\n\nDo not ask the agent to dump a 30-step JSON in one shot. The skill explains why.\n\n## 4. Validate, then run small\n\n```\nagentled workflows validate <workflowId> # graph-level checks\nagentled workflows lint <file.json> # static gotcha catches\n```\n\nFirst execution: feed it 3-5 sample inputs, not 500. Watch the credit count. If something is wrong, fix it cheap.\n\n## 5. Promote to production\n\n```\nagentled workflows publish <workflowId> --status live\n```\n\nThen schedule it (or trigger it manually, or wire it to a webhook). Iterate.\n\n## What good looks like\n\n- Sourcing on its own schedule, writing to a list with `userKey` dedup.\n- An orchestrator that filters by `status` so it never re-processes done rows.\n- Every branch terminates (`milestone` for top-level workflows, `return` for child workflows, or no `next.stepId`). `milestone` is a labeled endpoint, not a required step \u2014 a workflow with no `next` is already terminal.\n- Human-in-the-loop steps decoupled across workflows via the KG list (see WORKFLOW-SHAPE.md \"Pausing for human input\").\n- An outreach step (or workflow) gated on approval before sending.\n- ROI metadata + `eventSummary` + an `entryConditions` gate \u2014 added once the workflow is validated.\n\nFor the canonical shape and the \"where to put what\" reference, see `WORKFLOW-SHAPE.md` in this folder. For silent failure modes see `GOTCHAS.md`.\n"; export declare const GOTCHAS_MD = "# AgentLed \u2014 documented silent failure modes\n\nThese pass JSON syntax validation but silently misbehave at runtime.\nRun `agentled workflows lint <file>` to catch them statically before deploying.\n\n---\n\n## 1. `criteria` not `conditions` in entryConditions\n\n**Wrong:** `{ \"entryConditions\": { \"conditions\": [...] } }`\n**Correct:** `{ \"entryConditions\": { \"criteria\": [...] } }`\n\nThe executor reads `entryConditions.criteria`. The key `conditions` is silently ignored.\n\n## 2. `variable` not `field` in criteria items\n\n**Wrong:** `{ \"field\": \"{{steps.x.score}}\", \"operator\": \">\", \"value\": 70 }`\n**Correct:** `{ \"variable\": \"{{steps.x.score}}\", \"operator\": \">\", \"value\": 70 }`\n\nUsing `field` causes the criterion to be silently skipped.\n\n## 3. Gmail label_id must be the internal Label_XXXX ID\n\nGmail's API requires `Label_XXXXXXXXXX` IDs, not display names. Add a `GMAIL_CREATE_LABEL` step before and use `{{steps.ensure-label.id}}`.\n\n## 4. `aiActionWithTools` with no tools\n\nA step with `type: \"aiActionWithTools\"` must have at least one tool in `step.tools` or `step.agent.tools`. Valid `builtinType` values: `web_search`, `file_search`, `code_interpreter`, `fetch_website_content`, `kg_search`, `kg_traverse`, `kg_nodes`, `kg_write`, `workspace_memory`.\n\n## 5. Email steps need type + approval action + outreachProfile\n\nThree required pieces:\n- `pipelineStepPrompt.type: \"email\"`\n- `onApproval.action: \"schedule-email\"`\n- `outreachProfile` input page in `context.inputPages`\n\nMissing the schedule-email action means the email is drafted but never sent.\n\n## 6. Only the first step in a loop gets `loopConfig`\n\n`loopConfig` must be on the first step in the loop chain only. Subsequent steps inside the loop iterate automatically.\n\n## 7. Don't pass raw `{{input.*}}` directly to search APIs\n\nAdd an aiAction step before the search that generates optimized queries. Raw user input makes poor search queries.\n\n## 8. Child workflows use `return`; `internal: true` is for child-only workflows\n\nIf a workflow is called via `agentled.call-workflow` (i.e., a **child workflow** invoked by another workflow rather than a user), use `type: \"return\"` instead of `milestone`. `milestone` produces no return data \u2014 the parent receives nothing.\n\nAlso set `context.executionInputConfig.internal: true` on the **child** workflow \u2014 this hides it from the user-triggered list.\n\n**Top-level workflows** triggered directly by users (manual, schedule, webhook, public form, app event) keep `milestone` and **do NOT** set `internal: true`. Setting `internal: true` on a user-facing workflow hides it from its intended caller.\n\n## 9. Model IDs are internal format, not Anthropic format\n\nWrong: `claude-sonnet-4-6`. Correct: `claude-4-6-sonnet`. Run `agentled models list` for valid internal IDs.\n\n## 10. Native app actionId must include appId prefix\n\nWrong: `{ \"id\": \"kg\", \"actionId\": \"read-list\" }`\nCorrect: `{ \"id\": \"kg\", \"actionId\": \"kg.read-list\" }`\n\n## 11. `loop_completion` criteria requires `onCriteriaFail: \"wait\"`\n\nWithout `onCriteriaFail: \"wait\"`, the step skips instead of blocking until the loop finishes. The `stepId` field is also required.\n\n## 12. Arrays in JSON template strings \u2014 don't JSON.stringify\n\nThe serializer detects when a template variable is the sole content of a JSON field and inlines the raw value. Pass `{ \"items\": \"{{steps.x.items}}\" }` directly \u2014 no stringify needed. (Note: `kg.read-list` `filters` is the exception \u2014 it expects a JSON-string body, see WORKFLOW-SHAPE.md.)\n\n## 13. `kg.upsert-rows` needs `userKey` for dedup; `kg.add-rows` always inserts\n\n`kg.upsert-rows` with `userKey`: same key = same row, cross-run dedup O(1).\n`kg.add-rows`: always inserts a new row, duplicates accumulate.\nUse `mergeStrategy: \"merge\"` to preserve downstream-added fields.\n"; export declare const PATTERNS_MD = "# Pattern index \u2014 `~/.agentled/examples/scaffolds/`\n\nPreflight-clean pipeline templates. Pick the closest match to your intent and adapt \u2014 don't author from scratch.\n\n| Scaffold | Shape | Use when |\n|----------|-------|----------|\n| `minimal.json` | trigger \u2192 milestone | smoke-testing the pipeline runner |\n| `email-polling-dedup.json` | schedule \u2192 fetch emails (label dedup) \u2192 loop \u2192 add label | inbound email triage / processing without double-handling |\n| `source-from-platform.json` | schedule \u2192 source app \u2192 normalize \u2192 `kg.upsert-rows(status:new)` | first stage of a sourcing / lead / candidate funnel |\n| `lead-scoring-kg.json` | trigger \u2192 `kg.read-list` \u2192 AI scoring loop \u2192 `knowledgeSync` | the orchestrator phase of source \u2192 list \u2192 orchestrator |\n| `list-match-email.json` | trigger \u2192 `kg.read-list` \u2192 AI match \u2192 composed email (approval gate) \u2192 `knowledgeSync` | outreach phase: pull qualified rows, draft email, gate on approval |\n| `funnel-orchestrator.json` | schedule \u2192 read KG statuses \u2192 call child workflows \u2192 digest | daily / weekly coordinator after child workflows are validated |\n| `extract-threshold-alert.json` | trigger \u2192 AI extract \u2192 threshold check \u2192 external update \u2192 conditional Slack \u2192 `knowledgeSync` | conditional routing on AI-extracted scores |\n| `ai-with-tools.json` | trigger \u2192 `aiActionWithTools` (web_search + workspace_memory) \u2192 milestone | starter for agentic steps that need to call runtime tools |\n\n## Mapping to the canonical shape\n\nThe `source \u2192 list \u2192 score/qualify \u2192 contact discovery \u2192 outreach \u2192 orchestrator` flow uses these scaffolds in combination:\n\n- **Sourcing** (1+ workflows feeding the same list): start from `source-from-platform` and keep the `kg.upsert-rows` handoff with `userKey`, `mergeStrategy: \"merge\"`, and `status: \"new\"`.\n- **Orchestrator** (reads pending status, processes, transitions): start from `lead-scoring-kg` and add a final `kg.update-rows` step that sets `status: \"scored\"` (or `qualified` / `rejected`).\n- **Outreach** (reads qualified, sends with approval): start from `list-match-email`, then add the `kg.update-rows` to mark `status: \"contacted\"`.\n- **Daily / weekly coordinator** (runs the validated children): start from `funnel-orchestrator` only after the source, scoring, contact, and outreach workflows each work manually.\n- **Reports** (generate output, share, notify): see the \"Report-and-share-back sequence\" section in `WORKFLOW-SHAPE.md` \u2014 `aiAction` \u2192 `share` step \u2192 email notification.\n- **Human-in-the-loop** (workflow needs human input partway through): see \"Pausing for human input\" in `WORKFLOW-SHAPE.md` \u2014 split into producer + manual-trigger input form + consumer, all keyed on a status transition in the KG row.\n\nFor the full pattern shape and why `userKey` + `status` matter as indexes, run `agentled examples 13-entity-pipeline-lifecycle` and see `WORKFLOW-SHAPE.md` in this folder.\n";