@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,1303 +1,1303 @@
1
- # Tutorial: Technical Track
2
-
3
- This file is loaded by `.claude/skills/tutorial/SKILL.md` when the user selects the technical
4
- track. Do not invoke this file directly -- the router reads it and dispatches to the lesson the
5
- user picks.
6
-
7
- Each lesson is a script for the teaching agent. Instructions in plain text address the agent
8
- ("Read X", "Walk the user through Y"). User-facing strings are indented as block quotes.
9
-
10
- After each lesson, update `.claude/memory/tutorial-progress.md` by changing `[ ]` to
11
- `[x] YYYY-MM-DD` for that item. After completing any full section, redisplay the menu with
12
- updated markers.
13
-
14
- ---
15
-
16
- ## Menu
17
-
18
- ```
19
- SECTION A -- The workspace (3 items)
20
- 1 What is this workspace [ ]
21
- 2 The skill layer -- slash commands you'll use [ ]
22
- 3 The vibe layer -- ambient intent classification [ ]
23
-
24
- SECTION B -- Build your first thing (5 items)
25
- 4 Echo workflow tour [ ]
26
- 5 Custom workflow with schemas [ ]
27
- 6 Platform tools and credentials [ ]
28
- 7 Multi-step and conditionals [ ]
29
- 8 Going to production [ ]
30
-
31
- SECTION C -- The Organization Model (3 items)
32
- 9 /knowledge ceremony -- identity, customers, [ ]
33
- offerings via the layered flow
34
- 10 Systems, actions, and labels [ ]
35
- 11 Entity extensions -- BaseProject, BaseDeal [ ]
36
-
37
- SECTION D -- Modules (load on demand) (6 items)
38
- 12 HITL [ ]
39
- 13 Schedules [ ]
40
- 14 Notifications + integrations [ ]
41
- 15 Error handling [ ]
42
- 16 LLM and agents [ ]
43
- 17 Composition (execution.trigger) [ ]
44
-
45
- SECTION E -- Power user (2 items)
46
- 18 Rules, memory, scaffold registry [ ]
47
- 19 Template lifecycle and /git-sync [ ]
48
- ```
49
-
50
- ---
51
-
52
- ## SECTION A -- The Workspace
53
-
54
- ### Item 1: What is this workspace
55
-
56
- **Goal:** The user understands the three-layer project structure, the standalone repo model, and
57
- why the scaffold is described as an agent operating environment, not just an app starter.
58
-
59
- **Estimated time:** 15 min
60
-
61
- **Files referenced:** `.claude/rules/agent-start-here.md`, `CLAUDE.md`,
62
- `node_modules/@elevasis/sdk/reference/scaffold/index.mdx`
63
-
64
- **Flow:**
65
-
66
- Open by reading `.claude/rules/agent-start-here.md` (the canonical first-read) and `CLAUDE.md`
67
- (the project bootstrap surface). Use both to anchor the explanation below.
68
-
69
- Open with the skip affordance:
70
-
71
- > "Item 1 covers what this workspace is and how it is structured. If you already know the
72
- > three-layer layout (ui / operations / core), the standalone repo model, and why the scaffold
73
- > is an agent operating environment, type 'skip' and I'll mark it complete."
74
-
75
- If the user skips, mark `[x] YYYY-MM-DD` in `.claude/memory/tutorial-progress.md` for item 1
76
- and move on.
77
-
78
- Otherwise, walk through the following:
79
-
80
- **Three runtime layers.** The template is divided into three directories with hard runtime
81
- boundaries:
82
-
83
- - `ui/` -- React 19 frontend (Vite, TanStack Router, Mantine). Browser runtime. Imports from
84
- `core/` only.
85
- - `operations/` -- Platform workflows and agents (Elevasis SDK). Node target. Imports from
86
- `core/` only.
87
- - `core/` -- Runtime-agnostic shared contracts: Zod schemas, TypeScript types, organization
88
- model configuration. No React, no Node APIs, no SDK worker imports.
89
-
90
- Emphasize: `ui/` and `operations/` are separate runtimes. They communicate through the platform
91
- API at runtime. At build time they share types only via `core/`.
92
-
93
- **Standalone repo.** This project is NOT part of the monorepo pnpm workspace. It has its own
94
- `.git/`, own `pnpm-lock.yaml`, own `node_modules/`. The monorepo boundary hook does not apply
95
- here. Git, gh, and CLI commands work directly.
96
-
97
- **Agent operating environment.** Read the "Template Surfaces" section from `agent-start-here.md`
98
- aloud to the user. Key point: the `.claude/` directory is a first-class surface -- rules (always
99
- loaded), skills (invocable via slash commands), hooks (run on tool calls), and memory (persists
100
- across sessions). The scaffold is not just an app starter; the agent reads `.claude/rules/` on
101
- every session and uses it to route task classes, resolve boundaries, and choose the right tool.
102
-
103
- **SDK reference scaffold.** After `pnpm install`, the entry point
104
- `node_modules/@elevasis/sdk/reference/scaffold/index.mdx` gives access to canonical recipes, UI
105
- patterns, the gating model, contracts, and a glossary. Whenever the user wants the authoritative
106
- answer on a scaffold surface (how to add a System or UI feature, extend an entity, wire a workflow), that
107
- index is the starting point.
108
-
109
- **Verification:** Ask the user: "Where does the agent look first when entering a session?" (Answer:
110
- `agent-start-here.md` via the always-loaded rules.) If they get it right, continue. If not, point
111
- them to the "First Action: Check Active Projects" and "Discovery Order" sections in
112
- `agent-start-here.md`.
113
-
114
- **Completion signal:** Mark `[ ] 1 What is this workspace` as `[x] YYYY-MM-DD` in
115
- `.claude/memory/tutorial-progress.md`.
116
-
117
- ---
118
-
119
- ### Item 2: The skill layer -- slash commands you'll use
120
-
121
- **Goal:** The user knows all 12 slash commands, how to invoke them, where they live, and can
122
- demonstrate `/status` and `/project`.
123
-
124
- **Estimated time:** 15 min
125
-
126
- **Files referenced:** `.claude/skills/*/SKILL.md` (skim), `CLAUDE.md` slash command table
127
-
128
- **Flow:**
129
-
130
- Open with the skip affordance:
131
-
132
- > "Item 2 walks through the 12 slash commands in this scaffold. If you've already used them and
133
- > know where they live, type 'skip' and I'll mark it complete."
134
-
135
- If the user skips, mark complete and move on.
136
-
137
- Otherwise, read the Slash Commands table in `CLAUDE.md` aloud. Then explain the skill system:
138
-
139
- **Invocation pattern.** Every slash command is a skill. Type `/<name>` (optionally with args,
140
- e.g., `/knowledge systems`). The agent reads `.claude/skills/<name>/SKILL.md` and follows its
141
- instructions. Skills may be context-forked (they run in a subagent) or inline. The frontmatter
142
- `context: fork` means a subagent handles it.
143
-
144
- **Where they live.** Each skill lives in `.claude/skills/<name>/SKILL.md`. Multi-step operations
145
- that belong to a skill (but are too large for `SKILL.md`) live in
146
- `.claude/skills/<name>/operations/<op>.md`.
147
-
148
- **How the agent knows to use them.** The `description` frontmatter field (or `metadata.promptSignals`)
149
- tells the agent when to auto-invoke a skill without an explicit slash command. For example,
150
- `/knowledge` auto-invokes whenever the conversation references org-model entities.
151
-
152
- Walk through each of the 12 commands:
153
-
154
- - `/setup` -- first-time bootstrap: placeholder replacement, deps, verification, then hands off
155
- to `/knowledge`
156
- - `/save` -- conversation fanout: updates knowledge docs, persists `prj_tasks.resume_context`
157
- via `elevasis-sdk project:task:save`, creates a project note on blockers/status signals
158
- - `/dsp` -- parallel agent dispatch for implementation tasks with multiple independent steps
159
- - `/deploy` -- test, build, commit, push pipeline
160
- - `/explore` -- codebase exploration anchored to docs
161
- - `/git-sync` -- pull latest changes, surface new template sync notes, install when needed,
162
- run baseline verification, then stop before manual reconciliation
163
- - `/status` -- quick project health check
164
- - `/project` -- primary work-tracking entry point; portfolio orientation, intent detection
165
- (resume vs new), and project/milestone/task/note lifecycle via `elevasis-sdk project:*`
166
- - `/elevasis` -- SDK operations: check, deploy, exec, describe, logs, creds
167
- - `/sync` -- fresh reinstall and cache reset when local deps or build caches are stale
168
- - `/knowledge` -- org model ceremony: read, codify, toggle, layered flow for identity through
169
- goals
170
- - `/submit-request` -- submit a structured request (bug, feature, support) to the platform
171
-
172
- **Demo 1: `/status`.** Ask the user to type `/status`. Narrate what it shows: project health
173
- summary, active projects, recent executions if any.
174
-
175
- **Demo 2: `/project`.** Ask the user to type `/project`. Walk them through the portfolio
176
- orientation output. Show how to create a task: `/project create task --title "My first task"`.
177
-
178
- **Verification:** The user can name any 3 commands unprompted and describe what they do.
179
-
180
- **Completion signal:** Mark `[ ] 2 The skill layer` as `[x] YYYY-MM-DD` in
181
- `.claude/memory/tutorial-progress.md`.
182
-
183
- ---
184
-
185
- ### Item 3: The vibe layer -- ambient intent classification
186
-
187
- **Goal:** The user understands the 7-intent classifier, can recognize when it fires, and knows
188
- it is absent in the monorepo.
189
-
190
- **Estimated time:** 15 min
191
-
192
- **Files referenced:** `.claude/rules/vibe.md`, `CLAUDE.md` ambient vibe section
193
-
194
- **Flow:**
195
-
196
- Open with the skip affordance:
197
-
198
- > "Item 3 covers the vibe layer -- an ambient intent classifier that fires on every natural-language
199
- > message. If you already know the 7 intent types and how the classifier routes them, type 'skip'
200
- > and I'll mark it complete."
201
-
202
- If the user skips, mark complete and move on.
203
-
204
- Otherwise, read `.claude/rules/vibe.md` before explaining. Then walk through:
205
-
206
- **What vibe is.** Every natural-language message in an external project passes through the vibe
207
- classifier before the agent acts. No slash command, no activation phrase. The agent silently
208
- classifies the message into one of seven intent types and routes to the right behavior. The user
209
- never sees the classification.
210
-
211
- **The seven intent types.** Walk through each by name with one fixture example:
212
-
213
- - **Capture** -- "Add a task to follow up with the Shopify client." Agent drafts, confirms,
214
- writes via `elevasis-sdk project:*`.
215
- - **Query** -- "What's pending in the HITL queue?" Agent reads and narrates.
216
- - **Describe** -- "What's going on with this deal?" Agent narrates from org model labels.
217
- - **Transition** -- "Done with the proposal draft." Agent confirms, updates task status via
218
- `elevasis-sdk project:task:save`.
219
- - **Navigate** -- "Let's focus on the onboarding flow." Agent updates scope, narrates the shift.
220
- - **Codify** -- "We track deals by Shopify platform." Agent detects new organizational reality
221
- and delegates to `/knowledge`.
222
- - **Toggle** -- "Turn on the lead-gen system." Agent delegates to `/knowledge systems`.
223
-
224
- **Important behavioral rules.** Codify and Toggle delegate immediately to `/knowledge` -- the
225
- vibe layer detects intent but does NOT run the ceremony itself. The ceremony (snapshot, propose,
226
- confirm, write, validate, rollback) belongs to `/knowledge`. Ambiguous messages get one
227
- clarifying question; no precedence rule is applied.
228
-
229
- **Where it applies.** Vibe is always-on in external projects. It is explicitly OFF in the
230
- monorepo. The monorepo uses task-class routing via `agent-start-here.md` instead. If the user is
231
- working inside the monorepo (`apps/`, `packages/`, etc.), vibe does not fire.
232
-
233
- **Reference.** The full classifier definition, fixture tables, and codify heuristics live in
234
- `.claude/rules/vibe.md`. The `CLAUDE.md` table is a pointer -- for authoritative behavior, read
235
- the rule file.
236
-
237
- **Verification:** Ask "What happens when you type 'turn on SEO'?" Answer: Vibe classifies it as
238
- Toggle intent and delegates to `/knowledge systems` without running the ceremony itself.
239
-
240
- **Completion signal:** Mark `[ ] 3 The vibe layer` as `[x] YYYY-MM-DD` in
241
- `.claude/memory/tutorial-progress.md`.
242
-
243
- ---
244
-
245
- ## SECTION B -- Build Your First Thing
246
-
247
- ### Item 4: Echo workflow tour
248
-
249
- **Goal:** The user reads the echo workflow source, validates it, deploys it, and executes it
250
- end-to-end.
251
-
252
- **Estimated time:** 20 min
253
-
254
- **Files referenced:** `operations/src/example/echo.ts`, `core/types/index.ts`,
255
- `operations/src/index.ts`
256
-
257
- **Commands:** `pnpm -C operations check`, `pnpm -C operations deploy`,
258
- `pnpm elevasis-sdk exec echo --input '{"message":"hi"}'`
259
-
260
- **Flow:**
261
-
262
- Tell the user:
263
-
264
- > "Let's tour the echo workflow -- the starter resource that ships with every template project.
265
- > We'll read the source, run the validator, deploy it, and execute it."
266
-
267
- **Step 1: Read the source.** Open `operations/src/example/echo.ts` with the user. Walk through
268
- each section:
269
-
270
- - `config` block: `resourceId` (the deploy-time unique ID), `name`, `type: 'workflow'`,
271
- `description`, `version` (semver, bump on contract changes), `status: 'dev'` (new resources
272
- start here; `'prod'` means visible to end users in the production environment).
273
- - `contract` block: `inputSchema` and `outputSchema` are imported from `core/types/index.ts`,
274
- NOT defined inline. This is the pattern: schemas live in `core/` so both the frontend and
275
- `operations/` can import them without creating a dependency cycle.
276
- - `steps` map: each step has `id`, `name`, `description`, a `handler` async function, and
277
- `next: null` (last step). The handler receives `input` and `context`. `context.logger.info()`
278
- is the correct logging call -- `console.log` is not captured by the platform.
279
- - `entryPoint`: the key from `steps` that runs first.
280
- - `interface.form`: defines the UI form the Command Center renders when a user triggers this
281
- workflow manually.
282
-
283
- **Step 2: Validate.** Run:
284
-
285
- ```bash
286
- pnpm -C operations check
287
- ```
288
-
289
- Show the output. Explain: this catches duplicate `resourceId`s, broken step chains (`next`
290
- referencing a non-existent step), invalid schema serialization, and other errors the platform
291
- would reject at deploy time. Exit code 0 = pass.
292
-
293
- **Step 3: Deploy.** Run:
294
-
295
- ```bash
296
- pnpm -C operations deploy
297
- ```
298
-
299
- Walk through the output stages: Authenticating, Validating, Bundling (esbuild packages
300
- `operations/src/index.ts` and all dependencies into a single CJS file), Uploading. After deploy,
301
- resources are live immediately -- no restart required.
302
-
303
- **Step 4: Execute.** Run:
304
-
305
- ```bash
306
- pnpm elevasis-sdk exec echo --input '{"message":"hi"}'
307
- ```
308
-
309
- Show the output: status, duration, and output `{ "echo": "hi" }`. Explain: the platform
310
- validated `{"message":"hi"}` against `echoInputSchema`, spun up an ephemeral worker thread,
311
- ran the handler, returned the result, and terminated the worker.
312
-
313
- **Step 5: Check history.** Run:
314
-
315
- ```bash
316
- pnpm elevasis-sdk executions echo
317
- ```
318
-
319
- Pick the execution ID from the list and run:
320
-
321
- ```bash
322
- pnpm elevasis-sdk execution echo <execution-id>
323
- ```
324
-
325
- Show the full detail including logs. Point out the `[echo] Received message: "hi"` log line
326
- emitted by `context.logger.info()` in the handler.
327
-
328
- **Verification:** The user sees the execution complete with `{ "echo": "hi" }` output.
329
-
330
- **Completion signal:** Mark `[ ] 4 Echo workflow tour` as `[x] YYYY-MM-DD` in
331
- `.claude/memory/tutorial-progress.md`.
332
-
333
- ---
334
-
335
- ### Item 5: Custom workflow with schemas
336
-
337
- **Goal:** The user creates a new workflow in its own domain directory, defines a Zod input schema
338
- in `core/types/`, registers it in `operations/src/index.ts`, and validates it.
339
-
340
- **Estimated time:** 25 min
341
-
342
- **Files referenced:** `operations/src/example/echo.ts` (model), `core/types/index.ts`,
343
- `operations/src/index.ts`
344
-
345
- **Commands:** `pnpm -C operations check`, `pnpm -C core check-types`
346
-
347
- **Flow:**
348
-
349
- Tell the user:
350
-
351
- > "Now you'll build a real workflow from scratch. We'll pick a domain for your project, define
352
- > the input and output schemas in `core/types/`, author the workflow in `operations/src/`, and
353
- > register it."
354
-
355
- **Step 1: Pick a domain.** Ask the user what their project does -- even a rough description is
356
- enough. Suggest a simple workflow relevant to their context (e.g., "classify a support ticket",
357
- "score a lead", "send a notification on a Stripe event"). Name the domain in kebab-case.
358
-
359
- **Step 2: Define schemas in `core/types/`.** Open `core/types/index.ts`. Walk the user through
360
- the schema convention:
361
-
362
- ```typescript
363
- export const myWorkflowInputSchema = z.object({
364
- // define fields here
365
- })
366
- export type MyWorkflowInput = z.infer<typeof myWorkflowInputSchema>
367
-
368
- export const myWorkflowOutputSchema = z.object({
369
- // define fields here
370
- })
371
- export type MyWorkflowOutput = z.infer<typeof myWorkflowOutputSchema>
372
- ```
373
-
374
- Explain: `z.infer` gives you a TypeScript type from the schema so the type system can check your
375
- handlers. You define once, get both runtime validation and compile-time inference. The schema
376
- lives in `core/` so the frontend can import it for form validation without importing SDK worker
377
- code.
378
-
379
- Explain common field types: `z.string()`, `z.number()`, `z.boolean()`, `z.enum([...])`,
380
- `z.string().optional()`, `z.object({...})`, `z.array(z.string())`.
381
-
382
- After writing the schemas, run:
383
-
384
- ```bash
385
- pnpm -C core check-types
386
- ```
387
-
388
- Fix any TypeScript errors before continuing.
389
-
390
- **Step 3: Create the domain directory.** Create `operations/src/<domain>/` with two files:
391
- `index.ts` (the domain barrel) and `<workflow-name>.ts` (the workflow implementation). Mirror
392
- the echo structure but use the new schemas imported from `@core/types`.
393
-
394
- Key points to emphasize:
395
-
396
- - `resourceId` must be unique within the organization (kebab-case).
397
- - `status: 'dev'` for new resources.
398
- - `next: null` on the last step.
399
- - Import schemas from `@core/types`, never define them inline in the workflow file.
400
-
401
- **Step 4: Register in `operations/src/index.ts`.** Show the current registry:
402
-
403
- ```typescript
404
- import * as example from './example/index.js'
405
- import * as emailNotification from './email-notification/exports.js'
406
-
407
- const org: DeploymentSpec = {
408
- version: '0.1.0',
409
- workflows: [...example.workflows, ...emailNotification.workflows],
410
- agents: [...example.agents, ...emailNotification.agents]
411
- }
412
- ```
413
-
414
- Add the new domain import and spread its `workflows` into the `DeploymentSpec`.
415
-
416
- **Step 5: Validate.** Run `pnpm -C operations check`. The output should now show N+1 resources
417
- with 0 errors.
418
-
419
- **Verification:** `pnpm -C operations check` passes with the new workflow listed.
420
-
421
- **Completion signal:** Mark `[ ] 5 Custom workflow with schemas` as `[x] YYYY-MM-DD` in
422
- `.claude/memory/tutorial-progress.md`.
423
-
424
- ---
425
-
426
- ### Item 6: Platform tools and credentials
427
-
428
- **Goal:** The user understands singleton adapters vs factory adapters, imports them correctly,
429
- and knows how to create a credential in Command Center.
430
-
431
- **Estimated time:** 20 min
432
-
433
- **Files referenced:** `.claude/skills/elevasis/SKILL.md` (creds section),
434
- `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
435
-
436
- **Flow:**
437
-
438
- Tell the user:
439
-
440
- > "The platform provides typed adapters for external services: CRM, email, payments, AI, storage,
441
- > and more. You call them from workflow handlers without putting API keys in your code."
442
-
443
- **Singleton adapters.** Import once at the top of the worker file, use directly:
444
-
445
- ```typescript
446
- import { llm, scheduler, storage, notifications } from '@elevasis/sdk/worker'
447
- ```
448
-
449
- These are singletons -- no credential binding at construction. They use platform-managed config.
450
- Use them for: LLM generation, scheduling, object storage, in-app notifications.
451
-
452
- **Factory adapters.** Credential-bound: constructed with a credential name, then used:
453
-
454
- ```typescript
455
- import { createAttioAdapter } from '@elevasis/sdk/worker'
456
-
457
- const attio = createAttioAdapter('my-attio-cred')
458
- // inside a step handler:
459
- await attio.createRecord({ ... })
460
- ```
461
-
462
- The string `'my-attio-cred'` is the credential name you register in Command Center. The naming
463
- convention is `{org}-{service}` kebab-case, e.g. `acme-attio`, `acme-stripe`.
464
-
465
- **Credential setup in Command Center.** Walk the user through: Command Center -> Settings ->
466
- Credentials -> Create. The credential is stored encrypted on the platform. Workers access it at
467
- runtime through the adapter. It never appears in code or `.env`. The `.env` file holds only
468
- `ELEVASIS_PLATFORM_KEY` for CLI authentication.
469
-
470
- **Common error.** `PlatformToolError: credential not found` means the credential name in code
471
- does not exactly match what was created in Command Center. Check spelling and case; credential
472
- names are case-sensitive.
473
-
474
- **CLI credential management.** Show the `/elevasis creds` surface as an alternative to the UI:
475
-
476
- ```bash
477
- pnpm elevasis-sdk creds list
478
- pnpm elevasis-sdk creds create --name acme-attio --type api-key --value '{"apiKey":"..."}'
479
- ```
480
-
481
- **Verification:** Ask: "Where do integration credentials live at runtime?" Answer: on the platform,
482
- injected by the worker runtime. Not in `.env`, not in code.
483
-
484
- **Completion signal:** Mark `[ ] 6 Platform tools and credentials` as `[x] YYYY-MM-DD` in
485
- `.claude/memory/tutorial-progress.md`.
486
-
487
- ---
488
-
489
- ### Item 7: Multi-step and conditionals
490
-
491
- **Goal:** The user implements a two-step LINEAR workflow and a CONDITIONAL workflow, understanding
492
- how data flows between steps.
493
-
494
- **Estimated time:** 25 min
495
-
496
- **Files referenced:** `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`,
497
- `apps/docs/content/docs/sdk/concepts.mdx` (design decisions section)
498
-
499
- **Flow:**
500
-
501
- **Step 1: LINEAR steps.** Extend the workflow from Item 5 (or create a new one) to add a second
502
- step. Show the `next` field on step 1 pointing to the key of step 2:
503
-
504
- ```typescript
505
- steps: {
506
- fetchData: {
507
- id: 'fetchData',
508
- name: 'Fetch Data',
509
- handler: async (input, context) => {
510
- // ... fetch or compute something
511
- return { result: 'some-value' }
512
- },
513
- inputSchema: myInputSchema,
514
- outputSchema: z.object({ result: z.string() }),
515
- next: 'processData' // <-- key of the next step
516
- },
517
- processData: {
518
- id: 'processData',
519
- name: 'Process Data',
520
- handler: async (input, context) => {
521
- const { result } = input // receives output from fetchData
522
- return { finalResult: result.toUpperCase() }
523
- },
524
- inputSchema: z.object({ result: z.string() }),
525
- outputSchema: myOutputSchema,
526
- next: null
527
- }
528
- },
529
- entryPoint: 'fetchData'
530
- ```
531
-
532
- Emphasize: the output schema of step N must match the input schema of step N+1. The platform
533
- validates this chain at deploy time. Data passes from step to step -- no global state, no shared
534
- variables.
535
-
536
- **Step 2: CONDITIONAL routing.** Import `StepType` and show a conditional branch:
537
-
538
- ```typescript
539
- import type { WorkflowDefinition, StepType } from '@elevasis/sdk'
540
-
541
- // ... inside steps:
542
- routeStep: {
543
- id: 'routeStep',
544
- type: StepType.CONDITIONAL,
545
- name: 'Route by Score',
546
- handler: async (input, context) => {
547
- if (input.score >= 80) return { path: 'approve', ...input }
548
- if (input.score >= 50) return { path: 'review', ...input }
549
- return { path: 'reject', ...input }
550
- },
551
- routes: {
552
- approve: 'approveStep',
553
- review: 'reviewStep',
554
- default: 'rejectStep' // always include a default
555
- },
556
- // ...
557
- }
558
- ```
559
-
560
- Always include a `default` route. Without it, an execution whose output does not match any
561
- explicit key will fail at runtime.
562
-
563
- **Verification:** `pnpm -C operations check` passes with the multi-step workflow registered. Ask
564
- the user what happens if they omit the `default` route (runtime failure for unmatched paths).
565
-
566
- **Completion signal:** Mark `[ ] 7 Multi-step and conditionals` as `[x] YYYY-MM-DD` in
567
- `.claude/memory/tutorial-progress.md`.
568
-
569
- ---
570
-
571
- ### Item 8: Going to production
572
-
573
- **Goal:** The user knows the dev/prod split, version bumping flags, and the SDK CLI CWD
574
- guidance in the deployment rule.
575
-
576
- **Estimated time:** 15 min
577
-
578
- **Files referenced:** `.claude/rules/deployment.md`
579
-
580
- **Commands:** `pnpm -C operations deploy:prod`
581
-
582
- **Flow:**
583
-
584
- **Dev vs prod targeting.** The default `pnpm -C operations deploy` targets the development
585
- environment. To deploy to production:
586
-
587
- ```bash
588
- pnpm -C operations deploy:prod
589
- ```
590
-
591
- In `config.status`: `'dev'` means the resource is visible only in dev mode. Change to `'prod'`
592
- before deploying to production -- otherwise the resource deploys but is not exposed in the
593
- production surface.
594
-
595
- **Version bumping.** The deploy command accepts version bump flags that are written back to
596
- `operations/src/index.ts`:
597
-
598
- ```bash
599
- pnpm -C operations deploy:prod # no bump (same version)
600
- # or pass a flag via pnpm scripts if wired in package.json:
601
- pnpm elevasis-sdk deploy --prod --patch # 1.0.0 -> 1.0.1
602
- pnpm elevasis-sdk deploy --prod --minor # 1.0.0 -> 1.1.0
603
- pnpm elevasis-sdk deploy --prod --major # 1.0.0 -> 2.0.0
604
- ```
605
-
606
- Bump rules: `--patch` for bug fixes, `--minor` for new features (no breaking schema changes),
607
- `--major` for breaking input/output schema changes.
608
-
609
- **SDK CLI CWD guidance.** Read `.claude/rules/deployment.md`. Two critical rules:
610
-
611
- 1. The `--prod` flag belongs to the `deploy` command:
612
-
613
- ```bash
614
- # Correct
615
- pnpm elevasis-sdk deploy --prod
616
- ```
617
-
618
- The `pnpm -C operations deploy:prod` script in `package.json` handles this correctly.
619
- Prefer the script over a raw CLI call for production deploys.
620
-
621
- 2. Never use bare `cd <dir> && elevasis-sdk ...` -- use a subshell `(cd <dir> && ...)` or
622
- `pnpm -C <dir> ...` to avoid CWD drift that causes env resolution failures.
623
-
624
- **Standard pre-production checklist.** Walk the user through:
625
-
626
- ```
627
- 1. pnpm -C operations check -- validate resources
628
- 2. pnpm -C operations check-types -- TypeScript type-check
629
- 3. pnpm elevasis-sdk exec <id> -i '...' -- test in dev
630
- 4. pnpm -C operations deploy:prod -- ship to prod
631
- ```
632
-
633
- **Verification:** The user can explain where `--prod` must be placed and why.
634
-
635
- **Completion signal:** Mark `[ ] 8 Going to production` as `[x] YYYY-MM-DD` in
636
- `.claude/memory/tutorial-progress.md`.
637
-
638
- ---
639
-
640
- ## SECTION C -- The Organization Model
641
-
642
- ### Item 9: /knowledge ceremony -- identity, customers, offerings via the layered flow
643
-
644
- **Goal:** The user runs `/knowledge` and understands the six-step write ceremony, why direct
645
- edits to `core/config/organization-model.ts` are blocked, and the layered flow order.
646
-
647
- **Estimated time:** 25 min
648
-
649
- **Files referenced:** `.claude/skills/knowledge/SKILL.md`, `core/config/organization-model.ts`,
650
- `.claude/rules/organization-os.md`
651
-
652
- **Flow:**
653
-
654
- Tell the user:
655
-
656
- > "The organization model is the semantic contract layer that defines your business reality:
657
- > who you are, who your customers are, what you offer, your team, and your goals. All edits go
658
- > through `/knowledge` -- not direct file edits."
659
-
660
- **Why direct edits are blocked.** Read `core/config/organization-model.ts`. The file calls
661
- `resolveOrganizationModel()` which runs Zod cross-reference validation: every customer segment
662
- referenced in offerings must exist in `customers`, every resource mapping must reference a valid
663
- system ID, and so on. A direct edit that passes TypeScript can still fail the cross-ref check,
664
- leaving the project in a broken state. The `/knowledge` ceremony runs both checks and rolls back
665
- on failure.
666
-
667
- **The six-step ceremony.** Walk through `.claude/skills/knowledge/SKILL.md`:
668
-
669
- 1. **Snapshot** -- reads `core/config/organization-model.ts` into memory before any edit
670
- 2. **Propose** -- shows the diff and the proposed new value alongside current value
671
- 3. **Confirm** -- pauses for explicit user confirmation; never writes without a clear yes
672
- 4. **Write** -- applies the edit
673
- 5. **Validate** -- runs `pnpm -C operations check-types` (TypeScript) then `pnpm -C operations
674
- check` (Zod parse via `resolveOrganizationModel()`)
675
- 6. **Rollback** -- if either check fails, restores from the Step 1 snapshot
676
-
677
- **The layered flow.** Run `/knowledge` with no argument to walk through the full flow:
678
- identity -> customers -> offerings -> roles -> goals -> techStack. The agent reads the current
679
- state of each domain, proposes any missing or incomplete fields, and asks for confirmation before
680
- writing.
681
-
682
- Or target a specific domain:
683
-
684
- - `/knowledge identity` -- legal name, mission/vision, industry, geography, timezone
685
- - `/knowledge customers` -- customer segments with jobs-to-be-done, pains, gains
686
- - `/knowledge offerings` -- products and services with pricing model and segment references
687
- - `/knowledge roles` -- role chart with responsibilities and reporting lines
688
- - `/knowledge goals` -- organizational goals with period and measurable outcomes
689
- - `/knowledge techStack` -- external SaaS and integration context tied to OM Resources descriptors or knowledge nodes
690
-
691
- **Demo.** Ask the user to run `/knowledge identity`. Walk through the ceremony together -- read
692
- the current state, propose an edit, confirm, watch it validate.
693
-
694
- **Verification:** The user can describe what `resolveOrganizationModel()` does and why the
695
- rollback step exists.
696
-
697
- **Completion signal:** Mark `[ ] 9 /knowledge ceremony` as `[x] YYYY-MM-DD` in
698
- `.claude/memory/tutorial-progress.md`.
699
-
700
- ---
701
-
702
- ### Item 10: Systems, actions, and labels
703
-
704
- **Goal:** The user can enable/disable a System via `/knowledge systems`, understand Actions as
705
- invokable operations, and rename a display label via `/knowledge labels`.
706
-
707
- **Estimated time:** 15 min
708
-
709
- **Files referenced:** `.claude/skills/knowledge/operations/features.md` (legacy compatibility),
710
- `.claude/skills/knowledge/operations/labels.md`, `core/config/organization-model.ts`
711
-
712
- **Flow:**
713
-
714
- **Systems.** The org model uses Systems for availability, routing, ownership, navigation
715
- grouping, and knowledge mounts. Toggle availability by running:
716
-
717
- ```
718
- /knowledge systems
719
- ```
720
-
721
- The ceremony proposes the change (e.g., `seo: false -> true`), asks for confirmation, writes,
722
- and validates. Older scaffold recipes and UI packages may still say "feature"; translate that to
723
- System when discussing Organization OS availability or routing.
724
-
725
- System toggles affect the UI shell: a disabled System removes its nav entry and routes from
726
- the shell. Actions are the invokable operations owned or exposed by a System.
727
-
728
- **Labels.** The `labels` domain controls display strings on enum entries -- CRM pipeline stages,
729
- lead-gen lifecycle statuses, project statuses, and so on. Rename by running:
730
-
731
- ```
732
- /knowledge labels
733
- ```
734
-
735
- The agent reads the current enum entries (each carries an `id`, `label`, and `semanticClass`
736
- field), proposes a label rename, and writes through the ceremony. The `semanticClass` field
737
- should not change -- it maps to semantic behavior like `blocked`, `in_progress`, `complete`.
738
-
739
- Show an example: renaming the `discovery` CRM stage to `qualification`.
740
-
741
- **Verification:** Ask: "What is the difference between a System toggle and a label rename?"
742
- (Toggle controls visibility/routing. Label rename changes display text on an existing enum
743
- entry without changing its semantic ID or behavior.)
744
-
745
- **Completion signal:** Mark `[ ] 10 Systems, actions, and labels` as `[x] YYYY-MM-DD` in
746
- `.claude/memory/tutorial-progress.md`.
747
-
748
- ---
749
-
750
- ### Item 11: Entity extensions -- BaseProject, BaseDeal
751
-
752
- **Goal:** The user reads the entity extension pattern in `core/types/entities.ts` and understands
753
- how to add project-specific metadata fields to base entities.
754
-
755
- **Estimated time:** 20 min
756
-
757
- **Files referenced:** `core/types/entities.ts`, `core/config/organization-model.ts`
758
- (for the OM Resources descriptor context)
759
-
760
- **Flow:**
761
-
762
- **Read the demo extension.** Open `core/types/entities.ts`. Walk through both patterns it
763
- demonstrates:
764
-
765
- **Pattern 1: extend with metadata.**
766
-
767
- ```typescript
768
- import { BaseProjectSchema, type BaseProject } from '@elevasis/core/entities'
769
-
770
- export const ProjectMetaSchema = z.object({
771
- budget: z.number().nonnegative(),
772
- clientPriority: z.enum(['low', 'medium', 'high'])
773
- })
774
- export type ProjectMeta = z.infer<typeof ProjectMetaSchema>
775
-
776
- export const ProjectSchema = BaseProjectSchema.extend({ metadata: ProjectMetaSchema })
777
- export type Project = BaseProject<ProjectMeta>
778
- ```
779
-
780
- The base types from `@elevasis/core/entities` are generic over a `\<TMeta>` slot. You pass your
781
- metadata type to specialize the base. `BaseProjectSchema.extend(...)` is the Zod idiom; the
782
- TypeScript type is `BaseProject<ProjectMeta>`.
783
-
784
- **Pattern 2: use a base entity unchanged.**
785
-
786
- ```typescript
787
- export const DealSchema = BaseDealSchema
788
- export type Deal = BaseDeal
789
- ```
790
-
791
- When you have no project-specific fields, re-export the base. This keeps the import path
792
- consistent (`@core/types` everywhere) while avoiding redundant extension.
793
-
794
- **Using entity types in workflows.** When authoring a workflow that receives or returns a
795
- Project or Deal, reference these types in the input/output schemas rather than re-declaring the
796
- shape. This ensures the workflow contract stays in sync with the entity definition as it evolves.
797
-
798
- **Reference for all base shapes.** `@elevasis/core/entities` exports: `BaseProject`,
799
- `BaseProjectSchema`, `BaseProjectInput`, `BaseMilestone`, `BaseMilestoneSchema`,
800
- `BaseTask`, `BaseTaskSchema`, `BaseDeal`, `BaseDealSchema`, `BaseCompany`, `BaseCompanySchema`,
801
- `BaseContact`, `BaseContactSchema`.
802
-
803
- **Domain rename note.** In `core/config/organization-model.ts`, the domain config fields were
804
- renamed in the 2026-04-20 expansion: `crm` -> `sales`, `leadGen` -> `prospecting`,
805
- `delivery` -> `projects`. Older feature ID constants may still appear in UI package code and
806
- scaffold recipes; treat them as implementation constants, not live Organization OS primitives.
807
-
808
- **Verification:** The user can explain when to use Pattern 1 vs Pattern 2 and name two base
809
- entity types they could extend.
810
-
811
- **Completion signal:** Mark `[ ] 11 Entity extensions` as `[x] YYYY-MM-DD` in
812
- `.claude/memory/tutorial-progress.md`.
813
-
814
- ---
815
-
816
- ## SECTION D -- Modules (load on demand)
817
-
818
- Modules in Section D are available any time. No Section B or C prerequisites are enforced. After
819
- completing a module, redisplay the full menu with updated progress markers.
820
-
821
- ---
822
-
823
- ### Item 12: HITL
824
-
825
- **Goal:** The user implements an approval gate using `approval.create()` and understands the
826
- full lifecycle through Command Queue.
827
-
828
- **Estimated time:** 25 min
829
-
830
- **Files referenced:** `.claude/rules/error-handling.md`,
831
- `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
832
-
833
- **Flow:**
834
-
835
- **What HITL is.** Human-in-the-Loop (HITL) pauses a workflow execution and waits for a human
836
- decision before continuing. The execution is suspended at the approval gate; the platform stores
837
- the pending state. When a user approves or rejects in Command Center, the execution resumes.
838
-
839
- **Implementation.** Import `approval` from `@elevasis/sdk/worker` and call it inside a step
840
- handler:
841
-
842
- ```typescript
843
- import { approval } from '@elevasis/sdk/worker'
844
-
845
- const decision = await approval.create({
846
- title: 'Approve Invoice',
847
- description: `Invoice #${input.invoiceId} for $${input.amount} ready for approval.`,
848
- context: { invoiceId: input.invoiceId, amount: input.amount }
849
- })
850
-
851
- if (decision.approved) {
852
- // continue the workflow
853
- } else {
854
- // handle rejection
855
- }
856
- ```
857
-
858
- **Lifecycle.** The step calls `approval.create()` -> platform suspends the execution -> a
859
- pending item appears in the Command Queue in Command Center -> user reviews and approves or
860
- rejects -> execution resumes from the same step with `decision.approved` set.
861
-
862
- **Variant rule.** Always use `variant: 'light'` (hardcoded by the platform; never pass `variant`
863
- in the `approval.create()` call -- the field does not exist on the call signature and will cause
864
- a TypeScript error).
865
-
866
- **Verify.** Deploy the workflow, execute it, confirm that it appears as pending in Command Center
867
- Command Queue, approve it, and confirm the execution completes.
868
-
869
- **Completion signal:** Mark `[ ] 12 HITL` as `[x] YYYY-MM-DD` in
870
- `.claude/memory/tutorial-progress.md`.
871
-
872
- ---
873
-
874
- ### Item 13: Schedules
875
-
876
- **Goal:** The user understands the three Task Scheduler types (Recurring, Relative, Absolute),
877
- uses the `scheduler` singleton inside a workflow, and knows the cron syntax the platform accepts.
878
-
879
- **Estimated time:** 20 min
880
-
881
- **Files referenced:** `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
882
-
883
- **Flow:**
884
-
885
- **The `scheduler` singleton.** Import from `@elevasis/sdk/worker` to trigger workflow actions
886
- from within a running step:
887
-
888
- ```typescript
889
- import { scheduler } from '@elevasis/sdk/worker'
890
-
891
- await scheduler.schedule({
892
- resourceId: 'my-workflow',
893
- triggerAt: new Date(Date.now() + 60 * 60 * 1000), // 1 hour from now
894
- input: { ... }
895
- })
896
- ```
897
-
898
- **Task Scheduler UI -- three types.** Walk the user through Command Center -> Task Scheduler:
899
-
900
- - **Recurring** -- cron-based, runs on a schedule. Standard cron syntax: `0 9 * * 1-5` (9am
901
- weekdays). The platform interprets cron in UTC.
902
- - **Relative** -- fires N minutes/hours/days after a trigger event (e.g., "24 hours after a
903
- deal enters a stage").
904
- - **Absolute** -- fires at a specific UTC datetime (one-shot, not recurring).
905
-
906
- **Creating a schedule.** Show the Task Scheduler create flow: select resource, choose type,
907
- configure the trigger, set input. Schedules appear as `workflow_schedules` rows in the DB -- the
908
- `elevasis-sdk executions` command shows executions triggered by schedules alongside manual ones.
909
-
910
- **Verification:** Ask: "What time zone does the platform use for cron expressions?" (UTC.)
911
-
912
- **Completion signal:** Mark `[ ] 13 Schedules` as `[x] YYYY-MM-DD` in
913
- `.claude/memory/tutorial-progress.md`.
914
-
915
- ---
916
-
917
- ### Item 14: Notifications + integrations
918
-
919
- **Goal:** The user uses the `notifications` and `email` singletons and wires a real integration
920
- adapter using a credential from the project's identity.
921
-
922
- **Estimated time:** 25 min
923
-
924
- **Files referenced:** `.claude/skills/elevasis/SKILL.md` (credentials section),
925
- `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
926
-
927
- **Flow:**
928
-
929
- **`notifications` singleton.** Sends in-app notifications visible in Command Center:
930
-
931
- ```typescript
932
- import { notifications } from '@elevasis/sdk/worker'
933
-
934
- await notifications.send({
935
- title: 'Campaign complete',
936
- message: `Processed ${count} leads.`,
937
- level: 'info' // 'info' | 'warning' | 'error'
938
- })
939
- ```
940
-
941
- **`email` singleton.** Sends transactional email through the platform's configured mail provider:
942
-
943
- ```typescript
944
- import { email } from '@elevasis/sdk/worker'
945
-
946
- await email.send({
947
- to: 'user@example.com',
948
- subject: 'Your report is ready',
949
- body: 'Here is a summary...'
950
- })
951
- ```
952
-
953
- **Real adapter integration.** Read `core/config/organization-model.ts` and find the relevant
954
- OM Resources descriptor or project knowledge node for the integration. Use the documented
955
- credential name as the constructor argument:
956
-
957
- ```typescript
958
- import { createAttioAdapter } from '@elevasis/sdk/worker'
959
- const attio = createAttioAdapter('acme-attio')
960
- ```
961
-
962
- Walk the user through the end-to-end: create the credential in Command Center, reference it in
963
- the adapter constructor, deploy, execute a test run, check that the integration call succeeds.
964
-
965
- **Common error.** If the credential is missing or misspelled, the adapter throws
966
- `PlatformToolError: credential not found`. Check the exact name in Command Center.
967
-
968
- **Verification:** A test execution that calls the integration adapter completes without a
969
- `PlatformToolError`.
970
-
971
- **Completion signal:** Mark `[ ] 14 Notifications + integrations` as `[x] YYYY-MM-DD` in
972
- `.claude/memory/tutorial-progress.md`.
973
-
974
- ---
975
-
976
- ### Item 15: Error handling
977
-
978
- **Goal:** The user knows the three error types, uses `context.logger`, and implements a
979
- try/catch with retryable vs permanent error distinction.
980
-
981
- **Estimated time:** 20 min
982
-
983
- **Files referenced:** `.claude/rules/error-handling.md`,
984
- `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
985
-
986
- **Flow:**
987
-
988
- Read `.claude/rules/error-handling.md` before starting. Then walk through each error type:
989
-
990
- **`ExecutionError`.** Base class for workflow/step failures. Throw to halt an execution with a
991
- user-readable message:
992
-
993
- ```typescript
994
- import { ExecutionError } from '@elevasis/sdk'
995
-
996
- throw new ExecutionError('Payment processing failed', {
997
- context: { invoiceId: input.invoiceId }
998
- })
999
- ```
1000
-
1001
- **`PlatformToolError`.** Thrown by `platform.call()` and typed adapters when an integration
1002
- call fails. Always check `err.retryable`:
1003
-
1004
- ```typescript
1005
- import { PlatformToolError } from '@elevasis/sdk'
1006
-
1007
- try {
1008
- await attio.createRecord({ ... })
1009
- } catch (err) {
1010
- if (err instanceof PlatformToolError) {
1011
- if (err.retryable) {
1012
- context.logger.warn(`Transient error (rate limit or timeout): ${err.message}`)
1013
- // safe to retry or re-throw for the caller to handle
1014
- } else {
1015
- throw new ExecutionError(`Permanent integration error: ${err.message}`)
1016
- }
1017
- }
1018
- throw err
1019
- }
1020
- ```
1021
-
1022
- **`ToolingError`.** Internal SDK infrastructure error. Treat as non-retryable.
1023
-
1024
- **`context.logger`.** Use it for all logging inside handlers. `console.log` is not captured by
1025
- the platform worker runtime. Log levels: `debug`, `info`, `warn`, `error`. The error message in
1026
- an unhandled throw surfaces directly to CLI output and Command Center -- write it for humans.
1027
-
1028
- **Common retryable codes.** `rate_limit_exceeded` and `timeout_error` are retryable.
1029
- `credentials_invalid` and `validation_error` are not.
1030
-
1031
- **Verification:** Demonstrate a handler that catches a `PlatformToolError`, checks `retryable`,
1032
- logs appropriately, and re-throws as an `ExecutionError` with a clear message.
1033
-
1034
- **Completion signal:** Mark `[ ] 15 Error handling` as `[x] YYYY-MM-DD` in
1035
- `.claude/memory/tutorial-progress.md`.
1036
-
1037
- ---
1038
-
1039
- ### Item 16: LLM and agents
1040
-
1041
- **Goal:** The user calls `llm.generate()` with structured output (Zod -> JSON Schema -> typed
1042
- result) and understands when to use an agent definition vs a workflow definition.
1043
-
1044
- **Estimated time:** 25 min
1045
-
1046
- **Files referenced:** `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`,
1047
- `apps/docs/content/docs/sdk/concepts.mdx` (workflow vs agent section)
1048
-
1049
- **Flow:**
1050
-
1051
- **`llm.generate()` with structured output.** The `llm` singleton from `@elevasis/sdk/worker`
1052
- accepts a Zod output schema and returns a typed result:
1053
-
1054
- ```typescript
1055
- import { llm } from '@elevasis/sdk/worker'
1056
- import { z } from 'zod'
1057
-
1058
- const classificationSchema = z.object({
1059
- category: z.enum(['support', 'billing', 'feature-request', 'other']),
1060
- confidence: z.number().min(0).max(1),
1061
- summary: z.string()
1062
- })
1063
-
1064
- const result = await llm.generate({
1065
- prompt: `Classify this ticket: ${input.ticketBody}`,
1066
- outputSchema: classificationSchema,
1067
- model: 'gpt-4o',
1068
- temperature: 0.2
1069
- })
1070
-
1071
- // result is typed as z.infer<typeof classificationSchema>
1072
- context.logger.info(`Classified as: ${result.category} (${result.confidence})`)
1073
- ```
1074
-
1075
- The SDK converts the Zod schema to JSON Schema internally. The LLM is instructed to return JSON
1076
- matching that shape. The result is validated and returned as the inferred TypeScript type.
1077
-
1078
- **Agent definition vs workflow definition.** Read the glossary entries from
1079
- `apps/docs/content/docs/sdk/concepts.mdx`:
1080
-
1081
- - **Workflow** -- deterministic, step-by-step, 300s timeout. Use when inputs and outputs are
1082
- known and the process is predefined.
1083
- - **Agent** -- autonomous, tool-calling, 600s timeout (configurable). Use when the agent needs
1084
- to make decisions, call tools iteratively, or navigate ambiguous inputs.
1085
-
1086
- When to use an agent: the task requires the LLM to decide WHICH tools to call and in WHAT order
1087
- based on what it finds (not predetermined routing). When to use a workflow: the sequence of steps
1088
- is predetermined, even if LLM judgment is involved inside individual steps.
1089
-
1090
- **Model selection.** `gpt-4o` for complex reasoning, `gpt-4o-mini` for speed-sensitive tasks,
1091
- `o3-mini` for multi-step reasoning chains. Temperature: `0.0` for deterministic classification,
1092
- `0.2-0.4` for structured extraction, `0.7+` for creative generation.
1093
-
1094
- **Verification:** A workflow step calls `llm.generate()` with a Zod schema and returns a typed
1095
- value. The type system confirms the result matches the schema without a cast.
1096
-
1097
- **Completion signal:** Mark `[ ] 16 LLM and agents` as `[x] YYYY-MM-DD` in
1098
- `.claude/memory/tutorial-progress.md`.
1099
-
1100
- ---
1101
-
1102
- ### Item 17: Composition (execution.trigger)
1103
-
1104
- **Goal:** The user chains two workflows using `execution.trigger()`, declares the relationship in
1105
- `DeploymentSpec`, and can find the edge in Command View.
1106
-
1107
- **Estimated time:** 20 min
1108
-
1109
- **Files referenced:** `operations/src/index.ts`,
1110
- `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
1111
-
1112
- **Flow:**
1113
-
1114
- **`execution.trigger()`.** Call from inside a step handler to launch another workflow
1115
- asynchronously:
1116
-
1117
- ```typescript
1118
- import { execution } from '@elevasis/sdk/worker'
1119
-
1120
- const { executionId } = await execution.trigger({
1121
- resourceId: 'downstream-workflow',
1122
- input: { ...outputFromCurrentStep }
1123
- })
1124
-
1125
- context.logger.info(`Triggered downstream-workflow: ${executionId}`)
1126
- ```
1127
-
1128
- The calling step does not wait for the downstream workflow to complete. If you need the result,
1129
- use async polling or chain via HITL.
1130
-
1131
- **Declare the relationship in `DeploymentSpec`.** In `operations/src/index.ts`, add a
1132
- `relationships` entry so the platform knows this workflow triggers another:
1133
-
1134
- ```typescript
1135
- const org: DeploymentSpec = {
1136
- version: '0.1.0',
1137
- workflows: [...],
1138
- agents: [...],
1139
- relationships: [
1140
- {
1141
- source: 'upstream-workflow',
1142
- target: 'downstream-workflow',
1143
- type: 'triggers'
1144
- }
1145
- ]
1146
- }
1147
- ```
1148
-
1149
- This metadata populates the Command View graph. Without it, the edge is not visible in the UI
1150
- even if the trigger call works.
1151
-
1152
- **Command View.** Show the user how to find Command View in Command Center -> Operations.
1153
- Deployed relationships appear as directed edges between resource nodes. This is the primary
1154
- debugging surface for understanding how automations are connected.
1155
-
1156
- **Verification:** Deploy both workflows with the relationship declared, then view the edge in
1157
- Command View.
1158
-
1159
- **Completion signal:** Mark `[ ] 17 Composition` as `[x] YYYY-MM-DD` in
1160
- `.claude/memory/tutorial-progress.md`.
1161
-
1162
- ---
1163
-
1164
- ## SECTION E -- Power User
1165
-
1166
- ### Item 18: Rules, memory, scaffold registry
1167
-
1168
- **Goal:** The user can navigate the `.claude/rules/` and `.claude/memory/` directories and
1169
- understands the scaffold registry's purpose.
1170
-
1171
- **Estimated time:** 20 min
1172
-
1173
- **Files referenced:** `.claude/rules/` (all files), `.claude/memory/` (layout),
1174
- `.claude/scaffold-registry.yml` (reference, monorepo-side concept)
1175
-
1176
- **Flow:**
1177
-
1178
- **Rules directory.** List the current rule files in `.claude/rules/`. Each rule is automatically
1179
- loaded by the agent on every session based on its `paths:` frontmatter (path globs that trigger
1180
- auto-load). Key files:
1181
-
1182
- - `agent-start-here.md` -- always-loaded canonical first-read; task-class routing and boundary
1183
- resolution
1184
- - `vibe.md` -- always-loaded ambient intent classifier
1185
- - `organization-os.md` -- loaded when touching org model, System access, Action routing, or entity work
1186
- - `deployment.md` -- loaded when deploying resources
1187
- - `error-handling.md` -- loaded when authoring handlers with error concerns
1188
- - `execution.md` -- loaded when reasoning about the runtime model
1189
- - `observability.md` -- loaded when using `context.logger` or inspecting executions
1190
- - `operations.md` -- loaded when touching `operations/src/`
1191
- - `platform.md` -- loaded when importing from `@elevasis/sdk`
1192
- - `shared-types.md` -- loaded when touching `core/types/`
1193
- - `task-tracking.md` -- loaded when managing project tasks
1194
- - `active-change-index.md` -- flags areas under active architecture change; trust this over
1195
- stable scaffold docs for those areas
1196
-
1197
- To add a new rule: create `.claude/rules/<domain>.md` with `paths:` frontmatter matching the
1198
- glob of files it applies to. The rules system discovers it automatically -- no registration step.
1199
-
1200
- **Memory directory.** List `.claude/memory/`. Common files:
1201
-
1202
- - `profile.md` -- track choice and tone implications (written by this tutorial)
1203
- - `tutorial-progress.md` -- per-item progress markers for both tracks
1204
-
1205
- Memory files are readable by the agent at session start. The `profile.md` file is particularly
1206
- important: it sets the project-wide tone for all sessions after the tutorial track is selected.
1207
-
1208
- **Scaffold registry (monorepo-side concept).** `.claude/scaffold-registry.yml` is the
1209
- monorepo's source-of-truth for scaffold dependencies -- it maps source paths to generated or
1210
- manual scaffolds that depend on them. It drives the PostToolUse reminder hook and `/work handoff`
1211
- preflight in the monorepo. In an external project you are a consumer, not a contributor, of that
1212
- registry. The relevant thing to know: when the SDK ships a template update, the registry controls
1213
- which files are Tier 1 (always replaced on sync), Tier 2 (merge-aware), and Tier 3 (never
1214
- touched). Item 19 covers this in detail.
1215
-
1216
- **Verification:** Ask: "How does the agent know to load `deployment.md` when you run a deploy?"
1217
- (Answer: the `paths:` frontmatter in the rule file matches `operations/` file globs and deploy
1218
- command patterns.)
1219
-
1220
- **Completion signal:** Mark `[ ] 18 Rules, memory, scaffold registry` as `[x] YYYY-MM-DD` in
1221
- `.claude/memory/tutorial-progress.md`.
1222
-
1223
- ---
1224
-
1225
- ### Item 19: Template lifecycle and /git-sync
1226
-
1227
- **Goal:** The user understands the three-tier file classification, runs `/git-sync`, and knows
1228
- what manual reconciliation is required after a template update.
1229
-
1230
- **Estimated time:** 20 min
1231
-
1232
- **Files referenced:** `.claude/skills/git-sync/SKILL.md`, `.claude/sync-notes/` (directory)
1233
-
1234
- **Flow:**
1235
-
1236
- Tell the user:
1237
-
1238
- > "The template you scaffolded from is versioned. When a new SDK version ships, the template
1239
- > updates. `/git-sync` pulls those changes and tells you what changed. You decide what to do
1240
- > with them."
1241
-
1242
- **Three-tier file classification.** Walk through the tiers:
1243
-
1244
- - **Tier 1 (always replaced)** -- SDK-owned files that ship in a known correct state:
1245
- `.claude/skills/*/SKILL.md` (except project-authored skills), `.claude/hooks/`, `CLAUDE.md`
1246
- sections that are platform-managed. These are overwritten on every template sync. Do not put
1247
- custom logic in them; instead use Tier 3 files for project-specific config.
1248
- - **Tier 2 (merge-aware)** -- Files where the template ships defaults but the project may have
1249
- customized: `core/config/organization-model.ts`, `.claude/rules/active-change-index.md`,
1250
- vibe classifier threshold. The sync does not blindly overwrite -- the agent surfaces the diff
1251
- and the user decides what to keep.
1252
- - **Tier 3 (never touched)** -- Project-owned files the template never overwrites: project
1253
- source code in `operations/src/`, `ui/src/`, all `core/types/` files, `core/config/extensions/`,
1254
- custom rules added to `.claude/rules/`, everything in `.claude/memory/`.
1255
-
1256
- **Running `/git-sync`.** Read `.claude/skills/git-sync/SKILL.md` and walk the user through each
1257
- step:
1258
-
1259
- 1. Check for uncommitted changes (`git status --short`). Stop if dirty.
1260
- 2. Snapshot current sync-note filenames before pulling.
1261
- 3. `git pull --rebase` -- stop and report conflicts; do not auto-resolve.
1262
- 4. Detect dependency baseline changes; run `pnpm install` if `package.json` or
1263
- `pnpm-lock.yaml` changed.
1264
- 5. Run baseline verification: `pnpm -C ui check-types`, `pnpm -C ui build`,
1265
- `pnpm -C operations check`, `pnpm -C operations check-types`.
1266
- 6. Surface newly introduced sync notes from `.claude/sync-notes/`. Each note has required
1267
- actions and a verification section.
1268
- 7. Stop. `/git-sync` does not auto-reconcile. Manual follow-up is explicit.
1269
-
1270
- **Sync notes contract.** Files in `.claude/sync-notes/` named `YYYY-MM-DD-<slug>.md` are
1271
- operative release guidance. They use fixed headings: `## Why this note exists`,
1272
- `## Applies to`, `## Required actions`, `## Verification`, `## Not handled by /git-sync`.
1273
- Never edit operative note filenames after they ship -- they are append-only.
1274
-
1275
- **Verification:** The user knows which of their own files are Tier 3 (never touched) and can
1276
- explain why `/git-sync` stops before reconciliation rather than auto-applying diffs.
1277
-
1278
- **Completion signal:** Mark `[ ] 19 Template lifecycle and /git-sync` as `[x] YYYY-MM-DD` in
1279
- `.claude/memory/tutorial-progress.md`.
1280
-
1281
- ---
1282
-
1283
- ## After All 19 Items Complete
1284
-
1285
- When all 19 items are marked `[x]` in `.claude/memory/tutorial-progress.md`, deliver the
1286
- following closing script:
1287
-
1288
- > "You've completed the technical track. Here's where to go from here:
1289
- >
1290
- > - **Build real automations.** You now have the full surface: workflows, schemas, HITL, schedules,
1291
- > LLM integration, error handling, and composition. Start with the domain most relevant to your
1292
- > project and use `/project create` to track the work.
1293
- > - **SDK reference scaffold.** `node_modules/@elevasis/sdk/reference/scaffold/index.mdx` is the
1294
- > canonical recipe index for anything you want to build: adding a System or UI feature, extending lead-gen,
1295
- > customizing CRM actions, authoring agents. Read it whenever you are starting something new.
1296
- > - **Explore the codebase.** `/explore` is your tool for open-ended questions about how things
1297
- > are wired. Use it before making changes in unfamiliar parts of the project.
1298
- > - **Keep the org model current.** Run `/knowledge` any time your business reality changes --
1299
- > new offerings, new customer segments, new goals. The model is the agent's vocabulary for
1300
- > your project; an accurate model means better agent output.
1301
- > - **Stay current with template updates.** When a new SDK version ships, run `/git-sync` to pull
1302
- > it and read the sync notes. They tell you exactly what changed and what manual follow-up is
1303
- > needed."
1
+ # Tutorial: Technical Track
2
+
3
+ This file is loaded by `.claude/skills/tutorial/SKILL.md` when the user selects the technical
4
+ track. Do not invoke this file directly -- the router reads it and dispatches to the lesson the
5
+ user picks.
6
+
7
+ Each lesson is a script for the teaching agent. Instructions in plain text address the agent
8
+ ("Read X", "Walk the user through Y"). User-facing strings are indented as block quotes.
9
+
10
+ After each lesson, update `.claude/memory/tutorial-progress.md` by changing `[ ]` to
11
+ `[x] YYYY-MM-DD` for that item. After completing any full section, redisplay the menu with
12
+ updated markers.
13
+
14
+ ---
15
+
16
+ ## Menu
17
+
18
+ ```
19
+ SECTION A -- The workspace (3 items)
20
+ 1 What is this workspace [ ]
21
+ 2 The skill layer -- slash commands you'll use [ ]
22
+ 3 The vibe layer -- ambient intent classification [ ]
23
+
24
+ SECTION B -- Build your first thing (5 items)
25
+ 4 Echo workflow tour [ ]
26
+ 5 Custom workflow with schemas [ ]
27
+ 6 Platform tools and credentials [ ]
28
+ 7 Multi-step and conditionals [ ]
29
+ 8 Going to production [ ]
30
+
31
+ SECTION C -- The Organization Model (3 items)
32
+ 9 /knowledge ceremony -- identity, customers, [ ]
33
+ offerings via the layered flow
34
+ 10 Systems, actions, and labels [ ]
35
+ 11 Entity extensions -- BaseProject, BaseDeal [ ]
36
+
37
+ SECTION D -- Modules (load on demand) (6 items)
38
+ 12 HITL [ ]
39
+ 13 Schedules [ ]
40
+ 14 Notifications + integrations [ ]
41
+ 15 Error handling [ ]
42
+ 16 LLM and agents [ ]
43
+ 17 Composition (execution.trigger) [ ]
44
+
45
+ SECTION E -- Power user (2 items)
46
+ 18 Rules, memory, scaffold registry [ ]
47
+ 19 Template lifecycle and /git-sync [ ]
48
+ ```
49
+
50
+ ---
51
+
52
+ ## SECTION A -- The Workspace
53
+
54
+ ### Item 1: What is this workspace
55
+
56
+ **Goal:** The user understands the three-layer project structure, the standalone repo model, and
57
+ why the scaffold is described as an agent operating environment, not just an app starter.
58
+
59
+ **Estimated time:** 15 min
60
+
61
+ **Files referenced:** `.claude/rules/agent-start-here.md`, `CLAUDE.md`,
62
+ `node_modules/@elevasis/sdk/reference/scaffold/index.mdx`
63
+
64
+ **Flow:**
65
+
66
+ Open by reading `.claude/rules/agent-start-here.md` (the canonical first-read) and `CLAUDE.md`
67
+ (the project bootstrap surface). Use both to anchor the explanation below.
68
+
69
+ Open with the skip affordance:
70
+
71
+ > "Item 1 covers what this workspace is and how it is structured. If you already know the
72
+ > three-layer layout (ui / operations / core), the standalone repo model, and why the scaffold
73
+ > is an agent operating environment, type 'skip' and I'll mark it complete."
74
+
75
+ If the user skips, mark `[x] YYYY-MM-DD` in `.claude/memory/tutorial-progress.md` for item 1
76
+ and move on.
77
+
78
+ Otherwise, walk through the following:
79
+
80
+ **Three runtime layers.** The template is divided into three directories with hard runtime
81
+ boundaries:
82
+
83
+ - `ui/` -- React 19 frontend (Vite, TanStack Router, Mantine). Browser runtime. Imports from
84
+ `core/` only.
85
+ - `operations/` -- Platform workflows and agents (Elevasis SDK). Node target. Imports from
86
+ `core/` only.
87
+ - `core/` -- Runtime-agnostic shared contracts: Zod schemas, TypeScript types, organization
88
+ model configuration. No React, no Node APIs, no SDK worker imports.
89
+
90
+ Emphasize: `ui/` and `operations/` are separate runtimes. They communicate through the platform
91
+ API at runtime. At build time they share types only via `core/`.
92
+
93
+ **Standalone repo.** This project is NOT part of the monorepo pnpm workspace. It has its own
94
+ `.git/`, own `pnpm-lock.yaml`, own `node_modules/`. The monorepo boundary hook does not apply
95
+ here. Git, gh, and CLI commands work directly.
96
+
97
+ **Agent operating environment.** Read the "Template Surfaces" section from `agent-start-here.md`
98
+ aloud to the user. Key point: the `.claude/` directory is a first-class surface -- rules (always
99
+ loaded), skills (invocable via slash commands), hooks (run on tool calls), and memory (persists
100
+ across sessions). The scaffold is not just an app starter; the agent reads `.claude/rules/` on
101
+ every session and uses it to route task classes, resolve boundaries, and choose the right tool.
102
+
103
+ **SDK reference scaffold.** After `pnpm install`, the entry point
104
+ `node_modules/@elevasis/sdk/reference/scaffold/index.mdx` gives access to canonical recipes, UI
105
+ patterns, the gating model, contracts, and a glossary. Whenever the user wants the authoritative
106
+ answer on a scaffold surface (how to add a System or UI feature, extend an entity, wire a workflow), that
107
+ index is the starting point.
108
+
109
+ **Verification:** Ask the user: "Where does the agent look first when entering a session?" (Answer:
110
+ `agent-start-here.md` via the always-loaded rules.) If they get it right, continue. If not, point
111
+ them to the "First Action: Check Active Projects" and "Discovery Order" sections in
112
+ `agent-start-here.md`.
113
+
114
+ **Completion signal:** Mark `[ ] 1 What is this workspace` as `[x] YYYY-MM-DD` in
115
+ `.claude/memory/tutorial-progress.md`.
116
+
117
+ ---
118
+
119
+ ### Item 2: The skill layer -- slash commands you'll use
120
+
121
+ **Goal:** The user knows all 12 slash commands, how to invoke them, where they live, and can
122
+ demonstrate `/status` and `/project`.
123
+
124
+ **Estimated time:** 15 min
125
+
126
+ **Files referenced:** `.claude/skills/*/SKILL.md` (skim), `CLAUDE.md` slash command table
127
+
128
+ **Flow:**
129
+
130
+ Open with the skip affordance:
131
+
132
+ > "Item 2 walks through the 12 slash commands in this scaffold. If you've already used them and
133
+ > know where they live, type 'skip' and I'll mark it complete."
134
+
135
+ If the user skips, mark complete and move on.
136
+
137
+ Otherwise, read the Slash Commands table in `CLAUDE.md` aloud. Then explain the skill system:
138
+
139
+ **Invocation pattern.** Every slash command is a skill. Type `/<name>` (optionally with args,
140
+ e.g., `/knowledge systems`). The agent reads `.claude/skills/<name>/SKILL.md` and follows its
141
+ instructions. Skills may be context-forked (they run in a subagent) or inline. The frontmatter
142
+ `context: fork` means a subagent handles it.
143
+
144
+ **Where they live.** Each skill lives in `.claude/skills/<name>/SKILL.md`. Multi-step operations
145
+ that belong to a skill (but are too large for `SKILL.md`) live in
146
+ `.claude/skills/<name>/operations/<op>.md`.
147
+
148
+ **How the agent knows to use them.** The `description` frontmatter field (or `metadata.promptSignals`)
149
+ tells the agent when to auto-invoke a skill without an explicit slash command. For example,
150
+ `/knowledge` auto-invokes whenever the conversation references org-model entities.
151
+
152
+ Walk through each of the 12 commands:
153
+
154
+ - `/setup` -- first-time bootstrap: placeholder replacement, deps, verification, then hands off
155
+ to `/knowledge`
156
+ - `/save` -- conversation fanout: updates knowledge docs, persists `prj_tasks.resume_context`
157
+ via `elevasis-sdk project:task:save`, creates a project note on blockers/status signals
158
+ - `/dsp` -- parallel agent dispatch for implementation tasks with multiple independent steps
159
+ - `/deploy` -- test, build, commit, push pipeline
160
+ - `/explore` -- codebase exploration anchored to docs
161
+ - `/git-sync` -- pull latest changes, surface new template sync notes, install when needed,
162
+ run baseline verification, then stop before manual reconciliation
163
+ - `/status` -- quick project health check
164
+ - `/project` -- primary work-tracking entry point; portfolio orientation, intent detection
165
+ (resume vs new), and project/milestone/task/note lifecycle via `elevasis-sdk project:*`
166
+ - `/elevasis` -- SDK operations: check, deploy, exec, describe, logs, creds
167
+ - `/sync` -- fresh reinstall and cache reset when local deps or build caches are stale
168
+ - `/knowledge` -- org model ceremony: read, codify, toggle, layered flow for identity through
169
+ goals
170
+ - `/submit-request` -- submit a structured request (bug, feature, support) to the platform
171
+
172
+ **Demo 1: `/status`.** Ask the user to type `/status`. Narrate what it shows: project health
173
+ summary, active projects, recent executions if any.
174
+
175
+ **Demo 2: `/project`.** Ask the user to type `/project`. Walk them through the portfolio
176
+ orientation output. Show how to create a task: `/project create task --title "My first task"`.
177
+
178
+ **Verification:** The user can name any 3 commands unprompted and describe what they do.
179
+
180
+ **Completion signal:** Mark `[ ] 2 The skill layer` as `[x] YYYY-MM-DD` in
181
+ `.claude/memory/tutorial-progress.md`.
182
+
183
+ ---
184
+
185
+ ### Item 3: The vibe layer -- ambient intent classification
186
+
187
+ **Goal:** The user understands the 7-intent classifier, can recognize when it fires, and knows
188
+ it is absent in the monorepo.
189
+
190
+ **Estimated time:** 15 min
191
+
192
+ **Files referenced:** `.claude/rules/vibe.md`, `CLAUDE.md` ambient vibe section
193
+
194
+ **Flow:**
195
+
196
+ Open with the skip affordance:
197
+
198
+ > "Item 3 covers the vibe layer -- an ambient intent classifier that fires on every natural-language
199
+ > message. If you already know the 7 intent types and how the classifier routes them, type 'skip'
200
+ > and I'll mark it complete."
201
+
202
+ If the user skips, mark complete and move on.
203
+
204
+ Otherwise, read `.claude/rules/vibe.md` before explaining. Then walk through:
205
+
206
+ **What vibe is.** Every natural-language message in an external project passes through the vibe
207
+ classifier before the agent acts. No slash command, no activation phrase. The agent silently
208
+ classifies the message into one of seven intent types and routes to the right behavior. The user
209
+ never sees the classification.
210
+
211
+ **The seven intent types.** Walk through each by name with one fixture example:
212
+
213
+ - **Capture** -- "Add a task to follow up with the Shopify client." Agent drafts, confirms,
214
+ writes via `elevasis-sdk project:*`.
215
+ - **Query** -- "What's pending in the HITL queue?" Agent reads and narrates.
216
+ - **Describe** -- "What's going on with this deal?" Agent narrates from org model labels.
217
+ - **Transition** -- "Done with the proposal draft." Agent confirms, updates task status via
218
+ `elevasis-sdk project:task:save`.
219
+ - **Navigate** -- "Let's focus on the onboarding flow." Agent updates scope, narrates the shift.
220
+ - **Codify** -- "We track deals by Shopify platform." Agent detects new organizational reality
221
+ and delegates to `/knowledge`.
222
+ - **Toggle** -- "Turn on the lead-gen system." Agent delegates to `/knowledge systems`.
223
+
224
+ **Important behavioral rules.** Codify and Toggle delegate immediately to `/knowledge` -- the
225
+ vibe layer detects intent but does NOT run the ceremony itself. The ceremony (snapshot, propose,
226
+ confirm, write, validate, rollback) belongs to `/knowledge`. Ambiguous messages get one
227
+ clarifying question; no precedence rule is applied.
228
+
229
+ **Where it applies.** Vibe is always-on in external projects. It is explicitly OFF in the
230
+ monorepo. The monorepo uses task-class routing via `agent-start-here.md` instead. If the user is
231
+ working inside the monorepo (`apps/`, `packages/`, etc.), vibe does not fire.
232
+
233
+ **Reference.** The full classifier definition, fixture tables, and codify heuristics live in
234
+ `.claude/rules/vibe.md`. The `CLAUDE.md` table is a pointer -- for authoritative behavior, read
235
+ the rule file.
236
+
237
+ **Verification:** Ask "What happens when you type 'turn on SEO'?" Answer: Vibe classifies it as
238
+ Toggle intent and delegates to `/knowledge systems` without running the ceremony itself.
239
+
240
+ **Completion signal:** Mark `[ ] 3 The vibe layer` as `[x] YYYY-MM-DD` in
241
+ `.claude/memory/tutorial-progress.md`.
242
+
243
+ ---
244
+
245
+ ## SECTION B -- Build Your First Thing
246
+
247
+ ### Item 4: Echo workflow tour
248
+
249
+ **Goal:** The user reads the echo workflow source, validates it, deploys it, and executes it
250
+ end-to-end.
251
+
252
+ **Estimated time:** 20 min
253
+
254
+ **Files referenced:** `operations/src/example/echo.ts`, `core/types/index.ts`,
255
+ `operations/src/index.ts`
256
+
257
+ **Commands:** `pnpm -C operations check`, `pnpm -C operations deploy`,
258
+ `pnpm elevasis-sdk exec echo --input '{"message":"hi"}'`
259
+
260
+ **Flow:**
261
+
262
+ Tell the user:
263
+
264
+ > "Let's tour the echo workflow -- the starter resource that ships with every template project.
265
+ > We'll read the source, run the validator, deploy it, and execute it."
266
+
267
+ **Step 1: Read the source.** Open `operations/src/example/echo.ts` with the user. Walk through
268
+ each section:
269
+
270
+ - `config` block: `resourceId` (the deploy-time unique ID), `name`, `type: 'workflow'`,
271
+ `description`, `version` (semver, bump on contract changes), `status: 'dev'` (new resources
272
+ start here; `'prod'` means visible to end users in the production environment).
273
+ - `contract` block: `inputSchema` and `outputSchema` are imported from `core/types/index.ts`,
274
+ NOT defined inline. This is the pattern: schemas live in `core/` so both the frontend and
275
+ `operations/` can import them without creating a dependency cycle.
276
+ - `steps` map: each step has `id`, `name`, `description`, a `handler` async function, and
277
+ `next: null` (last step). The handler receives `input` and `context`. `context.logger.info()`
278
+ is the correct logging call -- `console.log` is not captured by the platform.
279
+ - `entryPoint`: the key from `steps` that runs first.
280
+ - `interface.form`: defines the UI form the Command Center renders when a user triggers this
281
+ workflow manually.
282
+
283
+ **Step 2: Validate.** Run:
284
+
285
+ ```bash
286
+ pnpm -C operations check
287
+ ```
288
+
289
+ Show the output. Explain: this catches duplicate `resourceId`s, broken step chains (`next`
290
+ referencing a non-existent step), invalid schema serialization, and other errors the platform
291
+ would reject at deploy time. Exit code 0 = pass.
292
+
293
+ **Step 3: Deploy.** Run:
294
+
295
+ ```bash
296
+ pnpm -C operations deploy
297
+ ```
298
+
299
+ Walk through the output stages: Authenticating, Validating, Bundling (esbuild packages
300
+ `operations/src/index.ts` and all dependencies into a single CJS file), Uploading. After deploy,
301
+ resources are live immediately -- no restart required.
302
+
303
+ **Step 4: Execute.** Run:
304
+
305
+ ```bash
306
+ pnpm elevasis-sdk exec echo --input '{"message":"hi"}'
307
+ ```
308
+
309
+ Show the output: status, duration, and output `{ "echo": "hi" }`. Explain: the platform
310
+ validated `{"message":"hi"}` against `echoInputSchema`, spun up an ephemeral worker thread,
311
+ ran the handler, returned the result, and terminated the worker.
312
+
313
+ **Step 5: Check history.** Run:
314
+
315
+ ```bash
316
+ pnpm elevasis-sdk executions echo
317
+ ```
318
+
319
+ Pick the execution ID from the list and run:
320
+
321
+ ```bash
322
+ pnpm elevasis-sdk execution echo <execution-id>
323
+ ```
324
+
325
+ Show the full detail including logs. Point out the `[echo] Received message: "hi"` log line
326
+ emitted by `context.logger.info()` in the handler.
327
+
328
+ **Verification:** The user sees the execution complete with `{ "echo": "hi" }` output.
329
+
330
+ **Completion signal:** Mark `[ ] 4 Echo workflow tour` as `[x] YYYY-MM-DD` in
331
+ `.claude/memory/tutorial-progress.md`.
332
+
333
+ ---
334
+
335
+ ### Item 5: Custom workflow with schemas
336
+
337
+ **Goal:** The user creates a new workflow in its own domain directory, defines a Zod input schema
338
+ in `core/types/`, registers it in `operations/src/index.ts`, and validates it.
339
+
340
+ **Estimated time:** 25 min
341
+
342
+ **Files referenced:** `operations/src/example/echo.ts` (model), `core/types/index.ts`,
343
+ `operations/src/index.ts`
344
+
345
+ **Commands:** `pnpm -C operations check`, `pnpm -C core check-types`
346
+
347
+ **Flow:**
348
+
349
+ Tell the user:
350
+
351
+ > "Now you'll build a real workflow from scratch. We'll pick a domain for your project, define
352
+ > the input and output schemas in `core/types/`, author the workflow in `operations/src/`, and
353
+ > register it."
354
+
355
+ **Step 1: Pick a domain.** Ask the user what their project does -- even a rough description is
356
+ enough. Suggest a simple workflow relevant to their context (e.g., "classify a support ticket",
357
+ "score a lead", "send a notification on a Stripe event"). Name the domain in kebab-case.
358
+
359
+ **Step 2: Define schemas in `core/types/`.** Open `core/types/index.ts`. Walk the user through
360
+ the schema convention:
361
+
362
+ ```typescript
363
+ export const myWorkflowInputSchema = z.object({
364
+ // define fields here
365
+ })
366
+ export type MyWorkflowInput = z.infer<typeof myWorkflowInputSchema>
367
+
368
+ export const myWorkflowOutputSchema = z.object({
369
+ // define fields here
370
+ })
371
+ export type MyWorkflowOutput = z.infer<typeof myWorkflowOutputSchema>
372
+ ```
373
+
374
+ Explain: `z.infer` gives you a TypeScript type from the schema so the type system can check your
375
+ handlers. You define once, get both runtime validation and compile-time inference. The schema
376
+ lives in `core/` so the frontend can import it for form validation without importing SDK worker
377
+ code.
378
+
379
+ Explain common field types: `z.string()`, `z.number()`, `z.boolean()`, `z.enum([...])`,
380
+ `z.string().optional()`, `z.object({...})`, `z.array(z.string())`.
381
+
382
+ After writing the schemas, run:
383
+
384
+ ```bash
385
+ pnpm -C core check-types
386
+ ```
387
+
388
+ Fix any TypeScript errors before continuing.
389
+
390
+ **Step 3: Create the domain directory.** Create `operations/src/<domain>/` with two files:
391
+ `index.ts` (the domain barrel) and `<workflow-name>.ts` (the workflow implementation). Mirror
392
+ the echo structure but use the new schemas imported from `@core/types`.
393
+
394
+ Key points to emphasize:
395
+
396
+ - `resourceId` must be unique within the organization (kebab-case).
397
+ - `status: 'dev'` for new resources.
398
+ - `next: null` on the last step.
399
+ - Import schemas from `@core/types`, never define them inline in the workflow file.
400
+
401
+ **Step 4: Register in `operations/src/index.ts`.** Show the current registry:
402
+
403
+ ```typescript
404
+ import * as example from './example/index.js'
405
+ import * as emailNotification from './email-notification/exports.js'
406
+
407
+ const org: DeploymentSpec = {
408
+ version: '0.1.0',
409
+ workflows: [...example.workflows, ...emailNotification.workflows],
410
+ agents: [...example.agents, ...emailNotification.agents]
411
+ }
412
+ ```
413
+
414
+ Add the new domain import and spread its `workflows` into the `DeploymentSpec`.
415
+
416
+ **Step 5: Validate.** Run `pnpm -C operations check`. The output should now show N+1 resources
417
+ with 0 errors.
418
+
419
+ **Verification:** `pnpm -C operations check` passes with the new workflow listed.
420
+
421
+ **Completion signal:** Mark `[ ] 5 Custom workflow with schemas` as `[x] YYYY-MM-DD` in
422
+ `.claude/memory/tutorial-progress.md`.
423
+
424
+ ---
425
+
426
+ ### Item 6: Platform tools and credentials
427
+
428
+ **Goal:** The user understands singleton adapters vs factory adapters, imports them correctly,
429
+ and knows how to create a credential in Command Center.
430
+
431
+ **Estimated time:** 20 min
432
+
433
+ **Files referenced:** `.claude/skills/elevasis/SKILL.md` (creds section),
434
+ `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
435
+
436
+ **Flow:**
437
+
438
+ Tell the user:
439
+
440
+ > "The platform provides typed adapters for external services: CRM, email, payments, AI, storage,
441
+ > and more. You call them from workflow handlers without putting API keys in your code."
442
+
443
+ **Singleton adapters.** Import once at the top of the worker file, use directly:
444
+
445
+ ```typescript
446
+ import { llm, scheduler, storage, notifications } from '@elevasis/sdk/worker'
447
+ ```
448
+
449
+ These are singletons -- no credential binding at construction. They use platform-managed config.
450
+ Use them for: LLM generation, scheduling, object storage, in-app notifications.
451
+
452
+ **Factory adapters.** Credential-bound: constructed with a credential name, then used:
453
+
454
+ ```typescript
455
+ import { createAttioAdapter } from '@elevasis/sdk/worker'
456
+
457
+ const attio = createAttioAdapter('my-attio-cred')
458
+ // inside a step handler:
459
+ await attio.createRecord({ ... })
460
+ ```
461
+
462
+ The string `'my-attio-cred'` is the credential name you register in Command Center. The naming
463
+ convention is `{org}-{service}` kebab-case, e.g. `acme-attio`, `acme-stripe`.
464
+
465
+ **Credential setup in Command Center.** Walk the user through: Command Center -> Settings ->
466
+ Credentials -> Create. The credential is stored encrypted on the platform. Workers access it at
467
+ runtime through the adapter. It never appears in code or `.env`. The `.env` file holds only
468
+ `ELEVASIS_PLATFORM_KEY` for CLI authentication.
469
+
470
+ **Common error.** `PlatformToolError: credential not found` means the credential name in code
471
+ does not exactly match what was created in Command Center. Check spelling and case; credential
472
+ names are case-sensitive.
473
+
474
+ **CLI credential management.** Show the `/elevasis creds` surface as an alternative to the UI:
475
+
476
+ ```bash
477
+ pnpm elevasis-sdk creds list
478
+ pnpm elevasis-sdk creds create --name acme-attio --type api-key --value '{"apiKey":"..."}'
479
+ ```
480
+
481
+ **Verification:** Ask: "Where do integration credentials live at runtime?" Answer: on the platform,
482
+ injected by the worker runtime. Not in `.env`, not in code.
483
+
484
+ **Completion signal:** Mark `[ ] 6 Platform tools and credentials` as `[x] YYYY-MM-DD` in
485
+ `.claude/memory/tutorial-progress.md`.
486
+
487
+ ---
488
+
489
+ ### Item 7: Multi-step and conditionals
490
+
491
+ **Goal:** The user implements a two-step LINEAR workflow and a CONDITIONAL workflow, understanding
492
+ how data flows between steps.
493
+
494
+ **Estimated time:** 25 min
495
+
496
+ **Files referenced:** `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`,
497
+ `apps/docs/content/docs/sdk/concepts.mdx` (design decisions section)
498
+
499
+ **Flow:**
500
+
501
+ **Step 1: LINEAR steps.** Extend the workflow from Item 5 (or create a new one) to add a second
502
+ step. Show the `next` field on step 1 pointing to the key of step 2:
503
+
504
+ ```typescript
505
+ steps: {
506
+ fetchData: {
507
+ id: 'fetchData',
508
+ name: 'Fetch Data',
509
+ handler: async (input, context) => {
510
+ // ... fetch or compute something
511
+ return { result: 'some-value' }
512
+ },
513
+ inputSchema: myInputSchema,
514
+ outputSchema: z.object({ result: z.string() }),
515
+ next: 'processData' // <-- key of the next step
516
+ },
517
+ processData: {
518
+ id: 'processData',
519
+ name: 'Process Data',
520
+ handler: async (input, context) => {
521
+ const { result } = input // receives output from fetchData
522
+ return { finalResult: result.toUpperCase() }
523
+ },
524
+ inputSchema: z.object({ result: z.string() }),
525
+ outputSchema: myOutputSchema,
526
+ next: null
527
+ }
528
+ },
529
+ entryPoint: 'fetchData'
530
+ ```
531
+
532
+ Emphasize: the output schema of step N must match the input schema of step N+1. The platform
533
+ validates this chain at deploy time. Data passes from step to step -- no global state, no shared
534
+ variables.
535
+
536
+ **Step 2: CONDITIONAL routing.** Import `StepType` and show a conditional branch:
537
+
538
+ ```typescript
539
+ import type { WorkflowDefinition, StepType } from '@elevasis/sdk'
540
+
541
+ // ... inside steps:
542
+ routeStep: {
543
+ id: 'routeStep',
544
+ type: StepType.CONDITIONAL,
545
+ name: 'Route by Score',
546
+ handler: async (input, context) => {
547
+ if (input.score >= 80) return { path: 'approve', ...input }
548
+ if (input.score >= 50) return { path: 'review', ...input }
549
+ return { path: 'reject', ...input }
550
+ },
551
+ routes: {
552
+ approve: 'approveStep',
553
+ review: 'reviewStep',
554
+ default: 'rejectStep' // always include a default
555
+ },
556
+ // ...
557
+ }
558
+ ```
559
+
560
+ Always include a `default` route. Without it, an execution whose output does not match any
561
+ explicit key will fail at runtime.
562
+
563
+ **Verification:** `pnpm -C operations check` passes with the multi-step workflow registered. Ask
564
+ the user what happens if they omit the `default` route (runtime failure for unmatched paths).
565
+
566
+ **Completion signal:** Mark `[ ] 7 Multi-step and conditionals` as `[x] YYYY-MM-DD` in
567
+ `.claude/memory/tutorial-progress.md`.
568
+
569
+ ---
570
+
571
+ ### Item 8: Going to production
572
+
573
+ **Goal:** The user knows the dev/prod split, version bumping flags, and the SDK CLI CWD
574
+ guidance in the deployment rule.
575
+
576
+ **Estimated time:** 15 min
577
+
578
+ **Files referenced:** `.claude/rules/deployment.md`
579
+
580
+ **Commands:** `pnpm -C operations deploy:prod`
581
+
582
+ **Flow:**
583
+
584
+ **Dev vs prod targeting.** The default `pnpm -C operations deploy` targets the development
585
+ environment. To deploy to production:
586
+
587
+ ```bash
588
+ pnpm -C operations deploy:prod
589
+ ```
590
+
591
+ In `config.status`: `'dev'` means the resource is visible only in dev mode. Change to `'prod'`
592
+ before deploying to production -- otherwise the resource deploys but is not exposed in the
593
+ production surface.
594
+
595
+ **Version bumping.** The deploy command accepts version bump flags that are written back to
596
+ `operations/src/index.ts`:
597
+
598
+ ```bash
599
+ pnpm -C operations deploy:prod # no bump (same version)
600
+ # or pass a flag via pnpm scripts if wired in package.json:
601
+ pnpm elevasis-sdk deploy --prod --patch # 1.0.0 -> 1.0.1
602
+ pnpm elevasis-sdk deploy --prod --minor # 1.0.0 -> 1.1.0
603
+ pnpm elevasis-sdk deploy --prod --major # 1.0.0 -> 2.0.0
604
+ ```
605
+
606
+ Bump rules: `--patch` for bug fixes, `--minor` for new features (no breaking schema changes),
607
+ `--major` for breaking input/output schema changes.
608
+
609
+ **SDK CLI CWD guidance.** Read `.claude/rules/deployment.md`. Two critical rules:
610
+
611
+ 1. The `--prod` flag belongs to the `deploy` command:
612
+
613
+ ```bash
614
+ # Correct
615
+ pnpm elevasis-sdk deploy --prod
616
+ ```
617
+
618
+ The `pnpm -C operations deploy:prod` script in `package.json` handles this correctly.
619
+ Prefer the script over a raw CLI call for production deploys.
620
+
621
+ 2. Never use bare `cd <dir> && elevasis-sdk ...` -- use a subshell `(cd <dir> && ...)` or
622
+ `pnpm -C <dir> ...` to avoid CWD drift that causes env resolution failures.
623
+
624
+ **Standard pre-production checklist.** Walk the user through:
625
+
626
+ ```
627
+ 1. pnpm -C operations check -- validate resources
628
+ 2. pnpm -C operations check-types -- TypeScript type-check
629
+ 3. pnpm elevasis-sdk exec <id> -i '...' -- test in dev
630
+ 4. pnpm -C operations deploy:prod -- ship to prod
631
+ ```
632
+
633
+ **Verification:** The user can explain where `--prod` must be placed and why.
634
+
635
+ **Completion signal:** Mark `[ ] 8 Going to production` as `[x] YYYY-MM-DD` in
636
+ `.claude/memory/tutorial-progress.md`.
637
+
638
+ ---
639
+
640
+ ## SECTION C -- The Organization Model
641
+
642
+ ### Item 9: /knowledge ceremony -- identity, customers, offerings via the layered flow
643
+
644
+ **Goal:** The user runs `/knowledge` and understands the six-step write ceremony, why direct
645
+ edits to `core/config/organization-model.ts` are blocked, and the layered flow order.
646
+
647
+ **Estimated time:** 25 min
648
+
649
+ **Files referenced:** `.claude/skills/knowledge/SKILL.md`, `core/config/organization-model.ts`,
650
+ `.claude/rules/organization-os.md`
651
+
652
+ **Flow:**
653
+
654
+ Tell the user:
655
+
656
+ > "The organization model is the semantic contract layer that defines your business reality:
657
+ > who you are, who your customers are, what you offer, your team, and your goals. All edits go
658
+ > through `/knowledge` -- not direct file edits."
659
+
660
+ **Why direct edits are blocked.** Read `core/config/organization-model.ts`. The file calls
661
+ `resolveOrganizationModel()` which runs Zod cross-reference validation: every customer segment
662
+ referenced in offerings must exist in `customers`, every resource mapping must reference a valid
663
+ system ID, and so on. A direct edit that passes TypeScript can still fail the cross-ref check,
664
+ leaving the project in a broken state. The `/knowledge` ceremony runs both checks and rolls back
665
+ on failure.
666
+
667
+ **The six-step ceremony.** Walk through `.claude/skills/knowledge/SKILL.md`:
668
+
669
+ 1. **Snapshot** -- reads `core/config/organization-model.ts` into memory before any edit
670
+ 2. **Propose** -- shows the diff and the proposed new value alongside current value
671
+ 3. **Confirm** -- pauses for explicit user confirmation; never writes without a clear yes
672
+ 4. **Write** -- applies the edit
673
+ 5. **Validate** -- runs `pnpm -C operations check-types` (TypeScript) then `pnpm -C operations
674
+ check` (Zod parse via `resolveOrganizationModel()`)
675
+ 6. **Rollback** -- if either check fails, restores from the Step 1 snapshot
676
+
677
+ **The layered flow.** Run `/knowledge` with no argument to walk through the full flow:
678
+ identity -> customers -> offerings -> roles -> goals -> techStack. The agent reads the current
679
+ state of each domain, proposes any missing or incomplete fields, and asks for confirmation before
680
+ writing.
681
+
682
+ Or target a specific domain:
683
+
684
+ - `/knowledge identity` -- legal name, mission/vision, industry, geography, timezone
685
+ - `/knowledge customers` -- customer segments with jobs-to-be-done, pains, gains
686
+ - `/knowledge offerings` -- products and services with pricing model and segment references
687
+ - `/knowledge roles` -- role chart with responsibilities and reporting lines
688
+ - `/knowledge goals` -- organizational goals with period and measurable outcomes
689
+ - `/knowledge techStack` -- external SaaS and integration context tied to OM Resources descriptors or knowledge nodes
690
+
691
+ **Demo.** Ask the user to run `/knowledge identity`. Walk through the ceremony together -- read
692
+ the current state, propose an edit, confirm, watch it validate.
693
+
694
+ **Verification:** The user can describe what `resolveOrganizationModel()` does and why the
695
+ rollback step exists.
696
+
697
+ **Completion signal:** Mark `[ ] 9 /knowledge ceremony` as `[x] YYYY-MM-DD` in
698
+ `.claude/memory/tutorial-progress.md`.
699
+
700
+ ---
701
+
702
+ ### Item 10: Systems, actions, and labels
703
+
704
+ **Goal:** The user can enable/disable a System via `/knowledge systems`, understand Actions as
705
+ invokable operations, and rename a display label via `/knowledge labels`.
706
+
707
+ **Estimated time:** 15 min
708
+
709
+ **Files referenced:** `.claude/skills/knowledge/operations/features.md` (legacy compatibility),
710
+ `.claude/skills/knowledge/operations/labels.md`, `core/config/organization-model.ts`
711
+
712
+ **Flow:**
713
+
714
+ **Systems.** The org model uses Systems for availability, routing, ownership, navigation
715
+ grouping, and knowledge mounts. Toggle availability by running:
716
+
717
+ ```
718
+ /knowledge systems
719
+ ```
720
+
721
+ The ceremony proposes the change (e.g., `seo: false -> true`), asks for confirmation, writes,
722
+ and validates. Older scaffold recipes and UI packages may still say "feature"; translate that to
723
+ System when discussing Organization OS availability or routing.
724
+
725
+ System toggles affect the UI shell: a disabled System removes its nav entry and routes from
726
+ the shell. Actions are the invokable operations owned or exposed by a System.
727
+
728
+ **Labels.** The `labels` domain controls display strings on enum entries -- CRM pipeline stages,
729
+ lead-gen lifecycle statuses, project statuses, and so on. Rename by running:
730
+
731
+ ```
732
+ /knowledge labels
733
+ ```
734
+
735
+ The agent reads the current enum entries (each carries an `id`, `label`, and `semanticClass`
736
+ field), proposes a label rename, and writes through the ceremony. The `semanticClass` field
737
+ should not change -- it maps to semantic behavior like `blocked`, `in_progress`, `complete`.
738
+
739
+ Show an example: renaming the `discovery` CRM stage to `qualification`.
740
+
741
+ **Verification:** Ask: "What is the difference between a System toggle and a label rename?"
742
+ (Toggle controls visibility/routing. Label rename changes display text on an existing enum
743
+ entry without changing its semantic ID or behavior.)
744
+
745
+ **Completion signal:** Mark `[ ] 10 Systems, actions, and labels` as `[x] YYYY-MM-DD` in
746
+ `.claude/memory/tutorial-progress.md`.
747
+
748
+ ---
749
+
750
+ ### Item 11: Entity extensions -- BaseProject, BaseDeal
751
+
752
+ **Goal:** The user reads the entity extension pattern in `core/types/entities.ts` and understands
753
+ how to add project-specific metadata fields to base entities.
754
+
755
+ **Estimated time:** 20 min
756
+
757
+ **Files referenced:** `core/types/entities.ts`, `core/config/organization-model.ts`
758
+ (for the OM Resources descriptor context)
759
+
760
+ **Flow:**
761
+
762
+ **Read the demo extension.** Open `core/types/entities.ts`. Walk through both patterns it
763
+ demonstrates:
764
+
765
+ **Pattern 1: extend with metadata.**
766
+
767
+ ```typescript
768
+ import { BaseProjectSchema, type BaseProject } from '@elevasis/core/entities'
769
+
770
+ export const ProjectMetaSchema = z.object({
771
+ budget: z.number().nonnegative(),
772
+ clientPriority: z.enum(['low', 'medium', 'high'])
773
+ })
774
+ export type ProjectMeta = z.infer<typeof ProjectMetaSchema>
775
+
776
+ export const ProjectSchema = BaseProjectSchema.extend({ metadata: ProjectMetaSchema })
777
+ export type Project = BaseProject<ProjectMeta>
778
+ ```
779
+
780
+ The base types from `@elevasis/core/entities` are generic over a `\<TMeta>` slot. You pass your
781
+ metadata type to specialize the base. `BaseProjectSchema.extend(...)` is the Zod idiom; the
782
+ TypeScript type is `BaseProject<ProjectMeta>`.
783
+
784
+ **Pattern 2: use a base entity unchanged.**
785
+
786
+ ```typescript
787
+ export const DealSchema = BaseDealSchema
788
+ export type Deal = BaseDeal
789
+ ```
790
+
791
+ When you have no project-specific fields, re-export the base. This keeps the import path
792
+ consistent (`@core/types` everywhere) while avoiding redundant extension.
793
+
794
+ **Using entity types in workflows.** When authoring a workflow that receives or returns a
795
+ Project or Deal, reference these types in the input/output schemas rather than re-declaring the
796
+ shape. This ensures the workflow contract stays in sync with the entity definition as it evolves.
797
+
798
+ **Reference for all base shapes.** `@elevasis/core/entities` exports: `BaseProject`,
799
+ `BaseProjectSchema`, `BaseProjectInput`, `BaseMilestone`, `BaseMilestoneSchema`,
800
+ `BaseTask`, `BaseTaskSchema`, `BaseDeal`, `BaseDealSchema`, `BaseCompany`, `BaseCompanySchema`,
801
+ `BaseContact`, `BaseContactSchema`.
802
+
803
+ **Domain rename note.** In `core/config/organization-model.ts`, the domain config fields were
804
+ renamed in the 2026-04-20 expansion: `crm` -> `sales`, `leadGen` -> `prospecting`,
805
+ `delivery` -> `projects`. Older feature ID constants may still appear in UI package code and
806
+ scaffold recipes; treat them as implementation constants, not live Organization OS primitives.
807
+
808
+ **Verification:** The user can explain when to use Pattern 1 vs Pattern 2 and name two base
809
+ entity types they could extend.
810
+
811
+ **Completion signal:** Mark `[ ] 11 Entity extensions` as `[x] YYYY-MM-DD` in
812
+ `.claude/memory/tutorial-progress.md`.
813
+
814
+ ---
815
+
816
+ ## SECTION D -- Modules (load on demand)
817
+
818
+ Modules in Section D are available any time. No Section B or C prerequisites are enforced. After
819
+ completing a module, redisplay the full menu with updated progress markers.
820
+
821
+ ---
822
+
823
+ ### Item 12: HITL
824
+
825
+ **Goal:** The user implements an approval gate using `approval.create()` and understands the
826
+ full lifecycle through Command Queue.
827
+
828
+ **Estimated time:** 25 min
829
+
830
+ **Files referenced:** `.claude/rules/error-handling.md`,
831
+ `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
832
+
833
+ **Flow:**
834
+
835
+ **What HITL is.** Human-in-the-Loop (HITL) pauses a workflow execution and waits for a human
836
+ decision before continuing. The execution is suspended at the approval gate; the platform stores
837
+ the pending state. When a user approves or rejects in Command Center, the execution resumes.
838
+
839
+ **Implementation.** Import `approval` from `@elevasis/sdk/worker` and call it inside a step
840
+ handler:
841
+
842
+ ```typescript
843
+ import { approval } from '@elevasis/sdk/worker'
844
+
845
+ const decision = await approval.create({
846
+ title: 'Approve Invoice',
847
+ description: `Invoice #${input.invoiceId} for $${input.amount} ready for approval.`,
848
+ context: { invoiceId: input.invoiceId, amount: input.amount }
849
+ })
850
+
851
+ if (decision.approved) {
852
+ // continue the workflow
853
+ } else {
854
+ // handle rejection
855
+ }
856
+ ```
857
+
858
+ **Lifecycle.** The step calls `approval.create()` -> platform suspends the execution -> a
859
+ pending item appears in the Command Queue in Command Center -> user reviews and approves or
860
+ rejects -> execution resumes from the same step with `decision.approved` set.
861
+
862
+ **Variant rule.** Always use `variant: 'light'` (hardcoded by the platform; never pass `variant`
863
+ in the `approval.create()` call -- the field does not exist on the call signature and will cause
864
+ a TypeScript error).
865
+
866
+ **Verify.** Deploy the workflow, execute it, confirm that it appears as pending in Command Center
867
+ Command Queue, approve it, and confirm the execution completes.
868
+
869
+ **Completion signal:** Mark `[ ] 12 HITL` as `[x] YYYY-MM-DD` in
870
+ `.claude/memory/tutorial-progress.md`.
871
+
872
+ ---
873
+
874
+ ### Item 13: Schedules
875
+
876
+ **Goal:** The user understands the three Task Scheduler types (Recurring, Relative, Absolute),
877
+ uses the `scheduler` singleton inside a workflow, and knows the cron syntax the platform accepts.
878
+
879
+ **Estimated time:** 20 min
880
+
881
+ **Files referenced:** `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
882
+
883
+ **Flow:**
884
+
885
+ **The `scheduler` singleton.** Import from `@elevasis/sdk/worker` to trigger workflow actions
886
+ from within a running step:
887
+
888
+ ```typescript
889
+ import { scheduler } from '@elevasis/sdk/worker'
890
+
891
+ await scheduler.schedule({
892
+ resourceId: 'my-workflow',
893
+ triggerAt: new Date(Date.now() + 60 * 60 * 1000), // 1 hour from now
894
+ input: { ... }
895
+ })
896
+ ```
897
+
898
+ **Task Scheduler UI -- three types.** Walk the user through Command Center -> Task Scheduler:
899
+
900
+ - **Recurring** -- cron-based, runs on a schedule. Standard cron syntax: `0 9 * * 1-5` (9am
901
+ weekdays). The platform interprets cron in UTC.
902
+ - **Relative** -- fires N minutes/hours/days after a trigger event (e.g., "24 hours after a
903
+ deal enters a stage").
904
+ - **Absolute** -- fires at a specific UTC datetime (one-shot, not recurring).
905
+
906
+ **Creating a schedule.** Show the Task Scheduler create flow: select resource, choose type,
907
+ configure the trigger, set input. Schedules appear as `workflow_schedules` rows in the DB -- the
908
+ `elevasis-sdk executions` command shows executions triggered by schedules alongside manual ones.
909
+
910
+ **Verification:** Ask: "What time zone does the platform use for cron expressions?" (UTC.)
911
+
912
+ **Completion signal:** Mark `[ ] 13 Schedules` as `[x] YYYY-MM-DD` in
913
+ `.claude/memory/tutorial-progress.md`.
914
+
915
+ ---
916
+
917
+ ### Item 14: Notifications + integrations
918
+
919
+ **Goal:** The user uses the `notifications` and `email` singletons and wires a real integration
920
+ adapter using a credential from the project's identity.
921
+
922
+ **Estimated time:** 25 min
923
+
924
+ **Files referenced:** `.claude/skills/elevasis/SKILL.md` (credentials section),
925
+ `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
926
+
927
+ **Flow:**
928
+
929
+ **`notifications` singleton.** Sends in-app notifications visible in Command Center:
930
+
931
+ ```typescript
932
+ import { notifications } from '@elevasis/sdk/worker'
933
+
934
+ await notifications.send({
935
+ title: 'Campaign complete',
936
+ message: `Processed ${count} leads.`,
937
+ level: 'info' // 'info' | 'warning' | 'error'
938
+ })
939
+ ```
940
+
941
+ **`email` singleton.** Sends transactional email through the platform's configured mail provider:
942
+
943
+ ```typescript
944
+ import { email } from '@elevasis/sdk/worker'
945
+
946
+ await email.send({
947
+ to: 'user@example.com',
948
+ subject: 'Your report is ready',
949
+ body: 'Here is a summary...'
950
+ })
951
+ ```
952
+
953
+ **Real adapter integration.** Read `core/config/organization-model.ts` and find the relevant
954
+ OM Resources descriptor or project knowledge node for the integration. Use the documented
955
+ credential name as the constructor argument:
956
+
957
+ ```typescript
958
+ import { createAttioAdapter } from '@elevasis/sdk/worker'
959
+ const attio = createAttioAdapter('acme-attio')
960
+ ```
961
+
962
+ Walk the user through the end-to-end: create the credential in Command Center, reference it in
963
+ the adapter constructor, deploy, execute a test run, check that the integration call succeeds.
964
+
965
+ **Common error.** If the credential is missing or misspelled, the adapter throws
966
+ `PlatformToolError: credential not found`. Check the exact name in Command Center.
967
+
968
+ **Verification:** A test execution that calls the integration adapter completes without a
969
+ `PlatformToolError`.
970
+
971
+ **Completion signal:** Mark `[ ] 14 Notifications + integrations` as `[x] YYYY-MM-DD` in
972
+ `.claude/memory/tutorial-progress.md`.
973
+
974
+ ---
975
+
976
+ ### Item 15: Error handling
977
+
978
+ **Goal:** The user knows the three error types, uses `context.logger`, and implements a
979
+ try/catch with retryable vs permanent error distinction.
980
+
981
+ **Estimated time:** 20 min
982
+
983
+ **Files referenced:** `.claude/rules/error-handling.md`,
984
+ `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
985
+
986
+ **Flow:**
987
+
988
+ Read `.claude/rules/error-handling.md` before starting. Then walk through each error type:
989
+
990
+ **`ExecutionError`.** Base class for workflow/step failures. Throw to halt an execution with a
991
+ user-readable message:
992
+
993
+ ```typescript
994
+ import { ExecutionError } from '@elevasis/sdk'
995
+
996
+ throw new ExecutionError('Payment processing failed', {
997
+ context: { invoiceId: input.invoiceId }
998
+ })
999
+ ```
1000
+
1001
+ **`PlatformToolError`.** Thrown by `platform.call()` and typed adapters when an integration
1002
+ call fails. Always check `err.retryable`:
1003
+
1004
+ ```typescript
1005
+ import { PlatformToolError } from '@elevasis/sdk'
1006
+
1007
+ try {
1008
+ await attio.createRecord({ ... })
1009
+ } catch (err) {
1010
+ if (err instanceof PlatformToolError) {
1011
+ if (err.retryable) {
1012
+ context.logger.warn(`Transient error (rate limit or timeout): ${err.message}`)
1013
+ // safe to retry or re-throw for the caller to handle
1014
+ } else {
1015
+ throw new ExecutionError(`Permanent integration error: ${err.message}`)
1016
+ }
1017
+ }
1018
+ throw err
1019
+ }
1020
+ ```
1021
+
1022
+ **`ToolingError`.** Internal SDK infrastructure error. Treat as non-retryable.
1023
+
1024
+ **`context.logger`.** Use it for all logging inside handlers. `console.log` is not captured by
1025
+ the platform worker runtime. Log levels: `debug`, `info`, `warn`, `error`. The error message in
1026
+ an unhandled throw surfaces directly to CLI output and Command Center -- write it for humans.
1027
+
1028
+ **Common retryable codes.** `rate_limit_exceeded` and `timeout_error` are retryable.
1029
+ `credentials_invalid` and `validation_error` are not.
1030
+
1031
+ **Verification:** Demonstrate a handler that catches a `PlatformToolError`, checks `retryable`,
1032
+ logs appropriately, and re-throws as an `ExecutionError` with a clear message.
1033
+
1034
+ **Completion signal:** Mark `[ ] 15 Error handling` as `[x] YYYY-MM-DD` in
1035
+ `.claude/memory/tutorial-progress.md`.
1036
+
1037
+ ---
1038
+
1039
+ ### Item 16: LLM and agents
1040
+
1041
+ **Goal:** The user calls `llm.generate()` with structured output (Zod -> JSON Schema -> typed
1042
+ result) and understands when to use an agent definition vs a workflow definition.
1043
+
1044
+ **Estimated time:** 25 min
1045
+
1046
+ **Files referenced:** `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`,
1047
+ `apps/docs/content/docs/sdk/concepts.mdx` (workflow vs agent section)
1048
+
1049
+ **Flow:**
1050
+
1051
+ **`llm.generate()` with structured output.** The `llm` singleton from `@elevasis/sdk/worker`
1052
+ accepts a Zod output schema and returns a typed result:
1053
+
1054
+ ```typescript
1055
+ import { llm } from '@elevasis/sdk/worker'
1056
+ import { z } from 'zod'
1057
+
1058
+ const classificationSchema = z.object({
1059
+ category: z.enum(['support', 'billing', 'feature-request', 'other']),
1060
+ confidence: z.number().min(0).max(1),
1061
+ summary: z.string()
1062
+ })
1063
+
1064
+ const result = await llm.generate({
1065
+ prompt: `Classify this ticket: ${input.ticketBody}`,
1066
+ outputSchema: classificationSchema,
1067
+ model: 'gpt-4o',
1068
+ temperature: 0.2
1069
+ })
1070
+
1071
+ // result is typed as z.infer<typeof classificationSchema>
1072
+ context.logger.info(`Classified as: ${result.category} (${result.confidence})`)
1073
+ ```
1074
+
1075
+ The SDK converts the Zod schema to JSON Schema internally. The LLM is instructed to return JSON
1076
+ matching that shape. The result is validated and returned as the inferred TypeScript type.
1077
+
1078
+ **Agent definition vs workflow definition.** Read the glossary entries from
1079
+ `apps/docs/content/docs/sdk/concepts.mdx`:
1080
+
1081
+ - **Workflow** -- deterministic, step-by-step, 300s timeout. Use when inputs and outputs are
1082
+ known and the process is predefined.
1083
+ - **Agent** -- autonomous, tool-calling, 600s timeout (configurable). Use when the agent needs
1084
+ to make decisions, call tools iteratively, or navigate ambiguous inputs.
1085
+
1086
+ When to use an agent: the task requires the LLM to decide WHICH tools to call and in WHAT order
1087
+ based on what it finds (not predetermined routing). When to use a workflow: the sequence of steps
1088
+ is predetermined, even if LLM judgment is involved inside individual steps.
1089
+
1090
+ **Model selection.** `gpt-4o` for complex reasoning, `gpt-4o-mini` for speed-sensitive tasks,
1091
+ `o3-mini` for multi-step reasoning chains. Temperature: `0.0` for deterministic classification,
1092
+ `0.2-0.4` for structured extraction, `0.7+` for creative generation.
1093
+
1094
+ **Verification:** A workflow step calls `llm.generate()` with a Zod schema and returns a typed
1095
+ value. The type system confirms the result matches the schema without a cast.
1096
+
1097
+ **Completion signal:** Mark `[ ] 16 LLM and agents` as `[x] YYYY-MM-DD` in
1098
+ `.claude/memory/tutorial-progress.md`.
1099
+
1100
+ ---
1101
+
1102
+ ### Item 17: Composition (execution.trigger)
1103
+
1104
+ **Goal:** The user chains two workflows using `execution.trigger()`, declares the relationship in
1105
+ `DeploymentSpec`, and can find the edge in Command View.
1106
+
1107
+ **Estimated time:** 20 min
1108
+
1109
+ **Files referenced:** `operations/src/index.ts`,
1110
+ `node_modules/@elevasis/sdk/reference/scaffold/operations/workflow-recipes.md`
1111
+
1112
+ **Flow:**
1113
+
1114
+ **`execution.trigger()`.** Call from inside a step handler to launch another workflow
1115
+ asynchronously:
1116
+
1117
+ ```typescript
1118
+ import { execution } from '@elevasis/sdk/worker'
1119
+
1120
+ const { executionId } = await execution.trigger({
1121
+ resourceId: 'downstream-workflow',
1122
+ input: { ...outputFromCurrentStep }
1123
+ })
1124
+
1125
+ context.logger.info(`Triggered downstream-workflow: ${executionId}`)
1126
+ ```
1127
+
1128
+ The calling step does not wait for the downstream workflow to complete. If you need the result,
1129
+ use async polling or chain via HITL.
1130
+
1131
+ **Declare the relationship in `DeploymentSpec`.** In `operations/src/index.ts`, add a
1132
+ `relationships` entry so the platform knows this workflow triggers another:
1133
+
1134
+ ```typescript
1135
+ const org: DeploymentSpec = {
1136
+ version: '0.1.0',
1137
+ workflows: [...],
1138
+ agents: [...],
1139
+ relationships: [
1140
+ {
1141
+ source: 'upstream-workflow',
1142
+ target: 'downstream-workflow',
1143
+ type: 'triggers'
1144
+ }
1145
+ ]
1146
+ }
1147
+ ```
1148
+
1149
+ This metadata populates the Command View graph. Without it, the edge is not visible in the UI
1150
+ even if the trigger call works.
1151
+
1152
+ **Command View.** Show the user how to find Command View in Command Center -> Operations.
1153
+ Deployed relationships appear as directed edges between resource nodes. This is the primary
1154
+ debugging surface for understanding how automations are connected.
1155
+
1156
+ **Verification:** Deploy both workflows with the relationship declared, then view the edge in
1157
+ Command View.
1158
+
1159
+ **Completion signal:** Mark `[ ] 17 Composition` as `[x] YYYY-MM-DD` in
1160
+ `.claude/memory/tutorial-progress.md`.
1161
+
1162
+ ---
1163
+
1164
+ ## SECTION E -- Power User
1165
+
1166
+ ### Item 18: Rules, memory, scaffold registry
1167
+
1168
+ **Goal:** The user can navigate the `.claude/rules/` and `.claude/memory/` directories and
1169
+ understands the scaffold registry's purpose.
1170
+
1171
+ **Estimated time:** 20 min
1172
+
1173
+ **Files referenced:** `.claude/rules/` (all files), `.claude/memory/` (layout),
1174
+ `.claude/scaffold-registry.yml` (reference, monorepo-side concept)
1175
+
1176
+ **Flow:**
1177
+
1178
+ **Rules directory.** List the current rule files in `.claude/rules/`. Each rule is automatically
1179
+ loaded by the agent on every session based on its `paths:` frontmatter (path globs that trigger
1180
+ auto-load). Key files:
1181
+
1182
+ - `agent-start-here.md` -- always-loaded canonical first-read; task-class routing and boundary
1183
+ resolution
1184
+ - `vibe.md` -- always-loaded ambient intent classifier
1185
+ - `organization-os.md` -- loaded when touching org model, System access, Action routing, or entity work
1186
+ - `deployment.md` -- loaded when deploying resources
1187
+ - `error-handling.md` -- loaded when authoring handlers with error concerns
1188
+ - `execution.md` -- loaded when reasoning about the runtime model
1189
+ - `observability.md` -- loaded when using `context.logger` or inspecting executions
1190
+ - `operations.md` -- loaded when touching `operations/src/`
1191
+ - `platform.md` -- loaded when importing from `@elevasis/sdk`
1192
+ - `shared-types.md` -- loaded when touching `core/types/`
1193
+ - `task-tracking.md` -- loaded when managing project tasks
1194
+ - `active-change-index.md` -- flags areas under active architecture change; trust this over
1195
+ stable scaffold docs for those areas
1196
+
1197
+ To add a new rule: create `.claude/rules/<domain>.md` with `paths:` frontmatter matching the
1198
+ glob of files it applies to. The rules system discovers it automatically -- no registration step.
1199
+
1200
+ **Memory directory.** List `.claude/memory/`. Common files:
1201
+
1202
+ - `profile.md` -- track choice and tone implications (written by this tutorial)
1203
+ - `tutorial-progress.md` -- per-item progress markers for both tracks
1204
+
1205
+ Memory files are readable by the agent at session start. The `profile.md` file is particularly
1206
+ important: it sets the project-wide tone for all sessions after the tutorial track is selected.
1207
+
1208
+ **Scaffold registry (monorepo-side concept).** `.claude/scaffold-registry.yml` is the
1209
+ monorepo's source-of-truth for scaffold dependencies -- it maps source paths to generated or
1210
+ manual scaffolds that depend on them. It drives the PostToolUse reminder hook and `/work handoff`
1211
+ preflight in the monorepo. In an external project you are a consumer, not a contributor, of that
1212
+ registry. The relevant thing to know: when the SDK ships a template update, the registry controls
1213
+ which files are Tier 1 (always replaced on sync), Tier 2 (merge-aware), and Tier 3 (never
1214
+ touched). Item 19 covers this in detail.
1215
+
1216
+ **Verification:** Ask: "How does the agent know to load `deployment.md` when you run a deploy?"
1217
+ (Answer: the `paths:` frontmatter in the rule file matches `operations/` file globs and deploy
1218
+ command patterns.)
1219
+
1220
+ **Completion signal:** Mark `[ ] 18 Rules, memory, scaffold registry` as `[x] YYYY-MM-DD` in
1221
+ `.claude/memory/tutorial-progress.md`.
1222
+
1223
+ ---
1224
+
1225
+ ### Item 19: Template lifecycle and /git-sync
1226
+
1227
+ **Goal:** The user understands the three-tier file classification, runs `/git-sync`, and knows
1228
+ what manual reconciliation is required after a template update.
1229
+
1230
+ **Estimated time:** 20 min
1231
+
1232
+ **Files referenced:** `.claude/skills/git-sync/SKILL.md`, `.claude/sync-notes/` (directory)
1233
+
1234
+ **Flow:**
1235
+
1236
+ Tell the user:
1237
+
1238
+ > "The template you scaffolded from is versioned. When a new SDK version ships, the template
1239
+ > updates. `/git-sync` pulls those changes and tells you what changed. You decide what to do
1240
+ > with them."
1241
+
1242
+ **Three-tier file classification.** Walk through the tiers:
1243
+
1244
+ - **Tier 1 (always replaced)** -- SDK-owned files that ship in a known correct state:
1245
+ `.claude/skills/*/SKILL.md` (except project-authored skills), `.claude/hooks/`, `CLAUDE.md`
1246
+ sections that are platform-managed. These are overwritten on every template sync. Do not put
1247
+ custom logic in them; instead use Tier 3 files for project-specific config.
1248
+ - **Tier 2 (merge-aware)** -- Files where the template ships defaults but the project may have
1249
+ customized: `core/config/organization-model.ts`, `.claude/rules/active-change-index.md`,
1250
+ vibe classifier threshold. The sync does not blindly overwrite -- the agent surfaces the diff
1251
+ and the user decides what to keep.
1252
+ - **Tier 3 (never touched)** -- Project-owned files the template never overwrites: project
1253
+ source code in `operations/src/`, `ui/src/`, all `core/types/` files, `core/config/extensions/`,
1254
+ custom rules added to `.claude/rules/`, everything in `.claude/memory/`.
1255
+
1256
+ **Running `/git-sync`.** Read `.claude/skills/git-sync/SKILL.md` and walk the user through each
1257
+ step:
1258
+
1259
+ 1. Check for uncommitted changes (`git status --short`). Stop if dirty.
1260
+ 2. Snapshot current sync-note filenames before pulling.
1261
+ 3. `git pull --rebase` -- stop and report conflicts; do not auto-resolve.
1262
+ 4. Detect dependency baseline changes; run `pnpm install` if `package.json` or
1263
+ `pnpm-lock.yaml` changed.
1264
+ 5. Run baseline verification: `pnpm -C ui check-types`, `pnpm -C ui build`,
1265
+ `pnpm -C operations check`, `pnpm -C operations check-types`.
1266
+ 6. Surface newly introduced sync notes from `.claude/sync-notes/`. Each note has required
1267
+ actions and a verification section.
1268
+ 7. Stop. `/git-sync` does not auto-reconcile. Manual follow-up is explicit.
1269
+
1270
+ **Sync notes contract.** Files in `.claude/sync-notes/` named `YYYY-MM-DD-<slug>.md` are
1271
+ operative release guidance. They use fixed headings: `## Why this note exists`,
1272
+ `## Applies to`, `## Required actions`, `## Verification`, `## Not handled by /git-sync`.
1273
+ Never edit operative note filenames after they ship -- they are append-only.
1274
+
1275
+ **Verification:** The user knows which of their own files are Tier 3 (never touched) and can
1276
+ explain why `/git-sync` stops before reconciliation rather than auto-applying diffs.
1277
+
1278
+ **Completion signal:** Mark `[ ] 19 Template lifecycle and /git-sync` as `[x] YYYY-MM-DD` in
1279
+ `.claude/memory/tutorial-progress.md`.
1280
+
1281
+ ---
1282
+
1283
+ ## After All 19 Items Complete
1284
+
1285
+ When all 19 items are marked `[x]` in `.claude/memory/tutorial-progress.md`, deliver the
1286
+ following closing script:
1287
+
1288
+ > "You've completed the technical track. Here's where to go from here:
1289
+ >
1290
+ > - **Build real automations.** You now have the full surface: workflows, schemas, HITL, schedules,
1291
+ > LLM integration, error handling, and composition. Start with the domain most relevant to your
1292
+ > project and use `/project create` to track the work.
1293
+ > - **SDK reference scaffold.** `node_modules/@elevasis/sdk/reference/scaffold/index.mdx` is the
1294
+ > canonical recipe index for anything you want to build: adding a System or UI feature, extending lead-gen,
1295
+ > customizing CRM actions, authoring agents. Read it whenever you are starting something new.
1296
+ > - **Explore the codebase.** `/explore` is your tool for open-ended questions about how things
1297
+ > are wired. Use it before making changes in unfamiliar parts of the project.
1298
+ > - **Keep the org model current.** Run `/knowledge` any time your business reality changes --
1299
+ > new offerings, new customer segments, new goals. The model is the agent's vocabulary for
1300
+ > your project; an accurate model means better agent output.
1301
+ > - **Stay current with template updates.** When a new SDK version ships, run `/git-sync` to pull
1302
+ > it and read the sync notes. They tell you exactly what changed and what manual follow-up is
1303
+ > needed."