@elevasis/sdk 1.8.3 → 1.9.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.
@@ -0,0 +1,689 @@
1
+ // Pure reference file -- NOT imported anywhere.
2
+ // Copy individual examples into organization-model.ts as needed.
3
+ // Each const is a valid `defineOrganizationModel()` override shape. All examples
4
+ // are written against the current @elevasis/core schema (reality-domain expansion)
5
+ // and will type-check once @elevasis/core is updated to the version that includes
6
+ // the new domains (identity, customers, offerings, roles, goals, statuses, operations).
7
+ //
8
+ // Examples are organized by domain. Each section shows the minimal shape a developer
9
+ // would write when answering /configure prompts for that domain.
10
+ import {
11
+ SALES_PIPELINE_SURFACE_ID,
12
+ defineOrganizationModel,
13
+ type OrganizationModelResourceMapping
14
+ } from '@elevasis/core/organization-model'
15
+
16
+ const SALES_FEATURE_ID = 'crm' as const
17
+ const PROSPECTING_FEATURE_ID = 'lead-gen' as const
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // 1. Branding override -- shortest useful case
21
+ // ---------------------------------------------------------------------------
22
+ export const brandingOverrideExample = defineOrganizationModel({
23
+ branding: {
24
+ organizationName: 'Acme Corp',
25
+ productName: 'Acme Command Center',
26
+ shortName: 'Acme'
27
+ }
28
+ })
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // 2. CRM customization -- replace default pipeline stages
32
+ // ---------------------------------------------------------------------------
33
+ export const crmCustomizationExample = defineOrganizationModel({
34
+ sales: {
35
+ entityId: 'crm.deal',
36
+ defaultPipelineId: 'sales',
37
+ pipelines: [
38
+ {
39
+ id: 'sales',
40
+ label: 'Sales Pipeline',
41
+ entityId: 'crm.deal',
42
+ stages: [
43
+ {
44
+ id: 'qualified',
45
+ label: 'Qualified',
46
+ color: 'blue',
47
+ order: 1,
48
+ semanticClass: 'open',
49
+ surfaceIds: [SALES_PIPELINE_SURFACE_ID],
50
+ resourceIds: []
51
+ },
52
+ {
53
+ id: 'negotiating',
54
+ label: 'Negotiating',
55
+ color: 'yellow',
56
+ order: 2,
57
+ semanticClass: 'active',
58
+ surfaceIds: [SALES_PIPELINE_SURFACE_ID],
59
+ resourceIds: []
60
+ },
61
+ {
62
+ id: 'won',
63
+ label: 'Won',
64
+ color: 'green',
65
+ order: 3,
66
+ semanticClass: 'closed_won',
67
+ surfaceIds: [SALES_PIPELINE_SURFACE_ID],
68
+ resourceIds: []
69
+ }
70
+ ]
71
+ }
72
+ ]
73
+ }
74
+ })
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // 3. Lead-gen customization -- replace company lifecycle stages
78
+ // ---------------------------------------------------------------------------
79
+ export const leadGenCustomizationExample = defineOrganizationModel({
80
+ prospecting: {
81
+ listEntityId: 'leadgen.list',
82
+ companyEntityId: 'leadgen.company',
83
+ contactEntityId: 'leadgen.contact',
84
+ companyStages: [
85
+ { id: 'scraped', label: 'Scraped', order: 1 },
86
+ { id: 'enriched', label: 'Enriched', order: 2 },
87
+ { id: 'approved', label: 'Approved', order: 3 }
88
+ ],
89
+ contactStages: [
90
+ { id: 'found', label: 'Found', order: 1 },
91
+ { id: 'verified', label: 'Verified', order: 2 },
92
+ { id: 'ready', label: 'Ready', order: 3 }
93
+ ]
94
+ }
95
+ })
96
+
97
+ // ---------------------------------------------------------------------------
98
+ // 4. Resource mappings -- associate platform resources with surfaces
99
+ // ---------------------------------------------------------------------------
100
+ const resourceMappingEntries: OrganizationModelResourceMapping[] = [
101
+ {
102
+ id: 'lead-gen-enrichment',
103
+ label: 'Lead Enrichment',
104
+ resourceId: 'my-org/lead-enrichment-workflow',
105
+ resourceType: 'workflow',
106
+ featureIds: [PROSPECTING_FEATURE_ID],
107
+ entityIds: ['leadgen.company'],
108
+ surfaceIds: ['lead-gen.lists'],
109
+ capabilityIds: []
110
+ },
111
+ {
112
+ id: 'crm-follow-up',
113
+ label: 'CRM Follow-Up Agent',
114
+ resourceId: 'my-org/crm-follow-up-agent',
115
+ resourceType: 'agent',
116
+ featureIds: [SALES_FEATURE_ID],
117
+ entityIds: ['crm.deal'],
118
+ surfaceIds: [SALES_PIPELINE_SURFACE_ID],
119
+ capabilityIds: ['crm.pipeline.manage']
120
+ }
121
+ ]
122
+
123
+ export const resourceMappingExample = defineOrganizationModel({
124
+ resourceMappings: resourceMappingEntries
125
+ })
126
+
127
+ // ---------------------------------------------------------------------------
128
+ // 5. Custom feature -- add a project-specific feature
129
+ //
130
+ // NOTE: the `features` field REPLACES the default array on merge (arrays are
131
+ // not deep-merged). To keep the built-in features (CRM, Lead Gen, etc.) while
132
+ // adding a custom one, spread them explicitly:
133
+ //
134
+ // features: [...DEFAULT_ORGANIZATION_MODEL.features, myCustomFeature]
135
+ //
136
+ // The example below shows a standalone override with only the custom feature
137
+ // to illustrate the shape. Import DEFAULT_ORGANIZATION_MODEL from
138
+ // @elevasis/core/organization-model if you need the full set.
139
+ // ---------------------------------------------------------------------------
140
+ export const customFeatureExample = defineOrganizationModel({
141
+ features: [
142
+ {
143
+ id: 'my-custom',
144
+ label: 'My Custom Feature',
145
+ description: 'A project-specific feature outside the standard suite',
146
+ enabled: true,
147
+ color: 'teal',
148
+ entityIds: [],
149
+ surfaceIds: ['my-custom.dashboard'],
150
+ resourceIds: [],
151
+ capabilityIds: []
152
+ }
153
+ ]
154
+ })
155
+
156
+ // ---------------------------------------------------------------------------
157
+ // 6. Identity domain -- legal entity, mission/vision, industry/geo anchors
158
+ //
159
+ // Decision #3: identity is distinct from branding. `branding` = display
160
+ // identity (logos, product names). `identity` = legal identity (entity,
161
+ // jurisdiction, mission/vision). Conflating risks branding edits touching
162
+ // compliance fields.
163
+ //
164
+ // Fields: mission, vision, legalName, entityType, jurisdiction,
165
+ // industryCategory, geographicFocus, timeZone, businessHours.
166
+ //
167
+ // businessHours uses HH:MM 24-hour format per day of week.
168
+ // timeZone is an IANA timezone identifier (e.g. "America/Los_Angeles").
169
+ // ---------------------------------------------------------------------------
170
+ export const identityExample = {
171
+ identity: {
172
+ mission: 'Automate the operational work that slows SMBs down so they can focus on what matters.',
173
+ vision: 'A world where every small business has the same operational leverage as a Fortune 500.',
174
+ legalName: 'Acme Automation, LLC',
175
+ entityType: 'LLC',
176
+ jurisdiction: 'United States \u2013 Delaware',
177
+ industryCategory: 'Software / SaaS',
178
+ geographicFocus: 'North America',
179
+ timeZone: 'America/New_York',
180
+ clientBrief:
181
+ 'Acme Automation serves SMBs in the US that are growing past founder-led operations. Primary buyers are ops leads and founders at 10\u201350 person companies. Warm via referral, short sales cycle (~2 weeks), monthly SaaS. The team has no dedicated engineering staff -- we own the full stack from automation design through deployment.',
182
+ businessHours: {
183
+ monday: { open: '09:00', close: '18:00' },
184
+ tuesday: { open: '09:00', close: '18:00' },
185
+ wednesday: { open: '09:00', close: '18:00' },
186
+ thursday: { open: '09:00', close: '18:00' },
187
+ friday: { open: '09:00', close: '17:00' }
188
+ }
189
+ }
190
+ }
191
+
192
+ // Minimal identity -- only mission + timezone filled in; all other fields empty
193
+ export const identityMinimalExample = {
194
+ identity: {
195
+ mission: 'Deliver premium digital marketing results for growth-stage brands.',
196
+ timeZone: 'America/Chicago'
197
+ }
198
+ }
199
+
200
+ // ---------------------------------------------------------------------------
201
+ // 7. Customers domain -- buyer archetypes with JTBD, pains, gains, firmographics
202
+ //
203
+ // Decision #4 (BMC/VPC shape): each segment declares jobs-to-be-done, pains,
204
+ // gains, firmographics (industry, companySize, region), and a value proposition.
205
+ // Agents use segments for outreach targeting, scoring, and proposal personalization.
206
+ //
207
+ // targetSegmentIds on offerings cross-reference segment ids declared here.
208
+ // Bidirectional validation is enforced via OrganizationModelSchema.superRefine().
209
+ // ---------------------------------------------------------------------------
210
+ export const customersExample = {
211
+ customers: {
212
+ segments: [
213
+ {
214
+ id: 'segment-smb-agencies',
215
+ name: 'SMB Marketing Agencies',
216
+ description:
217
+ 'Growth-oriented digital agencies with 5\u201350 staff who run client campaigns and need to eliminate manual operations.',
218
+ jobsToBeDone:
219
+ 'Run more client campaigns without growing headcount. Deliver consistent results faster with fewer errors and no dropped balls.',
220
+ pains: [
221
+ 'Manual data entry across disconnected tools (Instantly, HubSpot, Notion)',
222
+ 'Slow lead qualification that takes hours per batch',
223
+ 'Inconsistent follow-up causing deal leakage at the qualification stage'
224
+ ],
225
+ gains: [
226
+ 'Automated pipelines that run overnight without oversight',
227
+ 'Structured HITL handoffs that keep humans in the loop for high-stakes decisions',
228
+ 'A unified view of every active client project and deal in one surface'
229
+ ],
230
+ firmographics: {
231
+ industry: 'Marketing / Digital Agency',
232
+ companySize: '5\u201350',
233
+ region: 'North America'
234
+ },
235
+ valueProp:
236
+ 'Elevasis automates the repetitive parts of agency operations so the team focuses on strategy and client relationships \u2014 not spreadsheets.'
237
+ },
238
+ {
239
+ id: 'segment-ecom-operators',
240
+ name: 'E-Commerce Operators',
241
+ description:
242
+ 'Bootstrapped or VC-backed e-commerce brands running on Shopify or WooCommerce with 10\u2013100 SKUs.',
243
+ jobsToBeDone: 'Scale order operations and supplier communication without hiring a large ops team.',
244
+ pains: ['Supplier follow-up is manual and inconsistent', 'Returns processing is slow and error-prone'],
245
+ gains: ['Automated supplier status updates', 'Faster returns processing with fewer manual steps'],
246
+ firmographics: {
247
+ industry: 'E-Commerce / Retail',
248
+ companySize: '1\u201320',
249
+ region: 'Global'
250
+ },
251
+ valueProp:
252
+ 'Elevasis turns supplier and returns operations into structured workflows that run without daily oversight.'
253
+ }
254
+ ]
255
+ }
256
+ }
257
+
258
+ // ---------------------------------------------------------------------------
259
+ // 8. Offerings domain -- products/services with pricing model and segment targeting
260
+ //
261
+ // Decision #5 (BMC Value Propositions shape): pricingModel enum values are
262
+ // 'one-time' | 'subscription' | 'usage-based' | 'custom'.
263
+ // targetSegmentIds must resolve to declared customers.segments[].id.
264
+ // deliveryFeatureId (optional) must resolve to a declared features[].id.
265
+ //
266
+ // Arrays are NOT deep-merged: if you declare offerings here, include ALL products
267
+ // you want. Do not rely on default products being preserved.
268
+ // ---------------------------------------------------------------------------
269
+ export const offeringsExample = {
270
+ offerings: {
271
+ products: [
272
+ {
273
+ id: 'product-starter',
274
+ name: 'Starter Automation Pack',
275
+ description: 'Pre-built workflow bundle for lead enrichment, CRM follow-up, and project delivery automation.',
276
+ pricingModel: 'subscription' as const,
277
+ price: 299,
278
+ currency: 'USD',
279
+ targetSegmentIds: ['segment-smb-agencies']
280
+ },
281
+ {
282
+ id: 'product-growth',
283
+ name: 'Growth Plan',
284
+ description:
285
+ 'Full platform access including custom workflow builds, unlimited executions, and dedicated onboarding.',
286
+ pricingModel: 'subscription' as const,
287
+ price: 999,
288
+ currency: 'USD',
289
+ targetSegmentIds: ['segment-smb-agencies', 'segment-ecom-operators']
290
+ },
291
+ {
292
+ id: 'product-custom-build',
293
+ name: 'Custom Build',
294
+ description:
295
+ 'Bespoke AI workflow design and deployment for organizations with unique operational requirements.',
296
+ pricingModel: 'custom' as const,
297
+ price: 0,
298
+ currency: 'USD',
299
+ targetSegmentIds: ['segment-smb-agencies']
300
+ }
301
+ ]
302
+ }
303
+ }
304
+
305
+ // ---------------------------------------------------------------------------
306
+ // 9. Roles domain -- accountability chart with plain-language field names
307
+ //
308
+ // Decision #6 (EOS-inspired shape, plain language):
309
+ // Schema fields: id, title, responsibilities[], reportsToId?, heldBy?
310
+ // No EOS jargon: "title" not "seatTitle", "responsibilities" not "accountabilities".
311
+ // reportsToId cross-references another roles[].id; cycle detection is not enforced.
312
+ // heldBy is a free-form string (name or email) -- not validated against any user registry.
313
+ // Absence of reportsToId indicates a top-level role.
314
+ //
315
+ // Agents use roles for HITL routing, escalation, and approval-rights reasoning.
316
+ // "/configure roles" prompts the user to fill in this domain.
317
+ // ---------------------------------------------------------------------------
318
+ export const rolesExample = {
319
+ roles: {
320
+ roles: [
321
+ {
322
+ id: 'role-ceo',
323
+ title: 'CEO',
324
+ responsibilities: [
325
+ 'Set company direction and approve strategic initiatives',
326
+ 'Own enterprise-tier client relationships',
327
+ 'Final approver for all platform deployments and budget over $5K'
328
+ ],
329
+ heldBy: 'Alex Johnson'
330
+ },
331
+ {
332
+ id: 'role-head-of-ops',
333
+ title: 'Head of Operations',
334
+ responsibilities: [
335
+ 'Manage day-to-day workflow deployments and execution health',
336
+ 'Review and approve items in the HITL queue',
337
+ 'Escalate platform failures to CEO within 2 hours'
338
+ ],
339
+ reportsToId: 'role-ceo',
340
+ heldBy: 'Jordan Lee'
341
+ },
342
+ {
343
+ id: 'role-sales-lead',
344
+ title: 'Sales Lead',
345
+ responsibilities: [
346
+ 'Qualify inbound leads and manage the CRM pipeline',
347
+ 'Send proposals and follow up with prospects',
348
+ 'Coordinate with ops on client onboarding timelines'
349
+ ],
350
+ reportsToId: 'role-ceo',
351
+ heldBy: 'sam@acme.io'
352
+ }
353
+ ]
354
+ }
355
+ }
356
+
357
+ // Minimal roles -- solo founder, no reports-to
358
+ export const rolesSoloFounderExample = {
359
+ roles: {
360
+ roles: [
361
+ {
362
+ id: 'role-founder',
363
+ title: 'Founder',
364
+ responsibilities: ['Own all decisions', 'Review all HITL queue items', 'Approve all client deliverables'],
365
+ heldBy: 'founder@mycompany.io'
366
+ }
367
+ ]
368
+ }
369
+ }
370
+
371
+ // ---------------------------------------------------------------------------
372
+ // 10. Goals domain -- quarterly objectives with plain-language measurable outcomes
373
+ //
374
+ // Decision #7 (OKR-shaped, plain-language rendering):
375
+ // Schema fields: objectives[].{ id, description, periodStart, periodEnd, keyResults[] }
376
+ // keyResults[].{ id, description, targetMetric, currentValue, targetValue? }
377
+ // periodStart / periodEnd are ISO 8601 date strings (YYYY-MM-DD).
378
+ // periodEnd must be strictly after periodStart (enforced by superRefine).
379
+ //
380
+ // IMPORTANT naming convention: the schema uses "objectives" and "keyResults"
381
+ // internally for OKR-tooling compatibility. All user-facing labels and
382
+ // /configure prompts say "goals" and "measurable outcomes" -- never "OKR",
383
+ // "objective", or "key result".
384
+ // ---------------------------------------------------------------------------
385
+ export const goalsExample = {
386
+ goals: {
387
+ objectives: [
388
+ {
389
+ id: 'goal-grow-arr-q2-2026',
390
+ description: 'Grow monthly recurring revenue to hit our first ARR milestone by end of Q2 2026.',
391
+ periodStart: '2026-04-01',
392
+ periodEnd: '2026-06-30',
393
+ keyResults: [
394
+ {
395
+ id: 'kr-mrr-10k',
396
+ description: 'Reach $10K MRR',
397
+ targetMetric: 'Monthly recurring revenue (USD)',
398
+ currentValue: 2800,
399
+ targetValue: 10000
400
+ },
401
+ {
402
+ id: 'kr-customers-15',
403
+ description: 'Acquire 15 paying customers',
404
+ targetMetric: 'Paying customer count',
405
+ currentValue: 4,
406
+ targetValue: 15
407
+ }
408
+ ]
409
+ },
410
+ {
411
+ id: 'goal-launch-growth-tier-q2-2026',
412
+ description: 'Launch Growth Plan tier and land 3 customers on it by end of Q2 2026.',
413
+ periodStart: '2026-05-01',
414
+ periodEnd: '2026-06-30',
415
+ keyResults: [
416
+ {
417
+ id: 'kr-growth-launched',
418
+ description: 'Growth Plan live and purchasable',
419
+ targetMetric: 'Launch milestone (binary)',
420
+ currentValue: 0,
421
+ targetValue: 1
422
+ },
423
+ {
424
+ id: 'kr-growth-customers',
425
+ description: '3 customers on Growth tier',
426
+ targetMetric: 'Growth-tier customer count',
427
+ currentValue: 0,
428
+ targetValue: 3
429
+ }
430
+ ]
431
+ }
432
+ ]
433
+ }
434
+ }
435
+
436
+ // Directional goal -- no hard targetValue
437
+ export const goalsDirectionalExample = {
438
+ goals: {
439
+ objectives: [
440
+ {
441
+ id: 'goal-reduce-churn-q3-2026',
442
+ description: 'Reduce monthly churn through better onboarding and proactive success check-ins.',
443
+ periodStart: '2026-07-01',
444
+ periodEnd: '2026-09-30',
445
+ keyResults: [
446
+ {
447
+ id: 'kr-onboarding-nps',
448
+ description: 'Improve onboarding satisfaction',
449
+ targetMetric: 'Onboarding NPS score',
450
+ currentValue: 32
451
+ // targetValue omitted -- directional goal, no hard number yet
452
+ }
453
+ ]
454
+ }
455
+ ]
456
+ }
457
+ }
458
+
459
+ // ---------------------------------------------------------------------------
460
+ // 11. ResourceMappings with techStack extension
461
+ //
462
+ // Decision #4 (org-reality): techStack EXTENDS the resourceMappings subsection.
463
+ // `techStack` is an optional field on each ResourceMapping entry. Fields:
464
+ // platform -- external SaaS name (e.g. "HubSpot", "Stripe", "Notion")
465
+ // purpose -- free-form description of what the integration does
466
+ // credentialStatus -- 'configured' | 'pending' | 'expired' | 'missing'
467
+ // isSystemOfRecord -- boolean; true if this is the primary SoR for its domain
468
+ //
469
+ // ResourceMapping entries with no `techStack` parse cleanly (backward-compat).
470
+ // ---------------------------------------------------------------------------
471
+ export const resourceMappingsWithTechStackExample = {
472
+ resourceMappings: [
473
+ {
474
+ id: 'integration-attio',
475
+ label: 'Attio CRM',
476
+ resourceId: 'my-org/attio-sync',
477
+ resourceType: 'integration' as const,
478
+ featureIds: [],
479
+ entityIds: [],
480
+ surfaceIds: [],
481
+ capabilityIds: [],
482
+ techStack: {
483
+ platform: 'Attio',
484
+ purpose: 'System of record for contacts and deals; synced from the CRM pipeline on stage change',
485
+ credentialStatus: 'configured' as const,
486
+ isSystemOfRecord: true
487
+ }
488
+ },
489
+ {
490
+ id: 'integration-stripe',
491
+ label: 'Stripe',
492
+ resourceId: 'my-org/stripe-billing',
493
+ resourceType: 'integration' as const,
494
+ featureIds: [],
495
+ entityIds: [],
496
+ surfaceIds: [],
497
+ capabilityIds: [],
498
+ techStack: {
499
+ platform: 'Stripe',
500
+ purpose: 'Subscription billing and invoice generation for all products',
501
+ credentialStatus: 'configured' as const,
502
+ isSystemOfRecord: true
503
+ }
504
+ },
505
+ {
506
+ id: 'integration-instantly',
507
+ label: 'Instantly.ai',
508
+ resourceId: 'my-org/instantly-campaigns',
509
+ resourceType: 'integration' as const,
510
+ featureIds: [],
511
+ entityIds: [],
512
+ surfaceIds: [],
513
+ capabilityIds: [],
514
+ techStack: {
515
+ platform: 'Instantly.ai',
516
+ purpose: 'Cold email outreach and campaign management for lead-gen sequences',
517
+ credentialStatus: 'pending' as const,
518
+ isSystemOfRecord: false
519
+ }
520
+ },
521
+ {
522
+ id: 'workflow-lead-enrichment',
523
+ label: 'Lead Enrichment Workflow',
524
+ resourceId: 'my-org/lead-enrichment-workflow',
525
+ resourceType: 'workflow' as const,
526
+ featureIds: [PROSPECTING_FEATURE_ID],
527
+ entityIds: ['leadgen.company'],
528
+ surfaceIds: ['lead-gen.lists'],
529
+ capabilityIds: []
530
+ // No techStack -- this is a platform workflow, not an external SaaS
531
+ }
532
+ ]
533
+ }
534
+
535
+ // ---------------------------------------------------------------------------
536
+ // 12. Statuses domain -- per-org label customization of the platform status registry
537
+ //
538
+ // Decision #9 (vibe): statuses shape is { id, label, semanticClass, category? }.
539
+ // semanticClass enum: 'delivery.task' | 'delivery.project' | 'delivery.milestone'
540
+ // | 'queue' | 'execution' | 'schedule' | 'schedule.run' | 'request'
541
+ //
542
+ // The `entries` array REPLACES the default status registry (arrays are not deep-merged).
543
+ // To keep all platform defaults and only relabel a subset, include the full registry.
544
+ // See DEFAULT_ORGANIZATION_MODEL_STATUSES in @elevasis/core/organization-model.
545
+ //
546
+ // Pattern A -- minimal, override only a few labels (spread defaults + your changes):
547
+ // ---------------------------------------------------------------------------
548
+ export const statusesMinimalOverrideExample = {
549
+ // This shape shows only the entries you'd customise; in practice you must include
550
+ // the full DEFAULT_ORGANIZATION_MODEL_STATUSES.entries spread for all other statuses.
551
+ statuses: {
552
+ entries: [
553
+ // Relabeled to match agency vocabulary
554
+ { id: 'delivery.task.planned', label: 'Queued', semanticClass: 'delivery.task' as const, category: 'delivery' },
555
+ {
556
+ id: 'delivery.task.in_progress',
557
+ label: 'In Progress',
558
+ semanticClass: 'delivery.task' as const,
559
+ category: 'delivery'
560
+ },
561
+ {
562
+ id: 'delivery.task.revision_requested',
563
+ label: 'Needs Rework',
564
+ semanticClass: 'delivery.task' as const,
565
+ category: 'delivery'
566
+ },
567
+ {
568
+ id: 'delivery.task.completed',
569
+ label: 'Done',
570
+ semanticClass: 'delivery.task' as const,
571
+ category: 'delivery'
572
+ },
573
+ // Queue relabeled with client-facing language
574
+ { id: 'queue.pending', label: 'Awaiting Review', semanticClass: 'queue' as const, category: 'queue' },
575
+ { id: 'queue.completed', label: 'Resolved', semanticClass: 'queue' as const, category: 'queue' }
576
+ ]
577
+ }
578
+ }
579
+
580
+ // ---------------------------------------------------------------------------
581
+ // 13. Operations domain -- runtime entity catalog
582
+ //
583
+ // Decision #10 (vibe): operations catalogs HITL queue, sessions, executions,
584
+ // notifications, schedules as first-class model citizens.
585
+ // semanticClass enum: 'queue' | 'executions' | 'sessions' | 'notifications' | 'schedules'
586
+ // supportedStatusSemanticClass links back to the statuses domain for vibe rendering.
587
+ //
588
+ // Each entry represents one stateful runtime entity the org works with.
589
+ // Agents use this to answer Query intents ("what's pending?", "what's running?")
590
+ // without hardcoding service lookups. The `featureId` field routes the entity
591
+ // to the correct feature surface.
592
+ // ---------------------------------------------------------------------------
593
+ export const operationsExample = {
594
+ operations: {
595
+ entries: [
596
+ {
597
+ id: 'operations.queue',
598
+ label: 'Review Queue',
599
+ semanticClass: 'queue' as const,
600
+ featureId: 'operations',
601
+ supportedStatusSemanticClass: ['queue']
602
+ },
603
+ {
604
+ id: 'operations.executions',
605
+ label: 'Workflow Runs',
606
+ semanticClass: 'executions' as const,
607
+ featureId: 'operations',
608
+ supportedStatusSemanticClass: ['execution']
609
+ },
610
+ {
611
+ id: 'operations.sessions',
612
+ label: 'Agent Sessions',
613
+ semanticClass: 'sessions' as const,
614
+ featureId: 'operations'
615
+ },
616
+ {
617
+ id: 'operations.notifications',
618
+ label: 'Platform Alerts',
619
+ semanticClass: 'notifications' as const,
620
+ featureId: 'monitoring'
621
+ },
622
+ {
623
+ id: 'operations.schedules',
624
+ label: 'Scheduled Tasks',
625
+ semanticClass: 'schedules' as const,
626
+ featureId: 'operations',
627
+ supportedStatusSemanticClass: ['schedule', 'schedule.run']
628
+ }
629
+ ]
630
+ }
631
+ }
632
+
633
+ // ---------------------------------------------------------------------------
634
+ // 14. Open placement extension -- navigation group with a custom placement ID
635
+ //
636
+ // Decision #12 (vibe): `surfaceType` and `resourceType` are closed enums
637
+ // (UI/runtime invariants). `placement` is open via extension pattern.
638
+ //
639
+ // Core defines three canonical placement values: 'primary', 'secondary', 'bottom'.
640
+ // NavigationGroupSchema uses z.string() for `placement`, so any string is valid
641
+ // at the schema level -- no changes to @elevasis/core required.
642
+ //
643
+ // To introduce a new placement ID:
644
+ // 1. Add a navigation group with the new placement string (shown below).
645
+ // 2. Add matching rendering logic in the UI feature shell.
646
+ // 3. Document the new placement in this file so the vibe agent can narrate it.
647
+ //
648
+ // The UI feature shell renders groups in document order within each placement bucket.
649
+ // A custom placement that the UI doesn't recognize will be silently omitted from
650
+ // the sidebar unless matching render logic is added.
651
+ // ---------------------------------------------------------------------------
652
+ export const openPlacementExample = {
653
+ navigation: {
654
+ // Extend existing groups by spreading DEFAULT_ORGANIZATION_MODEL.navigation.groups
655
+ // and appending the custom group. Example (not runnable here since it needs the import):
656
+ //
657
+ // groups: [
658
+ // ...DEFAULT_ORGANIZATION_MODEL.navigation.groups,
659
+ // {
660
+ // id: 'spotlight-pinned',
661
+ // label: 'Pinned',
662
+ // placement: 'spotlight', // <-- custom placement, open string
663
+ // surfaceIds: ['crm.pipeline']
664
+ // }
665
+ // ]
666
+ //
667
+ // Standalone shape for illustration (single group, no spread):
668
+ groups: [
669
+ {
670
+ id: 'spotlight-pinned',
671
+ label: 'Pinned',
672
+ placement: 'spotlight', // custom placement ID -- valid per schema (z.string())
673
+ surfaceIds: ['crm.pipeline']
674
+ },
675
+ {
676
+ id: 'contextual-tools',
677
+ label: 'Tools',
678
+ placement: 'contextual', // another custom placement
679
+ surfaceIds: ['operations.command-queue', 'operations.task-scheduler']
680
+ }
681
+ ]
682
+ }
683
+ }
684
+
685
+ // NOTE on the open-placement example: because this overrides `groups` without
686
+ // spreading DEFAULT_ORGANIZATION_MODEL.navigation.groups, navigation groups from
687
+ // the default model (primary-workspace, primary-operations, etc.) would be lost
688
+ // at runtime. In practice, always spread the defaults unless you are intentionally
689
+ // replacing the entire group list. This example isolates the shape only.