void 0.10.13 → 0.20.1

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 (432) hide show
  1. package/AGENTS_TEMPLATE.md +6 -0
  2. package/{skills/void/docs/node_modules/void/node_modules/pglite-server/LICENSE.md → LICENSE} +1 -1
  3. package/README.md +34 -8
  4. package/dist/{auth-qgMlYp7Z.d.mts → auth-DkcFflXV.d.mts} +10 -11
  5. package/dist/auth-W9WII-mN.mjs +630 -0
  6. package/dist/{auth-cmd-BqsdZJp5.mjs → auth-cmd-CAH62yDU.mjs} +4 -3
  7. package/dist/{auth-migrations-BTZ-ATvQ.mjs → auth-migrations-9vif1uj8.mjs} +53 -12
  8. package/dist/{better-auth-shared-BQooDxbw.mjs → better-auth-shared-CYw1T3k4.mjs} +7 -10
  9. package/dist/{better-auth-shared-DealXecJ.d.mts → better-auth-shared-DSCeohOK.d.mts} +10 -5
  10. package/dist/{build-cmd-Bujrv5q-.mjs → build-cmd-CJvZvPQO.mjs} +6 -4
  11. package/dist/{cache-C11V8Fxq.mjs → cache-BlNeQjuP.mjs} +9 -5
  12. package/dist/{cancel-deploy-fwFYF04b.mjs → cancel-deploy-CmlAZ9P6.mjs} +3 -2
  13. package/dist/cf-access-AJ1ehiFR.mjs +42 -0
  14. package/dist/cf-access-DsSsZUPr.mjs +67 -0
  15. package/dist/cli/cli.d.mts +1 -1
  16. package/dist/cli/cli.mjs +1735 -165
  17. package/dist/cli/env-schema-probe.d.mts +48 -61
  18. package/dist/cli/env-schema-probe.mjs +10 -58
  19. package/dist/{client-Gb71-XkG.mjs → client-Clirrol3.mjs} +120 -463
  20. package/dist/cloudflare-auth-B1QtTO1b.mjs +217 -0
  21. package/dist/cloudflare-cmd-B6_OZx2V.mjs +62 -0
  22. package/dist/cloudflare-connect-j5D4hhrG.mjs +56 -0
  23. package/dist/cloudflare-operations-CPTpRW6d.mjs +566 -0
  24. package/dist/{config-qHGgPuWT.mjs → config-BQFq7QvD.mjs} +75 -41
  25. package/dist/{config-CutEMNGJ.mjs → config-NOG_U1aK.mjs} +10 -15
  26. package/dist/connect-C04Wdy_h.mjs +79 -0
  27. package/dist/{create-project-DsYvl3TB.mjs → create-project-ChGZ1DFd.mjs} +26 -16
  28. package/dist/database-provider.d.mts +21 -0
  29. package/dist/database-provider.mjs +6 -0
  30. package/dist/{db-C0i0sYMS.mjs → db-D2d_mUsB.mjs} +612 -117
  31. package/dist/{delete-mh6p-zkQ.mjs → delete-D8GigDk8.mjs} +9 -6
  32. package/dist/{deploy-jBJT1fUT.mjs → deploy-iXZ3F0N6.mjs} +3252 -1995
  33. package/dist/dev-inbox-DkgRWLkW.mjs +307 -0
  34. package/dist/{discover-CJHyvYfR.mjs → discover-xvfrgJeo.mjs} +3 -3
  35. package/dist/{magic-string.es-ZQjdJFFn.mjs → dist-BR1quN_w.mjs} +570 -216
  36. package/dist/{dist-DaKKDf8D.mjs → dist-BrsS7cai.mjs} +17 -2
  37. package/dist/{dist-BuiRJkTd.mjs → dist-m40_XgNh.mjs} +48 -33
  38. package/dist/{domain-DiaNQbrl.mjs → domain-B1VmoSr0.mjs} +41 -4
  39. package/dist/dotenv-VQxupEUv.mjs +181 -0
  40. package/dist/edge.d.mts +2 -0
  41. package/dist/edge.mjs +2 -0
  42. package/dist/email-Ce6SQq-i.mjs +182 -0
  43. package/dist/email-uKyQYUVY.mjs +1016 -0
  44. package/dist/{entry-D7yy4xVH.mjs → entry-DU3oDoQ3.mjs} +2 -2
  45. package/dist/env-BcQzYgoG.mjs +73 -0
  46. package/dist/env-D4Emu-M_.mjs +95 -0
  47. package/dist/env-helpers-CyKtOBpj.d.mts +22 -0
  48. package/dist/env-public-D_6u46fX.d.mts +135 -0
  49. package/dist/{env-types-QBj-ndax.mjs → env-types-BNPhro-M.mjs} +2 -2
  50. package/dist/{env-validation-Dea3v3ej.mjs → env-validation-ENpMy6Ez.mjs} +68 -122
  51. package/dist/{gen-BzXf3Jh2.mjs → gen-DI2YwdBM.mjs} +70 -15
  52. package/dist/generate-RTK8_kK1.mjs +47 -0
  53. package/dist/{github-cmd-DKcGUNsj.mjs → github-cmd-xItS5Zwf.mjs} +39 -31
  54. package/dist/{handler-Cjh8uM3Y.d.mts → handler-D1hLsObx.d.mts} +124 -122
  55. package/dist/{head-nmvOgFjd.d.mts → head-Do8P4puT.d.mts} +9 -8
  56. package/dist/{headers-ChAADPQu.mjs → headers-D8QfRX9Y.mjs} +12 -10
  57. package/dist/inbound-2d0zi2yS.mjs +706 -0
  58. package/dist/inbound-afAcWeQ9.d.mts +363 -0
  59. package/dist/index.d.mts +61 -34
  60. package/dist/index.mjs +1012 -293
  61. package/dist/{init-7JCAcKNQ.mjs → init-BD-9THgn.mjs} +329 -271
  62. package/dist/link-RMdgjF1v.mjs +52 -0
  63. package/dist/{list-CPwFDZ_c.mjs → list-3F52R_yO.mjs} +37 -5
  64. package/dist/{runner-kapo9aPs.mjs → local-d1-D2I6Ox5F.mjs} +116 -6
  65. package/dist/{login-BT3H8PN3.mjs → login-pV69H-ZO.mjs} +17 -15
  66. package/dist/{logs-Bt313ax7.mjs → logs-DFHHD6wE.mjs} +16 -2
  67. package/dist/mime-BJD7d_qL.mjs +1216 -0
  68. package/dist/neon-DHwd2zvC.mjs +54 -0
  69. package/dist/{node-pRg81HqV.mjs → node-Dk3H2jmU.mjs} +29 -8
  70. package/dist/operator-cmd-DYWRbWUA.mjs +348 -0
  71. package/dist/{agents-CtgBYqld.mjs → output-tFQLLj26.mjs} +676 -211
  72. package/dist/{package-json-Cx1osYo6.mjs → package-json-CPoWX79C.mjs} +1 -1
  73. package/dist/pages/client.d.mts +43 -41
  74. package/dist/pages/client.mjs +40 -33
  75. package/dist/pages/head-client.d.mts +10 -12
  76. package/dist/pages/head.d.mts +1 -1
  77. package/dist/pages/index.d.mts +37 -14
  78. package/dist/pages/index.mjs +5 -5
  79. package/dist/pages/islands-plugin.d.mts +25 -27
  80. package/dist/pages/islands-plugin.mjs +6 -4
  81. package/dist/pages/prefetch.d.mts +6 -7
  82. package/dist/pages/protocol.d.mts +2 -2
  83. package/dist/pages/protocol.mjs +2 -1
  84. package/dist/pages/serialize.d.mts +7 -8
  85. package/dist/platform-cmd-DxJ2FRwR.mjs +123 -0
  86. package/dist/platform-domain-ChvbJkdy.mjs +228 -0
  87. package/dist/platform-lifecycle-DN4MzJF_.mjs +4450 -0
  88. package/dist/platform-management-Db2PXw0B.mjs +698 -0
  89. package/dist/platform-recovery-C_YO-tIs.mjs +99 -0
  90. package/dist/{plugin-inference-DMeavIJ6.mjs → plugin-inference-BDRfZngg.mjs} +35 -19
  91. package/dist/prepare-BfJvFUtJ.mjs +14 -0
  92. package/dist/{prepare-BvvgAz-3.mjs → prepare-CBetXvsN.mjs} +15 -24
  93. package/dist/{preset-BjyR3lzz.mjs → preset-lAy0B0BQ.mjs} +25 -212
  94. package/dist/{project-cmd-D_w-4w5B.mjs → project-cmd-Mo0V9yKS.mjs} +25 -12
  95. package/dist/{project-paths-BQd7OmIo.mjs → project-paths-SK8nMHPp.mjs} +3 -1
  96. package/dist/{project-tsconfig-B-QtXjLQ.mjs → project-tsconfig-Ql2XsSQp.mjs} +2 -2
  97. package/dist/{protocol-Bnb0LFp3.d.mts → protocol-C-pqYJjE.d.mts} +3 -4
  98. package/dist/{provision-CPx2ZxsH.mjs → provision-Blnstcm2.mjs} +78 -45
  99. package/dist/r2-conditions-D1Wk8i7b.mjs +30 -0
  100. package/dist/{requests-B8sZxaFM.mjs → requests-BcKOVpRg.mjs} +5 -3
  101. package/dist/{resolve-project-BBMtLLV9.mjs → resolve-project--Vxawf7z.mjs} +2 -2
  102. package/dist/rollback-Bx85-0xh.mjs +166 -0
  103. package/dist/{rolldown-runtime-DJK8HYOj.mjs → rolldown-runtime-rQ84J-ij.mjs} +1 -1
  104. package/dist/{route-types-z1jtHEi_.mjs → route-types-Da-DpyUp.mjs} +77 -25
  105. package/dist/routes-stub.d.mts +22 -23
  106. package/dist/runner-mysql-7BPUNGmL.mjs +61 -0
  107. package/dist/{runner-pg-CHM76xuC.mjs → runner-pg-BkEza-dX.mjs} +18 -6
  108. package/dist/runtime/ai.d.mts +21 -14
  109. package/dist/runtime/ai.mjs +5 -4
  110. package/dist/runtime/auth-client-react.d.mts +3 -5
  111. package/dist/runtime/auth-client-solid.d.mts +3 -5
  112. package/dist/runtime/auth-client-svelte.d.mts +3 -5
  113. package/dist/runtime/auth-client-vue.d.mts +3 -5
  114. package/dist/runtime/auth-client.d.mts +3 -5
  115. package/dist/runtime/auth.d.mts +1 -1
  116. package/dist/runtime/better-auth-mysql.d.mts +10 -0
  117. package/dist/runtime/better-auth-mysql.mjs +49 -0
  118. package/dist/runtime/better-auth-pg.d.mts +8 -9
  119. package/dist/runtime/better-auth-pg.mjs +2 -2
  120. package/dist/runtime/better-auth.d.mts +8 -9
  121. package/dist/runtime/better-auth.mjs +2 -2
  122. package/dist/runtime/client-react.d.mts +1 -1
  123. package/dist/runtime/client-solid.d.mts +1 -1
  124. package/dist/runtime/client-svelte.d.mts +1 -1
  125. package/dist/runtime/client-vue.d.mts +1 -1
  126. package/dist/runtime/client.d.mts +1 -1
  127. package/dist/runtime/db-mysql.d.mts +2 -0
  128. package/dist/runtime/db-mysql.mjs +1 -0
  129. package/dist/runtime/db.d.mts +10 -11
  130. package/dist/runtime/durable.d.mts +47 -0
  131. package/dist/runtime/durable.mjs +146 -0
  132. package/dist/runtime/email/testing.d.mts +112 -0
  133. package/dist/runtime/email/testing.mjs +283 -0
  134. package/dist/runtime/email.d.mts +30 -0
  135. package/dist/runtime/email.mjs +573 -0
  136. package/dist/runtime/env-helpers.d.mts +2 -2
  137. package/dist/runtime/env-helpers.mjs +5 -42
  138. package/dist/runtime/env-public-client.d.mts +10 -11
  139. package/dist/runtime/env-public-client.mjs +1 -1
  140. package/dist/runtime/env-public.d.mts +2 -2
  141. package/dist/runtime/env-public.mjs +104 -49
  142. package/dist/runtime/env.d.mts +19 -18
  143. package/dist/runtime/env.mjs +15 -2
  144. package/dist/runtime/fetch-stream.d.mts +20 -21
  145. package/dist/runtime/fetch.d.mts +15 -16
  146. package/dist/runtime/handler.d.mts +1 -1
  147. package/dist/runtime/isr.d.mts +21 -22
  148. package/dist/runtime/isr.mjs +26 -8
  149. package/dist/runtime/kv.d.mts +9 -10
  150. package/dist/runtime/live-client.d.mts +5 -7
  151. package/dist/runtime/live-client.mjs +9 -7
  152. package/dist/runtime/live-server.d.mts +4 -5
  153. package/dist/runtime/live.d.mts +22 -24
  154. package/dist/runtime/live.mjs +1 -1
  155. package/dist/runtime/log.d.mts +16 -17
  156. package/dist/runtime/migration-handler-mysql.d.mts +4 -0
  157. package/dist/runtime/migration-handler-mysql.mjs +81 -0
  158. package/dist/runtime/migration-handler-pg.d.mts +2 -4
  159. package/dist/runtime/migration-handler.d.mts +5 -6
  160. package/dist/runtime/migration-handler.mjs +4 -3
  161. package/dist/runtime/queues.d.mts +3 -4
  162. package/dist/runtime/queues.mjs +2 -1
  163. package/dist/runtime/remote/binding-handler.d.mts +10 -12
  164. package/dist/runtime/remote/binding-handler.mjs +24 -3
  165. package/dist/runtime/remote/index.d.mts +5 -6
  166. package/dist/runtime/remote/index.mjs +21 -18
  167. package/dist/runtime/response.d.mts +10 -11
  168. package/dist/runtime/sandbox.d.mts +56 -55
  169. package/dist/runtime/sandbox.mjs +57 -49
  170. package/dist/runtime/schema-mysql.d.mts +1 -0
  171. package/dist/runtime/schema-mysql.mjs +2 -0
  172. package/dist/runtime/seed.d.mts +14 -9
  173. package/dist/runtime/sse-client.d.mts +6 -7
  174. package/dist/runtime/sse.d.mts +11 -12
  175. package/dist/runtime/storage.d.mts +3 -4
  176. package/dist/runtime/validator.d.mts +1 -1
  177. package/dist/runtime/ws-server.d.mts +12 -12
  178. package/dist/runtime/ws-server.mjs +32 -4
  179. package/dist/runtime/ws.d.mts +19 -21
  180. package/dist/{scan-ChWt4pX1.mjs → scan-BMH4rzlv.mjs} +42 -19
  181. package/dist/{scan-NU4xKGci.mjs → scan-CpK-57ug.mjs} +5 -4
  182. package/dist/{secret-Dt32J6RI.mjs → secret-ByhJ9AMl.mjs} +62 -5
  183. package/dist/{skills-CLjN0uUO.mjs → skills-Q46GZMO-.mjs} +6 -4
  184. package/dist/sqlite-validation-BzKMWnO4.mjs +25 -0
  185. package/dist/{standard-schema-DJ0HW7QP.d.mts → standard-schema-Fo_vCAZh.d.mts} +6 -6
  186. package/dist/{subcommand-prompt-BzV8iQZo.mjs → subcommand-prompt-WfySCQ7S.mjs} +67 -48
  187. package/dist/sveltekit.d.mts +12 -11
  188. package/dist/sveltekit.mjs +1 -1
  189. package/dist/types-BAp5AEBU.d.mts +79 -0
  190. package/dist/types-CKWnYgfy.d.mts +1 -0
  191. package/dist/{validate-Cw_RLeTj.mjs → validate-tBBN_dXH.mjs} +4 -3
  192. package/dist/wrangler--imS8n0d.mjs +1796 -0
  193. package/dist/{yarn-pnp-DJn3SAHF.mjs → yarn-pnp-DxSInkzL.mjs} +1 -1
  194. package/package.json +79 -65
  195. package/schema.json +22 -3
  196. package/skills/void/SKILL.md +59 -2
  197. package/skills/void/docs/guide/ai.md +32 -14
  198. package/skills/void/docs/guide/app-types.md +6 -6
  199. package/skills/void/docs/guide/auth.md +14 -16
  200. package/skills/void/docs/guide/database/d1.md +6 -0
  201. package/skills/void/docs/guide/database/mysql.md +60 -0
  202. package/skills/void/docs/guide/database/postgresql.md +14 -9
  203. package/skills/void/docs/guide/database.md +39 -26
  204. package/skills/void/docs/guide/deployment.md +99 -25
  205. package/skills/void/docs/guide/durable-state.md +140 -0
  206. package/skills/void/docs/guide/edge/headers.md +5 -5
  207. package/skills/void/docs/guide/edge/prerendering.md +2 -0
  208. package/skills/void/docs/guide/edge/revalidation.md +21 -6
  209. package/skills/void/docs/guide/edge/rewrites.md +18 -14
  210. package/skills/void/docs/guide/edge/static-assets.md +12 -10
  211. package/skills/void/docs/guide/email.md +640 -0
  212. package/skills/void/docs/guide/env-migration.md +109 -0
  213. package/skills/void/docs/guide/env-vars.md +70 -248
  214. package/skills/void/docs/guide/index.md +15 -17
  215. package/skills/void/docs/guide/jobs.md +8 -5
  216. package/skills/void/docs/guide/live.md +7 -15
  217. package/skills/void/docs/guide/pages-routing/actions-and-forms.md +8 -4
  218. package/skills/void/docs/guide/pages-routing/islands.md +3 -3
  219. package/skills/void/docs/guide/pages-routing/loaders.md +6 -4
  220. package/skills/void/docs/guide/pages-routing/overview.md +7 -7
  221. package/skills/void/docs/guide/platform-administration.md +212 -0
  222. package/skills/void/docs/guide/platform-development.md +264 -0
  223. package/skills/void/docs/guide/queues.md +10 -10
  224. package/skills/void/docs/guide/quickstart.md +46 -67
  225. package/skills/void/docs/guide/remote-dev.md +8 -6
  226. package/skills/void/docs/guide/sandboxes.md +33 -16
  227. package/skills/void/docs/guide/self-hosted-platform.md +553 -0
  228. package/skills/void/docs/guide/server-routing.md +5 -5
  229. package/skills/void/docs/guide/sse.md +4 -4
  230. package/skills/void/docs/guide/ssg.md +5 -3
  231. package/skills/void/docs/guide/storage.md +2 -2
  232. package/skills/void/docs/guide/websockets.md +15 -7
  233. package/skills/void/docs/index.md +3 -3
  234. package/skills/void/docs/integrations/agents.md +6 -64
  235. package/skills/void/docs/integrations/cloudflare.md +165 -146
  236. package/skills/void/docs/integrations/frameworks/analog.md +4 -4
  237. package/skills/void/docs/integrations/frameworks/astro.md +5 -5
  238. package/skills/void/docs/integrations/frameworks/nuxt.md +5 -5
  239. package/skills/void/docs/integrations/frameworks/overview.md +3 -3
  240. package/skills/void/docs/integrations/frameworks/react-router.md +3 -3
  241. package/skills/void/docs/integrations/frameworks/sveltekit.md +3 -3
  242. package/skills/void/docs/integrations/frameworks/tanstack-start.md +2 -2
  243. package/skills/void/docs/integrations/nodejs-bun-deno.md +11 -4
  244. package/skills/void/docs/reference/api.md +42 -6
  245. package/skills/void/docs/reference/cli.md +665 -160
  246. package/skills/void/docs/reference/config.md +67 -27
  247. package/skills/void/docs/reference/resource-inference.md +13 -9
  248. package/skills/void/docs/reference/structure.md +9 -11
  249. package/AGENT_PROMPT.md +0 -19
  250. package/dist/cf-access-Bqw81xAf.mjs +0 -22
  251. package/dist/env-CZy5MorI.mjs +0 -299
  252. package/dist/env-helpers-z4stu8uc.d.mts +0 -52
  253. package/dist/env-mask-Dd47NbR6.mjs +0 -90
  254. package/dist/env-public-BfiLcMBk.d.mts +0 -140
  255. package/dist/link-CdGHSIy-.mjs +0 -45
  256. package/dist/mcp-DoM3_nhd.mjs +0 -377
  257. package/dist/project-paths-GpziKeQQ.d.mts +0 -25
  258. package/dist/providers-BNKRacMr.d.mts +0 -7
  259. package/dist/proxy-D-3_D-Gl.mjs +0 -5
  260. package/dist/rollback-CkvTFXx5.mjs +0 -90
  261. package/dist/runtime/isr-cache.d.mts +0 -207
  262. package/dist/runtime/isr-cache.mjs +0 -523
  263. package/dist/types-lLjNE9Qp.d.mts +0 -51
  264. package/getting-started-prompt.txt +0 -28
  265. package/skills/void/command/void.md +0 -7
  266. package/skills/void/docs/integrations/auth-providers.md +0 -0
  267. package/skills/void/docs/integrations/payment-processors.md +0 -0
  268. package/skills/void/docs/node_modules/@iconify/vue/README.md +0 -408
  269. package/skills/void/docs/node_modules/@iconify/vue/offline/readme.md +0 -5
  270. package/skills/void/docs/node_modules/@voidzero-dev/vitepress-theme/README.md +0 -103
  271. package/skills/void/docs/node_modules/oxc-minify/README.md +0 -78
  272. package/skills/void/docs/node_modules/reka-ui/README.md +0 -80
  273. package/skills/void/docs/node_modules/vitepress/README.md +0 -28
  274. package/skills/void/docs/node_modules/vitepress/template/api-examples.md +0 -49
  275. package/skills/void/docs/node_modules/vitepress/template/index.md +0 -28
  276. package/skills/void/docs/node_modules/vitepress/template/markdown-examples.md +0 -85
  277. package/skills/void/docs/node_modules/vitepress-plugin-group-icons/README.md +0 -101
  278. package/skills/void/docs/node_modules/void/AGENT_PROMPT.md +0 -19
  279. package/skills/void/docs/node_modules/void/CLAUDE.md +0 -221
  280. package/skills/void/docs/node_modules/void/README.md +0 -90
  281. package/skills/void/docs/node_modules/void/node_modules/@clack/prompts/CHANGELOG.md +0 -685
  282. package/skills/void/docs/node_modules/void/node_modules/@clack/prompts/README.md +0 -396
  283. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/sandbox/README.md +0 -219
  284. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/vite-plugin/README.md +0 -37
  285. package/skills/void/docs/node_modules/void/node_modules/@cloudflare/workers-types/README.md +0 -135
  286. package/skills/void/docs/node_modules/void/node_modules/@electric-sql/pglite/README.md +0 -189
  287. package/skills/void/docs/node_modules/void/node_modules/@hono/oauth-providers/CHANGELOG.md +0 -143
  288. package/skills/void/docs/node_modules/void/node_modules/@hono/oauth-providers/README.md +0 -1272
  289. package/skills/void/docs/node_modules/void/node_modules/@napi-rs/keyring/README.md +0 -19
  290. package/skills/void/docs/node_modules/void/node_modules/@types/better-sqlite3/README.md +0 -15
  291. package/skills/void/docs/node_modules/void/node_modules/@types/node/README.md +0 -15
  292. package/skills/void/docs/node_modules/void/node_modules/@types/pg/README.md +0 -15
  293. package/skills/void/docs/node_modules/void/node_modules/@types/proper-lockfile/README.md +0 -51
  294. package/skills/void/docs/node_modules/void/node_modules/@typescript/native-preview/README.md +0 -22
  295. package/skills/void/docs/node_modules/void/node_modules/@typescript/native-preview/vendor/vscode-jsonrpc/README.md +0 -69
  296. package/skills/void/docs/node_modules/void/node_modules/@void/md/README.md +0 -153
  297. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@shikijs/engine-javascript/README.md +0 -9
  298. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@shikijs/transformers/README.md +0 -9
  299. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/@types/node/README.md +0 -15
  300. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/gray-matter/CHANGELOG.md +0 -24
  301. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/gray-matter/README.md +0 -565
  302. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-exit/README.md +0 -127
  303. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-anchor/README.md +0 -600
  304. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-attrs/README.md +0 -386
  305. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-container/README.md +0 -95
  306. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-emoji/README.md +0 -101
  307. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/markdown-it-footnote/README.md +0 -135
  308. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/pathslash/README.md +0 -64
  309. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/shiki/README.md +0 -15
  310. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/tinyglobby/README.md +0 -25
  311. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/AGENTS.md +0 -16
  312. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/README.md +0 -220
  313. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/build.md +0 -21
  314. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/check.md +0 -35
  315. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/create.md +0 -70
  316. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/fmt.md +0 -20
  317. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/index.md +0 -35
  318. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/lint.md +0 -26
  319. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/pack.md +0 -17
  320. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/run.md +0 -364
  321. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/staged.md +0 -15
  322. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/config/test.md +0 -18
  323. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/automatic-data-tracking.md +0 -145
  324. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/build.md +0 -40
  325. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/cache.md +0 -107
  326. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/check.md +0 -60
  327. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/ci.md +0 -62
  328. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/commit-hooks.md +0 -60
  329. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/create.md +0 -341
  330. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/dev.md +0 -24
  331. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/docker.md +0 -175
  332. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/env.md +0 -167
  333. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/fmt.md +0 -41
  334. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/github-actions-cache.md +0 -165
  335. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/ide-integration.md +0 -101
  336. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/implode.md +0 -23
  337. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/index.md +0 -134
  338. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/install.md +0 -199
  339. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/lint.md +0 -50
  340. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/migrate-rules.md +0 -347
  341. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/migrate.md +0 -197
  342. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/monorepo.md +0 -176
  343. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/pack.md +0 -69
  344. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/run.md +0 -356
  345. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/test.md +0 -35
  346. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/troubleshooting.md +0 -108
  347. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/upgrade.md +0 -101
  348. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/vpx.md +0 -66
  349. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/guide/why.md +0 -39
  350. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/index.md +0 -12
  351. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/docs/team.md +0 -35
  352. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/templates/generator/README.md +0 -35
  353. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vite-plus/templates/monorepo/README.md +0 -29
  354. package/skills/void/docs/node_modules/void/node_modules/@void/md/node_modules/vue/README.md +0 -58
  355. package/skills/void/docs/node_modules/void/node_modules/arktype/README.md +0 -165
  356. package/skills/void/docs/node_modules/void/node_modules/better-auth/LICENSE.md +0 -20
  357. package/skills/void/docs/node_modules/void/node_modules/better-auth/README.md +0 -32
  358. package/skills/void/docs/node_modules/void/node_modules/better-sqlite3/README.md +0 -99
  359. package/skills/void/docs/node_modules/void/node_modules/blake3-jit/README.md +0 -108
  360. package/skills/void/docs/node_modules/void/node_modules/drizzle-arktype/README.md +0 -51
  361. package/skills/void/docs/node_modules/void/node_modules/drizzle-kit/README.md +0 -79
  362. package/skills/void/docs/node_modules/void/node_modules/drizzle-orm/README.md +0 -44
  363. package/skills/void/docs/node_modules/void/node_modules/drizzle-valibot/README.md +0 -51
  364. package/skills/void/docs/node_modules/void/node_modules/drizzle-zod/README.md +0 -65
  365. package/skills/void/docs/node_modules/void/node_modules/es-module-lexer/README.md +0 -403
  366. package/skills/void/docs/node_modules/void/node_modules/estree-walker/README.md +0 -48
  367. package/skills/void/docs/node_modules/void/node_modules/hono/README.md +0 -85
  368. package/skills/void/docs/node_modules/void/node_modules/ignore/README.md +0 -452
  369. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/CHANGELOG.md +0 -76
  370. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/LICENSE.md +0 -21
  371. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/README.md +0 -364
  372. package/skills/void/docs/node_modules/void/node_modules/jsonc-parser/SECURITY.md +0 -41
  373. package/skills/void/docs/node_modules/void/node_modules/magic-string/README.md +0 -325
  374. package/skills/void/docs/node_modules/void/node_modules/ofetch/README.md +0 -398
  375. package/skills/void/docs/node_modules/void/node_modules/pathslash/README.md +0 -64
  376. package/skills/void/docs/node_modules/void/node_modules/pg/README.md +0 -96
  377. package/skills/void/docs/node_modules/void/node_modules/pglite-server/README.md +0 -135
  378. package/skills/void/docs/node_modules/void/node_modules/picocolors/README.md +0 -21
  379. package/skills/void/docs/node_modules/void/node_modules/proper-lockfile/CHANGELOG.md +0 -108
  380. package/skills/void/docs/node_modules/void/node_modules/proper-lockfile/README.md +0 -183
  381. package/skills/void/docs/node_modules/void/node_modules/tinyglobby/README.md +0 -25
  382. package/skills/void/docs/node_modules/void/node_modules/valibot/LICENSE.md +0 -9
  383. package/skills/void/docs/node_modules/void/node_modules/valibot/README.md +0 -94
  384. package/skills/void/docs/node_modules/void/node_modules/vite-plus/AGENTS.md +0 -16
  385. package/skills/void/docs/node_modules/void/node_modules/vite-plus/README.md +0 -220
  386. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/build.md +0 -21
  387. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/check.md +0 -35
  388. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/create.md +0 -70
  389. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/fmt.md +0 -20
  390. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/index.md +0 -35
  391. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/lint.md +0 -26
  392. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/pack.md +0 -17
  393. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/run.md +0 -364
  394. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/staged.md +0 -15
  395. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/config/test.md +0 -18
  396. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/automatic-data-tracking.md +0 -145
  397. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/build.md +0 -40
  398. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/cache.md +0 -107
  399. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/check.md +0 -60
  400. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/ci.md +0 -62
  401. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/commit-hooks.md +0 -60
  402. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/create.md +0 -341
  403. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/dev.md +0 -24
  404. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/docker.md +0 -175
  405. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/env.md +0 -167
  406. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/fmt.md +0 -41
  407. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/github-actions-cache.md +0 -165
  408. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/ide-integration.md +0 -101
  409. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/implode.md +0 -23
  410. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/index.md +0 -134
  411. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/install.md +0 -199
  412. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/lint.md +0 -50
  413. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/migrate-rules.md +0 -347
  414. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/migrate.md +0 -197
  415. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/monorepo.md +0 -176
  416. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/pack.md +0 -69
  417. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/run.md +0 -356
  418. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/test.md +0 -35
  419. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/troubleshooting.md +0 -108
  420. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/upgrade.md +0 -101
  421. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/vpx.md +0 -66
  422. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/guide/why.md +0 -39
  423. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/index.md +0 -12
  424. package/skills/void/docs/node_modules/void/node_modules/vite-plus/docs/team.md +0 -35
  425. package/skills/void/docs/node_modules/void/node_modules/vite-plus/templates/generator/README.md +0 -35
  426. package/skills/void/docs/node_modules/void/node_modules/vite-plus/templates/monorepo/README.md +0 -29
  427. package/skills/void/docs/node_modules/void/node_modules/wrangler/README.md +0 -63
  428. package/skills/void/docs/node_modules/void/node_modules/zod/README.md +0 -191
  429. package/skills/void/docs/node_modules/void/skills/migrate-vite-cloudflare-to-void/SKILL.md +0 -175
  430. package/skills/void/docs/node_modules/void/skills/void/SKILL.md +0 -76
  431. package/skills/void/docs/node_modules/void/skills/void/command/void.md +0 -7
  432. package/skills/void/docs/node_modules/void/test/e2e/README.md +0 -85
@@ -10,44 +10,53 @@ Use this page as a command reference. If you are setting up a project for the fi
10
10
 
11
11
  ## Cheat Sheet
12
12
 
13
- | Command | Purpose |
14
- | --------------------------------- | ------------------------------------------------------------------- |
15
- | `void deploy` | Build and deploy to Void |
16
- | `void prepare` | Generate `.void` artifacts without starting Vite |
17
- | `void gen model <name> [cols...]` | Scaffold migration + CRUD routes |
18
- | `void gen route <path>` | Create an API route |
19
- | `void db push` | Apply schema directly without migration files |
20
- | `void db generate` | Generate SQL migrations from schema changes |
21
- | `void db status` | Show local/remote migration status |
22
- | `void db reset` | Drop and re-apply all migrations |
23
- | `void db seed` | Reset + seed local database |
24
- | `void db execute <sql>` | Run SQL against the database (--remote for deployed) |
25
- | `void db studio` | Open Drizzle Studio (--remote for the deployed PostgreSQL database) |
26
- | `void secret put <name=value>` | Set a production secret |
27
- | `void secret list` | List production secrets |
28
- | `void secret sync .env.local` | Bulk upload secrets from dotenv file |
29
- | `void env check [--remote]` | Validate env.ts schema |
30
- | `void env types` | Regenerate .void/env.d.ts from env.ts |
31
- | `void env example` | Refresh the void-managed block in .env.example |
32
- | `void auth login` | Authenticate with Void |
33
- | `void project link` | Link directory to a project |
34
- | `void project logs` | Show runtime logs from deployed project |
35
- | `void project requests` | Show request-level traffic (status, method, timing) |
36
- | `void project rollback` | Roll back to a previous deployment |
37
- | `void project cancel` | Cancel an active deployment |
38
- | `void project purge-cache` | Purge all cached pages |
39
- | `void build logs` | Stream, tail, or download build logs |
40
- | `void mcp` | Start the Void MCP server |
41
- | `void init` | Setup wizard for new or existing projects |
13
+ | Command | Purpose |
14
+ | --------------------------------- | ----------------------------------------------------------------------------- |
15
+ | `void deploy` | Build and deploy to the configured platform |
16
+ | `void prepare` | Generate `.void` artifacts without starting Vite |
17
+ | `void gen model <name> [cols...]` | Scaffold migration + CRUD routes |
18
+ | `void gen route <path>` | Create an API route |
19
+ | `void db push` | Apply schema directly without migration files |
20
+ | `void db generate` | Generate SQL migrations from schema changes |
21
+ | `void db status` | Show local/remote migration status |
22
+ | `void db reset` | Drop and re-apply all migrations |
23
+ | `void db seed` | Reset + seed local database |
24
+ | `void db execute <sql>` | Run SQL against the database (--remote for deployed) |
25
+ | `void db studio` | Open Drizzle Studio (--remote for a deployed external database) |
26
+ | `void secret put <name=value>` | Set a production secret |
27
+ | `void secret list` | List production secrets |
28
+ | `void secret sync .env` | Bulk upload secrets from dotenv file |
29
+ | `void env check [--remote]` | Validate env.ts schema |
30
+ | `void env types` | Regenerate .void/env.d.ts from env.ts |
31
+ | `void auth login` | Authenticate with Void |
32
+ | `void cloudflare login` | Authenticate with Cloudflare through Void |
33
+ | `void platform install` | Install a company Void platform in Cloudflare |
34
+ | `void connect <url>` | Connect the CLI to a Void platform |
35
+ | `void project link` | Link directory to a project |
36
+ | `void project logs` | Show runtime logs from deployed project |
37
+ | `void project requests` | Show request-level traffic (status, method, timing) |
38
+ | `void project rollback` | Roll back to a previous deployment |
39
+ | `void project cancel` | Cancel an active deployment |
40
+ | `void project purge-cache` | Purge all cached pages |
41
+ | `void build logs` | Stream, tail, or download build logs |
42
+ | `void email status` | Show email readiness on your own Cloudflare account (`--platform cloudflare`) |
43
+ | `void email setup` | Set email up on your own Cloudflare account, without deploying |
44
+ | `void email usage` | Show monthly email send/receive counts and quota |
45
+ | `void email logs` | Show recent email delivery activity |
46
+ | `void email destinations` | List verified recipient addresses |
47
+ | `void email allow <address>` | Add a recipient and send a verification email |
48
+ | `void email disallow <address>` | Remove a recipient from the allowlist |
49
+ | `void email domain` | Send and receive at your own domain on a Cloudflare zone |
50
+ | `void init` | Setup wizard for new or existing projects |
42
51
 
43
52
  ## Binary Invocation
44
53
 
45
- Outside npm scripts, invoke `void` with `npx`, `pnpm`, `yarn`, or `bunx`. For readability, the docs show unprefixed `void` commands. In practice, you still need a binary runner unless the executable is already on your `PATH`.
54
+ The docs use `void` for brevity. Outside package scripts, run it with your package manager: `npx void`, `pnpm void`, `yarn void`, or `bunx void`.
46
55
 
47
56
  Alternatively, you can add `./node_modules/.bin` to your `PATH` so that you can invoke `void` directly when you are in the root directory of your app.
48
57
 
49
58
  :::warning ⚠️ Prefer local install
50
- We do not recommend installing `void` globally, because the CLI needs to be in sync with same version of the runtime framework. Always install `void` locally as a dev dependency of your project.
59
+ Install `void` in your project so the CLI and runtime use the same version.
51
60
  :::
52
61
 
53
62
  ## Help
@@ -62,49 +71,65 @@ void <group> <command> --help
62
71
  void <group> help <command>
63
72
  ```
64
73
 
65
- Use `void --help` or `void help` for the top-level command list. Every command and grouped subcommand has a focused help page, so `void deploy --help`, `void help db execute`, and `void db help execute` all print command-specific usage before any command validation or network/auth work runs.
74
+ Use `void --help` for the command list. For a specific command, try `void deploy --help` or `void db execute --help`. Help runs without signing in, validating the project, or making network requests.
66
75
 
67
76
  ## Setup
68
77
 
69
78
  ### `void init`
70
79
 
71
80
  ```
72
- void init [--tsconfig] [--github] [--agents]
81
+ void init [--tsconfig] [--github] [--agents] [--git | --no-git]
73
82
  ```
74
83
 
75
84
  Setup wizard for Void projects (new or existing).
76
85
 
77
- If run in a scaffoldable empty directory, `void init` scaffolds a Pages starter. It asks which scaffold toolchain to use, with Vite+ as the default top option and plain Vite as the alternative. If a single Pages adapter is already installed, it reuses that framework; otherwise it asks which framework to scaffold (React, Vue, Svelte, or Solid). It then asks which starter you want: D1, PostgreSQL, or Static Pages. The D1 and PostgreSQL starters write a framework-specific `vite.config.ts`, a `pages/` home page plus `.server.ts` loader, `db/schema.ts`, `db/seed.ts`, a generated initial migration under `db/migrations/`, and `routes/api/hello.ts`. The Static Pages starter writes just the framework-specific `vite.config.ts` and a `pages/` home page so you can add server features later. Vite+ starters add `vite-plus` and use `vp dev`, `vp build`, and `vp preview` scripts.
86
+ Outside an existing Git repository or workspace package, the interactive wizard first asks **Initialize a git repository?**, with Yes selected. Accepting runs `git init` using your Git default branch. At the end, Void suggests an optional `git add -A && git commit -m "chore: initial commit"` command; it does not stage files or commit automatically. Git initialization failures produce a warning and setup continues.
78
87
 
79
- If run in a non-empty folder that does not look like an app yet, such as a parent `Projects/` folder with subdirectories but no `package.json`, `void init` asks whether to create a new subfolder or continue in the current folder. Creating a subfolder is the default selection.
88
+ Use `--git` to initialize without the Git prompt, or `--no-git` to skip it. In CI or without an interactive terminal, Git initialization requires `--git`. Existing repositories, including parent repositories, are preserved. Workspace packages skip Git initialization and do not accept these two flags.
80
89
 
81
- If run in an existing project, `void init` configures the project in place: it ensures `void` and `vite` are declared, adds missing `dev` (`vite`) and `build` (`vite build`) scripts without overwriting existing scripts, and creates or patches `vite.config.*` with `voidPlugin()` when the config shape is safe to edit. If the Vite config is too dynamic to patch confidently, it prints the manual snippet instead of rewriting it.
90
+ Void's `.gitignore` defaults exclude dependencies, generated files, `.env`, and `.env.*`, while allowing `.env.example` to be committed.
91
+
92
+ In an empty project, `void init` asks you to choose:
93
+
94
+ - **Toolchain:** Vite+ (the default) or plain Vite.
95
+ - **Framework:** React, Vue, Svelte, or Solid. If one Pages adapter is already installed, Void uses it.
96
+ - **Starter:** D1, PostgreSQL, MySQL, or Static Pages.
97
+
98
+ Database starters include the framework config, a page and server loader, schema, seed, initial migration, and `routes/api/hello.ts`. Static Pages includes the framework config and home page. Vite+ starters use `vp dev`, `vp build`, and `vp preview`.
99
+
100
+ If the directory contains other files but isn't an app yet, Void offers to create a subfolder. You can choose to continue in the current directory instead.
101
+
102
+ In an existing app, Void adds missing dependencies and scripts, then updates `vite.config.*` with `voidPlugin()`. Existing scripts are preserved. If the config is too dynamic to edit, Void prints the snippet for you to add.
82
103
 
83
104
  After that, the full interactive flow walks through:
84
105
 
85
106
  1. **TypeScript:** creates or updates `tsconfig.json`, including `extends .void/tsconfig.json`, `void/env` types, and root-level `files` / `compilerOptions.paths` merges when an existing config would otherwise replace Void's generated entries.
86
- 2. **Database:** asks whether you want D1, PostgreSQL, or no database yet. Choosing PostgreSQL writes `"database": "pg"` to `void.json`; D1 stays implicit; choosing no database leaves config unchanged so you can add data features later.
87
- 3. **Agent instructions:** detects agents once and injects instructions into `CLAUDE.md` or `AGENTS.md`.
88
- 4. **Skills:** links Void skills using the same detected or selected agent context.
89
- 5. **MCP config:** writes MCP server config using that same agent context.
90
- 6. **Demo code:** for existing non-Pages projects, optionally scaffolds a `db/migrations/` directory plus an API route and typed fetch example.
91
- 7. **GitHub Actions:** optionally creates `.github/workflows/void-deploy.yml`. The workflow deploys on pushes to `main` and authenticates via [GitHub OIDC](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect) — no long-lived `VOID_TOKEN` secret is stored in the repo. The workflow is a single `void deploy` step: when it runs in GitHub Actions, `void deploy` mints an OIDC token (audience `void`), exchanges it at `POST $VOID_API_URL/auth/github-oidc` for a short-lived project-scoped deploy token, and deploys. `permissions: id-token: write` is retained so the CLI can mint that token. The project slug is baked in from your linked project (`.void/project.json`) when known; otherwise the workflow reads a `VOID_PROJECT` repository variable.
92
- 8. **`env.ts` scaffold:** if the project has no `env.ts` but has `.env` / `.env.example` / `.env.local` / `.env.development*` files on disk, generates an `env.ts` pre-populated with their keys. Values get conservative type inference (`boolean`/`url`/`number`/`string`) — the file carries a banner nudging you to tighten anything the heuristic got wrong.
93
- 9. **Project setup:** optionally logs you in, lets you select or create a project, and writes `.void/project.json` so your first deploy can just be `void deploy`.
107
+ 2. **Database:** asks whether you want D1, PostgreSQL, MySQL, or no database yet. PostgreSQL writes `"database": "pg"`; MySQL writes `"database": "mysql"`; D1 stays implicit.
108
+ 3. **Agent instructions:** always creates or updates `AGENTS.md` with brief Void instructions and the bundled docs path, preserving content outside the versioned block.
109
+ 4. **Skills:** links Void skills for detected coding agents.
110
+ 5. **Demo code:** for existing non-Pages projects, optionally scaffolds a `db/migrations/` directory plus an API route and typed fetch example.
111
+ 6. **Deployment platform:** asks where `void deploy` should send the app: Cloudflare (the default), Void, or Skip deployment setup. The choice is stored as `platform` in `.void/project.json`. Choosing Cloudflare creates or augments `wrangler.jsonc`, checks the Cloudflare session through Void's bundled tooling, opens secure browser sign-in when needed, and writes the selected account as `account_id` (automatically when only one account is available).
112
+ 7. **GitHub Actions:** optionally creates `.github/workflows/void-deploy.yml` for the selected target. Cloudflare workflows run `void deploy --platform cloudflare` with `CLOUDFLARE_API_TOKEN` and pass the optional `DATABASE_URL` secret needed by PostgreSQL/MySQL apps. Void workflows use the selected platform's API URL and are offered only when its discovery document advertises GitHub Actions support.
113
+ 8. **`env.ts` scaffold:** if the project has no `env.ts` but has a root `.env`, generates an `env.ts` pre-populated with its keys. Values get conservative type inference (`boolean`/`url`/`number`/`string`) — the file carries a banner nudging you to tighten anything the heuristic got wrong.
114
+ 9. **Void project setup:** when Void is selected, optionally logs you in, lets you select or create a project, and adds the link to `.void/project.json` so your first deploy can just be `void deploy`.
94
115
 
95
- If no agent is detected, `void init` asks you to choose one from a short list (Claude, Cursor, Codex, Gemini CLI, Generic). That single choice is reused across all agent steps.
116
+ If Cloudflare sign-in is declined or does not complete, initialization still finishes with the configuration in place. Rerun `void init`, or use `void cloudflare login`, when you are ready.
117
+
118
+ Agent setup never asks which coding agent you use. If no agent is detected, skill linking is skipped; `AGENTS.md` still points to the complete docs at `node_modules/void/skills/void/docs/`.
96
119
 
97
120
  Use flags to run individual steps without prompts:
98
121
 
99
- | Flag | Purpose |
100
- | ------------ | ------------------------------------------------- |
101
- | `--tsconfig` | Only update `tsconfig.json` |
102
- | `--agents` | Set up agent instructions, skills, and MCP config |
103
- | `--github` | Only create the GitHub Actions deploy workflow |
122
+ | Flag | Purpose |
123
+ | ------------ | ---------------------------------------------- |
124
+ | `--tsconfig` | Only update `tsconfig.json` |
125
+ | `--agents` | Set up agent instructions and skills |
126
+ | `--github` | Only create the GitHub Actions deploy workflow |
127
+
128
+ These step flags can be combined. When any of them is provided, only the specified steps run and interactive prompts are skipped. Git setup is skipped unless `--git` is also supplied. `--git` and `--no-git` alone keep the full setup wizard and control only its Git step.
104
129
 
105
- Flags can be combined. When any flag is provided, only the specified steps run and interactive prompts are skipped.
130
+ For Cloudflare, the generated workflow needs a `CLOUDFLARE_API_TOKEN` repository secret with access to your app's account and resources. PostgreSQL and MySQL apps also need `DATABASE_URL`.
106
131
 
107
- The `--github` workflow uses GitHub OIDC: you connect the repository to your Void project once with `void github connect <project> --repo <owner/repo> --executor github_actions` (see the GitHub section below), and pushes to `main` deploy automatically. There is no `VOID_TOKEN` secret to create or rotate. To target staging, set a `VOID_API_URL` repository variable to `https://api.staging.void.cloud`.
132
+ For a Void platform with GitHub Actions support, the workflow uses that platform's API URL and short-lived GitHub OIDC credentials. Authorize the repository with `void github connect <project> --repo <owner/repo> --executor github_actions`. Core self-hosted platforms don't yet support this integration, so Void explains that limitation instead of generating a workflow.
108
133
 
109
134
  For projects that already have `"extends"`, `void init --tsconfig` preserves the existing config and adds `./.void/tsconfig.json`. If the existing config defines `files` or `compilerOptions.paths`, Void also merges its generated declaration files and aliases into the root config because TypeScript replaces those fields across `extends` instead of deeply merging them.
110
135
 
@@ -118,13 +143,37 @@ Generates the project-local `.void/` artifacts used by TypeScript and runtime co
118
143
 
119
144
  This is the intended command for CI, fresh clones, editor bootstrap, and any workflow that needs `routes.d.ts`, `db.d.ts`, `queues.d.ts`, `env.d.ts`, and `.void/tsconfig.json` in place before typechecking.
120
145
 
146
+ ## Connect
147
+
148
+ ```sh
149
+ void connect
150
+ void connect https://platform.example.com
151
+ void connect --platform cloudflare
152
+ void connect --platform void
153
+ ```
154
+
155
+ Connect a project to its deployment destination. With no arguments, choose Cloudflare or a Void platform interactively. A URL selects a Void platform directly. `--platform void` offers saved platforms and an option to enter another URL.
156
+
157
+ For Cloudflare, Void signs in through the browser when needed, selects an accessible account, and saves `account_id` in the root `wrangler.jsonc` or `wrangler.json`. It shares this setup with `void init`. An existing account selection is preserved; conflicting or inaccessible account settings must be resolved before continuing.
158
+
159
+ For a Void platform, Void validates its discovery document, reuses a valid session or opens browser login using the platform's supported providers, and saves the verified API and proxy origins. Credentials are stored in the operating-system keychain for that API origin. A sole login provider is selected automatically.
160
+
161
+ The deployment preference is saved in `.void/project.json`. Connecting to another Void platform preserves an existing project link; the CLI explains when that link or an environment override still selects a different destination. Use `void project link` to explicitly choose a project. Cloudflare selection also retains existing Void project metadata so you can switch back later.
162
+
163
+ In a non-interactive shell, supply a URL or explicit target. Cloudflare requires usable credentials and an unambiguous account (`CLOUDFLARE_ACCOUNT_ID` when needed). For a Void platform, provide `VOID_TOKEN` with a matching `VOID_API_URL`, or reuse a valid origin-scoped keychain session. Use `void connect <url> --no-login` to save the verified connection without authenticating; this option is only available for Void platforms.
164
+
121
165
  ## Auth
122
166
 
123
167
  ### `void auth login`
124
168
 
125
- OAuth login. You choose GitHub or Google at the prompt, and the token is saved to `~/.void/config.json`.
169
+ OAuth login. You choose GitHub or Google at the prompt, and the token is saved in the operating-system keychain, scoped to the platform origin. Login fails closed when no keychain is available instead of writing the token to a plaintext file; headless environments use `VOID_TOKEN` from their secret manager.
126
170
 
127
- This is optional if you already completed auth during the interactive `void init` flow.
171
+ Set `VOID_API_URL` alongside `VOID_TOKEN` to identify the platform that issued it.
172
+ A token without an API URL is only used for Void Cloud's production API; a saved
173
+ connection or project cannot forward it to another platform. To use a platform's
174
+ saved login instead, unset `VOID_TOKEN`.
175
+
176
+ This is optional if you already completed auth during `void connect` or the interactive `void init` flow.
128
177
 
129
178
  ### `void auth logout`
130
179
 
@@ -138,22 +187,37 @@ Prints your current login.
138
187
 
139
188
  Copies your auth token to the system clipboard. Useful for setting up CI secrets.
140
189
 
190
+ ## Cloudflare authentication
191
+
192
+ Void ships and invokes compatible Cloudflare tooling itself. Users do not need to install or run a separate Cloudflare CLI. Browser credentials are stored in an encrypted file protected by the operating-system keychain. When Void adopts an existing browser session, it persists the secure-storage preference so subsequent logins through compatible tooling use the same credential store.
193
+
194
+ - `void cloudflare login` — open a fresh browser OAuth sign-in, including when already signed in. Use this to switch Cloudflare users without first logging out; Void does not remove the prior session before opening sign-in.
195
+ - `void cloudflare status` — show the authenticated email, authentication method, accessible account names and IDs, and the pinned deployment account and its source. Credential values are never printed.
196
+ - `void cloudflare logout` — remove the local browser session.
197
+
198
+ Interactive `void connect --platform cloudflare`, `void init`, and `void deploy --platform cloudflare` invoke the same login flow automatically when necessary. Non-interactive CI must set `CLOUDFLARE_API_TOKEN`.
199
+ When a browser session is required, Void opens Cloudflare login immediately and prints `Press Ctrl+C to cancel`; there is no redundant terminal confirmation.
200
+
201
+ Signing in changes the browser session, not `account_id` in the project configuration. Check `void cloudflare status` after switching users; if the new user cannot access the pinned account, resolve the project target separately before deploying.
202
+
203
+ An API token or global API key pair in the environment takes precedence over browser credentials. Explicit browser login stops with the names of these overrides; remove them from that shell before signing in. `status` reports the active credential source, and `logout` warns if environment credentials remain active. Explicit browser login requires an interactive terminal; automatic deployment checks continue to reuse valid sessions.
204
+
141
205
  ## Project commands
142
206
 
143
207
  ### `void project status [name]`
144
208
 
145
- Show the last 5 deployments for a project.
209
+ Show deployments for the configured target.
146
210
 
147
- - If `[name]` is provided, looks up the project by slug
148
- - Otherwise uses the linked project from `.void/project.json`
211
+ - Void targets show recent hosted deployments; `[name]` looks up a project by slug and otherwise the linked project is used.
212
+ - Cloudflare targets list Worker Versions, identify the active version, and show the recorded migration count. A project name is not accepted because the Worker name comes from root `wrangler.jsonc`.
149
213
 
150
214
  ### `void project link [name]`
151
215
 
152
- Link current directory to an existing project by slug, or select interactively if omitted. State is stored in `.void/project.json`.
216
+ Link current directory to an existing hosted Void project by slug, or select interactively if omitted. State is stored in `.void/project.json`. Direct Cloudflare apps use the Worker name in the root config and do not need linking.
153
217
 
154
218
  ### `void project list`
155
219
 
156
- List all your projects (slug, mode, URL).
220
+ List all hosted projects (slug, mode, URL). For a saved Cloudflare target, this displays the current Worker's versions instead because there is no Void project registry.
157
221
 
158
222
  ### `void project logs`
159
223
 
@@ -161,7 +225,7 @@ List all your projects (slug, mode, URL).
161
225
  void project logs [--level <level>] [--filter <text>] [--range <duration>] [--deployment <id>]
162
226
  ```
163
227
 
164
- Show runtime logs from the deployed project. Uses the linked project from `.void/project.json`.
228
+ Show runtime logs from the deployed target. Hosted Void targets query retained log history. Cloudflare targets open a live tail for the Worker named in root `wrangler.jsonc`; they do not provide historical log storage.
165
229
 
166
230
  | Flag | Purpose | Default |
167
231
  | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
@@ -179,7 +243,11 @@ void project logs --level error --range 12h
179
243
  void project logs --level error --filter websocket
180
244
  ```
181
245
 
182
- Tip: `void project logs` only sees what Cloudflare Tail captures — top-level `console.*` calls and uncaught throws. Application errors caught and persisted to your own DB are invisible to tail. Surface them via `console.error(...)` or `void/log`'s `logger.error(...)` so they show up under `--level error`. For 5xx that never reach your worker at all (edge-router errors, static/SPA projects), use `void project requests --status 5xx`.
246
+ Logs include top-level `console.*` calls and uncaught errors captured by Cloudflare Tail. If you catch an error and save it only to your database, it won't appear here. Also log it with `console.error()` or `logger.error()` from `void/log`.
247
+
248
+ For errors that never reach your Worker, such as edge routing errors or static site requests, use `void project requests --status 5xx`.
249
+
250
+ On a direct Cloudflare target, `--filter` becomes Cloudflare's live search, `--deployment` selects a Worker Version, and `--level error` selects error invocations. Other individual console levels cannot be filtered, and `--range` does not select history. `void project requests` is hosted-only.
183
251
 
184
252
  ### `void project requests`
185
253
 
@@ -212,12 +280,14 @@ void project requests --range 24h
212
280
  void project rollback [deployId]
213
281
  ```
214
282
 
215
- Roll back to a previous deployment. Traffic instantly switches to the target deployment's worker script via KV routing update.
283
+ Roll back to a previous deployment or Worker Version.
216
284
 
217
285
  - If `[deployId]` is omitted, shows an interactive select menu of retained deployments
218
286
  - If the target deployment has fewer applied migrations than the current one, a warning is shown listing the migration diff before confirmation
219
287
 
220
- Only **retained** deployments can be rolled back to. The number of retained deployments depends on your plan (free: 1, solo: 5, pro: 25, unlimited for sponsored/custom).
288
+ On a Void platform, you can select a retained deployment. On Cloudflare, use a complete Worker Version ID or an unambiguous prefix. Void activates that version at 100%. When both versions have complete trigger snapshots, it also restores the selected version's schedules, queues, workflows, routes, and custom domains. Otherwise, rollback keeps the current triggers and restores the code, including versions originally deployed outside Void.
289
+
290
+ Rollback doesn't reverse database migrations. If older code may run against a newer schema, or migration metadata is missing, Void explains the risk and asks for confirmation.
221
291
 
222
292
  ### `void project cancel [deployId]`
223
293
 
@@ -230,12 +300,16 @@ Cancel an active deployment.
230
300
  - If `[deployId]` is omitted, shows an interactive select menu of active deployments for the linked project
231
301
  - If `[deployId]` is provided, cancels that deployment directly
232
302
 
303
+ This command is hosted-only. Direct Cloudflare deploys are local operations and do not expose a remote build to cancel.
304
+
233
305
  ### `void project delete [name]`
234
306
 
235
- Permanently delete a project and all its resources (databases, KV namespaces, R2 buckets, deployments). Requires typing the project slug to confirm.
307
+ Permanently delete a hosted Void project and all its resources (databases, KV namespaces, R2 buckets, deployments). Requires typing the project slug to confirm.
236
308
 
237
309
  If `[name]` is omitted, uses the linked project.
238
310
 
311
+ For direct Cloudflare targets this command refuses to run. Inferred resources can be shared, so Void never performs automatic teardown; verify ownership and remove resources explicitly with Cloudflare tooling.
312
+
239
313
  ### `void project purge-cache`
240
314
 
241
315
  ```
@@ -246,34 +320,331 @@ Purge all cached pages for the linked project. The edge cache will clear within
246
320
 
247
321
  If `--project` is provided, purges that project's cache instead of the linked project.
248
322
 
323
+ This command is currently hosted-only. Direct Cloudflare cache purge fails closed with guidance.
324
+
325
+ ## Platform management
326
+
327
+ Void-managed projects deploy to an explicitly selected platform. Join one with [`void connect`](#connect). Connections are stored per API origin, and credentials are scoped to that origin.
328
+
329
+ ### Connection commands
330
+
331
+ ```sh
332
+ void platform list
333
+ void platform use [id]
334
+ void platform status [id]
335
+ ```
336
+
337
+ `use` and `status` auto-select the only configured platform; with multiple platforms they show a picker interactively and require an id or URL in non-interactive use. A project with a recorded platform URL keeps using that platform when the global default changes.
338
+
339
+ ### Operator commands
340
+
341
+ Use `void platform` to administer the users and apps on your selected platform. Start with the [Platform Administration guide](../guide/platform-administration.md) for signing in, giving people access, and investigating deployments.
342
+
343
+ Every command below accepts `--connection <registered-id-or-url>` to select a platform and `--json` for structured output. Without `--connection`, Void uses `VOID_API_URL` if set, then the active platform connection. Application project files do not change this selection.
344
+
345
+ #### Making Changes
346
+
347
+ Commands that change users, projects, signup access, invitations, or Workers show a preview before asking for confirmation:
348
+
349
+ ```sh
350
+ void platform user plan <user-id> pro --plan
351
+ void platform user plan <user-id> pro --yes
352
+ ```
353
+
354
+ `--plan` validates the change and prints its effect without applying it. `--yes` applies the change without prompting, which is required in scripts. Use one or the other; they cannot be combined. These flags also apply to deployment cancellation and maintenance commands, but not to authentication commands.
355
+
356
+ Each preview and apply request allows five minutes. Set `--timeout <seconds>` to an integer from 1 to 3600 to change that limit. Read requests and individual log polls allow 30 seconds.
357
+
358
+ Void does not automatically retry changes. If a request loses its connection or times out, inspect the affected objects and `void platform system events` before repeating it. Partial results describe the work that completed and exit with a nonzero status.
359
+
360
+ #### Authentication {#operator-authentication}
361
+
362
+ Sign in, inspect your session, or sign out:
363
+
364
+ ```sh
365
+ void platform auth login [--provider github|google] [--token-stdin]
366
+ void platform auth status
367
+ void platform auth logout
368
+ void platform auth token [--token-stdin]
369
+ ```
370
+
371
+ Browser login defaults to GitHub; Google is available when enabled on the platform. Login saves a one-hour administrator session in your system keychain. Logout revokes that session and removes its local credential.
372
+
373
+ `auth token` prints your current operator token. With `--token-stdin`, it exchanges a full administrator API login session from standard input for a new operator token. `auth login --token-stdin` saves the exchanged token to the keychain instead of printing it.
374
+
375
+ For automation, supply `VOID_OPERATOR_TOKEN` with an explicit `VOID_API_URL` or `--connection`. Operator tokens are stored separately from application deployment credentials. The API checks your current administrator access on every request. See [Using Scripts](../guide/platform-administration.md#using-scripts) for an example.
376
+
377
+ #### Users {#operator-users}
378
+
379
+ Find a user by login, email, or ID, then inspect their projects and usage:
380
+
381
+ ```sh
382
+ void platform user list [--search <text>] [--page <n>] [--limit <n>]
383
+ void platform user show <id>
384
+ ```
385
+
386
+ Use the same ID to change a plan, suspend or restore the account, or delete it:
387
+
388
+ ```sh
389
+ void platform user plan <id> <free|solo|pro|sponsored|custom>
390
+ void platform user suspend <id> [--reason <text>]
391
+ void platform user restore <id>
392
+ void platform user delete <id>
393
+ ```
394
+
395
+ Suspending a user blocks their applications. Deleting a user also deletes their project resources. A plan change updates resource limits while preserving any administrator suspension.
396
+
397
+ The last active administrator cannot be deleted or suspended. Both previews and
398
+ actual mutations enforce this rule, including in the browser admin UI. Allowed
399
+ administrator removals revoke administrator access before resource cleanup; if
400
+ cleanup fails, access stays revoked and the partial result reports it.
401
+
402
+ #### Projects {#operator-projects}
403
+
404
+ List projects across the platform, filter them by owner, or inspect one project's resources:
405
+
406
+ ```sh
407
+ void platform project list [--user <user-id>] [--search <text>] [--page <n>] [--limit <n>]
408
+ void platform project show <id>
409
+ void platform project delete <id>
410
+ ```
411
+
412
+ Search matches a project's slug, ID, or owner's login. `show` includes resources, domains, the latest 10 deployments, and the latest 20 builds. `delete` removes the project and its resources.
413
+
414
+ #### Deployments {#operator-deployments}
415
+
416
+ Find a deployment, inspect its manifest, or request cancellation:
417
+
418
+ ```sh
419
+ void platform deployment list [--project <id-or-slug>] [--status <status>] [--search <text>] [--page <n>] [--limit <n>]
420
+ void platform deployment show <id>
421
+ void platform deployment cancel <id>
422
+ ```
423
+
424
+ Cancellation applies while a deployment is pending, uploading, migrating, or prerendering, and can be requested again while it is canceling. A deployment that has begun switching traffic, is compensating for a failure, or has finished cannot be canceled through this command.
425
+
426
+ Read its runtime logs with:
427
+
428
+ ```sh
429
+ void platform deployment logs <id> [--since <time>] [--cursor <cursor>] [--limit <n>] [--follow]
430
+ ```
431
+
432
+ The default is the last hour, oldest first, with up to 100 records. `--since` accepts a duration such as `10m`, `2h`, or `1d`, an ISO date, or epoch milliseconds. Set `--limit` from 1 to 500 and pass the response's `nextCursor` as `--cursor` to read another page.
433
+
434
+ `--follow` reads the remaining pages and checks for new logs every two seconds until you press Ctrl+C. It checks a five-minute overlap for delayed records and suppresses replayed rows. Records that arrive later may need a subsequent historical query. Following stops with an error if a window exceeds 10,000 records; use a narrower historical query in that case.
435
+
436
+ #### Builds {#operator-builds}
437
+
438
+ Inspect a build or read its output:
439
+
440
+ ```sh
441
+ void platform build show <id>
442
+ void platform build logs <id> [--since <sequence>] [--limit <n>] [--follow]
443
+ ```
444
+
445
+ Build logs start at sequence `0` and return up to 500 lines. Use the returned `lastSeq` as `--since` to continue; `--limit` accepts 1 to 500. Container log retrieval requires managed builds to be enabled. GitHub Actions builds return an external log URL.
446
+
447
+ Following waits for the final logs after the build becomes terminal. If completion cannot be confirmed within two minutes, the command exits with an error. Older builds without a completion signal may wait for 30 seconds without new lines before following stops.
448
+
449
+ #### Signup Access {#operator-signup}
450
+
451
+ Inspect signup restrictions, open signup to everyone, or require an allowlist match:
452
+
453
+ ```sh
454
+ void platform signup show
455
+ void platform signup open
456
+ void platform signup restrict
457
+ ```
458
+
459
+ Add and remove entries by their type and pattern:
460
+
461
+ ```sh
462
+ void platform signup allow <github|email> <pattern> [--note <text>]
463
+ void platform signup remove <github|email> <pattern>
464
+ ```
465
+
466
+ GitHub entries match a login. Email entries match an address or a domain pattern such as `*@example.com`, across sign-in providers. Quote wildcard patterns in your shell. With restrictions enabled and an empty allowlist, nobody new can sign up.
467
+
468
+ #### Invitations {#operator-invitations}
469
+
470
+ Invite people by email and track whether they have joined:
471
+
472
+ ```sh
473
+ void platform invitation list [--page <n>] [--limit <n>]
474
+ void platform invitation send <email[,email...]>
475
+ void platform invitation revoke <id>
476
+ ```
477
+
478
+ Send accepts up to 100 comma-separated addresses. Invitations grant signup access even if email delivery is unavailable or fails; delivery is reported separately. Revoking a pending invitation removes its exact email grant. A broader domain entry can still allow that person to sign up.
479
+
480
+ #### System {#operator-system}
481
+
482
+ Inspect activity, check service health, or review administrative changes:
483
+
484
+ ```sh
485
+ void platform system overview
486
+ void platform system health
487
+ void platform system cli-versions
488
+ void platform system events [--page <n>] [--limit <n>]
489
+ void platform system backfill-queue-tokens
490
+ void platform system sandbox-drain [--cursor <opaque-cursor>]
491
+ ```
492
+
493
+ `overview` shows platform totals and recent activity. `health` checks the configured services and database, and exits with a nonzero status if a check fails. `cli-versions` reports the CLI versions used by deployments.
494
+
495
+ `events` shows the administrator, target, and outcome of changes. A pending event means the outcome has not been recorded. Previews and session login/logout do not create these events. `backfill-queue-tokens` repairs older queue entries that are missing authentication tokens and supports `--plan` before applying the repair.
496
+
497
+ Use `sandbox-drain` when an upgrade asks you to finish Sandbox cleanup. Preview with `--plan`; pass the returned `nextCursor` as `--cursor` to inspect later pages. Apply with `--yes` and rerun until it reports `complete: true`, then rerun the interrupted upgrade. Application traffic stays paused during cleanup, while administrator login remains available.
498
+
499
+ <span id="operator-workers"></span>
500
+
501
+ Use the [platform lifecycle commands](#lifecycle-commands) to maintain your installation's Workers.
502
+
503
+ #### Pagination and JSON
504
+
505
+ User, project, deployment, invitation, and event lists default to page `1` with 20 items. `--limit` accepts 1 to 100 for these lists. Their JSON responses include the page, limit, and total count.
506
+
507
+ With `--json`, results go to standard output and command errors go to standard error as JSON. Errors and partial failures exit with a nonzero status. An unhealthy `system health` result stays on standard output and also exits nonzero. Log following writes one JSON object per response, including each page and empty responses.
508
+
509
+ ### `void platform install`
510
+
511
+ ```sh
512
+ void platform install [options] [--yes]
513
+ ```
514
+
515
+ | Option | Purpose |
516
+ | --------------------------------- | ------------------------------------------------------------------------------------ |
517
+ | `--name <slug>` | Installation name used in `void-<name>-<role>` resource names; choose an unused name |
518
+ | `--display-name <name>` | Human-readable platform name |
519
+ | `--account <id>` | Cloudflare account id |
520
+ | `--application-domain <domain>` | Base domain for deployed apps |
521
+ | `--workers-dev` | Explicit testing mode; add an application domain later |
522
+ | `--zone <domain>` | Cloudflare zone containing the application domain |
523
+ | `--dedicated-zone` | Add zone-wide catch-all routes; valid only when the app domain is the whole zone |
524
+ | `--control-plane-domain <domain>` | Optional API custom hostname; defaults to `workers.dev` |
525
+ | `--plan` | Resolve and print a read-only plan |
526
+ | `--resume` | Continue the matching checkpointed installation |
527
+ | `--runtime <path>` | Deploy a locally built, integrity-checked runtime directory |
528
+ | `--yes` | Acknowledge Cloudflare changes in non-interactive use |
529
+
530
+ For a first installation, follow [Install a Void Platform](../guide/self-hosted-platform.md). The interactive installer recommends using a domain and offers **Use workers.dev for testing** as a visible alternative. Void creates the platform infrastructure and tables. External PostgreSQL and GitHub OAuth are required in either mode. `--workers-dev` skips zone/DNS/certificate operations and cannot be combined with `--application-domain`, `--zone`, or `--dedicated-zone`.
531
+
532
+ Read-only plans, workers.dev installations with the default API hostname, and supported lifecycle operations can use Cloudflare browser login and the system keychain. Installation that writes DNS or creates a zone needs an explicit management token through `CLOUDFLARE_API_TOKEN` or `CF_API_TOKEN`.
533
+
534
+ The installed platform needs a separate runtime token to provision resources for apps. The interactive installer prompts for it and the other setup values. For non-interactive installs, inject the variables listed in [Install from CI](../guide/self-hosted-platform.md#install-from-ci).
535
+
536
+ `--plan` prints the actual resource names, GitHub callback, and direct setup links without opening credential pages or saving a draft; Cloudflare browser login still opens if needed. New platform resources use `void-<name>-<role>` names without random suffixes. Existing installations keep their recorded names, and unowned name conflicts stop installation without overwriting resources. After you confirm an interactive install, Void opens each missing credential's setup page and shows a short permission/checklist fallback. The runtime-token link preselects all required account permissions, including Workers Tail, Hyperdrive, and AI Gateway when needed; domain installations must also select the indicated zone. Supplied credentials skip browser opening. Setup drafts pin Worker names and the GitHub callback and save partial credentials encrypted locally. Interactive installs list unfinished installations, including interrupted provisioning, or offer a new install. Entering an existing unfinished name asks to resume it; declining returns to name entry. Starting new leaves previous setup, credentials, and resources untouched. Completed platforms are not offered for resumption. `--resume` skips the choice and is required for non-interactive recovery.
537
+
538
+ Use an empty PostgreSQL database dedicated to the installation. You can correct a failed initial connection, but after the database is claimed or Hyperdrive is provisioned, commands reject a different URL.
539
+
540
+ Recovery secrets are encrypted with AES-256-GCM using a key in your system keychain. The encrypted data is tied to the installation identity. Without a keychain, supply a canonical base64-encoded 32-byte `VOID_PLATFORM_RECOVERY_KEY`; otherwise Void stops before saving secrets. CI can generate a temporary key when its original credentials remain in protected secrets.
541
+
542
+ If a newly created zone is waiting for registrar delegation, resume after it becomes active:
543
+
544
+ ```sh
545
+ void platform install --resume --name <installation-id>
546
+ ```
547
+
548
+ See [Self-host a Void platform](../guide/self-hosted-platform.md) for prerequisites, token scope, exact footprint, domain behavior, and an end-to-end walkthrough.
549
+
550
+ ### `void platform domain set`
551
+
552
+ ```sh
553
+ void platform domain set <domain> [--installation <id>] [--zone <domain>] [--dedicated-zone] [--plan] [--yes]
554
+ ```
555
+
556
+ Add an application domain to a workers.dev test platform. Domain-based installations remain the recommended default. The command detects the zone when possible, creates missing DNS and routes after confirmation, and checks HTTPS before making the domain canonical. If DNS or certificates are pending, rerun the same command to resume. `--plan` is read-only; non-interactive mutations require `--yes`.
557
+
558
+ Existing workers.dev URLs remain available, and the platform API origin, OAuth callback, projects, and deployments stay unchanged. The command verifies the running runtime token's Cache Purge permission for the new zone. A disabled platform stays disabled. Use the database URL from the original installation when administering from another machine. Replacing an already configured application domain is not supported. See [Add a Domain Later](../guide/self-hosted-platform.md#add-a-domain-later).
559
+
560
+ ### Lifecycle commands
561
+
562
+ Use these commands to recover, update, pause, or remove an installation:
563
+
564
+ ```sh
565
+ void platform discover [--account <id>] [--installation <id-or-name>]
566
+ void platform upgrade [id] [--runtime <path>] [--plan] [--yes]
567
+ void platform rollback [id] --runtime <earlier-path> [--from-runtime <current-path>] [--plan] [--yes]
568
+ void platform repair [id] [--runtime <path>] [--plan] [--yes]
569
+ void platform disable [id] [--plan] [--yes]
570
+ void platform enable [id] [--runtime <path>] [--plan] [--yes]
571
+ void platform uninstall [id] [--plan] [--purge-data] [--keep-zone] [--yes]
572
+ ```
573
+
574
+ `discover --installation` limits recovery and endpoint verification to one installation in a shared Cloudflare account.
575
+
576
+ Omit `id` when only one installation is configured, or choose from the interactive picker. Non-interactive commands need an ID when several installations exist. Commands that make changes also require `--yes`; `--plan` only previews changes.
577
+
578
+ After discovery on another machine, set `VOID_PLATFORM_DATABASE_URL`. Normal upgrades preserve deployed Worker secrets. Restore the original runtime, GitHub, R2, JWT, and project-encryption values only if repair needs to recreate a missing API or proxy Worker.
579
+
580
+ | Command | Behavior |
581
+ | ----------- | --------------------------------------------------------------------------------------------- |
582
+ | `discover` | Verifies remote ownership and restores local installation records without downloading secrets |
583
+ | `repair` | Recreates missing resources owned by the installer |
584
+ | `upgrade` | Deploys the selected runtime and supported pending migrations |
585
+ | `rollback` | Restores a declared-compatible earlier runtime without reversing PostgreSQL migrations |
586
+ | `disable` | Blocks platform traffic through routing storage without removing data |
587
+ | `enable` | Restores traffic after checking the platform |
588
+ | `uninstall` | Blocks traffic and removes eligible resources, retaining data by default |
589
+
590
+ Repair and upgrade preserve disabled state. New, resumed, and previously disabled installations block user traffic until all target Workers pass verification; the installer's health probes can still run. Routes and custom domains remain attached.
591
+
592
+ Commands preserve existing routes and domains, verify the configured database, and coordinate concurrent administrators before making changes.
593
+
594
+ `--runtime` selects a custom platform build. Relative paths resolve from your current directory. Void verifies the build before making changes; see [Platform Development](../guide/platform-development.md#deploying-your-runtime) for creating one.
595
+
596
+ Without `--runtime`, the CLI uses its packaged platform version.
597
+
598
+ Platform migrations only move forward. Void checks compatibility before updating the database and tells you if an intermediate release is needed.
599
+
600
+ An upgrade completes after the new Workers pass health checks. If rollout fails, Void attempts to restore the previous Workers. Retrying does not repeat completed migrations.
601
+
602
+ `platform rollback` restores a compatible earlier runtime without reversing database migrations. Pass its files with `--runtime`. If the installed version is a custom build, also supply that version with `--from-runtime`. Void refuses rollbacks that are incompatible with the current database. A later `upgrade` can move forward again.
603
+
604
+ Uninstall verifies remote ownership before removing anything. Data resources are retained unless you pass `--purge-data`. Workers, R2, AI Gateway, DNS records, routes, custom domains, adopted resources, external PostgreSQL, and zones are always retained for manual review.
605
+
606
+ Resources that may have been shared or repurposed are retained for manual review. Platform traffic stays blocked. External PostgreSQL and its data are never deleted.
607
+
608
+ See [Disable and safely uninstall](../guide/self-hosted-platform.md#disable-and-safely-uninstall) for the full removal policy.
609
+
249
610
  ## Deploy
250
611
 
251
612
  ### `void deploy`
252
613
 
253
614
  ```
254
615
  void deploy [--project <name>] [--dir <path>] [--spa] [--skip-build] [--debug]
255
- void deploy --backend cloudflare [--provision]
616
+ void deploy [--platform <cloudflare|void>] [--require-email]
256
617
  ```
257
618
 
258
619
  Auto-detects your project type and chooses the right pipeline. See [Supported App Types](../guide/app-types.md) and [Deployment](../guide/deployment.md) for details.
259
620
 
621
+ An unlinked project with a root `wrangler.jsonc` or `wrangler.json` gets a prompt to link and deploy to Cloudflare using its existing Worker and resources. Accepting verifies the target, saves Cloudflare as the destination, and continues deployment. A failed build retains the link for retry. Declining changes nothing. Explicit platform/project selections and saved destinations take precedence; CI must select a destination explicitly.
622
+
623
+ The first handoff preserves production bindings, variables, secrets, event handlers, and triggers. The active version must be the latest uploaded version so inherited secrets have an unambiguous source. Apart from an explicitly enabled ISR cache, new resources, migrations, runtime features, auth setup, or local secret overrides must be handled separately. See [Deploy an existing Worker](../integrations/cloudflare.md#deploy-an-existing-worker).
624
+
625
+ When prerendered or revalidated pages need a cache during migration, Void asks whether to enable ISR and saves `routing.isr` in `void.json`. Yes provisions the KV cache during this handoff; No keeps ISR disabled on every later deploy until you change the setting. CI must set `routing.isr` explicitly if a pending migration has no saved choice. Existing ISR namespaces are reused; application KV bindings are still required.
626
+
260
627
  For Drizzle projects, deploy performs a read-only schema drift check. If a new migration would be generated, deploy stops and tells you to run `void db generate`, review the migration, commit it yourself, and rerun `void deploy`.
261
628
 
262
- | Flag | Purpose |
263
- | ---------------------- | -------------------------------------------------------------------------------------------- |
264
- | `--project <name>` | Target a specific project by slug; not supported with `--backend cloudflare` |
265
- | `--dir <path>` | Deploy a pre-built static directory (skips build); not supported with `--backend cloudflare` |
266
- | `--spa` | Use SPA mode instead of SSG for static deploys; not supported with `--backend cloudflare` |
267
- | `--skip-build` | Skip the build step (use existing build output); not supported with `--backend cloudflare` |
268
- | `--backend cloudflare` | Deploy to your own Cloudflare account instead of the Void platform |
269
- | `--provision` | Create missing bindings (D1/KV/R2/Queues/Hyperdrive); requires `--backend cloudflare` |
270
- | `--debug` | Mirror the structured deploy log to stderr (also written to `~/.void/logs/`) |
629
+ | Flag | Purpose |
630
+ | ------------------------------- | -------------------------------------------------------------------------------------------------- |
631
+ | `--platform <cloudflare\|void>` | Override the platform stored in `.void/project.json` |
632
+ | `--project <name>` | Target a specific Void project by slug; not supported with `--platform cloudflare` |
633
+ | `--dir <path>` | Deploy a pre-built static directory (skips build) |
634
+ | `--spa` | Use SPA mode instead of SSG for static deploys |
635
+ | `--skip-build` | Skip the build step; on Cloudflare this is supported for static/SPA/SSG deploys only |
636
+ | `--require-email` | Fail when email cannot be set up instead of deploying without it; requires `--platform cloudflare` |
637
+ | `--debug` | Mirror the structured deploy log to stderr (also written to `~/.void/logs/`) |
638
+
639
+ The older `--backend cloudflare` spelling remains available as a compatibility alias for `--platform cloudflare`.
271
640
 
272
641
  Every deploy writes a structured JSONL trace to `~/.void/logs/deploy-<timestamp>.jsonl` regardless of `--debug`. On failure the path is printed at the end of the error message so you can attach it when reporting platform issues. `VOID_DEPLOY_DEBUG=1` is accepted as an alternate trigger for stderr mirroring.
273
642
 
643
+ Cloudflare upload failures include a detailed error message and stack locations when available. Use that message to identify the cause; the numeric error code alone may not be sufficient. The details are also available in the deploy log.
644
+
274
645
  When a deploy fails after it starts, the CLI also prints a summary of that trace under the error, so the cause is visible where the file is not — a CI runner, for example, is discarded with the job. The summary has two blocks: every `error` record with its flattened cause chain, then the last 20 records as a timeline.
275
646
 
276
- Pre-flight failures print no summary. A missing project, a rejected flag combination, or an unsupported `--backend cloudflare` feature stops before any trace exists, and each of those prints its own message explaining what to change. A build failure prints no summary either — the build streams its own output straight to the terminal.
647
+ Pre-flight failures print no summary. A missing project, a rejected flag combination, or an unsupported `--platform cloudflare` feature stops before any trace exists, and each of those prints its own message explaining what to change. A build failure prints no summary either — the build streams its own output straight to the terminal.
277
648
 
278
649
  Void masks the credentials it emits itself: signed query parameters, bearer tokens, and any field whose key names a credential.
279
650
 
@@ -295,7 +666,15 @@ Masking your own values is left to your CI platform, which holds the secrets and
295
666
  │ 9.0s error deploy_server_error message=deploy in progress
296
667
  ```
297
668
 
298
- Project resolution precedence:
669
+ Platform resolution precedence:
670
+
671
+ 1. `--platform <cloudflare|void>` (or the legacy `--backend cloudflare` alias)
672
+ 2. `platform` in `.void/project.json`
673
+ 3. Void for projects initialized by an older SDK without a saved platform
674
+
675
+ Selecting Skip deployment setup stores `"platform": "none"`; a later `void deploy` stops with guidance until a platform override is provided.
676
+
677
+ For the Void platform, project resolution precedence is:
299
678
 
300
679
  1. `--project <name>`
301
680
  2. `VOID_PROJECT`
@@ -303,44 +682,58 @@ Project resolution precedence:
303
682
 
304
683
  If no project is linked and no override is provided, CLI prompts to link or create one. In CI (non-TTY), `void deploy` errors out instead — set `VOID_PROJECT` or pass `--project <slug>`.
305
684
 
685
+ A new project's slug is lowercase alphanumeric with interior dashes, at most 56 characters — it is also the project's email sender, `<slug>+noreply@<mail domain>`, and that local part must fit RFC 5321's 64 octets. Slugs of 5 characters or fewer need a paid plan. Creating a project also registers the owner's own email address as a recipient (see `void email allow`); the CLI says so, and `void email destinations` shows whether it is verified yet.
686
+
306
687
  That fallback is mainly for projects that skipped Void project setup during `void init`.
307
688
 
308
- ### `void deploy --backend cloudflare`
689
+ ### `void deploy --platform cloudflare`
309
690
 
310
- Deploy the built worker straight to **your own** Cloudflare account instead of the Void platform. This path uses your local `wrangler` auth and your root `wrangler.jsonc` — no Void login or linked project is involved.
691
+ Build and deploy to your Cloudflare account using the root `wrangler.jsonc`:
311
692
 
693
+ ```sh
694
+ void deploy --platform cloudflare
695
+ void deploy --platform cloudflare --require-email # fail instead of deploying without email
312
696
  ```
313
- void deploy --backend cloudflare # deploy using resources already in wrangler.jsonc
314
- void deploy --backend cloudflare --provision # create any missing resources first, then deploy
315
- ```
316
697
 
317
- Prerequisites:
698
+ Void signs you in through your browser when needed and saves the selected account. In CI, set `CLOUDFLARE_API_TOKEN` and, if the token can access several accounts, `CLOUDFLARE_ACCOUNT_ID`.
699
+
700
+ | Option or setting | Cloudflare behavior |
701
+ | ------------------------------ | -------------------------------------------------------------------------------------- |
702
+ | `--dir`, `--spa` | Deploy static output through a small Worker and Workers Assets |
703
+ | `--skip-build` | Reuse existing static, SPA, or SSG output; unavailable for Worker apps |
704
+ | `--project` | Unavailable; the Worker and account come from the Cloudflare config |
705
+ | Named environments | Unavailable; use the top-level root config |
706
+ | `CLOUDFLARE_WORKERS_SUBDOMAIN` | Needed in fresh CI when versions have no preview URL; cached locally after a deploy |
707
+ | `--require-email` | Fail instead of deploying without email when the email step cannot run, as in CI |
708
+ | `DATABASE_URL` | Required in the deploy environment for PostgreSQL or MySQL provisioning and migrations |
709
+
710
+ The token needs Workers Scripts: Edit, read access to bound resources, and edit permissions for products Void provisions. First-time Hyperdrive provisioning specifically needs `CLOUDFLARE_API_TOKEN` with Hyperdrive edit permission, or an existing config ID in `wrangler.jsonc`.
711
+
712
+ Email setup needs a browser session from `void cloudflare login`, which carries the Email Routing and Email Sending scopes (a session created by older Cloudflare tooling lacks them: `void cloudflare logout`, then sign in again), or a `CLOUDFLARE_API_TOKEN` that also has Email Routing Edit and Email Sending Edit. A Global API Key pair is refused.
318
713
 
319
- - A Cloudflare account must be **pinned**: set `account_id` in your root `wrangler.jsonc`, or export `CLOUDFLARE_ACCOUNT_ID`. A multi-account token otherwise makes wrangler prompt (or error in CI), which Void cannot intercept.
320
- - Authenticate wrangler (`wrangler login`, or set `CLOUDFLARE_API_TOKEN`). Deploy needs a token with `Workers Scripts:Edit` plus read on the resources you bind; `--provision` additionally needs per-product `*:Edit` (D1, KV, R2, Queues, Hyperdrive).
321
- - `CLOUDFLARE_API_TOKEN` is **required** to provision a Hyperdrive config for the first time — `wrangler login` covers every other resource, but wrangler exposes no machine-readable Hyperdrive list, so Void checks for an existing config over the Cloudflare REST API, which OAuth cannot authenticate. Without a token, `--provision` stops before touching your account. Alternatively create the Hyperdrive config yourself and put its id in `wrangler.jsonc` — deploying an already-provisioned Hyperdrive app needs no token.
322
- - `--skip-build` is **not supported** with `--backend cloudflare`: this backend validates the artifact the build emits (worker `vars` in `dist/ssr/wrangler.json`, the generated auth schema), so there is nothing to check without a fresh build.
323
- - `--project`, `--dir` and `--spa` are **not supported** with `--backend cloudflare` either, and are rejected rather than ignored: no Void project is resolved on this path, and it uploads the worker your build emits rather than a static directory.
324
- - Local Docker is required to build apps that use the sandbox.
714
+ Sandbox apps need Docker, [Workers Paid](https://dash.cloudflare.com/?to=/:account/workers/plans), and Containers access. API tokens need Account / Containers: Edit and Account / Cloudchamber: Edit. Void checks access before provisioning or building; apps without Sandbox skip that check.
325
715
 
326
- What it does, in order: settles the app class before any account op (v1 supports **full Void apps on the Cloudflare Workers target** -- worker-bearing apps running Void's routing, with D1/KV/R2/Queues/Hyperdrive and, on D1/SQLite, auth + ISR; framework SSR of every kind, static/SPA/SSG apps, node/bun/deno targets, and PostgreSQL apps with auth or with checked-in migrations all fail closed with guidance), pins the account and checks auth, provisions or drift-checks resources, **builds**, then gates on the artifact the build emitted — production secrets checked against the build's effective mode/envDir, the auth schema, and migration validation — then applies remote D1 migrations for SQLite apps (verifying the applied set equals the validated set and none remain pending), and finally runs `wrangler deploy` on exactly the verified artifact. Auth apps must ship checked-in migrations that produce the Better Auth schema — the managed platform's runtime auth-migration step does not run on this backend.
716
+ Void provisions inferred resources, builds and validates the app, applies migrations, validates remote secrets, and checks the uploaded Worker Version before sending it traffic. After activation it synchronizes routes, custom domains, cron triggers, queue consumers, and the Email Routing rules derived from `addresses`. Static, hybrid, and SSR output from supported frameworks is also supported. A brand-new Worker may need one ordinary deployment before the Versions API can be used.
327
717
 
328
- The build deliberately comes **before** the secret, auth-schema, and migration gates, because those gates inspect the real emitted worker rather than a prediction of it. A missing secret or a bad migration surfaces after the build has run — relevant when a build is expensive or has side effects. Remote D1 migrations run only once every gate has passed, so a failed gate mutates nothing remote.
718
+ If Cloudflare Access protects readiness URLs, supply an allowed `CF_ACCESS_CLIENT_ID` and `CF_ACCESS_CLIENT_SECRET` pair, or a short-lived local `CF_ACCESS_TOKEN`. These credentials are used only for matching HTTPS readiness requests. Versions without accessible previews can be checked at 0% traffic through the stable hostname.
329
719
 
330
- `--provision` creates any D1 database, KV namespace, R2 bucket, Queues, Hyperdrive config, and the ISR cache namespace your source needs, then lets wrangler write the real ids into your root `wrangler.jsonc`. It is **idempotent** — re-running creates nothing that already exists (it reads existing ids first). Notes:
720
+ Secrets and migrations are validated after the build, so a failed check may leave provisioned resources. It doesn't apply remote D1 migrations or upload the application Worker. PostgreSQL migrations are transactional; MySQL schema changes may partially apply on error.
331
721
 
332
- - **Provision is a single-operator, dev-machine action.** The lock that guards it is per local config path only; it does not coordinate across machines. Two people provisioning the same account at once could create duplicate resources. `--provision` also **fails closed in CI / non-interactive shells** unless your committed `wrangler.jsonc` already covers every resource (a provable no-op). Provision locally, commit the updated `wrangler.jsonc`, then let CI run `void deploy --backend cloudflare`.
333
- - **Your `wrangler.jsonc` is rewritten.** When wrangler writes the new ids, it preserves your comments but normalizes the whole file's indentation — expect that in the diff.
334
- - **Your `.env*` values ship as plaintext.** All four of `.env`, `.env.local`, `.env.production` and `.env.production.local` are loaded by this backend and baked into the worker's `vars` — the `.local` files included, unlike managed `void deploy`. A value also present in the shell environment is stripped back out. Move real secrets to `wrangler secret put <NAME>` so they are not committed into `wrangler.json`. Deploy warns on likely-plaintext secrets and hard-blocks on missing required secrets.
335
- - **First deploy of a not-yet-deployed worker:** its remote secrets can't be listed yet, so the secret gate prints the required key names and the `wrangler secret put <NAME>` commands to bootstrap them on the draft worker before deploying (or add a value to `.env` / `.env.production` and rerun).
722
+ Provisioning reuses known resource IDs and writes newly resolved IDs into `wrangler.jsonc`, preserving comments but possibly changing indentation. Commit that file for other machines and CI. Run the first deploy from one machine at a time because provisioning locks are local. The old `--provision` flag is accepted but no longer needed.
336
723
 
337
- See the [Cloudflare integration guide](../integrations/cloudflare.md#deploy-to-your-own-cloudflare-account) for the full walk-through.
724
+ `.env` is local-only and isn't emitted into Worker vars. Store every schema-declared server key with `void secret put <NAME>`; Void emits required names through `secrets.required` and blocks plaintext server vars. On a new Worker, set required secrets before retrying if the initial remote check reports them missing. Custom D1 layouts are accepted only when Cloudflare's exact file set, bytes, and numeric order match the migrations Void validated. Direct deploy and operational commands use the top-level root config and reject named environments and alternate config-path overrides.
725
+
726
+ Existing remote secrets are preserved. Void also preserves or creates `BETTER_AUTH_SECRET` for auth apps.
727
+
728
+ **Email.** When the app uses email (`sendEmail()` or `email/` handlers) and `void.json` has `email.from`, the deploy reads the state of that address's zone before the build — session scopes, zone, MX records, Email Routing, subaddressing, routing rules, Email Sending, and what `wrangler.jsonc` holds — prints a checklist of what it would change in your account, and asks once (default Yes). On Yes it enables what is missing, writes `send_email: [{ "name": "SEND_EMAIL" }]`, the `__VOID_EMAIL_FROM` var and the `addresses` array into `wrangler.jsonc`, and lets wrangler create the routing rules when the activated version's triggers are synchronized; the deploy ends with the address map. A deploy with nothing left to set up asks nothing. Without `email.from` the deploy prints `add "email": { "from": "you@mail.acme.com" } to void.json` and continues without email. Non-interactive runs (CI, or stdin/stdout not a terminal) never prompt: they print the checklist plus `Run void email setup --platform cloudflare once locally, commit wrangler.jsonc, then redeploy` and deploy without email (or with the setup `wrangler.jsonc` already carries, when the binding is committed; a committed `addresses` array whose routing is off is removed first, since wrangler's plan on it would fail after the upload) — unless `--require-email` is passed, which fails instead. A deploy whose account rows all read ready reconciles the two config rows — `addresses` against the current derivation and `vars.__VOID_EMAIL_FROM` against `email.from` — with a plain file write and no prompt. See [Your own Cloudflare account](../guide/email.md#your-own-cloudflare-account) for the whole flow, including the subdomain-vs-apex rule and what stays manual.
729
+
730
+ See the [Cloudflare guide](../integrations/cloudflare.md#deploy-to-your-own-cloudflare-account) for the complete deployment sequence, first-deploy exceptions, secret precedence, and recovery behavior.
338
731
 
339
732
  ## Database
340
733
 
341
734
  ### `void db push`
342
735
 
343
- Apply your Drizzle schema directly to the development database without creating migration files. For D1 projects, this updates the local D1 database used by dev. For PostgreSQL projects, this uses `DATABASE_URL` from `.env.local`.
736
+ Apply your Drizzle schema directly to the development database without creating migration files. D1 updates the local database; PostgreSQL and MySQL use `DATABASE_URL` from `.env`.
344
737
 
345
738
  Use this for quick schema iteration while prototyping. Before deploying, generate and review migration files with `void db generate`.
346
739
 
@@ -348,11 +741,13 @@ Use this for quick schema iteration while prototyping. Before deploying, generat
348
741
 
349
742
  Generate SQL migration files from schema changes.
350
743
 
351
- The command compares your current `db/schema.ts` or `db/schema/` modules against the last generated Drizzle snapshot and writes new migration artifacts under `db/migrations/`. Review and commit the generated files before deploying.
744
+ The command compares your current `db/schema.ts` or `db/schema/` modules against the last generated Drizzle snapshot and writes new migration artifacts under `db/migrations/`. When Void-managed auth is enabled, it also resolves the Better Auth schema in production mode and includes those tables automatically, including configured renames and plugin tables. This works for auth-only apps without an application schema. Review and commit the generated files before deploying.
745
+
746
+ For SQLite, Void checks that the migration history applies to a fresh database. If generation fails this check, the previous SQL, snapshots, and journal are restored. If an existing migration fails, repair that unapplied migration first: rerunning generation compares snapshots and does not repair existing SQL. This check does not verify that a migration preserves existing data; review table rebuilds and foreign-key actions carefully.
352
747
 
353
748
  ### `void db status`
354
749
 
355
- Show migration status. Displays which migrations are applied or pending locally. When logged in and linked to a project, also shows remote status.
750
+ Show migration status. Displays which migrations are applied or pending locally, then uses the saved deployment target for remote status: the hosted API for Void projects, the pinned D1 database and its configured migration table for direct Cloudflare SQLite projects, or the shell `DATABASE_URL` for direct Cloudflare PostgreSQL/MySQL projects. If the remote credential or service is unavailable, local status is still shown.
356
751
 
357
752
  ### `void db reset`
358
753
 
@@ -382,10 +777,12 @@ void db execute --remote <sql>
382
777
 
383
778
  Run ad-hoc SQL against the database. Provide SQL inline or from a file. SELECT queries display results as a formatted table; other statements execute silently.
384
779
 
385
- By default, targets the local database. Pass `--remote` to run against the deployed database:
780
+ By default, targets the local database. Pass `--remote` to run against the deployed database selected in `.void/project.json`:
386
781
 
387
- - **D1 projects**: routes the query through the Void proxy (`proxy.void.cloud/d1/query`) using your auth token. No Cloudflare credentials needed.
388
- - **PostgreSQL projects**: fetches the stored connection string from the platform and connects directly. Requires that `void db set-url` has been run at least once (the platform stores the URL encrypted). If the URL isn't stored yet, you will see: _"Run `void db set-url` once to populate it, then retry."_
782
+ - **Hosted D1 projects**: routes the query through the Void proxy (`proxy.void.cloud/d1/query`) using your auth token.
783
+ - **Direct Cloudflare D1 projects**: invokes Cloudflare against the pinned D1 binding from root `wrangler.jsonc`.
784
+ - **Hosted PostgreSQL and MySQL projects**: fetches the stored connection string from the platform and connects directly.
785
+ - **Direct Cloudflare PostgreSQL and MySQL projects**: uses `DATABASE_URL` from the current shell; Cloudflare cannot return the password from Hyperdrive.
389
786
 
390
787
  For destructive statements (`DELETE`, `UPDATE`, `DROP`, etc.) when running in a TTY, you will be prompted to confirm before the query is sent to the deployed database. Non-TTY environments (CI) skip the prompt.
391
788
 
@@ -397,7 +794,7 @@ void db migrate [--remote]
397
794
 
398
795
  Apply pending migrations to the local database without resetting. Unlike `void db reset`, this preserves existing data and only runs migrations that haven't been applied yet.
399
796
 
400
- Pass `--remote` to apply pending migrations to the remote database instead. Requires being logged in (`void auth login`) and having a linked project.
797
+ Pass `--remote` to apply pending migrations to the saved target. Hosted projects require a Void login and link. Direct Cloudflare D1 projects use the binding's configured migration directory, table, and pattern; direct PostgreSQL and MySQL projects use the shell `DATABASE_URL`.
401
798
 
402
799
  ### `void db studio`
403
800
 
@@ -409,16 +806,32 @@ Open [Drizzle Studio](https://orm.drizzle.team/docs/drizzle-kit-studio) for the
409
806
 
410
807
  By default, targets the local database. Pass `--remote` to open Studio against the deployed database:
411
808
 
412
- - **PostgreSQL projects**: fetches the stored connection string from the platform and opens Studio against it. Requires being logged in (`void auth login`) with a linked project. If the URL isn't stored yet, run `void db set-url` first.
809
+ - **PostgreSQL and MySQL projects**: fetch the stored connection string from the platform and open Studio against it. If the URL isn't stored yet, run `void db set-url` first.
413
810
  - **D1 projects**: remote Studio is not yet supported. Use `void db execute --remote` for ad-hoc queries against your deployed D1 database.
414
811
 
812
+ On direct Cloudflare PostgreSQL/MySQL targets, remote Studio uses `DATABASE_URL` from the current shell. Direct D1 Studio remains unsupported; use `void db execute --remote`.
813
+
415
814
  ### `void db rename-migrations`
416
815
 
417
816
  Rename existing migrations from the old numeric prefix format (`0001_name.sql`) to timestamp-based format (`20260410161500_name.sql`). Updates local tracking table and remote records if logged in with a linked project.
418
817
 
818
+ ### `void db connect`
819
+
820
+ Connect an existing PostgreSQL/MySQL database or provision one through an adapter:
821
+
822
+ ```sh
823
+ void db connect 'postgresql://user:password@host/database'
824
+ NEON_API_KEY=... void db connect --provider neon --name my-app
825
+ void db connect --provider @acme/void-db-provider --region region-id
826
+ ```
827
+
828
+ The command saves `DATABASE_URL` in `.env`. When authenticated with a linked Void project, it also updates the encrypted deployment URL; pass `--local-only` to skip that sync. `neon` is built in. Other adapters are project dependencies or local modules exporting a `DatabaseProviderAdapter` from `void/database-provider`.
829
+
830
+ Provider-created credentials are never printed. For direct Cloudflare deploys, configure the same URL as a protected `DATABASE_URL` in the shell or CI environment that runs deploy.
831
+
419
832
  ### `void db set-url`
420
833
 
421
- Update the PostgreSQL connection string for deployment. Only available for projects with `"database": "pg"` in `void.json`.
834
+ Update the PostgreSQL or MySQL connection string for deployment. Available for projects with `"database": "pg"` or `"database": "mysql"`.
422
835
 
423
836
  Prompts for a connection string and sends it to the platform API to create or update the Hyperdrive configuration.
424
837
 
@@ -430,6 +843,8 @@ void db export [--output <path>] [--no-data] [--no-schema] [--table <name>]
430
843
 
431
844
  Dump the local database as SQL. Outputs to stdout by default (pipeable), or to a file with `--output`.
432
845
 
846
+ Data exports preserve SQLite AUTOINCREMENT and PostgreSQL SERIAL counters, including IDs consumed by deleted rows. PostgreSQL schema exports create serial sequences before their tables and restore ownership, constraints, and indexes afterward. `--no-schema` restores counter values into an existing schema; `--no-data` starts counters at their schema-defined starting values.
847
+
433
848
  | Flag | Purpose |
434
849
  | ----------------- | ---------------------------------- |
435
850
  | `--output <path>` | Write to a file instead of stdout |
@@ -557,10 +972,12 @@ void gen queue emails
557
972
  void secret list [--project <name>]
558
973
  ```
559
974
 
560
- List the production secrets configured for the project. Secret values are never printed.
975
+ List production secret names for the saved target. Secret values are never printed. Direct Cloudflare targets query the Worker named in root `wrangler.jsonc`; `--project` is hosted-only.
561
976
 
562
977
  ### `void secret put`
563
978
 
979
+ On hosted projects, secret writes and deletes return a retryable conflict while a deployment or rollback is in progress. Wait for that operation to finish and retry; the rejected operation leaves the stored secret unchanged.
980
+
564
981
  ```
565
982
  void secret put <name> [--project <name>]
566
983
  void secret put <name=value> [--project <name>]
@@ -572,6 +989,8 @@ Value input modes:
572
989
  - prompt (TTY): `void secret put API_KEY` (masked input)
573
990
  - stdin: `echo -n "abcd" | void secret put API_KEY`
574
991
 
992
+ On a direct Cloudflare target, the value is sent to Cloudflare over stdin and stored as an encrypted Worker secret.
993
+
575
994
  ### `void secret sync`
576
995
 
577
996
  ```
@@ -581,17 +1000,19 @@ void secret sync <file> [--project <name>]
581
1000
  Bulk upload secrets from a dotenv file. Each `KEY=value` line in the file is uploaded as a secret.
582
1001
 
583
1002
  ```sh
584
- void secret sync .env.local # uploads secrets from .env.local
585
- void secret sync .env.production # uploads a specific file
1003
+ void secret sync .env # validates and uploads declared server values
586
1004
  ```
587
1005
 
1006
+ Direct Cloudflare targets use Cloudflare's bulk-secret API. Existing remote secrets absent from the file are not pruned.
1007
+ Every entry must be a non-client key declared in `env.ts`, and its plaintext value must pass the schema before upload.
1008
+
588
1009
  ### `void secret delete`
589
1010
 
590
1011
  ```
591
1012
  void secret delete <name> [--project <name>]
592
1013
  ```
593
1014
 
594
- Project resolution for secrets follows the same order as deploy (`--project`, env var, linked project).
1015
+ Secret commands use the platform saved in `.void/project.json`. Hosted project resolution follows the same order as deploy (`--project`, env var, linked project). Direct Cloudflare targets reject `--project` and use the pinned root Cloudflare config.
595
1016
 
596
1017
  ## Env Schema
597
1018
 
@@ -601,7 +1022,7 @@ Project resolution for secrets follows the same order as deploy (`--project`, en
601
1022
  void env check [--remote]
602
1023
  ```
603
1024
 
604
- Validate `env.ts` against `.env` + `.env.production` (and, with `--remote`, also against the remote secret list). Exits non-zero if any required key is missing or invalid. Use in CI before deploy.
1025
+ Without `--remote`, validate `.env` plus the shell for local development. With `--remote`, validate build-shell client values and the remote server-secret names. Exits non-zero if a required key is missing or a readable value is invalid.
605
1026
 
606
1027
  ### `void env types`
607
1028
 
@@ -611,40 +1032,6 @@ void env types
611
1032
 
612
1033
  Regenerate `.void/env.d.ts` from `env.ts`. Normally happens automatically on dev server start and HMR; use this command after a fresh clone or to refresh stale types in non-dev contexts.
613
1034
 
614
- ### `void env example`
615
-
616
- ```
617
- void env example [--force]
618
- ```
619
-
620
- Generate or refresh a marker-delimited "void env" block inside `.env.example` at the project root, sourced from the registered `env.ts` schema. The block is grouped into `required`, `with defaults`, and `optional` sections, with enum members emitted as inline comments. Prefilled values are used for keys with a `.default(...)`.
621
-
622
- The command never overwrites the whole file — anything above or below the markers (custom CI tokens, build flags, etc.) is preserved verbatim:
623
-
624
- | State of `.env.example` | Behavior |
625
- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
626
- | File doesn't exist | Writes a fresh file containing only the marker block. |
627
- | Exists, contains both markers | Replaces only the lines between (and including) the markers; everything else is preserved. |
628
- | Exists, no markers | Appends the block at the end (one blank line separator) and prints `appended void env block to existing .env.example`. |
629
- | Exists, only one of the two markers present | Hard error — fix the file (restore the missing marker or delete the file) and rerun. |
630
-
631
- Pass `--force` to suppress the "appended block" notice for scripted runs.
632
-
633
- Example output:
634
-
635
- ```ini
636
- # >>> void env: managed block — do not edit between markers <<<
637
- # Run `void env example` to refresh.
638
- # required
639
- STRIPE_KEY=
640
- # enum: development | production
641
- NODE_ENV=
642
-
643
- # with defaults
644
- PORT=3000
645
- # >>> end void env <<<
646
- ```
647
-
648
1035
  ::: tip Deploy validation
649
1036
  `void deploy` runs the same schema validation automatically (with remote secrets) and refuses to upload if any required key is missing — no need to call `env check` separately when deploying.
650
1037
  :::
@@ -691,7 +1078,7 @@ List all GitHub App installations linked to your account. Each entry includes th
691
1078
  void github join
692
1079
  ```
693
1080
 
694
- Join the GitHub App installations your organization already has. If a teammate installed the Void GitHub App on a shared GitHub organization, run `void github join` to gain access to those installations without re-installing. Void opens your browser to authorize (a localhost + PKCE handshake, the same mechanics as `void github link`), confirms with GitHub which installations you can manage, and records your membership. Afterwards `void github installations` lists them and `void github connect` can connect your own projects to their repositories.
1081
+ Join the GitHub App installations your organization already has. If a teammate installed the Void GitHub App on a shared GitHub organization, run `void github join` to discover those installations without re-installing. Void opens your browser to authorize (a localhost + PKCE handshake, the same mechanics as `void github link`), confirms which installations GitHub makes visible to you, and records that visibility. Afterwards `void github installations` lists them without exposing the installation-wide private repository list; `void github connect` separately proves access to the repository you name.
695
1082
 
696
1083
  In an interactive terminal you rarely need to run this yourself — `void github connect` runs the same join automatically when no active installations are linked to your account. Running `void github join` yourself matters mainly for non-interactive use (without a TTY, `void github connect` never opens a browser), or to link installations ahead of time.
697
1084
 
@@ -737,7 +1124,9 @@ void github connect my-app \
737
1124
 
738
1125
  **Connecting as an organization member**
739
1126
 
740
- If you are a member of a GitHub organization but not the person who installed the App, `void github connect` first confirms that you personally have access to the specific repository. Interactively (TTY), when it detects this it opens your browser once to authorize access to that repo on GitHub (a localhost + PKCE handshake), then completes the connection automatically — no extra flags. Without a TTY, this per-repo authorization never opens a browser: connect fails closed with an error explaining that the installation requires per-repo authorization, which needs an interactive browser sign-in, and telling you to run `void github connect` locally to authorize, then retry. Interactively, connect joins the shared installation automatically when your account has no active installations linked, so running `void github join` first is optional — useful mainly to see the installation in `void github installations` beforehand. You can only connect repositories you can access on GitHub; one you cannot see is refused with a clear message.
1127
+ For every organization installation, `void github connect` confirms that you personally have access to the specific repository, including when you originally installed the App. Interactively (TTY), it opens your browser once to authorize access to that repo on GitHub (a localhost + PKCE handshake), then completes the connection automatically. Without a TTY, this per-repo authorization never opens a browser: connect fails closed with an error explaining that the installation requires per-repo authorization and telling you to run `void github connect` locally. Interactively, connect joins the shared installation automatically when your account has no active installations linked, so running `void github join` first is optional. You can only connect repositories you can access on GitHub; seeing the organization installation never grants access to its other private repositories.
1128
+
1129
+ After upgrading from a platform version that treated an organization installer as an owner, existing organization connections show **Reconnect required** and stop starting builds until their repository access is proven. Run `void github connect <project> --repo <owner/repo>` again. The command reauthorizes the same connection in place after the browser proof; if the repository or installation changed, disconnect it first and connect the intended repository.
741
1130
 
742
1131
  ### `void github update`
743
1132
 
@@ -770,7 +1159,7 @@ void github update my-app --executor github_actions
770
1159
  void github status [project]
771
1160
  ```
772
1161
 
773
- Show a project's current GitHub connection: the connected **repository**, the deploy **branch**, the **build executor** (`container` or `github_actions`), and the authorized **deploy workflow file**. Read-only — it never changes anything. The workflow file is the OIDC pin used only for `github_actions` builds; on a `container` connection it is still shown but marked unused. The project must already be connected (run `void github connect` first, otherwise it reports that and exits).
1162
+ Show a project's current GitHub connection: the connected **repository**, the deploy **branch**, the **build executor** (`container` or `github_actions`), and the authorized **deploy workflow file**. Read-only — it never changes anything. The workflow file is the OIDC pin used only for `github_actions` builds; on a `container` connection it is still shown but marked unused. Legacy organization connections also show **Reconnect required** until `void github connect` proves current access to that repository. The project must already be connected (run `void github connect` first, otherwise it reports that and exits).
774
1163
 
775
1164
  **Options**
776
1165
 
@@ -849,7 +1238,7 @@ void build logs bld_123 -o build.log # download a specific build's logs
849
1238
  void domain add <hostname> [--project <name>]
850
1239
  ```
851
1240
 
852
- Add a custom domain to a project. Prints the two DNS records to add at your DNS provider: a traffic **CNAME** pointing `<hostname>` at the CNAME target shown in the command output, and a non-rotating `_cf-custom-hostname` ownership **TXT**. Certificates are validated over HTTP at Cloudflare's edge and renew automatically — there are no `_acme-challenge` records to publish, at first issuance or ever. After adding the records the domain activates automatically (no polling required); run `void domain status <hostname>` to check progress.
1241
+ Add a custom domain to the saved target. Hosted Void projects print the DNS records needed for SaaS hostname validation. Direct Cloudflare projects add a `custom_domain` route and immediately synchronize only the route configuration, leaving cron, queue, and workflow triggers unchanged; Cloudflare manages the DNS record and TLS certificate in a zone on the pinned account. Convert a legacy singular `route` field to a `routes` array first so adding the domain cannot shadow the existing route.
853
1242
 
854
1243
  > Wildcard custom hostnames (`*.example.com`) are not supported — register each subdomain individually.
855
1244
 
@@ -859,7 +1248,9 @@ Add a custom domain to a project. Prints the two DNS records to add at your DNS
859
1248
  void domain delete <hostname> [--project <name>]
860
1249
  ```
861
1250
 
862
- Remove a custom domain from a project.
1251
+ Direct Cloudflare projects apply the change immediately. Deleting the final custom domain requires `CLOUDFLARE_API_TOKEN` with Workers Scripts: Edit permission because the standard trigger operation does not reconcile an empty custom-domain set; Void fails before changing local or remote state when that token is unavailable.
1252
+
1253
+ Remove a custom domain from the saved target. For Cloudflare, this removes the matching `custom_domain` route and synchronizes triggers. If Cloudflare rejects the update, Void restores the exact previous local config and immediately reapplies it remotely. If that second synchronization also fails, the CLI reports that remote route state may be partial instead of claiming a successful rollback.
863
1254
 
864
1255
  ### `void domain list`
865
1256
 
@@ -867,7 +1258,7 @@ Remove a custom domain from a project.
867
1258
  void domain list [--project <name>]
868
1259
  ```
869
1260
 
870
- List all custom domains and their status (active/pending).
1261
+ List all custom domains. Hosted projects show active/pending state from the platform; direct Cloudflare projects list the custom-domain routes currently configured in root `wrangler.jsonc`.
871
1262
 
872
1263
  ### `void domain status`
873
1264
 
@@ -881,25 +1272,139 @@ Pass `--verbose` to additionally print the raw multi-line status breakdown (DB s
881
1272
 
882
1273
  Project resolution for domain commands follows the same order as deploy (`--project`, `VOID_PROJECT`, linked project).
883
1274
 
884
- ## Agent
1275
+ For direct Cloudflare projects, status reports whether the route is present in the root config. It does not claim to inspect remote certificate issuance; Cloudflare owns that state and exposes it in the dashboard. `--project` is hosted-only.
885
1276
 
886
- ### `void init --agents`
1277
+ ## Email
887
1278
 
888
- Runs all agent setup steps:
1279
+ Inspect email usage and manage the recipients a project is allowed to send to. See [Email](../guide/email.md) for the runtime API.
889
1280
 
890
- 1. **Instructions:** detects agents once and injects Void framework instructions with versioned markers.
891
- 2. **Skills:** links skills for the same detected or selected agent context.
892
- 3. **MCP config:** writes MCP server config for that same context, or prints generic MCP JSON in Generic mode.
1281
+ Project resolution for email commands follows the same order as deploy (`--project`, `VOID_PROJECT`, linked project). `void email setup` and `void email status --platform cloudflare` are the exception: they act on your own Cloudflare account through your Cloudflare sign-in (`void cloudflare login`) and need no Void project.
893
1282
 
894
- If no agent is detected, `void init --agents` asks you to choose from Claude Code, Cursor, Codex, Gemini CLI, or Generic.
1283
+ ### `void email usage`
895
1284
 
896
- ### `void mcp`
1285
+ ```
1286
+ void email usage [--project <name>]
1287
+ ```
1288
+
1289
+ Show the current month's outbound and inbound counts, the monthly outbound limit, and how much of it is left. A suspended project is flagged in the output.
1290
+
1291
+ ### `void email logs`
1292
+
1293
+ ```
1294
+ void email logs [--limit <n>] [--project <name>]
1295
+ ```
1296
+
1297
+ Show recent email activity — timestamp, direction, sender, recipient, status, and subject. `--limit` takes a positive integer. Email activity logs are not available yet on the platform; the command says so. Console output from your email handler appears in `void project logs`, like any other invocation of your worker.
1298
+
1299
+ ### `void email destinations`
1300
+
1301
+ ```
1302
+ void email destinations [--project <name>]
1303
+ ```
1304
+
1305
+ List the project's recipient addresses and their state (`verified`, `pending`, or `failed`). Outbound mail is only delivered to verified addresses.
1306
+
1307
+ ### `void email allow`
1308
+
1309
+ ```
1310
+ void email allow <address> [--project <name>]
1311
+ ```
1312
+
1313
+ Add one recipient to the project's destination list. Cloudflare emails that address a verification link — the recipient clicks it, with no Void or Cloudflare account required. Then run `void email destinations`: the listing is what records the click, and until it has, a send to that address returns `UNVERIFIED_DESTINATION` for that recipient. If the link did not arrive or has expired, run `void email allow <address>` again while the address is still pending — the CLI re-sends the link, or tells you how to get a fresh one.
1314
+
1315
+ The project owner's email is added automatically when the project is created, so it skips this step but not the verification: unless Cloudflare already had it verified for an earlier project of yours, click the link it mailed and run `void email destinations`; until then a send to yourself returns `UNVERIFIED_DESTINATION` for that recipient.
1316
+
1317
+ ### `void email disallow`
897
1318
 
898
1319
  ```
899
- void mcp
1320
+ void email disallow <address> [--project <name>]
900
1321
  ```
901
1322
 
902
- Start the Void MCP server over stdio for supported coding agents.
1323
+ Remove one recipient from the project's destination list. Sends to that address are refused within about a minute: the platform updates the project's allowlist as part of the command, and the proxy re-reads it every 60 seconds. No deploy is involved.
1324
+
1325
+ ### `void email domain`
1326
+
1327
+ ```
1328
+ void email domain <add|status|list|sync|remove> [<domain>] [--project <name>]
1329
+ ```
1330
+
1331
+ Send and receive at your own domain on a Cloudflare zone you own, registered to the project. Void platform only — on your own Cloudflare account the mail domain comes from `email.from` instead (see `void email setup`). The walkthrough is [Your own domain on the platform](../guide/email.md#your-own-domain-on-the-platform).
1332
+
1333
+ #### `void email domain add`
1334
+
1335
+ ```
1336
+ void email domain add <domain> [--subdomain <label|host>] [--project <name>]
1337
+ ```
1338
+
1339
+ Register the domain with the project. One credential is required, granted two ways: an OAuth grant from Cloudflare's hosted consent page (the page names Wrangler — Void borrows its OAuth client), or, as the fallback Enter switches to at any point, a scoped API token created from a three-click template link and picked up from the clipboard or a masked paste. The credential is POSTed once and stored on the platform, encrypted for the project — nothing is kept locally. Needs an interactive terminal. The CLI proposes `mail.<domain>` when the apex already carries MX records and allows the apex only when it carries none; `--subdomain` overrides the proposal. One live email domain per zone and one project per domain are enforced — a conflict is refused with a 409. Re-running `add` on a `failed`, `token_revoked`, or `token_expired` row replaces the credential and retries; the routing rules stay.
1340
+
1341
+ #### `void email domain status`
1342
+
1343
+ ```
1344
+ void email domain status <domain> [--project <name>]
1345
+ ```
1346
+
1347
+ Show one registered domain. The platform re-probes the stored credential and the relay worker on every call, so this doubles as the drift report. A `pending` row whose only remaining step is the dashboard's subdomain form (printed by `add`) self-clears to `active` once public MX on the domain names Cloudflare — which makes this command the poll for that one human step.
1348
+
1349
+ #### `void email domain list`
1350
+
1351
+ ```
1352
+ void email domain list [--project <name>]
1353
+ ```
1354
+
1355
+ List the project's registered email domains with their status and mode.
1356
+
1357
+ #### `void email domain sync`
1358
+
1359
+ ```
1360
+ void email domain sync <domain> [--project <name>]
1361
+ ```
1362
+
1363
+ Redeploy the domain's relay worker at the current version and rotate its secret — the fix when `status` reports the relay missing or drifted.
1364
+
1365
+ #### `void email domain remove`
1366
+
1367
+ ```
1368
+ void email domain remove <domain> [--project <name>]
1369
+ ```
1370
+
1371
+ Delete the registration: the platform row, the stored credential, and the relay secret. Cloudflare-side cleanup is best-effort; any step that fails is named (`failed_steps`) so you can finish it in the Cloudflare dashboard.
1372
+
1373
+ ### `void email status`
1374
+
1375
+ ```
1376
+ void email status --platform cloudflare
1377
+ ```
1378
+
1379
+ Read-only. Checks the email setup on your own Cloudflare account for the domain of `email.from` in `void.json` — session scopes, zone, MX records, Email Routing (and its subaddressing setting), Email Sending, the routing rule for every `email/` handler, and the `send_email` binding — then prints the status rows and the address map (`inbound <address> → email/<handler>`, `outbound sendEmail() from <email.from>`). Exits 1 when anything is not ready. A domain still not onboarded for Email Sending reads as set up once the `send_email` binding is committed — the binding is written only after an onboarding attempt, so that pair is how a Workers Free refusal is remembered — and the sending row says so (`not onboarded — verified destinations only; after upgrading to Workers Paid run void email setup --platform cloudflare`). Takes no `--project`: it reads the local project and your Cloudflare session, never a Void project.
1380
+
1381
+ Without `--platform cloudflare` (or with `--platform void`) the command is not available yet; on the Void platform use `void email usage` and `void email destinations`. The older `--backend cloudflare` spelling remains available as a compatibility alias on `void email status` and `void email setup`, with the same rules as `void deploy`: at most once, and never together with `--platform`.
1382
+
1383
+ ### `void email setup`
1384
+
1385
+ ```
1386
+ void email setup --platform cloudflare
1387
+ ```
1388
+
1389
+ The same setup `void deploy --platform cloudflare` offers on its first deploy, on its own — for CI, which cannot press Enter: run it locally once, commit `wrangler.jsonc`, then let CI run `void deploy --platform cloudflare --require-email`. Needs `email.from` in `void.json` and a `void cloudflare login` session (a session created by older Cloudflare tooling lacks the email scopes: `void cloudflare logout`, then sign in again) or a `CLOUDFLARE_API_TOKEN` with Email Routing Edit + Email Sending Edit — the CI credential. It runs the preflight above, prints the checklist of what will change on your account, asks once, then:
1390
+
1391
+ 1. enables Email Routing on the domain (on an apex through Void's bundled Cloudflare tooling; a subdomain through your session's bearer, borrowed for that one call and dropped),
1392
+ 2. turns on subaddressing for the zone, so `support+anything@` reaches `support@`,
1393
+ 3. onboards the domain for Email Sending (a Workers Free account keeps inbound and sends to verified destinations only),
1394
+ 4. writes `send_email: [{ "name": "SEND_EMAIL" }]`, the derived `addresses` array, and `vars.__VOID_EMAIL_FROM` into your root `wrangler.jsonc`, comments preserved.
1395
+
1396
+ The routing rules themselves are created by the next `void deploy --platform cloudflare`: wrangler applies its Email Routing plan from `addresses` on deploy. `void email setup` never writes `addresses` unless routing is ready for the domain, prunes an address already routed to another worker or a forward (and says so), and skips the whole step when the existing `addresses` array holds entries it did not derive. A run that finds every row ready asks nothing and changes nothing on your account — with one exception: a domain still not onboarded for Email Sending while the `send_email` binding is committed (a remembered Workers Free refusal, see `void email status`) is offered as a retry on its own prompt, `Onboard <domain> for Email Sending? Inbound already works; onboarding needs Workers Paid.` — the step to run once after upgrading; answer No and nothing changes. The deploy never retries it. Needs an interactive terminal; exits 1 when the inbound rows are still not ready afterwards — routing not enabled, subaddressing still off, or `addresses` withheld — naming the row and saying to rerun. A Workers Free account's refused sending row is not a failure: inbound is complete, `addresses` is written, the plan hint is printed, and the binding written alongside is what makes the next deploy and `void email status` read the domain as set up. See [Your own Cloudflare account](../guide/email.md#your-own-cloudflare-account).
1397
+
1398
+ ## Agent
1399
+
1400
+ ### `void init --agents`
1401
+
1402
+ Runs all agent setup steps:
1403
+
1404
+ 1. **Instructions:** always creates or updates `AGENTS.md` with four brief bullets and versioned markers. Content outside the Void block and other instruction files are preserved.
1405
+ 2. **Skills:** links skills for detected coding agents.
1406
+
1407
+ There is no agent-selection prompt. If no agent is detected, skill linking is skipped; the instructions point directly to `node_modules/void/skills/void/docs/`.
903
1408
 
904
1409
  ## Environment variables
905
1410