everyapp 0.2.2 → 0.3.0-rc.2

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 (128) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -77
  3. package/bin/everyapp.js +235 -0
  4. package/dist/access-LGEN3ABJ.js +1 -0
  5. package/dist/activity-RSD4D66F.js +12 -0
  6. package/dist/apps-4RCFXT74.js +13 -0
  7. package/dist/chunk-23HJ5I2A.js +2 -0
  8. package/dist/chunk-2Y5Q6A5K.js +6 -0
  9. package/dist/chunk-4JRIS6S6.js +1 -0
  10. package/dist/chunk-5PTNYZK6.js +4 -0
  11. package/dist/chunk-6OGVO7QK.js +6 -0
  12. package/dist/chunk-6PGUCTJ6.js +11 -0
  13. package/dist/chunk-AGTCKFRB.js +22 -0
  14. package/dist/chunk-BHMRY53V.js +2 -0
  15. package/dist/chunk-CB4U7H2G.js +4 -0
  16. package/dist/chunk-CCWBPAKH.js +4 -0
  17. package/dist/chunk-CZTEDWZ2.js +22 -0
  18. package/dist/chunk-CZXHKPRZ.js +2 -0
  19. package/dist/chunk-E3EPK27P.js +10 -0
  20. package/dist/chunk-EGEWRFVY.js +1 -0
  21. package/dist/chunk-ELK7QZ2M.js +1 -0
  22. package/dist/chunk-FJJSSVET.js +33 -0
  23. package/dist/chunk-GKBPYVP3.js +25 -0
  24. package/dist/chunk-H6QQMY7B.js +18 -0
  25. package/dist/chunk-H7PDL3X5.js +1 -0
  26. package/dist/chunk-HOUHG236.js +20 -0
  27. package/dist/chunk-IFCPALVC.js +46 -0
  28. package/dist/chunk-IUOBIB5M.js +30 -0
  29. package/dist/chunk-J35DDCNU.js +1 -0
  30. package/dist/chunk-J455FAEN.js +7 -0
  31. package/dist/chunk-JYKRUS5C.js +1 -0
  32. package/dist/chunk-LXYMDZER.js +1 -0
  33. package/dist/chunk-LYNBZ7RV.js +57 -0
  34. package/dist/chunk-M2QQ2UD7.js +132 -0
  35. package/dist/chunk-N4E5YE4X.js +5 -0
  36. package/dist/chunk-N5GQLGEC.js +2 -0
  37. package/dist/chunk-NFU4YFXB.js +1 -0
  38. package/dist/chunk-OM2HDWVP.js +1 -0
  39. package/dist/chunk-ONLNJXVQ.js +32 -0
  40. package/dist/chunk-OP4DYXYI.js +2 -0
  41. package/dist/chunk-PNLU5U3P.js +1 -0
  42. package/dist/chunk-PS7S74DG.js +6 -0
  43. package/dist/chunk-RMF4YGD6.js +98 -0
  44. package/dist/chunk-T2GD7RHS.js +10 -0
  45. package/dist/chunk-TLRM3P7V.js +15 -0
  46. package/dist/chunk-W3JCQHHU.js +1 -0
  47. package/dist/chunk-WOVS3GV5.js +10 -0
  48. package/dist/chunk-YHJZMJYZ.js +1 -0
  49. package/dist/chunk-ZECBN24L.js +15 -0
  50. package/dist/chunk-ZEXVHB22.js +2 -0
  51. package/dist/chunk-ZFCUH5PK.js +7 -0
  52. package/dist/configure-F7UZCJUG.js +8 -0
  53. package/dist/create-2E5HVWYK.js +22 -0
  54. package/dist/db-HEQVTDTM.js +9 -0
  55. package/dist/delete-XCSIQIRS.js +3 -0
  56. package/dist/deploy-3QOZEZHC.js +1 -0
  57. package/dist/dev-JL3ZP5BT.js +86 -0
  58. package/dist/email-RLZFUFUN.js +10 -0
  59. package/dist/events-2V5VRBWP.js +15 -0
  60. package/dist/groups-HDG5DVFY.js +8 -0
  61. package/dist/index.js +97 -1
  62. package/dist/install-Z5FYXUYM.js +1 -0
  63. package/dist/login-KHJBC64Z.js +1 -0
  64. package/dist/mcp-EFDUKJ5V.js +1 -0
  65. package/dist/provider-EOI5PTFH.js +13 -0
  66. package/dist/release-74J5ZIL3.js +1 -0
  67. package/dist/restore-FFGYV7NO.js +3 -0
  68. package/dist/secret-7FKKTLHB.js +1 -0
  69. package/dist/setup-PAKRCAFO.js +1 -0
  70. package/dist/signin-AP3D4XM4.js +12 -0
  71. package/dist/status-RMWNHOEK.js +4 -0
  72. package/dist/teardown-E4JNKAZJ.js +22 -0
  73. package/dist/update-DWVZFNPS.js +1 -0
  74. package/dist/workspace-CJC5I66L.js +21 -0
  75. package/package.json +19 -16
  76. package/skills/build-every-app/SKILL.md +199 -0
  77. package/skills/build-every-app/patterns.md +140 -0
  78. package/skills/everyapp/SKILL.md +292 -0
  79. package/skills/everyapp/mcp.md +350 -0
  80. package/skills/everyapp/security-review.md +61 -0
  81. package/skills/everyapp/setup/README.md +274 -0
  82. package/skills/everyapp/setup/access.md +178 -0
  83. package/skills/everyapp/setup/context.md +117 -0
  84. package/skills/everyapp/setup/dataforseo.md +287 -0
  85. package/skills/everyapp/setup/email.md +366 -0
  86. package/skills/everyapp/setup/gateway.md +243 -0
  87. package/skills/everyapp/setup/google.md +360 -0
  88. package/skills/everyapp/setup/microsoft-365.md +281 -0
  89. package/skills/everyapp/setup/openai.md +318 -0
  90. package/skills/everyapp/setup/openrouter.md +309 -0
  91. package/skills/everyapp/setup/providers.md +1253 -0
  92. package/skills/everyapp/setup/remote-mcp.md +199 -0
  93. package/skills/everyapp/setup/signin-apple.md +178 -0
  94. package/skills/everyapp/setup/signin-cloudflare.md +148 -0
  95. package/skills/everyapp/setup/signin-github.md +139 -0
  96. package/skills/everyapp/setup/signin-google.md +178 -0
  97. package/skills/everyapp/setup/signin-microsoft.md +183 -0
  98. package/skills/everyapp/setup/signin-oidc.md +163 -0
  99. package/skills/everyapp/setup/slack.md +344 -0
  100. package/skills/everyapp/setup/workers-ai.md +138 -0
  101. package/bin/__everyapp_bash_complete.js +0 -12
  102. package/dist/bash-complete.js +0 -3
  103. package/dist/chunk-7BOQJFI5.js +0 -8
  104. package/dist/chunk-7YVJFS4A.js +0 -1
  105. package/dist/chunk-BIXKPCDH.js +0 -2
  106. package/dist/chunk-DLGPLHBH.js +0 -47
  107. package/dist/chunk-FD6K2YA7.js +0 -9
  108. package/dist/chunk-GAJEQYJH.js +0 -39
  109. package/dist/chunk-O2KDOP5R.js +0 -13
  110. package/dist/chunk-OI2MBGBG.js +0 -4
  111. package/dist/chunk-POSDLD3G.js +0 -8
  112. package/dist/chunk-RB5D2R45.js +0 -1
  113. package/dist/chunk-U4LIQ5VR.js +0 -1
  114. package/dist/chunk-VEYSNPDH.js +0 -3
  115. package/dist/chunk-VP6SKW44.js +0 -7
  116. package/dist/chunk-WO3NE7ZU.js +0 -7
  117. package/dist/chunk-XTO2VTPY.js +0 -6
  118. package/dist/chunk-YJ2DKIZS.js +0 -1
  119. package/dist/create-DYQ3NBWJ.js +0 -22
  120. package/dist/deploy-PYTCMDGV.js +0 -7
  121. package/dist/deploy-RMAHOA4Z.js +0 -55
  122. package/dist/dev-SAE237FS.js +0 -0
  123. package/dist/generateConfig-46Z3ERF3.js +0 -1
  124. package/dist/login-B6EF3SMX.js +0 -1
  125. package/dist/logout-XMKZBLNV.js +0 -1
  126. package/dist/remoteD1Shell-A67JMO3H.js +0 -6
  127. package/dist/setupLocal-TZJUW5ES.js +0 -6
  128. package/gateway/every-app-gateway-build.tar.gz +0 -0
@@ -0,0 +1,243 @@
1
+ # Cloudflare account, the Gateway and its owner for the Gateway
2
+
3
+ Everything else in this folder needs this first: a Cloudflare account on
4
+ Workers Paid with a domain, the Gateway Worker installed at `<gateway host>`
5
+ (`apps.<your domain>` unless the person chooses another name), the `cf` CLI
6
+ logged in, and an owner account. Every app uses it: OpenSEO, Open CRM,
7
+ agentic-inbox, OpenAnalytics, and anything `pnpm everyapp create` makes. At
8
+ the end the person has `https://<gateway host>` to sign in to,
9
+ `https://<gateway host>/admin` to invite people, and apps at
10
+ `<app>.<app base domain>`.
11
+
12
+ ## Settings
13
+
14
+ The first four rows setup writes itself and `secret set` refuses
15
+ (`SECRET_NOT_SETTABLE`; it also refuses `APP_BASE_DOMAIN` and
16
+ `THIRD_PARTY_DEPLOYS`, which setup doesn't write). The last two are optional
17
+ and set with `secret set` (Step 9).
18
+
19
+ | NAME | required or optional | what it holds |
20
+ | --- | --- | --- |
21
+ | `GATEWAY_URL` | set by setup | `https://<gateway host>` |
22
+ | `CLOUDFLARE_ACCOUNT_ID` | set by setup | the account's id (32 hex characters); Workers AI and email reuse it |
23
+ | `GATEWAY_DEPLOYMENT_MODE` | set by setup | `self_hosted` or `hosted`; set at the first upload, never changes |
24
+ | `BETTER_AUTH_SECRET`, `JWT_PRIVATE_KEY`, `JWT_PUBLIC_KEY` | set by setup | the Gateway's session and identity keys (rotation: docs/runbooks/key-rotation.md) |
25
+ | `CF_DEPLOY_TOKEN` | optional | a Cloudflare API token (Workers Scripts Edit, D1 Edit, Zone DNS Read) for installing apps from the browser |
26
+ | `BROWSER_APP_INSTALLS` | optional | exactly `off` turns browser installs off; unset or `on` keeps them on |
27
+
28
+ ## Costs and plans
29
+
30
+ As of October 2026. A Cloudflare account is free. Workers Paid is a $5 a
31
+ month minimum per account, then usage; it includes 10 million requests, 30
32
+ million CPU ms a month and D1's 25 billion rows read and 50 million written
33
+ a month plus 5 GB of storage, far more than a small team's Gateway uses.
34
+ The Free plan is refused: D1 Free stops answering at 5 million rows read or
35
+ 100,000 written a day (reset 00:00 UTC), and the Gateway reads D1 on every
36
+ request. A domain: Cloudflare Registrar sells at cost, with no promotions
37
+ of its own; price trackers list a `.dev` or `.app` at about $8 the first
38
+ year (a registry discount), then $12.20 or $14.20 a year, and a `.com` at
39
+ about $10.46 (setup's own message says about $10); the dashboard shows the
40
+ exact price before **Complete purchase**. Moving a domain you own is free,
41
+ on the Free zone plan. Node, pnpm, git and `cf` are free. No rate limits
42
+ matter; the device login gives 5 minutes (cf's own limit), the owner link
43
+ lasts 24 hours.
44
+
45
+ ## Only a person can
46
+
47
+ - Sign up for Cloudflare and verify the email.
48
+ - Add a card and subscribe to Workers Paid.
49
+ - Buy a domain, or change nameservers at the registrar they bought it from.
50
+ - Approve the device login in a browser, and pick a workers.dev subdomain when Cloudflare asks for one.
51
+ - Open the owner link and create the account (name, email, password).
52
+ - Answer setup's browser-installs question, at a terminal, and paste the token.
53
+ - Choose the Cloudflare account when the login sees several (you show the choices).
54
+ - Enable R2 in the dashboard once, before OpenSEO, OpenCRM or Agentic Inbox installs on an account that never had it (Step 11).
55
+
56
+ ## Before you start
57
+
58
+ 1. Tools: `node --version` prints 22.18.0 or newer (22 and 24 are LTS; 26, the Current release, works too), `pnpm --version` and `git --version` answer. The checkout: `git clone https://github.com/every-app/every-app.git && cd every-app && pnpm install` (it installs the CLI's pinned `cf` too; README's "Where you are" says how to run it). Every command below runs from that folder; `everyapp` outside it stops with `CHECKOUT_MISSING`.
59
+ 2. `pnpm everyapp status --json`. `done` with `data.installed: true` and `data.claimed: true`: the Gateway exists and has an owner, go to Verify (a `GATEWAY_OUTDATED` fix there is `severity: "info"`, not a reason to stop). `action_required install_gateway` (exit 2; `data.rerun` is `pnpm everyapp setup`): no Gateway in any account this login sees, do the Steps. `action_required cloudflare_login` with `waiting: true`: hand over `data.url` and `data.code` (Step 6) and keep reading. `done` with `data.installed: false` and a `GATEWAY_NOT_INSTALLED` fix, or fixes `GATEWAY_NOT_UPLOADED` or `NO_OWNER`: an earlier setup stopped, run Step 7 again. Error `GATEWAY_NOT_FOUND`: the account named by `--account-id` or `CLOUDFLARE_ACCOUNT_ID` has no Gateway; its message says where one is.
60
+ 3. Once `status` says `data.installed: true`: `pnpm everyapp secret list --json`; `data.gateway.names` has `GATEWAY_URL`, and `CF_DEPLOY_TOKEN` in it means browser installs are configured already. On a fresh account skip it: `secret list`, `email show` and `status` all need the Cloudflare login (under `--json` each starts the same `cloudflare_login` itself) and an installed Gateway; with none, `status` stops on `install_gateway` while the other two end `GATEWAY_NOT_FOUND` (exit 1), and an install that stopped before its first upload ends them `GATEWAY_NOT_INSTALLED` (exit 1, `data.rerun` is setup).
61
+ 4. Which account. Setup checks the rest itself: it logs in (`setup.auth`; `status` starts the same `cloudflare_login`), reads the plan (`setup.plan`) and the domain (`setup.domain`) and stops on `cloudflare_login`, `choose_account`, `upgrade_workers_paid`, `add_domain` or `ZONE_NOT_FOUND` (Step 7), so on a first install nothing here gates it. `cf auth whoami` (read-only) prints the login's email and its accounts: several, ask the person which and carry `--account-id <account id>` on every command. When setup stops: `cf zones list` shows the domains and whether each is `active`; `cf accounts subscriptions get` is what setup reads for the plan.
62
+
63
+ ## Steps
64
+
65
+ 1. **Person:** Create the Cloudflare account, or use the one they have. Open https://dash.cloudflare.com/sign-up, enter **Email** and **Password**, select **Create Account**. Open Cloudflare's verification email (check Spam) and follow its link, then log in. Check: **My Profile** → **Email Address** shows "(verified)"; if **Send verification email** is offered there, it isn't yet. A verified email is required to buy a domain, and Cloudflare refuses to create anything (API code 10034) until it is: setup would end `CF_EMAIL_UNVERIFIED` (Step 7). Wait for "verified".
66
+ 2. **Person:** Subscribe to Workers Paid. Open https://dash.cloudflare.com/?to=/:account/workers/plans (or `https://dash.cloudflare.com/<account id>/workers/plans`), choose the **Paid** plan ($5 a month), enter a card (Visa, Mastercard, American Express, Discover, UnionPay, PayPal or a wallet) and complete the purchase. A card can also be added first under **Billing** → **Subscriptions** → **Payment methods** → **Add Payment Method** → **Confirm**. Done when **Billing** → **Subscriptions** lists Workers Paid. You can check: `cf accounts subscriptions get` names a Workers plan containing "paid" or "standard".
67
+ 3. **Person:** Get a domain on Cloudflare, in the same account. Buy: open https://dash.cloudflare.com/?to=/:account/registrar/register, search a name, select **Purchase**, pick the term under **Payment option**, enter contact details (ASCII only) and payment, select **Complete purchase** (up to 30 seconds; a confirmation email follows). Registrar charges only the primary payment method (card, PayPal or Apple Pay): with several on the account, make the right one primary first under **Billing** → **Payment methods** (**Make primary payment method**). Move one they own: open https://dash.cloudflare.com/?to=/:account/domains/overview, select **Onboard a domain**, enter the apex without `www`, **Continue**, choose the **Free** plan, check the copied DNS records (mail records above all) and **Continue**, then replace the nameservers at the current registrar with the two Cloudflare shows (turn DNSSEC off there first). Done when Cloudflare's email says the domain is active (usually under an hour, up to a day). Wait for `cf zones list` to show it `active`.
68
+ 4. **You:** Install the tools and the checkout if Before you start found them missing (Node 22.18.0 or newer from https://nodejs.org, 22 or 24 LTS or 26; `npm install -g pnpm`; git from https://git-scm.com on Windows), then the clone and `pnpm install` above.
69
+ 5. **You:** `pnpm everyapp login --json`, when nothing has logged in yet (`status` and setup start the same device login themselves; on its own this is for seeing the accounts with `cf auth whoami` before choosing `--account-id`, or after `cf auth logout`). Already logged in: a `step cloudflare.login skip` with `data.email`, then `done`. Otherwise an `action_required cloudflare_login` with `data.url`, `data.code`, `data.expiresAt` and `waiting: true`: give the person the link and the code at once (Step 6; cf gives up after 5 minutes). The run ends with `step cloudflare.login ok` ("Logged in to Cloudflare.", `data.email`) and `done`, exit 0. Underneath it is `cf auth login --no-browser`. Unattended runs (CI) export `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` instead (the token takes priority over any stored login): a custom token made at https://dash.cloudflare.com/profile/api-tokens with Account › Workers Scripts › Edit, Account › D1 › Edit, Account › Workers KV Storage › Edit, Zone › Zone › Read (listing the domains needs it) and Zone › DNS › Read, limited to this account and the domain's zone. A token that lists no accounts needs `--account-id` (`ACCOUNT_REQUIRED`). The owner link is withheld only when the `CI` variable is set, or output is piped without `--json` (then `OWNER_NOT_CLAIMED`); a token login with `--json` on the person's machine still gets `claim_owner`.
70
+ 6. **Person:** Approve the login, within 5 minutes. Open `data.url` (Cloudflare's device page; the code is not in the link), sign in to Cloudflare if asked, type `data.code` where the page asks for it, and approve the request (Cloudflare's docs: "Approve the request to give cf access to your Cloudflare account"). The terminal moves on: wait for the `step … ok` "Logged in to Cloudflare" event. Over SSH or in a container the same link works from any browser. Datacenter IPs get a 403 managed challenge from the OAuth endpoints (cloudflare/cf issue 23, open): use the API token instead.
71
+ 7. **You:** `pnpm everyapp setup --domain apps.<your domain> --json` (add `--account-id <account id>` when the login sees several accounts). Its events, in order:
72
+
73
+ | event | what it carries |
74
+ | --- | --- |
75
+ | `setup.toolchain` | `data.node`, `data.cf` |
76
+ | `setup.auth` | `data.email`; before it, `cloudflare_login` when nothing is logged in |
77
+ | `setup.account` | `data.id`, `data.name`; `data.gateway` true when one exists |
78
+ | `setup.plan` | new install only: `ok` on Paid; `warning WORKERS_PAID_UNVERIFIED` when it can't tell (the run goes on); `skip` when cf couldn't read it |
79
+ | `setup.domain` | `data.gatewayHost`, `data.appBaseDomain`, `data.zone` |
80
+ | `setup.gateway` | `start` (`data.change`: `install`, `resume` after an earlier stop, `upgrade`, `repair` or `redeploy`; on a fresh install `data.expectedMinutes` `{ min: 5, max: 10 }`, the human line adding "usually 5–10 minutes, then the owner link": a whole first run takes 5 to 20 minutes, most of it waiting at that link, so run setup with a long timeout or in the background and keep reading its events); a minute or two of silence while the checkout builds (nothing is printed under `--json`: don't kill the run), then `step gateway.release ok` ("Built the Gateway … from this checkout." or "Using the Gateway … built from this checkout before"), `gateway.resources` (the D1 database and KV namespace, created or found), DNS, the Worker, its certificate, `ok` |
81
+ | `setup.owner` | `skip` "Owner account is <email>" when one exists; else `claim_owner` (Step 8), then `ok` |
82
+ | `done` | `data.gatewayUrl`, `data.adminUrl`, `data.owner`, `data.gateway` (`installed`, `upgraded`, `repaired` or `up-to-date`), `data.next`: `[{ command, note }]`. On a fresh self-hosted install, or when the owner was just created, four lines in this order: `pnpm everyapp create my-app`, `pnpm everyapp access on` (recommended), `pnpm everyapp secret set OPENAI_API_KEY` (or `OPENROUTER_API_KEY`, `WORKERS_AI_API_TOKEN`), `pnpm everyapp secret set EMAIL_FROM EMAIL_FROM_NAME`. Show them from the event, then take the person to access.md; hosted: no Access line; up to date: only `status` |
83
+
84
+ What it can stop on (exit 2, rerun `data.rerun` once done):
85
+ - `cloudflare_login` (`waiting: true`): Step 6.
86
+ - `choose_account`: several accounts and no Gateway, or Gateways in several accounts. `data.choices[]` has `accountId`, `accountName`, `label` and a ready `rerun` each (`--account-id <account id>`, or `--domain <gateway host>` when the host picks it); `gatewayUrl` only when the choice is between existing Gateways. Ask the person which, run that `rerun`.
87
+ - `upgrade_workers_paid` ("Subscribe this account to Workers Paid"; `data.url` the plans page, `data.plan`): the account is on Free, nothing was created. Step 2, then rerun. Cloudflare refusing the upload on the Free plan ends the same way.
88
+ - `add_domain` (`data.url`): "Finish activating": a domain whose nameservers don't point at Cloudflare yet (url: that domain's page, `data.zone`, `data.status`); "Add a domain": only when setup ran without `--domain` and the account has none (url: the domains overview). With `--domain`, no domain is the error `ZONE_NOT_FOUND` below. Step 3, then rerun.
89
+ - `register_workers_subdomain` (`data.url`, `…/workers/onboarding`): Cloudflare wants a workers.dev subdomain before the account's first Worker. The person opens the link and picks any name; apps never use it. If that page shows no name field, open **Workers & Pages** and select **Change** next to **Your subdomain** (or https://dash.cloudflare.com/?to=/:account/workers/subdomain). At a terminal cf offers to register one itself. It stops the Worker upload, after the D1 database, the KV namespace and the install row exist: a rerun (`--domain` may be left off) resumes (`setup.gateway start` with `data.change: "resume"`) and creates nothing twice.
90
+ - `rerun_interactive` (`data.needsTerminal: true`): the Gateway Worker serves a version everyapp didn't deploy (the dashboard, the API, an interrupted deploy), and nothing replaces it unattended. `data.rerun` is this command without `--json`, `data.rerunNote` "in a terminal" (or "…and confirm cf's prompt"): hand it to the person for their own terminal; never run it yourself, with or without `--json`.
91
+ - `claim_owner` (`waiting: true`): Step 8.
92
+ Errors (exit 1): `DOMAIN_REQUIRED` (unattended without `--domain`; `data.zones` lists the active domains. One zone: `data.rerun` is this command with `--domain apps.<zone>`, `data.rerunNote` "or another name under <zone>". Several: `data.choices[]`, `{ label, rerun }` per zone and no `data.rerun`: ask the person which, run its `rerun`), `CF_EMAIL_UNVERIFIED` ("Verify your Cloudflare account's email address first": Cloudflare API code 10034; `data.url` https://dash.cloudflare.com/profile, `data.rerun` this command: Step 1, then rerun), `ZONE_NOT_FOUND` (no domain in this account, or `--domain` isn't under one; `data.url` the domains overview, `data.zones` the active domains, empty when there are none: Step 3, then rerun), `DNS_RECORD_CONFLICT` (something already answers the name; `data.fix`: delete the record under the domain's **DNS** page, or another name; its `data.rerun` adds `--force-dns` with `data.authorize: true`: ask first, never add the flag on your own), `DNS_UNREADABLE` (an API token without Zone › DNS › Read can't tell whether a record is in the way; `data.fix` says to give it that; the same `--force-dns` rule), `DOMAIN_CHANGE_UNSUPPORTED` (installed elsewhere; rerun without `--domain`), `ACCOUNT_NOT_ACCESSIBLE` (lists the accounts the login can use), `ACCOUNT_REQUIRED` (an API token that lists no accounts: pass `--account-id`), `UNSUPPORTED_RUNTIME` (Node too old, or Bun).
93
+ 8. **Person:** Create the owner account. `action_required claim_owner` carries `data.url` (`https://<gateway host>/setup#token=est_…`), `data.expiresAt` (24 hours), `data.replaced` and `waiting: true` (`data.waitingFor`: "the owner account (up to 15 minutes)"); setup polls for 15 minutes. Show the link to the person and to nobody else: whoever opens it first owns the Gateway, so it never goes into a log, an issue, a commit or a file. At a terminal setup opens it itself. The page is titled **Set up your gateway** ("Create the owner account for this gateway."): **Name**, **Email**, **Password** (at least 8 characters), **Confirm password**, then **Create owner account**; the button reads "Setting up..." and they land in the Gateway, signed in. Before it, a `warning GATEWAY_UNREACHABLE` means the certificate is still on its way (the link works as soon as the host answers); `ACCESS_IN_FRONT` means they sign in to Cloudflare Access first. Wait for `step setup.owner ok` ("Owner account created for <email>") and `done`. Nobody opened it in 15 minutes: exit 2 `claim_owner` with `data.setupUrl`; the same link still works until `data.expiresAt`, and a rerun before anyone opens it mints a new one and kills it (`data.replaced: true`). Once they say the account exists after that exit 2: run `data.rerun` as given (under `--json` it is exactly `pnpm everyapp setup --json`; every rerun keeps the flags the run had, except a `needsTerminal: true` one, which the person runs); it finds the owner (`step setup.owner skip`, "Owner account is <email>"; no new link once there is one) and ends `done` with `data.gateway: "up-to-date"` and `data.adminUrl`. Or `pnpm everyapp status --json`: `data.claimed: true` and `data.owner.email` say the same. "Use the newer setup link": setup ran again elsewhere, or it expired; rerun for a new link.
94
+ 9. **Person (optional):** Browser installs. Only an interactive run without `--yes` asks, after the owner (`--yes`, `-y`, answers No): **Configure browser app installs?** (Yes/No, default No), then a hidden **Cloudflare API token** prompt. The token: https://dash.cloudflare.com/profile/api-tokens → **Create Token** → **Custom token** → **Get started**; permissions Account › Workers Scripts › Edit, Account › D1 › Edit, Zone › DNS › Read, limited to this account and the Gateway's zone; continue to summary, create, paste (nothing is echoed). It is stored as `CF_DEPLOY_TOKEN`. Under `--json` the question is skipped; to do it later, README's first way: the person runs `pnpm everyapp secret set CF_DEPLOY_TOKEN` in a second terminal in the `every-app` folder (hidden prompt), or the third: `pnpm everyapp secret set CF_DEPLOY_TOKEN --from-env CF_DEPLOY_TOKEN --json` with the variable exported in their shell. Skipped when the token is set already, and on a hosted Gateway.
95
+ 10. **You:** `pnpm everyapp status --json`, read as in Verify.
96
+ 11. **You, then the person:** The four Every App apps, offered once, as the setup prompt does (landing-page/content/docs/setup-prompt.txt, step 4): "I'll install OpenSEO, OpenCRM, OpenAnalytics and Agentic Inbox. Any you don't want?" For each one they keep, from the `every-app` folder: `pnpm everyapp install https://github.com/every-app/<repo> --json` with `open-seo`, `open-crm`, `open-analytics` or `agentic-inbox` as `<repo>`. It downloads the repository's latest release (`everyapp-release.tar.gz`, anonymously) and deploys it as `deploy` would from the app's directory, with nothing to clone or build (`step app.deploy` "Deploying <app> <version> from github.com/every-app/<repo> (release <tag>) to …", then the deploy's own steps; `done` with `data.url`, `data.live` and `data.next`; the same command later updates the app). The release path is the only one here: never clone a repository and deploy it, never build one from its URL. What an install can end on:
97
+ - `NO_RELEASE` (exit 1): the repository publishes no release yet. Say which app, and go on to the next one; its `data.fix` (clone, `pnpm install`, this checkout's deploy from the clone) is for when the person asks for that, not a step of yours.
98
+ - `R2_NOT_ENABLED` (exit 1): OpenSEO, OpenCRM and Agentic Inbox each bind an R2 bucket named after their Worker, the install makes it, and an account that never enabled R2 can't have one made by the API (OpenAnalytics binds none and never stops here). Once for the account, the person enables R2 in the dashboard: https://dash.cloudflare.com/?to=/:account/r2/overview, **R2 Object Storage** → **Get started** (free until something is stored; no bucket to make by hand; `data.fix` says the same). Wait for them, then run `data.rerun` (this same command); the other two won't stop on it again.
99
+ - `warning APP_NEEDS_SETUP` at `step app.secrets` ("<app> won't open until <names> is set", `data.setup`), after the upload: the app is live and shows **Needs setup** on the Gateway until its keys are set, and `done.data.next` carries `pnpm everyapp configure <app id>`, the one command that opens it. Tell the person which keys it wants, by name (the warning's names; `pnpm everyapp status --json` `data.apps[].setup.unmet[].names`, the id as `status` lists it: `openseo`, `crm`, `analytics` or `agentic-inbox`; or `pnpm everyapp secret list <app id> --json` `data.app.setup.unmet`), and stop there: the keys are never asked for here. When they want that app, each unmet setting's `setup` names its file in this folder ([dataforseo.md](dataforseo.md), [openrouter.md](openrouter.md), [context.md](context.md), [google.md](google.md), …), which takes over from this one; `pnpm everyapp configure <app id>` at their terminal sets every key the app needs in one go (README's first way).
100
+ An app that stops on neither opens at `data.url`; one the person skipped installs the same way later.
101
+
102
+ ## Verify
103
+
104
+ 1. `pnpm everyapp status --json`: `done` with `data.installed: true`, `data.claimed: true`, `data.owner.email`, `data.gatewayUrl` = `https://<gateway host>`, `data.appBaseDomain` (= `<app base domain>`), `data.mode: "self_hosted"`, `data.tls: true` (null: Cloudflare couldn't list the certificates, and a `CERTIFICATES_UNKNOWN` warning says so; rerun status later), `data.certificates[]` each `ready`, `data.access` (`{ on, teamDomain }`; null on a hosted Gateway, before the first upload, or when cf couldn't list the Worker's settings, which adds an `ACCESS_UNKNOWN` warning), `data.apps[]` (one per registered app; its `setup` is null when the app declares nothing to set or isn't up yet, else `{ ready, settings, unmet, groups, command }`: `unmet` the settings that keep the app closed, each with `names`, `holder`, `need.kind` and its guide `setup`, `setup/<name>.md` in this folder; `command`, `pnpm everyapp configure <app id>`, null once `ready`), and `data.fixes` (each `{ code, severity, message, run, note?, fix? }`; `severity` is `error`, `warning`, `info` or `settling`) empty or only codes that don't mean the Gateway is unfinished: `CERT_PENDING`, `DEPLOY_RUNNING`, `CERTIFICATES_UNKNOWN`, `ACCESS_UNKNOWN`, `APP_BINDING` (an app settling, not the Gateway), `APP_NEEDS_SETUP` (`warning`, "<app> needs setup": that app's `setup.ready` is false; its `run` is `setup.command.command`, and the person's report prints `Guide: .claude/skills/everyapp/setup/<name>.md` under it: that integration's file, not this one), `SETTINGS_UNKNOWN` (`warning`: cf couldn't list a Worker's secrets, so the settings it holds read `set: null`, which never blocks; run status again) and `GATEWAY_OUTDATED` (`info`, listed last: "Your every-app folder has a newer Gateway than the one online"; its `run` is `pnpm everyapp update`, or the next new app's deploy brings it; the summary still says "nothing to fix", so go on). Fix codes that mean this file isn't done: `GATEWAY_NOT_INSTALLED`, `GATEWAY_NOT_UPLOADED`, `NO_OWNER` (run setup again), `CHECKOUT_BEHIND` (`git pull`, then `pnpm install`), `GATEWAY_CHANGED` and `BINDINGS_DIFFER` (setup repairs; the first asks at a terminal). The other `APP_*` and `EMAIL_*` codes belong to app deploys, not here. Every other setup file relies on this check.
105
+ 2. `pnpm everyapp secret list --json` from the checkout root: `data.gateway.workerName` is `every-app-gateway` and `data.gateway.names` holds `GATEWAY_URL`, `CLOUDFLARE_ACCOUNT_ID`, `GATEWAY_DEPLOYMENT_MODE`, `BETTER_AUTH_SECRET`, `JWT_PRIVATE_KEY`, `JWT_PUBLIC_KEY`; `CF_DEPLOY_TOKEN` too after Step 9. From the root the event also carries `data.apps[]`, `{ id, setup }` for each deployed app that declares something (the same `setup` as status). One app's, from anywhere once it is deployed: `pnpm everyapp secret list <app id> --json`, whose `data.app.setup` is that `setup` and whose `data.gateway.needed` and `data.gateway.missing` still say the same of the Gateway's names (`APP_NOT_FOUND` before its first deploy: in its directory instead).
106
+ 3. Smoke check, from your shell: `curl -sS -o /dev/null -w '%{http_code}\n' https://<gateway host>/` answers `200` (the page loads and the browser does the sign-in redirect; read from the code, not checked live) or a `3xx` to a `cloudflareaccess.com` page (Cloudflare Access is in front; setup's own probe reads it the same way), not a TLS or name error; `000` means DNS or the certificate isn't ready yet, give it ten minutes. `cf auth whoami` says `authenticated: true` with the person's email.
107
+ 4. The person opens `https://<gateway host>`, signs in with the owner email and password, and `https://<gateway host>/admin` opens (Users, invitations, apps).
108
+ 5. Logs: `cf` has no Worker tail (Cloudflare's cf↔wrangler reference: "cf cannot stream live logs yet"; live logs are `npx wrangler tail every-app-gateway`, and wrangler has its own one-time login the person approves). In the dashboard, README's path: **Workers & Pages** → `every-app-gateway` → **Observability** (**Logs** on older accounts) → **Live**; Workers Logs are on for the Gateway, so the same page keeps them. `pnpm everyapp status --json` is faster for everything setup touches.
109
+
110
+ ## If it fails
111
+
112
+ | error or symptom | meaning | what to do |
113
+ | --- | --- | --- |
114
+ | `UNSUPPORTED_RUNTIME`, `NODE_TOO_OLD` | Node below 22.18.0, Bun, or a Volta/pnpm pin on an older Node | install Node 22.18.0 or newer (22, 24 or 26), open a new terminal, rerun; raise the pin |
115
+ | `CHECKOUT_MISSING` | `everyapp` ran outside the `every-app` folder (or via `npx`) | `cd every-app`, `pnpm everyapp …` |
116
+ | `cloudflare_login` repeats, `CLOUDFLARE_LOGIN_FAILED` | the device login wasn't approved within 5 minutes (cf's limit), or failed | `pnpm everyapp login --json` again, and hand the link and code over at once; a 403 managed challenge on a server: use `CLOUDFLARE_API_TOKEN` |
117
+ | `CLOUDFLARE_TOKEN_REJECTED` | `CLOUDFLARE_API_TOKEN` is set but mistyped, expired or short of permissions | fix the token (Step 5's list), or `unset CLOUDFLARE_API_TOKEN` and log in |
118
+ | `choose_account` | several accounts (or several Gateways) and no `--account-id` | ask the person; run the chosen `data.choices[].rerun` |
119
+ | `ACCOUNT_NOT_ACCESSIBLE`, `ACCOUNT_REQUIRED` | `--account-id` names an account this login can't use; a token lists none | pick an id from the message; the id is in the dashboard URL, `dash.cloudflare.com/<account id>/…` |
120
+ | `GATEWAY_NOT_FOUND` | the named account has no Gateway, or the login lists no accounts | drop `--account-id`/`CLOUDFLARE_ACCOUNT_ID`, log in to the right account, or run setup to install |
121
+ | `upgrade_workers_paid`, "Subscribe this account to Workers Paid" ("It's on the Free plan", or "Cloudflare refused the upload on the Free plan") | Free plan; nothing created | Step 2, rerun |
122
+ | `CF_EMAIL_UNVERIFIED` (Cloudflare API code 10034) | the account's email isn't verified, so Cloudflare creates nothing | the person opens `data.url` (https://dash.cloudflare.com/profile) and finishes Step 1; run `data.rerun` |
123
+ | `DOMAIN_REQUIRED` | setup ran unattended without `--domain` | one zone: run `data.rerun` (`--domain apps.<zone>`; another name under it works too); several: ask the person which `data.choices[].label`, run its `rerun` |
124
+ | `WORKERS_PAID_UNVERIFIED` (warning) | the subscription list didn't name the plan | ask the person to check **Billing** → **Subscriptions**; the run continues |
125
+ | `add_domain` "Add a domain" (no `--domain`), `ZONE_NOT_FOUND` | no domain in this account, or `--domain` isn't under one (wrong account?) | Step 3; check `cf auth whoami` shows the intended account |
126
+ | `add_domain` "Finish activating" | nameservers not switched yet | finish Step 3's nameserver change, wait for the active email |
127
+ | `DNS_RECORD_CONFLICT` | a record already answers `apps.<your domain>` | the person deletes it (domain → **DNS**) or picks another name; `--force-dns` only when they say so |
128
+ | `DNS_UNREADABLE` | the API token can't read the zone's DNS, so it can't tell whether a record is in the way | give the token Zone › DNS › Read, rerun; `--force-dns` only when they say so |
129
+ | `register_workers_subdomain` | first Worker in this account; the database and KV namespace exist already | open `data.url`, pick any name (no name field: **Workers & Pages** → **Change** next to **Your subdomain**), rerun: it resumes |
130
+ | `rerun_interactive` (`data.needsTerminal: true`) | the Gateway Worker serves a version everyapp didn't deploy | the person runs `data.rerun` in their own terminal and confirms; never rerun it yourself, with or without `--json` |
131
+ | `GATEWAY_OUTDATED` from `status` (`info`) | this checkout's Gateway is newer than the live one; nothing is broken | go on; `pnpm everyapp update` when the person wants it updated now |
132
+ | `DOMAIN_CHANGE_UNSUPPORTED` | the Gateway lives elsewhere; it can't move | rerun without `--domain` |
133
+ | `claim_owner` after 15 minutes | nobody opened the link | they open `data.setupUrl` now, or rerun for a new link |
134
+ | "Use the newer setup link", the page refuses the link | expired, or replaced by a later run (maybe on another machine) | rerun setup; use only the newest link |
135
+ | "Password must be at least 8 characters", "Passwords do not match" | the claim form's own checks | fix the fields, submit again |
136
+ | `GATEWAY_UNREACHABLE`, `CERT_PENDING`, `curl` answers `000` | certificate or DNS still on the way | wait up to ten minutes; the link works as soon as the host answers |
137
+ | `OWNER_NOT_CLAIMED` (warning, exit 0; `data.needsTerminal: true`) | `CI` is set, or output is piped without `--json`: no link is shown there | run setup at a terminal, or with `--json` from an agent on the person's machine |
138
+ | `SECRET_NOT_SETTABLE` | `secret set` on `GATEWAY_URL`, `JWT_*`, … | setup owns those; nothing to set |
139
+ | `SETTING_VALUE_INVALID` with `data.name` | `BROWSER_APP_INSTALLS` takes exactly `on` or `off` (a plain setting; nothing was written) | pipe the value `data.fix` describes |
140
+ | `SECRET_VALUE_REQUIRED`, `SECRET_SEVERAL_NAMES` | `secret set CF_DEPLOY_TOKEN --json` got no value, or a pipe with several names | one of README's three ways, one name per pipe |
141
+ | `CONFIRMATION_REQUIRED` | `secret unset … --json` without `--yes`: nothing was removed | ask the person; rerun with `--yes` only when they said so |
142
+ | `integration_not_configured`, `ai_provider_not_configured` from an app | the Gateway is fine; that integration's setting isn't set | the integration's own file in this folder |
143
+ | an app's host answers 503 `app_needs_setup`, or a browser lands on `https://<gateway host>/?setup=<app id>` | the Gateway keeps an app closed until its required settings are set; `status` names them under `APP_NEEDS_SETUP` | the file its `Guide:` line names |
144
+
145
+ ## Rerun, rotate, remove
146
+
147
+ - Rerun `pnpm everyapp setup --domain apps.<your domain> --json` any time: it logs in, finds the Gateway, upgrades it after a `git pull` (`pnpm everyapp update --json` does only that), repairs bindings and hostnames, mints a new owner link while there is no owner, and otherwise ends "up to date" (`data.gateway: "up-to-date"`). `--domain` can be left off once installed; the address and the mode can't change.
148
+ - Rotate the Cloudflare login: `cf auth logout`, then `pnpm everyapp login --json`. The owner's password: **Forgot password?** on the sign-in page when the Gateway sends email, else an admin's **Users** → **⋯** → **Password reset link** (valid an hour). The Gateway's own keys: docs/runbooks/key-rotation.md: a new pair in the dashboard, the public key recorded in the install row, `setup --redeploy` at a terminal, then `pnpm everyapp deploy` from every app's directory (apps keep the old key and answer 401 until then). `CF_DEPLOY_TOKEN`: roll the token at https://dash.cloudflare.com/profile/api-tokens (**⋯** → **Roll** → **Confirm**: same permissions, new secret, the old one stops at once), then set the new value one of the three ways; or create a new token, set it, then delete the old one.
149
+ - Remove browser installs: `pnpm everyapp secret unset CF_DEPLOY_TOKEN --json` (under `--json` it needs `--yes`, else `CONFIRMATION_REQUIRED`; add it only when the person said so), then delete the token in the dashboard; or keep the token and turn installs off: `BROWSER_APP_INSTALLS=off pnpm everyapp secret set BROWSER_APP_INSTALLS --from-env BROWSER_APP_INSTALLS --json` (`off` is a toggle, not a secret: the one value this folder puts on a command line, as docs/runbooks/browser-app-install.md does). Removing the Gateway itself is the person's, in the dashboard, and never yours to start (`delete` removes an app; `teardown` empties a dedicated test account the person names, never one in use: SKILL.md "Wipe"). Setup finds a Gateway only by its D1 database `every-app-gateway`: while that database exists, a rerun repairs the Gateway it describes (a Worker deleted by hand comes back at the same address); once it is gone, setup installs fresh, asking first when a Worker `every-app-gateway` is still in the account ("Replace it with <version>?"; unattended, `rerun_interactive`).
150
+
151
+ ## Optional: MCP servers worth having beside Every App
152
+
153
+ Not part of setup, and never added by you unasked. Two are worth adding;
154
+ nothing else is. When the person's task needs one, offer it in one line
155
+ ("Cloudflare's MCP server would let me read this account's DNS and Access
156
+ settings from here. Add it to Claude Code?") and do nothing until they say
157
+ yes.
158
+
159
+ **The Gateway's own connector, first.** `https://<gateway host>/mcp` is
160
+ every app the person can open, as tools, behind the Gateway's sign-in and
161
+ consent; [mcp.md](../mcp.md) has the commands per client. Every member can
162
+ have it. The one below is for the owner or operator, the person whose
163
+ Cloudflare login ran `pnpm everyapp setup`.
164
+
165
+ **Cloudflare's MCP server, `https://mcp.cloudflare.com/mcp`.** The whole
166
+ Cloudflare API and its docs behind four tools: `search` and `execute` (the
167
+ agent writes JavaScript against the API; it runs on Cloudflare's side),
168
+ `docs` and `whoami`. Connecting opens Cloudflare's login and a consent
169
+ page: choose **Minimal**; a call that needs more asks for that scope then
170
+ (step-up, since 2026-10-19). It then acts as that person on every account
171
+ their login reaches.
172
+
173
+ - Good for, with a Gateway: reading the account the Gateway runs in when
174
+ `pnpm everyapp status` and `pnpm everyapp access show` don't answer the
175
+ question. The zone and its DNS records (`<gateway host>` and one
176
+ `<app>.<app base domain>` per app, each a Workers Custom Domain with its
177
+ own record), the Workers (`every-app-gateway` and each app's) with their
178
+ versions, the D1 database `every-app-gateway`, the Access team,
179
+ applications and policies that `pnpm everyapp access on` made, Email
180
+ Routing, Workers logs, the plan and the bill. "Which version is serving",
181
+ "is the DNS record there", "why does this app host 503", "who does the
182
+ Access policy let in", "what did October cost".
183
+ - Noise for: building and deploying. `pnpm everyapp setup`, `deploy`,
184
+ `update`, `install`, `secret set`, `access on`, `email` and `mcp on`
185
+ write the Gateway's registry and the deploy ledger as well as Cloudflare,
186
+ and a deploy refuses to replace a Worker last changed outside everyapp
187
+ (`assertReplaceable` in `packages/cli/src/lib/cf/deploy.ts`: the next
188
+ `pnpm everyapp deploy` stops and asks a person to confirm in a
189
+ terminal). A Worker, secret, DNS record or Access policy changed through
190
+ this server is one `everyapp` doesn't know about. Look with it; change
191
+ with `pnpm everyapp`.
192
+ - The rule: read before write. A write through it is a live API call on
193
+ the whole account, as the person, with no undo. It goes in the person's
194
+ own client config (Claude Code's default `local` scope or `--scope user`,
195
+ `~/.cursor/mcp.json`, `~/.codex/config.toml`), never in one the
196
+ repository shares (`.mcp.json` from `--scope project`, `.cursor/mcp.json`,
197
+ `.codex/config.toml`), where every clone would be offered the account.
198
+
199
+ When they say yes, by client. The sign-in is the person's step every time:
200
+ the consent page is theirs, never yours.
201
+
202
+ - Claude Code. You may run it:
203
+
204
+ ```bash
205
+ claude mcp add --transport http cloudflare https://mcp.cloudflare.com/mcp
206
+ ```
207
+
208
+ Then the person types `/mcp` in Claude Code, chooses **cloudflare**,
209
+ **Authenticate**, and allows in the browser.
210
+ - Codex. You run `codex mcp add cloudflare --url https://mcp.cloudflare.com/mcp`;
211
+ the person runs `codex mcp login cloudflare` in their own terminal.
212
+ - claude.ai and Claude Desktop: **Settings** → **Connectors** → **Add
213
+ custom connector**, the URL above.
214
+ - Cursor: in `~/.cursor/mcp.json`,
215
+ `{ "mcpServers": { "cloudflare": { "url": "https://mcp.cloudflare.com/mcp" } } }`,
216
+ then sign in when Cursor asks.
217
+
218
+ Removing it: `claude mcp remove cloudflare`, `codex mcp remove cloudflare`,
219
+ or delete the entry.
220
+
221
+ **GitHub.** `pnpm everyapp install <github url>` downloads a public release
222
+ anonymously and needs no GitHub access. For what surrounds an app's
223
+ repository (which release, its README, an issue, the Actions runs of the
224
+ starter's `security-review.yml`), a harness with a shell has `gh`; in
225
+ claude.ai, turn on the GitHub connector (**Settings** → **Connectors**).
226
+ Nothing to add.
227
+
228
+ **Not worth adding.** Cloudflare's separate docs server
229
+ (`https://docs.mcp.cloudflare.com/mcp`): the API server's `docs` tool is
230
+ the same search. A docs server for Every App: none; the agent docs are
231
+ Markdown at `https://everyapp.com/docs/agent/<page>.md` and
232
+ https://everyapp.com/llms.txt, which any client reads without MCP.
233
+
234
+ ## Sources
235
+
236
+ Verified 2026-10-23; CLI shapes re-checked after #400, #401 and #410 merged; `data.apps[].setup`, `APP_NEEDS_SETUP`, `SETTINGS_UNKNOWN` and `secret list <app id>` after #383, #395, #396 and #397 (2026-10-24). The agent docs' version of this page: landing-page/content/agent/setup.md in the checkout, served at https://everyapp.com/docs/agent/setup.md once the site deploys with the launch.
237
+
238
+ - Plans and prices: https://developers.cloudflare.com/workers/platform/pricing/, https://developers.cloudflare.com/d1/platform/pricing/, https://developers.cloudflare.com/registrar/faq/ (at cost), https://costgoat.com/pricing/cloudflare-domains (third party, 2026-10-20)
239
+ - Account, billing, domains: https://developers.cloudflare.com/fundamentals/account/create-account/, https://developers.cloudflare.com/fundamentals/user-profiles/verify-email-address/, https://developers.cloudflare.com/fundamentals/subscriptions-and-billing/create-billing-profile/, https://developers.cloudflare.com/registrar/get-started/register-domain/, https://developers.cloudflare.com/fundamentals/manage-domains/add-site/
240
+ - `cf` and tokens: https://developers.cloudflare.com/cf/get-started/, https://developers.cloudflare.com/cf/ci/, cf 1.0.0-beta.14's source (`Math.min(expires_in, 300)`: the 5-minute login), https://github.com/cloudflare/cf/issues/23 (the 403 from datacenter IPs), https://developers.cloudflare.com/api/resources/zones/methods/list/ and https://developers.cloudflare.com/fundamentals/api/reference/permissions/ (Zone Read and DNS Read are distinct), https://developers.cloudflare.com/fundamentals/api/how-to/roll-token/
241
+ - workers.dev, logs, Node: https://developers.cloudflare.com/workers/configuration/routing/workers-dev/, https://github.com/cloudflare/workers-sdk/issues/9045, https://developers.cloudflare.com/workers/observability/logs/workers-logs/, https://developers.cloudflare.com/cf/wrangler/reference/, https://nodejs.org/en/about/previous-releases
242
+ - The four apps (Step 11), verified 2026-10-25: landing-page/content/docs/setup-prompt.txt (step 4 and its "Only I can" list; #595, #607), docs/runbooks/app-releases.md (#611: `pnpm pack-for-app`, the Release workflow, which apps bind R2), landing-page/content/agent/deploy.md ("Release installs") and landing-page/content/agent/errors.md (`NO_RELEASE`, `R2_NOT_ENABLED`), packages/cli/src/commands/install/index.ts, packages/cli/src/lib/app/release.ts, packages/cli/src/lib/app/buckets.ts, https://developers.cloudflare.com/r2/get-started/ (the dashboard link)
243
+ - In this repository: packages/cli/src/commands/setup/{runSetup,deployGateway,index,command}.ts, commands/status/{index,problems,render}.ts, lib/app/settings.ts and packages/sdk/src/internal/appSettings.ts (the settings model), apps/every-app-gateway/src/server/app-needs-setup.ts (the closed app), commands/update/command.ts, commands/secret/index.ts, commands/configure/index.ts, commands/email/index.ts, lib/cf/{account,plan,deploy,errors}.ts, lib/domains/{preflight,zones}.ts, lib/gateway/{discover,connect,setup-link,apply,resources}.ts, lib/access/settings.ts, lib/errors.ts, lib/output/{events,report,command}.ts, lib/runtime.ts, apps/every-app-gateway/src/routes/{__root,setup}.tsx, docs/runbooks/{key-rotation,browser-app-install}.md, landing-page/content/docs/{cloudflare,domain,gateway,troubleshooting}.mdx