@elevasis/sdk 1.21.0 → 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 (160) hide show
  1. package/dist/cli.cjs +951 -171
  2. package/dist/index.d.ts +632 -341
  3. package/dist/index.js +3102 -142
  4. package/dist/node/index.d.ts +1 -0
  5. package/dist/node/index.js +19 -1
  6. package/dist/test-utils/index.d.ts +313 -4
  7. package/dist/test-utils/index.js +3246 -281
  8. package/dist/worker/index.js +3041 -80
  9. package/package.json +3 -3
  10. package/reference/claude-config/hooks/post-edit-validate.mjs +98 -98
  11. package/reference/claude-config/hooks/scaffold-registry-reminder.mjs +188 -188
  12. package/reference/claude-config/hooks/tool-failure-recovery.mjs +73 -73
  13. package/reference/claude-config/registries/graph-skills.json +4 -4
  14. package/reference/claude-config/registries/knowledge-flags.json +0 -2
  15. package/reference/claude-config/rules/active-change-index.md +80 -80
  16. package/reference/claude-config/rules/agent-start-here.md +277 -277
  17. package/reference/claude-config/rules/deployment.md +57 -57
  18. package/reference/claude-config/rules/error-handling.md +56 -56
  19. package/reference/claude-config/rules/execution.md +40 -40
  20. package/reference/claude-config/rules/frontend.md +4 -4
  21. package/reference/claude-config/rules/observability.md +31 -31
  22. package/reference/claude-config/rules/operations.md +29 -17
  23. package/reference/claude-config/rules/organization-model.md +110 -84
  24. package/reference/claude-config/rules/organization-os.md +115 -113
  25. package/reference/claude-config/rules/package-taxonomy.md +33 -33
  26. package/reference/claude-config/rules/platform.md +42 -42
  27. package/reference/claude-config/rules/shared-types.md +49 -46
  28. package/reference/claude-config/rules/task-tracking.md +47 -47
  29. package/reference/claude-config/rules/ui.md +200 -200
  30. package/reference/claude-config/rules/vibe.md +235 -235
  31. package/reference/claude-config/scripts/statusline-command.js +18 -18
  32. package/reference/claude-config/settings.json +34 -34
  33. package/reference/claude-config/skills/deploy/{SKILL.md → skill.md} +156 -156
  34. package/reference/claude-config/skills/dsp/SKILL.md +66 -66
  35. package/reference/claude-config/skills/elevasis/SKILL.md +235 -235
  36. package/reference/claude-config/skills/explore/SKILL.md +6 -6
  37. package/reference/claude-config/skills/git-sync/SKILL.md +126 -126
  38. package/reference/claude-config/skills/knowledge/SKILL.md +314 -299
  39. package/reference/claude-config/skills/knowledge/operations/codify-level-a.md +100 -100
  40. package/reference/claude-config/skills/knowledge/operations/codify-level-b.md +159 -159
  41. package/reference/claude-config/skills/knowledge/operations/customers.md +109 -109
  42. package/reference/claude-config/skills/knowledge/operations/features.md +76 -76
  43. package/reference/claude-config/skills/knowledge/operations/goals.md +118 -118
  44. package/reference/claude-config/skills/knowledge/operations/identity.md +93 -93
  45. package/reference/claude-config/skills/knowledge/operations/labels.md +94 -94
  46. package/reference/claude-config/skills/knowledge/operations/offerings.md +109 -109
  47. package/reference/claude-config/skills/knowledge/operations/roles.md +99 -99
  48. package/reference/claude-config/skills/knowledge/operations/techStack.md +30 -30
  49. package/reference/claude-config/skills/project/SKILL.md +1088 -1088
  50. package/reference/claude-config/skills/run-ui/SKILL.md +73 -73
  51. package/reference/claude-config/skills/save/SKILL.md +3 -3
  52. package/reference/claude-config/skills/setup/SKILL.md +275 -275
  53. package/reference/claude-config/skills/status/SKILL.md +59 -59
  54. package/reference/claude-config/skills/submit-request/SKILL.md +180 -180
  55. package/reference/claude-config/skills/sync/SKILL.md +47 -47
  56. package/reference/claude-config/skills/tutorial/SKILL.md +259 -259
  57. package/reference/claude-config/skills/tutorial/progress-template.md +74 -74
  58. package/reference/claude-config/skills/tutorial/technical.md +1303 -1303
  59. package/reference/claude-config/skills/tutorial/vibe-coder.md +890 -890
  60. package/reference/claude-config/sync-notes/2026-04-22-git-sync-and-sync-notes.md +27 -27
  61. package/reference/claude-config/sync-notes/2026-04-22-lead-gen-deliverability-removal.md +30 -30
  62. package/reference/claude-config/sync-notes/2026-04-24-test-utils-and-template-tests.md +73 -73
  63. package/reference/claude-config/sync-notes/2026-04-24-ui-consolidation-and-sdk-cli-train.md +86 -86
  64. package/reference/claude-config/sync-notes/2026-04-25-auth-role-system-and-settings-roles.md +55 -55
  65. package/reference/claude-config/sync-notes/2026-04-27-crm-hitl-action-layer-cutover.md +97 -97
  66. package/reference/claude-config/sync-notes/2026-04-27-lead-gen-substrate-train.md +112 -112
  67. package/reference/claude-config/sync-notes/2026-04-29-crm-state-and-lead-gen-processing-status.md +93 -93
  68. package/reference/claude-config/sync-notes/2026-05-02-crm-ownership-next-action.md +58 -58
  69. package/reference/claude-config/sync-notes/2026-05-02-template-hardcode-workos-config.md +56 -56
  70. package/reference/claude-config/sync-notes/2026-05-04-elevasis-workspace.md +71 -71
  71. package/reference/claude-config/sync-notes/2026-05-04-knowledge-bundle.md +83 -83
  72. package/reference/claude-config/sync-notes/2026-05-04-template-skills-run-ui-and-tutorial.md +59 -59
  73. package/reference/claude-config/sync-notes/2026-05-05-list-builder.md +42 -42
  74. package/reference/claude-config/sync-notes/2026-05-06-crm-spine.md +60 -60
  75. package/reference/claude-config/sync-notes/2026-05-06-sdk-changes-release-train.md +37 -37
  76. package/reference/claude-config/sync-notes/2026-05-07-sdk-changes-release-train.md +34 -34
  77. package/reference/claude-config/sync-notes/2026-05-08-resource-governance-scaffold-guidance.md +38 -38
  78. package/reference/claude-config/sync-notes/2026-05-09-clients-domain.md +32 -32
  79. package/reference/claude-config/sync-notes/2026-05-09-command-system.md +33 -33
  80. package/reference/claude-config/sync-notes/2026-05-09-resource-governance-and-misc.md +69 -69
  81. package/reference/claude-config/sync-notes/2026-05-12-sdk-ready-release-train.md +30 -30
  82. package/reference/claude-config/sync-notes/2026-05-14-organization-model-ontology-refactor.md +42 -0
  83. package/reference/claude-config/sync-notes/README.md +43 -43
  84. package/reference/cli.mdx +808 -808
  85. package/reference/concepts.mdx +146 -146
  86. package/reference/deployment/api.mdx +297 -297
  87. package/reference/deployment/command-center.mdx +209 -209
  88. package/reference/deployment/index.mdx +195 -195
  89. package/reference/deployment/provided-features.mdx +107 -107
  90. package/reference/deployment/ui-execution.mdx +250 -250
  91. package/reference/examples/organization-model.ts +146 -83
  92. package/reference/framework/agent.mdx +156 -156
  93. package/reference/framework/index.mdx +195 -195
  94. package/reference/framework/interaction-guidance.mdx +182 -182
  95. package/reference/framework/memory.mdx +326 -326
  96. package/reference/framework/project-structure.mdx +282 -282
  97. package/reference/framework/tutorial-system.mdx +135 -135
  98. package/reference/getting-started.mdx +142 -142
  99. package/reference/index.mdx +106 -106
  100. package/reference/packages/core/src/README.md +14 -14
  101. package/reference/packages/core/src/business/README.md +2 -2
  102. package/reference/packages/core/src/knowledge/README.md +32 -32
  103. package/reference/packages/core/src/organization-model/README.md +149 -149
  104. package/reference/packages/core/src/test-utils/README.md +37 -37
  105. package/reference/packages/ui/src/api/README.md +18 -18
  106. package/reference/packages/ui/src/app/README.md +24 -24
  107. package/reference/packages/ui/src/auth/README.md +18 -18
  108. package/reference/packages/ui/src/components/README.md +24 -24
  109. package/reference/packages/ui/src/execution/README.md +16 -16
  110. package/reference/packages/ui/src/features/README.md +28 -28
  111. package/reference/packages/ui/src/graph/README.md +16 -16
  112. package/reference/packages/ui/src/hooks/README.md +23 -23
  113. package/reference/packages/ui/src/initialization/README.md +19 -19
  114. package/reference/packages/ui/src/knowledge/README.md +31 -31
  115. package/reference/packages/ui/src/organization/README.md +18 -18
  116. package/reference/packages/ui/src/profile/README.md +19 -19
  117. package/reference/packages/ui/src/provider/README.md +32 -32
  118. package/reference/packages/ui/src/router/README.md +18 -18
  119. package/reference/packages/ui/src/sse/README.md +13 -13
  120. package/reference/packages/ui/src/test-utils/README.md +7 -7
  121. package/reference/packages/ui/src/theme/README.md +23 -23
  122. package/reference/packages/ui/src/theme/presets/README.md +19 -19
  123. package/reference/packages/ui/src/types/README.md +16 -16
  124. package/reference/packages/ui/src/utils/README.md +18 -18
  125. package/reference/packages/ui/src/zustand/README.md +18 -18
  126. package/reference/platform-tools/adapters-integration.mdx +301 -301
  127. package/reference/platform-tools/adapters-platform.mdx +553 -553
  128. package/reference/platform-tools/index.mdx +217 -217
  129. package/reference/platform-tools/type-safety.mdx +82 -82
  130. package/reference/resources/index.mdx +349 -349
  131. package/reference/resources/patterns.mdx +449 -449
  132. package/reference/resources/types.mdx +116 -116
  133. package/reference/roadmap.mdx +165 -165
  134. package/reference/runtime.mdx +173 -173
  135. package/reference/scaffold/core/organization-graph.mdx +110 -90
  136. package/reference/scaffold/core/organization-model.mdx +226 -219
  137. package/reference/scaffold/index.mdx +67 -67
  138. package/reference/scaffold/operations/propagation-pipeline.md +77 -77
  139. package/reference/scaffold/operations/scaffold-maintenance.md +12 -12
  140. package/reference/scaffold/operations/workflow-recipes.md +138 -138
  141. package/reference/scaffold/recipes/add-a-feature.md +308 -88
  142. package/reference/scaffold/recipes/add-a-resource.md +134 -110
  143. package/reference/scaffold/recipes/customize-knowledge-browser.md +5 -5
  144. package/reference/scaffold/recipes/customize-organization-model.md +273 -138
  145. package/reference/scaffold/recipes/extend-a-base-entity.md +8 -8
  146. package/reference/scaffold/recipes/extend-crm.md +3 -3
  147. package/reference/scaffold/recipes/extend-lead-gen.md +400 -400
  148. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +118 -118
  149. package/reference/scaffold/recipes/index.md +46 -46
  150. package/reference/scaffold/recipes/query-the-knowledge-graph.md +197 -170
  151. package/reference/scaffold/reference/contracts.md +2101 -2096
  152. package/reference/scaffold/reference/glossary.md +76 -76
  153. package/reference/scaffold/ui/composition-extensibility.mdx +233 -233
  154. package/reference/scaffold/ui/customization.md +243 -243
  155. package/reference/scaffold/ui/feature-flags-and-gating.md +46 -46
  156. package/reference/scaffold/ui/feature-shell.mdx +72 -72
  157. package/reference/scaffold/ui/recipes.md +221 -214
  158. package/reference/spine/spine-primer.md +96 -96
  159. package/reference/templates/index.mdx +47 -47
  160. 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