create-flowdular 0.2.4 → 0.2.6

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 (271) hide show
  1. package/README.md +11 -0
  2. package/agent-template/.agents/skills/agent-tool-design/SKILL.md +203 -0
  3. package/agent-template/.agents/skills/auth-security-review/SKILL.md +90 -0
  4. package/agent-template/.agents/skills/auto-review/SKILL.md +103 -0
  5. package/agent-template/.agents/skills/bug-hunt/SKILL.md +104 -0
  6. package/agent-template/.agents/skills/business-agent-design/SKILL.md +182 -0
  7. package/agent-template/.agents/skills/cli-extension/SKILL.md +108 -0
  8. package/agent-template/.agents/skills/core-extend/SKILL.md +99 -0
  9. package/agent-template/.agents/skills/database-adapter/SKILL.md +198 -0
  10. package/agent-template/.agents/skills/database-adapter/references/first-run-and-matrix.md +105 -0
  11. package/agent-template/.agents/skills/migration-authoring/SKILL.md +161 -0
  12. package/agent-template/.agents/skills/module-new/SKILL.md +171 -0
  13. package/agent-template/.agents/skills/module-update/SKILL.md +91 -0
  14. package/agent-template/.agents/skills/perf-audit/SKILL.md +98 -0
  15. package/agent-template/.agents/skills/release-eject-pr/SKILL.md +107 -0
  16. package/agent-template/.agents/skills/spec-approval/SKILL.md +106 -0
  17. package/agent-template/.agents/skills/test-hardening/SKILL.md +79 -0
  18. package/agent-template/.agents/skills/translations-i18n/SKILL.md +78 -0
  19. package/agent-template/.agents/skills/ux-design/SKILL.md +92 -0
  20. package/agent-template/.agents/skills/variables/SKILL.md +156 -0
  21. package/agent-template/.agents/skills/workflow-development/SKILL.md +192 -0
  22. package/agent-template/.ai/README.md +62 -0
  23. package/agent-template/.ai/agents/README.md +27 -0
  24. package/agent-template/.ai/agents/module-executor.md +36 -0
  25. package/agent-template/.ai/agents/reviewer.md +23 -0
  26. package/agent-template/.ai/agents/sandbox/agentic-engineer.md +31 -0
  27. package/agent-template/.ai/agents/sandbox/backend-engineer.md +36 -0
  28. package/agent-template/.ai/agents/sandbox/business-manager.md +23 -0
  29. package/agent-template/.ai/agents/sandbox/frontend-engineer.md +27 -0
  30. package/agent-template/.ai/agents/sandbox/ux-designer.md +23 -0
  31. package/agent-template/.ai/agents/spec-author.md +29 -0
  32. package/agent-template/.ai/blueprints/add-migration/README.md +5 -0
  33. package/agent-template/.ai/blueprints/add-migration/allowed-paths.yaml +23 -0
  34. package/agent-template/.ai/blueprints/add-migration/blueprint.json +14 -0
  35. package/agent-template/.ai/blueprints/add-migration/examples/invalid/input-destructive.json +6 -0
  36. package/agent-template/.ai/blueprints/add-migration/examples/invalid/plan-unnumbered-file.json +9 -0
  37. package/agent-template/.ai/blueprints/add-migration/examples/valid/input.json +6 -0
  38. package/agent-template/.ai/blueprints/add-migration/examples/valid/plan.json +9 -0
  39. package/agent-template/.ai/blueprints/add-migration/gates.yaml +30 -0
  40. package/agent-template/.ai/blueprints/add-migration/input.schema.json +23 -0
  41. package/agent-template/.ai/blueprints/add-migration/plan.schema.json +54 -0
  42. package/agent-template/.ai/blueprints/add-migration/required-files.yaml +18 -0
  43. package/agent-template/.ai/blueprints/add-migration/spec-requirements.yaml +13 -0
  44. package/agent-template/.ai/blueprints/add-migration/steps.yaml +62 -0
  45. package/agent-template/.ai/blueprints/author-spec/README.md +5 -0
  46. package/agent-template/.ai/blueprints/author-spec/allowed-paths.yaml +7 -0
  47. package/agent-template/.ai/blueprints/author-spec/blueprint.json +14 -0
  48. package/agent-template/.ai/blueprints/author-spec/examples/invalid/input-missing-outcome.json +5 -0
  49. package/agent-template/.ai/blueprints/author-spec/examples/valid/input.json +6 -0
  50. package/agent-template/.ai/blueprints/author-spec/gates.yaml +13 -0
  51. package/agent-template/.ai/blueprints/author-spec/input.schema.json +20 -0
  52. package/agent-template/.ai/blueprints/author-spec/plan.schema.json +14 -0
  53. package/agent-template/.ai/blueprints/author-spec/required-files.yaml +6 -0
  54. package/agent-template/.ai/blueprints/author-spec/spec-requirements.yaml +35 -0
  55. package/agent-template/.ai/blueprints/author-spec/steps.yaml +28 -0
  56. package/agent-template/.ai/blueprints/author-spec/templates/module.yaml +45 -0
  57. package/agent-template/.ai/blueprints/bug-fix/README.md +5 -0
  58. package/agent-template/.ai/blueprints/bug-fix/allowed-paths.yaml +29 -0
  59. package/agent-template/.ai/blueprints/bug-fix/blueprint.json +14 -0
  60. package/agent-template/.ai/blueprints/bug-fix/examples/invalid/input-no-symptom.json +4 -0
  61. package/agent-template/.ai/blueprints/bug-fix/examples/invalid/plan-no-test.json +8 -0
  62. package/agent-template/.ai/blueprints/bug-fix/examples/valid/input.json +6 -0
  63. package/agent-template/.ai/blueprints/bug-fix/examples/valid/plan.json +8 -0
  64. package/agent-template/.ai/blueprints/bug-fix/gates.yaml +30 -0
  65. package/agent-template/.ai/blueprints/bug-fix/input.schema.json +25 -0
  66. package/agent-template/.ai/blueprints/bug-fix/plan.schema.json +53 -0
  67. package/agent-template/.ai/blueprints/bug-fix/required-files.yaml +7 -0
  68. package/agent-template/.ai/blueprints/bug-fix/spec-requirements.yaml +7 -0
  69. package/agent-template/.ai/blueprints/bug-fix/steps.yaml +51 -0
  70. package/agent-template/.ai/blueprints/core-extend/README.md +5 -0
  71. package/agent-template/.ai/blueprints/core-extend/allowed-paths.yaml +49 -0
  72. package/agent-template/.ai/blueprints/core-extend/blueprint.json +14 -0
  73. package/agent-template/.ai/blueprints/core-extend/examples/invalid/input-unknown-package.json +5 -0
  74. package/agent-template/.ai/blueprints/core-extend/examples/invalid/plan-missing-gates.json +7 -0
  75. package/agent-template/.ai/blueprints/core-extend/examples/valid/input.json +6 -0
  76. package/agent-template/.ai/blueprints/core-extend/examples/valid/plan.json +10 -0
  77. package/agent-template/.ai/blueprints/core-extend/gates.yaml +16 -0
  78. package/agent-template/.ai/blueprints/core-extend/input.schema.json +54 -0
  79. package/agent-template/.ai/blueprints/core-extend/plan.schema.json +39 -0
  80. package/agent-template/.ai/blueprints/core-extend/required-files.yaml +36 -0
  81. package/agent-template/.ai/blueprints/core-extend/spec-requirements.yaml +17 -0
  82. package/agent-template/.ai/blueprints/core-extend/steps.yaml +54 -0
  83. package/agent-template/.ai/blueprints/edit-module/README.md +9 -0
  84. package/agent-template/.ai/blueprints/edit-module/allowed-paths.yaml +27 -0
  85. package/agent-template/.ai/blueprints/edit-module/blueprint.json +20 -0
  86. package/agent-template/.ai/blueprints/edit-module/examples/invalid/input-unknown-change.json +5 -0
  87. package/agent-template/.ai/blueprints/edit-module/examples/invalid/plan-touches-platform.json +15 -0
  88. package/agent-template/.ai/blueprints/edit-module/examples/valid/input.json +5 -0
  89. package/agent-template/.ai/blueprints/edit-module/examples/valid/plan.json +25 -0
  90. package/agent-template/.ai/blueprints/edit-module/gates.yaml +30 -0
  91. package/agent-template/.ai/blueprints/edit-module/input.schema.json +31 -0
  92. package/agent-template/.ai/blueprints/edit-module/plan.schema.json +65 -0
  93. package/agent-template/.ai/blueprints/edit-module/required-files.yaml +80 -0
  94. package/agent-template/.ai/blueprints/edit-module/spec-requirements.yaml +15 -0
  95. package/agent-template/.ai/blueprints/edit-module/steps.yaml +115 -0
  96. package/agent-template/.ai/blueprints/new-module/README.md +7 -0
  97. package/agent-template/.ai/blueprints/new-module/allowed-paths.yaml +27 -0
  98. package/agent-template/.ai/blueprints/new-module/blueprint.json +20 -0
  99. package/agent-template/.ai/blueprints/new-module/examples/invalid/input-spec-outside-modules.json +4 -0
  100. package/agent-template/.ai/blueprints/new-module/examples/invalid/plan-unknown-gate.json +8 -0
  101. package/agent-template/.ai/blueprints/new-module/examples/valid/input.json +5 -0
  102. package/agent-template/.ai/blueprints/new-module/examples/valid/plan.json +22 -0
  103. package/agent-template/.ai/blueprints/new-module/gates.yaml +30 -0
  104. package/agent-template/.ai/blueprints/new-module/input.schema.json +21 -0
  105. package/agent-template/.ai/blueprints/new-module/plan.schema.json +58 -0
  106. package/agent-template/.ai/blueprints/new-module/required-files.yaml +73 -0
  107. package/agent-template/.ai/blueprints/new-module/spec-requirements.yaml +30 -0
  108. package/agent-template/.ai/blueprints/new-module/steps.yaml +138 -0
  109. package/agent-template/.ai/blueprints/release/README.md +5 -0
  110. package/agent-template/.ai/blueprints/release/allowed-paths.yaml +19 -0
  111. package/agent-template/.ai/blueprints/release/blueprint.json +14 -0
  112. package/agent-template/.ai/blueprints/release/examples/invalid/input-bad-version.json +4 -0
  113. package/agent-template/.ai/blueprints/release/examples/invalid/plan-bad-branch.json +7 -0
  114. package/agent-template/.ai/blueprints/release/examples/valid/input.json +5 -0
  115. package/agent-template/.ai/blueprints/release/examples/valid/plan.json +20 -0
  116. package/agent-template/.ai/blueprints/release/gates.yaml +20 -0
  117. package/agent-template/.ai/blueprints/release/input.schema.json +24 -0
  118. package/agent-template/.ai/blueprints/release/plan.schema.json +46 -0
  119. package/agent-template/.ai/blueprints/release/required-files.yaml +19 -0
  120. package/agent-template/.ai/blueprints/release/spec-requirements.yaml +8 -0
  121. package/agent-template/.ai/blueprints/release/steps.yaml +47 -0
  122. package/agent-template/.ai/blueprints/security-review/README.md +5 -0
  123. package/agent-template/.ai/blueprints/security-review/allowed-paths.yaml +6 -0
  124. package/agent-template/.ai/blueprints/security-review/blueprint.json +14 -0
  125. package/agent-template/.ai/blueprints/security-review/examples/invalid/input-unknown-kind.json +4 -0
  126. package/agent-template/.ai/blueprints/security-review/examples/invalid/plan-finding-without-scenario.json +14 -0
  127. package/agent-template/.ai/blueprints/security-review/examples/valid/input.json +4 -0
  128. package/agent-template/.ai/blueprints/security-review/examples/valid/plan.json +19 -0
  129. package/agent-template/.ai/blueprints/security-review/gates.yaml +22 -0
  130. package/agent-template/.ai/blueprints/security-review/input.schema.json +20 -0
  131. package/agent-template/.ai/blueprints/security-review/plan.schema.json +65 -0
  132. package/agent-template/.ai/blueprints/security-review/required-files.yaml +6 -0
  133. package/agent-template/.ai/blueprints/security-review/spec-requirements.yaml +9 -0
  134. package/agent-template/.ai/blueprints/security-review/steps.yaml +38 -0
  135. package/agent-template/.ai/examples/README.md +8 -0
  136. package/agent-template/.ai/examples/bad/client-imports-server/README.md +20 -0
  137. package/agent-template/.ai/examples/bad/client-imports-server/api.ts +12 -0
  138. package/agent-template/.ai/examples/bad/missing-acl/README.md +23 -0
  139. package/agent-template/.ai/examples/bad/missing-acl/endpoints.ts +12 -0
  140. package/agent-template/.ai/examples/bad/tenant-from-body/README.md +19 -0
  141. package/agent-template/.ai/examples/bad/tenant-from-body/endpoints.ts +33 -0
  142. package/agent-template/.ai/examples/client-contribution/CustomerListView.tsrx +34 -0
  143. package/agent-template/.ai/examples/client-contribution/README.md +11 -0
  144. package/agent-template/.ai/examples/client-contribution/contribution.tsrx +48 -0
  145. package/agent-template/.ai/examples/client-contribution/index.ts +20 -0
  146. package/agent-template/.ai/examples/client-contribution/permissions.ts +8 -0
  147. package/agent-template/.ai/examples/customer-cli-extension/README.md +14 -0
  148. package/agent-template/.ai/examples/customer-cli-extension/commands.json +17 -0
  149. package/agent-template/.ai/examples/customer-cli-extension/index.ts +36 -0
  150. package/agent-template/.ai/examples/module-create/task-packet.json +11 -0
  151. package/agent-template/.ai/guides/application-development.md +97 -0
  152. package/agent-template/.ai/policies/capabilities.yaml +164 -0
  153. package/agent-template/.ai/policies/model-routing.yaml +72 -0
  154. package/agent-template/.ai/policies/path-ownership.yaml +65 -0
  155. package/agent-template/.ai/policies/task-budgets.yaml +37 -0
  156. package/agent-template/.ai/references/catalog/LICENSE +21 -0
  157. package/agent-template/.ai/references/catalog/migrations/0001_catalog_core.down.sql +2 -0
  158. package/agent-template/.ai/references/catalog/migrations/0001_catalog_core.up.sql +21 -0
  159. package/agent-template/.ai/references/catalog/migrations/0002_catalog_history.down.sql +3 -0
  160. package/agent-template/.ai/references/catalog/migrations/0002_catalog_history.up.sql +20 -0
  161. package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.down.sql +3 -0
  162. package/agent-template/.ai/references/catalog/migrations/0003_catalog_history_service_actors.up.sql +36 -0
  163. package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.down.sql +3 -0
  164. package/agent-template/.ai/references/catalog/migrations/0004_catalog_idempotency_ledger.up.sql +19 -0
  165. package/agent-template/.ai/references/catalog/migrations/README.md +3 -0
  166. package/agent-template/.ai/references/catalog/module.json +27 -0
  167. package/agent-template/.ai/references/catalog/package.json +49 -0
  168. package/agent-template/.ai/references/catalog/spec/module.yaml +86 -0
  169. package/agent-template/.ai/references/catalog/src/acl/permissions.ts +6 -0
  170. package/agent-template/.ai/references/catalog/src/agent/tools.ts +164 -0
  171. package/agent-template/.ai/references/catalog/src/api/endpoints.ts +243 -0
  172. package/agent-template/.ai/references/catalog/src/client/CatalogHistoryDrawer.tsrx +123 -0
  173. package/agent-template/.ai/references/catalog/src/client/CatalogItemForm.tsrx +190 -0
  174. package/agent-template/.ai/references/catalog/src/client/CatalogView.tsrx +473 -0
  175. package/agent-template/.ai/references/catalog/src/client/api.ts +111 -0
  176. package/agent-template/.ai/references/catalog/src/client/contribution.tsrx +61 -0
  177. package/agent-template/.ai/references/catalog/src/client/index.ts +18 -0
  178. package/agent-template/.ai/references/catalog/src/client/navigation-copy.ts +9 -0
  179. package/agent-template/.ai/references/catalog/src/client/state.ts +24 -0
  180. package/agent-template/.ai/references/catalog/src/domain/types.ts +32 -0
  181. package/agent-template/.ai/references/catalog/src/domain/variables.ts +111 -0
  182. package/agent-template/.ai/references/catalog/src/index.ts +31 -0
  183. package/agent-template/.ai/references/catalog/src/platform.ts +35 -0
  184. package/agent-template/.ai/references/catalog/src/server/index.ts +4 -0
  185. package/agent-template/.ai/references/catalog/src/server/runtime.ts +86 -0
  186. package/agent-template/.ai/references/catalog/src/services/catalog-service.ts +306 -0
  187. package/agent-template/.ai/references/catalog/src/services/database-repository.ts +440 -0
  188. package/agent-template/.ai/references/catalog/src/services/index.ts +4 -0
  189. package/agent-template/.ai/references/catalog/src/services/migration.ts +171 -0
  190. package/agent-template/.ai/references/catalog/src/services/repository.ts +36 -0
  191. package/agent-template/.ai/references/catalog/src/services/target-idempotency.ts +59 -0
  192. package/agent-template/.ai/references/catalog/tests/agent-tools.test.ts +277 -0
  193. package/agent-template/.ai/references/catalog/tests/endpoints.test.ts +320 -0
  194. package/agent-template/.ai/references/catalog/tests/idempotency.test.ts +297 -0
  195. package/agent-template/.ai/references/catalog/tests/migrations.test.ts +149 -0
  196. package/agent-template/.ai/references/catalog/tests/module.test.ts +271 -0
  197. package/agent-template/.ai/references/catalog/tests/support/database.ts +76 -0
  198. package/agent-template/.ai/references/catalog/translations/en.json +101 -0
  199. package/agent-template/.ai/references/catalog/translations/pl.json +101 -0
  200. package/agent-template/.ai/references/catalog/tsconfig.json +15 -0
  201. package/agent-template/.ai/references/catalog/vitest.config.ts +16 -0
  202. package/agent-template/.ai/references/catalog.provenance.json +55 -0
  203. package/agent-template/.ai/rules/flowdular.md +86 -0
  204. package/agent-template/.ai/skills/README.md +36 -0
  205. package/agent-template/.ai/skills/agent-tool-design/SKILL.md +209 -0
  206. package/agent-template/.ai/skills/auth-security-review/SKILL.md +96 -0
  207. package/agent-template/.ai/skills/auto-review/SKILL.md +112 -0
  208. package/agent-template/.ai/skills/bug-hunt/SKILL.md +110 -0
  209. package/agent-template/.ai/skills/business-agent-design/SKILL.md +188 -0
  210. package/agent-template/.ai/skills/cli-extension/SKILL.md +114 -0
  211. package/agent-template/.ai/skills/core-extend/SKILL.md +104 -0
  212. package/agent-template/.ai/skills/database-adapter/SKILL.md +204 -0
  213. package/agent-template/.ai/skills/database-adapter/references/first-run-and-matrix.md +105 -0
  214. package/agent-template/.ai/skills/migration-authoring/SKILL.md +167 -0
  215. package/agent-template/.ai/skills/module-new/SKILL.md +180 -0
  216. package/agent-template/.ai/skills/module-update/SKILL.md +100 -0
  217. package/agent-template/.ai/skills/perf-audit/SKILL.md +105 -0
  218. package/agent-template/.ai/skills/release-eject-pr/SKILL.md +113 -0
  219. package/agent-template/.ai/skills/spec-approval/SKILL.md +112 -0
  220. package/agent-template/.ai/skills/test-hardening/SKILL.md +86 -0
  221. package/agent-template/.ai/skills/translations-i18n/SKILL.md +85 -0
  222. package/agent-template/.ai/skills/ux-design/SKILL.md +97 -0
  223. package/agent-template/.ai/skills/variables/SKILL.md +164 -0
  224. package/agent-template/.ai/skills/workflow-development/SKILL.md +199 -0
  225. package/agent-template/.claude/skills/agent-tool-design/SKILL.md +203 -0
  226. package/agent-template/.claude/skills/auth-security-review/SKILL.md +90 -0
  227. package/agent-template/.claude/skills/auto-review/SKILL.md +103 -0
  228. package/agent-template/.claude/skills/bug-hunt/SKILL.md +104 -0
  229. package/agent-template/.claude/skills/business-agent-design/SKILL.md +182 -0
  230. package/agent-template/.claude/skills/cli-extension/SKILL.md +108 -0
  231. package/agent-template/.claude/skills/core-extend/SKILL.md +99 -0
  232. package/agent-template/.claude/skills/database-adapter/SKILL.md +198 -0
  233. package/agent-template/.claude/skills/database-adapter/references/first-run-and-matrix.md +105 -0
  234. package/agent-template/.claude/skills/migration-authoring/SKILL.md +161 -0
  235. package/agent-template/.claude/skills/module-new/SKILL.md +171 -0
  236. package/agent-template/.claude/skills/module-update/SKILL.md +91 -0
  237. package/agent-template/.claude/skills/perf-audit/SKILL.md +98 -0
  238. package/agent-template/.claude/skills/release-eject-pr/SKILL.md +107 -0
  239. package/agent-template/.claude/skills/spec-approval/SKILL.md +106 -0
  240. package/agent-template/.claude/skills/test-hardening/SKILL.md +79 -0
  241. package/agent-template/.claude/skills/translations-i18n/SKILL.md +78 -0
  242. package/agent-template/.claude/skills/ux-design/SKILL.md +92 -0
  243. package/agent-template/.claude/skills/variables/SKILL.md +156 -0
  244. package/agent-template/.claude/skills/workflow-development/SKILL.md +192 -0
  245. package/agent-template/AGENTS.md +77 -0
  246. package/agent-template/CLAUDE.md +77 -0
  247. package/agent-template/docs/adr/0001-development-reload.md +16 -0
  248. package/agent-template/docs/adr/0002-durable-agent-execution.md +21 -0
  249. package/agent-template/docs/adr/0003-module-settings.md +22 -0
  250. package/agent-template/docs/adr/0004-enterprise-access-and-audit.md +36 -0
  251. package/agent-template/docs/adr/0005-sandbox-runtime-and-coding-agents.md +81 -0
  252. package/agent-template/docs/adr/0006-agentic-workflows.md +1702 -0
  253. package/agent-template/docs/adr/0007-module-owned-agents.md +429 -0
  254. package/agent-template/docs/adr/0008-database-adapter-contract.md +90 -0
  255. package/agent-template/docs/agent-contract.md +45 -0
  256. package/agent-template/docs/configuration.md +122 -0
  257. package/agent-template/docs/database-adapters.md +346 -0
  258. package/agent-template/docs/design-system.md +217 -0
  259. package/agent-template/docs/modules.md +146 -0
  260. package/agent-template/platform/scripts/build.mjs +38 -0
  261. package/agent-template/rulesync.jsonc +11 -0
  262. package/dist/bin.js +40 -2
  263. package/package.json +3 -2
  264. package/template/default/.prettierignore +9 -0
  265. package/template/default/README.md +12 -0
  266. package/template/default/flowdular.json +3 -3
  267. package/template/default/modules/example/package.json +2 -2
  268. package/template/default/package.json +6 -2
  269. package/template/default/platform/octane.config.ts +17 -6
  270. package/template/default/platform/package.json +3 -2
  271. package/template/default/pnpm-workspace.yaml +1 -0
@@ -0,0 +1,429 @@
1
+ # ADR 0007: Module-owned business agents
2
+
3
+ - Status: accepted
4
+ - Date: 2026-09-02
5
+ - Approval gate: `modules/agents/spec/module.yaml` 0.7.0
6
+
7
+ ## Problem
8
+
9
+ Modules can register tools, but they cannot ship the business-agent behavior
10
+ that uses those tools. An operator must recreate the same instructions and tool
11
+ allowlist as tenant data. That copy drifts when the module changes and prevents
12
+ an enabled module from being agentic by itself.
13
+
14
+ Every agent managed by `agents.core` is a business agent. "Module-owned" and
15
+ "tenant-created" describe who owns its definition, not two different kinds of
16
+ runtime. Sandbox coding specialists are a separate development system and are
17
+ not registered through this contract.
18
+
19
+ The concrete consumers are:
20
+
21
+ 1. A business module such as `catalog.core`, which ships a catalog curation
22
+ agent next to its tools.
23
+ 2. `agents.core`, which lists, configures and executes module-owned agents next
24
+ to tenant-created agents.
25
+ 3. `workflows.core`, which publishes a graph against an exact executable agent
26
+ revision and must keep that revision after the module publishes a newer one.
27
+ 4. Any module that invokes an agent through the public run capability using a
28
+ trusted tenant, actor and permission snapshot.
29
+
30
+ ## Decision
31
+
32
+ Build module-owned business agents, but keep module-owned behavior separate
33
+ from tenant-owned execution configuration.
34
+
35
+ - A module registers a frozen definition with `defineAgent()` during server
36
+ composition.
37
+ - The platform carries a generic agent definition registry in the composition
38
+ context. It is created and sealed by the platform, not by `agents.core`.
39
+ - `defineAgent()` and the semantic agent types are exported by
40
+ `@flowdular/sdk/modules/agents/server`. A module using them declares `agents.core`
41
+ as a module dependency and `@flowdular/sdk/modules/agents` as a package dependency.
42
+ - Module source owns identity, display copy, instructions, maximum tool
43
+ allowlist and execution limits.
44
+ - Each tenant owns a binding that selects an available provider and model,
45
+ chooses active or paused state, and may reduce the code tool allowlist.
46
+ - Module-owned behavior is read-only in the Agents UI. Tenant binding fields
47
+ remain editable under `agents.definitions.manage`.
48
+ - Tenant-created definitions keep their current lifecycle and appear separately
49
+ from module-owned agents.
50
+
51
+ The 0.7.0 specification is approved. Runtime, migrations, UI, and module
52
+ integrations implement this contract together.
53
+
54
+ ## Consumer call sites
55
+
56
+ ### A module defines and registers an agent
57
+
58
+ ```ts
59
+ // modules/catalog/src/agent/agents.ts
60
+ import { defineAgent } from '@flowdular/sdk/modules/agents/server';
61
+
62
+ export const catalogCurator = defineAgent({
63
+ moduleId: 'catalog.core',
64
+ key: 'catalog-curator',
65
+ definitionRevision: 1,
66
+ name: 'Catalog curator',
67
+ description: 'Normalizes and enriches catalog items.',
68
+ instructions:
69
+ 'Review the requested catalog records. Use only the tools available to you.',
70
+ allowedTools: ['catalog.item.create', 'catalog.item.list'],
71
+ limits: {
72
+ maxSteps: 8,
73
+ timeoutMs: 120_000,
74
+ temperature: 0.2,
75
+ maxOutputTokens: 4_096,
76
+ },
77
+ });
78
+ ```
79
+
80
+ ```ts
81
+ // modules/catalog/src/platform.ts
82
+ context.agentDefinitions.register([catalogCurator]);
83
+ ```
84
+
85
+ The module does not choose credentials, a provider connection or a model. Those
86
+ are tenant deployment choices and never belong in a distributable business
87
+ agent definition.
88
+
89
+ ### agents.core consumes the sealed registry
90
+
91
+ ```ts
92
+ const runtime = createAgentRuntime({
93
+ moduleAgents: () => context.agentDefinitions.list(),
94
+ tools: () => context.agentTools.list(),
95
+ // existing options
96
+ });
97
+ ```
98
+
99
+ The registry is read when `start()` runs, after every module has composed and
100
+ the platform has sealed both registries.
101
+
102
+ ### A module invokes an agent
103
+
104
+ ```ts
105
+ await runQueue.enqueue(
106
+ {
107
+ agentId,
108
+ trigger: 'service',
109
+ input,
110
+ toolGrants: ['catalog.item.list'],
111
+ idempotencyKey,
112
+ },
113
+ {
114
+ tenantId: principal.tenantId,
115
+ actor,
116
+ permissionSnapshot: principal.scopes,
117
+ },
118
+ );
119
+ ```
120
+
121
+ The tenant and authority are trusted context, never input fields. An omitted
122
+ `toolGrants` list means no tools, not every tool.
123
+
124
+ ## Public contract
125
+
126
+ The semantic surface belongs to `@flowdular/sdk/modules/agents/server`:
127
+
128
+ ```ts
129
+ export interface ModuleAgentDefinitionInput {
130
+ readonly moduleId: string;
131
+ readonly key: string;
132
+ readonly definitionRevision: number;
133
+ readonly name: string;
134
+ readonly description: string;
135
+ readonly instructions: string;
136
+ readonly allowedTools: readonly string[];
137
+ readonly limits: {
138
+ readonly maxSteps: number;
139
+ readonly timeoutMs: number;
140
+ readonly temperature: number;
141
+ readonly maxOutputTokens: number;
142
+ };
143
+ }
144
+
145
+ export interface ModuleAgentDefinition
146
+ extends Readonly<ModuleAgentDefinitionInput> {
147
+ readonly id: string;
148
+ readonly ownership: {
149
+ readonly kind: 'module';
150
+ readonly moduleId: string;
151
+ readonly definitionRevision: number;
152
+ };
153
+ }
154
+
155
+ export function defineAgent(
156
+ input: ModuleAgentDefinitionInput,
157
+ ): ModuleAgentDefinition;
158
+ ```
159
+
160
+ `id` is derived as `module-agent:<moduleId>:<key>` and is limited to 128
161
+ characters. The prefix is reserved and tenant-created agents cannot use it.
162
+ Callers never supply or parse this id. They treat it as opaque after
163
+ registration.
164
+
165
+ The generic registry belongs to `@flowdular/sdk/kernel` so auth and the composition
166
+ contract do not import `agents.core`:
167
+
168
+ ```ts
169
+ export interface PlatformAgentRegistry<T = unknown> {
170
+ register(definitions: readonly T[]): void;
171
+ list(): readonly T[];
172
+ }
173
+
174
+ export interface MutablePlatformAgentRegistry<T>
175
+ extends PlatformAgentRegistry<T> {
176
+ seal(): void;
177
+ }
178
+
179
+ export function createPlatformAgentRegistry<
180
+ T extends { readonly id: string },
181
+ >(): MutablePlatformAgentRegistry<T>;
182
+ ```
183
+
184
+ `PlatformServerContext` gains:
185
+
186
+ ```ts
187
+ readonly agentDefinitions: PlatformAgentRegistry;
188
+ ```
189
+
190
+ The platform creates the registry before module composition and calls `seal()`
191
+ after every module has composed but before any module `start()` hook. Duplicate
192
+ ids fail registration. Registration after sealing fails. A sealed `list()` is
193
+ sorted by id and returns an immutable snapshot.
194
+
195
+ ## Ownership and served state
196
+
197
+ The API exposes ownership as a discriminated union:
198
+
199
+ ```ts
200
+ export type AgentOwnership =
201
+ | { readonly kind: 'tenant' }
202
+ | {
203
+ readonly kind: 'module';
204
+ readonly moduleId: string;
205
+ readonly definitionRevision: number;
206
+ };
207
+ ```
208
+
209
+ A tenant-created agent keeps its positive `revision`. A module-owned agent also
210
+ has a tenant-local positive executable `revision` after binding. Before binding,
211
+ it is served with `status: 'unconfigured'` and no executable revision. Workflow
212
+ catalogs exclude unconfigured agents.
213
+
214
+ The Agents screen presents two explicit groups:
215
+
216
+ - Module agents: module, definition revision, provider binding, model, status,
217
+ enabled tools and unavailable reasons. Behavior fields are read-only.
218
+ - Custom agents: the existing tenant-created agent table and full create,
219
+ update, archive and eligible-delete lifecycle.
220
+
221
+ Calling the current tenant-agent update, archive or delete operation with a
222
+ module-owned id returns `MODULE_AGENT_READ_ONLY`. Binding changes use a separate
223
+ operation so a careless client cannot replace module behavior while appearing
224
+ to edit deployment configuration.
225
+
226
+ ## Tenant binding and executable revisions
227
+
228
+ The tenant binding contains:
229
+
230
+ ```ts
231
+ export interface ModuleAgentBinding {
232
+ readonly tenantId: string;
233
+ readonly agentId: string;
234
+ readonly provider: string;
235
+ readonly model: string;
236
+ readonly enabledTools: readonly string[];
237
+ readonly status: 'active' | 'paused';
238
+ readonly moduleDefinitionRevision: number;
239
+ readonly executableRevision: number;
240
+ readonly revision: number;
241
+ readonly updatedBy: string;
242
+ readonly updatedAt: number;
243
+ }
244
+ ```
245
+
246
+ `revision` is the optimistic concurrency revision of the mutable binding.
247
+ `executableRevision` is the monotonic revision referenced by runs and workflows.
248
+ Creating a binding, changing provider or model, changing enabled tools, or
249
+ receiving a higher module definition revision creates a new immutable executable
250
+ snapshot. Pausing alone changes availability and audit state without rewriting
251
+ an existing snapshot.
252
+
253
+ The immutable snapshot extends the existing retained revision with ownership and
254
+ module definition revision. It contains the resolved provider, model,
255
+ instructions, exact enabled tools and limits. It is the only source for an
256
+ exact-revision run.
257
+
258
+ At runtime start, `agents.core` reconciles registered definitions against
259
+ existing bindings in one transaction:
260
+
261
+ - same definition revision and same content hash is unchanged;
262
+ - higher definition revision creates the next executable revision for each
263
+ existing binding;
264
+ - same definition revision with a different hash fails boot;
265
+ - a lower definition revision fails boot;
266
+ - a definition absent from the sealed registry is unavailable for new work;
267
+ retained revisions and historical runs remain untouched.
268
+
269
+ An old retained revision remains executable after a newer module definition is
270
+ registered only while the owning module is still present, the selected provider
271
+ is usable, and every required registered tool still exists. Module removal is
272
+ not promised to keep new workflow executions alive.
273
+
274
+ ## Tool authority
275
+
276
+ Agent access is a capability intersection, not an instruction convention.
277
+
278
+ For a tenant-created agent:
279
+
280
+ ```text
281
+ effective tools = definition allowedTools
282
+ intersect invocation toolGrants
283
+ intersect registered tools allowed by actor permissions
284
+ ```
285
+
286
+ For a module-owned business agent:
287
+
288
+ ```text
289
+ effective tools = code allowedTools
290
+ intersect tenant binding enabledTools
291
+ intersect invocation toolGrants
292
+ intersect registered tools allowed by actor permissions
293
+ ```
294
+
295
+ The permission term means every `requiredPermissions` entry declared by the
296
+ tool exists in the trusted permission snapshot captured at enqueue. Tool ids are
297
+ exact identifiers. `*`, prefix patterns and implicit all-tools defaults are
298
+ invalid. A grant outside the agent maximum is refused. A missing permission
299
+ removes the tool before provider execution and a later invocation is denied
300
+ before the tool body runs.
301
+
302
+ The model never receives `PlatformCapabilityRegistry`. Platform capabilities
303
+ are typed module-to-module services. Model-visible authority is only the
304
+ registered tool surface enforced by the harness.
305
+
306
+ Every run persists the effective tool ids and permission digest used for that
307
+ decision. The existing short-lived run grant remains bound to both digests.
308
+
309
+ ## Workflow compatibility
310
+
311
+ `agents.run-execution.v2` continues to use `{ agentId, revision }`. For a
312
+ module-owned agent, `revision` means the tenant executable revision, not the code
313
+ definition revision or mutable binding revision.
314
+
315
+ Workflow publication receives only configured active executable revisions. A
316
+ published workflow keeps its exact retained snapshot after a module publishes a
317
+ higher code revision or a tenant changes the current provider binding. Newly
318
+ published workflows select the new current executable revision.
319
+
320
+ Changing the ownership discriminator is additive for list consumers. Existing
321
+ tenant revisions are adopted as `{ kind: 'tenant' }`. Existing workflow rows do
322
+ not change shape.
323
+
324
+ ## Guarantees
325
+
326
+ - Module agent identity is stable for one module id and key.
327
+ - Business-agent definition content is immutable within one definition
328
+ revision.
329
+ - Duplicate ids, late registration, revision downgrade and same-revision content
330
+ drift fail platform boot before workers start.
331
+ - Module behavior cannot be edited or deleted through tenant APIs.
332
+ - Tenant bindings cannot enable a tool outside the code allowlist.
333
+ - Every execution is tenant-scoped and uses the initiating Actor and trusted
334
+ permission snapshot.
335
+ - Workflow execution uses the exact retained executable revision it published.
336
+ - Completed runs, revisions and audit evidence survive module removal.
337
+ - No credentials or provider secrets enter a code definition, binding response,
338
+ run event or audit payload.
339
+
340
+ ## Deliberately unspecified
341
+
342
+ - The database table layout and whether reconciliation uses one or several
343
+ internal transactions.
344
+ - The visual grouping control used by the Agents screen.
345
+ - Internal hashes and serialization used to detect definition content drift.
346
+ - Whether a future release offers bulk binding APIs or module installation
347
+ defaults.
348
+ - Ordering before the registry is sealed. Consumers may rely only on the sealed
349
+ id order.
350
+ - Automatic migration of a binding when its selected provider or a required
351
+ tool disappears. Version one reports the agent unavailable and requires an
352
+ operator decision.
353
+
354
+ ## Lifecycle and errors
355
+
356
+ - `defineAgent()` validates and freezes one value. Calling it has no I/O.
357
+ - Registration is valid only during module composition.
358
+ - Double registration and registration after seal are programmer errors and
359
+ throw synchronously.
360
+ - `list()` after seal is read-only and repeatable.
361
+ - Binding mutations use optimistic concurrency and audit the user actor.
362
+ - Runs already durably queued continue from their snapshot when a binding is
363
+ paused or the module reloads.
364
+ - New runs refuse `unconfigured`, `paused`, missing-provider, stale-readiness,
365
+ missing-tool and missing-permission states with stable codes.
366
+ - Shutdown disposes workers as it does today. The registry owns no timers,
367
+ connections or callbacks.
368
+
369
+ ## Stability and evolution
370
+
371
+ This surface is experimental with `agents.core` 0.7.0. Identity and revision
372
+ semantics are one-way serialized contracts because workflows and run history
373
+ store them. They require compatibility tests before the surface can become
374
+ stable.
375
+
376
+ Additive fields belong in the options object. New binding controls must default
377
+ to further restriction, never broader authority. Wildcard grants are excluded
378
+ from future compatibility.
379
+
380
+ ## Challenge result
381
+
382
+ ### Strongest case for the feature
383
+
384
+ The feature removes a real manual copy between a module and tenant data. It lets
385
+ a module ship a ready business agent and its tools together while keeping
386
+ credentials and tenant authority outside the distributable definition. Catalog
387
+ and workflows are current, concrete consumers.
388
+
389
+ ### Alternatives rejected
390
+
391
+ 1. Module migrations insert rows into `agents.core`. This crosses a module
392
+ database boundary, needs tenant enumeration, creates unclear uninstall
393
+ behavior and lets code mutate another module's storage.
394
+ 2. `module.json` embeds agent definitions. This turns long instructions into
395
+ manifest data, duplicates runtime validation, and still needs a registry and
396
+ tenant provider binding.
397
+ 3. A module ships a tenant-agent template with a Copy button. This is simpler,
398
+ but the copy immediately loses module ownership, safe upgrades and exact
399
+ revision lineage. It does not solve the stated problem.
400
+ 4. Code pins provider and model. This avoids a binding table but makes modules
401
+ non-portable and can name a connection that does not exist in another tenant.
402
+
403
+ ### Cost and failure modes
404
+
405
+ Boot registration is O(d) time and O(d) memory for d current module definitions.
406
+ Tenant listing is O(d + a) for d module definitions and a tenant agents. Storage
407
+ grows O(b \* r) for bindings b and retained executable revisions r, which is the
408
+ same deliberate append-only cost already accepted for exact workflow revisions.
409
+
410
+ The largest blast radius is a bad reconciliation that advances many tenant
411
+ bindings during boot. The mitigation is content-addressed comparison, a
412
+ transactional repository operation, same-revision drift refusal, fault-injection
413
+ rollback tests and no deletion of retained rows.
414
+
415
+ The strongest surviving objection is operational setup: a module-owned agent is
416
+ not runnable until each tenant binds a provider and model. That friction is
417
+ intentional. Silent provider selection would make behavior non-portable and
418
+ would change published workflows without a new executable revision.
419
+
420
+ ### Verdict
421
+
422
+ Build the split definition and binding design. Do not build direct database
423
+ seeding or a code-pinned provider shortcut.
424
+
425
+ The falsifying experiment is a thin implementation with one catalog agent and
426
+ two tenants using different provider bindings. It must prove distinct tool
427
+ reductions, immutable workflow revisions across a code bump, and boot refusal
428
+ for same-revision content drift. If that cannot be done without module database
429
+ access or mutable workflow behavior, revise this ADR before expanding adoption.
@@ -0,0 +1,90 @@
1
+ # ADR 0008: asynchronous database adapter contract
2
+
3
+ Status: accepted; the SQLite half is superseded (2026-09)
4
+
5
+ > Superseded in part (2026-09): the contract, the leased provider and the v2
6
+ > ledger stand, but SQLite is no longer an adapter and the synchronous
7
+ > compatibility path is gone. Flowdular runs on PostgreSQL everywhere, embedded
8
+ > through PGlite outside production. See `docs/database-adapters.md`.
9
+
10
+ ## Decision
11
+
12
+ Flowdular uses the asynchronous, dialect-explicit contract in
13
+ `@flowdular/sdk/database` for new database adapter work. SQLite is the local adapter.
14
+ PostgreSQL is the first production adapter target through a structural driver
15
+ port owned by platform composition.
16
+
17
+ Transactions receive a callback-scoped session pinned to one connection.
18
+ Adapters own placeholder style, schema introspection, migration locking,
19
+ cancellation capability, pooling, and disposal. Modules own repository ports,
20
+ queries, and SQL for every dialect they support. The platform owns credentials
21
+ and gives modules leased handles through `DatabaseProvider`.
22
+
23
+ The existing synchronous SQLite repositories and kernel migration runner remain
24
+ supported during conversion. They are a compatibility path, not the contract
25
+ for PostgreSQL.
26
+
27
+ The package depends on `@flowdular/sdk/kernel` only for the existing checksum
28
+ algorithm, so v1 and v2 ledgers calculate identical hashes for identical SQL.
29
+ The kernel does not import `@flowdular/sdk/database`. A future
30
+ `PlatformServerContext` type may import the provider from this package at the
31
+ module composition layer without creating a package cycle.
32
+
33
+ ## Consumer call sites
34
+
35
+ The immediate consumers are existing SQLite module repositories. They can move
36
+ to `SqliteDatabaseAdapter` one module at a time without changing storage. The
37
+ named next consumer is a PostgreSQL deployment, which supplies a pool bridge and
38
+ the same `DatabaseHandle` to an asynchronous repository.
39
+
40
+ Migration authors provide an explicit SQL script per supported dialect and an
41
+ optional adapter-backed adoption inspection. The runner owns the namespaced
42
+ ledger, checksums, transaction, and migration lock.
43
+
44
+ ## Guarantees
45
+
46
+ - Query values are separate from SQL text.
47
+ - SQL is never translated between placeholder styles.
48
+ - A transaction uses one connection and its session cannot escape the callback.
49
+ - Migration checksum drift is checked before new SQL runs.
50
+ - Migration DDL and ledger rows commit or roll back together.
51
+ - Disposal is idempotent and drains accepted work.
52
+ - Capabilities describe cancellation, isolation, DDL, lock, and returning
53
+ behavior without version sniffing.
54
+
55
+ ## Deliberately unspecified
56
+
57
+ The contract does not standardize SQL syntax, database error codes, generated
58
+ identifier values, query planning, physical pool behavior, or row type parsing.
59
+ Repositories translate database-specific errors into domain errors at their own
60
+ boundary.
61
+
62
+ ## Challenge record
63
+
64
+ The strongest argument against this addition is conversion cost. Current
65
+ services and repositories are synchronous, so the adapter does not make the
66
+ existing application PostgreSQL-ready by itself. A narrow seam still earns its
67
+ cost because the production target is already PostgreSQL and retaining a
68
+ synchronous public port would make that target impossible.
69
+
70
+ Rejected alternatives:
71
+
72
+ 1. Extend the current structural `MigrationDatabase`. Its implementation relies
73
+ on `sqlite_master`, `PRAGMA`, `STRICT`, and `BEGIN IMMEDIATE`, and every method
74
+ is synchronous. Calling it neutral would preserve a false contract.
75
+ 2. Rewrite `?` placeholders to `$1`. SQL strings contain comments, literals,
76
+ operators, DDL types, and dialect features. Text replacement would corrupt
77
+ valid queries while hiding the real compatibility work.
78
+ 3. Put `pg` pools and DSNs in modules. That duplicates pools, exposes secrets,
79
+ and makes teardown and production policy impossible to enforce centrally.
80
+ 4. Adopt an ORM now. It would add a second query and migration system before one
81
+ reference module proves that abstraction is needed.
82
+
83
+ ## Follow-up required for production PostgreSQL
84
+
85
+ Add `pg` to the deployable platform, create the secret-backed provider, inject
86
+ it into server composition, convert a reference module to asynchronous
87
+ repositories, add PostgreSQL integration tests, and run its migrations against
88
+ an empty database plus an upgraded snapshot. Until that work lands, PostgreSQL
89
+ is an implemented adapter seam rather than the application's selected production
90
+ database.
@@ -0,0 +1,45 @@
1
+ # Agent implementation reference
2
+
3
+ Lookup only. The always-active contract lives in `.ai/rules/flowdular.md`.
4
+ Use one task skill; consult only the relevant section here, not the whole file.
5
+
6
+ Flowdular is an agentic foundation framework. It ships the foundation platform (accounts, workspaces, permissions, modules, agents runtime, CLI, sandbox) and people build their own platform on top of it: in the sandbox with AI specialists, or with the skills in `.ai/skills` inside their own coding tool. This contract and the skills are the shared RuleSync sources for every supported coding agent. Spec-first is a working rule here: a module is created only from an approved `spec/module.yaml`.
7
+
8
+ Use the already selected task skill. Consult `.ai/references/catalog` for implementation examples and `docs/design-system.md` for visual work only when the current task needs them.
9
+
10
+ ## Rules
11
+
12
+ 1. Read the owning code end to end before changing it. Copy the shape of `.ai/references/catalog`; do not invent architecture, permissions, entities, routes, or dependencies. Stop when required input is missing or contradictory and say exactly what you need.
13
+ 2. Write only inside the paths your role or blueprint names. In the sandbox these paths are advisory; a reviewer treats a write elsewhere as a defect.
14
+ 3. Identifiers: module, permission and capability ids match `^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)+$`. `inventory.core` lives in `modules/inventory` as `@flowdular/module-inventory`; permissions are `<module>.<entity>.read` and `<module>.<entity>.manage`.
15
+ 4. A module is created only from a spec with `status: approved`. An agent never initiates, infers, or grants approval from its own judgment. After a current, explicit user instruction naming the spec, a host coding agent may record that decision mechanically by following `spec-approval`; a sandbox specialist can only request approval, and the operator route records the exact approved hash. Spec `permissions[].id` equal the constants in `src/acl/permissions.ts`: the spec is what `auth sync-scopes` grants.
16
+ 5. Every endpoint is `defineEndpoint` from `@flowdular/sdk/server` with `access: { kind: 'permission', permission }` and `resolveIdentity: endpointIdentityFromContext`. Deny by default; a public endpoint needs a written reason. No raw `new ServerRoute` outside `modules/auth`.
17
+ 6. The tenant id comes only from `principalFromContext(octane)!.tenantId`, never from the body, query or headers. Every query on a tenant-owned table filters by `tenant_id`; unique constraints and indexes start with `tenant_id`; SQL uses bound parameters. PostgreSQL tenant tables also enable and force row-level security with `USING` and `WITH CHECK` policies bound to transaction-local `coreloom.tenant_id`. Every repository operation runs through `database.transaction(..., { tenantId, access })`; the runtime role is never a superuser and never has `BYPASSRLS`, while a separate migration lease may own DDL. `WHERE tenant_id = ...` remains defense in depth.
18
+ 7. Every mutation calls `sessionMutationDenial(octane, auth)` first and reads its body with `readJsonObject` plus `requiredString`, `optionalString`, `requiredInteger`. Clients send `content-type: application/json`, `x-csrf-token`, and `credentials: 'same-origin'`.
19
+ 8. Routes mount only through `src/platform.ts` exporting `createServerComposition(context)` with `platform.server: true` in `module.json` and a `./platform` export in `package.json`; the context carries `auth`, `settings`, `agentTools`, `agentDefinitions`, `capabilities` and `databases`. A database module passes `context.databases` into one runtime, which acquires and releases one provider lease lazily; `prepare` stays read-only and never opens a database. A composition may return `settings`, read-only `prepare`, `start`, background-work `stop`, and final `dispose`. Client contributions mount only through `createClientContribution(context)` in `src/client/index.ts` with `platform.client: true`. `pnpm flowdular module validate` fails on a missing entry (`PLATFORM_*`).
20
+ 9. Never edit the composition by hand: `platform/octane.config.ts`, `platform/src/App.tsrx`, `platform/src/generated/**`, `platform/package.json` dependencies and `modules.enabled` in `flowdular.json` are written by `pnpm flowdular module enable <id> --apply` and `pnpm flowdular module sync --apply`.
21
+ 10. `pnpm flowdular module enable <id> --apply` grants the spec permissions to every tenant owner as its last step; `pnpm flowdular auth sync-scopes --module <id> --apply` re-grants later (new permission, another database). Members receive scopes only through `MEMBER_SCOPES` in `modules/auth/src/acl/scopes.ts`, a core change.
22
+ 11. Declare every imported package in the module `package.json`; the sandbox `dependencies` gate and the eject fail otherwise. Every relative import carries its `.ts` or `.tsrx` extension.
23
+ 12. Use the CLI for discovery, validation and scaffolding: `doctor`, `spec validate`, `module validate`, `module new`, `module enable`, `auth sync-scopes`. Run destructive, external or production capabilities only with what the runner demands (`--apply`, `--confirm`, `--spec`) and never work around a refusal.
24
+ 13. Gates are `spec-schema`, `module-schema`, `dependencies`, `typecheck`, `tests`, `format`. The sandbox runs `dependencies` plus the ones your role lists after every turn, per draft module, and feeds a failure back to you; with a shell you may run the module's own gate commands yourself, never installs, network or git. From a checkout run them yourself and `pnpm verify` before any pull request.
25
+ 14. Build UI only from `@flowdular/sdk/ui` components, `ui-*` classes and tokens (`docs/design-system.md`). No hardcoded colors, fonts or sizes; never restyle a `ui-*` class; `glyph` and `Icon name` are `ICON_PATHS` keys. Modules use the shared `Table` and `TableCard`, which are backed by the official Octane TanStack adapter; they never import `@octanejs/tanstack-table` directly. A missing primitive becomes a module-local component on tokens, flagged as a promotion candidate. Guard UX: no visual artifacts. A card head is one line (title left; search and the `Filters` dropdown right), filters live inside `Filters` not loose in the head, form rows top-align so a `help` line never drops its neighbour, a field is labelled once, no decorative tags, long values use `ui-mono`/`ui-table-wrap`, adjacent top-level nodes go in a fragment. Look at the rendered screen before handing off and fix any alignment, wrapping, padding or duplicated-label glitch.
26
+ 15. One screen, form, table or stateful region per named component. Records own the page; create and edit happen in a `Drawer`. Every screen shows loading, empty, error, populated and denied.
27
+ 16. Tests live in `tests/*.test.ts`: identity, tenant isolation, uniqueness, one 401 and one 403 per endpoint, each validation bound. Repository behavior uses `createTestDatabaseProvider()` from `@flowdular/sdk/database-testing`: PGlite locally and isolated server PostgreSQL in CI. Open one provider per test file, migrate once, and truncate module tables between cases (`modules/profile/tests/support/database.ts`). Tenancy tests use two tenants, prove `TENANT_CONTEXT_REQUIRED` without a transaction tenant id, prove RLS prevents cross-tenant reads and writes under the non-bypass runtime role, and cover `WITH CHECK`. Tenant fixture work also supplies tenant context on a migration connection. The sandbox `tests` gate passes with zero tests, so an empty suite is a defect.
28
+ 17. Translations are live. Every module contribution registers all declared `translations/*.json` bundles, user-facing copy uses fully qualified `t('<module>.<key>')` keys, navigation labels are lazy getters, locale-aware formatting uses `activeLocale()`, and every locale has the same key set. `module validate` rejects missing files, key drift, and missing static translation keys.
29
+ 18. Numbered migration SQL is immutable source. `migrations/000N_<module>_<name>.up.sql` and `.down.sql` are PostgreSQL and the only schema source; there is no dialect subdirectory. `src/services/migration.ts` mirrors every `.up.sql` byte for byte as `databaseMigrations: readonly DatabaseMigration[]` with `sql: { postgresql: ... }`, and the runtime calls `runDatabaseMigrations` through its provider lease. The namespaced `_coreloom_migrations_v2` ledger records the checksum, adopts only an explicit complete `inspectExisting` result (`postgresTenantTableState` is the standard check), and refuses drift, duplicates, or partial schema. Add a new numbered, additive migration instead of changing existing bytes. A tenant table's migration includes enabled and forced RLS plus a tenant policy, with the policy behavior covered by tests.
30
+ 19. Module CLI commands live in `src/cli/commands.json` and `src/cli/index.ts`, metadata-identical, inside the module namespace.
31
+ 20. Passwords, session tokens and provider credentials never leave `auth.core` (or the `agents.core` vault) and never appear in logs, audit metadata or responses.
32
+ 21. `setup quick` and `auth greenfield` are destructive local resets. Preview first, stop the app, never point them at a custom or deployed database.
33
+ 22. Agent workers reach ERP data only through registered API or CLI tools. A module defines them with `defineApiAgentTool` or `defineCliAgentTool` from `@flowdular/sdk/harness/tool-adapters` and registers them inside `createServerComposition` with `context.agentTools.register([...])`; nothing else registers a tool. A module may also ship business agents with `defineAgent()` from `@flowdular/sdk/modules/agents/server` and `context.agentDefinitions.register([...])` after declaring an `agents.core` dependency. Their code allowlist is only a maximum: effective tools are the exact intersection of that allowlist, the tenant binding reduction, invocation grants, registered tool permissions, the actor's saved permission ceiling, and live authorization. Sandbox coding specialists are not business agents.
34
+ 23. A background run is persisted before enqueue returns; idempotency, leases, recovery, tenant scoping and append-only audit evidence for every fire-and-forget run.
35
+ 24. Module settings are declared with `defineModuleSettings` from `@flowdular/sdk/kernel`, returned as `settings` from the composition, read live with `context.settings.get(tenantId, '<module>.core', key)`, and rendered in that module's drawer under Administration, Modules. User-facing setting copy declares fully qualified `labelKey` and `descriptionKey` present in every module locale, with English `label` and `description` literals as compatibility fallbacks. Values, identifiers and secrets are never translated. Administration, Settings is only for workspace and organization settings. A cross-module setting read needs a declared dependency and a `shared`, non-secret setting. Cross-module operations use a typed public service registered in `context.capabilities` by the owning module and resolved by a declared dependent, never the other module's database.
36
+ 25. `Development` navigation is owner-only in the client; server permissions remain authoritative.
37
+ 26. Generated files are production code: no placeholders, silent fallbacks or skipped tests. `module.json` `version`, spec `specVersion` and `package.json` `version` move together.
38
+ 27. Commits and pull requests: short body, one line on verification, no AI attribution footers, generated files only through the CLI. Never use em or en dashes in anything you write.
39
+ 28. End a sandbox turn with one line: `HANDOFF: <role-id> - <why>` or `HANDOFF: none - <why>`. The role must be in your role's `handoff` list and never yourself; otherwise the sandbox routing decides.
40
+
41
+ ## Sequence
42
+
43
+ Sandbox: brief, planner picks all affected modules and the first role, specification or spec delta per module, operator approval of each exact spec hash, specialist turns with gates per changed module, scaffold when needed, eject (fresh spec-hash check, gates, copy and removals, `pnpm install`, `module enable` with scope grant for new modules, `auth sync-scopes`, platform typecheck, restart note), pull request. A host agent may invoke the operator approval action only after the user explicitly delegates that exact approval through `spec-approval`.
44
+
45
+ Checkout: read the skill, approved spec, `module new` dry run then `--apply`, implement, gates, `module enable --apply` (grants scopes), `pnpm verify`, pull request.