spine-framework 0.4.3 → 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 (320) 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/agent-runner.ts +1000 -81
  15. package/.framework/functions/_shared/cil.ts +2 -1
  16. package/.framework/functions/_shared/db.ts +3 -6
  17. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  18. package/.framework/functions/_shared/kb.ts +61 -7
  19. package/.framework/functions/_shared/logging.ts +562 -224
  20. package/.framework/functions/_shared/message-sequence.ts +53 -0
  21. package/.framework/functions/_shared/middleware.ts +47 -44
  22. package/.framework/functions/_shared/pipeline-runner.ts +150 -37
  23. package/.framework/functions/_shared/principal.ts +9 -6
  24. package/.framework/functions/_shared/trigger-engine.ts +149 -40
  25. package/.framework/functions/admin-data.ts +48 -31
  26. package/.framework/functions/ai-agents.ts +103 -33
  27. package/.framework/functions/api-keys.ts +301 -122
  28. package/.framework/functions/apps.ts +43 -26
  29. package/.framework/functions/cil-ingest.ts +48 -15
  30. package/.framework/functions/debug-auth.ts +14 -8
  31. package/.framework/functions/deliveries.ts +39 -12
  32. package/.framework/functions/embeddings.ts +145 -76
  33. package/.framework/functions/integration-outbound.ts +67 -27
  34. package/.framework/functions/integrations.ts +254 -127
  35. package/.framework/functions/logs.ts +273 -133
  36. package/.framework/functions/observability.ts +277 -147
  37. package/.framework/functions/pipeline-executions.ts +1 -1
  38. package/.framework/functions/pipeline-runner-background.ts +120 -0
  39. package/.framework/functions/pipelines.ts +14 -9
  40. package/.framework/functions/prompt-configs.ts +7 -4
  41. package/.framework/functions/roles.ts +8 -5
  42. package/.framework/functions/security.ts +30 -17
  43. package/.framework/functions/system-cron.ts +250 -128
  44. package/.framework/functions/tests.ts +7 -6
  45. package/.framework/functions/timers.ts +310 -107
  46. package/.framework/functions/trigger-scheduler.ts +65 -5
  47. package/.framework/functions/triggers.ts +28 -13
  48. package/.framework/functions/types.ts +13 -10
  49. package/.framework/migrations/064_episode_leases.sql +196 -0
  50. package/.framework/migrations/065_execution_tables_updated_at.sql +20 -0
  51. package/.framework/migrations/066_episode_steal_thread_merge.sql +148 -0
  52. package/.framework/migrations/067_episode_lease_stale_steal.sql +93 -0
  53. package/.framework/migrations/068_cron_schedule_timer_rpcs.sql +251 -0
  54. package/.framework/migrations/069_log_stats_window.sql +54 -0
  55. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  56. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  57. package/.framework/migrations/072_slug_autofill.sql +77 -0
  58. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  59. package/.framework/schemas/spine.config.schema.json +62 -0
  60. package/.framework/src/App.tsx +3 -1
  61. package/.framework/src/apps/admin/index.tsx +1141 -775
  62. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  63. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  64. package/.framework/src/components/admin/AdminSidebar.tsx +92 -81
  65. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  66. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  67. package/.framework/src/components/app-shell/GenericAppShell.tsx +3 -1
  68. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  69. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  70. package/.framework/src/components/auth/TurnstileWidget.tsx +9 -6
  71. package/.framework/src/components/kb/KBArticleEditor.tsx +49 -6
  72. package/.framework/src/components/layout/Layout.tsx +4 -2
  73. package/.framework/src/components/layout/Sidebar.tsx +304 -179
  74. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  75. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  76. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  77. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  78. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  79. package/.framework/src/components/ui/sheet.tsx +24 -26
  80. package/.framework/src/components/ui/textarea.tsx +74 -48
  81. package/.framework/src/hooks/useBranding.ts +47 -0
  82. package/.framework/src/hooks/useEntityList.ts +12 -9
  83. package/.framework/src/hooks/useListSchema.ts +108 -58
  84. package/.framework/src/instructions/README.md +57 -0
  85. package/.framework/src/instructions/ai-agents.md +69 -0
  86. package/.framework/src/instructions/alerts.md +80 -0
  87. package/.framework/src/instructions/api-keys.md +87 -0
  88. package/.framework/src/instructions/apps.md +77 -0
  89. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  90. package/.framework/src/instructions/concepts/apps-and-renderers.md +162 -0
  91. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  92. package/.framework/src/instructions/concepts/automation.md +186 -0
  93. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  94. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  95. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  96. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  97. package/.framework/src/instructions/concepts/observability.md +116 -0
  98. package/.framework/src/instructions/concepts/permissions.md +150 -0
  99. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  100. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  101. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  102. package/.framework/src/instructions/deliveries.md +59 -0
  103. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  104. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  105. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  106. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  107. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  108. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  109. package/.framework/src/instructions/integrations.md +96 -0
  110. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  111. package/.framework/src/instructions/invites.md +60 -0
  112. package/.framework/src/instructions/kb.md +80 -0
  113. package/.framework/src/instructions/logs.md +77 -0
  114. package/.framework/src/instructions/observability.md +61 -0
  115. package/.framework/src/instructions/operations/deployment.md +115 -0
  116. package/.framework/src/instructions/operations/migrations.md +125 -0
  117. package/.framework/src/instructions/operations/security-checklist.md +148 -0
  118. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  119. package/.framework/src/instructions/operations/upgrade.md +116 -0
  120. package/.framework/src/instructions/pipeline-executions.md +62 -0
  121. package/.framework/src/instructions/pipelines.md +78 -0
  122. package/.framework/src/instructions/prompts.md +95 -0
  123. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  124. package/.framework/src/instructions/reference/api/auth.md +113 -0
  125. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  126. package/.framework/src/instructions/reference/app-manifest.md +150 -0
  127. package/.framework/src/instructions/reference/cli.md +124 -0
  128. package/.framework/src/instructions/reference/database.md +132 -0
  129. package/.framework/src/instructions/reference/design-schema.md +280 -0
  130. package/.framework/src/instructions/reference/env-vars.md +133 -0
  131. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  132. package/.framework/src/instructions/reference/functions/admin-data.md +195 -0
  133. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  134. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  135. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  136. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  137. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  138. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  139. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  140. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  141. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  142. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  143. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  144. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  145. package/.framework/src/instructions/reference/functions/index.md +103 -0
  146. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  147. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  148. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  149. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  150. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  151. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  152. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  153. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  154. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  155. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  156. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  157. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  158. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  159. package/.framework/src/instructions/reference/functions/security.md +140 -0
  160. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  161. package/.framework/src/instructions/reference/functions/system.md +106 -0
  162. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  163. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  164. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  165. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  166. package/.framework/src/instructions/reference/functions/types.md +146 -0
  167. package/.framework/src/instructions/reference/seeds.md +126 -0
  168. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  169. package/.framework/src/instructions/reference/spine-config.md +114 -0
  170. package/.framework/src/instructions/roles.md +80 -0
  171. package/.framework/src/instructions/runtime-detail.md +70 -0
  172. package/.framework/src/instructions/runtime-list.md +77 -0
  173. package/.framework/src/instructions/security.md +67 -0
  174. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  175. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  176. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  177. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  178. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  179. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  180. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  181. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  182. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  183. package/.framework/src/instructions/tasks/package-and-install-an-app.md +127 -0
  184. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  185. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  186. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  187. package/.framework/src/instructions/testing.md +59 -0
  188. package/.framework/src/instructions/timers.md +82 -0
  189. package/.framework/src/instructions/triggers.md +69 -0
  190. package/.framework/src/instructions/types.md +93 -0
  191. package/.framework/src/lib/branding.ts +128 -0
  192. package/.framework/src/pages/NoAppPage.tsx +3 -1
  193. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  194. package/.framework/src/pages/SetupPage.tsx +5 -2
  195. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  196. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  197. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  198. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  199. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  200. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  201. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  202. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  203. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  204. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  205. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  206. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  207. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  208. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  209. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  210. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  211. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  212. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  213. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  214. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  215. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  216. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  217. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  218. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  219. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  220. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  221. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  222. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  223. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  224. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  225. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  226. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  227. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  228. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  229. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  230. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  231. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  232. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  233. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  234. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  235. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  236. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  237. package/.framework/src/pages/auth/AuthConfirmPage.tsx +3 -1
  238. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +3 -1
  239. package/.framework/src/pages/auth/LoginPage.tsx +4 -2
  240. package/.framework/src/pages/auth/RegisterPage.tsx +3 -1
  241. package/.framework/templates/agent/AGENTS.md +150 -0
  242. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  243. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  244. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  245. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  246. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +72 -0
  247. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  248. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
  249. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
  250. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -0
  251. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  252. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  253. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  254. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  255. package/.framework/templates/project.json +5 -1
  256. package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
  257. package/.framework/tests/unit/agent-files.test.ts +355 -0
  258. package/.framework/tests/unit/agent-runner.test.ts +496 -47
  259. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  260. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  261. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  262. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  263. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  264. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  265. package/.framework/tests/unit/episode-lease.test.ts +695 -0
  266. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  267. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  268. package/.framework/tests/unit/kb-ingest-lease.test.ts +19 -0
  269. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  270. package/.framework/tests/unit/pipeline-runner-background.test.ts +120 -0
  271. package/.framework/tests/unit/pipeline-runner.test.ts +153 -1
  272. package/.framework/tests/unit/principal-cache.test.ts +15 -0
  273. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  274. package/.framework/tests/unit/system-cron.test.ts +240 -0
  275. package/.framework/tests/unit/timers.test.ts +159 -0
  276. package/.framework/tests/unit/trigger-engine.test.ts +278 -91
  277. package/.framework/tests/unit/trigger-scheduler.test.ts +78 -0
  278. package/README.md +125 -166
  279. package/config/tsconfig.cli.json +2 -2
  280. package/netlify.toml +5 -0
  281. package/package.json +15 -4
  282. package/templates/project/package-lock.json +2 -2
  283. package/.framework/docs/admin-routes.md +0 -76
  284. package/.framework/docs/api-docs-progress.md +0 -38
  285. package/.framework/docs/api-governance.md +0 -146
  286. package/.framework/docs/api-testing-results.md +0 -212
  287. package/.framework/docs/assembly-launch-guide.md +0 -138
  288. package/.framework/docs/audit-results.md +0 -590
  289. package/.framework/docs/db-api-inventory.md +0 -95
  290. package/.framework/docs/gap-remediation-backlog.md +0 -103
  291. package/.framework/docs/ui-adoption-verification.md +0 -111
  292. package/.framework/docs/ui-api-coverage.md +0 -84
  293. package/.framework/docs/v2-compatibility-audit.md +0 -228
  294. package/.framework/mcp/index.ts +0 -133
  295. package/.framework/mcp/load-env.ts +0 -60
  296. package/.framework/mcp/shared/app-manifest.ts +0 -275
  297. package/.framework/mcp/shared/db.ts +0 -477
  298. package/.framework/mcp/shared/kb.ts +0 -118
  299. package/.framework/mcp/tools/architect.ts +0 -431
  300. package/.framework/mcp/tools/cil/context.ts +0 -345
  301. package/.framework/mcp/tools/cil/graph.ts +0 -242
  302. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  303. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  304. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  305. package/.framework/mcp/tools/cil/project.ts +0 -791
  306. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  307. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  308. package/.framework/mcp/tools/cil/search.ts +0 -97
  309. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  310. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  311. package/.framework/mcp/tools/kb/delete.ts +0 -139
  312. package/.framework/mcp/tools/kb/index.ts +0 -52
  313. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  314. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  315. package/.framework/mcp/tools/kb/publish.ts +0 -100
  316. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  317. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  318. package/.framework/mcp/tools/kb/search.ts +0 -101
  319. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  320. package/.framework/mcp/tools/observability.ts +0 -510
@@ -0,0 +1,140 @@
1
+ ---
2
+ title: triggers
3
+ audience: both
4
+ kind: reference
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/functions/triggers.ts
9
+ - .framework/functions/_shared/middleware.ts
10
+ - .framework/functions/_shared/trigger-engine.ts
11
+ - .framework/migrations/020_schema_reconciliation.sql
12
+ - .framework/public/_redirects
13
+ ---
14
+
15
+ # triggers
16
+
17
+ ## What it does
18
+
19
+ CRUD plus `toggle`, `listByEvent`, and `getExecutions` over
20
+ `public.triggers` — the config rows that bind an `event_type` to a
21
+ `pipeline_id`. **This function never fires anything**: matching and
22
+ dispatch happen in `.framework/functions/_shared/trigger-engine.ts`
23
+ (`checkAndFireTriggers`/`fireCreateTriggers`/`fireUpdateTriggers`,
24
+ invoked by `admin-data` on record writes), which reserves a
25
+ `trigger_executions` row and POSTs the run to the
26
+ `pipeline-runner-background` function. See
27
+ [Automation](../../concepts/automation.md).
28
+
29
+ ## Route and methods
30
+
31
+ `/.netlify/functions/triggers`, reachable as `/api/triggers` (`/api/*` →
32
+ `/.netlify/functions/:splat`, `.framework/public/_redirects`). `?action=`
33
+ takes precedence; without it the dispatcher falls back to the HTTP method —
34
+ `GET` → `get` (with `id`) else `list`, `POST` → `create`, `PATCH` →
35
+ `update`, `DELETE` → `remove`:
36
+
37
+ | Call | Handler |
38
+ |---|---|
39
+ | `/api/triggers?action=list` | `list` |
40
+ | `/api/triggers?action=listByEvent&event_type=<e>` | `listByEvent` |
41
+ | `/api/triggers?action=get&id=<uuid>` | `get` |
42
+ | `/api/triggers?action=getExecutions&trigger_id=<uuid>` | `getExecutions` |
43
+ | `/api/triggers?action=create` | `create` |
44
+ | `/api/triggers?action=update` (`id` in body or query) | `update` |
45
+ | `/api/triggers?action=remove` (`id` in body or query) | `remove` |
46
+ | `/api/triggers?action=toggle` (`id` in body or query) | `toggle` |
47
+
48
+ A bare `GET /api/triggers` returns the active trigger list.
49
+
50
+ ## Authentication
51
+
52
+ Standard `createHandler` auth: `x-api-key` → machine principal,
53
+ `x-internal-secret` → internal principal, `Bearer <jwt>` → human;
54
+ anonymous → 401.
55
+
56
+ - `list`/`listByEvent`/`getExecutions`/`create` require `ctx.accountId`.
57
+ - `create` requires `system_admin` or a `canCreate` grant from
58
+ `resolveFirstSurfacePermissions(..., 'trigger', 'create')`.
59
+ - `update`/`remove`/`toggle` have no explicit gate — humans are bounded
60
+ by RLS on `ctx.db`; machines run service-role.
61
+ - Reads are sanitized: non-admins get `{ id }` per row (trigger rows
62
+ carry no `design_schema`).
63
+
64
+ ## Request contract
65
+
66
+ **list** (query): `app_id`, `event_type`, `include_inactive` (`'true'`
67
+ to include; default active only). Ordered by `name`.
68
+
69
+ **listByEvent** (query): `event_type` required; `app_id`,
70
+ `include_inactive` optional.
71
+
72
+ **get** (query): `id`. **getExecutions** (query): `trigger_id`
73
+ required; `limit` (default 50), `offset` — reads
74
+ `public.trigger_executions` ordered `executed_at` desc.
75
+
76
+ **create** (body): `name`, `event_type`, `pipeline_id` required.
77
+ Optional: `app_id`, `description`, `trigger_type` (defaults `'event'`),
78
+ `config` `{}`, `metadata` `{}`. `account_id`/`created_by` stamped —
79
+ `created_by` is `null` for machine principals. (`event_type`,
80
+ `trigger_type`, `pipeline_id` columns were added by
81
+ `.framework/migrations/020_schema_reconciliation.sql`.)
82
+
83
+ **update** (`id` in body or query + body): allowlist — `name`,
84
+ `description`, `config`, `pipeline_id`, `metadata`, `is_active`,
85
+ `event_type`, `trigger_type`, `app_id`.
86
+
87
+ **remove** (`id` in body or query): soft delete (`is_active = false`).
88
+
89
+ **toggle** (`id` in body or query): flips `is_active` — no target-state
90
+ argument.
91
+
92
+ ## Response contract
93
+
94
+ Standard `{ data, error, meta }` envelope.
95
+
96
+ - `list`/`listByEvent`/`get`/`create`/`update`/`toggle` → sanitized
97
+ row(s); `remove` → `{ success: true }`; `getExecutions` → raw
98
+ `trigger_executions` array (unsanitized).
99
+ - The file also exports `AGENT_EVENT_TYPES` — the `agent.*` event names
100
+ (`agent.inference.completed`, `agent.tool.called`,
101
+ `agent.message.received`, …) usable as `event_type` values — but
102
+ `event_type` is free-form text; any string is accepted.
103
+
104
+ ## Side effects
105
+
106
+ - `toggle`/`update`/`remove` stamp `updated_at`; `is_active` is what the
107
+ trigger engine filters on when matching events.
108
+ - `emitLog` writes `trigger.created` / `.updated` / `.deleted` /
109
+ `.toggled` audit rows to `public.logs`.
110
+ - Writing a trigger has no immediate run effect — the row is only read
111
+ the next time `admin-data` (or another caller of the trigger engine)
112
+ emits a matching event.
113
+
114
+ ## Errors
115
+
116
+ | Condition | HTTP | Message |
117
+ |---|---|---|
118
+ | No account context | 500 | `Account context required` |
119
+ | `listByEvent` without `event_type` | 500 | `event_type is required` |
120
+ | `getExecutions` without `trigger_id` | 500 | `trigger_id is required` |
121
+ | Missing create fields | 500 | `name, event_type, and pipeline_id are required` |
122
+ | Non-admin without create grant | 500 | `Insufficient permissions to create triggers` |
123
+ | Missing `id` | 500 | `Trigger ID is required` |
124
+ | Missing row | 500 | `Trigger not found` |
125
+ | Missing/unknown action | 500 | `Unsupported action: <action>` |
126
+
127
+ ## Agent notes
128
+
129
+ - Trigger→pipeline wiring is `pipeline_id` on the row; the engine reads
130
+ `config.entity_type`, `config.type_slug`, `config.filters`, and
131
+ `config.fire_on_transition` at match time — none of that is validated
132
+ by this endpoint, so a malformed `config` fails silently at match time
133
+ (the trigger simply never fires or always fires).
134
+ - `getExecutions` is read-only bookkeeping written by the trigger
135
+ engine's `record_trigger_fire` path — execution lifecycle (queued →
136
+ running → complete/failed) is covered by `pipeline-executions` and
137
+ `pipeline-runner-background`, not this function.
138
+ - `remove` is a soft delete; a deleted trigger stops matching on the
139
+ next event (the engine queries `is_active = true`).
140
+ - `toggle` flips blindly — read first if you need a target state.
@@ -0,0 +1,146 @@
1
+ ---
2
+ title: types
3
+ audience: both
4
+ kind: reference
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/functions/types.ts
9
+ - .framework/functions/_shared/middleware.ts
10
+ - .framework/functions/_shared/schema-utils.ts
11
+ - .framework/functions/_shared/permissions.ts
12
+ - .framework/migrations/015_types_kind_slug_unique.sql
13
+ - .framework/public/_redirects
14
+ ---
15
+
16
+ # types
17
+
18
+ ## What it does
19
+
20
+ CRUD over `public.types` — the type-definition registry whose
21
+ `design_schema`/`validation_schema` columns drive record validation,
22
+ permissions, and the generic UI (see
23
+ [Design Schema](../../concepts/design-schema.md)). Also resolves single
24
+ types by `slug` and exposes a schema-lookup RPC pass-through.
25
+
26
+ ## Route and methods
27
+
28
+ `/.netlify/functions/types`, reachable as `/api/types` (`/api/*` →
29
+ `/.netlify/functions/:splat`, `.framework/public/_redirects`). Dispatch is
30
+ by `?action=` plus the HTTP method (`?method=` can override the method):
31
+
32
+ | Call | Handler |
33
+ |---|---|
34
+ | `GET /api/types?action=schema&kind=<k>&slug=<s>[&app_id=<uuid>]` | `getSchema` → RPC `get_type_schema` |
35
+ | `GET /api/types?action=list` (or bare `GET` with no `id`/`slug`/`kind`) | `list` |
36
+ | `GET /api/types?slug=<s>` | `getBySlug` (active rows only, joins `apps`) |
37
+ | `GET /api/types?id=<uuid>` | `get` |
38
+ | `POST /api/types` | `create` |
39
+ | `PATCH /api/types?id=<uuid>` | `update` |
40
+ | `DELETE /api/types?id=<uuid>` | `remove` |
41
+
42
+ Quirk: a bare `GET` carrying `kind` (without `action=list` or
43
+ `action=schema`) routes to `get`, which then fails with
44
+ `Type ID is required` — kind-filtered listing requires `action=list`.
45
+
46
+ ## Authentication
47
+
48
+ Standard `createHandler` auth (`resolvePrincipal` in
49
+ `.framework/functions/_shared/principal.ts`): `x-api-key` → machine
50
+ principal, `x-internal-secret` → internal principal,
51
+ `Authorization: Bearer <jwt>` → human. Anonymous → 401.
52
+
53
+ - `create`, `update`, `remove` require a `system_admin` role
54
+ (`PermissionEngine.isSystemAdmin(ctx)`) — no fallback permission path.
55
+ - `list`/`get`/`getBySlug`/`getSchema` only require authentication.
56
+ System admins read via `adminDb` (all accounts); other principals use
57
+ `ctx.db` — JWT-scoped (RLS) for humans, service role for machines.
58
+
59
+ ## Request contract
60
+
61
+ **list** (query): `kind`, `app_id` (`'null'` filters to global types),
62
+ `ownership`, `active` (`'false'` → inactive only, `'all'` → everything,
63
+ default → active only), `limit` (default 50), `offset` (default 0),
64
+ `include_schema` (`'true'` also returns `validation_schema`).
65
+
66
+ **getBySlug** (query): `slug` — active rows only.
67
+
68
+ **getSchema** (query): `kind`, `slug` required; `app_id` optional
69
+ (passed to the RPC as `null` when absent).
70
+
71
+ **create** (body): `name`, `slug`, `kind` required. Optional:
72
+ `ownership` (default `'system'`), `app_id` (default `null`),
73
+ `design_schema` (default `{}`), `validation_schema` (default `null` →
74
+ generated), `description`, `icon`, `color`.
75
+
76
+ **update** (query `id` + body): `name`, `slug`, `description`, `icon`,
77
+ `color`, `is_active`, `kind`, `app_id`, `ownership`, `design_schema` —
78
+ only keys present in the body are written. An empty update returns the
79
+ existing row unchanged.
80
+
81
+ **remove** (query): `id`.
82
+
83
+ ## Response contract
84
+
85
+ Standard `{ data, error, meta }` envelope.
86
+
87
+ - `list` → array of sanitized type rows. `get`/`getBySlug`/`create`/
88
+ `update` → single row. `remove` → `{ success: true }`. `getSchema` →
89
+ `{ design_schema }`.
90
+ - Sanitization (`sanitizeRecordData`): system admins get the full row.
91
+ Other principals go through first-surface logic — the row's own
92
+ `design_schema.record_permissions` decides visibility; rows without
93
+ them collapse to `{ id }`. `list` re-attaches `design_schema` to the
94
+ sanitized row when it was stripped, and attaches `validation_schema`
95
+ when `include_schema=true`.
96
+
97
+ ## Side effects
98
+
99
+ - `create` inserts into `public.types` with `is_active: true`; when the
100
+ body omits `validation_schema` it is generated from `design_schema` by
101
+ `generateValidationSchema` (`.framework/functions/_shared/schema-utils.ts`).
102
+ - `update` regenerates `validation_schema` **every time `design_schema`
103
+ is present in the body** — the derived schema is never hand-editable.
104
+ - `remove` is a soft delete (`is_active = false`); `ownership: 'system'`
105
+ rows cannot be deleted, and their `ownership` cannot be changed away
106
+ from `'system'`.
107
+ - `emitLog` writes `type.created` / `type.updated` / `type.deleted`
108
+ audit rows to `public.logs`.
109
+ - Updating a type does **not** restamp `design_schema` onto existing
110
+ records — records keep the schema stamped at their own creation.
111
+
112
+ ## Errors
113
+
114
+ | Condition | HTTP | Message |
115
+ |---|---|---|
116
+ | Not system admin (create/update/remove) | 500 | `System admin required` |
117
+ | Missing create fields | 500 | `name, slug, and kind are required` |
118
+ | Duplicate active slug/kind/app_id | 500 | `Type with slug '<s>' already exists for kind '<k>'` |
119
+ | Missing `id` / `slug` / `kind`+`slug` | 500 | `Type ID is required` / `Type slug is required` / `kind and slug are required` |
120
+ | Update/delete of missing row | 500 | `Type not found` |
121
+ | Ownership change on system type | 500 | `Cannot change ownership of system types` |
122
+ | Delete system type | 500 | `Cannot delete system types` |
123
+ | Bad action/method | 500 | `Invalid action or method` |
124
+
125
+ Validation failures surface as HTTP 500 — the shared error path maps
126
+ thrown `Error`s without a `statusCode` to 500.
127
+
128
+ ## Agent notes
129
+
130
+ - Slug uniqueness is global per `kind`: the `types_kind_slug_unique`
131
+ index on `types(kind, slug)`
132
+ (`.framework/migrations/015_types_kind_slug_unique.sql`) is stricter
133
+ than `create`'s pre-check (which scopes to `app_id` + `is_active`), so
134
+ a same-kind/same-slug insert under a different `app_id` passes the
135
+ pre-check and then fails at the database. Pick globally unique slugs.
136
+ - `kind` must match the runtime table the type governs (`item`,
137
+ `thread`, `message`, …); `admin-data` resolves types by kind+slug.
138
+ - `getSchema` delegates to the Postgres RPC
139
+ `get_type_schema(kind, slug, app_id)`, provided by migration
140
+ `070_app_type_schema_rpcs.sql` (along with `get_app_schema`,
141
+ `is_app_available`, `update_app_version`). Installs missing that
142
+ migration will see `function does not exist` errors.
143
+ - `update` accepts `kind` and `app_id` changes — there is no guard
144
+ keeping `kind` aligned with already-stamped records.
145
+ - The unauthenticated "minimal row" branch in `list` is unreachable via
146
+ HTTP: `createHandler` rejects anonymous callers with 401 first.
@@ -0,0 +1,126 @@
1
+ ---
2
+ title: Seeds Reference
3
+ audience: developers, agents
4
+ kind: reference
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/cli/commands/install-app.ts
9
+ - .framework/cli/commands/migrate.ts
10
+ - .framework/functions/_shared/app-manifest.ts
11
+ - .framework/seeds/types/spine_instance.json
12
+ - .framework/seeds/link_types/account_cli_instances.json
13
+ - .framework/migrations/003_core_system_data.sql
14
+ - .framework/migrations/053_builtin_action_seeds.sql
15
+ ---
16
+
17
+ # Seeds Reference
18
+
19
+ Seeds are JSON row files that materialize an app's database contract — types,
20
+ roles, link types, agents, prompt configs, pipelines, triggers — at install
21
+ time. They are distinct from migrations: **migrations are SQL and change
22
+ schema; seeds are data and are applied by the app installer.**
23
+
24
+ ## Where seeds live
25
+
26
+ | Location | Contents | Format |
27
+ |---|---|---|
28
+ | `custom/apps/<slug>/seed/*.json` | app-owned rows, declared in `manifest.json` `seed[]` | JSON **array** of row objects |
29
+ | `.framework/seeds/` | framework-owned seed payloads (e.g. `.framework/seeds/types/spine_instance.json`, `.framework/seeds/link_types/account_cli_instances.json`) | single JSON object per file |
30
+ | `.framework/migrations/` | system rows written by SQL (`003_core_system_data.sql` seeds roles/types/apps; `053_builtin_action_seeds.sql` seeds `public.actions`) | SQL `INSERT … ON CONFLICT DO NOTHING` |
31
+
32
+ ## When seeds run
33
+
34
+ Seeds are applied by `seedApp` in `.framework/cli/commands/install-app.ts`:
35
+
36
+ | Command | Runs seeds? |
37
+ |---|---|
38
+ | `install-app <pkg>` | yes — after `runMigrations` succeeds, unless `--no-seed`. Migration failure aborts before seeding; without `SUPABASE_URL`/`SUPABASE_DB_PASSWORD` only `--no-seed` installs may proceed |
39
+ | `seed-app <slug>` | yes — seed block only, no npm, no file changes |
40
+ | `update-db-app <slug>` | no — upserts the `apps` row and syncs `registration` only |
41
+ | `update-app <pkg>` | no — refreshes files from npm only |
42
+ | `migrate` | no — migrations apply SQL only; system seeds inside migrations run as SQL |
43
+ | `uninstall-app <pkg>` | no — removes files and the npm dependency; it does not delete seeded rows |
44
+
45
+ Requires `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY`; seeding uses the
46
+ service-role client and bypasses RLS.
47
+
48
+ ## Apply order
49
+
50
+ Entries are stable-sorted by `SEED_TABLE_ORDER`
51
+ (`.framework/cli/commands/install-app.ts`), regardless of declaration order:
52
+
53
+ 1. `roles`
54
+ 2. `types`
55
+ 3. `permissions_patch` entries (rank 1.5 — always after types)
56
+ 4. `link_types`
57
+ 5. `actions`
58
+ 6. `ai_agents`
59
+ 7. `prompt_configs`
60
+ 8. `pipelines`
61
+ 9. `triggers`
62
+ 10. unknown tables — last, in declared order
63
+
64
+ Ordering exists so dependents resolve: a `triggers` row's `pipeline_slug` is
65
+ looked up in `public.pipelines` (scoped to this app's `app_id`) and rewritten
66
+ to `pipeline_id`, and a `pipelines` row's `stages[].stage_type` is validated
67
+ against `public.actions` — so a bad stage type fails at install, not at first
68
+ trigger fire.
69
+
70
+ ## Per-entry behavior
71
+
72
+ Each record is upserted into `entry.table` with `onConflict: entry.conflict`.
73
+
74
+ - **`inject_app_id`** (default `true`): stamps `app_id` on every row. Set
75
+ `false` for global rows — `types` seeds use `conflict: "kind,slug"` with
76
+ `inject_app_id: false` because type slugs are global, not per-app.
77
+ - **`ignore_duplicates`**: rows that conflict are skipped, not updated.
78
+ Always forced on for `types` (the read-then-compare below decides the real
79
+ outcome) and opt-in per entry via `ignore_duplicates: true`.
80
+ - **`types` rows are never silently overwritten.** Before each types upsert
81
+ the existing row is read: an identical `design_schema` skips cleanly; a
82
+ differing one throws — unless the slug is declared in
83
+ `manifest.owned_types` and `--reconcile-owned-types` was passed, which
84
+ prompts `[U]pdate / [K]eep` and merges (`seed` wins shared fields,
85
+ DB-only fields are preserved) with a regenerated `validation_schema`.
86
+ - **`permissions_patch` rows** (`{kind, slug, record_permissions}`) replace
87
+ `design_schema.record_permissions` on an existing type after a
88
+ `[R]eplace / [K]eep` prompt; grant lists may only contain
89
+ `create`/`read`/`update`/`delete`. A `seed/type_permissions.json` file is
90
+ auto-declared when no patch entry exists.
91
+ - **`types` seeds get a fresh `validation_schema`** generated from
92
+ `design_schema` at apply time — author `design_schema` only.
93
+ - **`pipelines` seeds** are validated before upsert: every `stages[].stage_type`
94
+ must exist in `public.actions`; `send_notification`/`send_email`
95
+ `config.recipients` must be `role:<slug>`, `self`, `owner`, `watchers`, a
96
+ person UUID, or (email only) an email address.
97
+ - **`triggers` seeds** may use `pipeline_slug`; it is resolved to
98
+ `pipeline_id` within the app's pipelines and removed before upsert.
99
+
100
+ ## Failure model
101
+
102
+ Seeding is fail-closed: a malformed manifest, a missing declared seed file,
103
+ an unparseable file, a non-array file, a missing referenced
104
+ type/pipeline/role, or any row-write error throws and aborts the run. Files
105
+ not declared in `manifest.seed` are skipped silently (except the auto-added
106
+ `type_permissions.json`). All validation runs **before** the database client
107
+ is created, so bad input produces zero writes.
108
+
109
+ After all entries apply, `syncAppRegistration` writes the resolved
110
+ `registration` policy to `apps.config.registration` and `spine.config.json`.
111
+
112
+ ## Authoring checklist
113
+
114
+ - [ ] Every `seed[]` entry's `file` exists inside the app dir and parses as a JSON array of objects
115
+ - [ ] `conflict` names real unique columns (`slug` for roles; `kind,slug` for types; `app_id,slug` for app-scoped config tables)
116
+ - [ ] `types` rows have a complete `design_schema` — see [Design Schema](design-schema.md); `validation_schema` is generated
117
+ - [ ] `inject_app_id: false` on `types` entries
118
+ - [ ] `pipeline_slug` used in trigger seeds; pipelines seeded (they always apply first)
119
+ - [ ] `owned_types` declared in the manifest for any type the app must reconcile
120
+ - [ ] `manifest.seed` omitted only when the conventional trio (`seed/roles.json`, `seed/types.json`, `seed/link-types.json`) covers everything
121
+
122
+ ## Related files
123
+
124
+ - `.framework/cli/commands/install-app.ts` — `seedApp`, `SEED_TABLE_ORDER`, `reconcileOwnedType`, `validatePipelineSeedStages`
125
+ - `.framework/cli/commands/migrate.ts` — migration runner (SQL only)
126
+ - [App Manifest](app-manifest.md) · [CLI](cli.md) · [Design Schema](design-schema.md)
@@ -0,0 +1,127 @@
1
+ ---
2
+ title: Shared Modules Reference
3
+ audience: developers, agents
4
+ kind: reference
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/functions/_shared/index.ts
9
+ - .framework/functions/_shared/middleware.ts
10
+ - .framework/functions/_shared/principal.ts
11
+ - .framework/functions/_shared/db.ts
12
+ - .framework/functions/_shared/permissions.ts
13
+ - .framework/functions/_shared/schema-utils.ts
14
+ - .framework/functions/_shared/trigger-engine.ts
15
+ - .framework/functions/_shared/pipeline-runner.ts
16
+ - .framework/functions/_shared/agent-runner.ts
17
+ - .framework/functions/_shared/logging.ts
18
+ - .framework/functions/_shared/audit.ts
19
+ - .framework/functions/_shared/tracing.ts
20
+ - .framework/functions/_shared/rate-limit.ts
21
+ - .framework/functions/_shared/resolve-credentials.ts
22
+ - .framework/functions/_shared/resolve-ids.ts
23
+ - .framework/functions/_shared/hash-api-key.ts
24
+ - .framework/functions/_shared/webhook-registration.ts
25
+ - .framework/functions/_shared/webhook-registry.ts
26
+ - .framework/functions/_shared/message-sequence.ts
27
+ - .framework/functions/_shared/security.ts
28
+ ---
29
+
30
+ # Shared Modules Reference
31
+
32
+ `.framework/functions/_shared/` is the library every Netlify function builds
33
+ on — bundled per function, never deployed as an endpoint itself.
34
+ `.framework/functions/_shared/index.ts` re-exports the common surface
35
+ (`createHandler`, `createPublicHandler`, `requireUserContext`,
36
+ `requireSystemContextWithAudit`, `json`, `errorResponse`, `cors`, the
37
+ `Principal`/`RequestContext`/`CoreContext`/`HandlerFunction`/`HandlerResult`
38
+ types). Import a sibling as `from './_shared/<module>'`.
39
+
40
+ ## Request handling
41
+
42
+ | Module | Exports | Import when |
43
+ |---|---|---|
44
+ | `middleware.ts` | `createHandler`, `createPublicHandler`, `json`, `error`, `cors`, `parseBody`, `requireUserContext`, `requireSystemContextWithAudit`; `RequestContext`, `CoreContext`, `HandlerFunction`, `HandlerResult` | every function — wraps auth, tracing, envelope, and error mapping around your handler |
45
+ | `principal.ts` | `resolvePrincipal`, `SYSTEM_PRINCIPAL`, `ANONYMOUS_PRINCIPAL`, `getPrincipalDb`, `isSystemAdmin`, `humanHasRole`, `machineHasScope`, `resolveInternalPersonId`, `formatPrincipalForAudit` | reading `ctx.principal`, checking roles/scopes, internal invocations |
46
+ | `db.ts` | `adminDb` (service-role, bypasses RLS), `getUserDb(token)` (RLS-scoped), `joins` | direct table access — prefer `ctx.db` (already principal-scoped) inside handlers |
47
+
48
+ ## Permissions & data shape
49
+
50
+ | Module | Exports | Import when |
51
+ |---|---|---|
52
+ | `permissions.ts` | `PermissionEngine`, `resolveFirstSurfacePermissions`, `sanitizeRecordData`, `validateUpdatePermissions`, `canAccessRecord`, `isSystemAdmin`, `PermissionResult` | evaluating `design_schema` grants, stripping fields a principal can't read, validating writes |
53
+ | `schema-utils.ts` | `generateValidationSchema`, `sanitizeFieldData`, `formatFieldData`, `transformRecordData`, `ValidationSchema` | field validation/sanitization against `data_type`; generating `validation_schema` |
54
+ | `resolve-ids.ts` | `resolveTypeId`, `resolveTypeIds`, `resolveTypeRecord`, `resolveAccountId`, `resolveLinkTypeId(s)`, `resolveAgentId`, `resolvePromptConfigId` | slug→uuid lookups for types, link types, accounts, agents, prompts |
55
+
56
+ ## Automation & agents
57
+
58
+ | Module | Exports | Import when |
59
+ |---|---|---|
60
+ | `trigger-engine.ts` | `fireCreateTriggers`, `fireUpdateTriggers`, `fireDeleteTriggers`, `checkAndFireTriggers`, `dispatchTriggerPipeline`, `EventType` | firing record-change triggers; dispatching a pipeline run (needs `INTERNAL_INVOKE_SECRET`) |
61
+ | `pipeline-runner.ts` | `runPipeline`, `sweepStaleExecutions`, `ExecutionResult`, `StageResult` | executing a pipeline's stages inside a function/background context |
62
+ | `agent-runner.ts` | `runAgent`, `runAgentStep`, `claimAgentEpisode`, `kickAgentEpisode`, `acquireEpisodeLease`, `resolveAgentConfig`, `executeToolAction`, `retrieveKnowledge`, `AgentConfig`, `ToolCall`, `ToolResult` | running an AI agent turn against a thread |
63
+ | `message-sequence.ts` | `insertMessageSequenced` | inserting a message outside `runAgent` — allocates `MAX(sequence)+1` and retries on the `(thread_id, sequence)` race |
64
+ | `notify.ts` | `resolveNotificationRecipients` | resolving `role:<slug>` / `self` / UUID recipients to `people.id` |
65
+
66
+ ## Observability & audit
67
+
68
+ | Module | Exports | Import when |
69
+ |---|---|---|
70
+ | `logging.ts` | `withAdminLogging`, `logAdminDataOperation`, `resolveLogLevels`, `resolveAppUuid`, `LogLevel` | wrapping handlers with the instance log-level-aware logging pipeline |
71
+ | `audit.ts` | `emitAudit`, `emitLog`, `emitSpan`, `emitActivity` | writing structured log/audit/span rows into `public.logs` |
72
+ | `tracing.ts` | `newTrace`, `startSpan`, `endSpan`, `withSpan(Sync)`, `traceDb`, `formatTraceParent/State`, `parseTraceParent/State`, `generateTraceId/SpanId`, `isSampled` | W3C trace-context propagation and span wrapping of DB calls |
73
+ | `outcomes.ts` | `emitOutcome` | recording outcome audit rows |
74
+
75
+ ## Security
76
+
77
+ | Module | Exports | Import when |
78
+ |---|---|---|
79
+ | `hash-api-key.ts` | `hashApiKey`, `verifyApiKey`, `omitSecretFields` | minting/verifying API keys (`pbkdf2$iter$salt$hash`, 100k sha256); stripping key material from responses |
80
+ | `rate-limit.ts` | `checkRateLimit`, `resolveRateLimitPolicies`, `RateLimitError`, `RateLimitPolicy` | enforcing `config.rate_limits` policies via the atomic `rate_limit_hit` RPC |
81
+ | `security.ts` | `isBlockedRequest`, `isBlockedIp`, `checkTypeSlugRateLimit`, `detectInjection`, `emitSecurityEvent`, `getAppSecurityConfig`, `checkRegistrationBlocklist`, `touchPersonGeo`, `INJECTION_PATTERNS` | blocklist checks, per-type-slug rate limits, prompt-injection screening |
82
+ | `geo.ts` | `getClientGeo`, `ClientGeo` | best-effort client IP/geo from request headers |
83
+
84
+ ## Integrations & webhooks
85
+
86
+ | Module | Exports | Import when |
87
+ |---|---|---|
88
+ | `resolve-credentials.ts` | `resolveCredential`, `resolveCredentials`, `ResolvedCredential` | resolving `integrations.config.credentials` (`value` literal or `env_var` lookup) server-side |
89
+ | `webhook-registration.ts` | `registerWebhookHandler`, `deregisterWebhookHandler`, `isHandlerRegistered` | self-registering a custom function as a webhook handler (`webhook_handlers` upsert) |
90
+ | `webhook-registry.ts` | `lookupHandler`, `resolveHandler`, `loadHandler`, `listRegisteredHandlers`, `clearHandlerCache` | resolving which registered handler receives an inbound event |
91
+ | `retry-deliveries.ts` | `retryPendingDeliveries` | sweeping due `webhook_deliveries` rows for retry |
92
+
93
+ ## Knowledge & LLM
94
+
95
+ | Module | Exports | Import when |
96
+ |---|---|---|
97
+ | `kb.ts` | `kbIngest`, `kbPublish`, `kbReindex`, `kbRevoke`, `kbSearch`, `resolveKnowledgeScope`, `knowledgeRowAllowed`, `resolveSecurityLevel`, `matchItemType`, `KnowledgeScope`, `KnowledgeEnvelope` | ingesting/searching embeddings with scope + security-level enforcement |
98
+ | `llm.ts` | `callOpenAI`, `callOpenAIChat`, `callOpenAIEmbeddings`, `callEmbeddingApi`, `LlmContext` | thin wrappers over the `openai` outbound integration |
99
+ | `funnel.ts` | `emitSignal`, `accountDataFlag`, `SignalInput` | emitting typed funnel/signal events that can fire triggers |
100
+ | `access.ts` | `hasInternalAudience`, `projectMessageForCustomer`, `INTERNAL_AUDIENCE_ROLES`, `CUSTOMER_STEP_TYPES` | deciding whether a principal may read `visibility: 'internal'` rows and projecting customer-safe message shapes |
101
+
102
+ ## Framework internals
103
+
104
+ | Module | Purpose |
105
+ |---|---|
106
+ | `app-manifest.ts` | `loadManifest`, `mergeWithManifest`, `discoverManifests`, `clearManifestCache` — `manifest.json` loading for app rows with `config_source = 'manifest'` |
107
+ | `ast.ts` | `extractIdentities` — TypeScript compiler API for code-analysis pipelines |
108
+ | `cil.ts` | stable-id generation, content hashing, file-tree helpers for the code-intelligence pipeline — not needed by custom apps |
109
+ | `testing.ts` | `mockEvent`, `mockPrincipal`, `makeTestContext`, `expectSuccessResponse`, `expectErrorResponse`, `setupTests` — function-level test harness |
110
+
111
+ ## Usage notes
112
+
113
+ - `ctx.db` is already the right client for the request's principal — humans
114
+ get an RLS-scoped client, machines get `adminDb`. Reach for `adminDb`
115
+ directly only when you must deliberately bypass RLS (system writes,
116
+ cross-account lookups like `types`/`accounts` resolution).
117
+ - Never `JSON.stringify(ctx.principal)` — `authContext.jwt` rides on it; use
118
+ `formatPrincipalForAudit`.
119
+ - Circular-import hazards are real in this layer (`middleware → security →
120
+ rate-limit → funnel → trigger-engine → pipeline-runner → kb → llm →
121
+ integration-outbound → admin-data → middleware`); some modules import
122
+ lazily on purpose — copy that pattern rather than adding a static edge.
123
+
124
+ ## Related
125
+
126
+ - [admin-data](api/admin-data.md) · [Authentication](api/auth.md) · [Errors and Envelopes](api/errors-and-envelopes.md)
127
+ - [Design Schema](design-schema.md) · [Database](database.md)
@@ -0,0 +1,114 @@
1
+ ---
2
+ title: spine.config.json Reference
3
+ audience: developers, agents
4
+ kind: reference
5
+ verified_against: f69c37d
6
+ verified_on: 2026-10-30
7
+ source_files:
8
+ - .framework/schemas/spine.config.schema.json
9
+ - .framework/templates/spine.config.neutral.json
10
+ - .framework/src/lib/branding.ts
11
+ - .framework/src/hooks/useBranding.ts
12
+ - .framework/cli/commands/install-app.ts
13
+ ---
14
+
15
+ # `spine.config.json` Reference
16
+
17
+ `spine.config.json` is the per-project instance config. It lives at the
18
+ project root and is served to the browser as a static public asset — the
19
+ frontend fetches `/spine.config.json`. **Everything in it is client-visible;
20
+ never put secrets here.** The JSON Schema is
21
+ `.framework/schemas/spine.config.schema.json`; the neutral starting point is
22
+ `.framework/templates/spine.config.neutral.json`.
23
+
24
+ ```json
25
+ {
26
+ "branding": {
27
+ "app_name": "My Product",
28
+ "title": "My Product",
29
+ "logo_url": "/logo.svg",
30
+ "favicon_url": "/favicon.svg"
31
+ },
32
+ "registration": {
33
+ "default_app": "my-app",
34
+ "default_role": "member",
35
+ "allow_url_override": false,
36
+ "default_app_by_role": { "support": "my-app" },
37
+ "apps": {
38
+ "my-app": {
39
+ "roles": ["member", "member_admin"],
40
+ "default_role": "member_admin",
41
+ "path": "/my-app",
42
+ "enabled": true,
43
+ "account_strategy": "new",
44
+ "parent_account": "spine-system"
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## `branding`
52
+
53
+ Read by `.framework/src/lib/branding.ts` (`loadBranding` fetches
54
+ `/spine.config.json` and caches it) and applied to framework-owned pages —
55
+ login, register, setup, sidebars — plus `document.title` and the favicon via
56
+ `useBranding` (`.framework/src/hooks/useBranding.ts`). All keys optional;
57
+ an absent block falls back to Spine defaults.
58
+
59
+ | Key | Default | Effect |
60
+ |---|---|---|
61
+ | `app_name` | `"Spine"` | display name in headings and logo alt text |
62
+ | `title` | `app_name` (or `"Spine Framework"`) | `document.title` and sidebar wordmark |
63
+ | `logo_url` | `"/spine-logo.svg"` | public asset path for the brand logo |
64
+ | `favicon_url` | `"/spine-logo.svg"` | swapped into `link[rel=icon]` at runtime |
65
+
66
+ ## `registration`
67
+
68
+ Consumed by the registration/login pages and kept in sync with
69
+ `apps.config.registration` by the installer (`syncAppRegistration` and
70
+ `updateRegistrationConfig` in `.framework/cli/commands/install-app.ts` — the
71
+ DB write lands first, then the file).
72
+
73
+ | Key | Type | Effect |
74
+ |---|---|---|
75
+ | `default_app` | string (app slug) | where registrants land when no role rule matches; auto-set to the first enabled app when absent |
76
+ | `default_role` | string (role slug) | role assigned when the app entry has no `default_role` |
77
+ | `allow_url_override` | boolean | allow a `?app=`/`?role=` URL override at registration; installer sets `true` when undefined |
78
+ | `default_app_by_role` | `{role: appSlug}` | per-role landing-app map |
79
+ | `apps` | `{appSlug: AppEntry}` | per-app registration policy, see below |
80
+
81
+ ### `registration.apps.<slug>`
82
+
83
+ | Key | Type | Effect |
84
+ |---|---|---|
85
+ | `roles` | string[] | roles registrants may be placed into through this app |
86
+ | `default_role` | string | role assigned by default |
87
+ | `path` | string | redirect path after registration completes |
88
+ | `enabled` | boolean | `true` opens self-service registration for this app; explicit `false` persists a disabled policy |
89
+ | `account_strategy` | `"new" \| "existing"` | create a new account or join `target_account` |
90
+ | `parent_account` | string | account slug new accounts are parented under (e.g. `spine-system`) |
91
+ | `target_account` | string (uuid) | account to join under `existing` strategy |
92
+ | `default_workspace_name` | string | name for the workspace created at registration |
93
+ | `allow_domain_join` | boolean | allow signups whose email domain matches an existing account to join it |
94
+
95
+ ## File vs. schema notes
96
+
97
+ - `additionalProperties: true` at the root — extra top-level keys are allowed
98
+ and preserved.
99
+ - `loadSpineConfig` throws on malformed JSON, a non-object root, a non-object
100
+ `registration`, or a non-object `registration.apps`; a missing file returns
101
+ `{registration: {apps: {}}}`.
102
+ - The installer writes `registration.apps.<slug>` and `default_app`/`default_role`
103
+ when an app manifest declares `registration.enabled: true` — see
104
+ [App Manifest](app-manifest.md).
105
+ - `.framework/public/spine.config.json` is the framework's copy of the served
106
+ asset; the project root file is what `init` scaffolds and the frontend
107
+ actually fetches at runtime.
108
+
109
+ ## Related files
110
+
111
+ - `.framework/schemas/spine.config.schema.json` — validation schema
112
+ - `.framework/templates/spine.config.neutral.json` — minimal valid config
113
+ - `.framework/src/lib/branding.ts` — branding resolution and defaults
114
+ - `.framework/cli/commands/install-app.ts` — `loadSpineConfig`, `saveSpineConfig`, `updateRegistrationConfig`