@elevasis/sdk 1.5.3 → 1.5.5

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 (58) hide show
  1. package/dist/cli.cjs +967 -57
  2. package/dist/index.d.ts +94 -110
  3. package/package.json +2 -2
  4. package/reference/_navigation.md +11 -1
  5. package/reference/_reference-manifest.json +70 -0
  6. package/reference/claude-config/commands/submit-issue.md +11 -0
  7. package/reference/claude-config/hooks/post-edit-validate.mjs +109 -0
  8. package/reference/claude-config/hooks/tool-failure-recovery.mjs +73 -0
  9. package/reference/claude-config/rules/deployment.md +57 -0
  10. package/reference/claude-config/rules/docs.md +26 -0
  11. package/reference/claude-config/rules/error-handling.md +56 -0
  12. package/reference/claude-config/rules/execution.md +40 -0
  13. package/reference/claude-config/rules/frontend.md +43 -0
  14. package/reference/claude-config/rules/observability.md +31 -0
  15. package/reference/claude-config/rules/organization-os.md +62 -0
  16. package/reference/claude-config/rules/platform.md +41 -0
  17. package/reference/claude-config/rules/shared-types.md +46 -0
  18. package/reference/claude-config/rules/task-tracking.md +47 -0
  19. package/reference/claude-config/scripts/statusline-command.js +18 -0
  20. package/reference/claude-config/settings.json +30 -0
  21. package/reference/claude-config/skills/deploy/SKILL.md +166 -0
  22. package/reference/claude-config/skills/dsp/SKILL.md +66 -0
  23. package/reference/claude-config/skills/elevasis/SKILL.md +239 -0
  24. package/reference/claude-config/skills/explore/SKILL.md +78 -0
  25. package/reference/claude-config/skills/project/SKILL.md +918 -0
  26. package/reference/claude-config/skills/save/SKILL.md +197 -0
  27. package/reference/claude-config/skills/setup/SKILL.md +210 -0
  28. package/reference/claude-config/skills/status/SKILL.md +60 -0
  29. package/reference/claude-config/skills/submit-issue/SKILL.md +165 -0
  30. package/reference/claude-config/skills/sync/SKILL.md +81 -0
  31. package/reference/cli.mdx +19 -4
  32. package/reference/deployment/provided-features.mdx +24 -2
  33. package/reference/framework/agent.mdx +12 -4
  34. package/reference/framework/project-structure.mdx +9 -3
  35. package/reference/packages/core/src/README.md +1 -1
  36. package/reference/packages/core/src/business/README.md +52 -0
  37. package/reference/packages/core/src/organization-model/README.md +25 -26
  38. package/reference/packages/ui/src/app/README.md +24 -0
  39. package/reference/platform-tools/type-safety.mdx +0 -10
  40. package/reference/scaffold/core/organization-graph.mdx +37 -28
  41. package/reference/scaffold/core/organization-model.mdx +34 -36
  42. package/reference/scaffold/index.mdx +1 -0
  43. package/reference/scaffold/operations/propagation-pipeline.md +7 -3
  44. package/reference/scaffold/operations/scaffold-maintenance.md +2 -2
  45. package/reference/scaffold/operations/workflow-recipes.md +18 -1
  46. package/reference/scaffold/recipes/add-a-feature.md +37 -21
  47. package/reference/scaffold/recipes/add-a-resource.md +4 -2
  48. package/reference/scaffold/recipes/customize-organization-model.md +400 -0
  49. package/reference/scaffold/recipes/extend-a-base-entity.md +140 -0
  50. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +18 -12
  51. package/reference/scaffold/recipes/index.md +3 -3
  52. package/reference/scaffold/reference/contracts.md +11 -32
  53. package/reference/scaffold/reference/feature-registry.md +10 -9
  54. package/reference/scaffold/reference/glossary.md +14 -18
  55. package/reference/scaffold/ui/customization.md +2 -2
  56. package/reference/scaffold/ui/feature-flags-and-gating.md +40 -54
  57. package/reference/scaffold/ui/feature-shell.mdx +22 -23
  58. package/reference/scaffold/ui/recipes.md +118 -3
@@ -21,7 +21,7 @@ The model does **not** replace the shared feature-provider system. It enriches a
21
21
  - `packages/core/src/organization-model/types.ts` -- exported TypeScript types
22
22
  - `packages/core/src/organization-model/defaults.ts` -- `DEFAULT_ORGANIZATION_MODEL`
23
23
  - `packages/core/src/organization-model/resolve.ts` -- `defineOrganizationModel`, `resolveOrganizationModel`
24
- - `packages/core/src/organization-model/domains/*.ts` -- feature keys, navigation surfaces, CRM/lead-gen/delivery semantics
24
+ - `packages/core/src/organization-model/domains/*.ts` -- feature schema, navigation surfaces, CRM/lead-gen/delivery semantics
25
25
  - `packages/core/src/published.ts` -- curated root barrel for the published package
26
26
  - `packages/core/src/organization-model/published.ts` -- curated organization-model barrel
27
27
  - `packages/core/src/__tests__/template-foundations-compatibility.test.ts` -- adapter-baseline guard
@@ -31,9 +31,8 @@ The model does **not** replace the shared feature-provider system. It enriches a
31
31
  Top-level fields on `OrganizationModel`:
32
32
 
33
33
  - `version`
34
- - `domains` -- semantic domains (`crm`, `lead-gen`, `delivery`, `operations`)
34
+ - `features` -- unified feature array (`OrganizationModelFeature[]`); each entry combines access gating, semantic grouping, and display metadata
35
35
  - `branding`
36
- - `features` -- `enabled` map and `labels` overrides
37
36
  - `navigation` -- surfaces, groups, `defaultSurfaceId`
38
37
  - `crm` -- pipeline stages and stage semantics
39
38
  - `leadGen` -- company/contact lifecycle stages
@@ -61,24 +60,21 @@ All `id` fields, `parentId`, `defaultSurfaceId`, and reference ID arrays use `Mo
61
60
 
62
61
  This applies to domain IDs, surface IDs, navigation group IDs, and resource mapping IDs.
63
62
 
64
- ### Default Feature Keys
63
+ ### Default Features
65
64
 
66
- ```ts
67
- type OrganizationModelFeatureKey =
68
- | 'acquisition'
69
- | 'delivery'
70
- | 'operations'
71
- | 'monitoring'
72
- | 'settings'
73
- | 'seo'
74
- | 'calibration'
75
- ```
65
+ Seven features ship by default in `DEFAULT_ORGANIZATION_MODEL.features`:
76
66
 
77
- These are the **grouped** published access/visibility keys. They differ from shell feature-module keys (`crm`, `lead-gen`, `delivery`). See [Feature Shell](../ui/feature-shell.mdx) for how the provider bridges the two.
67
+ - `crm` -- enabled; CRM pipeline and deal management
68
+ - `lead-gen` -- enabled; prospecting, qualification, and outreach
69
+ - `projects` -- enabled; projects, milestones, and client work execution (formerly `delivery`)
70
+ - `operations` -- enabled; organizational topology and orchestration visibility
71
+ - `monitoring` -- enabled; execution monitoring
72
+ - `settings` -- enabled; organization settings
73
+ - `seo` -- disabled by default; SEO surface
78
74
 
79
- ### Default Semantic Domains
75
+ Each feature entry (`OrganizationModelFeature`) combines what were previously three separate concepts: an access/gating key (the former `OrganizationModelFeatureKey`), a semantic domain (the former `SemanticDomainSchema` entry), and display metadata. The `features` field is now `z.array(FeatureSchema)` -- there is no separate `domains` array and no separate `enabled`/`labels` map.
80
76
 
81
- Four domains ship by default -- `crm`, `lead-gen`, `delivery`, `operations`. Each binds together entity IDs, surface IDs, resource IDs, and capability IDs. Domains are semantic, not purely navigational -- they describe what area of the business or resource model a thing belongs to, not which access key gates it.
77
+ `FeatureModule.featureId` on the UI side maps directly to one of these IDs. No alias layer is needed. See [Feature Shell](../ui/feature-shell.mdx) for how the provider resolves feature access from this array.
82
78
 
83
79
  ### ResourceMapping Shape
84
80
 
@@ -88,7 +84,7 @@ Four domains ship by default -- `crm`, `lead-gen`, `delivery`, `operations`. Eac
88
84
  - `resourceId` -- the actual resource identifier (string, max 255 chars)
89
85
  - `resourceType` -- one of `'workflow' | 'agent' | 'trigger' | 'integration' | 'external' | 'human_checkpoint'`
90
86
  - `label`, `description`, `color`, `icon` -- display metadata (from `DisplayMetadataSchema`)
91
- - `domainIds` -- domains this resource belongs to
87
+ - `featureIds` -- features this resource belongs to (replaces the former `domainIds`)
92
88
  - `entityIds` -- entities this resource operates on
93
89
  - `surfaceIds` -- surfaces this resource is exposed in
94
90
  - `capabilityIds` -- capabilities this resource fulfills
@@ -109,9 +105,9 @@ Surfaces such as `crm.pipeline`, `lead-gen.lists`, `projects.index`, `operations
109
105
  - `surfaceType` -- `'page' | 'dashboard' | 'graph' | 'detail' | 'list' | 'settings'`
110
106
  - `description` -- optional
111
107
  - `icon` -- optional icon name token (max 80 chars)
112
- - `featureKey` -- optional `OrganizationModelFeatureKey` that gates this surface
108
+ - `featureId` -- optional feature ID that gates this surface (replaces the former `featureKey` field); must match a feature `id` in the features array
113
109
  - `parentId` -- optional ModelId referencing a parent surface; validated to exist
114
- - `domainIds` -- domains this surface belongs to (bidirectionally validated)
110
+ - `featureIds` -- features this surface belongs to (bidirectionally validated; replaces the former `domainIds`)
115
111
  - `entityIds` -- entity IDs relevant to this surface
116
112
  - `resourceIds` -- resources exposed on this surface (bidirectionally validated against resource mappings)
117
113
  - `capabilityIds` -- capabilities this surface fulfills
@@ -126,11 +122,13 @@ Surfaces such as `crm.pipeline`, `lead-gen.lists`, `projects.index`, `operations
126
122
 
127
123
  The default groups (`primary-workspace`, `primary-operations`) both use `placement: 'primary'`.
128
124
 
129
- ### Domain-Specific Semantics
125
+ ### Feature-Specific Semantics
130
126
 
131
- - **CRM** -- pipeline stages and stage semantics
132
- - **Lead-gen** -- company and contact lifecycle stages
133
- - **Delivery** -- project, milestone, and task statuses
127
+ The top-level `crm`, `leadGen`, and `delivery` fields on `OrganizationModel` remain as named fields (not moved into per-feature config) and carry domain-specific semantic shapes:
128
+
129
+ - `crm` -- pipeline stages and stage semantics
130
+ - `leadGen` -- company and contact lifecycle stages
131
+ - `delivery` -- project, milestone, and task statuses (used by the `projects` feature)
134
132
 
135
133
  This is why the organization model is semantic, not just nav config -- it owns product meaning for the business objects the shell surfaces expose.
136
134
 
@@ -152,7 +150,7 @@ Merge semantics:
152
150
 
153
151
  **Uniqueness checks** -- IDs must be unique within their respective collections:
154
152
 
155
- - `domains[].id`
153
+ - `features[].id`
156
154
  - `navigation.surfaces[].id`
157
155
  - `navigation.groups[].id`
158
156
  - `resourceMappings[].id`
@@ -162,20 +160,20 @@ Merge semantics:
162
160
 
163
161
  - `navigation.defaultSurfaceId` must point at a declared surface
164
162
  - every `surfaceId` in a navigation group must resolve to a declared surface
165
- - every `surfaceId` in a domain must resolve to a declared surface
166
- - every `resourceId` in a domain must resolve to a declared resource mapping (by `resourceId`)
163
+ - every `surfaceId` in a feature must resolve to a declared surface
164
+ - every `resourceId` in a feature must resolve to a declared resource mapping (by `resourceId`)
167
165
  - surface `parentId` must reference an existing surface
168
- - every `domainId` on a surface must resolve to a declared domain
166
+ - every `featureId` on a surface must resolve to a declared feature
169
167
  - every `resourceId` on a surface must resolve to a declared resource mapping
170
- - every `domainId` on a resource mapping must resolve to a declared domain
168
+ - every `featureId` on a resource mapping must resolve to a declared feature
171
169
  - every `surfaceId` on a resource mapping must resolve to a declared surface
172
170
 
173
171
  **Bidirectional reference enforcement** -- cross-references must be mutual, not one-sided:
174
172
 
175
- - a domain listing `surfaceId` S requires surface S to list that domain's ID in its `domainIds`
176
- - a surface listing `domainId` D requires domain D to list that surface's ID in its `surfaceIds`
177
- - a domain listing `resourceId` R requires resource mapping R to list that domain's ID in its `domainIds`
178
- - a resource mapping listing `domainId` D requires domain D to list that resource's `resourceId` in its `resourceIds`
173
+ - a feature listing `surfaceId` S requires surface S to list that feature's ID in its `featureIds`
174
+ - a surface listing `featureId` F requires feature F to list that surface's ID in its `surfaceIds`
175
+ - a feature listing `resourceId` R requires resource mapping R to list that feature's ID in its `featureIds`
176
+ - a resource mapping listing `featureId` F requires feature F to list that resource's `resourceId` in its `resourceIds`
179
177
  - a surface listing `resourceId` R requires resource mapping R to list that surface's ID in its `surfaceIds`
180
178
  - a resource mapping listing `surfaceId` S requires surface S to list that resource's `resourceId` in its `resourceIds`
181
179
 
@@ -185,8 +183,8 @@ This bidirectional enforcement is what keeps the organization model semantically
185
183
 
186
184
  `ElevasisFeaturesProvider` uses the organization model in three ways:
187
185
 
188
- 1. **Feature resolution** -- provider first checks `useFeatureAccess()`, then refines through organization-model feature state when the model knows the key.
189
- 2. **Nav label and path resolution** -- when `organizationModel` is present, feature labels resolve from `organizationModel.features.labels`, and surface labels and paths resolve from `organizationModel.navigation.surfaces`. Semantic customization without changing manifest code.
186
+ 1. **Feature resolution** -- the provider looks up each manifest's `featureId` in `organizationModel.features` to determine `access.enabled`. If no matching feature entry is found, `access.enabled` defaults to `false`.
187
+ 2. **Nav label and path resolution** -- when `organizationModel` is present, feature labels resolve from the matching feature entry's `label` field, and surface labels and paths resolve from `organizationModel.navigation.surfaces`. Semantic customization without changing manifest code.
190
188
  3. **Organization-graph bridge** -- the `operationsManifest` declares `organizationGraph.surfaceId = 'operations.organization-graph'`. The provider resolves that against organization-model surfaces and exposes the result as `organizationGraph` in context. See [Organization Graph](./organization-graph.mdx).
191
189
 
192
190
  ## Published Package: `@elevasis/core`
@@ -238,7 +236,7 @@ Exports the foundations module provides to consumers:
238
236
  - `FoundationFeatureKey`, `FoundationSurfaceIcon`, `FoundationNavigationSurface`, `FoundationOrganizationModel`
239
237
  - `homeLabel`, `quickAccessSurfaceIds`, `getOrganizationSurface(surfaceId)`
240
238
 
241
- Downstream template shells pass `canonicalOrganizationModel` into `ElevasisFeaturesProvider`, preserving host-local dashboard/nav customizations alongside the shared runtime. Grouped core features map onto template vocabulary -- `crm` and `lead-gen` project from `acquisition`, `projects` from `delivery`.
239
+ Downstream template shells pass `canonicalOrganizationModel` into `ElevasisFeaturesProvider`, preserving host-local dashboard/nav customizations alongside the shared runtime. Feature IDs are now direct matches -- `crm`, `lead-gen`, `projects` in the org model correspond directly to the same IDs on `FeatureModule.featureId`. No alias layer is needed.
242
240
 
243
241
  Derivative projects (`external/nirvana-marketing`, `external/ZentaraHQ`) follow the same adapter + provider-wiring baseline with their own project-local customizations.
244
242
 
@@ -19,6 +19,7 @@ This scaffold reference contains universal documentation that applies to all Ele
19
19
 
20
20
  - [Add a Feature](./recipes/add-a-feature.md) -- end-to-end from org model key through manifest, routes, gating
21
21
  - [Add a Resource](./recipes/add-a-resource.md) -- author and deploy a workflow or agent
22
+ - [Extend a Base Entity](./recipes/extend-a-base-entity.md) -- add project-specific metadata to canonical entity shapes via the TMeta slot
22
23
  - [Gate by Feature or Admin](./recipes/gate-by-feature-or-admin.md) -- decision table for access control patterns
23
24
 
24
25
  ### UI Patterns
@@ -57,7 +57,7 @@ Drift is healed at the moment it would otherwise leak downstream. This is cheape
57
57
 
58
58
  | Tier | Policy | Examples |
59
59
  | ------------------------------ | ----------------------------------------- | ------------------------------------------------------------------- |
60
- | **Tier 1 (Infrastructure)** | Always replaced from template | Configs, `shared/`, `lib/`, `test-utils/`, `.claude/`, entry points |
60
+ | **Tier 1 (Infrastructure)** | Always replaced from template | Configs, shared runtime surfaces, `lib/`, `test-utils/`, entry points |
61
61
  | **Tier 2 (Standard Features)** | Synced unless project has customized them | Standard UI features, common patterns |
62
62
  | **Tier 3 (Project-Specific)** | Never touched | `nav-items.ts`, `operations/src/`, `docs/`, `CLAUDE.md` |
63
63
 
@@ -78,8 +78,8 @@ The sync skill doc (`.claude/skills/external/SKILL.md`) defines the full tier mo
78
78
  | `org-os` | Organization model exists, exports canonical symbols, imports from `@elevasis/core/organization-model`, calls `defineOrganizationModel` + `resolveOrganizationModel`, app-config references org model, `__root.tsx` uses `ElevasisFeaturesProvider` + `canonicalOrganizationModel`, `main.tsx` uses `ElevasisUIProvider`, all 3 CSS subpath imports present |
79
79
  | `placeholders` | No unresolved `__PROJECT_SLUG__`, `__PROJECT_NAME__`, `__PROJECT_DESCRIPTION__` in key config files |
80
80
  | `scripts` | `ui` and `operations` `package.json` have required npm scripts |
81
- | `claude` | `.claude/skills/`, `hooks/`, `rules/` exist; `settings.json` is valid JSON |
82
- | `shared` | `ui/src/shared/`, `lib/`, `test-utils/` exist with minimum file counts |
81
+ | `generated-docs` | `docs/index.md` and `docs/resources.md` are current with `pnpm exec elevasis-sdk generate-docs` and `pnpm exec elevasis-sdk generate-resources`; `pnpm exec elevasis-sdk validate-docs` passes |
82
+ | `lib` | `ui/src/lib/`, `lib/`, `test-utils/` exist with minimum file counts |
83
83
  | `tier3` | `nav-items.ts` has project-specific customization (not overwritten by template) |
84
84
  | `conflicts` | No merge conflict markers in source files |
85
85
  | `git` | Working tree is clean |
@@ -116,6 +116,10 @@ Some failures are expected and intentional:
116
116
 
117
117
  These do not indicate sync failures.
118
118
 
119
+ ### Tier Ownership Note
120
+
121
+ Local `.claude/` guidance remains valuable inside the template, but it is project-owned documentation and agent configuration rather than a Tier 1 sync contract. Template propagation should treat the generated docs, published package surfaces, and runtime entrypoints as the authoritative shared scaffold surface.
122
+
119
123
  ---
120
124
 
121
125
  ## Remaining Gaps (Future Work)
@@ -35,7 +35,7 @@ Scaffold docs are co-located with their owning package and copied into the SDK r
35
35
  | Composition & Extensibility | `packages/ui/src/scaffold/composition-extensibility.mdx` | `scaffold/ui/composition-extensibility.mdx` |
36
36
  | Feature Registry (auto-gen) | `packages/ui/src/scaffold/_generated/feature-registry.md` | `scaffold/reference/feature-registry.md` |
37
37
  | Scaffold Index | `packages/sdk/docs/scaffold/index.mdx` | `scaffold/index.mdx` |
38
- | Pathway Recipes (3) | `packages/sdk/docs/scaffold/recipes/` | `scaffold/recipes/` |
38
+ | Pathway Recipes (4) | `packages/sdk/docs/scaffold/recipes/` | `scaffold/recipes/` |
39
39
  | Workflow Recipes | `packages/sdk/docs/scaffold/operations/workflow-recipes.md` | `scaffold/operations/workflow-recipes.md` |
40
40
  | Propagation Pipeline | `packages/sdk/docs/scaffold/operations/propagation-pipeline.md` | `scaffold/operations/propagation-pipeline.md` |
41
41
  | This doc | `packages/sdk/docs/scaffold/operations/scaffold-maintenance.md` | `scaffold/operations/scaffold-maintenance.md` |
@@ -120,6 +120,6 @@ The output lands in `packages/sdk/reference/` which is included in the npm packa
120
120
 
121
121
  ## Freshness Validation
122
122
 
123
- External projects have a local freshness validator: `scripts/validate-autogenerated-docs.mjs` (invoked via `pnpm check:autogenerated-docs`). This checks that generated docs in the project match what their generators would produce.
123
+ External projects validate generated docs with `pnpm check:autogenerated-docs`, which now calls `pnpm exec elevasis-sdk validate-docs`. The legacy `scripts/validate-autogenerated-docs.mjs` file may still exist as a temporary compatibility shim in the template, but the SDK CLI is the canonical path.
124
124
 
125
125
  At the monorepo level, `pnpm scaffold:sync` followed by `pnpm sync:verify` confirms that all artifacts are current and all downstream projects are consistent.
@@ -68,6 +68,23 @@ contract: {
68
68
  - Both runtimes (frontend and platform) import from `@foundation/types`, keeping validation consistent.
69
69
  - `@foundation/types` resolves to `foundations/types/index.ts` via the tsconfig path alias.
70
70
 
71
+ **Entity-backed workflows:** for workflows that operate on a domain entity, reference the entity contract rather than redeclaring it.
72
+
73
+ ```typescript
74
+ // foundations/types/index.ts
75
+ import { BaseDealSchema } from '@elevasis/core/entities'
76
+ import { DealSchema } from '@foundation/types/entities' // project-local extended version
77
+
78
+ export const closeDealInputSchema = z.object({
79
+ deal: DealSchema,
80
+ closedReason: z.string()
81
+ })
82
+
83
+ export type CloseDealInput = z.infer<typeof closeDealInputSchema>
84
+ ```
85
+
86
+ `DealSchema` is defined in `foundations/types/entities.ts` by extending `BaseDealSchema` with project-specific metadata. See [../recipes/extend-a-base-entity.md](../recipes/extend-a-base-entity.md) for the pattern.
87
+
71
88
  ### Steps
72
89
 
73
90
  Each step is a `WorkflowStep` with: `id`, `name`, `description`, `handler`, `inputSchema`, `outputSchema`, and `next`.
@@ -273,7 +290,7 @@ Use this pattern in React components and hooks. `apiRequest` automatically attac
273
290
  ```typescript
274
291
  // ui/src/features/notifications/hooks/useSendEmailNotification.ts
275
292
  import { useMutation } from '@tanstack/react-query'
276
- import { useApiClient } from '@/shared/api'
293
+ import { useApiClient } from '@/lib/hooks/useApiClient'
277
294
  import type { EmailNotificationInput, EmailNotificationOutput } from '@foundation/types'
278
295
 
279
296
  export function useSendEmailNotification() {
@@ -13,14 +13,14 @@ See [glossary.md](../reference/glossary.md) for term disambiguation throughout t
13
13
 
14
14
  ## 1. Decide the feature shape
15
15
 
16
- A shell feature requires an `OrganizationModelFeatureKey` to gate it. You have two options:
16
+ A shell feature requires a `feature.id` in the org model's `features[]` array to gate it. You have two options:
17
17
 
18
- - **Reuse an existing key** (e.g., `operations`, `monitoring`). The new feature shares an on/off toggle with other features using that key. Fine for sub-features within an existing domain.
19
- - **Add a new platform key** -- only possible if you are extending `OrganizationModelFeatureKey` itself, which requires a core package change. For template-local keys, use `FoundationLegacyFeatureKey` instead.
18
+ - **Reuse an existing feature** (e.g., `operations`, `monitoring`). The new shell module shares the on/off toggle with the existing feature entry. Fine for sub-modules within the same product area.
19
+ - **Add a new feature object** -- add an entry to the `features[]` array in `foundations/config/organization-model.ts`. This is always a template-local change; no core package change is required.
20
20
 
21
- For a genuinely new capability (e.g., `analytics`), you will extend `FoundationLegacyFeatureKey` in foundations so it becomes a valid `FoundationFeatureKey` and then declare it in the org model.
21
+ For a genuinely new capability (e.g., `analytics`), you add a feature object to the defaults array and author a matching manifest.
22
22
 
23
- See [glossary.md](../reference/glossary.md) under **Feature** (three contexts) and **OrganizationModelFeatureKey**.
23
+ See [glossary.md](../reference/glossary.md) under **Feature** (three contexts).
24
24
 
25
25
  ---
26
26
 
@@ -28,26 +28,42 @@ See [glossary.md](../reference/glossary.md) under **Feature** (three contexts) a
28
28
 
29
29
  File: `foundations/config/organization-model.ts`
30
30
 
31
- Add the key to `FoundationLegacyFeatureKey`, then declare it under `features.enabled`, `features.labels`, and the `featuresEnabled` resolver map.
31
+ Add a new feature object to the `features[]` array passed to `defineOrganizationModel`.
32
32
 
33
33
  ```ts
34
- // 1. Extend the local key union
35
- type FoundationLegacyFeatureKey = 'crm' | 'lead-gen' | 'projects' | 'analytics'
34
+ import { defineOrganizationModel } from '@elevasis/core/organization-model'
35
+ ```
36
36
 
37
- // 2. Enable in defineOrganizationModel call
38
- features: {
39
- enabled: { ..., analytics: false }, // start disabled
40
- labels: { ..., analytics: 'Analytics' }
41
- }
37
+ Use typed constants for the 7 platform features (`CRM_FEATURE_ID`, `LEAD_GEN_FEATURE_ID`, `PROJECTS_FEATURE_ID`, `OPERATIONS_FEATURE_ID`, `MONITORING_FEATURE_ID`, `SETTINGS_FEATURE_ID`, `SEO_FEATURE_ID`); use string literals for project-specific features you invent.
42
38
 
43
- // 3. Add to featuresEnabled resolver
44
- const featuresEnabled: Record<FoundationFeatureKey, boolean> = {
45
- ...
46
- analytics: resolvedOrganizationModel.features.enabled.analytics ?? false
47
- }
39
+ ```ts
40
+ const foundationOrganizationModelOverride = defineOrganizationModel({
41
+ features: [
42
+ // ... existing features
43
+ {
44
+ id: 'analytics',
45
+ label: 'Analytics',
46
+ enabled: false, // start disabled
47
+ entityIds: [],
48
+ surfaceIds: [],
49
+ resourceIds: [],
50
+ capabilityIds: []
51
+ }
52
+ ],
53
+ // ... rest of model
54
+ })
48
55
  ```
49
56
 
50
- Optionally, add a new domain entry and a navigation surface. See `OrganizationModelSemanticDomain` and `OrganizationModelSurface` shapes in [contracts.md](../reference/contracts.md).
57
+ Each field of the feature object:
58
+
59
+ - `id` -- unique stable identifier; this is the value `FeatureModule.featureId` must match
60
+ - `label` -- display name; used by nav label resolution when no manifest override is provided
61
+ - `enabled` -- org-wide default; `MembershipFeatureConfig.features` can override per member
62
+ - `entityIds`, `surfaceIds`, `resourceIds`, `capabilityIds` -- semantic references (leave empty to start)
63
+
64
+ No domain entry or separate key resolver is needed. The `features[]` array is the sole source of truth.
65
+
66
+ **Two-step pattern:** in a template-derived project, the `defineOrganizationModel` output is passed to `createFoundationOrganizationModel(override)` in `foundations/config/organization-model.ts`. The result exposes `.model`, `.canonical`, and `.homeLabel`. See `external/_template/foundations/config/organization-model.ts` for the canonical two-step example.
51
67
 
52
68
  ---
53
69
 
@@ -62,7 +78,7 @@ import { AnalyticsSidebar } from './sidebar'
62
78
 
63
79
  export const analyticsManifest: FeatureModule = {
64
80
  key: 'analytics',
65
- accessFeatureKey: 'analytics', // must match a FoundationFeatureKey
81
+ featureId: 'analytics', // must match a feature.id in the org model's features[] array
66
82
  navEntry: {
67
83
  label: 'Analytics',
68
84
  icon: IconChartBar,
@@ -75,7 +91,7 @@ export const analyticsManifest: FeatureModule = {
75
91
 
76
92
  Key fields:
77
93
 
78
- - `accessFeatureKey` -- the org-model key that gates the entire feature. The provider throws at startup if this key is not declared. See [glossary.md](../reference/glossary.md) under **accessFeatureKey**.
94
+ - `featureId` -- the org-model feature ID that gates the entire feature. The provider throws at startup if this ID is not found in the org model's `features[]` array. See [glossary.md](../reference/glossary.md) under **featureId**.
79
95
  - `sidebar` -- a component that renders the subshell sidebar. Compose from published primitives. See [customization.md](../ui/customization.md).
80
96
  - `subshellRoutes` -- every path that should activate this feature's sidebar.
81
97
 
@@ -52,6 +52,8 @@ export const myWorkflow: WorkflowDefinition = {
52
52
 
53
53
  Define input/output schemas in `foundations/types/index.ts`, not inline. Both runtimes import from `@foundation/types`. See [workflow-recipes.md](../operations/workflow-recipes.md) for Zod schema conventions and adapter usage (`llm`, `storage`, `scheduler`, `notifications` from `@elevasis/sdk/worker`).
54
54
 
55
+ **Entity-backed workflows:** if your workflow operates on a domain entity (Project, Deal, Company, etc.), define or reference the entity shape in `foundations/types/entities.ts` rather than declaring an ad-hoc shape here. The entity types extend base contracts from `@elevasis/core/entities` (`BaseProject`, `BaseDeal`, etc.) with project-specific metadata. See [./extend-a-base-entity.md](./extend-a-base-entity.md) for the pattern.
56
+
55
57
  ---
56
58
 
57
59
  ## 2. Register in the DeploymentSpec
@@ -134,7 +136,7 @@ See `OrganizationModelResourceMapping` in [contracts.md](../reference/contracts.
134
136
  ## 5. Regenerate the topology map
135
137
 
136
138
  ```bash
137
- pnpm generate-resources
139
+ pnpm exec elevasis-sdk generate-resources
138
140
  ```
139
141
 
140
142
  Open `docs/resources.md` and confirm:
@@ -162,4 +164,4 @@ pnpm exec elevasis describe Elevasis/my-workflow
162
164
  pnpm exec elevasis exec Elevasis/my-workflow --input '{"field": "value"}'
163
165
  ```
164
166
 
165
- Use `--async` for long-running resources. Use `pnpm exec elevasis --prod exec ...` (flag before `exec`) for production. See [workflow-recipes.md](../operations/workflow-recipes.md) recipe 3 for the frontend trigger pattern.
167
+ Use `--async` for long-running resources. Use `pnpm exec elevasis --prod exec ...` (flag before `exec`) for production. See [workflow-recipes.md](../operations/workflow-recipes.md) recipe 3 for the low-level frontend trigger pattern (`useApiClient` + `useMutation`). For the higher-level UI pattern using `RunResourceButton`, `useExecuteResource`, and `ZodFormRenderer`, see [../ui/recipes.md](../ui/recipes.md) recipe 6.