spine-framework 0.4.4 → 0.5.0-rc.4

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 (283) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/migrate.ts +36 -30
  8. package/.framework/cli/commands/migrations.ts +16 -56
  9. package/.framework/cli/commands/upgrade.ts +35 -0
  10. package/.framework/cli/commands/validate-schema.ts +147 -0
  11. package/.framework/cli/context.ts +223 -110
  12. package/.framework/cli/index.ts +6 -0
  13. package/.framework/cli/lib/project-files.ts +241 -1
  14. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  15. package/.framework/functions/_shared/logging.ts +562 -224
  16. package/.framework/functions/_shared/middleware.ts +47 -44
  17. package/.framework/functions/admin-data.ts +39 -28
  18. package/.framework/functions/ai-agents.ts +10 -6
  19. package/.framework/functions/api-keys.ts +301 -122
  20. package/.framework/functions/apps.ts +43 -26
  21. package/.framework/functions/cil-ingest.ts +48 -15
  22. package/.framework/functions/debug-auth.ts +14 -8
  23. package/.framework/functions/deliveries.ts +39 -12
  24. package/.framework/functions/embeddings.ts +145 -76
  25. package/.framework/functions/integration-outbound.ts +67 -27
  26. package/.framework/functions/integrations.ts +254 -127
  27. package/.framework/functions/logs.ts +273 -133
  28. package/.framework/functions/observability.ts +277 -147
  29. package/.framework/functions/pipeline-executions.ts +1 -1
  30. package/.framework/functions/pipelines.ts +14 -9
  31. package/.framework/functions/prompt-configs.ts +7 -4
  32. package/.framework/functions/roles.ts +8 -5
  33. package/.framework/functions/security.ts +30 -17
  34. package/.framework/functions/system-cron.ts +240 -127
  35. package/.framework/functions/tests.ts +7 -6
  36. package/.framework/functions/timers.ts +310 -107
  37. package/.framework/functions/triggers.ts +28 -13
  38. package/.framework/functions/types.ts +13 -10
  39. package/.framework/migrations/069_log_stats_window.sql +54 -0
  40. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  41. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  42. package/.framework/migrations/072_slug_autofill.sql +77 -0
  43. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  44. package/.framework/src/apps/admin/index.tsx +1141 -775
  45. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  46. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  47. package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
  48. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  49. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  50. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  51. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  52. package/.framework/src/components/layout/Sidebar.tsx +300 -177
  53. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  54. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  55. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  56. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  57. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  58. package/.framework/src/components/ui/sheet.tsx +24 -26
  59. package/.framework/src/components/ui/textarea.tsx +74 -48
  60. package/.framework/src/hooks/useEntityList.ts +12 -9
  61. package/.framework/src/hooks/useListSchema.ts +108 -58
  62. package/.framework/src/instructions/README.md +57 -0
  63. package/.framework/src/instructions/ai-agents.md +69 -0
  64. package/.framework/src/instructions/alerts.md +80 -0
  65. package/.framework/src/instructions/api-keys.md +87 -0
  66. package/.framework/src/instructions/apps.md +77 -0
  67. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  68. package/.framework/src/instructions/concepts/apps-and-renderers.md +162 -0
  69. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  70. package/.framework/src/instructions/concepts/automation.md +186 -0
  71. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  72. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  73. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  74. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  75. package/.framework/src/instructions/concepts/observability.md +116 -0
  76. package/.framework/src/instructions/concepts/permissions.md +150 -0
  77. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  78. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  79. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  80. package/.framework/src/instructions/deliveries.md +59 -0
  81. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  82. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  83. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  84. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  85. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  86. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  87. package/.framework/src/instructions/integrations.md +96 -0
  88. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  89. package/.framework/src/instructions/invites.md +60 -0
  90. package/.framework/src/instructions/kb.md +80 -0
  91. package/.framework/src/instructions/logs.md +77 -0
  92. package/.framework/src/instructions/observability.md +61 -0
  93. package/.framework/src/instructions/operations/deployment.md +115 -0
  94. package/.framework/src/instructions/operations/migrations.md +125 -0
  95. package/.framework/src/instructions/operations/security-checklist.md +148 -0
  96. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  97. package/.framework/src/instructions/operations/upgrade.md +116 -0
  98. package/.framework/src/instructions/pipeline-executions.md +62 -0
  99. package/.framework/src/instructions/pipelines.md +78 -0
  100. package/.framework/src/instructions/prompts.md +95 -0
  101. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  102. package/.framework/src/instructions/reference/api/auth.md +113 -0
  103. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  104. package/.framework/src/instructions/reference/app-manifest.md +150 -0
  105. package/.framework/src/instructions/reference/cli.md +124 -0
  106. package/.framework/src/instructions/reference/database.md +132 -0
  107. package/.framework/src/instructions/reference/design-schema.md +280 -0
  108. package/.framework/src/instructions/reference/env-vars.md +133 -0
  109. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  110. package/.framework/src/instructions/reference/functions/admin-data.md +195 -0
  111. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  112. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  113. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  114. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  115. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  116. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  117. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  118. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  119. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  120. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  121. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  122. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  123. package/.framework/src/instructions/reference/functions/index.md +103 -0
  124. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  125. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  126. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  127. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  128. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  129. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  130. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  131. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  132. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  133. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  134. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  135. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  136. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  137. package/.framework/src/instructions/reference/functions/security.md +140 -0
  138. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  139. package/.framework/src/instructions/reference/functions/system.md +106 -0
  140. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  141. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  142. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  143. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  144. package/.framework/src/instructions/reference/functions/types.md +146 -0
  145. package/.framework/src/instructions/reference/seeds.md +126 -0
  146. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  147. package/.framework/src/instructions/reference/spine-config.md +114 -0
  148. package/.framework/src/instructions/roles.md +80 -0
  149. package/.framework/src/instructions/runtime-detail.md +70 -0
  150. package/.framework/src/instructions/runtime-list.md +77 -0
  151. package/.framework/src/instructions/security.md +67 -0
  152. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  153. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  154. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  155. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  156. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  157. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  158. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  159. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  160. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  161. package/.framework/src/instructions/tasks/package-and-install-an-app.md +127 -0
  162. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  163. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  164. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  165. package/.framework/src/instructions/testing.md +59 -0
  166. package/.framework/src/instructions/timers.md +82 -0
  167. package/.framework/src/instructions/triggers.md +69 -0
  168. package/.framework/src/instructions/types.md +93 -0
  169. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  170. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  171. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  172. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  173. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  174. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  175. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  176. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  177. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  178. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  179. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  180. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  181. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  182. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  183. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  184. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  185. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  186. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  187. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  188. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  189. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  190. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  191. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  192. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  193. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  194. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  195. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  196. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  197. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  198. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  199. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  200. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  201. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  202. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  203. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  204. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  205. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  206. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  207. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  208. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  209. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  210. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  211. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  212. package/.framework/templates/agent/AGENTS.md +150 -0
  213. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  214. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  215. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  216. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  217. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +72 -0
  218. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  219. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
  220. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
  221. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -0
  222. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  223. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  224. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  225. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  226. package/.framework/templates/project.json +4 -1
  227. package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
  228. package/.framework/tests/unit/agent-files.test.ts +355 -0
  229. package/.framework/tests/unit/agent-runner.test.ts +479 -44
  230. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  231. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  232. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  233. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  234. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  235. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  236. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  237. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  238. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  239. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  240. package/.framework/tests/unit/system-cron.test.ts +240 -0
  241. package/.framework/tests/unit/timers.test.ts +159 -0
  242. package/README.md +125 -166
  243. package/config/tsconfig.cli.json +2 -2
  244. package/package.json +15 -4
  245. package/templates/project/package-lock.json +2 -2
  246. package/.framework/docs/admin-routes.md +0 -76
  247. package/.framework/docs/api-docs-progress.md +0 -38
  248. package/.framework/docs/api-governance.md +0 -146
  249. package/.framework/docs/api-testing-results.md +0 -212
  250. package/.framework/docs/assembly-launch-guide.md +0 -138
  251. package/.framework/docs/audit-results.md +0 -590
  252. package/.framework/docs/db-api-inventory.md +0 -95
  253. package/.framework/docs/gap-remediation-backlog.md +0 -103
  254. package/.framework/docs/ui-adoption-verification.md +0 -111
  255. package/.framework/docs/ui-api-coverage.md +0 -84
  256. package/.framework/docs/v2-compatibility-audit.md +0 -228
  257. package/.framework/mcp/index.ts +0 -133
  258. package/.framework/mcp/load-env.ts +0 -60
  259. package/.framework/mcp/shared/app-manifest.ts +0 -275
  260. package/.framework/mcp/shared/db.ts +0 -477
  261. package/.framework/mcp/shared/kb.ts +0 -118
  262. package/.framework/mcp/tools/architect.ts +0 -431
  263. package/.framework/mcp/tools/cil/context.ts +0 -345
  264. package/.framework/mcp/tools/cil/graph.ts +0 -242
  265. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  266. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  267. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  268. package/.framework/mcp/tools/cil/project.ts +0 -791
  269. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  270. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  271. package/.framework/mcp/tools/cil/search.ts +0 -97
  272. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  273. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  274. package/.framework/mcp/tools/kb/delete.ts +0 -139
  275. package/.framework/mcp/tools/kb/index.ts +0 -52
  276. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  277. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  278. package/.framework/mcp/tools/kb/publish.ts +0 -100
  279. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  280. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  281. package/.framework/mcp/tools/kb/search.ts +0 -101
  282. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  283. package/.framework/mcp/tools/observability.ts +0 -510
@@ -0,0 +1,106 @@
1
+ ---
2
+ title: Orientation — what Spine Framework is
3
+ audience: developers, agents
4
+ kind: guide
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-29
7
+ source_files:
8
+ - package.json
9
+ - netlify.toml
10
+ - .env.example
11
+ - .framework/cli/commands/init.ts
12
+ - .framework/templates/project.json
13
+ - .framework/src/components/admin/PageInstructions.tsx
14
+ - .framework/src/instructions/README.md
15
+ ---
16
+
17
+ # Orientation
18
+
19
+ Spine Framework is a multi-tenant application platform you install into an npm
20
+ project. It gives you the "boring 80%" of a SaaS product — the infrastructure
21
+ every app needs and nobody wants to rebuild — so your code can be the
22
+ interesting 20%.
23
+
24
+ ## What you get out of the box
25
+
26
+ - **A typed runtime data layer.** Accounts, people, and typed records (items,
27
+ threads, messages, links, attachments, watchers) stored in Supabase Postgres,
28
+ all reachable through one CRUD/permissions API (`.framework/functions/admin-data.ts`).
29
+ - **Auth and tenancy.** Supabase Auth for sign-in, an invite/registration
30
+ pipeline (`.framework/functions/invites.ts`), hierarchical accounts, and a
31
+ first-user bootstrap that seeds a system administrator.
32
+ - **RBAC.** Roles plus per-type `record_permissions` evaluated on every request
33
+ (`.framework/functions/_shared/permissions.ts`).
34
+ - **Automation.** Declarative pipelines, event triggers, timers, integrations,
35
+ and AI agents — all database rows, all driven by the same runtime
36
+ (`.framework/functions/_shared/pipeline-runner.ts`,
37
+ `.framework/functions/_shared/trigger-engine.ts`).
38
+ - **An admin UI.** A schema-driven admin surface at `/spine-framework/admin`
39
+ built from `.framework/src/apps/admin/index.tsx`, plus generic list/detail
40
+ pages that render directly from each type's views.
41
+ - **Operations.** API keys for machine principals, delivery tracking, logs,
42
+ metrics, and pipeline execution history.
43
+
44
+ The stack is deliberately conventional: a React + Vite frontend, Netlify
45
+ Functions as the API layer, and Supabase (Postgres + Auth) as the database.
46
+ `netlify.toml` points functions at `.assembled/netlify/functions` and publishes
47
+ `dist`; `.env.example` lists the Supabase keys the app needs.
48
+
49
+ ## What `npm install spine-framework` + `npx spine-framework init` gave you
50
+
51
+ `init` copies a framework-owned file set — declared in
52
+ `.framework/templates/project.json` — into your project: the `.framework/`
53
+ tree (frontend source, Netlify functions, migrations, CLI, seeds, schemas),
54
+ `config/` build files, root `scripts/`, `bin/`, a neutral `spine.config.json`,
55
+ a merged `package.json`, `netlify.toml`, `.gitignore`, and a frozen
56
+ `.spine-manifest.json` recording the hash of every protected file. It also
57
+ creates an empty `custom/` workspace — the one place your code lives.
58
+
59
+ Two consequences follow:
60
+
61
+ 1. **`.framework/` (plus `config/` and `scripts/`) is sealed.** Every file is
62
+ hashed into `.spine-manifest.json`; `npx spine-framework upgrade` refuses to
63
+ overwrite a locally modified tree unless you pass `--force`.
64
+ 2. **`custom/` is yours.** Apps, functions, components, and migrations you
65
+ write go there; the framework never touches it.
66
+
67
+ See [02-project-map.md](./02-project-map.md) for the full anatomy.
68
+
69
+ ## How this instruction book is organized
70
+
71
+ This book ships inside the package at `.framework/src/instructions/` and is
72
+ also rendered inside the admin UI — admin pages mount a
73
+ `PageInstructions` sheet that loads these files as raw markdown and renders
74
+ them with `react-markdown` + `remark-gfm`
75
+ (`.framework/src/components/admin/PageInstructions.tsx`). Diagrams are plain
76
+ ASCII; the renderer does not load mermaid.
77
+
78
+ | Section | Kind | Contents |
79
+ |---|---|---|
80
+ | `guide/` | guide | End-to-end walkthroughs — you are here. |
81
+ | `concepts/` | concept | Mental models (tenancy, permissions, schema). |
82
+ | `tasks/` | task | Single-goal procedures with verification steps. |
83
+ | `reference/` | reference | Exhaustive lookups (env vars, CLI, endpoints). |
84
+ | `operations/` | ui | Admin-UI surfaces and operational runbooks. |
85
+ | `internal/` | mixed | Repo-only notes; exempt from shipped-doc rules. |
86
+ | book root | entity | One file per Spine entity — [types](../types.md), [apps](../apps.md), [roles](../roles.md), [pipelines](../pipelines.md), [triggers](../triggers.md), [timers](../timers.md), [integrations](../integrations.md), [ai-agents](../ai-agents.md), [prompts](../prompts.md), [api-keys](../api-keys.md), [deliveries](../deliveries.md). |
87
+
88
+ Entity files all use the same seven sections — *What this is for → Fields and
89
+ settings → Minimal configuration → Full configuration → Example → Core files →
90
+ Agent notes* — so once you have read one, you know the shape of all of them.
91
+
92
+ ## How to read it
93
+
94
+ - **Developers:** read this guide section in order
95
+ ([install](./01-install-and-first-run.md) →
96
+ [project map](./02-project-map.md) →
97
+ [domain model](./03-domain-model.md) →
98
+ [first app](./04-first-app.md)), then the entity file for whatever you are
99
+ building, then `reference/` for exact spellings.
100
+ - **Agents:** [03-domain-model.md](./03-domain-model.md) gives you the
101
+ primitives and how they compose; each entity file's *Agent notes* section
102
+ lists the mistakes that actually break things; [05-glossary.md](./05-glossary.md)
103
+ pins down terminology.
104
+ - Every page is verified against the code at the `verified_against` commit in
105
+ its frontmatter. Where the docs disagree with code, code wins — treat that as
106
+ a bug and check `Core files` on the relevant entity page.
@@ -0,0 +1,253 @@
1
+ ---
2
+ title: Install and first run
3
+ audience: developers, agents
4
+ kind: guide
5
+ verified_against: d0c49d4
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/cli/commands/init.ts
9
+ - .framework/cli/lib/project-files.ts
10
+ - .framework/templates/project.json
11
+ - .framework/templates/spine.config.neutral.json
12
+ - .framework/cli/commands/migrate.ts
13
+ - .framework/cli/commands/bootstrap.ts
14
+ - .env.example
15
+ - netlify.toml
16
+ - scripts/dev-netlify.sh
17
+ - scripts/netlify-dev-wrapper.sh
18
+ - config/vite.config.ts
19
+ - .framework/public/_redirects
20
+ - .framework/src/App.tsx
21
+ - .framework/src/pages/SetupPage.tsx
22
+ - .framework/src/pages/auth/RegisterPage.tsx
23
+ - .framework/functions/invites.ts
24
+ - .framework/migrations/052_registration_security.sql
25
+ ---
26
+
27
+ # Install and first run
28
+
29
+ Prerequisites: Node ≥ 22.13 and npm ≥ 10 (recorded in `.spine-manifest.json`
30
+ by init), a Supabase project, and (for local dev) the Netlify CLI — pinned as a
31
+ devDependency, so `npm install` puts it in `node_modules`.
32
+
33
+ ## Step 1 — scaffold
34
+
35
+ ```bash
36
+ npm install spine-framework
37
+ npx spine-framework init # or: init <dir>
38
+ ```
39
+
40
+ Tarball/pre-release installs work the same way: `npm i
41
+ ./spine-framework-<ver>.tgz` — `init` keeps the `file:` spec in
42
+ `package.json` rather than overwriting it with a registry version.
43
+
44
+ `init` (`.framework/cli/commands/init.ts`) copies the framework-owned file set
45
+ declared by `.framework/templates/project.json` into the target directory:
46
+
47
+ - **`.framework/`** — `cli`, `functions`, `migrations`, `public`, `schemas`,
48
+ `scripts`, `seeds`, `src`, `tests`, `docs`, `templates`, plus `index.html`
49
+ and `README.md`.
50
+ - **`config/`** — `vite.config.ts`, the tsconfig family, `tailwind.config.cjs`,
51
+ `postcss.config.cjs`, `components.json`.
52
+ - **Root files** — the shipped `scripts/*.sh` / `*.mts` / `verify-install.ts`
53
+ set, `bin/`, `vitest.config.ts`, `.env.example`, `LICENSE.md`.
54
+ - **`custom/`** — the empty workspace `init` creates for your code:
55
+ `custom/apps`, `custom/functions`, `custom/components`,
56
+ `custom/migrations`, `custom/tests`.
57
+ - **Generated files** — `package.json` (your name, framework scripts, the
58
+ framework's dependency set inlined, plus an exact `spine-framework` pin),
59
+ `package-lock.json` (when the package ships the verified lock template),
60
+ `.gitignore`, `netlify.toml`, a neutral `spine.config.json`, and the frozen
61
+ `.spine-manifest.json` integrity manifest.
62
+ - **Agent assets** — `AGENTS.md` (the framework-owned rules block between the
63
+ `spine-framework:begin/end` markers — refreshed on upgrade; keep your own
64
+ notes outside the markers) and `.devin/skills/spine-*/` task skills, synced
65
+ from `.framework/templates/agent/`. These are hashed into the manifest's
66
+ `agent_files` map rather than `files`.
67
+
68
+ `init` is deliberately file-only: it does **not** run `npm install`, write
69
+ `.env`, or touch any database or network resource. It refuses to run into a
70
+ directory that already has `.framework/` — that is what
71
+ `npx spine-framework upgrade` is for.
72
+
73
+ ## Step 2 — `.env`
74
+
75
+ ```bash
76
+ cp .env.example .env
77
+ ```
78
+
79
+ Required for a working install (`.env.example` has the full list):
80
+
81
+ | Variable | Used by |
82
+ |---|---|
83
+ | `VITE_SUPABASE_URL`, `VITE_SUPABASE_ANON_KEY` | the browser app (`.framework/src/lib/supabase.ts`) |
84
+ | `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `SUPABASE_ANON_KEY` | Netlify functions (service-role + user-scoped clients) |
85
+ | `SUPABASE_DB_PASSWORD` | `npx spine-framework migrate` — connects directly to `db.<project-ref>.supabase.co:5432` as `postgres` (`.framework/cli/commands/migrate.ts`) |
86
+ | `APP_BASE_URL` | invite links and auth redirects (`http://localhost:8888` in dev) |
87
+
88
+ Where to find them: the URL and both keys are on one page — **Supabase
89
+ Dashboard → Project Settings → API Keys** (older dashboards: Settings →
90
+ API / Data API); `SUPABASE_DB_PASSWORD` is under **Project Settings →
91
+ Database**. Current dashboards issue new-style keys: the **Publishable
92
+ key** (`sb_publishable_…`) is the anon key and a **Secret key**
93
+ (`sb_secret_…`) is the service-role key — set `*_ANON_KEY` /
94
+ `SUPABASE_SERVICE_ROLE_KEY` to them directly. Legacy `anon`/`service_role`
95
+ JWTs work identically (verified end-to-end on a hosted project:
96
+ `signInWithPassword`, `auth.admin.createUser`, and PostgREST all accept the
97
+ new formats).
98
+
99
+ Optional but worth knowing early: `RESEND_API_KEY` (invite/notification
100
+ email), `OPENAI_API_KEY` (AI stage types), `VITE_TURNSTILE_SITE_KEY` (bot
101
+ protection on auth pages), `SCHEDULER_API_KEY` (system-cron HTTP guard), and
102
+ `INTERNAL_INVOKE_SECRET` — **required for trigger-dispatched pipelines**: if it
103
+ is unset, triggers write a `queued` execution row but the pipeline runner is
104
+ never invoked (`.framework/functions/_shared/trigger-engine.ts`).
105
+
106
+ ## Step 3 — install deps and verify
107
+
108
+ ```bash
109
+ npm install
110
+ npm run verify # scripts/verify-integrity.sh — checks the tree against .spine-manifest.json
111
+ ```
112
+
113
+ Expect `npm audit` findings — the pinned dependency set (mostly the
114
+ `netlify-cli` devDependency tree) carries known advisories, and the count
115
+ jumps between the tarball-only install and the full post-init install. The
116
+ shipped `package-lock.json` template is the verified set: do **not** run
117
+ `npm audit fix`, which moves pinned versions the manifest was generated
118
+ against. Findings are tracked upstream, not per-project.
119
+
120
+ ## Step 4 — migrate the database
121
+
122
+ ```bash
123
+ npx spine-framework migrate
124
+ ```
125
+
126
+ This applies every `.framework/migrations/*.sql` file (and anything in
127
+ `custom/migrations/`, unless `--framework-only`) in order, recording each in a
128
+ `_spine_migrations` table so reruns are idempotent (`--dry-run` shows pending
129
+ files without applying them). File numbering is non-contiguous — retired
130
+ migrations are removed from the package rather than renumbered, so gaps are
131
+ expected and only lexical order matters. The core migration seeds the `system_admin`
132
+ role, the `spine-core` and `admin` apps, the `spine-system` account, and the
133
+ core runtime types (`.framework/migrations/003_core_system_data.sql`,
134
+ `.framework/migrations/011_spine_system_account.sql`).
135
+
136
+ ## Step 5 — run it
137
+
138
+ ```bash
139
+ npm run dev:netlify
140
+ ```
141
+
142
+ `dev:netlify` runs `npm run assemble` first (via `predev:netlify`) and then
143
+ `scripts/dev-netlify.sh`, which cleans stale processes and launches the pinned
144
+ `netlify dev`. Netlify serves the site on **http://localhost:8888** and starts
145
+ the Vite dev server on 3001 via `scripts/netlify-dev-wrapper.sh`.
146
+ **Wait for the "Local dev server ready" banner** — the first `dev:netlify`
147
+ run bundles ~80 functions and can take a couple of minutes before the banner
148
+ appears; this is normal, not a hang. Early requests during function bundling
149
+ can crash the dev server (noted in `scripts/dev-netlify.sh`).
150
+
151
+ Ports are **fixed**: `netlify dev` must bind 8888 and Vite 3001 — both are
152
+ set in manifest-protected files (`netlify.toml` `[dev]` port/targetPort,
153
+ `config/vite.config.ts`), and there is no supported alternate-port
154
+ configuration. Moving only one side breaks the `/api` proxy and can
155
+ silently cross-connect two Spine projects on the same machine. Check the
156
+ ports are free first (`lsof -i :8888 -i :3001`): `dev-netlify.sh` cleans up
157
+ stale processes it owns but will not kill an unrelated server holding the
158
+ port — a second Spine project's dev stack is the usual culprit; stop that
159
+ one yourself.
160
+
161
+ Ignore `Failed to fetch AI Gateway token … Unauthorized` in `netlify dev`
162
+ output — that is the Netlify CLI's own AI feature probing your Netlify
163
+ account, unrelated to Spine.
164
+
165
+ Two URL spaces matter:
166
+
167
+ - `/api/*` → `/.netlify/functions/:splat`. In dev this is the Vite proxy to
168
+ `localhost:8888` (`config/vite.config.ts`); in production it is the
169
+ `_redirects` rule in `.framework/public/_redirects`.
170
+ - Everything else → the React SPA.
171
+
172
+ `npm run dev` alone starts *only* Vite on 3001 — fine for frontend work, but
173
+ `/api/*` calls still proxy to 8888, so functions need `netlify dev` running.
174
+
175
+ ## First admin — browser-free bootstrap (recommended for automation)
176
+
177
+ ```bash
178
+ npx spine-framework bootstrap --email you@example.com --password '<pick-one>'
179
+ ```
180
+
181
+ This is the scriptable path (`S-002`): it creates the first `system_admin`
182
+ person bound to the `spine-system` account — the same row shape the
183
+ `handle_new_auth_user` trigger writes on registration — creates a confirmed
184
+ auth user through `auth.admin.createUser(email_confirm: true)`, and mints a
185
+ `sk_` API key, all without a browser. The raw key is printed **once**; only
186
+ its PBKDF2 hash is stored. `--scope <scope>` (repeatable) narrows the key —
187
+ the default `*:*` resolves to the `system_admin` role on the machine
188
+ principal. Omit `--email`/`--password` and the person record is created
189
+ DB-only (no UI login; the minted key still works for `x-api-key` callers).
190
+ The command is idempotent: when a `system_admin` already exists in
191
+ `spine-system` it skips person creation and just mints another key
192
+ (`.framework/cli/commands/bootstrap.ts`).
193
+
194
+ ## First login — what actually happens
195
+
196
+ Alternatively, register in the browser. The real flow, as the code
197
+ implements it:
198
+
199
+ 1. An unauthenticated visitor is redirected to `/login`
200
+ (`.framework/src/App.tsx`). If `VITE_SETUP_MODE=true` is set, the `/` route
201
+ instead shows a static `SetupPage` listing the same steps as this page
202
+ (`.framework/src/pages/SetupPage.tsx`).
203
+ 2. Go to `/register` and create an account. **The first user to register gets
204
+ `system_admin`**: the `handle_new_auth_user` database trigger detects an
205
+ empty `people` table and binds the new person to the `spine-system` account
206
+ with the `system_admin` role
207
+ (`.framework/migrations/052_registration_security.sql`). If the seeds are
208
+ missing, registration raises instead of creating a rootless user.
209
+ 3. Non-first, non-invited signups get **no account and no role** — placement
210
+ happens when `complete-registration` runs the server-side RPC
211
+ (`.framework/functions/invites.ts`). An authenticated user without an
212
+ account is routed to `/register?resume=1` until placement finishes, never
213
+ to a 404 (`.framework/src/App.tsx`).
214
+ 4. After login, a `system_admin` lands on `/spine-framework/admin` — the
215
+ schema-driven admin app from `.framework/src/apps/admin/index.tsx`. Other
216
+ users land on the first app their role can see, or `NoAppPage` when nothing
217
+ is routable.
218
+
219
+ ## Giving your agent access
220
+
221
+ The verified path for letting an agent (or any machine caller) reach the
222
+ runtime API:
223
+
224
+ 1. **Bootstrap an admin + key** — one step, no browser: `npx
225
+ spine-framework bootstrap` (see "First admin" above) both creates the
226
+ `system_admin` and prints a `sk_` key. The browser alternative: register
227
+ at `/register` (first user becomes `system_admin`), then create a scoped
228
+ key under **Admin → Configs → API Keys**. Either way the raw key is shown
229
+ **once** — copy it immediately (`.framework/functions/api-keys.ts`).
230
+ 2. **Give the key to the agent** as the environment variable `SPINE_API_KEY`.
231
+ Agents send `x-api-key: sk_…` on `/api/*` requests; the header resolves to
232
+ a machine principal carrying the key's scopes and account binding
233
+ (`.framework/functions/_shared/principal.ts`). Turnstile is not in this
234
+ path — bot protection only guards the human auth pages.
235
+
236
+ **Caveat:** for the browser path, Supabase **email confirmation must be
237
+ off** in the project (Auth → Providers), or the first registrant cannot sign
238
+ in without access to a real inbox. `bootstrap` is unaffected — it creates
239
+ the auth user with `email_confirm: true` through the service role.
240
+
241
+ ## Gaps
242
+
243
+ - **`npx spine-framework dev` runs the same flow as the package scripts** —
244
+ `scripts/assemble.sh`, then Vite via `config/vite.config.ts` (`--netlify`
245
+ for the full `netlify dev` stack on :8888). `npm run dev` /
246
+ `npm run dev:netlify` remain the canonical entry points.
247
+ - **`bootstrap` covers first-run provisioning only.** Subsequent admins are
248
+ added through the invite flow in the admin app (or another `bootstrap`
249
+ run, which skips person creation and only mints a new key).
250
+ - **Timers only tick under the Netlify scheduler.** `trigger-scheduler` is a
251
+ scheduled function (`* * * * *` in `netlify.toml`); pipelines triggered by
252
+ timers do not run without it, and trigger dispatch additionally needs
253
+ `INTERNAL_INVOKE_SECRET` (see Step 2).
@@ -0,0 +1,147 @@
1
+ ---
2
+ title: Anatomy of an installed project
3
+ audience: developers, agents
4
+ kind: guide
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-29
7
+ source_files:
8
+ - .framework/templates/project.json
9
+ - .framework/cli/commands/init.ts
10
+ - .framework/cli/commands/upgrade.ts
11
+ - .framework/cli/lib/project-files.ts
12
+ - scripts/checksum-manifest.mts
13
+ - scripts/verify-integrity.sh
14
+ - scripts/assemble.sh
15
+ - scripts/assemble-frontend.sh
16
+ - scripts/assemble-functions.sh
17
+ - config/vite.config.ts
18
+ - netlify.toml
19
+ - .framework/cli/commands/create-app.ts
20
+ - .framework/cli/commands/install-app.ts
21
+ - .framework/src/components/CustomAppLoader.tsx
22
+ - .framework/schemas/spine.config.schema.json
23
+ ---
24
+
25
+ # Anatomy of an installed project
26
+
27
+ A Spine project is two concentric layers: a **sealed framework layer** the
28
+ package owns and overwrites on upgrade, and a **customer layer** the framework
29
+ never writes to.
30
+
31
+ ```
32
+ my-project/
33
+ ├─ .framework/ # SEALED — framework source, vendored by init/upgrade
34
+ │ ├─ cli/ # the spine-framework CLI source
35
+ │ ├─ functions/ # Netlify functions (the whole API surface)
36
+ │ ├─ migrations/ # SQL migrations applied by `migrate`
37
+ │ ├─ public/ # static assets + _redirects
38
+ │ ├─ schemas/ # spine.config.schema.json
39
+ │ ├─ scripts/ seeds/ docs/ templates/
40
+ │ ├─ src/ # React frontend + admin app + this book
41
+ │ └─ tests/
42
+ ├─ config/ # SEALED — build config (vite, tsconfig, tailwind…)
43
+ ├─ scripts/ # SEALED — assemble/verify/dev shell scripts
44
+ ├─ bin/ # SEALED — spine-framework bin shims
45
+ ├─ custom/ # YOURS — apps, functions, components, migrations, tests
46
+ ├─ .assembled/ # GENERATED — build output, never edit
47
+ ├─ .spine-manifest.json # GENERATED — frozen integrity manifest
48
+ ├─ spine.config.json # YOURS — branding + registration policy
49
+ ├─ netlify.toml # mixed — framework blocks + your custom_* sections
50
+ ├─ package.json # merged — framework scripts/deps + your own
51
+ └─ .env # YOURS — secrets; never written by the framework
52
+ ```
53
+
54
+ ## The sealed layer
55
+
56
+ The file set is declared in `.framework/templates/project.json`
57
+ (`framework_dirs`, `framework_files`, `config_files`, `root_scripts`, `bin`)
58
+ and every protected file's sha256 is recorded in `.spine-manifest.json` — the
59
+ protected trees are `.framework`, `config`, `scripts`, and `bin`
60
+ (`scripts/checksum-manifest.mts`, `PROTECTED_DIRS`).
61
+
62
+ - `npm run verify` (`scripts/verify-integrity.sh` → `scripts/verify-manifest.mts`)
63
+ re-hashes the tree and fails on drift. `SPINE_INTEGRITY=warn` downgrades to
64
+ warnings.
65
+ - `npx spine-framework upgrade` re-syncs the sealed layer to the
66
+ `spine-framework` version installed in `node_modules`
67
+ (`.framework/cli/commands/upgrade.ts`). It first verifies the tree against
68
+ the manifest and **aborts on any locally modified or missing protected file**
69
+ unless `--force` is passed — so do not edit `.framework/`, `config/`,
70
+ `scripts/`, or `bin/`; changes there are destroyed on the next upgrade
71
+ anyway.
72
+ - Deletions on upgrade are confined to `.framework/`; sealed files dropped
73
+ upstream outside it are left in place with a warning.
74
+
75
+ ## `custom/` — your code
76
+
77
+ `init` creates `custom/apps`, `custom/functions`, `custom/components`,
78
+ `custom/migrations`, and `custom/tests` (`.framework/cli/commands/init.ts`).
79
+ Everything in it is yours: not integrity-tracked, never touched by upgrade.
80
+
81
+ - **Custom apps** live at `custom/apps/<slug>/`.
82
+ `npx spine-framework create-app <slug>` scaffolds `manifest.json`,
83
+ `index.tsx`, and `components/`, then inserts the `apps` row with
84
+ `renderer: 'custom'` (`.framework/cli/commands/create-app.ts`).
85
+ `CustomAppLoader` resolves the UI via
86
+ `import.meta.glob('../../../custom/apps/*/index.tsx')`
87
+ (`.framework/src/components/CustomAppLoader.tsx`), and the Vite alias
88
+ `@custom` points at `custom/apps` (`config/vite.config.ts`).
89
+ - **Custom functions** live at `custom/functions/` or inside an app at
90
+ `custom/apps/<slug>/functions/`; assembly merges them into the flat
91
+ functions directory and hard-fails on basename collisions with framework
92
+ functions (`scripts/assemble-functions.sh`). Name yours `custom_*`.
93
+ - **Custom migrations** in `custom/migrations/` run with
94
+ `npx spine-framework migrate` (skip them with `--framework-only`).
95
+ - **Packaged apps** installed via `npx spine-framework install-app <pkg>` also
96
+ land under `custom/apps/<slug>/`; their `manifest.json` can seed types,
97
+ roles, pipelines, and registration policy into the database
98
+ (`.framework/cli/commands/install-app.ts`).
99
+
100
+ ## `.assembled/` — build output
101
+
102
+ `npm run assemble` (`scripts/assemble.sh`) produces `.assembled/` fresh on
103
+ every dev start and build:
104
+
105
+ - `.assembled/src` — the framework frontend plus each `custom/apps/<slug>/`
106
+ copied verbatim (never basename-flattened), plus the fixed-up `index.html`
107
+ (`scripts/assemble-frontend.sh`). Vite builds and serves from here.
108
+ - `.assembled/netlify/functions` — framework + custom functions flattened into
109
+ the single directory Netlify requires (`netlify.toml`
110
+ `functions.directory`); duplicate basenames are a hard error, not a
111
+ last-wins overwrite (`scripts/assemble-functions.sh`).
112
+
113
+ Never edit `.assembled/` — it is regenerated and deleted freely.
114
+
115
+ ## `.spine-manifest.json` — the integrity contract
116
+
117
+ Written by `init` and regenerated by `upgrade`
118
+ (`.framework/cli/lib/project-files.ts` → `writeFrozenManifest`): the package
119
+ version (`framework_version`), the framework-owned dependency list, a tree
120
+ digest, and a sha256 per protected file. It is the input to `npm run verify`
121
+ and to upgrade's local-modification check.
122
+
123
+ ## `spine.config.json` — project runtime config
124
+
125
+ Customer-owned; `init` seeds the neutral template
126
+ (`.framework/templates/spine.config.neutral.json`) and
127
+ `install-app`/`update-db-app` merge per-app registration policy into it
128
+ (`.framework/cli/commands/install-app.ts`). It carries `branding` and the
129
+ `registration` block that drives signup routing/role assignment — schema at
130
+ `.framework/schemas/spine.config.schema.json`. Upgrade never writes it.
131
+
132
+ ## `netlify.toml` and `package.json` — mixed ownership
133
+
134
+ - `netlify.toml`: framework blocks are rewritten on upgrade, but
135
+ `[functions."custom_*"]` sections are treated as app-owned and preserved
136
+ verbatim (`.framework/cli/lib/project-files.ts` → `splitNetlifyToml` /
137
+ `renderNetlifyToml`). Scheduled custom functions belong there.
138
+ - `package.json`: framework-owned scripts and dependencies are merged in and
139
+ `spine-framework` pinned exactly; your own scripts and deps are preserved.
140
+ Upgrade removes a dependency only if the previous framework version owned it
141
+ and the new one does not.
142
+
143
+ ## `.env` — yours, always
144
+
145
+ No framework command writes `.env`; it is gitignored and excluded from the
146
+ file set (`.framework/templates/project.json` `exclude_globs`). `.env.example`
147
+ ships as the documented baseline.