@codemation/agent-skills 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @codemation/agent-skills
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#185](https://github.com/MadeRelevant/codemation/pull/185) [`be520d2`](https://github.com/MadeRelevant/codemation/commit/be520d2755144a3709ecc109019b84e2c502337e) Thanks [@cblokland90](https://github.com/cblokland90)! - feat(workspace-files): examples + skill (story 04)
8
+
9
+ Two CI-verified examples for workspace file nodes:
10
+ - node-workspace-files-read.example.ts — read a workspace CSV by filename (latest-wins) + parse
11
+ - concierge-digest-to-workflow.example.ts — concierge digests PDF → workflow reads derived JSON
12
+
13
+ New codemation-workspace-files skill documenting: read-by-filename vs pinned fileId, binary slot
14
+ handoff, read-only boundary, and the raw-upload → concierge-digests → workflow-reads pattern.
15
+
16
+ ### Patch Changes
17
+
18
+ - [#184](https://github.com/MadeRelevant/codemation/pull/184) [`8c5b213`](https://github.com/MadeRelevant/codemation/commit/8c5b213092501bb48aa0c575b0489bbd36b46c79) Thanks [@cblokland90](https://github.com/cblokland90)! - Add `codemation-document-scanner` skill entry covering analyzerType routing table, confidence opt-in (LD6), output shape, and when to choose the managed node vs standalone OCR nodes.
19
+
20
+ ## 0.3.0
21
+
22
+ ### Minor Changes
23
+
24
+ - [#174](https://github.com/MadeRelevant/codemation/pull/174) [`b2c1855`](https://github.com/MadeRelevant/codemation/commit/b2c185525fdbb903a6ad5e756cd180e249c3d6c3) Thanks [@cblokland90](https://github.com/cblokland90)! - feat(metadata): emit skills[] into package metadata — SkillFrontmatterParser reads YAML-frontmatter SKILL.md files and resolves @codemation/\* uses deps to concrete versions via monorepo walk (D8); PackageMetadataExtractor walks skills/ directory; all 8 agent-skills SKILL.md files updated with tags and version-sensitive uses declarations per D7
25
+
26
+ - [#180](https://github.com/MadeRelevant/codemation/pull/180) [`5f28922`](https://github.com/MadeRelevant/codemation/commit/5f289221b35b165f84beb263f823f223b51b3f66) Thanks [@cblokland90](https://github.com/cblokland90)! - Restructure all 8 agent skills to orient+constrain pattern: keep mental model, when-to-use, decision branches, and anti-patterns in the skill body; replace multi-snippet code dumps with a single quickstart + find_examples() pointer to version-matched examples. Total line count reduced from 788 to ~421 (46%). Adds references/anti-patterns.md to codemation-ai-agent-node for version-specific gotchas (managed model id churn, chatModel string shorthand trap).
27
+
28
+ Product-owner steering applied (PR [#180](https://github.com/MadeRelevant/codemation/issues/180)): plugin-development SKILL.md slimmed with managed-mode non-relevance note; plugin anatomy + full definePlugin code moved to references/plugin-anatomy.md. mcp-capabilities adds managed CP-loaded discovery path and non-managed plugin note. ai-agent-node reframes CodemationChatModelConfig as the managed default (LLM broker auto-authenticates via HMAC pairing; no API key needed) and steers away from BYOK for managed users. credential-development adds conceptual test() explanation (what it does, when called, return shape) with pointer to new defineCredential example.
29
+
3
30
  ## 0.2.0
4
31
 
5
32
  ### Minor Changes
@@ -0,0 +1,147 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "packageName": "@codemation/agent-skills",
4
+ "packageVersion": "0.4.0",
5
+ "description": "Reusable agent skills for Codemation projects and plugin development.",
6
+ "kind": "skills",
7
+ "skills": [
8
+ {
9
+ "name": "codemation-ai-agent-node",
10
+ "description": "AIAgent constructor, message shape, managed and BYOK chatModel configs, outputSchema, mcpServers. Read before writing any workflow step that calls an LLM.",
11
+ "tags": [
12
+ "agent",
13
+ "llm",
14
+ "ai"
15
+ ],
16
+ "sourcePath": "skills/codemation-ai-agent-node/SKILL.md",
17
+ "dependencies": {
18
+ "@codemation/core-nodes": "0.10.0"
19
+ },
20
+ "code": "---\nname: codemation-ai-agent-node\ndescription: AIAgent constructor, message shape, managed and BYOK chatModel configs, outputSchema, mcpServers. Read before writing any workflow step that calls an LLM.\ncompatibility: Codemation core-nodes. Requires @codemation/core-nodes import.\ntags: agent, llm, ai\nuses: \"@codemation/core-nodes\"\n---\n\n# Codemation AI Agent Node\n\n## Mental model\n\n`AIAgent` is the single building block for any LLM step in a workflow. It receives items, runs a chat completion per item using the configured model and messages, and emits `{ output: string }` (or a parsed object when `outputSchema` is set) on its `main` port. The `chatModel` field determines whether the run consumes Codemation-managed quota (no credential needed) or a BYOK key the operator supplies. Every AIAgent emits exactly one output item per input item — it never fans out or filters.\n\n## When to use / when NOT\n\nUse `AIAgent` when a workflow step needs an LLM call: classification, extraction, summarisation, drafting, or decision.\nUse a plain `Callback` instead when the logic is deterministic code — no LLM needed.\nUse `mcpServers` (see `codemation-mcp-capabilities`) when the agent needs tool access to external services.\nRead `codemation-workflow-dsl` for the surrounding workflow structure.\n\n## Quickstart\n\n```ts\nimport { AIAgent, CodemationChatModelConfig } from \"@codemation/core-nodes\";\n\nnew AIAgent({\n name: \"Classify email\",\n messages: [\n { role: \"system\", content: \"Classify the email as spam or not-spam.\" },\n { role: \"user\", content: (args) => args.item.json.body as string },\n ],\n chatModel: new CodemationChatModelConfig(\"Claude Haiku\", \"anthropic/claude-haiku-4-5-20251001\"),\n});\n```\n\nFor full patterns — BYOK (`OpenAIChatModelConfig`), `outputSchema`, tools, multi-step pipelines, and gmail classification — use your harness's example-discovery tool: `find_examples({ query: \"AIAgent\" })`.\n\n## Decision branches & gotchas\n\n**Managed mode (default — no API key needed):** use `CodemationChatModelConfig(label, modelId)`. In managed mode the LLM broker **auto-authenticates via the workspace HMAC pairing** — no API key, no credential slot, no user setup required. This is the correct default for all managed-mode workflows. Do NOT tell managed users to \"get an API key\" — the broker handles authentication transparently.\n\n```ts\nchatModel: new CodemationChatModelConfig(\"Claude Haiku\", \"anthropic/claude-haiku-4-5-20251001\");\n// No credential slot created. Discover live model ids:\n// GET <CONTROL_PLANE_URL>/api/llm/managed-models\n```\n\n**BYOK (self-hosted / non-managed only):** use `OpenAIChatModelConfig(label, modelId, slotKey)` — it creates a credential slot the operator must bind with an API key. Only use this in self-hosted deployments where no managed broker is available.\n\n**Messages:** `content` is a plain string or a function `(args: { item, itemIndex, items, ctx }) => string`. Put instructions in the `system` message, per-item data in the `user` message. Use `\"assistant\"` role only for few-shot examples.\n\n**Structured output:** add `outputSchema: z.object({...})` to validate and parse the response. Without it, `item.json.output` is always a plain string.\n\n**Stable node id:** if the node has a credential binding (BYOK), set an explicit `id:` on the constructor. Without it the id derives from the `name` label — renaming the label orphans the binding. See `codemation-workflow-dsl` for the full id-stability rule.\n\n**Downstream access:** the next node sees `item.json.output` as the agent's text response. Cast it via a typed `Callback<{ output: string }>`.\n\n## Anti-patterns\n\n- Do not tell managed users to get an API key — use `CodemationChatModelConfig`; the broker authenticates automatically.\n- Do not use `OpenAIChatModelConfig` in managed mode — it creates an unnecessary credential slot and will prompt the user to bind a key they don't need.\n- Do not use `AIAgent` for deterministic logic; use `Callback` instead (cheaper, faster, no LLM billing).\n- Do not attempt to return multiple items from a single `AIAgent` step — it emits exactly one output per input.\n\nSee `references/anti-patterns.md` for version-specific gotchas (managed model id churn, chatModel string shorthand trap).\n"
21
+ },
22
+ {
23
+ "name": "codemation-cli",
24
+ "description": "Guides Codemation CLI work for consumer apps and framework-author development. Use when the user asks about `codemation dev`, `build`, `serve web`, `serve worker`, `user create`, `user list`, `--consumer-root`, `.codemation/output`, or consumer versus framework-author mode.",
25
+ "tags": [
26
+ "cli",
27
+ "dev"
28
+ ],
29
+ "sourcePath": "skills/codemation-cli/SKILL.md",
30
+ "dependencies": {},
31
+ "code": "---\nname: codemation-cli\ndescription: Guides Codemation CLI work for consumer apps and framework-author development. Use when the user asks about `codemation dev`, `build`, `serve web`, `serve worker`, `user create`, `user list`, `--consumer-root`, `.codemation/output`, or consumer versus framework-author mode.\ncompatibility: Designed for Codemation repositories and projects that use the Codemation CLI.\ntags: cli, dev\n---\n\n# Codemation CLI\n\n## Mental model\n\nThe CLI is a thin orchestrator: it loads `codemation.config.ts`, delegates to `@codemation/host` (web server) and worker packages, and manages build artifacts in `.codemation/output/`. It owns no workflow logic. There are two modes: **consumer mode** (`codemation dev`) runs a stable packaged UI against the consumer's workflows; **framework-author mode** (`codemation dev --watch-framework`) enables `next-host` HMR for monorepo development.\n\n## When to use / when NOT\n\nUse this skill for command selection, local development flow, and CLI troubleshooting.\nDo not use for workflow graph design, custom node implementation, or credential modeling unless the CLI command is the core question.\n\n## Quickstart\n\n```\ncodemation dev # consumer development (default)\ncodemation dev --watch-framework # framework-author / UI HMR (monorepo)\ncodemation build # emit .codemation/output/build\ncodemation serve web # run packaged web host\ncodemation serve worker # start queue-backed worker\ncodemation user create # bootstrap local-auth user\ncodemation user list # inspect auth users\n```\n\nUse `codemation --help` or `codemation <command> --help` before guessing flags.\n\n## Decision branches & gotchas\n\n**Standalone consumer vs monorepo:** confirm which context the user is in before suggesting commands. In the monorepo, distinguish framework-author mode from consumer mode explicitly.\n\n**Plugin loading:** in consumer mode, plugins are loaded from the built JavaScript path declared in `package.json#codemation.plugin` — not from TypeScript source under `node_modules`. In plugin dev mode, the CLI TypeScript-loads only the current plugin repo through the generated `.codemation/plugin-dev/codemation.config.ts`.\n\n**Redis-backed execution:** when Redis-backed execution is involved, mention the shared PostgreSQL requirement — local SQLite no longer fits.\n\n**Skills sync:** after `@codemation/cli` or `@codemation/agent-skills` package upgrades in monorepo work, run `codemation skills sync` to refresh extracted packaged skills in `.agents/skills/extracted`. Automatic refresh is intentionally disabled in the monorepo worktree to keep it clean.\n\n## Anti-patterns\n\n- Do not guess CLI flags — use `codemation <command> --help`.\n- Do not assume SQLite fits when Redis-backed workers are in play — check for the PostgreSQL requirement.\n\n## Read next when needed\n\n- Read `references/command-map.md` for command responsibilities and development-mode guidance.\n"
32
+ },
33
+ {
34
+ "name": "codemation-credential-development",
35
+ "description": "Guides Codemation custom credential development with `defineCredential(...)`, typed sessions, credential testing, and node credential slots. Use when creating or updating custom credentials, credential registrations, or credential-aware custom nodes.",
36
+ "tags": [
37
+ "credential",
38
+ "oauth",
39
+ "plugin"
40
+ ],
41
+ "sourcePath": "skills/codemation-credential-development/SKILL.md",
42
+ "dependencies": {},
43
+ "code": "---\nname: codemation-credential-development\ndescription: Guides Codemation custom credential development with `defineCredential(...)`, typed sessions, credential testing, and node credential slots. Use when creating or updating custom credentials, credential registrations, or credential-aware custom nodes.\ncompatibility: Designed for Codemation apps and plugins that register typed credentials.\ntags: credential, oauth, plugin\n---\n\n# Codemation Credential Development\n\n## Mental model\n\nA credential type is a schema + runtime adapter: it declares `public` config (e.g. OAuth client id), `secret` material (e.g. tokens), a `createSession(...)` factory that returns the typed object nodes consume, and a `test(...)` function for pre-activation validation. Nodes declare named credential slots; operators bind concrete instances to those slots in the UI. The binding key is `(workflowId, nodeId, slotKey)`.\n\n## When to use / when NOT\n\nUse this skill for defining new credential types, wiring them into apps or plugins, and teaching nodes to request typed credential sessions.\nDo not use for general workflow authoring unless credential slots or runtime sessions are the core problem.\n\n## Quickstart\n\nNo standalone snippet — the full `defineCredential(...)` shape is in `references/credential-patterns.md`. Use your harness's example-discovery tool for runnable examples: `find_examples({ query: \"defineCredential api-key test\" })` or `find_examples({ query: \"credential slot\" })`.\n\n## What `test()` does and why it matters\n\nEvery credential type must implement `test(args)`. It is called:\n\n- When the operator clicks **Connect** in the credential dialog (validates before saving).\n- Before a workflow activates (blocks activation on failing credentials).\n\n`test()` receives the same `{ publicConfig, material }` args as `createSession()`. It must return `{ status: \"healthy\" | \"failing\", message, testedAt }`. A \"failing\" result blocks workflow activation and surfaces the `message` to the operator — use it to give actionable guidance (\"API key is empty\", \"Endpoint returned 401 — key is invalid\").\n\nImplement `test()` as a cheap probe against the real service when possible (e.g. a `/health` or `/me` call). At minimum, validate that required secret fields are non-empty. Do NOT call `createSession()` from inside `test()` — test independently so credential issues are caught before runtime.\n\nSee the `define-credential-api-key` example for a concrete `test()` implementation: `find_examples({ query: \"defineCredential api-key test\" })`.\n\n## Authoring rules\n\n1. Start with `defineCredential(...)`.\n2. Keep `public` versus `secret` fields intentional.\n3. Make `createSession(...)` return the typed runtime object the node actually needs.\n4. Implement `test(...)` so failure states are explicit before workflow activation.\n5. Register credential types at the app or plugin boundary, not inside random workflow files.\n\n## Decision branches & gotchas\n\n**Node integration:** helper-defined nodes declare credentials directly in the `credentials` field; class-based nodes use lower-level credential requirement APIs when needed.\n\n**Binding stability:** the `nodeId` defaults to a slug of the node's `name` label. Renaming a credential-using node's label silently changes its id and orphans the binding in the UI. To prevent this, set an explicit `id:` on credential-using node configs so the id is decoupled from the label.\n\n## Anti-patterns\n\n- Do not hard-code secrets in node implementation — use credential slots.\n- Do not register credential types inside workflow files — use the app or plugin composition root.\n\n## Read next when needed\n\n- Read `references/credential-patterns.md` for schema, registration, and slot guidance.\n"
44
+ },
45
+ {
46
+ "name": "codemation-custom-node-development",
47
+ "description": "Guides Codemation custom node development with `defineNode(...)` (`execute` per item), `defineBatchNode(...)` (batch `run`), reusable node modules, credential-aware nodes, and the class-based node fallback for advanced cases. Use when creating or updating custom nodes for apps or plugin packages.",
48
+ "tags": [
49
+ "node",
50
+ "custom",
51
+ "plugin"
52
+ ],
53
+ "sourcePath": "skills/codemation-custom-node-development/SKILL.md",
54
+ "dependencies": {
55
+ "@codemation/core": "0.13.0"
56
+ },
57
+ "code": "---\nname: codemation-custom-node-development\ndescription: Guides Codemation custom node development with `defineNode(...)` (`execute` per item), `defineBatchNode(...)` (batch `run`), reusable node modules, credential-aware nodes, and the class-based node fallback for advanced cases. Use when creating or updating custom nodes for apps or plugin packages.\ncompatibility: Designed for Codemation apps and plugin packages that define reusable nodes.\ntags: node, custom, plugin\nuses: \"@codemation/core\"\n---\n\n# Codemation Custom Node Development\n\n## Mental model\n\nCustom nodes are the extension point for reusable business logic that doesn't belong inline in a workflow callback. `defineNode(...)` wraps a per-item `execute` function with a typed contract (input schema, credential slots, output shape); the engine calls it once per item. `defineBatchNode(...)` is the batch variant for logic that must see all items at once. Nodes compose into workflows via config class instances — the node definition is separate from the config class used to wire it into a workflow.\n\n## Use this skill when\n\nUse this skill for reusable custom node work, whether the node lives inside an app or a published plugin package.\n\nDo not use this skill for pure workflow chaining questions unless the node implementation itself is changing.\n\n## Per-item vs batch\n\n**`defineNode(...)` (per-item)** — the engine calls `execute(args, context)` once per item. This is the right default for the vast majority of nodes: straightforward logic, credential slots, input schema, optional fan-out.\n\n**`defineBatchNode(...)` (batch)** — the engine calls `run(items, context)` with the full activation batch. Use only when the node genuinely needs to see all items at once (aggregation, bulk API calls, cross-item correlation).\n\nWhen in doubt, start with `defineNode`.\n\n## Node rules\n\n1. Keep nodes deterministic and focused.\n2. Request credentials through named slots — never hard-code secrets.\n3. Put **static** options (credentials, retry policy, labels) on **config**; put **per-item** behavior in **inputs** / wire JSON and optional `itemExpr` on config fields.\n4. **Emit files with `ctx.binary`, not base64 in `json`** — base64 in `item.json` bloats persisted run data. See `references/node-patterns.md`.\n5. Drop to class-based node APIs only when you need constructor-injected collaborators, decorators, or deeper runtime metadata.\n\n## Minimal `defineNode` example\n\n```ts\nimport { defineNode } from \"@codemation/core\";\nimport { z } from \"zod\";\n\nexport const uppercaseNode = defineNode({\n key: \"example.uppercase\",\n title: \"Uppercase field\",\n icon: \"lucide:languages\",\n inputSchema: z.object({ field: z.string() }),\n async execute({ input }) {\n return { ...input, field: input.field.toUpperCase() };\n },\n});\n```\n\nFor full patterns — credential-slotted nodes, batch nodes, fan-out, binary payloads, and test kit usage — use your harness's example-discovery tool: `find_examples({ query: \"defineNode\" })` or `find_examples({ query: \"defineBatchNode\" })`.\n\n## Read next\n\n- `references/define-node-per-item.md` — full `defineNode(...)` contract, `inputSchema`, `itemExpr`, fan-out, assertion nodes, and `WorkflowTestKit` usage. Load this when writing or debugging a per-item node.\n- `references/define-batch-node.md` — `defineBatchNode(...)` contract and when to choose batch over per-item. Load this when the node must see the entire batch at once.\n- `references/credential-aware-nodes.md` — credential slots, typed sessions, and how to test credential-aware nodes. Load this when your node needs a credential.\n- `references/node-patterns.md` — binary payloads (`ctx.binary`, `attach`, `withAttachment`), fan-out return shapes, polling-trigger binary patterns, MS Graph attachment download, and HTTP binary round-trips. Load this when working with file data or HTTP binaries.\n"
58
+ },
59
+ {
60
+ "name": "codemation-document-scanner",
61
+ "description": "CodemationDocumentScanner node — managed document/invoice/image extraction via the Codemation doc-scanner service. No Azure credentials required. Read before writing any workflow that scans documents, invoices, or images.",
62
+ "tags": [
63
+ "ocr",
64
+ "document",
65
+ "invoice",
66
+ "image",
67
+ "scan",
68
+ "extract",
69
+ "managed",
70
+ "confidence"
71
+ ],
72
+ "sourcePath": "skills/codemation-document-scanner/SKILL.md",
73
+ "dependencies": {
74
+ "@codemation/core-nodes": "0.10.0"
75
+ },
76
+ "code": "---\nname: codemation-document-scanner\ndescription: CodemationDocumentScanner node — managed document/invoice/image extraction via the Codemation doc-scanner service. No Azure credentials required. Read before writing any workflow that scans documents, invoices, or images.\ncompatibility: Codemation core-nodes. Requires @codemation/core-nodes import.\ntags: ocr, document, invoice, image, scan, extract, managed, confidence\nuses: \"@codemation/core-nodes\"\n---\n\n# Codemation Document Scanner Node\n\n> **Start here: call `find_examples` before reading further.**\n>\n> - `find_examples({ query: \"CodemationDocumentScanner\" })` — node-level usage and all analyzerType variants\n> - `find_examples({ query: \"invoice scan post accounting\" })` — end-to-end invoice extraction scenario\n> - `find_examples({ query: \"document scanner confidence fields\" })` — how to enable per-field confidence scores\n\n## Use this skill when\n\nWriting a workflow that extracts text and/or structured fields from documents, invoices, or images\nusing the Codemation managed scanning service. No Azure credentials are required — the service is\npre-wired to the platform.\n\nUse `codemation-workflow-dsl` for surrounding workflow structure.\nUse `codemation-ai-agent-node` if you need to pass the extracted markdown to an LLM for further processing.\n\n## When to use CodemationDocumentScanner vs the standalone OCR nodes\n\n| Situation | Use |\n| ------------------------------------------------ | --------------------------------------------------------------------------------------------------- |\n| Managed platform deployment, no Azure credential | `codemationDocumentScannerNode` (this skill) |\n| Self-hosted / BYOK Azure Content Understanding | `analyzeDocumentNode` / `analyzeInvoiceNode` / `analyzeImageNode` from `@codemation/core-nodes-ocr` |\n\n`codemationDocumentScannerNode` calls the internal `doc-scanner` service via HMAC — the workspace holds\nno Azure key. The standalone OCR nodes call Azure directly using a per-workspace credential.\n\n## Choosing `analyzerType`\n\n| `analyzerType` | When to use | Azure analyzer | Field extraction | Confidence opt-in supported |\n| -------------- | ----------------------------------------------- | ----------------------------------------------------------------------- | ---------------------- | --------------------------------------- |\n| `\"document\"` | General PDFs, Word docs, HTML, text-heavy files | `prebuilt-document` | Yes | Yes |\n| `\"invoice\"` | Invoices, receipts — always prebuilt-invoice | `prebuilt-invoice` | Yes | Yes |\n| `\"image\"` | Photos, screenshots, diagrams | `prebuilt-imageAnalyzer` | No (markdown only) | No — image carries no extraction charge |\n| `\"auto\"` | Unknown mime type at author time | Routes on `Content-Type`: `image/*` → image, everything else → document | Depends on routed type | Depends on routed type |\n\n**Default is `\"auto\"`.** Set an explicit type whenever you know the content class — it avoids\nunnecessary re-routing and makes the workflow self-documenting.\n\n## Output shape\n\n```ts\n{\n markdown: string; // full text content\n fields: Record<\n string,\n {\n value: unknown; // extracted scalar, date ISO string, nested object, or array\n confidence: number | null; // 0–1 when includeConfidence:true; null otherwise\n }\n >;\n}\n```\n\n`item.json.markdown` is the Markdown rendering of the document.\n`item.json.fields` is a flat-or-nested map of structured fields found by the analyzer.\nFor `analyzerType: \"image\"`, `fields` is always `{}`.\nFields may be sparse or absent for generic documents — extraction is best-effort.\n\n## WARNING: How to enable per-field confidence scores (LD6)\n\n**By default, `confidence` is `null` on every field.** This keeps token cost low for the majority\nof workflows that only need `value`.\n\nTo get a populated `confidence` (0–1 float) on each field, set `includeConfidence: true`:\n\n```ts\ncodemationDocumentScannerNode.create(\n {\n binaryField: \"data\",\n analyzerType: \"invoice\",\n includeConfidence: true, // ← opt-in: fields carry confidence 0–1\n },\n \"Scan invoice\",\n \"scan-invoice\",\n);\n```\n\n**Cost implication:** enabling confidence routes the request to a confidence-enabled analyzer variant,\nwhich roughly doubles the contextualization token count for document/invoice analyzers.\nOnly enable it when your downstream logic actually reads `field.confidence`.\n\nImages (`analyzerType: \"image\"`) and auto-routed-to-image requests carry no field-extraction charge\nregardless of this flag — they silently ignore `includeConfidence` (confidence stays `null`, never a 400).\n\n## API usage\n\n```ts\nimport { codemationDocumentScannerNode } from \"@codemation/core-nodes\";\n\ncodemationDocumentScannerNode.create(\n {\n binaryField?: string; // key on item.binary — default \"data\"\n analyzerType?: \"document\" | \"invoice\" | \"image\" | \"auto\"; // default \"auto\"\n contentType?: string; // MIME type override — falls back to attachment.mimeType\n includeConfidence?: boolean; // default false — see cost note above\n maxBytes?: number; // size cap before reading; default 50 MiB (LD10)\n },\n label?: string, // node label on the canvas\n nodeId?: string, // explicit stable id — set when output is used downstream\n)\n```\n\nSet an explicit `nodeId` whenever downstream nodes reference this node's output by id, or when\nthe node may be renamed later (avoids credential-binding orphaning).\n\n## Consuming fields downstream\n\n```ts\nimport type { DocScannerOutput, DocScannerField } from \"@codemation/core-nodes\";\n\n// item.json after codemationDocumentScannerNode:\n// DocScannerOutput = { markdown: string; fields: Record<string, DocScannerField> }\n// DocScannerField = { value: unknown; confidence: number | null }\n\nnew Callback<DocScannerOutput>(\"Use fields\", (items, _ctx) =>\n items.map((item) => {\n const vendorName = item.json.fields[\"VendorName\"]?.value as string | undefined;\n const vendorConf = item.json.fields[\"VendorName\"]?.confidence; // null unless includeConfidence:true\n return { ...item, json: { ...item.json, vendorName, vendorConf } };\n }),\n);\n```\n\n## Read next when needed\n\n- `codemation-workflow-dsl` — workflow builder, trigger types, fluent vs low-level API.\n- `codemation-ai-agent-node` — pass `item.json.markdown` to an LLM for summarisation or extraction.\n"
77
+ },
78
+ {
79
+ "name": "codemation-framework-concepts",
80
+ "description": "Explains Codemation package boundaries, runtime concepts, observability shape, and the normal consumer mental model. Use when the user asks where code belongs across `@codemation/core`, `@codemation/host`, `@codemation/next-host`, `@codemation/cli`, workflows, plugins, credentials, activation, telemetry, or runtime modes. Read this first when starting any Codemation task — it points at the right skill for the work.",
81
+ "tags": [
82
+ "concepts",
83
+ "architecture"
84
+ ],
85
+ "sourcePath": "skills/codemation-framework-concepts/SKILL.md",
86
+ "dependencies": {},
87
+ "code": "---\nname: codemation-framework-concepts\ndescription: Explains Codemation package boundaries, runtime concepts, observability shape, and the normal consumer mental model. Use when the user asks where code belongs across `@codemation/core`, `@codemation/host`, `@codemation/next-host`, `@codemation/cli`, workflows, plugins, credentials, activation, telemetry, or runtime modes. Read this first when starting any Codemation task — it points at the right skill for the work.\ncompatibility: Designed for Codemation apps, plugins, and framework contributors.\ntags: concepts, architecture\n---\n\n# Codemation Framework Concepts\n\n## Mental model\n\nCodemation is a workflow engine with a layered package structure. `@codemation/core` owns the engine and runtime contracts (must stay pure — no HTTP, UI, or vendor SDKs). `@codemation/host` adds persistence, credentials, APIs, and scheduler wiring. `@codemation/next-host` is the framework UI shell. `@codemation/cli` runs local development, build, and serve. Consumer apps define behavior in `codemation.config.ts` and `src/workflows/` — they never touch core internals.\n\n## When to use / when NOT\n\nUse this skill to orient on package ownership, runtime shape, observability boundaries, and the consumer/framework divide.\nDo not use as a substitute for detailed CLI, workflow DSL, or plugin implementation guidance when you already know which skill you need.\n\n## Core concepts\n\n- **workflows** define behavior; **triggers** start runs; **nodes** process items; **items** carry `item.json` data.\n- **credentials** provide typed runtime resources (bound per operator instance, not per workflow code).\n- **activation** is framework-managed and happens in the UI — consumer code does not call it directly.\n- **telemetry** is observability-first: traces, spans, artifacts, and metric points are framework-owned runtime data.\n- **workflow testing** is a first-class primitive: `TestTrigger` yields one item per test case; `Assertion` nodes record per-run results into `TestAssertion` rows; the canvas exposes a Tests tab.\n- **run retention** and **telemetry retention** can differ — trend data can outlive raw run state.\n\n## Where to go next\n\n| Task | Skill |\n| ------------------------------------- | ------------------------------------ |\n| Authoring workflows | `codemation-workflow-dsl` |\n| Building a reusable node | `codemation-custom-node-development` |\n| Building a credential type | `codemation-credential-development` |\n| Packaging as a plugin | `codemation-plugin-development` |\n| Calling an MCP server from a workflow | `codemation-mcp-capabilities` |\n| CLI commands / dev loop | `codemation-cli` |\n\n## Read next when needed\n\n- Read `references/architecture-map.md` for package ownership and runtime-mode guidance.\n"
88
+ },
89
+ {
90
+ "name": "codemation-mcp-capabilities",
91
+ "description": "Discover MCP servers registered on the Codemation control plane. Use before authoring agent workflows that reference mcpServers to find available server ids and their credential requirements.",
92
+ "tags": [
93
+ "mcp",
94
+ "agent",
95
+ "tool"
96
+ ],
97
+ "sourcePath": "skills/codemation-mcp-capabilities/SKILL.md",
98
+ "dependencies": {},
99
+ "code": "---\nname: codemation-mcp-capabilities\ndescription: Discover MCP servers registered on the Codemation control plane. Use before authoring agent workflows that reference mcpServers to find available server ids and their credential requirements.\ncompatibility: Requires an installation paired with a connected control plane (Sprint 2+).\ntags: mcp, agent, tool\n---\n\n# Codemation MCP Capabilities\n\n## Mental model\n\nMCP servers extend `AIAgent` with tool access to external services (Gmail, Sheets, etc.). Server ids and credential requirements come from the control-plane registry — they are not hard-coded in framework code. The agent's `mcpServers` array contains stable server id slugs; each declared server surfaces a credential slot the operator must bind in the canvas before activation.\n\n## When to use / when NOT\n\nUse this skill before writing `agent({ mcpServers: [\"...\"] })` to discover available server ids and their credential types.\nDo not use for general AIAgent authoring — read `codemation-ai-agent-node` for that.\n\n## Managed mode: CP-loaded MCP servers (default path)\n\nIn **managed mode**, MCP servers are loaded from the **control plane (CP)** — not declared in plugin code. Discover available servers by querying the CP registry:\n\n```\nGET /api/registry/capabilities?query=gmail\n```\n\nResponse contains objects with `{ kind, id, displayName, description, acceptedCredentialTypes }`. Use `id` in the workflow's `mcpServers` array. An empty `query` string returns all registered servers.\n\nFor a full wired example — cron workflow + AIAgent + mcpServers — use your harness's example-discovery tool: `find_examples({ query: \"AIAgent gmail mcpServers\" })` or `find_examples({ query: \"mcp server\" })`.\n\n## Non-managed: plugin-declared MCP servers\n\nIn self-hosted / non-managed deployments, MCP servers can also be declared via `mcpServers: [...]` in a `definePlugin(...)` call. This is a framework-author pattern — do not use it in managed-mode workflows. See `references/plugin-anatomy.md` in the `codemation-plugin-development` skill for the plugin declaration syntax.\n\n## Decision branches & gotchas\n\n**Credential types:** `\"oauth.google.gmail\"` requires the user to connect a Google account via the credential dialog before the workflow runs. The same instance can be shared between a `GmailTrigger` and the Gmail MCP server. An empty `acceptedCredentialTypes` array means no credential is needed.\n\n**Multiple instances:** a user may have multiple instances of the same credential type (personal vs work Gmail). The canvas credential dropdown surfaces all matching instances — the operator picks the one to bind.\n\n**Bind via UI only:** there is no inline credential field on the workflow definition. The operator binds the credential instance via the canvas credential dropdown before activation.\n\n**Typical flow (managed):**\n\n1. `GET /api/registry/capabilities?query=<term>` → find `id` and `acceptedCredentialTypes`.\n2. Add `id` to `mcpServers` in the `AIAgent` config.\n3. Report: \"The user will need to bind a `<type>` credential instance via the canvas before activating.\"\n\n## Anti-patterns\n\n- Do not guess server ids — always query the registry first.\n- Do not add `acceptedCredentialTypes` to the workflow definition — credential binding is UI-driven, not code-driven.\n- Do not declare MCP servers inside plugin code for managed-mode workflows — use the CP registry instead.\n"
100
+ },
101
+ {
102
+ "name": "codemation-plugin-development",
103
+ "description": "Guides Codemation plugin package development, including `definePlugin(...)`, plugin sandboxes, custom nodes, custom credentials, and publishable plugin package structure. Use when building or updating a Codemation plugin package or the plugin starter template.",
104
+ "tags": [
105
+ "plugin",
106
+ "node",
107
+ "package"
108
+ ],
109
+ "sourcePath": "skills/codemation-plugin-development/SKILL.md",
110
+ "dependencies": {},
111
+ "code": "---\nname: codemation-plugin-development\ndescription: Guides Codemation plugin package development, including `definePlugin(...)`, plugin sandboxes, custom nodes, custom credentials, and publishable plugin package structure. Use when building or updating a Codemation plugin package or the plugin starter template.\ncompatibility: Designed for Codemation plugin packages and the Codemation plugin starter template.\ntags: plugin, node, package\n---\n\n# Codemation Plugin Development\n\n## Mental model\n\nA Codemation plugin is an npm package with a `codemation.plugin.ts` composition root that calls `definePlugin(...)`. It registers custom nodes and credential types, optionally declares MCP servers, and ships a sandbox app so the plugin is immediately testable. Consumers load the built JavaScript entry (`package.json#codemation.plugin`) — not TypeScript source. Plugin code follows the same `defineNode` / `defineCredential` patterns as app-level code; the plugin boundary is purely about packaging and distribution.\n\n## When to use / when NOT\n\n**Plugin authoring is a framework-author / non-managed task.** Managed-mode agents work with credential slots and workflow DSL — they do not author or modify plugin packages.\n\nUse this skill for published plugin packages, plugin starter work, and sandbox-driven plugin development. Do not use for ordinary consumer workflow-only changes.\n\n## Decision branches & gotchas\n\n**MCP servers in plugins:** Plugin-declared `mcpServers` is a non-managed pattern for self-hosted / framework-author scenarios. In managed mode, MCP servers are loaded from the control plane — see `codemation-mcp-capabilities` for the managed path.\n\n**Publishing guardrail:** `package.json#codemation.plugin` must point at runnable JavaScript (`./dist/codemation.plugin.js`). Do not rely on consumers TypeScript-loading plugin files from `node_modules`.\n\n## Read next when needed\n\n- Read `references/plugin-anatomy.md` for the full `definePlugin(...)` code, package layout, sandbox setup, MCP server declaration, binary payload rules, and publishing guidance.\n- Read `references/plugin-structure.md` for a concise package layout reference.\n"
112
+ },
113
+ {
114
+ "name": "codemation-workflow-dsl",
115
+ "description": "Guides Codemation workflow authoring. Use when creating or updating workflow definitions in `src/workflows` — manual-trigger flows via `workflow(\"...\").manualTrigger(...)`, or cron/webhook/other triggers via `createWorkflowBuilder({id, name}).trigger(...)`.",
116
+ "tags": [
117
+ "workflow",
118
+ "dsl",
119
+ "authoring"
120
+ ],
121
+ "sourcePath": "skills/codemation-workflow-dsl/SKILL.md",
122
+ "dependencies": {
123
+ "@codemation/core-nodes": "0.10.0",
124
+ "@codemation/host": "0.10.0"
125
+ },
126
+ "code": "---\nname: codemation-workflow-dsl\ndescription: Guides Codemation workflow authoring. Use when creating or updating workflow definitions in `src/workflows` — manual-trigger flows via `workflow(\"...\").manualTrigger(...)`, or cron/webhook/other triggers via `createWorkflowBuilder({id, name}).trigger(...)`.\ncompatibility: Designed for Codemation apps and plugins that author workflows.\ntags: workflow, dsl, authoring\nuses: \"@codemation/core-nodes, @codemation/host\"\n---\n\n# Codemation Workflow DSL\n\n## Mental model\n\nA workflow definition describes how items move from a trigger through downstream node steps. Items carry data in `item.json`; earlier outputs are available through `ctx.data`. Activations are batch-shaped but most node steps execute per-item. Every workflow definition finishes with `.build()`, which validates node ids and emits a `WorkflowDefinitionError` on collision or empty id.\n\n## When to use / when NOT\n\nUse this skill when authoring or reviewing workflow definitions under `src/workflows/`.\nDo not use for CLI-only troubleshooting or deep host architecture questions unless they directly affect workflow authoring.\n\n## Quickstart — pick API by trigger type\n\n```ts\n// Manual trigger — full fluent sugar (.map, .if, .switch, .agent, .node, .then)\nimport { workflow } from \"@codemation/host\";\nexport default workflow(\"wf.example\")\n .manualTrigger(\"Start\", {\n /* seed items */\n })\n .map(/* ... */)\n .build();\n\n// Cron / webhook / any other trigger — low-level .then(new NodeConfig(...)) only\nimport { createWorkflowBuilder, CronTrigger } from \"@codemation/core-nodes\";\nexport default createWorkflowBuilder({ id: \"wf.example\", name: \"Example\" })\n .trigger(new CronTrigger(\"Daily\", { schedule: \"0 9 * * *\", timezone: \"UTC\" }))\n .then(/* new SomeNodeConfig(...) */)\n .build();\n```\n\nFor full patterns — multi-step pipelines, branching, SubWorkflow, binary, agent tools, TestTrigger, and complete working examples — use your harness's example-discovery tool: `find_examples({ query: \"...\" })`. Useful queries: `\"CronTrigger\"`, `\"if branch\"`, `\"AIAgent multi-step\"`, `\"SubWorkflow binary\"`, `\"TestTrigger assertion\"`.\n\n## Decision branches & gotchas\n\n**Two authoring APIs — pick by trigger type.** `workflow(\"id\").manualTrigger(...)` returns a `WorkflowChain` with full fluent helpers (`.map`, `.if`, `.switch`, `.split`, `.agent`, `.node`). `createWorkflowBuilder({id, name}).trigger(new XxxTrigger(...))` returns a `ChainCursor` whose only chain method is `.then(new NodeConfig(...))`. Do NOT call `.trigger(...)` on the `workflow(...)` builder — it doesn't exist there.\n\n**Node ids and stability.** When no explicit `id:` is given, the engine slugifies the node's `name` label (lowercase, non-alphanumeric → `-`). `\"Send Email\"` → `\"send-email\"`. Nodes sharing credential bindings use `(workflowId, nodeId, slotKey)` as the binding key — renaming a label orphans the binding. **Set explicit `id:` on every credential-using node.** `.build()` throws `WorkflowDefinitionError` on empty or duplicate ids.\n\n**Id collision pitfall.** A manual-trigger label and a downstream agent label that share the same string both slugify to the same id — `.build()` throws. Fix: add `id: \"...-agent\"` to disambiguate.\n\n**Collection nodes** use `.then(node.create(...))` instead of `.node(label, node, opts)` — TypeScript can't infer the `ParamDeep` constraint via the fluent helper. See `find_examples({ query: \"collection crud\" })`.\n\n**Install state in example results.** Every `find_examples` result includes `installed: boolean` and `requiresInstall: string[]`. If `installed` is `false` or `requiresInstall` is non-empty, call `install_package` for each missing package before writing any workflow code that imports them.\n\n**When no example matches — self-solving fallback chain.**\n\n1. Retry with intent variations (different verb, more generic term).\n2. For HTTP APIs: `find_examples({ query: \"defineRestNode\" })` — covers basic and credential-slotted REST.\n3. For one-shot inline HTTP: `find_examples({ query: \"HttpRequest\" })`.\n4. For non-HTTP custom logic: `find_examples({ query: \"defineNode template\" })`.\n Do NOT ask the user to pick between primitives — they can't help; use the chain. Do NOT grep `node_modules/@codemation/*` for node implementations — examples are authoritative. Surface the technique used in your reply.\n\n**Workflow testing.** Three built-in nodes from `@codemation/core-nodes`: `TestTrigger` (yields one item per test case), `IsTestRun` (routes `true`/`false` by `ctx.testContext`), `Assertion` (emits `AssertionResult[]`, sets `emitsAssertions: true`). See `references/workflow-testing.md` for authoring details.\n\n**SubWorkflow binary.** `item.binary` slots pass transparently through SubWorkflow boundaries in both directions — no special config needed. Both runs share the same `BinaryStorage` singleton.\n\n**Verify your workflow.** Call `verify_workflow({ path: \"src/workflows/my-workflow.ts\" })` instead of running `pnpm typecheck` yourself. Returns `{ ok, data: { typecheck, lint, build, structure }, hint? }`.\n\n## Anti-patterns\n\n- Do not call `.trigger(...)` on the `workflow(...)` manual builder — use `createWorkflowBuilder(...)` for non-manual triggers.\n- Do not rely on slug-derived node ids for production workflows with credential bindings — always set an explicit `id:`.\n- Do not improvise from memory when `find_examples` returns zero hits — use the fallback chain above.\n\n## Read next when needed\n\n- `references/builder-patterns.md` — item-flow rules and fluent authoring patterns.\n- `references/workflow-testing.md` — TestTrigger / IsTestRun / Assertion with full examples.\n- `references/complete-example.md` — dense end-to-end example covering most authoring features.\n"
127
+ },
128
+ {
129
+ "name": "codemation-workspace-files",
130
+ "description": "ListWorkspaceFiles + ReadWorkspaceFile nodes — read files from the shared workspace pool. Covers read-by-filename (latest-wins), pinned fileId, binary slot handoff, and the raw-upload → concierge-digests → workflow-reads-derived-file pattern. Read before building any workflow that reads workspace files.",
131
+ "tags": [
132
+ "workspace",
133
+ "files",
134
+ "binary",
135
+ "storage",
136
+ "read",
137
+ "csv",
138
+ "json"
139
+ ],
140
+ "sourcePath": "skills/codemation-workspace-files/SKILL.md",
141
+ "dependencies": {
142
+ "@codemation/core-nodes-workspace-files": "0.2.0"
143
+ },
144
+ "code": "---\nname: codemation-workspace-files\ndescription: ListWorkspaceFiles + ReadWorkspaceFile nodes — read files from the shared workspace pool. Covers read-by-filename (latest-wins), pinned fileId, binary slot handoff, and the raw-upload → concierge-digests → workflow-reads-derived-file pattern. Read before building any workflow that reads workspace files.\ncompatibility: Codemation core-nodes-workspace-files. Requires WORKSPACE_ID and BLOB_STORAGE_* env vars.\ntags: workspace, files, binary, storage, read, csv, json\nuses: \"@codemation/core-nodes-workspace-files\"\n---\n\n# Codemation Workspace Files\n\n## Mental model\n\nWorkflows **read** the shared workspace file pool; they do **not** write to it. Files are\ncreated and managed on the control-plane side (the Files UI, the concierge, the\nDocumentScanner). The framework's role is to provide `ListWorkspaceFiles` and\n`ReadWorkspaceFile` as pure read nodes.\n\nThe **headline scenario** is: a user uploads a raw PDF; the concierge digests it into a\nstructured JSON; the workflow reads the _derived JSON_, not the raw bytes. Workflows\nnever touch raw uploads directly.\n\n## When to use / when NOT\n\nUse `ReadWorkspaceFile` when a workflow needs data that lives in the workspace pool\n(pricing sheets, config JSON, concierge-derived documents, CSV exports).\n\nUse `ListWorkspaceFiles` to discover what files exist or to drive a fan-out (one item per file).\n\nDo NOT use these nodes to write files — writing is CP-mediated and deferred to v2.\n\nDo NOT base64-encode bytes onto `item.json`. Binary payloads always flow through\n`item.binary` via `ctx.binary`.\n\n## Quickstart\n\n```ts\nimport { readWorkspaceFileNode } from \"@codemation/core-nodes-workspace-files\";\n\n// Read the latest \"pricing.csv\" by name — picks up the newest upload automatically.\nreadWorkspaceFileNode.create({ filename: \"pricing.csv\", binarySlot: \"data\" }, \"Read pricing CSV\", \"read-pricing-csv\");\n```\n\n```ts\n// Pin to an exact version — a later upload never changes what this reads.\nreadWorkspaceFileNode.create(\n { fileId: \"abc123def456\", binarySlot: \"data\" },\n \"Read pinned pricing CSV\",\n \"read-pricing-pinned\",\n);\n```\n\nFor full patterns (parse the bytes, scenario walkthrough, list + filter), use your\nharness's example-discovery tool: `find_examples({ query: \"workspace files\" })`.\n\n## Resolution modes\n\n| Mode | Config | Behaviour |\n| ------------------------- | ------------------------- | -------------------------------------------------------------------------------------------------- |\n| **latest-wins** (default) | `filename: \"pricing.csv\"` | Reads the **newest** file with that name. Next upload of the same name is what the next run reads. |\n| **pinned fileId** | `fileId: \"abc123...\"` | Reads that exact, immutable version forever. A new upload never changes this ref. |\n\nUse **latest-wins** for \"always use the current sheet\" patterns.\nUse **pinned fileId** for reproducible/auditable runs (e.g., regression tests, compliance audits).\n\n## Binary slot handoff\n\n`ReadWorkspaceFile` streams the file's bytes into `item.binary[binarySlot]` (default `\"data\"`).\nThe node emits:\n\n```ts\n{\n fileId: string;\n filename: string;\n contentType: string;\n size: number; // bytes\n lastModified: string; // ISO 8601\n binarySlot: string; // e.g. \"data\"\n}\n```\n\nDownstream nodes read the bytes via `ctx.binary.openReadStream(item.binary[\"data\"])`.\nThe bytes are **never** base64-encoded on `item.json`.\n\n## Concierge → digest → workflow pattern\n\nThis is the intended headline flow:\n\n```\nUser uploads PDF → CP Files UI stores it in the workspace pool\nConcierge sees upload → DocumentScanner digests it → writes \"report-digested.json\" back\nWorkflow runs (schedule/webhook) → ReadWorkspaceFile(\"report-digested.json\") → acts\n```\n\nThe workflow is **decoupled** from the upload event. It reads the _derived_ file that the\nconcierge produced, not the raw upload. The concierge's job is to bridge the raw-upload world\nand the structured-data world.\n\nKey boundaries:\n\n- **CP side (write)**: raw file ingest, concierge digest, derived file write, Files UI.\n- **Workflow side (read)**: `ReadWorkspaceFile` + `ListWorkspaceFiles` only.\n\n## Anti-patterns\n\n- Do NOT tell users to read the raw PDF upload in a workflow — point at the concierge-derived JSON.\n- Do NOT base64-encode file bytes onto `item.json` — use `item.binary[slot]` + `ctx.binary`.\n- Do NOT attempt to write a file from a workflow node — there is no write surface in v1.\n- Do NOT assume `WORKSPACE_ID` is always set — in local dev without CP integration, the storage\n token resolves to `undefined`. Add a guard if your workflow runs in dev mode.\n\n## Node reference\n\n### `listWorkspaceFilesNode`\n\n```ts\nlistWorkspaceFilesNode.create(\n {\n filenameFilter?: string; // optional substring match (case-insensitive)\n },\n \"List files\",\n \"list-files\",\n)\n```\n\nOutput per item: `{ fileId, filename, contentType, size, lastModified }`. Sorted newest-first.\n\n### `readWorkspaceFileNode`\n\n```ts\nreadWorkspaceFileNode.create(\n {\n filename?: string; // latest-wins resolution\n fileId?: string; // pinned resolution (takes precedence over filename)\n binarySlot?: string; // default: \"data\"\n maxBytes?: number; // default: 100 MiB — raise for large files\n },\n \"Read file\",\n \"read-file\",\n)\n```\n\nEither `filename` or `fileId` must be set. Output: metadata JSON + bytes in `item.binary[binarySlot]`.\n"
145
+ }
146
+ ]
147
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemation/agent-skills",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Reusable agent skills for Codemation projects and plugin development.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -43,11 +43,14 @@
43
43
  "README.md",
44
44
  "CHANGELOG.md",
45
45
  "bin",
46
+ "dist",
46
47
  "lib",
47
48
  "skills"
48
49
  ],
49
50
  "scripts": {
50
51
  "changeset:verify": "pnpm --workspace-root run changeset:verify",
52
+ "build": "pnpm build:metadata",
53
+ "build:metadata": "tsx ../../tooling/discovery/scripts/extract-metadata.ts",
51
54
  "test": "vitest run",
52
55
  "test:unit": "vitest run"
53
56
  }
@@ -1,78 +1,25 @@
1
1
  ---
2
2
  name: codemation-ai-agent-node
3
- description: AIAgent constructor, message shape, output contract, and chat-model configs (managed and BYOK). Read before writing any workflow that uses AIAgent.
3
+ description: AIAgent constructor, message shape, managed and BYOK chatModel configs, outputSchema, mcpServers. Read before writing any workflow step that calls an LLM.
4
4
  compatibility: Codemation core-nodes. Requires @codemation/core-nodes import.
5
+ tags: agent, llm, ai
6
+ uses: "@codemation/core-nodes"
5
7
  ---
6
8
 
7
9
  # Codemation AI Agent Node
8
10
 
9
- > **Start here: call `find_examples` before reading further.**
10
- >
11
- > - `find_examples({ query: "AIAgent" })` — basic usage and constructor patterns
12
- > - `find_examples({ query: "AIAgent multi-step" })` — chained pipeline patterns
13
- > - `find_examples({ query: "AIAgent tools" })` — agent with callable tools
14
- > - `find_examples({ query: "AIAgent gmail classify" })` — domain-specific examples
15
- >
16
- > The sections below are a quick orientation for when you need the exact constructor or output shape.
11
+ ## Mental model
17
12
 
18
- ## Use this skill when
13
+ `AIAgent` is the single building block for any LLM step in a workflow. It receives items, runs a chat completion per item using the configured model and messages, and emits `{ output: string }` (or a parsed object when `outputSchema` is set) on its `main` port. The `chatModel` field determines whether the run consumes Codemation-managed quota (no credential needed) or a BYOK key the operator supplies. Every AIAgent emits exactly one output item per input item — it never fans out or filters.
19
14
 
20
- Writing a workflow that uses `AIAgent` — classification, extraction, summarisation, drafting, decision, or any step that calls an LLM.
21
- Use `codemation-workflow-dsl` for the surrounding workflow structure.
22
- Use `codemation-mcp-capabilities` when the agent needs MCP servers.
15
+ ## When to use / when NOT
23
16
 
24
- ## When to use `AIAgent` vs other approaches
17
+ Use `AIAgent` when a workflow step needs an LLM call: classification, extraction, summarisation, drafting, or decision.
18
+ Use a plain `Callback` instead when the logic is deterministic code — no LLM needed.
19
+ Use `mcpServers` (see `codemation-mcp-capabilities`) when the agent needs tool access to external services.
20
+ Read `codemation-workflow-dsl` for the surrounding workflow structure.
25
21
 
26
- Use `AIAgent` when an item needs an LLM call with a fixed or per-item prompt and optional tool use.
27
- Use a plain `Callback` instead when the logic is deterministic code (no LLM needed).
28
- Use the `.agent(...)` fluent helper on a manual-trigger workflow only if you need the full fluent chain sugar — under the hood it also produces an `AIAgent`.
29
-
30
- ## Constructor
31
-
32
- ```ts
33
- import { AIAgent } from "@codemation/core-nodes";
34
-
35
- new AIAgent({
36
- name: string, // display name and default node id slug
37
- messages: AgentMessageConfig, // see below
38
- chatModel: ChatModelConfig, // see Managed and BYOK sections below
39
- tools?: ReadonlyArray<ToolConfig>, // optional callable tools
40
- id?: string, // stable node id (set explicitly if node has credential bindings)
41
- })
42
- ```
43
-
44
- ## `messages` shape
45
-
46
- `messages` is an ordered array of `{ role, content }` objects.
47
-
48
- ```ts
49
- messages: [
50
- { role: "system", content: "You are a helpful assistant that classifies emails." },
51
- { role: "user", content: (args) => `Classify this email:\n\n${args.item.json.body}` },
52
- ];
53
- ```
54
-
55
- - `role` is `"system"` | `"user"` (use `"assistant"` only for few-shot examples — rare).
56
- - `content` can be a plain string or a function `(args: { item, itemIndex, items, ctx }) => string`.
57
- - Put the detailed instructions in the `system` message and the per-item data in the `user` message.
58
-
59
- ## Output shape
60
-
61
- `AIAgent` emits `{ output: string }` on its single port `main`.
62
-
63
- The next node sees `item.json.output` as the agent's text response.
64
- Type your downstream `Callback` accordingly:
65
-
66
- ```ts
67
- .then(new Callback<{ output: string }>("Handle result", (item) => {
68
- const reply = item.json.output;
69
- // ...
70
- }))
71
- ```
72
-
73
- If you set `outputSchema` (a Zod schema), the agent validates and parses the output into a structured object. Without `outputSchema`, `item.json.output` is always a plain string.
74
-
75
- ## Managed model (no credentials needed)
22
+ ## Quickstart
76
23
 
77
24
  ```ts
78
25
  import { AIAgent, CodemationChatModelConfig } from "@codemation/core-nodes";
@@ -83,46 +30,37 @@ new AIAgent({
83
30
  { role: "system", content: "Classify the email as spam or not-spam." },
84
31
  { role: "user", content: (args) => args.item.json.body as string },
85
32
  ],
86
- chatModel: new CodemationChatModelConfig(
87
- "Claude Haiku", // display label
88
- "anthropic/claude-haiku-4-5-20251001", // managed model id
89
- ),
33
+ chatModel: new CodemationChatModelConfig("Claude Haiku", "anthropic/claude-haiku-4-5-20251001"),
90
34
  });
91
35
  ```
92
36
 
93
- ### Currently allowlisted managed models
37
+ For full patterns BYOK (`OpenAIChatModelConfig`), `outputSchema`, tools, multi-step pipelines, and gmail classification — use your harness's example-discovery tool: `find_examples({ query: "AIAgent" })`.
94
38
 
95
- | Model id | Notes |
96
- | ------------------------------------- | -------------------- |
97
- | `anthropic/claude-haiku-4-5-20251001` | Fastest and cheapest |
98
- | `anthropic/claude-sonnet-4-6` | Balanced |
99
- | `anthropic/claude-opus-4-5-20251101` | High capability |
100
- | `anthropic/claude-opus-4-6` | Latest flagship |
39
+ ## Decision branches & gotchas
101
40
 
102
- Discover live: `GET <CONTROL_PLANE_URL>/api/llm/managed-models`
103
-
104
- ## BYOK model (user supplies their own key)
41
+ **Managed mode (default — no API key needed):** use `CodemationChatModelConfig(label, modelId)`. In managed mode the LLM broker **auto-authenticates via the workspace HMAC pairing** — no API key, no credential slot, no user setup required. This is the correct default for all managed-mode workflows. Do NOT tell managed users to "get an API key" — the broker handles authentication transparently.
105
42
 
106
43
  ```ts
107
- import { AIAgent, OpenAIChatModelConfig } from "@codemation/core-nodes";
108
-
109
- new AIAgent({
110
- name: "Summarise",
111
- id: "summarise-agent", // stable id — required when node has a credential binding
112
- messages: [
113
- { role: "system", content: "Summarise the following text in one paragraph." },
114
- { role: "user", content: (args) => args.item.json.text as string },
115
- ],
116
- chatModel: new OpenAIChatModelConfig(
117
- "OpenAI GPT-4o", // display label
118
- "gpt-4o", // OpenAI model id
119
- "openai", // credential slot key — matches the slot used in getCredentialRequirements
120
- ),
121
- });
44
+ chatModel: new CodemationChatModelConfig("Claude Haiku", "anthropic/claude-haiku-4-5-20251001");
45
+ // No credential slot created. Discover live model ids:
46
+ // GET <CONTROL_PLANE_URL>/api/llm/managed-models
122
47
  ```
123
48
 
124
- `OpenAIChatModelConfig` requires the user to connect an `openai.apiKey` credential. The concierge handles credential acquisition the coding agent must not invent credentials.
49
+ **BYOK (self-hosted / non-managed only):** use `OpenAIChatModelConfig(label, modelId, slotKey)` it creates a credential slot the operator must bind with an API key. Only use this in self-hosted deployments where no managed broker is available.
50
+
51
+ **Messages:** `content` is a plain string or a function `(args: { item, itemIndex, items, ctx }) => string`. Put instructions in the `system` message, per-item data in the `user` message. Use `"assistant"` role only for few-shot examples.
52
+
53
+ **Structured output:** add `outputSchema: z.object({...})` to validate and parse the response. Without it, `item.json.output` is always a plain string.
54
+
55
+ **Stable node id:** if the node has a credential binding (BYOK), set an explicit `id:` on the constructor. Without it the id derives from the `name` label — renaming the label orphans the binding. See `codemation-workflow-dsl` for the full id-stability rule.
56
+
57
+ **Downstream access:** the next node sees `item.json.output` as the agent's text response. Cast it via a typed `Callback<{ output: string }>`.
58
+
59
+ ## Anti-patterns
125
60
 
126
- ## MCP servers
61
+ - Do not tell managed users to get an API key — use `CodemationChatModelConfig`; the broker authenticates automatically.
62
+ - Do not use `OpenAIChatModelConfig` in managed mode — it creates an unnecessary credential slot and will prompt the user to bind a key they don't need.
63
+ - Do not use `AIAgent` for deterministic logic; use `Callback` instead (cheaper, faster, no LLM billing).
64
+ - Do not attempt to return multiple items from a single `AIAgent` step — it emits exactly one output per input.
127
65
 
128
- If you need tools / MCP servers on the agent, see the `codemation-mcp-capabilities` skill.
66
+ See `references/anti-patterns.md` for version-specific gotchas (managed model id churn, chatModel string shorthand trap).
@@ -0,0 +1,11 @@
1
+ # AIAgent anti-patterns (version-specific)
2
+
3
+ ## Managed model ids change between releases
4
+
5
+ Do NOT hard-code managed model ids sourced from training data. The allowlisted set changes with each release.
6
+ Always discover the live list via `GET <CONTROL_PLANE_URL>/api/llm/managed-models` before committing a model id.
7
+
8
+ ## `chatModel` string shorthand is not supported on AIAgent
9
+
10
+ `AIAgent` does not accept a plain string for `chatModel` — only `CodemationChatModelConfig` or `OpenAIChatModelConfig` instances.
11
+ (The string shorthand `model: "openai:gpt-4o-mini"` works on the `.agent(...)` fluent DSL helper only.)
@@ -2,42 +2,48 @@
2
2
  name: codemation-cli
3
3
  description: Guides Codemation CLI work for consumer apps and framework-author development. Use when the user asks about `codemation dev`, `build`, `serve web`, `serve worker`, `user create`, `user list`, `--consumer-root`, `.codemation/output`, or consumer versus framework-author mode.
4
4
  compatibility: Designed for Codemation repositories and projects that use the Codemation CLI.
5
+ tags: cli, dev
5
6
  ---
6
7
 
7
8
  # Codemation CLI
8
9
 
9
- ## Use this skill when
10
+ ## Mental model
10
11
 
11
- Use this skill for command selection, local development flow, and CLI troubleshooting in a Codemation app or monorepo.
12
+ The CLI is a thin orchestrator: it loads `codemation.config.ts`, delegates to `@codemation/host` (web server) and worker packages, and manages build artifacts in `.codemation/output/`. It owns no workflow logic. There are two modes: **consumer mode** (`codemation dev`) runs a stable packaged UI against the consumer's workflows; **framework-author mode** (`codemation dev --watch-framework`) enables `next-host` HMR for monorepo development.
12
13
 
13
- Do not use this skill for workflow graph design, custom node implementation, or credential modeling unless the CLI command flow is the main question.
14
+ ## When to use / when NOT
14
15
 
15
- ## Default approach
16
+ Use this skill for command selection, local development flow, and CLI troubleshooting.
17
+ Do not use for workflow graph design, custom node implementation, or credential modeling unless the CLI command is the core question.
16
18
 
17
- 1. Confirm whether the user is in a standalone consumer project or the Codemation monorepo.
18
- 2. Prefer `codemation --help` or `codemation <command> --help` before guessing flags.
19
- 3. Explain the shortest command path first, then mention framework-author alternatives only if they matter.
20
- 4. Keep the CLI thin in your mental model: it orchestrates host and runtime packages instead of owning workflow logic itself.
19
+ ## Quickstart
21
20
 
22
- ## Command map
21
+ ```
22
+ codemation dev # consumer development (default)
23
+ codemation dev --watch-framework # framework-author / UI HMR (monorepo)
24
+ codemation build # emit .codemation/output/build
25
+ codemation serve web # run packaged web host
26
+ codemation serve worker # start queue-backed worker
27
+ codemation user create # bootstrap local-auth user
28
+ codemation user list # inspect auth users
29
+ ```
23
30
 
24
- - `codemation dev`: default consumer development flow with packaged UI and a stable CLI-owned dev gateway.
25
- - `codemation dev --watch-framework`: framework-author mode for monorepo work and `next-host` UI HMR.
26
- - `codemation build`: emits production-oriented consumer output under `.codemation/output/build`.
27
- - `codemation serve web`: runs the packaged web host for a built or configured consumer app.
28
- - `codemation serve worker`: starts the queue-backed worker runtime when execution is separated.
29
- - `codemation user create` and `codemation user list`: local-auth bootstrap and inspection commands.
31
+ Use `codemation --help` or `codemation <command> --help` before guessing flags.
30
32
 
31
- ## Working rules
33
+ ## Decision branches & gotchas
32
34
 
33
- 1. Treat `codemation.config.ts` as the consumer entrypoint.
34
- 2. Mention `.codemation/output` only when build artifacts or runtime bootstrap details matter.
35
- 3. When the user is in the monorepo, distinguish framework-author mode from normal consumer mode explicitly.
36
- 4. When Redis-backed execution is involved, mention the shared PostgreSQL requirement instead of assuming local SQLite still fits.
37
- 5. In consumer mode, discovered plugins are loaded from the built JavaScript path declared in `package.json#codemation.plugin`, not from TypeScript source under `node_modules`.
38
- 6. In plugin mode, the CLI TypeScript-loads only the current plugin repo through the generated `.codemation/plugin-dev/codemation.config.ts`.
39
- 7. In the Codemation framework monorepo, automatic refresh of `.agents/skills/extracted` is intentionally disabled to keep the worktree clean.
40
- 8. After `@codemation/cli` or `@codemation/agent-skills` package upgrades in monorepo work, remind the user to run `codemation skills sync` if they want the extracted packaged skills refreshed.
35
+ **Standalone consumer vs monorepo:** confirm which context the user is in before suggesting commands. In the monorepo, distinguish framework-author mode from consumer mode explicitly.
36
+
37
+ **Plugin loading:** in consumer mode, plugins are loaded from the built JavaScript path declared in `package.json#codemation.plugin` — not from TypeScript source under `node_modules`. In plugin dev mode, the CLI TypeScript-loads only the current plugin repo through the generated `.codemation/plugin-dev/codemation.config.ts`.
38
+
39
+ **Redis-backed execution:** when Redis-backed execution is involved, mention the shared PostgreSQL requirement local SQLite no longer fits.
40
+
41
+ **Skills sync:** after `@codemation/cli` or `@codemation/agent-skills` package upgrades in monorepo work, run `codemation skills sync` to refresh extracted packaged skills in `.agents/skills/extracted`. Automatic refresh is intentionally disabled in the monorepo worktree to keep it clean.
42
+
43
+ ## Anti-patterns
44
+
45
+ - Do not guess CLI flags — use `codemation <command> --help`.
46
+ - Do not assume SQLite fits when Redis-backed workers are in play — check for the PostgreSQL requirement.
41
47
 
42
48
  ## Read next when needed
43
49
 
@@ -2,27 +2,36 @@
2
2
  name: codemation-credential-development
3
3
  description: Guides Codemation custom credential development with `defineCredential(...)`, typed sessions, credential testing, and node credential slots. Use when creating or updating custom credentials, credential registrations, or credential-aware custom nodes.
4
4
  compatibility: Designed for Codemation apps and plugins that register typed credentials.
5
+ tags: credential, oauth, plugin
5
6
  ---
6
7
 
7
8
  # Codemation Credential Development
8
9
 
9
- ## Use this skill when
10
+ ## Mental model
11
+
12
+ A credential type is a schema + runtime adapter: it declares `public` config (e.g. OAuth client id), `secret` material (e.g. tokens), a `createSession(...)` factory that returns the typed object nodes consume, and a `test(...)` function for pre-activation validation. Nodes declare named credential slots; operators bind concrete instances to those slots in the UI. The binding key is `(workflowId, nodeId, slotKey)`.
13
+
14
+ ## When to use / when NOT
10
15
 
11
16
  Use this skill for defining new credential types, wiring them into apps or plugins, and teaching nodes to request typed credential sessions.
17
+ Do not use for general workflow authoring unless credential slots or runtime sessions are the core problem.
18
+
19
+ ## Quickstart
20
+
21
+ No standalone snippet — the full `defineCredential(...)` shape is in `references/credential-patterns.md`. Use your harness's example-discovery tool for runnable examples: `find_examples({ query: "defineCredential api-key test" })` or `find_examples({ query: "credential slot" })`.
12
22
 
13
- Do not use this skill for general workflow authoring unless credential slots or runtime sessions are the core problem.
23
+ ## What `test()` does and why it matters
14
24
 
15
- ## Credential binding stability
25
+ Every credential type must implement `test(args)`. It is called:
16
26
 
17
- Credentials bind to a node via `(workflowId, nodeId, slotKey)`. The `nodeId` defaults to a slug of the node's `name` label (lowercase, non-alphanumeric runs replaced with `-`). Renaming a credential-using node's label silently changes its id and the binding appears unbound in the UI the operator must re-attach manually.
27
+ - When the operator clicks **Connect** in the credential dialog (validates before saving).
28
+ - Before a workflow activates (blocks activation on failing credentials).
18
29
 
19
- To prevent this: either keep the node's label stable across edits, or set an explicit `id:` on the node config so the id is decoupled from the label.
30
+ `test()` receives the same `{ publicConfig, material }` args as `createSession()`. It must return `{ status: "healthy" | "failing", message, testedAt }`. A "failing" result blocks workflow activation and surfaces the `message` to the operator use it to give actionable guidance ("API key is empty", "Endpoint returned 401 — key is invalid").
20
31
 
21
- ## Core mental model
32
+ Implement `test()` as a cheap probe against the real service when possible (e.g. a `/health` or `/me` call). At minimum, validate that required secret fields are non-empty. Do NOT call `createSession()` from inside `test()` — test independently so credential issues are caught before runtime.
22
33
 
23
- 1. A credential type defines public config, secret material, session creation, and health testing.
24
- 2. Nodes request credentials through named slots instead of hard-coded secrets.
25
- 3. Operators configure concrete credential instances in the UI and bind them to those slots.
34
+ See the `define-credential-api-key` example for a concrete `test()` implementation: `find_examples({ query: "defineCredential api-key test" })`.
26
35
 
27
36
  ## Authoring rules
28
37
 
@@ -32,10 +41,16 @@ To prevent this: either keep the node's label stable across edits, or set an exp
32
41
  4. Implement `test(...)` so failure states are explicit before workflow activation.
33
42
  5. Register credential types at the app or plugin boundary, not inside random workflow files.
34
43
 
35
- ## Node integration
44
+ ## Decision branches & gotchas
45
+
46
+ **Node integration:** helper-defined nodes declare credentials directly in the `credentials` field; class-based nodes use lower-level credential requirement APIs when needed.
47
+
48
+ **Binding stability:** the `nodeId` defaults to a slug of the node's `name` label. Renaming a credential-using node's label silently changes its id and orphans the binding in the UI. To prevent this, set an explicit `id:` on credential-using node configs so the id is decoupled from the label.
49
+
50
+ ## Anti-patterns
36
51
 
37
- - helper-defined nodes can declare credentials directly in `credentials`
38
- - class-based nodes can use lower-level credential requirement APIs when needed
52
+ - Do not hard-code secrets in node implementation use credential slots.
53
+ - Do not register credential types inside workflow files — use the app or plugin composition root.
39
54
 
40
55
  ## Read next when needed
41
56