@elevasis/sdk 1.20.2 → 1.22.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 (164) hide show
  1. package/dist/cli.cjs +4220 -1583
  2. package/dist/index.d.ts +1035 -481
  3. package/dist/index.js +7381 -4187
  4. package/dist/node/index.d.ts +1 -3
  5. package/dist/node/index.js +40 -49
  6. package/dist/test-utils/index.d.ts +699 -123
  7. package/dist/test-utils/index.js +3826 -630
  8. package/dist/worker/index.js +3616 -442
  9. package/package.json +3 -3
  10. package/reference/_navigation.md +9 -7
  11. package/reference/_reference-manifest.json +1 -1
  12. package/reference/claude-config/hooks/post-edit-validate.mjs +98 -98
  13. package/reference/claude-config/hooks/scaffold-registry-reminder.mjs +188 -188
  14. package/reference/claude-config/hooks/tool-failure-recovery.mjs +73 -73
  15. package/reference/claude-config/registries/graph-skills.json +4 -4
  16. package/reference/claude-config/registries/knowledge-flags.json +0 -2
  17. package/reference/claude-config/rules/active-change-index.md +80 -80
  18. package/reference/claude-config/rules/agent-start-here.md +277 -273
  19. package/reference/claude-config/rules/deployment.md +57 -57
  20. package/reference/claude-config/rules/error-handling.md +56 -56
  21. package/reference/claude-config/rules/execution.md +40 -40
  22. package/reference/claude-config/rules/frontend.md +4 -4
  23. package/reference/claude-config/rules/observability.md +31 -31
  24. package/reference/claude-config/rules/operations.md +29 -17
  25. package/reference/claude-config/rules/organization-model.md +108 -40
  26. package/reference/claude-config/rules/organization-os.md +115 -113
  27. package/reference/claude-config/rules/package-taxonomy.md +33 -33
  28. package/reference/claude-config/rules/platform.md +42 -42
  29. package/reference/claude-config/rules/shared-types.md +49 -46
  30. package/reference/claude-config/rules/task-tracking.md +47 -47
  31. package/reference/claude-config/rules/ui.md +200 -200
  32. package/reference/claude-config/rules/vibe.md +235 -231
  33. package/reference/claude-config/scripts/statusline-command.js +18 -18
  34. package/reference/claude-config/settings.json +34 -34
  35. package/reference/claude-config/skills/deploy/{SKILL.md → skill.md} +156 -156
  36. package/reference/claude-config/skills/dsp/SKILL.md +66 -66
  37. package/reference/claude-config/skills/elevasis/SKILL.md +235 -235
  38. package/reference/claude-config/skills/explore/SKILL.md +6 -6
  39. package/reference/claude-config/skills/git-sync/SKILL.md +126 -126
  40. package/reference/claude-config/skills/knowledge/SKILL.md +330 -271
  41. package/reference/claude-config/skills/knowledge/operations/codify-level-a.md +100 -100
  42. package/reference/claude-config/skills/knowledge/operations/codify-level-b.md +159 -158
  43. package/reference/claude-config/skills/knowledge/operations/customers.md +109 -109
  44. package/reference/claude-config/skills/knowledge/operations/features.md +76 -113
  45. package/reference/claude-config/skills/knowledge/operations/goals.md +118 -118
  46. package/reference/claude-config/skills/knowledge/operations/identity.md +93 -93
  47. package/reference/claude-config/skills/knowledge/operations/labels.md +94 -89
  48. package/reference/claude-config/skills/knowledge/operations/offerings.md +109 -109
  49. package/reference/claude-config/skills/knowledge/operations/roles.md +99 -99
  50. package/reference/claude-config/skills/knowledge/operations/techStack.md +30 -30
  51. package/reference/claude-config/skills/project/SKILL.md +1088 -1088
  52. package/reference/claude-config/skills/run-ui/SKILL.md +73 -73
  53. package/reference/claude-config/skills/save/SKILL.md +3 -3
  54. package/reference/claude-config/skills/setup/SKILL.md +275 -275
  55. package/reference/claude-config/skills/status/SKILL.md +59 -59
  56. package/reference/claude-config/skills/submit-request/SKILL.md +180 -180
  57. package/reference/claude-config/skills/sync/SKILL.md +47 -47
  58. package/reference/claude-config/skills/tutorial/SKILL.md +259 -259
  59. package/reference/claude-config/skills/tutorial/progress-template.md +74 -74
  60. package/reference/claude-config/skills/tutorial/technical.md +1303 -1306
  61. package/reference/claude-config/skills/tutorial/vibe-coder.md +890 -890
  62. package/reference/claude-config/sync-notes/2026-04-22-git-sync-and-sync-notes.md +27 -27
  63. package/reference/claude-config/sync-notes/2026-04-22-lead-gen-deliverability-removal.md +30 -30
  64. package/reference/claude-config/sync-notes/2026-04-24-test-utils-and-template-tests.md +73 -73
  65. package/reference/claude-config/sync-notes/2026-04-24-ui-consolidation-and-sdk-cli-train.md +86 -86
  66. package/reference/claude-config/sync-notes/2026-04-25-auth-role-system-and-settings-roles.md +55 -55
  67. package/reference/claude-config/sync-notes/2026-04-27-crm-hitl-action-layer-cutover.md +97 -97
  68. package/reference/claude-config/sync-notes/2026-04-27-lead-gen-substrate-train.md +112 -112
  69. package/reference/claude-config/sync-notes/2026-04-29-crm-state-and-lead-gen-processing-status.md +93 -93
  70. package/reference/claude-config/sync-notes/2026-05-02-crm-ownership-next-action.md +58 -58
  71. package/reference/claude-config/sync-notes/2026-05-02-template-hardcode-workos-config.md +56 -56
  72. package/reference/claude-config/sync-notes/2026-05-04-elevasis-workspace.md +71 -71
  73. package/reference/claude-config/sync-notes/2026-05-04-knowledge-bundle.md +83 -83
  74. package/reference/claude-config/sync-notes/2026-05-04-template-skills-run-ui-and-tutorial.md +59 -59
  75. package/reference/claude-config/sync-notes/2026-05-05-list-builder.md +42 -42
  76. package/reference/claude-config/sync-notes/2026-05-06-crm-spine.md +60 -60
  77. package/reference/claude-config/sync-notes/2026-05-06-sdk-changes-release-train.md +37 -37
  78. package/reference/claude-config/sync-notes/2026-05-07-sdk-changes-release-train.md +34 -34
  79. package/reference/claude-config/sync-notes/2026-05-08-resource-governance-scaffold-guidance.md +38 -38
  80. package/reference/claude-config/sync-notes/2026-05-09-clients-domain.md +32 -32
  81. package/reference/claude-config/sync-notes/2026-05-09-command-system.md +33 -33
  82. package/reference/claude-config/sync-notes/2026-05-09-resource-governance-and-misc.md +69 -69
  83. package/reference/claude-config/sync-notes/2026-05-12-sdk-ready-release-train.md +30 -0
  84. package/reference/claude-config/sync-notes/2026-05-14-organization-model-ontology-refactor.md +42 -0
  85. package/reference/claude-config/sync-notes/README.md +43 -43
  86. package/reference/cli.mdx +808 -668
  87. package/reference/concepts.mdx +146 -146
  88. package/reference/deployment/api.mdx +297 -297
  89. package/reference/deployment/command-center.mdx +209 -209
  90. package/reference/deployment/index.mdx +195 -195
  91. package/reference/deployment/provided-features.mdx +107 -93
  92. package/reference/deployment/ui-execution.mdx +250 -250
  93. package/reference/examples/organization-model.ts +147 -84
  94. package/reference/framework/agent.mdx +156 -156
  95. package/reference/framework/index.mdx +195 -195
  96. package/reference/framework/interaction-guidance.mdx +182 -182
  97. package/reference/framework/memory.mdx +326 -326
  98. package/reference/framework/project-structure.mdx +282 -282
  99. package/reference/framework/tutorial-system.mdx +135 -135
  100. package/reference/getting-started.mdx +142 -142
  101. package/reference/index.mdx +106 -106
  102. package/reference/packages/core/src/README.md +14 -14
  103. package/reference/packages/core/src/business/README.md +2 -2
  104. package/reference/packages/core/src/knowledge/README.md +33 -32
  105. package/reference/packages/core/src/organization-model/README.md +149 -109
  106. package/reference/packages/core/src/test-utils/README.md +37 -37
  107. package/reference/packages/ui/src/api/README.md +18 -18
  108. package/reference/packages/ui/src/app/README.md +24 -24
  109. package/reference/packages/ui/src/auth/README.md +18 -18
  110. package/reference/packages/ui/src/components/README.md +24 -24
  111. package/reference/packages/ui/src/execution/README.md +16 -16
  112. package/reference/packages/ui/src/features/README.md +28 -28
  113. package/reference/packages/ui/src/graph/README.md +16 -16
  114. package/reference/packages/ui/src/hooks/README.md +23 -23
  115. package/reference/packages/ui/src/initialization/README.md +19 -19
  116. package/reference/packages/ui/src/knowledge/README.md +31 -31
  117. package/reference/packages/ui/src/organization/README.md +18 -18
  118. package/reference/packages/ui/src/profile/README.md +19 -19
  119. package/reference/packages/ui/src/provider/README.md +32 -32
  120. package/reference/packages/ui/src/router/README.md +18 -18
  121. package/reference/packages/ui/src/sse/README.md +13 -13
  122. package/reference/packages/ui/src/test-utils/README.md +7 -7
  123. package/reference/packages/ui/src/theme/README.md +23 -23
  124. package/reference/packages/ui/src/theme/presets/README.md +19 -19
  125. package/reference/packages/ui/src/types/README.md +16 -16
  126. package/reference/packages/ui/src/utils/README.md +18 -18
  127. package/reference/packages/ui/src/zustand/README.md +18 -18
  128. package/reference/platform-tools/adapters-integration.mdx +301 -301
  129. package/reference/platform-tools/adapters-platform.mdx +553 -553
  130. package/reference/platform-tools/index.mdx +217 -217
  131. package/reference/platform-tools/type-safety.mdx +82 -82
  132. package/reference/resources/index.mdx +349 -349
  133. package/reference/resources/patterns.mdx +449 -449
  134. package/reference/resources/types.mdx +116 -116
  135. package/reference/roadmap.mdx +165 -165
  136. package/reference/runtime.mdx +173 -173
  137. package/reference/scaffold/core/organization-graph.mdx +110 -89
  138. package/reference/scaffold/core/organization-model.mdx +226 -171
  139. package/reference/scaffold/index.mdx +67 -67
  140. package/reference/scaffold/operations/propagation-pipeline.md +77 -77
  141. package/reference/scaffold/operations/scaffold-maintenance.md +10 -10
  142. package/reference/scaffold/operations/workflow-recipes.md +138 -138
  143. package/reference/scaffold/recipes/add-a-feature.md +310 -88
  144. package/reference/scaffold/recipes/add-a-resource.md +137 -117
  145. package/reference/scaffold/recipes/customize-crm-actions.md +439 -439
  146. package/reference/scaffold/recipes/customize-knowledge-browser.md +384 -0
  147. package/reference/scaffold/recipes/customize-organization-model.md +281 -118
  148. package/reference/scaffold/recipes/extend-a-base-entity.md +8 -8
  149. package/reference/scaffold/recipes/extend-crm.md +40 -39
  150. package/reference/scaffold/recipes/extend-lead-gen.md +400 -401
  151. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +118 -114
  152. package/reference/scaffold/recipes/index.md +47 -46
  153. package/reference/scaffold/recipes/query-the-knowledge-graph.md +227 -0
  154. package/reference/scaffold/reference/contracts.md +2389 -2121
  155. package/reference/scaffold/reference/feature-registry.md +9 -20
  156. package/reference/scaffold/reference/glossary.md +76 -76
  157. package/reference/scaffold/ui/composition-extensibility.mdx +233 -233
  158. package/reference/scaffold/ui/customization.md +243 -243
  159. package/reference/scaffold/ui/feature-flags-and-gating.md +46 -46
  160. package/reference/scaffold/ui/feature-shell.mdx +72 -72
  161. package/reference/scaffold/ui/recipes.md +221 -213
  162. package/reference/spine/spine-primer.md +96 -96
  163. package/reference/templates/index.mdx +47 -47
  164. package/reference/troubleshooting.mdx +223 -223
@@ -1,349 +1,349 @@
1
- ---
2
- title: Writing Resources
3
- description: Guide to creating descriptor-backed workflows and agents with the Elevasis SDK
4
- loadWhen: "Building or modifying a workflow"
5
- ---
6
-
7
- Resources are the building blocks of your Elevasis project. Resource identity and governance metadata live in the Organization Model under `organizationModel.resources.entries`; operations code imports those descriptors, attaches executable workflow or agent behavior, and exports a `DeploymentSpec` for deployment.
8
-
9
- This page covers how to structure executable resources, derive runtime IDs from OM descriptors, write step handlers, and assemble the deployment spec without creating a second identity catalog.
10
-
11
- ## WorkflowDefinition
12
-
13
- A workflow is a series of named steps executed in sequence or branching paths. You define it with a `WorkflowDefinition` object.
14
-
15
- A complete workflow definition has four required properties:
16
-
17
- - `config` - metadata about the workflow (name, description, status)
18
- - `contract` - Zod schemas for input and output validation
19
- - `steps` - a record of named step handlers
20
- - `entryPoint` - the name of the first step to execute
21
-
22
- ### Minimal Example
23
-
24
- ```typescript
25
- import { z } from 'zod';
26
- import type { WorkflowDefinition } from '@elevasis/sdk';
27
- import { resourceDescriptors } from '@core/config/organization-model';
28
-
29
- const echoInput = z.object({
30
- message: z.string(),
31
- });
32
-
33
- const echoOutput = z.object({
34
- result: z.string(),
35
- });
36
-
37
- type EchoInput = z.infer<typeof echoInput>;
38
-
39
- const echoWorkflow: WorkflowDefinition = {
40
- config: {
41
- resource: resourceDescriptors.echo,
42
- resourceId: resourceDescriptors.echo.id,
43
- name: 'Echo',
44
- type: resourceDescriptors.echo.kind,
45
- description: 'Returns the input message unchanged',
46
- version: '1.0.0',
47
- status: 'dev',
48
- },
49
- contract: {
50
- inputSchema: echoInput,
51
- outputSchema: echoOutput,
52
- },
53
- steps: {
54
- run: {
55
- id: 'run',
56
- name: 'Run',
57
- description: 'Returns the input message unchanged',
58
- handler: async (input) => {
59
- const { message } = input as EchoInput;
60
- return { result: message };
61
- },
62
- inputSchema: echoInput,
63
- outputSchema: echoOutput,
64
- next: null,
65
- },
66
- },
67
- entryPoint: 'run',
68
- };
69
- ```
70
-
71
- ### config
72
-
73
- The `config` block binds executable behavior to the OM resource descriptor:
74
-
75
- | Field | Type | Description |
76
- | ------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
77
- | `resource` | `ResourceEntry` | OM descriptor from `core/config/organization-model.ts`; owns stable identity, kind, system membership, ownership, and status. |
78
- | `resourceId` | `string` | Derived from `resource.id`. Used by runtime invocation, CLI targeting, execution logs, and dashboard links. Do not invent it here. |
79
- | `name` | `string` | Human-readable display name shown in the dashboard. |
80
- | `type` | `'workflow'` | Derived from `resource.kind` for workflow resources. |
81
- | `description` | `string` | Summary shown in the dashboard and command center. |
82
- | `version` | `string` | Semver string (e.g., `'1.0.0'`). Increment when making breaking changes to the contract. |
83
- | `status` | `'dev' | 'prod'` | Controls runtime availability. Use `'dev'` while building. See [Resource Status](#resource-status). |
84
- | `domains` | `string[]` | Optional. Groups resources in the command center view. |
85
-
86
- ### contract
87
-
88
- The `contract` block defines the Zod schemas for input and output. The platform validates input against `contract.inputSchema` before passing it to your entry step handler, and validates the final step's return value against `contract.outputSchema`.
89
-
90
- Always use `z.object()` for both schemas. Use `z.infer` to derive TypeScript types -- this keeps types and runtime validation in sync automatically.
91
-
92
- ```typescript
93
- const contract = {
94
- inputSchema: z.object({
95
- userId: z.string().uuid(),
96
- action: z.string(),
97
- }),
98
- outputSchema: z.object({
99
- success: z.boolean(),
100
- message: z.string(),
101
- }),
102
- };
103
- ```
104
-
105
- ### steps
106
-
107
- The `steps` record maps step IDs to step objects. Each step has metadata (`id`, `name`, `description`), a `handler` function, Zod schemas for its own input and output, and a `next` property that controls routing.
108
-
109
- ```typescript
110
- const steps = {
111
- validate: {
112
- id: 'validate',
113
- name: 'Validate',
114
- description: 'Validates the incoming request',
115
- handler: async (input: MyInput) => {
116
- return { validated: true, data: input };
117
- },
118
- inputSchema: myInputSchema,
119
- outputSchema: z.object({ validated: z.boolean(), data: myInputSchema }),
120
- next: { type: 'linear', target: 'process' }, // points to the next step
121
- },
122
- process: {
123
- id: 'process',
124
- name: 'Process',
125
- description: 'Processes the validated data',
126
- handler: async (input: ValidatedData) => {
127
- return { result: 'done' };
128
- },
129
- inputSchema: z.object({ validated: z.boolean(), data: myInputSchema }),
130
- outputSchema: z.object({ result: z.string() }),
131
- next: null, // terminal step
132
- },
133
- };
134
- ```
135
-
136
- ### entryPoint
137
-
138
- `entryPoint` is the name of the first step. For single-step workflows it is always the only step name. For multi-step workflows it is the name of the first step in the chain.
139
-
140
- ```typescript
141
- const workflow: WorkflowDefinition = {
142
- // ...
143
- entryPoint: 'validate', // execution starts here
144
- };
145
- ```
146
-
147
- ---
148
-
149
- ## Multi-Step Workflows
150
-
151
- For workflows with more than one step, import `StepType` from `@elevasis/sdk` to configure step routing.
152
-
153
- ### Linear Steps
154
-
155
- Use `StepType.LINEAR` to connect steps in a fixed sequence. Each step declares a `next` property pointing to the next step name.
156
-
157
- ```typescript
158
- import { z } from 'zod';
159
- import type { WorkflowDefinition, WorkflowStep } from '@elevasis/sdk';
160
-
161
- const fetchStep: WorkflowStep = {
162
- id: 'fetch',
163
- name: 'Fetch',
164
- description: 'Fetches the raw data',
165
- handler: async (input) => {
166
- const data = await fetchSomething((input as { id: string }).id);
167
- return { data };
168
- },
169
- inputSchema: z.object({ id: z.string() }),
170
- outputSchema: z.object({ data: z.unknown() }),
171
- next: { type: 'linear', target: 'process' },
172
- };
173
-
174
- const processStep: WorkflowStep = {
175
- id: 'process',
176
- name: 'Process',
177
- description: 'Transforms the fetched data',
178
- handler: async (input) => {
179
- return { result: transform((input as { data: unknown }).data) };
180
- },
181
- inputSchema: z.object({ data: z.unknown() }),
182
- outputSchema: z.object({ result: z.string() }),
183
- next: null, // terminal step
184
- };
185
-
186
- const pipeline: WorkflowDefinition = {
187
- config: {
188
- resourceId: 'pipeline',
189
- name: 'Pipeline',
190
- type: 'workflow',
191
- description: 'Fetch then process',
192
- version: '1.0.0',
193
- status: 'dev',
194
- },
195
- contract: { inputSchema: pipelineInput, outputSchema: pipelineOutput },
196
- steps: { fetch: fetchStep, process: processStep },
197
- entryPoint: 'fetch',
198
- };
199
- ```
200
-
201
- ### Conditional Branching
202
-
203
- Use `StepType.CONDITIONAL` to route to different steps based on output values. Each route has a `condition` function and a `target` step name. The first condition that returns `true` wins. A `default` fallback step is required.
204
-
205
- ```typescript
206
- import { z } from 'zod';
207
- import type { WorkflowStep } from '@elevasis/sdk';
208
-
209
- const routerStep: WorkflowStep = {
210
- id: 'router',
211
- name: 'Router',
212
- description: 'Scores the input and routes to the appropriate path',
213
- handler: async (input) => {
214
- const score = await evaluate(input);
215
- return { score };
216
- },
217
- inputSchema: z.object({ value: z.unknown() }),
218
- outputSchema: z.object({ score: z.number() }),
219
- next: {
220
- type: 'conditional',
221
- routes: [
222
- {
223
- condition: (output) => (output as { score: number }).score \>= 80,
224
- target: 'highScorePath',
225
- },
226
- {
227
- condition: (output) => (output as { score: number }).score \>= 50,
228
- target: 'mediumScorePath',
229
- },
230
- ],
231
- default: 'lowScorePath',
232
- },
233
- };
234
- ```
235
-
236
- ---
237
-
238
- ## StepContext
239
-
240
- Every step handler can optionally accept a second `context` parameter. TypeScript allows you to omit it if you do not need it -- you can write `handler: async (input) => { ... }` without declaring `context`.
241
-
242
- When you do need it, the context provides runtime metadata:
243
-
244
- ```typescript
245
- import type { StepHandler } from '@elevasis/sdk';
246
-
247
- const myStep: StepHandler = async (input, context) => {
248
- const { executionId, organizationId, resourceId, logger, store } = context;
249
-
250
- logger.info('Starting step', { executionId });
251
-
252
- // store is a simple key-value store scoped to this execution
253
- await store.set('progress', '50%');
254
-
255
- return { done: true };
256
- };
257
- ```
258
-
259
- | Field | Type | Description |
260
- | ---------------- | -------- | -------------------------------------------------------------- |
261
- | `executionId` | `string` | Unique ID for this execution run |
262
- | `organizationId` | `string` | Your organization ID |
263
- | `resourceId` | `string` | ID of the workflow or agent being executed |
264
- | `logger` | `Logger` | Structured logger -- messages appear in the Elevasis dashboard |
265
- | `store` | `Store` | Key-value store scoped to the current execution |
266
-
267
- ---
268
-
269
- ## AgentDefinition
270
-
271
- Agents are autonomous resources that use an LLM and tools to complete a goal. You define them with `AgentDefinition`.
272
-
273
- **Note:** Use `elevasis-sdk exec --async` when executing agents. Agents can run for minutes or longer, and the synchronous execute endpoint will time out for long-running runs. The `--async` flag returns an execution ID immediately and polls for the result.
274
-
275
- ```typescript
276
- import type { AgentDefinition } from '@elevasis/sdk';
277
- import { resourceDescriptors } from '@core/config/organization-model';
278
-
279
- const myAgent: AgentDefinition = {
280
- config: {
281
- resource: resourceDescriptors.myAgent,
282
- resourceId: resourceDescriptors.myAgent.id,
283
- name: 'my-agent',
284
- type: resourceDescriptors.myAgent.kind,
285
- description: 'Answers questions using platform tools',
286
- status: 'dev',
287
- },
288
- agentConfig: {
289
- model: { provider: 'openai', model: 'gpt-4o' },
290
- systemPrompt: 'You are a helpful assistant.',
291
- maxIterations: 10,
292
- },
293
- tools: [],
294
- };
295
- ```
296
-
297
- ---
298
-
299
- ## DeploymentSpec
300
-
301
- All executable resources must be assembled through a `DeploymentSpec` default export from `operations/src/index.ts`. This is the entry point the platform reads when you deploy. Include the Organization Model payload so the validator can compare code-backed resources against OM descriptors.
302
-
303
- ```typescript
304
- import type { DeploymentSpec } from '@elevasis/sdk';
305
- import { resourceGovernanceModel } from '@core/config/organization-model';
306
-
307
- const org: DeploymentSpec = {
308
- version: '0.1.0',
309
- organizationModel: resourceGovernanceModel,
310
- workflows: [echoWorkflow, pipeline],
311
- agents: [
312
- // myAgent,
313
- ],
314
- };
315
-
316
- export default org;
317
- ```
318
-
319
- Each resource's `config.resourceId` is still the deployed runtime identifier. The important authoring rule is that `config.resourceId` derives from the OM descriptor (`resource.id`) instead of being duplicated by hand.
320
-
321
- ### Resource Status
322
-
323
- Set `config.status` to control whether the platform accepts execution requests:
324
-
325
- - `'dev'` - Resource is visible in the dashboard but the platform will not route scheduled or webhook-triggered executions to it. You can still trigger it manually via `elevasis-sdk exec`.
326
- - `'prod'` - Resource is live and accepts all execution sources.
327
-
328
- Use `'dev'` while you are building and testing. Switch to `'prod'` when you are ready to go live.
329
-
330
- You can also set a global default status in `elevasis.config.ts`:
331
-
332
- ```typescript
333
- import type { ElevasConfig } from '@elevasis/sdk';
334
-
335
- const config: ElevasConfig = {
336
- defaultStatus: 'dev',
337
- };
338
-
339
- export default config;
340
- ```
341
-
342
- ## Documentation
343
-
344
- - [SDK Types](types.mdx) - Complete type reference for `@elevasis/sdk` exports, config, and step handler context
345
- - [Common Patterns](patterns.mdx) - Sequential steps, conditional branching, error handling, and resource status patterns
346
-
347
- ---
348
-
349
- **Last Updated:** 2026-02-25
1
+ ---
2
+ title: Writing Resources
3
+ description: Guide to creating descriptor-backed workflows and agents with the Elevasis SDK
4
+ loadWhen: "Building or modifying a workflow"
5
+ ---
6
+
7
+ Resources are the building blocks of your Elevasis project. Resource identity and governance metadata live in the Organization Model under the id-keyed `organizationModel.resources` map; operations code imports those descriptors, attaches executable workflow or agent behavior, and exports a `DeploymentSpec` for deployment.
8
+
9
+ This page covers how to structure executable resources, derive runtime IDs from OM descriptors, write step handlers, and assemble the deployment spec without creating a second identity catalog.
10
+
11
+ ## WorkflowDefinition
12
+
13
+ A workflow is a series of named steps executed in sequence or branching paths. You define it with a `WorkflowDefinition` object.
14
+
15
+ A complete workflow definition has four required properties:
16
+
17
+ - `config` - metadata about the workflow (name, description, status)
18
+ - `contract` - Zod schemas for input and output validation
19
+ - `steps` - a record of named step handlers
20
+ - `entryPoint` - the name of the first step to execute
21
+
22
+ ### Minimal Example
23
+
24
+ ```typescript
25
+ import { z } from 'zod';
26
+ import type { WorkflowDefinition } from '@elevasis/sdk';
27
+ import { resourceDescriptors } from '@core/config/organization-model';
28
+
29
+ const echoInput = z.object({
30
+ message: z.string(),
31
+ });
32
+
33
+ const echoOutput = z.object({
34
+ result: z.string(),
35
+ });
36
+
37
+ type EchoInput = z.infer<typeof echoInput>;
38
+
39
+ const echoWorkflow: WorkflowDefinition = {
40
+ config: {
41
+ resource: resourceDescriptors.echo,
42
+ resourceId: resourceDescriptors.echo.id,
43
+ name: 'Echo',
44
+ type: resourceDescriptors.echo.kind,
45
+ description: 'Returns the input message unchanged',
46
+ version: '1.0.0',
47
+ status: 'dev',
48
+ },
49
+ contract: {
50
+ inputSchema: echoInput,
51
+ outputSchema: echoOutput,
52
+ },
53
+ steps: {
54
+ run: {
55
+ id: 'run',
56
+ name: 'Run',
57
+ description: 'Returns the input message unchanged',
58
+ handler: async (input) => {
59
+ const { message } = input as EchoInput;
60
+ return { result: message };
61
+ },
62
+ inputSchema: echoInput,
63
+ outputSchema: echoOutput,
64
+ next: null,
65
+ },
66
+ },
67
+ entryPoint: 'run',
68
+ };
69
+ ```
70
+
71
+ ### config
72
+
73
+ The `config` block binds executable behavior to the OM resource descriptor:
74
+
75
+ | Field | Type | Description |
76
+ | ------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
77
+ | `resource` | `ResourceEntry` | OM descriptor from `core/config/organization-model.ts`; owns stable identity, kind, system membership, ownership, and status. |
78
+ | `resourceId` | `string` | Derived from `resource.id`. Used by runtime invocation, CLI targeting, execution logs, and dashboard links. Do not invent it here. |
79
+ | `name` | `string` | Human-readable display name shown in the dashboard. |
80
+ | `type` | `'workflow'` | Derived from `resource.kind` for workflow resources. |
81
+ | `description` | `string` | Summary shown in the dashboard and command center. |
82
+ | `version` | `string` | Semver string (e.g., `'1.0.0'`). Increment when making breaking changes to the contract. |
83
+ | `status` | `'dev' | 'prod'` | Controls runtime availability. Use `'dev'` while building. See [Resource Status](#resource-status). |
84
+ | `domains` | `string[]` | Optional. Groups resources in the command center view. |
85
+
86
+ ### contract
87
+
88
+ The `contract` block defines the Zod schemas for input and output. The platform validates input against `contract.inputSchema` before passing it to your entry step handler, and validates the final step's return value against `contract.outputSchema`.
89
+
90
+ Always use `z.object()` for both schemas. Use `z.infer` to derive TypeScript types -- this keeps types and runtime validation in sync automatically.
91
+
92
+ ```typescript
93
+ const contract = {
94
+ inputSchema: z.object({
95
+ userId: z.string().uuid(),
96
+ action: z.string(),
97
+ }),
98
+ outputSchema: z.object({
99
+ success: z.boolean(),
100
+ message: z.string(),
101
+ }),
102
+ };
103
+ ```
104
+
105
+ ### steps
106
+
107
+ The `steps` record maps step IDs to step objects. Each step has metadata (`id`, `name`, `description`), a `handler` function, Zod schemas for its own input and output, and a `next` property that controls routing.
108
+
109
+ ```typescript
110
+ const steps = {
111
+ validate: {
112
+ id: 'validate',
113
+ name: 'Validate',
114
+ description: 'Validates the incoming request',
115
+ handler: async (input: MyInput) => {
116
+ return { validated: true, data: input };
117
+ },
118
+ inputSchema: myInputSchema,
119
+ outputSchema: z.object({ validated: z.boolean(), data: myInputSchema }),
120
+ next: { type: 'linear', target: 'process' }, // points to the next step
121
+ },
122
+ process: {
123
+ id: 'process',
124
+ name: 'Process',
125
+ description: 'Processes the validated data',
126
+ handler: async (input: ValidatedData) => {
127
+ return { result: 'done' };
128
+ },
129
+ inputSchema: z.object({ validated: z.boolean(), data: myInputSchema }),
130
+ outputSchema: z.object({ result: z.string() }),
131
+ next: null, // terminal step
132
+ },
133
+ };
134
+ ```
135
+
136
+ ### entryPoint
137
+
138
+ `entryPoint` is the name of the first step. For single-step workflows it is always the only step name. For multi-step workflows it is the name of the first step in the chain.
139
+
140
+ ```typescript
141
+ const workflow: WorkflowDefinition = {
142
+ // ...
143
+ entryPoint: 'validate', // execution starts here
144
+ };
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Multi-Step Workflows
150
+
151
+ For workflows with more than one step, import `StepType` from `@elevasis/sdk` to configure step routing.
152
+
153
+ ### Linear Steps
154
+
155
+ Use `StepType.LINEAR` to connect steps in a fixed sequence. Each step declares a `next` property pointing to the next step name.
156
+
157
+ ```typescript
158
+ import { z } from 'zod';
159
+ import type { WorkflowDefinition, WorkflowStep } from '@elevasis/sdk';
160
+
161
+ const fetchStep: WorkflowStep = {
162
+ id: 'fetch',
163
+ name: 'Fetch',
164
+ description: 'Fetches the raw data',
165
+ handler: async (input) => {
166
+ const data = await fetchSomething((input as { id: string }).id);
167
+ return { data };
168
+ },
169
+ inputSchema: z.object({ id: z.string() }),
170
+ outputSchema: z.object({ data: z.unknown() }),
171
+ next: { type: 'linear', target: 'process' },
172
+ };
173
+
174
+ const processStep: WorkflowStep = {
175
+ id: 'process',
176
+ name: 'Process',
177
+ description: 'Transforms the fetched data',
178
+ handler: async (input) => {
179
+ return { result: transform((input as { data: unknown }).data) };
180
+ },
181
+ inputSchema: z.object({ data: z.unknown() }),
182
+ outputSchema: z.object({ result: z.string() }),
183
+ next: null, // terminal step
184
+ };
185
+
186
+ const pipeline: WorkflowDefinition = {
187
+ config: {
188
+ resourceId: 'pipeline',
189
+ name: 'Pipeline',
190
+ type: 'workflow',
191
+ description: 'Fetch then process',
192
+ version: '1.0.0',
193
+ status: 'dev',
194
+ },
195
+ contract: { inputSchema: pipelineInput, outputSchema: pipelineOutput },
196
+ steps: { fetch: fetchStep, process: processStep },
197
+ entryPoint: 'fetch',
198
+ };
199
+ ```
200
+
201
+ ### Conditional Branching
202
+
203
+ Use `StepType.CONDITIONAL` to route to different steps based on output values. Each route has a `condition` function and a `target` step name. The first condition that returns `true` wins. A `default` fallback step is required.
204
+
205
+ ```typescript
206
+ import { z } from 'zod';
207
+ import type { WorkflowStep } from '@elevasis/sdk';
208
+
209
+ const routerStep: WorkflowStep = {
210
+ id: 'router',
211
+ name: 'Router',
212
+ description: 'Scores the input and routes to the appropriate path',
213
+ handler: async (input) => {
214
+ const score = await evaluate(input);
215
+ return { score };
216
+ },
217
+ inputSchema: z.object({ value: z.unknown() }),
218
+ outputSchema: z.object({ score: z.number() }),
219
+ next: {
220
+ type: 'conditional',
221
+ routes: [
222
+ {
223
+ condition: (output) => (output as { score: number }).score \>= 80,
224
+ target: 'highScorePath',
225
+ },
226
+ {
227
+ condition: (output) => (output as { score: number }).score \>= 50,
228
+ target: 'mediumScorePath',
229
+ },
230
+ ],
231
+ default: 'lowScorePath',
232
+ },
233
+ };
234
+ ```
235
+
236
+ ---
237
+
238
+ ## StepContext
239
+
240
+ Every step handler can optionally accept a second `context` parameter. TypeScript allows you to omit it if you do not need it -- you can write `handler: async (input) => { ... }` without declaring `context`.
241
+
242
+ When you do need it, the context provides runtime metadata:
243
+
244
+ ```typescript
245
+ import type { StepHandler } from '@elevasis/sdk';
246
+
247
+ const myStep: StepHandler = async (input, context) => {
248
+ const { executionId, organizationId, resourceId, logger, store } = context;
249
+
250
+ logger.info('Starting step', { executionId });
251
+
252
+ // store is a simple key-value store scoped to this execution
253
+ await store.set('progress', '50%');
254
+
255
+ return { done: true };
256
+ };
257
+ ```
258
+
259
+ | Field | Type | Description |
260
+ | ---------------- | -------- | -------------------------------------------------------------- |
261
+ | `executionId` | `string` | Unique ID for this execution run |
262
+ | `organizationId` | `string` | Your organization ID |
263
+ | `resourceId` | `string` | ID of the workflow or agent being executed |
264
+ | `logger` | `Logger` | Structured logger -- messages appear in the Elevasis dashboard |
265
+ | `store` | `Store` | Key-value store scoped to the current execution |
266
+
267
+ ---
268
+
269
+ ## AgentDefinition
270
+
271
+ Agents are autonomous resources that use an LLM and tools to complete a goal. You define them with `AgentDefinition`.
272
+
273
+ **Note:** Use `elevasis-sdk exec --async` when executing agents. Agents can run for minutes or longer, and the synchronous execute endpoint will time out for long-running runs. The `--async` flag returns an execution ID immediately and polls for the result.
274
+
275
+ ```typescript
276
+ import type { AgentDefinition } from '@elevasis/sdk';
277
+ import { resourceDescriptors } from '@core/config/organization-model';
278
+
279
+ const myAgent: AgentDefinition = {
280
+ config: {
281
+ resource: resourceDescriptors.myAgent,
282
+ resourceId: resourceDescriptors.myAgent.id,
283
+ name: 'my-agent',
284
+ type: resourceDescriptors.myAgent.kind,
285
+ description: 'Answers questions using platform tools',
286
+ status: 'dev',
287
+ },
288
+ agentConfig: {
289
+ model: { provider: 'openai', model: 'gpt-4o' },
290
+ systemPrompt: 'You are a helpful assistant.',
291
+ maxIterations: 10,
292
+ },
293
+ tools: [],
294
+ };
295
+ ```
296
+
297
+ ---
298
+
299
+ ## DeploymentSpec
300
+
301
+ All executable resources must be assembled through a `DeploymentSpec` default export from `operations/src/index.ts`. This is the entry point the platform reads when you deploy. Include the Organization Model payload so the validator can compare code-backed resources against OM descriptors.
302
+
303
+ ```typescript
304
+ import type { DeploymentSpec } from '@elevasis/sdk';
305
+ import { resourceGovernanceModel } from '@core/config/organization-model';
306
+
307
+ const org: DeploymentSpec = {
308
+ version: '0.1.0',
309
+ organizationModel: resourceGovernanceModel,
310
+ workflows: [echoWorkflow, pipeline],
311
+ agents: [
312
+ // myAgent,
313
+ ],
314
+ };
315
+
316
+ export default org;
317
+ ```
318
+
319
+ Each resource's `config.resourceId` is still the deployed runtime identifier. The important authoring rule is that `config.resourceId` derives from the OM descriptor (`resource.id`) instead of being duplicated by hand.
320
+
321
+ ### Resource Status
322
+
323
+ Set `config.status` to control whether the platform accepts execution requests:
324
+
325
+ - `'dev'` - Resource is visible in the dashboard but the platform will not route scheduled or webhook-triggered executions to it. You can still trigger it manually via `elevasis-sdk exec`.
326
+ - `'prod'` - Resource is live and accepts all execution sources.
327
+
328
+ Use `'dev'` while you are building and testing. Switch to `'prod'` when you are ready to go live.
329
+
330
+ You can also set a global default status in `elevasis.config.ts`:
331
+
332
+ ```typescript
333
+ import type { ElevasConfig } from '@elevasis/sdk';
334
+
335
+ const config: ElevasConfig = {
336
+ defaultStatus: 'dev',
337
+ };
338
+
339
+ export default config;
340
+ ```
341
+
342
+ ## Documentation
343
+
344
+ - [SDK Types](types.mdx) - Complete type reference for `@elevasis/sdk` exports, config, and step handler context
345
+ - [Common Patterns](patterns.mdx) - Sequential steps, conditional branching, error handling, and resource status patterns
346
+
347
+ ---
348
+
349
+ **Last Updated:** 2026-02-25