@ultimat3/cli 29.4.0 → 30.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/CLAUDE.md +64 -40
  2. package/README.md +61 -11
  3. package/package.json +42 -28
  4. package/src/affected-tests.ts +97 -0
  5. package/src/affected-unowned.ts +43 -0
  6. package/src/affected.ts +25 -6
  7. package/src/app-boundaries.ts +29 -1
  8. package/src/app-evals.ts +12 -4
  9. package/src/app-load-unresolved.ts +62 -0
  10. package/src/app-load.ts +30 -37
  11. package/src/app-mcp.ts +14 -2
  12. package/src/app-module-graph.ts +232 -0
  13. package/src/app-reload-graph.ts +2 -2
  14. package/src/app-root.ts +37 -1
  15. package/src/bin.ts +1 -0
  16. package/src/boundary-findings.ts +6 -0
  17. package/src/budgets-freshness.ts +32 -0
  18. package/src/budgets.ts +20 -1
  19. package/src/build-capture-env.ts +9 -0
  20. package/src/cdp-shot-a11y.ts +2 -39
  21. package/src/ci-tested.ts +243 -0
  22. package/src/client-emit-customer-runtime.ts +139 -0
  23. package/src/client-emit-customer.ts +108 -0
  24. package/src/client-emit-drift.ts +72 -0
  25. package/src/client-emit-header.ts +67 -0
  26. package/src/client-emit-schemas.ts +175 -0
  27. package/src/client-emit-types.ts +121 -0
  28. package/src/client-emit-vendor.ts +146 -0
  29. package/src/client-errors-routes.ts +229 -0
  30. package/src/client-errors-script.ts +74 -0
  31. package/src/client-vitals-route.ts +197 -0
  32. package/src/client-vitals-script.ts +56 -0
  33. package/src/cmd-affected.ts +23 -0
  34. package/src/cmd-build-spec.ts +7 -1
  35. package/src/cmd-build.ts +35 -9
  36. package/src/cmd-ci-spec.ts +42 -6
  37. package/src/cmd-ci.ts +99 -2
  38. package/src/cmd-client-customer.ts +134 -0
  39. package/src/cmd-client-source.ts +81 -0
  40. package/src/cmd-client-spec.ts +48 -0
  41. package/src/cmd-client-write.ts +41 -0
  42. package/src/cmd-client.ts +111 -0
  43. package/src/cmd-db-recount.ts +120 -0
  44. package/src/cmd-db-spec.ts +36 -6
  45. package/src/cmd-db.ts +11 -3
  46. package/src/cmd-deploy-compose.ts +61 -3
  47. package/src/cmd-deploy-drain.ts +10 -2
  48. package/src/cmd-deploy-helm.ts +11 -0
  49. package/src/cmd-deploy-preflight.ts +118 -0
  50. package/src/cmd-deploy-spec.ts +58 -6
  51. package/src/cmd-deploy-verify.ts +380 -0
  52. package/src/cmd-deploy.ts +42 -9
  53. package/src/cmd-docs.ts +34 -4
  54. package/src/cmd-doctor.ts +66 -9
  55. package/src/cmd-drill-spec.ts +25 -0
  56. package/src/cmd-drill.ts +176 -0
  57. package/src/cmd-env-init.ts +102 -0
  58. package/src/cmd-env-spec.ts +10 -3
  59. package/src/cmd-env.ts +15 -10
  60. package/src/cmd-errors-recent.ts +60 -0
  61. package/src/cmd-errors-spec.ts +9 -1
  62. package/src/cmd-errors.ts +4 -0
  63. package/src/cmd-exercise-spec.ts +19 -0
  64. package/src/cmd-exercise.ts +129 -0
  65. package/src/cmd-generate-spec.ts +9 -1
  66. package/src/cmd-generate.ts +32 -27
  67. package/src/cmd-graph-load.ts +97 -0
  68. package/src/cmd-graph-spec.ts +16 -0
  69. package/src/cmd-graph.ts +73 -0
  70. package/src/cmd-i18n.ts +4 -1
  71. package/src/cmd-impact-spec.ts +13 -0
  72. package/src/cmd-impact.ts +64 -0
  73. package/src/cmd-jobs-resolve.ts +76 -0
  74. package/src/cmd-jobs-spec.ts +21 -2
  75. package/src/cmd-jobs.ts +10 -6
  76. package/src/cmd-mail-spec.ts +28 -0
  77. package/src/cmd-mail.ts +70 -0
  78. package/src/cmd-mcp-lock.ts +69 -0
  79. package/src/cmd-mcp-spec.ts +23 -4
  80. package/src/cmd-mcp.ts +17 -3
  81. package/src/cmd-new-spec.ts +8 -1
  82. package/src/cmd-new.ts +61 -9
  83. package/src/cmd-planned.ts +0 -6
  84. package/src/cmd-repro-spec.ts +31 -0
  85. package/src/cmd-repro.ts +174 -0
  86. package/src/cmd-stop-spec.ts +21 -0
  87. package/src/cmd-stop.ts +166 -0
  88. package/src/cmd-test-spec.ts +17 -4
  89. package/src/cmd-test.ts +70 -14
  90. package/src/cmd-upgrade-spec.ts +26 -0
  91. package/src/cmd-upgrade.ts +274 -0
  92. package/src/cmd-verify-spec.ts +3 -3
  93. package/src/db-backfill.ts +6 -0
  94. package/src/db-diagnostics.ts +106 -0
  95. package/src/db-generate.ts +9 -0
  96. package/src/db-reset-template.ts +1 -1
  97. package/src/db-rolling.ts +45 -0
  98. package/src/db-seed-generate.ts +188 -0
  99. package/src/deploy-verify-findings.ts +98 -0
  100. package/src/deploy-verify-flags.ts +109 -0
  101. package/src/deploy-verify-grade.ts +185 -0
  102. package/src/deploy-verify-queues.ts +53 -0
  103. package/src/dev-boot.ts +35 -15
  104. package/src/dev-child-watch.ts +16 -4
  105. package/src/dev-dashboard-guard.ts +8 -1
  106. package/src/dev-dashboard.ts +7 -0
  107. package/src/dev-lock-identity.ts +61 -0
  108. package/src/dev-lock-port-holder.ts +80 -0
  109. package/src/dev-lock-steal.ts +124 -0
  110. package/src/dev-lock.ts +92 -120
  111. package/src/dev-mail-templates.ts +51 -0
  112. package/src/dev-rebuild.ts +26 -2
  113. package/src/dev-route-table.ts +17 -0
  114. package/src/dev-supervisor.ts +5 -2
  115. package/src/dev-watch-tree.ts +11 -10
  116. package/src/dev-watch.ts +1 -1
  117. package/src/dispatch.ts +29 -6
  118. package/src/docs-section.ts +69 -0
  119. package/src/docs-sources.ts +100 -0
  120. package/src/doctor-auth.ts +11 -2
  121. package/src/doctor-chart-alerts.ts +55 -0
  122. package/src/doctor-pooler.ts +107 -0
  123. package/src/doctor-rolling.ts +35 -0
  124. package/src/doctor-row-security.ts +40 -0
  125. package/src/document-options.ts +13 -0
  126. package/src/drill-sync-lane.ts +25 -0
  127. package/src/drill-targets.ts +39 -0
  128. package/src/duplicate-packages.ts +1 -1
  129. package/src/env-production.ts +93 -0
  130. package/src/error-codes-shot.ts +59 -0
  131. package/src/error-codes-tooling.ts +29 -0
  132. package/src/error-codes.ts +100 -54
  133. package/src/error-contract.ts +2 -2
  134. package/src/errors.ts +22 -3
  135. package/src/exercise-database.ts +99 -0
  136. package/src/exercise-findings.ts +159 -0
  137. package/src/exercise-overrides.ts +42 -0
  138. package/src/exercise-registration.ts +58 -0
  139. package/src/exercise-static.ts +88 -0
  140. package/src/exercise-subject.ts +69 -0
  141. package/src/failure-capture-boot.ts +30 -0
  142. package/src/framework-env.ts +7 -1
  143. package/src/framework-schema.ts +72 -5
  144. package/src/generate-catalog-locales.ts +19 -0
  145. package/src/generate-chart-alerts.ts +156 -0
  146. package/src/generate-feature-required.ts +65 -0
  147. package/src/generate-feature.ts +83 -6
  148. package/src/generate-files.ts +24 -0
  149. package/src/generate-format-written.ts +32 -0
  150. package/src/generate-kinds.ts +6 -0
  151. package/src/generate-sign-in-config.ts +100 -0
  152. package/src/generate-sign-in-manifest.ts +28 -0
  153. package/src/generate-sign-in-mode.ts +101 -0
  154. package/src/generate-sign-in.ts +250 -0
  155. package/src/generate-write.ts +44 -7
  156. package/src/hand-rolled-socket.ts +72 -0
  157. package/src/i18n-app-key-shapes.ts +29 -0
  158. package/src/i18n-audit.ts +10 -3
  159. package/src/i18n-registration.ts +18 -3
  160. package/src/index.ts +2 -0
  161. package/src/island-bundle.ts +4 -3
  162. package/src/island-disposer.ts +116 -0
  163. package/src/island-realtime-state.ts +34 -6
  164. package/src/island-realtime.ts +6 -2
  165. package/src/island-routes.ts +3 -2
  166. package/src/isr-query-advice.ts +6 -11
  167. package/src/isr-query-guard.ts +4 -3
  168. package/src/job-budget.ts +95 -0
  169. package/src/jobs-json.ts +11 -0
  170. package/src/lint-findings.ts +104 -0
  171. package/src/local-cli.ts +34 -4
  172. package/src/loopback-host.ts +2 -2
  173. package/src/mail-preview-findings.ts +24 -0
  174. package/src/mcp-errors.ts +82 -2
  175. package/src/mcp-host.ts +11 -1
  176. package/src/mcp-lock-findings.ts +57 -0
  177. package/src/measure-paths.ts +12 -4
  178. package/src/measure-scope.ts +27 -13
  179. package/src/messages-client.ts +23 -0
  180. package/src/messages-db.ts +56 -0
  181. package/src/messages-gate.ts +107 -0
  182. package/src/messages-repro.ts +11 -0
  183. package/src/messages-shot.ts +51 -0
  184. package/src/messages-upgrade.ts +45 -0
  185. package/src/messages.ts +53 -178
  186. package/src/metrics-endpoint.ts +23 -5
  187. package/src/new-shapes-generate.ts +71 -0
  188. package/src/new-shapes.ts +63 -0
  189. package/src/openapi-compile-ir.ts +68 -0
  190. package/src/openapi-compile-schema.ts +284 -0
  191. package/src/openapi-compile.ts +273 -0
  192. package/src/openapi-refuse.ts +45 -0
  193. package/src/otlp-export.ts +2 -1
  194. package/src/output-findings.ts +123 -0
  195. package/src/output.ts +32 -8
  196. package/src/package-boundaries.ts +110 -0
  197. package/src/page-pins.ts +23 -0
  198. package/src/plain-routes.ts +13 -0
  199. package/src/prerender-entries.ts +59 -0
  200. package/src/prerender-heaviest.ts +27 -0
  201. package/src/prerender-preload.ts +6 -0
  202. package/src/prerender-report.ts +12 -0
  203. package/src/prerender-seo-reads.ts +38 -0
  204. package/src/prerender-served.ts +22 -7
  205. package/src/prerender-vitals.ts +42 -0
  206. package/src/prerender.ts +61 -32
  207. package/src/pwa-artifacts.ts +4 -3
  208. package/src/pwa-manifest-locales.ts +1 -1
  209. package/src/registry.ts +18 -0
  210. package/src/repro-bundle.ts +65 -0
  211. package/src/repro-errors.ts +47 -0
  212. package/src/repro-job.ts +72 -0
  213. package/src/repro-literal.ts +41 -0
  214. package/src/repro-request.ts +48 -0
  215. package/src/repro-write.ts +100 -0
  216. package/src/retain-sweep.ts +27 -0
  217. package/src/retained-assets-boot.ts +113 -0
  218. package/src/retained-assets-layout.ts +110 -0
  219. package/src/retained-assets-read.ts +142 -0
  220. package/src/retained-assets-sweep.ts +70 -0
  221. package/src/retained-assets.ts +171 -0
  222. package/src/revalidated-response.ts +8 -5
  223. package/src/role-replicator.ts +7 -1
  224. package/src/role-start-devices.ts +119 -0
  225. package/src/role-start-types.ts +6 -0
  226. package/src/role-start.ts +22 -5
  227. package/src/role-sync.ts +7 -1
  228. package/src/route-islands.ts +42 -0
  229. package/src/route-table.ts +2 -1
  230. package/src/row-security-boot.ts +58 -0
  231. package/src/row-security-wanted.ts +32 -0
  232. package/src/runtime-admin.ts +0 -1
  233. package/src/runtime-assets-site-cache.ts +55 -0
  234. package/src/runtime-assets-site.ts +136 -0
  235. package/src/runtime-assets.ts +99 -55
  236. package/src/runtime-bindings.ts +19 -3
  237. package/src/runtime-cache.ts +23 -14
  238. package/src/runtime-isr-outcome.ts +114 -60
  239. package/src/runtime-purge.ts +14 -2
  240. package/src/runtime-queue.ts +31 -4
  241. package/src/runtime-render-document.ts +204 -0
  242. package/src/runtime-render.ts +48 -198
  243. package/src/runtime-replica-position.ts +62 -0
  244. package/src/runtime-replica.ts +18 -3
  245. package/src/runtime-s3-path-style.ts +17 -0
  246. package/src/runtime-services.ts +19 -6
  247. package/src/runtime-statement-bound.ts +22 -0
  248. package/src/runtime-storage-upload.ts +9 -0
  249. package/src/runtime-storage.ts +41 -81
  250. package/src/schema-diff-views.ts +54 -0
  251. package/src/schema-diff.ts +21 -3
  252. package/src/schema-drift.ts +28 -9
  253. package/src/schema-dump-drift.ts +91 -7
  254. package/src/script-csp.ts +1 -1
  255. package/src/seo-cards.ts +26 -0
  256. package/src/seo-routes.ts +22 -8
  257. package/src/serve-boot.ts +54 -21
  258. package/src/serve-drain.ts +1 -0
  259. package/src/serve-env.ts +26 -8
  260. package/src/serve-retire.ts +12 -6
  261. package/src/serve-web.ts +42 -4
  262. package/src/serve.ts +9 -7
  263. package/src/site-asset-routes.ts +7 -1
  264. package/src/site-config.ts +4 -0
  265. package/src/site-llms-pages.ts +106 -0
  266. package/src/site-llms.ts +64 -0
  267. package/src/site-seo-write.ts +4 -2
  268. package/src/site-seo.ts +55 -6
  269. package/src/source-mtime.ts +50 -0
  270. package/src/static-capture-errors.ts +41 -0
  271. package/src/static-capture.ts +56 -0
  272. package/src/static-cards-serve.ts +39 -0
  273. package/src/static-cards.ts +93 -0
  274. package/src/static-document.ts +14 -13
  275. package/src/static-images.ts +115 -0
  276. package/src/stream-hole-scope.ts +55 -0
  277. package/src/style-bundle.ts +1 -1
  278. package/src/style-routes.ts +3 -2
  279. package/src/sw-precache-plan.ts +2 -2
  280. package/src/sw-routes.ts +2 -2
  281. package/src/templates/action-tests.ts +306 -0
  282. package/src/templates/action.ts +81 -269
  283. package/src/templates/backfill.ts +1 -1
  284. package/src/templates/entity.ts +21 -5
  285. package/src/templates/github/ci.yml.ts +8 -9
  286. package/src/templates/guard-bare-error.ts +2 -2
  287. package/src/templates/guard-error-declared.ts +263 -0
  288. package/src/templates/guard-native-confirm.ts +132 -0
  289. package/src/templates/guard-raw-fetch.ts +151 -0
  290. package/src/templates/guard-raw-interval.ts +121 -0
  291. package/src/templates/guard-repo-raw-sql.ts +71 -2
  292. package/src/templates/job.ts +1 -1
  293. package/src/templates/naming.ts +5 -0
  294. package/src/templates/pinned/docker-compose.yml +6 -0
  295. package/src/templates/pinned-images.ts +8 -0
  296. package/src/templates/policy.ts +85 -2
  297. package/src/templates/query.ts +70 -13
  298. package/src/templates/resource-create.ts +3 -1
  299. package/src/templates/resource-form-island.ts +15 -4
  300. package/src/templates/resource-page-db.ts +83 -0
  301. package/src/templates/resource-page.ts +161 -52
  302. package/src/templates/route.ts +4 -6
  303. package/src/templates/scaffold-app.ts +3 -0
  304. package/src/templates/scaffold-auth.ts +2 -1
  305. package/src/templates/scaffold-bin.ts +5 -52
  306. package/src/templates/scaffold-claude-agents.ts +19 -19
  307. package/src/templates/scaffold-claude-commands.ts +28 -31
  308. package/src/templates/scaffold-claude.ts +26 -23
  309. package/src/templates/scaffold-container-compose.ts +6 -1
  310. package/src/templates/scaffold-container.ts +24 -4
  311. package/src/templates/scaffold-dashboard-bare.ts +3 -3
  312. package/src/templates/scaffold-dashboard-example-tests.ts +49 -9
  313. package/src/templates/scaffold-dashboard-example-view.ts +156 -0
  314. package/src/templates/scaffold-dashboard-example.ts +43 -131
  315. package/src/templates/scaffold-dashboard-shared.ts +3 -7
  316. package/src/templates/scaffold-db-client.ts +20 -6
  317. package/src/templates/scaffold-db-package.ts +5 -14
  318. package/src/templates/scaffold-docs.ts +73 -57
  319. package/src/templates/scaffold-domain-package.ts +18 -14
  320. package/src/templates/scaffold-entries.ts +7 -2
  321. package/src/templates/scaffold-exercise.ts +37 -0
  322. package/src/templates/scaffold-guards.ts +13 -1
  323. package/src/templates/scaffold-helm-alerts.ts +234 -0
  324. package/src/templates/scaffold-helm-templates.ts +7 -5
  325. package/src/templates/scaffold-helm.ts +46 -12
  326. package/src/templates/scaffold-i18n.ts +6 -2
  327. package/src/templates/scaffold-mcp-endpoint.ts +182 -0
  328. package/src/templates/scaffold-mcp-json.ts +31 -0
  329. package/src/templates/scaffold-mcp-package.ts +59 -56
  330. package/src/templates/scaffold-repo.ts +7 -2
  331. package/src/templates/scaffold-shell.ts +45 -79
  332. package/src/templates/scaffold-test-services.ts +13 -5
  333. package/src/templates/shapes/api-keys.ts +170 -0
  334. package/src/templates/shapes/api.ts +101 -0
  335. package/src/templates/shapes/blog-site.ts +340 -0
  336. package/src/templates/shapes/blog-slice.ts +265 -0
  337. package/src/templates/shapes/blog.ts +114 -0
  338. package/src/templates/shapes/dashboard-detail.ts +242 -0
  339. package/src/templates/shapes/dashboard.ts +53 -0
  340. package/src/templates/shapes/index.ts +17 -0
  341. package/src/templates/shapes/overlay.ts +99 -0
  342. package/src/templates/shapes/shared-edits.ts +46 -0
  343. package/src/templates/sign-in-action-tests.ts +237 -0
  344. package/src/templates/sign-in-authenticator.ts +112 -0
  345. package/src/templates/sign-in-oidc.ts +189 -0
  346. package/src/templates/sign-in-pages.ts +148 -0
  347. package/src/templates/sign-in-password.ts +216 -0
  348. package/src/templates/sign-in-shared.ts +268 -0
  349. package/src/templates/slice-foundation.ts +70 -15
  350. package/src/test-batches.ts +1 -1
  351. package/src/test-database.ts +1 -1
  352. package/src/test-shards.ts +7 -1
  353. package/src/test-workers.ts +18 -12
  354. package/src/tool-gate-names.ts +34 -0
  355. package/src/upgrade-agents-link.ts +49 -0
  356. package/src/upgrade-bun-floor.ts +225 -0
  357. package/src/upgrade-gate.ts +228 -0
  358. package/src/upgrade-pins.ts +63 -0
  359. package/src/upgrade-plan.ts +214 -0
  360. package/src/upgrade-registry.ts +53 -0
  361. package/src/upgrade-report.ts +139 -0
  362. package/src/upgrade-root.ts +74 -0
  363. package/src/verify-budgets-build.ts +118 -0
  364. package/src/verify-checks.ts +67 -24
  365. package/src/verify-coverage-run.ts +1 -1
  366. package/src/verify-e2e-lane.ts +41 -0
  367. package/src/verify-exercise.ts +64 -0
  368. package/src/verify-floor.ts +41 -0
  369. package/src/verify-merge.ts +19 -4
  370. package/src/verify-role-load.ts +2 -0
  371. package/src/verify-run.ts +28 -8
  372. package/src/verify-shard.ts +12 -2
  373. package/src/verify-skip-ceiling.ts +87 -0
  374. package/src/verify-step.ts +5 -0
  375. package/src/verify-tests.ts +25 -5
  376. package/src/view-drift.ts +55 -0
  377. package/src/worker-bundle.ts +3 -2
  378. package/src/workspace-graph.ts +38 -19
  379. package/src/write-generated.ts +43 -0
  380. package/src/zone-boot.ts +20 -0
  381. package/wiki/Actions.md +342 -0
  382. package/wiki/Admin-Dashboard.md +432 -0
  383. package/wiki/Agents.md +958 -0
  384. package/wiki/Auth.md +195 -0
  385. package/wiki/Bare-VM.md +111 -0
  386. package/wiki/Batching-And-Preloading.md +136 -0
  387. package/wiki/Building-Your-Own-Base.md +203 -0
  388. package/wiki/CI-Parallel-Gate.md +220 -0
  389. package/wiki/CLI-Reference.md +1894 -0
  390. package/wiki/Caching-And-Invalidation.md +255 -0
  391. package/wiki/Client-Data.md +194 -0
  392. package/wiki/Client-Navigation.md +513 -0
  393. package/wiki/Compared.md +93 -0
  394. package/wiki/Configuration.md +868 -0
  395. package/wiki/Contributing.md +12 -0
  396. package/wiki/Deploy-Recipes.md +122 -0
  397. package/wiki/Deployment.md +508 -0
  398. package/wiki/Entities-And-Migrations.md +1116 -0
  399. package/wiki/FAQ.md +175 -0
  400. package/wiki/Feature-Flags.md +65 -0
  401. package/wiki/Getting-Started.md +221 -0
  402. package/wiki/Home.md +160 -0
  403. package/wiki/I18n.md +239 -0
  404. package/wiki/Installation.md +206 -0
  405. package/wiki/Interface-Rules.md +339 -0
  406. package/wiki/Jobs-And-Workflows.md +783 -0
  407. package/wiki/Known-Gaps.md +185 -0
  408. package/wiki/MCP-And-AI.md +753 -0
  409. package/wiki/Mail.md +138 -0
  410. package/wiki/Migrating-An-Existing-App.md +594 -0
  411. package/wiki/Migrating-From-Django.md +54 -0
  412. package/wiki/Migrating-From-Laravel.md +53 -0
  413. package/wiki/Migrating-From-Node-Drizzle.md +53 -0
  414. package/wiki/Migrating-From-Rails.md +53 -0
  415. package/wiki/Migrations-And-Backfills.md +552 -0
  416. package/wiki/Money.md +338 -0
  417. package/wiki/N-Plus-One-Detection.md +197 -0
  418. package/wiki/Notify.md +208 -0
  419. package/wiki/Observability.md +245 -0
  420. package/wiki/Outbound-HTTP.md +109 -0
  421. package/wiki/PWA-And-Offline.md +343 -0
  422. package/wiki/Policies-And-Authz.md +251 -0
  423. package/wiki/Project-Layout.md +150 -0
  424. package/wiki/Queries-And-Live-Queries.md +429 -0
  425. package/wiki/Realtime.md +734 -0
  426. package/wiki/Resource-Management.md +121 -0
  427. package/wiki/Routes-And-Render-Modes.md +521 -0
  428. package/wiki/SEO.md +288 -0
  429. package/wiki/Scheduled-Tasks.md +175 -0
  430. package/wiki/Scraping.md +493 -0
  431. package/wiki/Shapes.md +63 -0
  432. package/wiki/Stability.md +97 -0
  433. package/wiki/Static-Assets.md +166 -0
  434. package/wiki/Storage-And-Uploads.md +404 -0
  435. package/wiki/Testing.md +1314 -0
  436. package/wiki/The-Eight-Primitives.md +247 -0
  437. package/wiki/Theming.md +362 -0
  438. package/wiki/Timezones-And-Dates.md +194 -0
  439. package/wiki/Troubleshooting.md +163 -0
  440. package/wiki/Tutorial-01-First-App.md +289 -0
  441. package/wiki/Tutorial-02-First-Feature.md +339 -0
  442. package/wiki/Tutorial-03-Auth-And-Admin.md +379 -0
  443. package/wiki/Tutorial-04-Jobs-And-Realtime.md +263 -0
  444. package/wiki/Tutorial-05-Deploy-Free.md +231 -0
  445. package/wiki/Tutorial-06-Growing-Up.md +158 -0
  446. package/wiki/UI-Components.md +156 -0
  447. package/wiki/Upgrading.md +3667 -0
  448. package/src/stored-object-headers.ts +0 -43
@@ -0,0 +1,289 @@
1
+ # Tutorial 1 — your first app
2
+
3
+ One command scaffolds a monorepo that already runs. No Docker daemon, no database to provision, no `.env` to fill in.
4
+
5
+ `As of 2026-08-23`, with every gate row re-measured `As of 2026-09-12`. **This page documents `main`, not a published release.** Every file count, gate result and command output below was re-measured on this tree: `x new` → `bun install` → the command, in a directory outside the checkout. Rows that still describe a published version say so in their own line.
6
+
7
+ Series: **1** · [2 — first feature](Tutorial-02-First-Feature) · [3 — auth and admin](Tutorial-03-Auth-And-Admin) · [4 — jobs and realtime](Tutorial-04-Jobs-And-Realtime) · [5 — deploy free](Tutorial-05-Deploy-Free) · [6 — growing up](Tutorial-06-Growing-Up)
8
+
9
+ ## Prerequisites
10
+
11
+ | Need | Version | Check |
12
+ |---|---|---|
13
+ | Bun | ≥ 1.4.4 | `bun --version` |
14
+ | Docker | only for [tutorial 5](Tutorial-05-Deploy-Free) | `docker --version` |
15
+ | Postgres | never, locally | — |
16
+
17
+ ## Scaffold
18
+
19
+ ```bash
20
+ cd $(mktemp -d)
21
+ bunx create-ultimate myapp
22
+ ```
23
+
24
+ **Unpinned on purpose.** Pinning the tutorial to a version pins readers to a scaffold that stops matching this page on the next tag; `README.md` and `llms.txt` drop the pin for the same reason. To reproduce a specific release, add `@<version>` and read that release's tag of this page.
25
+
26
+ ```text
27
+ 213 files in /tmp/tmp.XXXXXXXX/myapp
28
+ ✓ created myapp — next: cd myapp && bun run setup && bun run dev
29
+ ```
30
+
31
+ `As of 2026-11-03`; `--no-example` writes 181.
32
+
33
+ Counts are a derived fact — `x new --dry-run --json` lists every file, and one added template moves the number.
34
+
35
+ ```bash
36
+ cd myapp && bun run setup
37
+ ```
38
+
39
+ ```text
40
+ setup complete — next: bun run dev
41
+ ```
42
+
43
+ `bun run setup` is `bun install`, an `.env.development.local` touch, `x db gen "initial"`, `x db migrate`, `x db seed`, then `x manifest` — so the database is migrated and `x.manifest.json` exists before the gate asks for either. `x new` installs nothing, so this is not optional.
44
+
45
+ `x` is a workspace dependency, not a global install. `bunx x <command>` resolves `node_modules/.bin/x`; the `package.json` scripts (`bun run verify`, `bun run dev`) resolve the same binary. A globally installed `x` (`bun link`, `bun add -g`) run inside the app **hands over** to that same file, `As of 2026-09-05`, and says so on stderr: a global copy carries its own `@ultimat3/entity` with an empty registry, and it wrote a zero-entity manifest under a green exit code before it did. `ULTIMATE_KEEP_GLOBAL_CLI=1` is the opt-out — [`@ultimat3/cli`'s README](https://github.com/developerz-ai/ultimate/blob/main/packages/cli/README.md) has the measurement.
46
+
47
+ ### Two shapes, one generator
48
+
49
+ Counts are derived, never quoted here — `x new --dry-run --json | jq '.data.files | length'`, per
50
+ shape. Measured on fresh scaffolds of this tree, `As of 2026-11-05`:
51
+
52
+ | Invocation | `bun run setup && bun run verify` on run one |
53
+ |---|---|
54
+ | `bunx create-ultimate myapp` | **green, 20 of 21 steps pass** — `budgets` among them; `roadmap` skipped (a framework-repo step) |
55
+ | `bunx create-ultimate myapp --no-example` | **green, 17 of 21 steps pass** — `live`, `job`, `e2e` skipped (no such test yet) and `roadmap` |
56
+
57
+ `--no-example` omits the `post` feature slice and its route. Pick it when an agent is about to write the real feature anyway — [tutorial 2](Tutorial-02-First-Feature) starts there. Pick the default when you want a worked example to read.
58
+
59
+ ## The gate, first thing
60
+
61
+ ```bash
62
+ bun run verify
63
+ ```
64
+
65
+ The app's own gate is `x verify`, alone. Its `budgets` step weighs `.x/build-stats.json`, and on a
66
+ fresh scaffold no such file exists yet, so the step runs `x build --target static` itself first
67
+ (into `.x/verify-static`, never over `.x/static`).
68
+
69
+ The default scaffold, after `bun run setup`, with no `.x/build-stats.json` beforehand,
70
+ `As of 2026-11-03` (`exercise` measured 2026-11-05): the whole gate, in the order it runs:
71
+
72
+ ```text
73
+ ✓ typecheck 3064ms
74
+ ✓ lint 232ms
75
+ ✓ boundaries 844ms
76
+ ✓ filesize 906ms
77
+ ✓ package-shape 402ms
78
+ ✓ errors 951ms
79
+ ✓ unit 2790ms 3 workers (budget 4.0 GB)
80
+ ✓ contract 1233ms 3 workers (budget 4.0 GB)
81
+ ✓ live 840ms serial
82
+ ✓ job 345ms 1 of 3 workers (budget 4.0 GB)
83
+ ✓ exercise 1952ms
84
+ ✓ e2e 12124ms serial
85
+ ✓ eval 91ms
86
+ ✓ drift 1486ms
87
+ ✓ contract-diff 78ms
88
+ ✓ budgets 6336ms
89
+ ✓ seo 40ms
90
+ ✓ i18n 63ms
91
+ ✓ policy 75ms
92
+ ✓ manifest 1131ms
93
+ - roadmap 0ms
94
+ ✓ 20 of 21 steps passed in …ms — 1 skipped: roadmap
95
+ ```
96
+
97
+ `-` is skipped, not passed: `roadmap` is a framework-repo step. The default scaffold ships its
98
+ example slice with a live test, a job test and an e2e test, so `live`, `job` and `e2e` are ticks on
99
+ run one; **with `--no-example`** there is no such test yet, and those three are dashes too. `contract` is **not** among them — the scaffold
100
+ ships `apps/web/api/health.contract.test.ts`, which is what makes it a tick on run one. Nor is
101
+ `exercise`: it needs no test file — it runs every action, query and job the app registers, once,
102
+ against seeded rows — and both shapes write the `apps/web/exercise.ts` it reads. The summary
103
+ names every skip, so a gate that is green because a suite does not exist says so on the one line you
104
+ read. [Tutorial 2](Tutorial-02-First-Feature) turns more of those dashes into ticks.
105
+
106
+ The list is
107
+ `VERIFY_STEP_NAMES` ([`packages/cli/src/verify-step.ts`](https://github.com/developerz-ai/ultimate/blob/main/packages/cli/src/verify-step.ts)), whole or not at all: the same steps run here and in the framework repo.
108
+
109
+ ### `budgets` builds before it weighs
110
+
111
+ `budgets` took 6.3 s above because it built first. Delete the stats and `--verbose` prints the line
112
+ that says so; run it again and it reads the stats it just wrote:
113
+
114
+ ```bash
115
+ rm .x/build-stats.json
116
+ bunx x verify --only budgets --verbose
117
+ bunx x verify --only budgets
118
+ ```
119
+
120
+ ```text
121
+ ✓ budgets 7320ms
122
+ | built first: build stats were missing — x build --target static --out .x/verify-static (6968ms)
123
+ ✓ NOT A GATE RUN — all 1 steps passed in …ms
124
+ ✓ budgets 324ms
125
+ ✓ NOT A GATE RUN — all 1 steps passed in …ms
126
+ ```
127
+
128
+ It builds when `.x/build-stats.json` is missing, written by an earlier measurement rule, or older
129
+ than the newest app source file (tests excluded), and never otherwise: run the gate again with
130
+ nothing edited and the step reads the stats it has. After an edit, the gate pays one static build.
131
+ A build that fails is the step's verdict, under the build's own code and `fix:`.
132
+
133
+ CI asserts the result: `scaffold-smoke` runs a fresh app's own scripts **once, with no waiver and no fix-follow**, and `budgets` must come back **green** rather than merely not-red — a skip would mean the static build bought nothing ([`scripts/scaffold-gate.ts`](https://github.com/developerz-ai/ultimate/blob/main/scripts/scaffold-gate.ts)).
134
+
135
+ ### The invariant block is typed from your columns
136
+
137
+ `invariants` is one callback over the whole list, and `c` is typed from the `columns` above it:
138
+
139
+ ```ts
140
+ invariants: (c) => [
141
+ invariant('post_title_not_blank', c.title.trimmed().minLength(1)),
142
+ invariant('post_price_non_negative', c.price.minor.atLeast(0)),
143
+ ],
144
+ ```
145
+
146
+ `c.titel` is a compile error that names `title`, not a runtime surprise. Everything `x new` and `x g` write typechecks as generated — no `!`, no edit before the first `x verify`.
147
+
148
+ What still ships broken: [Known gaps](Known-Gaps).
149
+
150
+ ## Run it
151
+
152
+ <!-- no-run: a server that runs until stopped; the --once fence below is its smoke test -->
153
+ ```bash
154
+ bunx x dev
155
+ ```
156
+
157
+ `--once` boots, reports and exits — the shape to paste into a smoke test:
158
+
159
+ ```bash
160
+ bunx x dev --once --port 3100
161
+ ```
162
+
163
+ ```text
164
+ {"ts":"2026-11-03T16:48:57.124Z","level":"info","msg":"ultimate web listening on http://localhost:3100"}
165
+ {"ts":"2026-11-03T16:48:57.118Z","level":"info","msg":"sync node ready","buildId":"e6af64a2077e5d60","path":"/_x/sync"}
166
+ {"ts":"2026-11-03T16:48:57.134Z","level":"info","msg":"jobs.worker.started","workerId":"worker-01a1a250-…","queues":["myapp-default","default"]}
167
+ {"ts":"2026-11-03T16:48:57.137Z","level":"info","msg":"jobs.scheduler.started","tasks":1}
168
+ {"ts":"2026-11-03T16:48:57.142Z","level":"info","msg":"live feed in-process","detail":"the embedded database has no walsender; repository writes in this process reach subscribers"}
169
+ roles web, sync, worker, scheduler
170
+ panels routes, timeline, live, jobs, db, mail, cache, policy, manifest, services, boundaries
171
+ manifest /tmp/…/myapp/x.manifest.json
172
+ introspect http://localhost:3100/_x
173
+ mcp POST /mcp
174
+ ✓ dev ready on http://localhost:3100 — /_x mounted (11 panels), db=embedded events=embedded storage=embedded mail=embedded cdn=none live=in-process
175
+ ```
176
+
177
+ An excerpt, `As of 2026-11-03`: the boot also logs the dev viewer warning, the metrics port and the drain `--once` ends with.
178
+
179
+ Four roles in one process, isolation simulated rather than skipped. `replicator` is opt-in via `--role`; `migrate` is not a dev role.
180
+
181
+ ### Why no Docker
182
+
183
+ `.env.development` ships every service key **empty**, and empty means embedded:
184
+
185
+ ```bash
186
+ DATABASE_URL=
187
+ NATS_URL=
188
+ S3_ENDPOINT=
189
+ PORT=3000
190
+ ROLE=web
191
+ ```
192
+
193
+ | Key | Unset means | Set means |
194
+ |---|---|---|
195
+ | `DATABASE_URL` | PGlite in this process, under `.x/pgdata` | that Postgres |
196
+ | `NATS_URL` | in-process fanout | that NATS server |
197
+ | `S3_ENDPOINT` | `.x/storage` on disk | that S3 |
198
+
199
+ Nothing in the framework branches on `if (dev)` — only the driver behind the seam differs. Same code path, same `db()`, same `enqueue()`. Full table: [CLI reference § x dev](CLI-Reference).
200
+
201
+ ## What each directory is
202
+
203
+ ```
204
+ myapp/
205
+ ├── app.config.ts the one config file — names env KEYS, never values
206
+ ├── apps/
207
+ │ ├── web/
208
+ │ │ ├── site/ static, 0kb JS, SEO-critical. May NOT import app/
209
+ │ │ ├── app/ authed, streaming, realtime. Feature slices live here
210
+ │ │ ├── api/ actions only — no rendering, no components
211
+ │ │ ├── shared/ actor type, tokens, primitives. A leaf both surfaces import
212
+ │ │ ├── server.ts the production entry: ROLE + PORT, nothing else
213
+ │ │ └── prerender.ts the static entry: one HTML file per `render: 'static'` route,
214
+ │ │ plus sitemap.xml and robots.txt
215
+ │ ├── admin/ the admin app, gated on `admin:read`
216
+ │ ├── desktop/ mobile/ README stubs, no code
217
+ ├── packages/
218
+ │ ├── db/ schema.ts (the entity export list — the package's public
219
+ │ │ surface, not the generator's input) + migrations/
220
+ │ ├── domain/ pure types, no I/O
221
+ │ ├── i18n/ catalogs/<locale>.json — one flat file per locale
222
+ │ ├── mcp/ the app's own MCP surface over its actions
223
+ │ └── ui/ app components on semantic tokens
224
+ ├── docker/ Dockerfile, .dockerignore, dev + prod compose, helm/
225
+ ├── guards/ one rule per file, run by `x verify`'s boundaries step.
226
+ │ Every name in SHIPPED_GUARD_NAMES ships; `x doctor`
227
+ │ lists any missing. Delete one by deleting its file
228
+ ├── bin/ setup.ts — `bun run setup`; `dev` and `verify` are x's own
229
+ └── CLAUDE.md AGENTS.md what an agent reads first: one file, AGENTS.md a symlink
230
+ ```
231
+
232
+ Boundaries are a build error, not a note — but `boundaries` is a **step of `x verify`**, not a top-level command. `bunx x boundaries` exits `X_CLI_UNKNOWN_COMMAND`. Run `bunx x verify` and read the `boundaries` line. Full model: [Project layout](Project-Layout).
233
+
234
+ ### The database, first run
235
+
236
+ `packages/db/migrations` starts **empty**, and `x db gen` is its only writer. Two commands, in this order:
237
+
238
+ ```bash
239
+ bunx x db gen "initial" # entities → <id>.sql, <id>.snapshot.json, <id>.hash
240
+ bunx x db migrate # applies them, then diffs the live schema against the ledger it wrote
241
+ ```
242
+
243
+ `bun run setup` runs both — `bun install`, an `.env.development.local` touch, `x db gen "initial"` when the directory holds no `.sql`, `x db migrate`, `x db seed`, then `x manifest`. `x db migrate` is `@ultimat3/db`'s own migrator, the one `ROLE=migrate` runs, so nothing extra has to be installed.
244
+
245
+ Until the generate has run, `x verify` is **red on its `drift` step** — correct behaviour with a runnable fix, not a defect:
246
+
247
+ ```text
248
+ X_DB_DRIFT: schema differs from migrations
249
+ cause: packages/db has a schema but no migration recorded it
250
+ fix: x db gen "initial"
251
+ ```
252
+
253
+ That is the scaffold **with** the example slice, which declares one entity. `x new --no-example` declares none, and zero entities against zero migrations is agreement rather than drift, so its `drift` step is green from the first run and goes red the moment you write your first `entity()`.
254
+
255
+ `x new` hand-wrote a `0000_initial.sql` until 2026-08 and that was the defect — a second writer of a directory the generator owns, whose file carried no `.snapshot.json`, so `x db migrate` answered `X_DB_DRIFT` naming `x db gen` and `x db gen` answered `X_MIGRATION_SNAPSHOT_MISSING` naming version control for a file version control never had. Neither `fix:` now names the command that raises the other ([Known gaps](Known-Gaps)).
256
+
257
+ ## The routes are clean
258
+
259
+ `x routes` on a fresh scaffold reports four file routes and no findings, plus the admin's
260
+ screens. `As of 2026-10`, read off the templates `x new` writes:
261
+
262
+ | path | surface | render | hydrate | offline | declared by |
263
+ |---|---|---|---|---|---|
264
+ | `/` | site | static | never | precache | `apps/web/site/page.tsx` |
265
+ | `/offline` | site | static | never | precache | `apps/web/site/offline/page.tsx` |
266
+ | `/dashboard` | app | ssr | visible | runtime | `apps/web/app/dashboard/page.tsx` |
267
+ | `/posts` | app | ssr | visible | runtime | `apps/web/app/posts/page.tsx` |
268
+
269
+ The admin has no page file: `apps/admin/app/admin/admin.ts` declares `defineAdmin()`, which mounts
270
+ `/admin` and a list, detail and form per entity. Those rows name the call and the permissions that
271
+ gate them instead of a file — `defineAdmin() · admin:read + posts:read` — and their `--json` rows
272
+ carry `mount`. `--no-example` drops `/posts`. `x routes` is not a gate step either way, so a finding
273
+ here never fails `x verify` — run it after scaffolding and after every `x g route`.
274
+
275
+ A read that should not hold up the page goes in a `<Hole>` on a `stream` page ([Routes and render modes](Routes-And-Render-Modes#what-a-hole-does)).
276
+
277
+ ## The five commands worth memorising
278
+
279
+ | Want | Command |
280
+ |---|---|
281
+ | is it shippable | `bun run verify` (add `--json`) |
282
+ | what is wrong with my environment | `bunx x doctor --json` |
283
+ | what does this error code mean | `bunx x errors explain X_FORBIDDEN` |
284
+ | what does this app contain | `bunx x manifest --json` |
285
+ | what commands exist | `bunx x help` — planned ones are marked `(planned)` and throw `X_NOT_IMPLEMENTED` |
286
+
287
+ ## Next
288
+
289
+ [Tutorial 2 — your first feature](Tutorial-02-First-Feature): one `entity`, one `policy`, one `action`, one `route`, one test, and the five artifacts a single declaration projects.
@@ -0,0 +1,339 @@
1
+ # Tutorial 2 — your first feature
2
+
3
+ Scaffold the slice, register it, migrate it, name the tests. One `action` declaration becomes an HTTP route, an OpenAPI operation, a typed client method, a job handle, an MCP tool and three contract assertions — with no second file to keep in step.
4
+
5
+ `As of 2026-11-03`. Every command and every output on this page was re-run in the app [tutorial 1](Tutorial-01-First-App) leaves — `bunx create-ultimate myapp`, example slice included, built from this tree's packages (`scripts/scaffold-smoke-overrides.ts`) — by hand, in that order. `scripts/tutorial-run.ts` runs tutorials 1–4 the same way. Timings are that machine's; yours differ.
6
+
7
+ Series: [1 — first app](Tutorial-01-First-App) · **2** · [3 — auth and admin](Tutorial-03-Auth-And-Admin) · [4 — jobs and realtime](Tutorial-04-Jobs-And-Realtime) · [5 — deploy free](Tutorial-05-Deploy-Free) · [6 — growing up](Tutorial-06-Growing-Up)
8
+
9
+ ## Never hand-write a primitive
10
+
11
+ ```bash
12
+ bunx x g resource todo --dry-run
13
+ ```
14
+
15
+ ```text
16
+ + apps/web/app/todo/entity.ts
17
+ + apps/web/app/todo/entity.test.ts
18
+ + apps/web/app/todo/repo.ts
19
+ + apps/web/app/todo/repo.test.ts
20
+ + apps/web/app/todo/policy.ts
21
+ + apps/web/app/todo/policy.test.ts
22
+ + apps/web/app/todo/actions/create-todo.ts
23
+ + apps/web/app/todo/actions/create-todo.test.ts
24
+ + apps/web/app/todo/actions/create-todo.contract.test.ts
25
+ + apps/web/app/todo/errors.ts
26
+ + apps/web/app/todo/actions/archive-todo.ts
27
+ + apps/web/app/todo/actions/archive-todo.test.ts
28
+ + apps/web/app/todo/actions/archive-todo.contract.test.ts
29
+ + packages/i18n/catalogs/en.json
30
+ + apps/web/app/todo/live/todo-list.ts
31
+ + apps/web/app/todo/live/todo-list.live.test.ts
32
+ + apps/web/app/todo/live/todo-list.test.ts
33
+ + apps/web/app/todo/jobs/reindex-todo.ts
34
+ + apps/web/app/todo/jobs/reindex-todo.job.test.ts
35
+ + apps/web/app/todo/jobs/reindex-todo.test.ts
36
+ + apps/web/app/todo/service.ts
37
+ + apps/web/app/todo/service.test.ts
38
+ + apps/web/app/todo/ui.tsx
39
+ + apps/web/app/todo/ui.test.ts
40
+ + apps/web/app/todo/ui.module.scss
41
+ + apps/web/app/todo/ui/todo-card.tsx
42
+ + apps/web/app/todo/todo-form.island.tsx
43
+ + apps/web/app/todo/todo-form.island.states.ts
44
+ + apps/web/app/todo/todo-form.island.test.ts
45
+ + apps/web/app/todos/page.module.scss
46
+ + apps/web/app/todos/page.e2e.test.ts
47
+ + apps/web/app/todos/page.tsx
48
+ + apps/web/app/todos/page.test.ts
49
+ + apps/web/app/todos/page-db.test.ts
50
+ + apps/web/shared/roles.ts
51
+ + apps/web/api/index.ts
52
+ + packages/db/src/client.ts
53
+ ✓ would write 37 file(s) for resource todo — nothing written
54
+ ```
55
+
56
+ **The form is an island, not a `ui/` component** — `todo-form.island.tsx` beside the slice rather than under `ui/`. A `createSignal` needs the browser, `.island.tsx` is what puts a module in the client bundle graph, and the route's `budget.js` is what bounds it. Everything under `ui/` renders on the server and ships no JS.
57
+
58
+ Drop `--dry-run` to write them:
59
+
60
+ ```bash
61
+ bunx x g resource todo
62
+ ```
63
+
64
+ ```text
65
+ ✓ wrote 39 file(s) for resource todo — next: …
66
+ ```
67
+
68
+ `x g` never clobbers — an existing file is `X_GENERATE_CONFLICT`; the i18n catalog is merged key-by-key rather than overwritten; and a **slice module** (`entity.ts`, `repo.ts`, `policy.ts`, `errors.ts`) the slice already has is skipped, `--force` included, because it belongs to the slice rather than to the generator that needed it. The last three lines are the wiring: the grants in `roles.ts`, the slice's actions, query and job in `api/index.ts`, and its entity in the db client (`packages/db/src/client.ts`). A file the run would leave unchanged — a catalog merge that gains no key, wiring a previous slice already wrote — is skipped rather than counted. Here `bun run setup` has written `x.manifest.json` and `openapi.json` ([tutorial 1](Tutorial-01-First-App)), so the run re-projects both and prints 39; in an app with neither it prints 37. In a `x new --no-example` app, whose two `package.json`s do not yet name the workspace packages, the same runs print 39 and 41 (42 with `--admin`).
69
+
70
+ **No migration is in that list.** `x db gen` is the only writer of `packages/db/migrations`, so a new slice is `x g resource todo` and then the two steps below.
71
+
72
+ | Generator | Emits |
73
+ |---|---|
74
+ | `x g resource <n>` | the whole slice above — 37 files on a dry run in tutorial 1's app, 40 with `--admin` (`As of 2026-11-04`); a real run after `bun run setup` adds the two re-projected artifacts |
75
+ | `x g entity` / `policy` / `action` / `mutator` / `query` / `job` / `task` | that primitive plus its test — **and the slice modules its own source imports**, when the slice has none: `x g job` is 5 files into a bare slice, `x g action` 8. Which ones differ per generator, so a job plants no `policy.ts` ([CLI reference § x g](CLI-Reference)) |
76
+ | `x g route <path> --surface site\|app` | `page.tsx`, its stylesheet, its test, its catalog keys |
77
+
78
+ `--surface site` on a `resource` is refused: a slice ships a live query and a form with a signal, and `site/` is the never-hydrated surface. Full flag table: [CLI reference § x g](CLI-Reference).
79
+
80
+ ## The layer rule
81
+
82
+ The slice enforces one call direction, and `x verify`'s `boundaries` step is what makes it real.
83
+
84
+ | Layer | File | May call |
85
+ |---|---|---|
86
+ | route | `apps/web/app/todos/page.tsx` | actions, queries |
87
+ | action / query | `actions/*.ts`, `live/*.ts` | services |
88
+ | service | `service.ts` | the repo |
89
+ | repo | `repo.ts` | `db()` — the **only** module that may touch the table |
90
+
91
+ ## The entity
92
+
93
+ ```ts
94
+ export const todo = entity('todos', {
95
+ // Naming the tenant column is what turns tenancy on: a read with no org predicate then fails
96
+ // with X_TENANCY_UNSCOPED instead of leaking another org's rows.
97
+ tenant: 'orgId',
98
+ columns: {
99
+ id: uuid().primaryKey(),
100
+ orgId: uuid(),
101
+ title: text({ max: 200 }),
102
+ price: money(), // two physical columns: price_minor bigint + price_currency char(3)
103
+ createdAt: timestamp().defaultNow(),
104
+ },
105
+ invariants: (c) => [
106
+ invariant('todo_title_not_blank', c.title.trimmed().minLength(1)),
107
+ invariant('todo_price_non_negative', c.price.minor.atLeast(0)),
108
+ ],
109
+ indexes: [{ on: ['orgId', 'createdAt'] }],
110
+ });
111
+ ```
112
+
113
+ `c` is typed from the `columns` above it, so `c.titel` is a compile error naming `title` — see [tutorial 1](Tutorial-01-First-App#the-invariant-block-is-typed-from-your-columns).
114
+
115
+ Each invariant runs twice from one declaration — in the app on every write, and as a Postgres `CHECK` in the migration. Details: [Entities and migrations](Entities-And-Migrations).
116
+
117
+ ## The policy decides once, everywhere
118
+
119
+ ```ts
120
+ export const canTodoWrite = can<TodoScope>(
121
+ 'todo:write',
122
+ ({ actor, input }) => actor !== null && actor.orgId === input.orgId,
123
+ );
124
+ ```
125
+
126
+ `can()` checks the grant first and the predicate second, so a denial distinguishes *you may never do this* from *you may, but not in that org*. The generated `policy.test.ts` pins the second gate with an actor who **holds** the grant and is still denied — delete the predicate and that test fails.
127
+
128
+ `canTodoCreate` is the same grant with the one tenancy rule a create can have — the actor **has** an org — because the row is written under the actor's org, never one named in the body.
129
+
130
+ The generator also **grants** what it declares, in `apps/web/shared/roles.ts`: `todo:read` to `member`, `todo:write` to `admin` (the dev actor's role). A permission an action requires and no role grants is `X_PERMISSION_UNGRANTED` on `x verify`'s `policy` step — every request to it would answer 403.
131
+
132
+ Full model: [Policies and authz](Policies-And-Authz).
133
+
134
+ ## The action, and what it projects
135
+
136
+ ```ts
137
+ export const CreateTodoInput = todo.$view(['title', 'price']);
138
+
139
+ export const createTodo = action({
140
+ input: CreateTodoInput,
141
+ output: TodoView,
142
+ policy: canTodoCreate,
143
+ cache: { invalidates: [todoTag] },
144
+ // No `mcp` until you write a real description: an agent reads it to decide to call the tool.
145
+ async handle({ input, ctx }) { … return service.create({ ...input, orgId }); },
146
+ });
147
+ ```
148
+
149
+ A real insert. The input is the entity's own view of the columns a caller supplies, so a column added to `entity.ts` is one edit to that list; `orgId` comes from `ctx.actor`, never from the body.
150
+
151
+ <!-- no-run: needs `bunx x dev` serving on :3000 -->
152
+ ```bash
153
+ curl -X POST localhost:3000/api/todos/create -H 'content-type: application/json' \
154
+ -H 'sec-fetch-site: same-origin' -d '{"title":"Ship it","price":{"minor":1250,"currency":"USD"}}'
155
+ ```
156
+
157
+ Five artifacts, read off the real registry with `createTodo.describe()`, `.openapi()`, `.job()`, `.contract()` and `@ultimat3/mcp`'s `toolFrom(createTodo)`:
158
+
159
+ | Projection | Value, verbatim |
160
+ |---|---|
161
+ | HTTP route | `POST /api/todos/create`, capability `todo:write` |
162
+ | OpenAPI operation | `operationId: "createTodo"`, `summary` from `mcp.description` |
163
+ | MCP tool | none until `mcp: { expose: true, description }` is written; then `createTodo` — the export name verbatim — and every call goes through `createTodo`'s own `invoke`, so its policy is the one authz object, not a copy |
164
+ | Job handle | `action:createTodo` — the same handler, run through the queue |
165
+ | Contract tests | 3 generated assertions: garbage input rejected, anonymous denied, operation present in the spec |
166
+ | Typed client | `.client({ baseUrl })` derives the path by string math, so the browser imports no server code |
167
+
168
+ ```bash
169
+ bunx x actions list
170
+ ```
171
+
172
+ ```text
173
+ name verb resource path capability mcp
174
+ archivePost archive posts /api/posts/archive post:write no
175
+ archiveTodo archive todos /api/todos/archive todo:write no
176
+ createPost create posts /api/posts/create post:write no
177
+ createTodo create todos /api/todos/create todo:write no
178
+ health invoke healths /api/healths/invoke public yes
179
+ ✓ 5 actions
180
+ ```
181
+
182
+ `archivePost` and `createPost` are the example `post` slice tutorial 1's app ships with. Rename a column in the entity and every consumer fails typecheck. One rename, N errors, all real work. Every field: [Actions](Actions).
183
+
184
+ ## Registered for you
185
+
186
+ `x new` writes `apps/web/api/index.ts`, and every `x g` adds the primitives it wrote to it. A job no `defineApi` lists keeps the positional name `job()` gave it — `anonymous-job-2` — and `x verify`'s `manifest` step refuses that as `X_JOB_UNREGISTERED`. After `x g resource todo`:
187
+
188
+ ```ts
189
+ // apps/web/api/index.ts, in an app made with `x new --no-example` — importing it IS the boot
190
+ import { defineApi } from '@ultimat3/action';
191
+ import * as archiveTodo from '../app/todo/actions/archive-todo';
192
+ import * as createTodo from '../app/todo/actions/create-todo';
193
+ import * as reindexTodo from '../app/todo/jobs/reindex-todo';
194
+ import * as todoList from '../app/todo/live/todo-list';
195
+ import * as health from './health';
196
+
197
+ export const api = defineApi({
198
+ actions: [health, createTodo, archiveTodo],
199
+ queries: [todoList],
200
+ jobs: [reindexTodo],
201
+ });
202
+ ```
203
+
204
+ Tutorial 1's app lists its example `post` slice the same way, ahead of the `todo` lines. The jobs are the half an app cannot skip: the module scan registers actions and queries by export name on its own, and registers no job. Actions and queries are listed for the type — `Api` is what the browser's typed client is shaped from. Each primitive is imported as a **file**, never a directory. Two features exporting one name collide with `X_ACTION_DUPLICATE` rather than merging in silence.
205
+
206
+ ## Migrations
207
+
208
+ `x g resource` writes no migration and does not touch the entity export list. Two steps.
209
+
210
+ **1. Export the entity.** `packages/db/src/schema.ts` is the db package's public surface — what the
211
+ rest of the app imports a `todo` from:
212
+
213
+ ```ts
214
+ export { todo } from '@myapp/web/app/todo/entity';
215
+ ```
216
+
217
+ It is **not** what the migration generator reads. `x db gen` diffs the entity **registry**
218
+ (`describeEntities()`), and `x verify`'s `drift` step hashes that same registry alongside the text
219
+ under `packages/db/src/**` — so the entity is already in the diff the moment its own file exists.
220
+ `loadApp` imports every module under `apps/*/{site,app,api,shared}/**` and `packages/*/src/**`, and
221
+ `entity()` registers on import. `examples/dummy` is the proof: it has entities, migrations and a
222
+ green `drift` step, and no `packages/db/src/schema.ts` at all.
223
+ Adding the export line moves the text half of the hash too, which is why the drift below is the same
224
+ either way. `bunx x verify --only drift`:
225
+
226
+ ```text
227
+ ✗ drift 2161ms
228
+ X_DB_SCHEMA_UNMIGRATED (packages/db/migrations)
229
+ cause: table "todos" is declared by the entities and no migration recorded it
230
+ fix: bunx x db gen "record todos"
231
+ ```
232
+
233
+ The newest migration is tutorial 1's `initial`, which recorded the example `posts` table; `todos` is
234
+ in no migration yet. The slug is yours to choose; the fix only suggests one.
235
+
236
+ **2. Generate the migration.** `x db gen` diffs the entity registry against the newest
237
+ migration's snapshot and writes three files — `<id>.sql`, `<id>.snapshot.json` and `<id>.hash` —
238
+ and refreshes the schema dump under `packages/db/schema/` (`todos.sql` under `04_tables/` and
239
+ `05_indexes/`). A migration id is `<stamp>_<slug>`; the stamp is `x db gen`'s own clock:
240
+
241
+ ```bash
242
+ bunx x db gen "add todos"
243
+ ```
244
+
245
+ ```text
246
+ ✓ migration …_add_todos generated
247
+ ```
248
+
249
+ The 1.1.0 workaround this step used to carry (a hand-written `db-gen.ts` script, and two manual
250
+ edits to the emitted SQL) is gone: all three defects it worked around were fixed in 2.0.0, and
251
+ `scaffold-smoke` in CI runs `x db gen` then `x db migrate` on a fresh scaffold on every push.
252
+
253
+ Apply them the way production does — same code path, no toolchain:
254
+
255
+ <!-- no-run: the release-phase path; the x db migrate fence below applies the same migrations -->
256
+ ```bash
257
+ ROLE=migrate bun apps/web/server.ts
258
+ ```
259
+
260
+ ```text
261
+ {"ts":"2026-11-03T15:52:26.924Z","level":"info","msg":"ultimate migrate applied","applied":1,"available":1,"appVersion":"dev"}
262
+ ```
263
+
264
+ `bunx x db migrate` is that same code path with a drift check after it. Both read
265
+ `packages/db/migrations` and write one `x_migrations` ledger:
266
+
267
+ ```bash
268
+ bunx x db migrate
269
+ ```
270
+
271
+ ```text
272
+ ✓ migrations applied
273
+ ```
274
+
275
+ The `.hash` sidecar beside each migration is what `drift` compares against, so a fresh clone detects drift with no database and no local state.
276
+
277
+ ## Name the tests after their step
278
+
279
+ A test's type is its **filename suffix**, not the helper it calls. `contractTest()` inside `create-todo.test.ts` runs under `unit`, and `x test contract` reports `X_TEST_NO_FILES`. `x g` already writes the typed names — `create-todo.contract.test.ts`, `todo-list.live.test.ts`, `reindex-todo.job.test.ts`, `page.e2e.test.ts` in the list above — so this is the rule for a test you add by hand:
280
+
281
+ | Suffix | Runs in step |
282
+ |---|---|
283
+ | `*.contract.test.ts` | `contract` |
284
+ | `*.live.test.ts` | `live` |
285
+ | `*.job.test.ts` | `job` |
286
+ | `*.e2e.test.ts`, anything under `e2e/` | `e2e` |
287
+ | `*.eval.test.ts` | `eval` |
288
+
289
+ ## The gate, green
290
+
291
+ ```bash
292
+ bunx x verify
293
+ ```
294
+
295
+ Timings, worker counts and the `slowest:` lines trimmed:
296
+
297
+ ```text
298
+ ✓ typecheck
299
+ ✓ lint
300
+ ✓ boundaries
301
+ ✓ filesize
302
+ ✓ package-shape
303
+ ✓ errors
304
+ ✓ unit
305
+ ✓ contract
306
+ ✓ live
307
+ ✓ job
308
+ ✓ exercise
309
+ ✓ e2e
310
+ ✓ eval
311
+ ✓ drift
312
+ ✓ contract-diff
313
+ ✓ budgets
314
+ ✓ seo
315
+ ✓ i18n
316
+ ✓ policy
317
+ ✓ manifest
318
+ - roadmap
319
+ ✓ 20 of 21 steps passed in …ms — 1 skipped: roadmap
320
+ ```
321
+
322
+ `live`, `job` and `e2e` were dashes in [tutorial 1](Tutorial-01-First-App); the slice's own typed tests are what they now run. `budgets` builds the site first when no current measurement exists, so it is green on the first run. `e2e` drives a real Chrome; on a machine without one its browser cases skip (`E2E_BROWSER_REQUIRED=1` makes that a refusal). `roadmap` reads `docs/idea/14-roadmap.md`, which an app does not have.
323
+
324
+ ## Drive it from an agent
325
+
326
+ <!-- no-run: a server that runs until stopped -->
327
+ ```bash
328
+ bunx x mcp serve --transport http --port 9229
329
+ ```
330
+
331
+ 19 tools, one catalog, the same on `stdio` and `http` — 14 framework tools (`routes.list`, `schema.describe`, `policies.list`, `actions.describe`, `jobs.inspect`, `queue.depth`, `manifest.read`, `errors.explain`, `db.query`, `db.migrate`, `tests.run`, `verify.run`, `logs.tail`, `graph.query`) and five that look at the UI (`ui.shot`, `ui.island`, `ui.inspect`, `ui.interact`, `ui.diff`). `bunx x mcp tools` prints them with their scopes.
332
+
333
+ `createTodo` reaches an agent's tool list through the app's own surface in `packages/mcp/src/index.ts` (`defineAppMcp({ include: 'exposed' })`), carrying `mcp: { expose: true }` and **the action's own policy** as its authorization. Full model: [MCP and AI](MCP-And-AI).
334
+
335
+ ## Next
336
+
337
+ [Tutorial 3 — auth and admin](Tutorial-03-Auth-And-Admin): who the actor is, which roles grant which permissions, and the admin surface over the actions you just declared.
338
+
339
+ Related: [Actions](Actions) · [Entities and migrations](Entities-And-Migrations) · [Testing](Testing) · [Known gaps](Known-Gaps)