@elevasis/sdk 1.48.0 → 1.49.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.
Files changed (46) hide show
  1. package/dist/cli.cjs +742 -231
  2. package/dist/index.d.ts +685 -47
  3. package/dist/index.js +274 -40
  4. package/dist/node/index.d.ts +108 -24
  5. package/dist/test-utils/index.d.ts +647 -34
  6. package/dist/test-utils/index.js +240 -38
  7. package/dist/worker/index.d.ts +663 -39
  8. package/dist/worker/index.js +115 -6
  9. package/package.json +4 -4
  10. package/reference/_navigation.md +4 -4
  11. package/reference/_reference-manifest.json +1 -1
  12. package/reference/core/index.mdx +6 -4
  13. package/reference/index.mdx +11 -5
  14. package/reference/packages/core/src/README.md +46 -44
  15. package/reference/packages/core/src/content/README.md +13 -12
  16. package/reference/rules/ui.md +1 -1
  17. package/reference/rules/vibe-intents.md +2 -2
  18. package/reference/rules/vibe.md +30 -10
  19. package/reference/scaffold/recipes/extend-content.md +82 -3
  20. package/reference/sdk/cli-management.mdx +184 -41
  21. package/reference/sdk/cli.mdx +103 -64
  22. package/reference/sdk/define-builders.mdx +1 -1
  23. package/reference/sdk/deployment/command-center.mdx +2 -2
  24. package/reference/sdk/deployment/index.mdx +1 -1
  25. package/reference/sdk/exports.mdx +4 -4
  26. package/reference/sdk/framework/agent.mdx +4 -3
  27. package/reference/sdk/framework/index.mdx +1 -1
  28. package/reference/sdk/framework/project-structure.mdx +34 -23
  29. package/reference/sdk/framework/tutorial-system.mdx +1 -1
  30. package/reference/sdk/getting-started.mdx +25 -52
  31. package/reference/sdk/index.mdx +3 -3
  32. package/reference/sdk/platform-tools/adapters-integration.mdx +1 -1
  33. package/reference/sdk/platform-tools/adapters-platform.mdx +1 -1
  34. package/reference/sdk/platform-tools/type-safety.mdx +1 -1
  35. package/reference/sdk/resources/patterns.mdx +10 -11
  36. package/reference/sdk/resources/types.mdx +15 -9
  37. package/reference/sdk/templates/data-enrichment.mdx +1 -1
  38. package/reference/sdk/templates/email-sender.mdx +1 -1
  39. package/reference/sdk/templates/index.mdx +47 -47
  40. package/reference/sdk/templates/lead-scorer.mdx +1 -1
  41. package/reference/sdk/templates/pdf-generator.mdx +42 -24
  42. package/reference/sdk/templates/recurring-job.mdx +20 -15
  43. package/reference/sdk/templates/text-classifier.mdx +1 -1
  44. package/reference/sdk/templates/web-scraper.mdx +9 -5
  45. package/reference/ui/exports.mdx +1 -1
  46. package/reference/ui/index.mdx +2 -2
@@ -15,56 +15,27 @@ cd my-project
15
15
  pnpm install
16
16
  ```
17
17
 
18
- After `pnpm install`, all `elevasis-sdk` commands work via the scripts in `package.json` or `pnpm exec elevasis-sdk <command>`.
18
+ After `pnpm install`, the CLI is available from the project root as `pnpm elevasis-sdk <command>`, which the root `package.json` delegates into `operations/`. Inside `operations/` itself, run `pnpm exec elevasis-sdk <command>` directly.
19
19
 
20
- The project ships with 30 files covering configuration, source, documentation, and Claude Code integration:
20
+ The project is a pnpm workspace containing three packages -- shared config and types, your platform resources, and your frontend:
21
21
 
22
22
  ```
23
23
  my-project/
24
- ├── CLAUDE.md # Project instructions for Claude Code
25
- ├── .claude/
26
- ├── settings.json # autoCompact: false
27
- ├── commands/
28
- │ │ ├── docs.md # Documentation lifecycle
29
- │ │ ├── meta.md # Project lifecycle (init, fix, deploy, health)
30
- │ │ ├── tutorial.md # Progressive learning
31
- │ │ └── work.md # Task tracking
32
- ├── hooks/
33
- │ │ └── enforce-sdk-boundary.mjs # Blocks file modifications outside project (auto-loaded)
34
- │ ├── scripts/
35
- │ │ └── statusline-command.js # Dynamic status line script
36
- │ ├── skills/
37
- │ │ └── creds/SKILL.md # Credential management (auto-triggers)
38
- │ └── rules/
39
- │ ├── sdk-patterns.md # SDK imports, structure, runtime (auto-loaded)
40
- │ ├── docs-authoring.md # MDX conventions (auto-loaded)
41
- │ ├── memory-conventions.md # Memory system conventions (auto-loaded)
42
- │ ├── project-map.md # Project map conventions (auto-loaded)
43
- │ ├── task-tracking.md # Task tracking conventions (auto-loaded)
44
- │ └── workspace-patterns.md # Project-specific patterns (you add these)
45
- ├── src/
46
- │ ├── index.ts # Registry entry point (aggregates domain barrels)
47
- │ ├── operations/
48
- │ │ ├── index.ts # Domain barrel (exports workflows + agents)
49
- │ │ └── platform-status.ts # Platform status workflow (real API example)
50
- │ ├── example/
51
- │ │ ├── index.ts # Domain barrel (exports workflows + agents)
52
- │ │ └── echo.ts # Starter workflow (replace with your own)
53
- │ └── shared/
54
- │ └── .gitkeep # Cross-domain shared utilities
55
- ├── docs/
56
- │ ├── index.mdx # Starter documentation page
57
- │ └── in-progress/
58
- │ └── .gitkeep # Work-in-progress docs directory
59
- ├── elevasis.config.ts # Config with workspace options
60
- ├── package.json # check-types + deploy scripts
61
- ├── tsconfig.json # TypeScript config (app-focused)
62
- ├── pnpm-workspace.yaml # Standalone project workspace
63
- ├── .env # API key only
64
- ├── .npmrc # auto-install-peers
65
- └── .gitignore # Excludes worker temp file, claude files
24
+ ├── CLAUDE.md # Project instructions for Claude Code
25
+ ├── .claude/ # Agent integration: rules, skills, hooks, registries
26
+ ├── core/ # Organization model, knowledge nodes, shared browser-safe types
27
+ ├── operations/ # Workflows, agents, and resource definitions -- what you deploy
28
+ ├── ui/ # Frontend app shell and routes
29
+ ├── package.json # Root scripts that delegate into the three packages
30
+ ├── pnpm-workspace.yaml # Standalone project workspace
31
+ ├── tsconfig.json # Shared TypeScript config
32
+ ├── .env # Platform API key
33
+ ├── .npmrc # auto-install-peers, ignore-workspace-root-check
34
+ └── .gitignore
66
35
  ```
67
36
 
37
+ See [Project Structure](framework/project-structure.mdx) for the full tree, including what lives inside each package.
38
+
68
39
  ### Set Up Your API Key
69
40
 
70
41
  Open `.env` and set your API key:
@@ -81,7 +52,7 @@ The `.env` file is gitignored -- never commit it.
81
52
 
82
53
  After scaffolding, open the project in Claude Code. The agent detects that the project is new and automatically walks you through setup: installing dependencies, configuring `.env`, creating your developer profile in `.claude/memory/`, and optionally running your first deploy. No commands needed -- just answer the questions.
83
54
 
84
- If the automatic setup doesn't trigger, you can start it manually with `/meta init`.
55
+ If the automatic setup doesn't trigger, you can start it manually with `/setup`.
85
56
 
86
57
  ---
87
58
 
@@ -90,13 +61,15 @@ If the automatic setup doesn't trigger, you can start it manually with `/meta in
90
61
  Validate your resources and deploy:
91
62
 
92
63
  ```bash
93
- elevasis-sdk check # Validate resource definitions
94
- elevasis-sdk deploy # Bundle and deploy to the platform
64
+ pnpm check # Validate resource definitions
65
+ pnpm deploy # Bundle and deploy to the platform
95
66
  ```
96
67
 
97
- `elevasis-sdk check` runs validation without deploying. Fix any errors it reports before running `elevasis-sdk deploy`.
68
+ Both root scripts delegate into `operations/`, where the resource registry lives. You can also run `pnpm exec elevasis-sdk check` and `pnpm exec elevasis-sdk deploy` from inside `operations/` directly.
69
+
70
+ `check` runs validation without deploying. Fix any errors it reports before deploying.
98
71
 
99
- `elevasis-sdk deploy` bundles your `src/` code and `docs/` documentation into a single deployment transaction. Both ship atomically -- there is no separate upload step for documentation.
72
+ `deploy` bundles `operations/src/index.ts` and everything it imports into a single JavaScript bundle, then uploads and activates it as one transaction. Use `--entry` if your registry entry point is somewhere other than `./src/index.ts`.
100
73
 
101
74
  After a successful deploy, confirm the resources are live:
102
75
 
@@ -119,7 +92,7 @@ View the execution result:
119
92
 
120
93
  ```bash
121
94
  elevasis-sdk executions echo # Execution history
122
- elevasis-sdk execution echo \<execution-id\> # Full detail for one execution
95
+ elevasis-sdk execution echo <execution-id> # Full detail for one execution
123
96
  ```
124
97
 
125
98
  Replace `<execution-id>` with the ID returned from the executions list.
@@ -134,8 +107,8 @@ Replace `<execution-id>` with the ID returned from the executions list.
134
107
  - [CLI Reference](cli.mdx) -- Full command reference with flags
135
108
  - [Deployment](deployment/index.mdx) -- Deployment lifecycle and environment variables
136
109
 
137
- When a new SDK version is released, run `/meta fix` in Claude Code for an interactive upgrade that includes SDK update, drift repair, and documentation verification. To update the SDK package itself directly, run `pnpm update @elevasis/sdk`.
110
+ When a new SDK version is released, the dependency baseline arrives with the upstream changes rather than through a manual package bump. Run `/git-sync` in Claude Code to pull the latest, install when the baseline moved, and run baseline verification. If packages feel stale or a cache is serving old code afterwards, `/sync` does a fresh reinstall and cache reset.
138
111
 
139
112
  ---
140
113
 
141
- **Last Updated:** 2026-02-27
114
+ **Last Updated:** 2026-08-17
@@ -1,5 +1,5 @@
1
1
  ---
2
- title: Elevasis SDK
2
+ title: "@elevasis/sdk"
3
3
  description: Build and deploy workflows, agents, and resources with the Elevasis SDK
4
4
  ---
5
5
 
@@ -70,8 +70,8 @@ See [Platform Tools](platform-tools/index.mdx) for the full catalog, adapter ref
70
70
 
71
71
  - [Development Framework](framework/index.mdx) - How Claude Code helps you build: project structure, agent integration, and the skill surface
72
72
  - [Project Structure](framework/project-structure.mdx) - Scaffolded file layout, domain barrels, src/index.ts entry point, and config files
73
- - [Agent Configuration](framework/agent.mdx) - The shipped skill inventory, project context via `project:*`, upgrades via `/git-sync`, and the ambient vibe layer
74
- - [Tutorial System](framework/tutorial-system.mdx) - Two-track onboarding: 8 vibe-coder lessons and 19 technical lessons across 5 sections, with track choice persisted to `profile.md`
73
+ - [Agent Configuration](framework/agent.mdx) - The shipped skill inventory, project context via `project:*`, upgrades via `/git-sync`, and ambient vibe layer
74
+ - [Tutorial System](framework/tutorial-system.mdx) - Two-track onboarding: 8 vibe-coder lessons and 19 technical lessons across 5 sections
75
75
 
76
76
  ### Resources Subpages
77
77
 
@@ -13,7 +13,7 @@ Integration adapters use a factory pattern. Call `create*Adapter(credential)` wi
13
13
  | Attio | `createAttioAdapter(credential)` | `createRecord`, `updateRecord`, `listRecords`, `getRecord`, `deleteRecord`, `listObjects`, `listAttributes`, `createAttribute`, `updateAttribute`, `createNote`, `listNotes`, `deleteNote` | Attio CRM — create, read, update, delete records, objects, attributes, and notes. |
14
14
  | Apify | `createApifyAdapter(credential)` | `runActor`, `getDatasetItems`, `startActor` | Apify — run actors and retrieve dataset items from web scraping runs. |
15
15
  | ClickUp | `createClickUpAdapter(credential)` | `verify`, `createTask` | ClickUp — verify connection and create tasks in ClickUp lists. |
16
- | Dropbox | `createDropboxAdapter(credential)` | `uploadFile`, `createFolder` | Dropbox — upload files and create folders. |
16
+ | Dropbox | `createDropboxAdapter(credential)` | `uploadFile`, `createFolder`, `listFolder`, `getMetadata`, `getTemporaryLink`, `createSharedLink`, `download`, `getThumbnail`, `getThumbnailBatch` | Dropbox — upload files and create folders. |
17
17
  | Gmail | `createGmailAdapter(credential)` | `sendEmail` | Gmail — send emails via a bound Gmail credential. |
18
18
  | GoogleSheets | `createGoogleSheetsAdapter(credential)` | `readSheet`, `writeSheet`, `appendRows`, `clearRange`, `getSpreadsheetMetadata`, `batchUpdate`, `getHeaders`, `getLastRow`, `getRowByValue`, `updateRowByValue`, `upsertRow`, `filterRows`, `deleteRowByValue` | Google Sheets — read, write, append, filter, and manage spreadsheet data. |
19
19
  | Instantly | `createInstantlyAdapter(credential)` | `sendReply`, `removeFromSubsequence`, `getEmails`, `updateInterestStatus`, `addToCampaign`, `listCampaigns`, `getCampaign`, `updateCampaign`, `pauseCampaign`, `activateCampaign`, `getCampaignAnalytics`, `getStepAnalytics`, `bulkAddLeads`, `getAccountHealth`, `createInboxTest`, `createCampaign`, `getDailyCampaignAnalytics`, `listLeads`, `bulkDeleteLeads`, `deleteCampaign`, `patchLead` | Instantly — manage email outreach campaigns, leads, analytics, and inbox health. |
@@ -23,4 +23,4 @@ Platform adapters are singletons — import them directly, no credential require
23
23
  | Execution | `execution` | `trigger`, `triggerAsync` | Execution — trigger other workflows or agents within the same organization. |
24
24
  | Email | `email` | `send` | Email — send platform emails (from notifications@elevasis.io) to organization members. |
25
25
  | Artifacts | `artifacts` | `listArtifacts`, `createArtifact`, `getActive` | Artifacts — org-scoped governing-document store, keyed by owner and kind, for acquisition's audits, proposals, and ICP docs. |
26
- | Content | `content` | `createItem`, `getItem`, `listItems`, `updateItem`, `createAttempt`, `listAttempts`, `updateAttempt`, `createSourceAsset`, `getSourceAsset`, `listSourceAssets`, `updateSourceAsset`, `createDistribution`, `updateDistribution` | Content — create, read, and update content_items/content_item_attempts/content_distributions/content_source_assets rows for the content pipeline. |
26
+ | Content | `content` | `createItem`, `getItem`, `listItems`, `updateItem`, `addItemSourceAsset`, `removeItemSourceAsset`, `reorderItemSourceAssets`, `updateItemSourceAsset`, `createAttempt`, `listAttempts`, `updateAttempt`, `createSourceAsset`, `getSourceAsset`, `listSourceAssets`, `updateSourceAsset`, `getDistribution`, `listDistributions`, `createDistribution`, `updateDistribution` | Content — create, read, and update content_items/content_item_attempts/content_distributions/content_source_assets rows for the content pipeline. |
@@ -29,7 +29,7 @@ await llm.generate({
29
29
 
30
30
  ### Tomba Adapter -- `domain` and `email`
31
31
 
32
- `domain` is required on `TombaDomainSearchParams` and `TombaEmailFinderParams`. `email` is required on `TombaEmailVerifierParams`. Previously all params were optional, allowing calls to compile but fail at runtime. The type change enforces the fields that are always necessary for email discovery and verification.
32
+ `domain` is required on `DomainSearchParams` and `EmailFinderParams` (the `domainSearch` and `emailFinder` entries of `TombaToolMap`, defined in `packages/core/src/execution/engine/tools/integration/types/tomba.ts`). `email` is required on `EmailVerifierParams` (the `emailVerifier` entry). Previously all params were optional, allowing calls to compile but fail at runtime. The type change enforces the fields that are always necessary for email discovery and verification.
33
33
 
34
34
  ---
35
35
 
@@ -98,11 +98,11 @@ const scoreStep: WorkflowStep = {
98
98
  type: 'conditional',
99
99
  routes: [
100
100
  {
101
- condition: (output) => output.score \>= 80,
101
+ condition: (output) => output.score >= 80,
102
102
  target: 'autoApprove',
103
103
  },
104
104
  {
105
- condition: (output) => output.score \>= 40,
105
+ condition: (output) => output.score >= 40,
106
106
  target: 'manualReview',
107
107
  },
108
108
  ],
@@ -253,7 +253,7 @@ const validateStep = async (input) => {
253
253
  if (!input.userId) {
254
254
  throw new ExecutionError('userId is required', { code: 'MISSING_INPUT' });
255
255
  }
256
- if (input.amount \<= 0) {
256
+ if (input.amount <= 0) {
257
257
  throw new ExecutionError('amount must be positive', { code: 'INVALID_AMOUNT' });
258
258
  }
259
259
  return { valid: true };
@@ -312,7 +312,7 @@ Avoid logging sensitive values (API keys, passwords, PII) since logs are stored
312
312
 
313
313
  ## Using the Execution Store
314
314
 
315
- `context.store` is a simple key-value store scoped to the current execution. Use it to pass data between steps without coupling step interfaces, or to checkpoint long-running work.
315
+ `context.store` is a plain `Map<string, unknown>` scoped to the current execution. Use it to pass data between steps without coupling step interfaces, or to checkpoint long-running work.
316
316
 
317
317
  {/* doc-snippet:skip: illustrative excerpt -- fetchExpensiveData/transform are placeholder names for your own logic, not a standalone compilable file */}
318
318
 
@@ -324,20 +324,19 @@ const firstStep: StepHandler = async (input, context) => {
324
324
  const data = await fetchExpensiveData(id);
325
325
 
326
326
  // Save for use by later steps
327
- await context.store.set('fetchedData', JSON.stringify(data));
327
+ context.store.set('fetchedData', data);
328
328
 
329
329
  return { fetched: true };
330
330
  };
331
331
 
332
332
  const secondStep: StepHandler = async (input, context) => {
333
- const raw = await context.store.get('fetchedData');
334
- const data = JSON.parse(raw ?? '{}');
333
+ const data = context.store.get('fetchedData');
335
334
 
336
335
  return { processed: transform(data) };
337
336
  };
338
337
  ```
339
338
 
340
- Store values are strings. Serialize objects with `JSON.stringify` and parse with `JSON.parse`.
339
+ `.set()` / `.get()` are synchronous `Map` methods and accept any value directly -- no `JSON.stringify` / `JSON.parse` round-trip required.
341
340
 
342
341
  ---
343
342
 
@@ -381,19 +380,19 @@ config: {
381
380
 
382
381
  ### Global Default Status
383
382
 
384
- Set a project-wide default in `elevasis.config.ts` to keep all resources in `'dev'` mode during development without touching each resource file:
383
+ `config.status` is a required field on every resource definition -- there is currently no CLI-enforced project-wide default. `elevasis.config.ts` declares a `defaultStatus` field on `ElevasConfig` for this purpose, but the CLI does not yet read `elevasis.config.ts` to apply it:
385
384
 
386
385
  ```typescript
387
386
  import type { ElevasConfig } from '@elevasis/sdk';
388
387
 
389
388
  const config: ElevasConfig = {
390
- defaultStatus: 'dev',
389
+ defaultStatus: 'dev', // reserved for future use -- not currently applied
391
390
  };
392
391
 
393
392
  export default config;
394
393
  ```
395
394
 
396
- Individual resources that set their own `config.status` override this default.
395
+ Until the CLI reads this file, set `config.status` explicitly on each resource.
397
396
 
398
397
  ---
399
398
 
@@ -17,20 +17,24 @@ Zod is a peer dependency.
17
17
  {
18
18
  "exports": {
19
19
  ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
20
- "./worker": { "import": "./dist/worker/index.js" }
20
+ "./worker": { "types": "./dist/worker/index.d.ts", "import": "./dist/worker/index.js" },
21
+ "./test-utils": { "types": "./dist/test-utils/index.d.ts", "import": "./dist/test-utils/index.js" },
22
+ "./node": { "types": "./dist/node/index.d.ts", "import": "./dist/node/index.js" }
21
23
  }
22
24
  }
23
25
  ```
24
26
 
25
27
  - `@elevasis/sdk` -- resource, workflow, agent, trigger, deployment, and execution types plus runtime errors.
26
28
  - `@elevasis/sdk/worker` -- worker runtime module, platform adapters, and worker helpers.
29
+ - `@elevasis/sdk/test-utils` -- in-memory registry and mock adapters for testing resources without a live deployment.
30
+ - `@elevasis/sdk/node` -- knowledge codegen and other build-time helpers requiring Node built-ins (`fs`, `path`, `process`); not browser-safe.
27
31
 
28
32
  ## Platform Types
29
33
 
30
34
  | Type | Description |
31
35
  | ----------------------- | --------------------------------------------------------------------------------------------------------------------------- |
32
36
  | `ResourceDefinition` | Base interface for resource definitions |
33
- | `ResourceType` | Resource kind such as `workflow`, `agent`, `trigger`, `integration`, `external`, or `human_checkpoint` |
37
+ | `ResourceType` | Resource kind such as `workflow`, `agent`, `trigger`, `integration`, `external`, or `human` |
34
38
  | `ResourceStatus` | Resource lifecycle status such as `dev` or `prod` |
35
39
  | `ResourceLink` | Graph link `{ nodeId, kind }` binding a resource to an Organization Model node |
36
40
  | `ResourceCategory` | Operational category: `production`, `diagnostic`, `internal`, or `testing` |
@@ -64,9 +68,9 @@ config: {
64
68
  | Type | Description |
65
69
  | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
66
70
  | `WorkflowDefinition` | Complete workflow definition including config, contract, steps, and entryPoint |
67
- | `WorkflowStep` | Individual step definition with type, handler, and next routing |
71
+ | `WorkflowStep` | Individual step definition with `handler`, `inputSchema`, `outputSchema`, and `next` routing -- no `type` field on the step itself |
68
72
  | `WorkflowConfig` | Metadata block: name, description, status, links, category |
69
- | `StepHandler` | Function type: `(input: unknown, context: StepContext) => Promise<unknown>` |
73
+ | `StepHandler` | Function type: `(input: unknown, context: ExecutionContext) => Promise<unknown>` |
70
74
  | `NextConfig` | Union of `LinearNext` and `ConditionalNext` |
71
75
  | `LinearNext` | Fixed next step routing |
72
76
  | `ConditionalNext` | Branching step routing |
@@ -87,10 +91,10 @@ export interface ElevasConfig {
87
91
  }
88
92
  ```
89
93
 
90
- | Field | Type | Default | Description |
91
- | --------------- | -------- | ------- | ----------------------------- | ---------------------------------------------------------------- |
92
- | `defaultStatus` | `'dev' | 'prod'` | `'prod'` | Default status applied when resources do not set `config.status` |
93
- | `dev.port` | `number` | `3001` | Local worker development port |
94
+ | Field | Type | Description |
95
+ | --------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
96
+ | `defaultStatus` | `'dev' | 'prod'` | Reserved for a project-wide default `config.status`. The CLI does not currently read `elevasis.config.ts` to apply it -- `config.status` is required on every resource definition. |
97
+ | `dev.port` | `number` | Reserved for a local worker development port. Not currently read by the CLI. |
94
98
 
95
99
  ## StepHandler Context
96
100
 
@@ -102,11 +106,13 @@ import type { StepHandler, ExecutionContext } from '@elevasis/sdk'
102
106
  const handler: StepHandler = async (input, context: ExecutionContext) => {
103
107
  context.logger.info(`Processing execution ${context.executionId} for resource ${context.resourceId}`)
104
108
 
105
- await context.store.set('checkpoint', JSON.stringify({ step: 'started' }))
109
+ context.store.set('checkpoint', { step: 'started' })
106
110
  return { done: true }
107
111
  }
108
112
  ```
109
113
 
114
+ `context.store` is a plain `Map<string, unknown>` scoped to the current execution -- `.set()` / `.get()` are synchronous and accept any value directly, no `JSON.stringify` / `JSON.parse` round-trip required.
115
+
110
116
  ## Runtime Values
111
117
 
112
118
  Runtime exports include:
@@ -75,7 +75,7 @@ type Input = z.infer<typeof inputSchema>
75
75
 
76
76
  export const dataEnrichment: WorkflowDefinition = {
77
77
  config: {
78
- resourceId: 'data-enrichment',
78
+ resourceId: 'data-enrichment-workflow',
79
79
  name: 'Data Enrichment',
80
80
  type: 'workflow',
81
81
  description: 'Enriches database records using an LLM',
@@ -74,7 +74,7 @@ type Input = z.infer<typeof inputSchema>
74
74
 
75
75
  export const emailSender: WorkflowDefinition = {
76
76
  config: {
77
- resourceId: 'email-sender',
77
+ resourceId: 'email-sender-workflow',
78
78
  name: 'Email Sender',
79
79
  type: 'workflow',
80
80
  description: 'Sends transactional email via Resend',
@@ -1,47 +1,47 @@
1
- ---
2
- title: Templates
3
- description: Ready-to-use workflow templates for common automation patterns -- web scraping, data enrichment, email sending, lead scoring, PDF generation, text classification, and recurring jobs
4
- ---
5
-
6
- Templates are pre-built workflow definitions covering the most common SDK automation patterns. Each template includes a complete `WorkflowDefinition` with Zod schemas, step handlers, and real platform tool usage. Scaffold any template through Claude Code (`/work` then describe the template) or adapt the code manually.
7
-
8
- Templates follow the same `WorkflowDefinition` structure as any custom resource -- they are reference implementations, not a special feature. The patterns demonstrated (multi-step chains, LLM structured output, Supabase CRUD, scheduler setup) apply directly to custom workflows you build.
9
-
10
- All templates are available for any organization. Credentials specific to each template (Supabase, Resend, Apify, etc.) must be created in the command center before running the workflow.
11
-
12
- ## Documentation
13
-
14
- ### Data Collection & Processing
15
-
16
- - [Web Scraper](web-scraper.mdx) - Apify actor runs web scrape, stores structured results in Supabase table
17
- - [Data Enrichment](data-enrichment.mdx) - Reads Supabase records, enriches each with LLM, writes results back; supports batching
18
-
19
- ### Communication & CRM
20
-
21
- - [Email Sender](email-sender.mdx) - Transactional email via Resend with plain text and HTML support, single or multiple recipients
22
- - [Lead Scorer](lead-scorer.mdx) - Multi-criteria LLM lead scoring with configurable rubric and Supabase result storage
23
-
24
- ### Documents & AI
25
-
26
- - [PDF Generator](pdf-generator.mdx) - Renders structured data to PDF, uploads to platform storage, returns signed download URL
27
- - [Text Classifier](text-classifier.mdx) - Multi-label text classification via LLM structured output, configurable categories and confidence scoring
28
-
29
- ### Scheduling
30
-
31
- - [Recurring Job](recurring-job.mdx) - Two-workflow setup pattern: a setup workflow creates the schedule, the job workflow runs on each trigger; uses idempotency keys for safe re-registration
32
-
33
- ## Platform Tools Used
34
-
35
- | Template | Platform Tools | Credentials Needed |
36
- | --------------- | ------------------- | ------------------------------- |
37
- | Web Scraper | `apify`, `supabase` | `apify`, `my-database` |
38
- | Data Enrichment | `llm`, `supabase` | `my-database` (LLM server-side) |
39
- | Email Sender | `resend` | `my-resend` |
40
- | Lead Scorer | `llm`, `supabase` | `my-database` (LLM server-side) |
41
- | PDF Generator | `pdf`, `storage` | None (platform services) |
42
- | Text Classifier | `llm` | None (LLM server-side) |
43
- | Recurring Job | `scheduler` | None (platform service) |
44
-
45
- ---
46
-
47
- **Last Updated:** 2026-03-19
1
+ ---
2
+ title: Templates
3
+ description: Ready-to-use workflow templates for common automation patterns -- web scraping, data enrichment, email sending, lead scoring, PDF generation, text classification, and recurring jobs
4
+ ---
5
+
6
+ Templates are pre-built workflow definitions covering the most common SDK automation patterns. Each template includes a complete `WorkflowDefinition` with Zod schemas, step handlers, and real platform tool usage. Scaffold any template through Claude Code (`/work` then describe the template) or adapt the code manually.
7
+
8
+ Templates follow the same `WorkflowDefinition` structure as any custom resource -- they are reference implementations, not a special feature. The patterns demonstrated (multi-step chains, LLM structured output, Supabase CRUD, scheduler setup) apply directly to custom workflows you build.
9
+
10
+ All templates are available for any organization. Credentials specific to each template (Supabase, Resend, Apify, etc.) must be created in the command center before running the workflow.
11
+
12
+ ## Documentation
13
+
14
+ ### Data Collection & Processing
15
+
16
+ - [Web Scraper](web-scraper.mdx) - Apify actor runs web scrape, stores structured results in Supabase table
17
+ - [Data Enrichment](data-enrichment.mdx) - Reads Supabase records, enriches each with LLM, writes results back; supports batching
18
+
19
+ ### Communication & CRM
20
+
21
+ - [Email Sender](email-sender.mdx) - Transactional email via Resend with plain text and HTML support, single or multiple recipients
22
+ - [Lead Scorer](lead-scorer.mdx) - Multi-criteria LLM lead scoring with configurable rubric and Supabase result storage
23
+
24
+ ### Documents & AI
25
+
26
+ - [PDF Generator](pdf-generator.mdx) - Renders structured data to PDF, uploads to platform storage, returns signed download URL
27
+ - [Text Classifier](text-classifier.mdx) - Multi-label text classification via LLM structured output, configurable categories and confidence scoring
28
+
29
+ ### Scheduling
30
+
31
+ - [Recurring Job](recurring-job.mdx) - Two-workflow setup pattern: a setup workflow creates the schedule, the job workflow runs on trigger
32
+
33
+ ## Platform Tools Used
34
+
35
+ | Template | Platform Tools | Credentials Needed |
36
+ | --------------- | ------------------- | ------------------------------- |
37
+ | Web Scraper | `apify`, `supabase` | `apify`, `my-database` |
38
+ | Data Enrichment | `llm`, `supabase` | `my-database` (LLM server-side) |
39
+ | Email Sender | `resend` | `my-resend` |
40
+ | Lead Scorer | `llm`, `supabase` | `my-database` (LLM server-side) |
41
+ | PDF Generator | `pdf`, `storage` | None (platform services) |
42
+ | Text Classifier | `llm` | None (LLM server-side) |
43
+ | Recurring Job | `scheduler` | None (platform service) |
44
+
45
+ ---
46
+
47
+ **Last Updated:** 2026-03-19
@@ -90,7 +90,7 @@ type Input = z.infer<typeof inputSchema>
90
90
 
91
91
  export const leadScorer: WorkflowDefinition = {
92
92
  config: {
93
- resourceId: 'lead-scorer',
93
+ resourceId: 'lead-scorer-workflow',
94
94
  name: 'Lead Scorer',
95
95
  type: 'workflow',
96
96
  description: 'Scores leads using an LLM and stores results in Supabase',
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "Template: PDF Generator"
3
- description: "PDF generation from structured data with platform storage upload -- render a PDF from a template and upload to platform storage"
3
+ description: "PDF generation from structured data with platform storage upload -- render a PDF from typed content blocks and upload to platform storage"
4
4
  loadWhen: "Applying the pdf-generator workflow template"
5
5
  ---
6
6
 
@@ -16,7 +16,9 @@ loadWhen: "Applying the pdf-generator workflow template"
16
16
 
17
17
  ## What This Workflow Does
18
18
 
19
- Receives structured data, renders a PDF using an HTML template, uploads the result to platform storage, and returns a signed URL for download. Suitable for invoices, reports, certificates, contracts, and any document that needs to be generated on demand and delivered as a downloadable file.
19
+ Receives structured content (a title, body text, and an optional data table), renders it to a PDF using the platform's declarative document builder, uploads the result to platform storage, and returns a signed URL for download. Suitable for invoices, reports, certificates, contracts, and any document that needs to be generated on demand and delivered as a downloadable file.
20
+
21
+ The platform's `pdf` tool does not accept raw HTML -- it renders a JSON document tree of typed content blocks (`text`, `metric`, `list`, `table`, `card`, `columns`). This template covers the common `text` + `table` case; adapt the `sections` array for other block types.
20
22
 
21
23
  ---
22
24
 
@@ -26,8 +28,10 @@ Receives structured data, renders a PDF using an HTML template, uploads the resu
26
28
 
27
29
  ```typescript
28
30
  z.object({
29
- templateHtml: z.string(), // HTML template with {variable} placeholders
30
- data: z.record(z.string(), z.unknown()), // Data to inject into the template
31
+ title: z.string(), // Document title, rendered as the page heading
32
+ bodyText: z.string(), // Main body paragraph
33
+ tableHeaders: z.array(z.string()).optional(), // Optional data table column headers
34
+ tableRows: z.array(z.array(z.string())).optional(), // Optional data table rows
31
35
  filename: z.string(), // Output filename (without .pdf extension)
32
36
  expiresInSeconds: z.number().optional(), // Signed URL expiry (default: 3600)
33
37
  })
@@ -56,8 +60,10 @@ import { platform } from '@elevasis/sdk/worker'
56
60
  import { z } from 'zod'
57
61
 
58
62
  const inputSchema = z.object({
59
- templateHtml: z.string(),
60
- data: z.record(z.string(), z.unknown()),
63
+ title: z.string(),
64
+ bodyText: z.string(),
65
+ tableHeaders: z.array(z.string()).optional(),
66
+ tableRows: z.array(z.array(z.string())).optional(),
61
67
  filename: z.string(),
62
68
  expiresInSeconds: z.number().optional(),
63
69
  })
@@ -69,16 +75,12 @@ const outputSchema = z.object({
69
75
 
70
76
  type Input = z.infer<typeof inputSchema>
71
77
 
72
- function renderTemplate(html: string, data: Record<string, unknown>): string {
73
- return html.replace(/\{(\w+)\}/g, (_, key) => String(data[key] ?? ''))
74
- }
75
-
76
78
  export const pdfGenerator: WorkflowDefinition = {
77
79
  config: {
78
- resourceId: 'pdf-generator',
80
+ resourceId: 'pdf-generator-workflow',
79
81
  name: 'PDF Generator',
80
82
  type: 'workflow',
81
- description: 'Generates a PDF from HTML template and uploads to storage',
83
+ description: 'Generates a PDF from structured content blocks and uploads to storage',
82
84
  version: '1.0.0',
83
85
  status: 'dev',
84
86
  },
@@ -87,17 +89,30 @@ export const pdfGenerator: WorkflowDefinition = {
87
89
  render: {
88
90
  id: 'render',
89
91
  name: 'Render PDF',
90
- description: 'Render HTML template to PDF buffer',
92
+ description: 'Render a structured document to a PDF buffer',
91
93
  inputSchema,
92
94
  outputSchema: z.object({ buffer: z.string(), filename: z.string(), expiresInSeconds: z.number() }),
93
95
  handler: async (input) => {
94
- const { templateHtml, data, filename, expiresInSeconds } = input as Input
95
- const html = renderTemplate(templateHtml, data)
96
+ const { title, bodyText, tableHeaders, tableRows, filename, expiresInSeconds } = input as Input
97
+
98
+ const document = {
99
+ pages: [
100
+ {
101
+ sections: [
102
+ { type: 'text' as const, content: title, variant: 'title' as const },
103
+ { type: 'text' as const, content: bodyText, variant: 'body' as const },
104
+ ...(tableHeaders && tableRows
105
+ ? [{ type: 'table' as const, headers: tableHeaders, rows: tableRows }]
106
+ : []),
107
+ ],
108
+ },
109
+ ],
110
+ }
96
111
 
97
112
  const result = await platform.call({
98
113
  tool: 'pdf',
99
114
  method: 'renderToBuffer',
100
- params: { html },
115
+ params: { document },
101
116
  }) as { buffer: string } // base64-encoded buffer
102
117
 
103
118
  return { buffer: result.buffer, filename, expiresInSeconds: expiresInSeconds ?? 3600 }
@@ -112,13 +127,15 @@ export const pdfGenerator: WorkflowDefinition = {
112
127
  outputSchema,
113
128
  handler: async (input, context) => {
114
129
  const { buffer, filename, expiresInSeconds } = input as { buffer: string; filename: string; expiresInSeconds: number }
115
- const key = `documents/${filename}-${Date.now()}.pdf`
130
+ const bucket = 'documents'
131
+ const path = `${filename}-${Date.now()}.pdf`
116
132
 
117
133
  await platform.call({
118
134
  tool: 'storage',
119
135
  method: 'upload',
120
136
  params: {
121
- key,
137
+ bucket,
138
+ path,
122
139
  content: buffer,
123
140
  contentType: 'application/pdf',
124
141
  },
@@ -127,11 +144,11 @@ export const pdfGenerator: WorkflowDefinition = {
127
144
  const urlResult = await platform.call({
128
145
  tool: 'storage',
129
146
  method: 'createSignedUrl',
130
- params: { key, expiresIn: expiresInSeconds },
147
+ params: { bucket, path, expiresIn: expiresInSeconds },
131
148
  }) as { signedUrl: string; expiresAt: string }
132
149
 
133
- context.logger.info(`PDF generated and uploaded: ${filename} at ${key}`)
134
- return { downloadUrl: urlResult.signedUrl, storageKey: key, expiresAt: urlResult.expiresAt }
150
+ context.logger.info(`PDF generated and uploaded: ${filename} at ${bucket}/${path}`)
151
+ return { downloadUrl: urlResult.signedUrl, storageKey: `${bucket}/${path}`, expiresAt: urlResult.expiresAt }
135
152
  },
136
153
  next: null,
137
154
  },
@@ -144,11 +161,12 @@ export const pdfGenerator: WorkflowDefinition = {
144
161
 
145
162
  ## Adaptation Notes
146
163
 
147
- - **Template format:** The simple `{variable}` placeholder system handles most cases. For complex documents, suggest the user write a more complete HTML template with inline CSS.
164
+ - **Content blocks:** The `pdf` tool renders a JSON document tree, not HTML. This template covers `text` and `table` blocks; add `metric`, `list`, `card`, or `columns` blocks to `sections` for richer layouts.
165
+ - **Storage bucket:** The template hardcodes `bucket = 'documents'`. Ask the user what bucket name their organization's platform storage is configured to use.
148
166
  - **Filename:** The template appends a timestamp to avoid collisions. Adapt naming to the user's convention (e.g., `invoice-{invoiceId}`).
149
167
  - **Expiry:** Default is 1 hour. For document delivery workflows, increase to 24-72 hours.
150
- - **Data structure:** Ask the user what fields their document needs before defining the `data` schema. For typed use cases (invoices, reports), define a stricter input schema.
151
- - **Skill adaptation:** For beginners, show a complete example HTML template and explain what "template variables" are.
168
+ - **Data structure:** Ask the user what fields their document needs before defining the input schema and mapping it into `sections`. For typed use cases (invoices, reports), add more input fields and a matching table row or card per field group.
169
+ - **Skill adaptation:** For beginners, walk through the difference between a JSON document tree and an HTML template before generating code.
152
170
 
153
171
  ---
154
172