@elevasis/sdk 1.6.0 → 1.7.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 (28) hide show
  1. package/dist/cli.cjs +5 -5
  2. package/package.json +2 -2
  3. package/reference/claude-config/hooks/__tests__/pre-edit-vibe-gate.test.mjs +169 -0
  4. package/reference/claude-config/hooks/pre-edit-vibe-gate.mjs +128 -0
  5. package/reference/claude-config/logs/pre-edit-vibe-gate.log +23 -0
  6. package/reference/claude-config/rules/organization-os.md +55 -8
  7. package/reference/claude-config/rules/vibe.md +210 -0
  8. package/reference/claude-config/settings.json +11 -0
  9. package/reference/claude-config/skills/configure/SKILL.md +100 -0
  10. package/reference/claude-config/skills/configure/operations/codify-level-a.md +100 -0
  11. package/reference/claude-config/skills/configure/operations/codify-level-b.md +158 -0
  12. package/reference/claude-config/skills/configure/operations/customers.md +150 -0
  13. package/reference/claude-config/skills/configure/operations/features.md +163 -0
  14. package/reference/claude-config/skills/configure/operations/goals.md +147 -0
  15. package/reference/claude-config/skills/configure/operations/identity.md +133 -0
  16. package/reference/claude-config/skills/configure/operations/labels.md +128 -0
  17. package/reference/claude-config/skills/configure/operations/offerings.md +159 -0
  18. package/reference/claude-config/skills/configure/operations/roles.md +153 -0
  19. package/reference/claude-config/skills/configure/operations/techStack.md +139 -0
  20. package/reference/claude-config/skills/setup/SKILL.md +81 -32
  21. package/reference/packages/core/src/organization-model/README.md +16 -12
  22. package/reference/scaffold/core/organization-graph.mdx +1 -0
  23. package/reference/scaffold/core/organization-model.mdx +84 -19
  24. package/reference/scaffold/recipes/add-a-feature.md +1 -1
  25. package/reference/scaffold/recipes/customize-organization-model.md +5 -5
  26. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +3 -3
  27. package/reference/scaffold/reference/contracts.md +115 -7
  28. package/reference/scaffold/reference/glossary.md +25 -4
package/dist/cli.cjs CHANGED
@@ -44004,7 +44004,7 @@ function wrapAction(commandName, fn) {
44004
44004
  // package.json
44005
44005
  var package_default = {
44006
44006
  name: "@elevasis/sdk",
44007
- version: "1.6.0",
44007
+ version: "1.7.0",
44008
44008
  description: "SDK for building Elevasis organization resources",
44009
44009
  type: "module",
44010
44010
  bin: {
@@ -45494,9 +45494,7 @@ function renderProjectWorkBrief(brief) {
45494
45494
  if (!brief.resumeTarget) {
45495
45495
  lines.push(" No clear resume target yet.");
45496
45496
  } else {
45497
- lines.push(
45498
- ` ${brief.resumeTarget.kind}: ${brief.resumeTarget.name} (${brief.resumeTarget.status ?? "unknown"})`
45499
- );
45497
+ lines.push(` ${brief.resumeTarget.kind}: ${brief.resumeTarget.name} (${brief.resumeTarget.status ?? "unknown"})`);
45500
45498
  if (brief.resumeTarget.savedState) {
45501
45499
  lines.push(` Saved state: ${brief.resumeTarget.savedState}`);
45502
45500
  }
@@ -45544,7 +45542,9 @@ Projects (${projects.length}):
45544
45542
  );
45545
45543
  }
45546
45544
  function registerProjectResolve(program3) {
45547
- program3.command("project:resolve <query>").description('Resolve a project ID from a name, UUID, or search query\n Example: elevasis-sdk project:resolve "Alpha"').option("--api-url <url>", "API base URL").option("--pretty", "Render project details instead of only the resolved ID").action(
45545
+ program3.command("project:resolve <query>").description(
45546
+ 'Resolve a project ID from a name, UUID, or search query\n Example: elevasis-sdk project:resolve "Alpha"'
45547
+ ).option("--api-url <url>", "API base URL").option("--pretty", "Render project details instead of only the resolved ID").action(
45548
45548
  wrapAction("project:resolve", async (query, options2) => {
45549
45549
  const project = await resolveProject(query, options2.apiUrl);
45550
45550
  if (options2.pretty) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/sdk",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "SDK for building Elevasis organization resources",
5
5
  "type": "module",
6
6
  "bin": {
@@ -44,7 +44,7 @@
44
44
  "tsup": "^8.0.0",
45
45
  "typescript": "5.9.2",
46
46
  "zod": "^4.1.0",
47
- "@repo/core": "0.5.0",
47
+ "@repo/core": "0.6.0",
48
48
  "@repo/typescript-config": "0.0.0"
49
49
  },
50
50
  "scripts": {
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ // pre-edit-vibe-gate.test.mjs
3
+ // Tests for the pre-edit-vibe-gate hook.
4
+ // Run with: node --test .claude/hooks/__tests__/pre-edit-vibe-gate.test.mjs
5
+ //
6
+ // Tests the exported `isProtectedPath` helper directly (pure logic, no stdin/stdout
7
+ // mocking needed). Integration cases simulate the full hook by spawning it as a
8
+ // child process.
9
+
10
+ import { describe, it } from 'node:test'
11
+ import assert from 'node:assert/strict'
12
+ import { spawnSync } from 'node:child_process'
13
+ import { resolve, dirname } from 'node:path'
14
+ import { fileURLToPath, pathToFileURL } from 'node:url'
15
+
16
+ const __dirname = dirname(fileURLToPath(import.meta.url))
17
+ const HOOK_PATH = resolve(__dirname, '..', 'pre-edit-vibe-gate.mjs')
18
+
19
+ // Import the exported helper for unit-level tests.
20
+ // Using a dynamic import so the module's top-level await (stdin read) doesn't
21
+ // execute — the hook guards that behind the stdin loop which only runs when
22
+ // there is actual input; unit tests call the exported function directly.
23
+ // On Windows, absolute paths must be converted to file:// URLs for ESM imports.
24
+ const { isProtectedPath } = await import(pathToFileURL(HOOK_PATH).href)
25
+
26
+ // Template root = 3 levels up from __tests__/
27
+ const TEMPLATE_ROOT = resolve(__dirname, '..', '..', '..')
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Helper: run the hook as a subprocess with a synthetic PreToolUse event.
31
+ // filePath may be relative (to template root) or already absolute.
32
+ // ---------------------------------------------------------------------------
33
+ function runHook(toolName, filePath, env = {}) {
34
+ // Claude always sends absolute paths to hooks. Resolve relative paths
35
+ // against the template root so toRelative() inside the hook works correctly.
36
+ const absFilePath =
37
+ filePath.startsWith('/') || /^[A-Za-z]:/.test(filePath) ? filePath : resolve(TEMPLATE_ROOT, filePath)
38
+
39
+ const event = JSON.stringify({
40
+ tool_name: toolName,
41
+ tool_input: { file_path: absFilePath }
42
+ })
43
+
44
+ return spawnSync(process.execPath, [HOOK_PATH], {
45
+ input: event,
46
+ encoding: 'utf-8',
47
+ env: {
48
+ ...process.env,
49
+ // Override AFTER spreading so this always wins over any ambient value
50
+ CLAUDE_PROJECT_DIR: TEMPLATE_ROOT,
51
+ ...env
52
+ },
53
+ timeout: 5000
54
+ })
55
+ }
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // Unit tests — isProtectedPath (pure function, no process spawning)
59
+ // ---------------------------------------------------------------------------
60
+
61
+ describe('isProtectedPath — exact protected files', () => {
62
+ it('blocks organization-model.ts', () => {
63
+ assert.equal(isProtectedPath('foundations/config/organization-model.ts'), true)
64
+ })
65
+
66
+ it('blocks organization-model.examples.ts', () => {
67
+ assert.equal(isProtectedPath('foundations/config/organization-model.examples.ts'), true)
68
+ })
69
+
70
+ it('blocks organization-model.override.ts', () => {
71
+ assert.equal(isProtectedPath('foundations/config/organization-model.override.ts'), true)
72
+ })
73
+ })
74
+
75
+ describe('isProtectedPath — extensions glob', () => {
76
+ it('blocks a .ts file directly under extensions/', () => {
77
+ assert.equal(isProtectedPath('foundations/config/extensions/deal-ecom.ts'), true)
78
+ })
79
+
80
+ it('blocks a .ts file in a subdirectory under extensions/', () => {
81
+ assert.equal(isProtectedPath('foundations/config/extensions/crm/deal-ecom.ts'), true)
82
+ })
83
+
84
+ it('blocks the discriminated-union index.ts under extensions/', () => {
85
+ assert.equal(isProtectedPath('foundations/config/extensions/index.ts'), true)
86
+ })
87
+
88
+ it('does NOT block a non-.ts file under extensions/', () => {
89
+ assert.equal(isProtectedPath('foundations/config/extensions/README.md'), false)
90
+ })
91
+ })
92
+
93
+ describe('isProtectedPath — unrelated paths always pass', () => {
94
+ it('allows ui/ files', () => {
95
+ assert.equal(isProtectedPath('ui/src/routes/__root.tsx'), false)
96
+ })
97
+
98
+ it('allows operations/ files', () => {
99
+ assert.equal(isProtectedPath('operations/src/index.ts'), false)
100
+ })
101
+
102
+ it('allows foundations/types (not config)', () => {
103
+ assert.equal(isProtectedPath('foundations/types/entities.ts'), false)
104
+ })
105
+
106
+ it('does NOT block a partial-match path that is not under foundations/config', () => {
107
+ // "organization-model.ts" without the full prefix should not be blocked
108
+ assert.equal(isProtectedPath('src/organization-model.ts'), false)
109
+ })
110
+ })
111
+
112
+ describe('isProtectedPath — partial path / edge cases', () => {
113
+ it('does not block foundations/config/ itself (no .ts suffix)', () => {
114
+ // The directory path should not be blocked
115
+ assert.equal(isProtectedPath('foundations/config/'), false)
116
+ })
117
+
118
+ it('strips leading ./ before matching', () => {
119
+ assert.equal(isProtectedPath('./foundations/config/organization-model.ts'), true)
120
+ })
121
+ })
122
+
123
+ // ---------------------------------------------------------------------------
124
+ // Integration tests — spawn the hook with synthetic events
125
+ // ---------------------------------------------------------------------------
126
+
127
+ describe('hook subprocess — blocked without VIBE_APPROVED', () => {
128
+ it('exits 2 for Write to organization-model.ts', () => {
129
+ const result = runHook('Write', 'foundations/config/organization-model.ts')
130
+ assert.equal(result.status, 2, `expected exit 2, got ${result.status}`)
131
+ assert.ok(result.stderr.includes('BLOCKED'), 'expected BLOCKED in stderr')
132
+ })
133
+
134
+ it('exits 2 for Edit to extensions/deal-ecom.ts', () => {
135
+ const result = runHook('Edit', 'foundations/config/extensions/deal-ecom.ts')
136
+ assert.equal(result.status, 2)
137
+ assert.ok(result.stderr.includes('BLOCKED'))
138
+ })
139
+
140
+ it('exits 2 for MultiEdit to organization-model.override.ts', () => {
141
+ const result = runHook('MultiEdit', 'foundations/config/organization-model.override.ts')
142
+ assert.equal(result.status, 2)
143
+ assert.ok(result.stderr.includes('BLOCKED'))
144
+ })
145
+ })
146
+
147
+ describe('hook subprocess — passes with VIBE_APPROVED=1', () => {
148
+ it('exits 0 for Write to organization-model.ts when VIBE_APPROVED=1', () => {
149
+ const result = runHook('Write', 'foundations/config/organization-model.ts', { VIBE_APPROVED: '1' })
150
+ assert.equal(result.status, 0, `expected exit 0, got ${result.status}`)
151
+ })
152
+
153
+ it('exits 0 for Edit to extensions/deal-ecom.ts when VIBE_APPROVED=1', () => {
154
+ const result = runHook('Edit', 'foundations/config/extensions/deal-ecom.ts', { VIBE_APPROVED: '1' })
155
+ assert.equal(result.status, 0)
156
+ })
157
+ })
158
+
159
+ describe('hook subprocess — unrelated path always passes', () => {
160
+ it('exits 0 for Write to ui/src/routes/__root.tsx without VIBE_APPROVED', () => {
161
+ const result = runHook('Write', 'ui/src/routes/__root.tsx')
162
+ assert.equal(result.status, 0)
163
+ })
164
+
165
+ it('exits 0 for Edit to operations/src/index.ts without VIBE_APPROVED', () => {
166
+ const result = runHook('Edit', 'operations/src/index.ts')
167
+ assert.equal(result.status, 0)
168
+ })
169
+ })
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ // pre-edit-vibe-gate.mjs
3
+ // PreToolUse backstop — blocks raw writes to protected foundations/config paths
4
+ // unless the VIBE_APPROVED=1 trust marker is present.
5
+ //
6
+ // Protected paths (relative to project root):
7
+ // foundations/config/organization-model.ts
8
+ // foundations/config/organization-model.examples.ts
9
+ // foundations/config/organization-model.override.ts
10
+ // foundations/config/extensions/**/*.ts
11
+ //
12
+ // To allow a write: set VIBE_APPROVED=1 in the environment before invoking the
13
+ // agent, or run /configure which sets the marker automatically after user
14
+ // confirmation.
15
+
16
+ import { appendFileSync, mkdirSync } from 'node:fs'
17
+ import { normalize, resolve, relative, sep } from 'node:path'
18
+ import { fileURLToPath } from 'node:url'
19
+
20
+ const ROOT = normalize(process.env.CLAUDE_PROJECT_DIR ?? process.cwd())
21
+ const LOG_DIR = ROOT + sep + '.claude' + sep + 'logs'
22
+ const LOG_FILE = LOG_DIR + sep + 'pre-edit-vibe-gate.log'
23
+
24
+ function log(msg) {
25
+ try {
26
+ mkdirSync(LOG_DIR, { recursive: true })
27
+ appendFileSync(LOG_FILE, `[${new Date().toISOString()}] ${msg}\n`)
28
+ } catch {
29
+ // Never crash on log failure
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Normalise an incoming file path (may be absolute or project-relative) to a
35
+ * forward-slash relative path from ROOT for consistent matching.
36
+ */
37
+ function toRelative(filePath) {
38
+ const abs = normalize(resolve(filePath))
39
+ // relative() returns OS-separator paths — normalise to forward slashes
40
+ return relative(ROOT, abs).replace(/\\/g, '/')
41
+ }
42
+
43
+ /**
44
+ * Returns true if `rel` (forward-slash relative path from root) matches one of
45
+ * the protected path patterns. No external deps — uses simple string checks.
46
+ *
47
+ * Protected patterns:
48
+ * foundations/config/organization-model.ts (exact)
49
+ * foundations/config/organization-model.examples.ts (exact)
50
+ * foundations/config/organization-model.override.ts (exact)
51
+ * foundations/config/extensions/**\/*.ts (glob — any .ts under extensions/)
52
+ */
53
+ export function isProtectedPath(rel) {
54
+ // Normalise away any leading ./
55
+ const r = rel.replace(/^\.\//, '')
56
+
57
+ // Exact protected files
58
+ const EXACT = [
59
+ 'foundations/config/organization-model.ts',
60
+ 'foundations/config/organization-model.examples.ts',
61
+ 'foundations/config/organization-model.override.ts'
62
+ ]
63
+ if (EXACT.includes(r)) return true
64
+
65
+ // Glob: foundations/config/extensions/**/*.ts
66
+ // Must start with the prefix, end with .ts, and have at least one path segment
67
+ // after the extensions/ directory.
68
+ const EXT_PREFIX = 'foundations/config/extensions/'
69
+ if (r.startsWith(EXT_PREFIX) && r.endsWith('.ts')) {
70
+ // Ensure there is at least one filename after the prefix (not just the dir itself)
71
+ const remainder = r.slice(EXT_PREFIX.length)
72
+ if (remainder.length > 3) return true // at least "x.ts"
73
+ }
74
+
75
+ return false
76
+ }
77
+
78
+ const BLOCK_MESSAGE =
79
+ 'BLOCKED: This file is protected by the vibe gate.\n' +
80
+ 'WHY: Direct edits to foundations/config/organization-model.ts and\n' +
81
+ ' foundations/config/extensions/*.ts bypass the ambient vibe ceremony\n' +
82
+ ' (confirm + /configure write + pnpm check-types).\n' +
83
+ 'FIX: Run /configure to codify changes with proper ceremony (sets VIBE_APPROVED=1\n' +
84
+ ' automatically), or set VIBE_APPROVED=1 explicitly if you are a power user\n' +
85
+ ' who has already completed the ceremony manually.'
86
+
87
+ // Only run the stdin-reading main loop when this file is the entry point,
88
+ // not when it is imported as a module (e.g., by tests).
89
+ const isMain =
90
+ process.argv[1] != null && normalize(fileURLToPath(import.meta.url)) === normalize(resolve(process.argv[1]))
91
+
92
+ if (isMain) {
93
+ try {
94
+ const chunks = []
95
+ for await (const chunk of process.stdin) chunks.push(chunk)
96
+ const input = JSON.parse(Buffer.concat(chunks).toString())
97
+
98
+ const toolName = input.tool_name ?? ''
99
+ const filePath = input.tool_input?.file_path ?? ''
100
+
101
+ // Only gate Write, Edit, MultiEdit
102
+ if (!['Write', 'Edit', 'MultiEdit'].includes(toolName)) {
103
+ log(`SKIP tool=${toolName} (not a write tool)`)
104
+ process.exit(0)
105
+ }
106
+
107
+ if (!filePath) {
108
+ log(`SKIP tool=${toolName} no file_path in input`)
109
+ process.exit(0)
110
+ }
111
+
112
+ const rel = toRelative(filePath)
113
+ const protected_ = isProtectedPath(rel)
114
+ const approved = process.env.VIBE_APPROVED === '1'
115
+ const decision = protected_ && !approved ? 'BLOCK' : 'ALLOW'
116
+
117
+ log(`tool=${toolName} path=${rel} protected=${protected_} VIBE_APPROVED=${approved} decision=${decision}`)
118
+
119
+ if (decision === 'BLOCK') {
120
+ process.stderr.write(BLOCK_MESSAGE)
121
+ process.exit(2)
122
+ }
123
+ } catch (err) {
124
+ log(`ERROR: ${err?.message ?? String(err)}`)
125
+ }
126
+
127
+ process.exit(0)
128
+ }
@@ -0,0 +1,23 @@
1
+ [2026-04-20T09:29:53.658Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=false decision=ALLOW
2
+ [2026-04-20T09:29:53.702Z] tool=Edit path=../../foundations/config/extensions/deal-ecom.ts protected=false VIBE_APPROVED=false decision=ALLOW
3
+ [2026-04-20T09:29:53.747Z] tool=MultiEdit path=../../foundations/config/organization-model.override.ts protected=false VIBE_APPROVED=false decision=ALLOW
4
+ [2026-04-20T09:29:53.793Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=true decision=ALLOW
5
+ [2026-04-20T09:29:53.837Z] tool=Edit path=../../foundations/config/extensions/deal-ecom.ts protected=false VIBE_APPROVED=true decision=ALLOW
6
+ [2026-04-20T09:29:53.890Z] tool=Write path=../../ui/src/routes/__root.tsx protected=false VIBE_APPROVED=false decision=ALLOW
7
+ [2026-04-20T09:29:53.934Z] tool=Edit path=../../operations/src/index.ts protected=false VIBE_APPROVED=false decision=ALLOW
8
+ [2026-04-20T09:32:06.844Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=false decision=ALLOW
9
+ [2026-04-20T09:32:06.890Z] tool=Edit path=../../foundations/config/extensions/deal-ecom.ts protected=false VIBE_APPROVED=false decision=ALLOW
10
+ [2026-04-20T09:32:06.934Z] tool=MultiEdit path=../../foundations/config/organization-model.override.ts protected=false VIBE_APPROVED=false decision=ALLOW
11
+ [2026-04-20T09:32:06.978Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=true decision=ALLOW
12
+ [2026-04-20T09:32:07.021Z] tool=Edit path=../../foundations/config/extensions/deal-ecom.ts protected=false VIBE_APPROVED=true decision=ALLOW
13
+ [2026-04-20T09:32:07.065Z] tool=Write path=../../ui/src/routes/__root.tsx protected=false VIBE_APPROVED=false decision=ALLOW
14
+ [2026-04-20T09:32:07.109Z] tool=Edit path=../../operations/src/index.ts protected=false VIBE_APPROVED=false decision=ALLOW
15
+ [2026-04-20T09:32:30.340Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=false decision=ALLOW
16
+ [2026-04-20T09:38:14.624Z] tool=Write path=../../foundations/config/organization-model.ts protected=false VIBE_APPROVED=false decision=ALLOW
17
+ [2026-04-20T09:40:20.586Z] tool=Write path=foundations/config/organization-model.ts protected=true VIBE_APPROVED=false decision=BLOCK
18
+ [2026-04-20T09:40:20.631Z] tool=Edit path=foundations/config/extensions/deal-ecom.ts protected=true VIBE_APPROVED=false decision=BLOCK
19
+ [2026-04-20T09:40:20.674Z] tool=MultiEdit path=foundations/config/organization-model.override.ts protected=true VIBE_APPROVED=false decision=BLOCK
20
+ [2026-04-20T09:40:20.718Z] tool=Write path=foundations/config/organization-model.ts protected=true VIBE_APPROVED=true decision=ALLOW
21
+ [2026-04-20T09:40:20.762Z] tool=Edit path=foundations/config/extensions/deal-ecom.ts protected=true VIBE_APPROVED=true decision=ALLOW
22
+ [2026-04-20T09:40:20.807Z] tool=Write path=ui/src/routes/__root.tsx protected=false VIBE_APPROVED=false decision=ALLOW
23
+ [2026-04-20T09:40:20.905Z] tool=Edit path=operations/src/index.ts protected=false VIBE_APPROVED=false decision=ALLOW
@@ -5,12 +5,34 @@ Organization OS is the semantic contract layer defining how organizations, featu
5
5
  ## Key Files in This Project
6
6
 
7
7
  - `foundations/config/organization-model.ts` -- project-specific org model definition (calls `defineOrganizationModel` + `resolveOrganizationModel`)
8
- - `foundations/config/organization-model.examples.ts` -- 5 reference patterns: branding, CRM stages, lead-gen stages, resource mappings, custom features. Pure reference -- not imported anywhere. Read this when customizing the org model.
8
+ - `foundations/config/organization-model.examples.ts` -- reference patterns for all 14 domains: branding, identity, customers, offerings, roles, goals, sales stages, prospecting stages, resource mappings with techStack, custom features, statuses, and open-placement navigation groups. Pure reference -- not imported anywhere. Read this when customizing the org model.
9
9
  - `foundations/types/entities.ts` -- typed entity contracts (Project, Deal, etc.). Extends `BaseProject`, `BaseDeal` from `@elevasis/core/entities` with project-specific metadata. Read this when authoring workflows that operate on these entities.
10
10
  - `ui/src/routes/__root.tsx` -- wires `ElevasisFeaturesProvider` with `canonicalOrganizationModel`
11
11
  - `ui/src/app-config.ts` -- references the org model
12
12
  - `operations/src/index.ts` -- `DeploymentSpec` registry for workflows and agents
13
13
 
14
+ ## Domain Overview
15
+
16
+ As of the 2026-04-20 expansion, `OrganizationModel` contains 14 top-level domains:
17
+
18
+ **Platform configuration:** `features`, `branding`, `navigation`, `sales` (formerly `crm`), `prospecting` (formerly `leadGen`), `projects` (formerly `delivery`), `resourceMappings`
19
+
20
+ **Organizational reality:** `identity`, `customers`, `offerings`, `roles`, `goals`
21
+
22
+ **Vibe layer:** `statuses`, `operations`
23
+
24
+ The `resourceMappings` entries may carry an optional `techStack` extension (`platform`, `purpose`, `credentialStatus`, `isSystemOfRecord`) without introducing a new top-level domain.
25
+
26
+ ### Domain Rename Note
27
+
28
+ Three field names changed in the 2026-04-20 expansion. Feature ID constants and consumer-facing feature IDs are unchanged:
29
+
30
+ | Old field | New field | Feature ID (unchanged) | Constant (unchanged) |
31
+ | ---------- | ------------- | ---------------------- | --------------------- |
32
+ | `crm` | `sales` | `'crm'` | `CRM_FEATURE_ID` |
33
+ | `leadGen` | `prospecting` | `'lead-gen'` | `LEAD_GEN_FEATURE_ID` |
34
+ | `delivery` | `projects` | `'projects'` | `PROJECTS_FEATURE_ID` |
35
+
14
36
  ## Reference Documentation
15
37
 
16
38
  Full Organization OS documentation ships with the SDK and is available locally after `pnpm install`:
@@ -20,7 +42,7 @@ Full Organization OS documentation ships with the SDK and is available locally a
20
42
  All paths under `node_modules/@elevasis/sdk/reference/scaffold/`:
21
43
 
22
44
  - `node_modules/@elevasis/sdk/reference/scaffold/index.mdx` -- scaffold root and navigation
23
- - `node_modules/@elevasis/sdk/reference/scaffold/core/organization-model.mdx` -- semantic contract, schema, authoring helpers
45
+ - `node_modules/@elevasis/sdk/reference/scaffold/core/organization-model.mdx` -- semantic contract, all 14 domains, adapter authoring, validation gate, `/configure` entry point
24
46
  - `node_modules/@elevasis/sdk/reference/scaffold/core/organization-graph.mdx` -- graph derivation, node/edge taxonomy, lenses
25
47
  - `node_modules/@elevasis/sdk/reference/scaffold/ui/feature-shell.mdx` -- FeatureModule manifest, provider runtime
26
48
  - `node_modules/@elevasis/sdk/reference/scaffold/ui/composition-extensibility.mdx` -- layout primitives, router abstraction
@@ -48,15 +70,40 @@ All paths under `node_modules/@elevasis/sdk/reference/scaffold/`:
48
70
  - `@elevasis/core/organization-model` -- the curated organization-model barrel. Exports `defineOrganizationModel`, `resolveOrganizationModel`, `OrganizationModelSchema`, `DEFAULT_ORGANIZATION_MODEL`, organization-model types, and typed feature/surface constants.
49
71
  - Feature IDs: `CRM_FEATURE_ID`, `LEAD_GEN_FEATURE_ID`, `PROJECTS_FEATURE_ID`, `OPERATIONS_FEATURE_ID`, `MONITORING_FEATURE_ID`, `SETTINGS_FEATURE_ID`, `SEO_FEATURE_ID`
50
72
  - Headline surface IDs: `CRM_PIPELINE_SURFACE_ID`, `LEAD_GEN_LISTS_SURFACE_ID`, `PROJECTS_INDEX_SURFACE_ID`, `OPERATIONS_ORGANIZATION_GRAPH_SURFACE_ID`
51
- - Use these constants instead of magic strings when overriding the org model.
73
+ - Reality domain types: `OrganizationModelIdentity`, `OrganizationModelCustomers`, `OrganizationModelCustomerSegment`, `OrganizationModelOfferings`, `OrganizationModelProduct`, `OrganizationModelRoles`, `OrganizationModelRole`, `OrganizationModelGoals`, `OrganizationModelObjective`, `OrganizationModelKeyResult`
74
+ - Vibe domain types: `OrganizationModelStatuses`, `OrganizationModelOperations`
75
+ - TechStack: `TechStackEntrySchema`, `OrganizationModelTechStackEntry`
76
+ - Use constants instead of magic strings when overriding the org model.
52
77
  - `@elevasis/core/entities` -- entity contracts barrel. Exports `BaseProject`, `BaseProjectSchema`, `BaseProjectInput` and the equivalents for `Milestone`, `Task`, `Deal`, `Company`, `Contact`. Each base interface is generic over a `\<TMeta>` extension slot. Extend these in `foundations/types/entities.ts` to add project-specific fields.
53
78
 
54
79
  ## When Working with Organization OS
55
80
 
56
- - **Adding a feature:** Follow `node_modules/@elevasis/sdk/reference/scaffold/recipes/add-a-feature.md`
57
- - **Adding a resource:** Follow `node_modules/@elevasis/sdk/reference/scaffold/recipes/add-a-resource.md`
58
- - **Changing org model:** Start with `foundations/config/organization-model.examples.ts` for reference patterns, then edit `foundations/config/organization-model.ts`. Use the typed feature/surface constants from `@elevasis/core/organization-model` rather than magic strings. Verify the org-os wiring (provider chain, CSS imports, feature shell).
81
+ - **Changing org model (structural reality):** Use `/configure` as the entry point. Do not edit `foundations/config/organization-model.ts` directly -- the `pre-edit-vibe-gate.mjs` hook blocks raw writes without `VIBE_APPROVED=1`, which `/configure` sets after user confirmation. Run `/configure` for the full layered flow or `/configure \<domain>` for a targeted domain.
82
+ - **Adding a feature:** Follow `node_modules/@elevasis/sdk/reference/scaffold/recipes/add-a-feature.md`. For toggling an existing feature, use `/configure features`.
83
+ - **Adding a resource:** Follow `node_modules/@elevasis/sdk/reference/scaffold/recipes/add-a-resource.md`.
59
84
  - **Extending entities:** Start with `foundations/types/entities.ts` for the demo extension pattern. Base shapes come from `@elevasis/core/entities`.
60
85
  - **Authoring a workflow that takes a Project/Deal/etc.:** Reference entity types from `foundations/types/entities.ts` in the input schema -- do not redeclare them.
61
- - **Understanding contracts:** Check `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md` for current type shapes
62
- - **Debugging sync issues:** Check `node_modules/@elevasis/sdk/reference/scaffold/operations/propagation-pipeline.md` for the verification pipeline
86
+ - **Understanding contracts:** Check `node_modules/@elevasis/sdk/reference/scaffold/reference/contracts.md` for current type shapes.
87
+ - **Debugging sync issues:** Check `node_modules/@elevasis/sdk/reference/scaffold/operations/propagation-pipeline.md` for the verification pipeline.
88
+
89
+ ## `/configure` -- Org Model QA Entry Point
90
+
91
+ `/configure` is the recurring, safe-to-re-run org model editor for this project. It is a skill (not a command) at `.claude/skills/configure/SKILL.md`.
92
+
93
+ **Usage:**
94
+
95
+ - `/configure` -- layered flow: identity → customers → offerings → roles → goals → techStack
96
+ - `/configure identity` -- legal identity, mission/vision, industry, geography, timezone
97
+ - `/configure customers` -- customer segments with jobs-to-be-done, pains, gains, firmographics
98
+ - `/configure offerings` -- products and services with pricing model and segment references
99
+ - `/configure roles` -- role chart with responsibilities, reporting lines, and holders
100
+ - `/configure goals` -- organizational goals with period and measurable outcomes
101
+ - `/configure techStack` -- external-SaaS integration metadata on resource mappings
102
+ - `/configure features` -- enable, disable, or add features
103
+ - `/configure labels` -- edit display labels on enum entries (statuses, stages)
104
+
105
+ Every write is gated: `resolveOrganizationModel()` must succeed (Zod cross-refs pass) and `pnpm -C operations check-types` must pass. On failure the change is rolled back.
106
+
107
+ **Distinction from `/setup`:** `/setup` is first-time bootstrap only. After bootstrap it delegates here. `/configure` is idempotent and safe to re-run at any time.
108
+
109
+ The ambient vibe layer (`.claude/rules/vibe.md`) automatically detects Codify intent in plain language and delegates to `/configure`. Power users can invoke `/configure` directly to bypass the ambient layer entirely.