create-ailk 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +3 -3
  2. package/dist/cli.js +12 -1
  3. package/dist/lib/module-license-gate.d.ts +29 -23
  4. package/dist/lib/module-license-gate.js +98 -0
  5. package/dist/module-architecture.js +5 -4
  6. package/dist/programmatic.js +12 -4
  7. package/dist/starter-grid.d.ts +4 -67
  8. package/dist/starter-grid.js +6 -84
  9. package/dist/template-manifest.d.ts +1 -1
  10. package/dist/template-manifest.js +5 -5
  11. package/package.json +4 -2
  12. package/release-scope.json +25 -0
  13. package/site-templates/designs/minimalism/sample/README.md +2 -2
  14. package/site-templates/designs/minimalism/sample/content/en/HomePage/home.mdx +1 -1
  15. package/templates/.claude/agents/web.md +10 -8
  16. package/templates/.claude/rules/architecture.md +10 -7
  17. package/templates/.claude/skills/add-auth/SKILL.md +142 -90
  18. package/templates/.claude/skills/add-auth/references/env-vars.md +9 -1
  19. package/templates/.claude/skills/add-auth/references/oauth-app-setup.md +14 -6
  20. package/templates/.claude/skills/add-page/references/page-types.md +9 -10
  21. package/templates/.claude/skills/check-site/SKILL.md +28 -18
  22. package/templates/.claude/skills/check-site/references/common-errors.md +12 -9
  23. package/templates/.claude/skills/check-site/references/findings-glossary.md +4 -4
  24. package/templates/.claude/skills/check-site/references/severity-levels.md +3 -3
  25. package/templates/.claude/skills/setup-deploy/SKILL.md +75 -38
  26. package/templates/.claude/skills/update-page/SKILL.md +1 -1
  27. package/templates/.env.example +23 -2
  28. package/templates/CLAUDE.md +1 -1
  29. package/templates/package.json +2 -0
  30. package/dist/modules/commerce/0.6.0.tar.gz +0 -0
  31. package/dist/modules/commerce/0.6.1.tar.gz +0 -0
  32. package/dist/modules/docs-blog/0.6.0.tar.gz +0 -0
  33. package/dist/modules/docs-blog/0.6.1.tar.gz +0 -0
  34. package/dist/modules/marketing-site/0.6.1.tar.gz +0 -0
  35. package/dist/modules/minimalism-site/0.6.1.tar.gz +0 -0
  36. package/dist/modules/multi-tenant/0.6.0.tar.gz +0 -0
  37. package/dist/modules/multi-tenant/0.6.1.tar.gz +0 -0
  38. package/dist/modules/saas-product/0.6.1.tar.gz +0 -0
  39. package/dist/modules/scheduling/0.6.0.tar.gz +0 -0
  40. package/dist/modules/scheduling/0.6.1.tar.gz +0 -0
  41. package/dist/modules/signal-collectors/0.6.0.tar.gz +0 -0
  42. package/dist/modules/signal-collectors/0.6.1.tar.gz +0 -0
  43. package/dist/modules/simple-service/0.6.1.tar.gz +0 -0
  44. package/dist/modules/workspace/0.6.0.tar.gz +0 -0
  45. package/dist/modules/workspace/0.6.1.tar.gz +0 -0
  46. package/site-templates/aliases/minimalism-site.TEMPLATE-MANIFEST.json +0 -538
  47. package/templates/.claude/skills/setup-deploy/references/env-vars-template.md +0 -192
  48. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-31.552Z-fallback-1789916251590-037e9005.json +0 -8
  49. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.840Z-fallback-1789916253842-b52659e9.json +0 -12
  50. package/templates/apps/api/.ailk/inbox/2026-09-20T14-57-33.844Z-fallback-1789916253845-6b266f8c.json +0 -12
@@ -22,8 +22,8 @@ upstream packages; don't try to edit them locally.
22
22
  ## Read before edit
23
23
 
24
24
  1. `.claude/rules/architecture.md` — confirm what `apps/web` may
25
- import. NextAuth handlers are the only API-shaped code allowed in
26
- `apps/web`; everything else server-side goes through `apps/api`.
25
+ import, including its one database exception (the Better Auth
26
+ adapter). Everything else server-side goes through `apps/api`.
27
27
  2. The page or component you're modifying, plus any sibling files in
28
28
  the same directory.
29
29
  3. Any project-local theme override file before touching styles —
@@ -46,7 +46,8 @@ Run `pnpm preflight` before opening a PR.
46
46
  - Need a new content type? Add it under `content/<TypeName>/` and
47
47
  reference the schema from `@working-theory/schema`.
48
48
  - Need a database read? Wrong layer — `apps/web` does not read the
49
- database. Route through `apps/api`.
49
+ database outside the one exception `.claude/rules/architecture.md`
50
+ names. Route through `apps/api`.
50
51
 
51
52
  ## Domain conventions
52
53
 
@@ -55,23 +56,24 @@ Run `pnpm preflight` before opening a PR.
55
56
  Adding `'use client'` to a file that just renders JSX is the
56
57
  default failure mode — resist it.
57
58
  - **Tailwind tokens only.** No raw hex, rgb, or arbitrary colors.
58
- Use semantic tokens from `@working-theory/theme` (`bg-canvas`, `text-fg`,
59
+ Use semantic tokens from `@working-theory/theme` (`bg-surface`, `text-fg`,
59
60
  `border-border`, etc.). If a token doesn't exist, extend the theme;
60
61
  don't bypass.
61
62
  - **Mobile-first responsive.** Default styles target mobile;
62
63
  `md:`/`lg:` modifiers for larger viewports.
63
64
  - **MDX rendering** uses `next-mdx-remote/rsc`, never `@next/mdx`
64
65
  (the latter requires runtime config that fights Server Components).
65
- - **NextAuth handlers** are the only API-shaped code in `apps/web`
66
- — they live at `apps/web/app/api/auth/[...nextauth]/route.ts`.
66
+ - **Better Auth's route handler** is the only API-shaped code in
67
+ `apps/web` — it lives at `apps/web/app/api/auth/[...all]/route.ts`.
67
68
  Everything else goes to `apps/api`.
68
69
 
69
70
  ## Forbidden
70
71
 
71
72
  - Importing from `apps/api` or `apps/mcp` — these are peer apps;
72
73
  speak to the API via `@working-theory/api-client`.
73
- - Importing `@working-theory/database` — `apps/web` does not touch the DB;
74
- route through `apps/api`.
74
+ - Importing `@working-theory/database` outside the Better Auth adapter
75
+ (the exception `.claude/rules/architecture.md` names) — route through
76
+ `apps/api`.
75
77
  - Importing `resend`, `@react-email/*` directly — wrap through
76
78
  `@working-theory/email`, server-side via `apps/api`.
77
79
  - Adding a `utils.ts`, `helpers.ts`, `common.ts`, or `misc.ts` file
@@ -25,13 +25,16 @@ other.
25
25
  or `@working-theory/schema` (schema.org types).
26
26
  - Need an HTTP call from `apps/web` to `apps/api`? Use
27
27
  `@working-theory/api-client`. Don't import API route handlers directly.
28
- - Need database access? Only `apps/api` and `apps/mcp` import
29
- `@working-theory/database`. `apps/web` never reads the database directly — it
30
- goes through the HTTP API.
31
- - Cross-cutting integrations (auth, email, analytics) go through their
32
- wrapper packages: `@working-theory/auth-client`, `@working-theory/email`,
33
- `@working-theory/analytics`. Never import `next-auth`, `resend`, etc.
34
- directly.
28
+ - Need database access? `apps/api` and `apps/mcp` import
29
+ `@working-theory/database`. `apps/web` does not read the database — it goes
30
+ through `apps/api` via the published HTTP client. The one exception is the
31
+ Better Auth adapter (`apps/web/lib/prisma-for-auth.ts`, typed in
32
+ `apps/web/auth.ts`).
33
+ - Cross-cutting integrations (email, analytics) go through their
34
+ wrapper packages: `@working-theory/email`, `@working-theory/analytics`.
35
+ Never import `resend`, etc. directly. Auth has no wrapper package: it is
36
+ Better Auth, configured in `apps/web/auth.ts` and mounted at
37
+ `apps/web/app/api/auth/[...all]/route.ts`.
35
38
 
36
39
  ## What you can verify, what you can't
37
40
 
@@ -1,68 +1,95 @@
1
1
  ---
2
2
  name: add-auth
3
- description: Activate auth providers (magic-link via Resend, Google OAuth, GitHub OAuth) on an AILK consumer site. Use when the user says "wire up auth", "add login", "set up sign-in", "I need users to log in", or asks how to enable any of magic-link / Google / GitHub auth on their AILK site. The skill writes env vars for whichever subset of providers the consumer activates and prints (plus saves) an OAuth-app-setup runbook. It does NOT modify `auth.config.ts` and does NOT emit any pages.
3
+ description: Activate the site's sign-in providers (email-and-password, Google OAuth, GitHub OAuth) on an AILK consumer site. Use when the user says "wire up auth", "add login", "set up sign-in", "I need users to log in", or asks how to enable email / Google / GitHub sign-in on their AILK site. The skill writes env vars for whichever subset of providers the consumer activates and prints (plus saves) an OAuth-app-setup runbook. It does NOT modify `apps/web/auth.ts` and does NOT emit any pages.
4
4
  ---
5
5
 
6
6
  # add-auth
7
7
 
8
- Activate one or more auth providers on an AILK site by writing the env
9
- vars NextAuth reads to detect them, plus a `RUNBOOK.md` that documents
10
- the OAuth-app-creation steps for the consumer's records.
8
+ Activate one or more sign-in providers on an AILK site by writing the
9
+ env vars `getActiveProviderIds()` (`apps/web/lib/auth-env.ts`) reads
10
+ to detect them, plus a `RUNBOOK.md` that documents the OAuth-app-creation
11
+ steps for the consumer's records.
12
+
13
+ The site's auth library is **Better Auth**, configured in
14
+ `apps/web/auth.ts` and mounted at `apps/web/app/api/auth/[...all]/route.ts`.
11
15
 
12
16
  ## When to use
13
17
 
14
18
  The user has a working AILK site (post-`pnpm create ailk`) and wants
15
- to gate routes behind sign-in, send magic-link emails, or accept
16
- Google / GitHub OAuth. Phrases that should trigger this skill:
19
+ to gate routes behind sign-in or accept email, Google or GitHub
20
+ sign-in. Phrases that should trigger this skill:
17
21
 
18
22
  - "wire up auth" / "add login" / "set up sign-in"
19
23
  - "I want users to log in"
20
24
  - "enable Google sign-in" / "enable GitHub login"
21
- - "set up magic-link auth"
25
+ - "set up email login" / "set up magic-link auth"
22
26
  - "add OAuth"
23
27
 
28
+ A magic link is not wired: Better Auth core ships no magic-link
29
+ provider, so the `email` provider id switches on email-and-password
30
+ sign-in instead. Say so when the consumer asks for a magic link, and
31
+ offer `email` on those terms.
32
+
24
33
  Skip this skill when:
25
34
 
26
- - The user wants a `/login` or `/account` _page_ — those are pages, not
27
- auth wiring. Use `add-page` for that.
28
- - The user is asking about a third-party provider that isn't in the
29
- AILK locked set (Apple, Microsoft, Twitter, etc.). The locked set is
30
- magic-link + Google + GitHub at v1; broader provider support is a
31
- future PR. Acknowledge the request and stop.
35
+ - The user wants a new page. The site already ships its sign-in and
36
+ sign-up pages (`apps/web/app/[locale]/(auth)/`), which list whichever
37
+ providers are active. Any other page is `add-page`'s job.
38
+ - The user is asking about a third-party provider outside the three
39
+ provider ids below (Apple, Microsoft, Twitter, etc.). Adding one is a
40
+ code change to `apps/web/auth.ts`, not env wiring. Acknowledge the
41
+ request and stop.
32
42
  - The user is in production and needs production callback URLs. v1
33
43
  ships dev-mode callbacks (`http://localhost:3000`) only —
34
44
  production callback setup is deferred to `setup-deploy`
35
45
  or a future deploy skill. Note this and stop.
36
46
 
47
+ ## The provider ids
48
+
49
+ `getActiveProviderIds()` in `apps/web/lib/auth-env.ts` returns a
50
+ provider id only when every one of its env vars is set to a non-empty
51
+ value:
52
+
53
+ | Provider id | Env vars | What it switches on |
54
+ | ----------- | ------------------------------------------- | --------------------------------------------------------------- |
55
+ | `email` | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | Email-and-password sign-in (Better Auth's `emailAndPassword`) |
56
+ | `google` | `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` | Google OAuth (Better Auth's `socialProviders.google`) |
57
+ | `github` | `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET` | GitHub OAuth (Better Auth's `socialProviders.github`) |
58
+
59
+ `references/env-vars.md` is the full contract, including the auxiliary
60
+ vars (`BETTER_AUTH_URL`, `BETTER_AUTH_SECRET`, `AILK_AUTH_REQUIRED`,
61
+ `AILK_AUTH_SIGNUP_OPEN`, `AILK_AUTH_PASSWORD_RESET`,
62
+ `AUTH_EMAIL_WEBHOOK_SECRET`).
63
+
37
64
  ## What this skill does (and does not do)
38
65
 
39
66
  **Does:**
40
67
 
41
- - Reads `.env.local` to see which providers are already activated.
42
- - Asks the consumer which of the three locked providers
43
- (magic-link, Google, GitHub) they want to activate _this session_.
68
+ - Reads `.env.local` to see which provider ids are already active.
69
+ - Asks the consumer which of the three provider ids (`email`,
70
+ `google`, `github`) they want to activate _this session_.
44
71
  - For each picked provider, walks the consumer through
45
- OAuth-app-creation (Google / GitHub) or Resend-key setup
46
- (magic-link), then writes the resulting secrets to `.env.local`.
47
- - Auto-detects whether `@working-theory/database` is installed with User /
48
- Session models (Prisma adapter mode) or not (JWT-only mode), and
49
- states which mode the site is in.
72
+ OAuth-app creation (`google` / `github`) or the Resend sender setup
73
+ (`email`), then writes the resulting values to `.env.local`.
74
+ - Checks that sign-in has a database to write to. Better Auth always
75
+ runs its Prisma adapter with database sessions, so sign-in needs
76
+ `DATABASE_URL` and the auth tables in place.
50
77
  - Writes (or merges) a `RUNBOOK.md` in the consumer's repo root
51
78
  with the same setup instructions the consumer just followed, so
52
79
  they can refer back later or hand to a collaborator.
53
80
 
54
81
  **Does not:**
55
82
 
56
- - Modify `auth.config.ts`. The locked-set providers are env-var-driven
57
- — present env vars activate the matching provider in
58
- `auth.config.ts`'s `buildProviders()`. No code changes are needed.
83
+ - Modify `apps/web/auth.ts`. The three provider ids are env-var-driven
84
+ — `apps/web/auth.ts` reads `getActiveProviderIds()` at startup and
85
+ builds only the providers it returns. No code changes are needed.
59
86
  - Create any new files under `app/`, `pages/`, or `content/`. The
60
87
  emit is limited to `.env.local` writes and a `RUNBOOK.md` write.
61
88
  - Set up production callback URLs. Dev-mode (`http://localhost:3000`)
62
89
  only at v1.
63
- - Add, remove, or modify any provider entry in `auth.config.ts`
64
- outside of magic-link / Google / GitHub. Consumer-added providers
65
- (e.g., Apple) are preserved as-is and never touched by this skill.
90
+ - Add, remove, or modify any provider in `apps/web/auth.ts`. A
91
+ provider the consumer added there by hand (e.g., Apple) is preserved
92
+ as-is and never touched by this skill.
66
93
  - Accept production OAuth credentials. If the consumer pastes a
67
94
  production-looking secret, that's acceptable, but the runbook still
68
95
  documents only the dev callback URL.
@@ -71,28 +98,28 @@ Skip this skill when:
71
98
 
72
99
  ### Step 1 — Show the menu
73
100
 
74
- Greet the consumer and present the three locked providers, marking
75
- which are already activated (env vars present in `.env.local`):
101
+ Greet the consumer and present the three provider ids, marking
102
+ which are already active (env vars present in `.env.local`):
76
103
 
77
104
  ```
78
- Which auth providers do you want to activate?
105
+ Which sign-in providers do you want to activate?
79
106
 
80
- [ ] magic-link (passwordless email login via Resend)
81
- [ ] Google OAuth
82
- [ ] GitHub OAuth
107
+ [ ] email (email-and-password sign-in)
108
+ [ ] google (Google OAuth)
109
+ [ ] github (GitHub OAuth)
83
110
 
84
111
  You can pick any subset, including "none of the above" (in which case
85
112
  this skill exits without writing anything). You can also re-run this
86
- skill later to activate more providers — already-activated providers
113
+ skill later to activate more providers — already-active providers
87
114
  will be skipped automatically.
88
115
  ```
89
116
 
90
- If `.env.local` already has any of these activated, mark them:
117
+ If `.env.local` already has any of these active, mark them:
91
118
 
92
119
  ```
93
- [x] magic-link (already activated — AUTH_EMAIL_SERVER + AUTH_EMAIL_FROM are set)
94
- [ ] Google OAuth
95
- [ ] GitHub OAuth
120
+ [x] email (already active — AUTH_EMAIL_SERVER + AUTH_EMAIL_FROM are set)
121
+ [ ] google (Google OAuth)
122
+ [ ] github (GitHub OAuth)
96
123
  ```
97
124
 
98
125
  Wait for the consumer to pick a subset. Then, for each picked
@@ -100,12 +127,13 @@ provider, run the matching sub-flow.
100
127
 
101
128
  ### Step 2 — Run per-provider sub-flows
102
129
 
103
- #### magic-link sub-flow
130
+ #### `email` sub-flow
104
131
 
105
- 1. Tell the consumer: _"Magic-link uses Resend as the email provider
106
- at AILK v1. Other email providers ship as additive future PRs.
107
- You'll need a Resend API key (free tier is fine for development).
108
- Get one at <https://resend.com/api-keys>."_
132
+ 1. Tell the consumer: _"The `email` provider turns on
133
+ email-and-password sign-in. It switches on when `AUTH_EMAIL_SERVER`
134
+ and `AUTH_EMAIL_FROM` are both set. You'll need a Resend API key
135
+ (free tier is fine for development). Get one at
136
+ <https://resend.com/api-keys>."_
109
137
  2. Wait for the consumer to paste the API key.
110
138
  3. Ask for the `AUTH_EMAIL_FROM` address. This must be a verified
111
139
  sender on the consumer's Resend account. For development it's
@@ -118,16 +146,33 @@ provider, run the matching sub-flow.
118
146
  AUTH_EMAIL_SERVER=smtp://resend:re_...@smtp.resend.com:465
119
147
  AUTH_EMAIL_FROM=onboarding@resend.dev
120
148
  ```
121
-
122
- #### Google OAuth sub-flow
149
+ 6. Tell the consumer who actually sends the mail. `apps/web` sends
150
+ none: `AUTH_EMAIL_SERVER` is read for its presence only, and
151
+ `apps/web/lib/auth-email.ts` relays each auth email (verification,
152
+ password reset) to `apps/api`, which sends it with `RESEND_API_KEY`
153
+ from `AUTH_EMAIL_FROM`. For that mail to go out, `RESEND_API_KEY`
154
+ and `AUTH_EMAIL_FROM` must be set for `apps/api`, and
155
+ `AUTH_EMAIL_WEBHOOK_SECRET` (any long random string, the same value)
156
+ for both apps. Password reset — and the verification mail with it —
157
+ is off until `AILK_AUTH_PASSWORD_RESET=1`, and also needs
158
+ `BETTER_AUTH_URL` and `BETTER_AUTH_SECRET` (`resetSendConfigured()`
159
+ in `apps/web/lib/auth-env.ts`).
160
+ 7. Tell the consumer that public sign-up stays closed until they set
161
+ `AILK_AUTH_SIGNUP_OPEN=1` (read by `isSignUpOpen()` in
162
+ `apps/web/lib/auth-env.ts`). With sign-up closed and `email` the only
163
+ provider, nobody can create the first account — so either open
164
+ sign-up long enough to create it, or activate `google` or `github`
165
+ as well. Ask which they want; leave the flag unset otherwise.
166
+
167
+ #### `google` sub-flow
123
168
 
124
169
  1. Tell the consumer the steps in chat AND queue the same content for
125
170
  the runbook (see Step 3). Steps:
126
171
  - Go to <https://console.cloud.google.com/apis/credentials>.
127
172
  - Click **Create Credentials → OAuth client ID**. If prompted,
128
173
  configure the OAuth consent screen first (**External** → fill
129
- name, support email, developer contact email; scopes are
130
- auto-populated by NextAuth).
174
+ name, support email, developer contact email; Better Auth
175
+ requests the scopes at runtime, so leave the scope list empty).
131
176
  - Application type: **Web application**.
132
177
  - Name: anything (e.g., "AILK dev").
133
178
  - **Authorized redirect URIs** — add exactly:
@@ -141,7 +186,7 @@ provider, run the matching sub-flow.
141
186
  GOOGLE_CLIENT_SECRET=...
142
187
  ```
143
188
 
144
- #### GitHub OAuth sub-flow
189
+ #### `github` sub-flow
145
190
 
146
191
  1. Tell the consumer the steps in chat AND queue the same content for
147
192
  the runbook. Steps:
@@ -171,49 +216,56 @@ or refer back later.
171
216
  Use `references/oauth-app-setup.md` as the template. Replace
172
217
  `<provider>` headings as appropriate, and only include sections for
173
218
  providers actually activated this session. If `RUNBOOK.md` already
174
- exists with sections for already-activated providers, do not
219
+ exists with sections for already-active providers, do not
175
220
  duplicate — add only the new sections beneath any existing content.
176
221
 
177
- ### Step 4 — Detect the database adapter mode
222
+ ### Step 4 — Check the database
178
223
 
179
- Before printing the closing summary, check the consumer's setup:
224
+ Sign-in always reads and writes the database: `apps/web/auth.ts`
225
+ runs Better Auth's Prisma adapter, and sessions are rows, not
226
+ cookie-only tokens. There is no database-free mode. Before printing
227
+ the closing summary, check:
180
228
 
181
- - If `package.json` lists `@working-theory/database` as a dependency AND
182
- `database/prisma/schema.prisma` defines `User` and `Session` models
183
- → **Prisma adapter mode**. Sessions persist across server restarts.
184
- - Otherwise → **JWT-only mode**. Sessions are cookies, no database.
229
+ - `DATABASE_URL` (and `DATABASE_URL_NON_POOLED`, which the migrations
230
+ use) is set in `.env.local`. If it is not, sign-in will fail on its
231
+ first request — point the consumer at the `setup-database` skill,
232
+ which sets both and creates the tables.
233
+ - The auth tables exist. The Prisma schema is `database/schema.prisma`
234
+ (Prisma reads the whole `database/` folder; the `User`, `Session`,
235
+ `Account` and `Verification` models are in `database/auth/schema.prisma`).
236
+ If the consumer has not applied the migrations yet, they run
237
+ `pnpm db:migrate:deploy`.
185
238
 
186
- State the mode in the closing summary so the consumer is never
239
+ State what you found in the closing summary so the consumer is never
187
240
  surprised:
188
241
 
189
- > "Your site is running in **Prisma adapter mode** — sessions persist
190
- > in the `User` and `Session` tables. Run `pnpm db:push` after this
191
- > skill if you haven't applied the migration yet."
242
+ > "Sign-in stores its users and sessions in your database (the
243
+ > `User` and `Session` tables). Run `pnpm db:migrate:deploy` if you
244
+ > haven't applied the migrations yet."
192
245
 
193
- or
246
+ or, when `DATABASE_URL` is unset:
194
247
 
195
- > "Your site is running in **JWT-only mode** — sessions are
196
- > cookie-only and don't require a database. To switch to persistent
197
- > sessions, install `@working-theory/database` and add the `User` / `Session`
198
- > models from `database/prisma/schema.prisma`."
248
+ > "Sign-in needs a database and none is configured yet. Run the
249
+ > `setup-database` skill before you try to sign in."
199
250
 
200
251
  ### Step 5 — Closing summary
201
252
 
202
253
  Print:
203
254
 
204
- - Which providers are now active (subset picked this session +
205
- already-activated providers).
206
- - The database adapter mode (Prisma or JWT).
255
+ - Which provider ids are now active (subset picked this session +
256
+ already-active providers).
257
+ - What Step 4 found about the database.
207
258
  - A reminder to set `AILK_AUTH_REQUIRED=1` in `.env.local` if they
208
259
  want protected routes (default is auth-disabled / public).
209
260
  - A pointer to `RUNBOOK.md` for future reference.
210
- - A pointer to `setup-deploy` for production callback URL
211
- setup when the consumer is ready to deploy.
261
+ - A pointer to `setup-deploy` for production callback URLs and
262
+ `BETTER_AUTH_URL` / `BETTER_AUTH_SECRET` when the consumer is ready
263
+ to deploy — a production deploy fails without `BETTER_AUTH_SECRET`.
212
264
 
213
265
  ## Re-invocation
214
266
 
215
267
  The skill is idempotent. On a second run, the menu in Step 1 marks
216
- already-activated providers with `[x]` (read from `.env.local`), and
268
+ already-active providers with `[x]` (read from `.env.local`), and
217
269
  the per-provider sub-flows skip those and only run for the new ones.
218
270
  The closing summary lists everything, not just what changed this
219
271
  session.
@@ -225,37 +277,37 @@ existing values in `.env.local`. Confirm before overwriting.
225
277
 
226
278
  ## Customization preservation
227
279
 
228
- If `auth.config.ts` has been modified by the consumer to add a
280
+ If `apps/web/auth.ts` has been modified by the consumer to add a
229
281
  third-party provider (e.g., Apple), this skill leaves that file
230
- completely untouched. The skill never reads, edits, or even opens
231
- `auth.config.ts`. Activation of the AILK locked set happens entirely
232
- through env vars — `getActiveProviderIds()` in
233
- `apps/web/lib/auth-env.ts` is what reads them at startup.
282
+ completely untouched. The skill never edits `apps/web/auth.ts`.
283
+ Activation of the three provider ids happens entirely through env
284
+ vars — `getActiveProviderIds()` in `apps/web/lib/auth-env.ts` is what
285
+ reads them at startup.
234
286
 
235
287
  ## What "activation" means under the hood
236
288
 
237
- - **Provider list is computed at startup from env-var presence** in
238
- `apps/web/auth.config.ts` → `buildProviders()`.
239
- - A provider is included only when every required env var is set:
240
- - `email` (magic-link): `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM`
241
- - `google`: `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET`
242
- - `github`: `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET`
289
+ - **The provider list is computed at startup from env-var presence**
290
+ by `getActiveProviderIds()` in `apps/web/lib/auth-env.ts`.
291
+ - `apps/web/auth.ts` consumes that list: `google` and `github` become
292
+ Better Auth `socialProviders` entries built from their env vars, and
293
+ `email` switches `emailAndPassword` on.
294
+ - A provider id is returned only when every one of its env vars is set
295
+ (the table under § The provider ids).
243
296
  - A site with zero auth env vars boots cleanly with no active
244
- providers (`apps/web/lib/auth-env.ts` returns an empty array).
297
+ providers (`getActiveProviderIds()` returns an empty array).
245
298
 
246
299
  This means the skill's job is purely env-var wiring + documentation.
247
300
 
248
301
  ## References
249
302
 
250
303
  - `references/oauth-app-setup.md` — RUNBOOK template the skill instantiates per session.
251
- - `references/env-vars.md` — env-var contract (which vars activate which provider).
304
+ - `references/env-vars.md` — env-var contract (which vars activate which provider id).
252
305
 
253
306
  ## Coordination
254
307
 
255
- - **`add-page`** — `/login` or `/account` pages. This skill
256
- emits no pages.
257
- - **`setup-deploy`** — production callback URL setup. v1
258
- is dev-only.
259
- - **`@working-theory/database`** — Prisma adapter detection. Install
260
- `@working-theory/database` separately to upgrade from JWT-only to persistent
261
- sessions.
308
+ - **`add-page`** — any new page. This skill emits no pages; the
309
+ sign-in and sign-up pages already ship.
310
+ - **`setup-database`** — `DATABASE_URL` and the tables sign-in
311
+ needs.
312
+ - **`setup-deploy`** — production callback URLs and the production
313
+ auth env vars. v1 of this skill is dev-only.
@@ -32,12 +32,20 @@ env-presence signal: it switches on the password method
32
32
  | `AILK_AUTH_REQUIRED` | unset | Read by `isAuthRequired()` in `apps/web/lib/auth-env.ts` (`"1"` or `"true"`). Default is auth-disabled / public, so a fresh scaffold boots without requiring any auth wiring. |
33
33
  | `BETTER_AUTH_URL` | unset | The site's public origin (e.g. `https://your-domain.com`). Better Auth builds OAuth callback URLs on it and it is the one trusted origin; unset, Better Auth derives both from each request. Set it in production. Local dev can leave it unset. |
34
34
  | `BETTER_AUTH_SECRET` | unset | Signs session cookies and email-verification tokens. **Required in production** — `apps/web/auth.ts` throws when it is unset there, rather than fall back to the development secret published in the source. Generate with `openssl rand -base64 32`. Optional for `next dev`. |
35
+ | `AILK_AUTH_SIGNUP_OPEN` | unset | Read by `isSignUpOpen()` in `apps/web/lib/auth-env.ts` (`"1"` or `"true"`). Unset, public sign-up is closed: with `email` active, the password form signs existing accounts in but creates none. |
36
+ | `AILK_AUTH_PASSWORD_RESET` | unset | Read by `isResetAvailable()` (`"1"` or `"true"`). Password reset also needs `BETTER_AUTH_URL`, `BETTER_AUTH_SECRET` and `AUTH_EMAIL_WEBHOOK_SECRET` (`resetSendConfigured()`). |
37
+ | `AUTH_EMAIL_WEBHOOK_SECRET` | unset | Signs the auth-mail relay from `apps/web` to `apps/api`, which sends with `RESEND_API_KEY` from `AUTH_EMAIL_FROM`. Set the same value for both apps; unset, no auth mail is sent. |
35
38
 
36
- The skill writes none of these auxiliary vars on its own. It mentions
39
+ The skill writes none of these auxiliary vars unasked. It mentions
37
40
  them in the closing summary so the consumer is aware:
38
41
 
39
42
  - `AILK_AUTH_REQUIRED` is the consumer's call (skill always defaults
40
43
  to leaving it unset).
44
+ - `AILK_AUTH_SIGNUP_OPEN` is the consumer's call too; the skill asks
45
+ when `email` is active, because with sign-up closed and no OAuth
46
+ provider nobody can create the first account.
47
+ - `AILK_AUTH_PASSWORD_RESET` and `AUTH_EMAIL_WEBHOOK_SECRET` are the
48
+ auth-mail setup the `email` sub-flow describes.
41
49
  - `BETTER_AUTH_URL` and `BETTER_AUTH_SECRET` are deferred to
42
50
  production-time setup (`setup-deploy`), and a production deploy
43
51
  fails without `BETTER_AUTH_SECRET`.
@@ -1,4 +1,4 @@
1
- # OAuth + Magic-Link Setup — RUNBOOK Template
1
+ # OAuth + Email Sign-In Setup — RUNBOOK Template
2
2
 
3
3
  The `add-auth` skill writes (or merges into) `RUNBOOK.md` at the
4
4
  consumer's repo root using the per-provider sections below. Only the
@@ -10,13 +10,13 @@ sections appear in the final runbook.
10
10
 
11
11
  ---
12
12
 
13
- ## Provider section: magic-link (Resend)
13
+ ## Provider section: email (Resend)
14
14
 
15
15
  ```markdown
16
- ## Auth — magic-link (Resend)
16
+ ## Auth — email sign-in (Resend)
17
17
 
18
- Magic-link sign-in uses Resend as the email provider. Activation is
19
- keyed off two env vars in `.env.local`:
18
+ Email-and-password sign-in is activated when both env vars are present
19
+ in `.env.local`:
20
20
 
21
21
  - `AUTH_EMAIL_SERVER` — `smtp://resend:<API_KEY>@smtp.resend.com:465`
22
22
  - `AUTH_EMAIL_FROM` — verified sender address on your Resend account
@@ -30,6 +30,14 @@ keyed off two env vars in `.env.local`:
30
30
  Resend's shared dev sender and works without verification. For
31
31
  production, verify your own sending domain in the Resend dashboard.
32
32
 
33
+ `AUTH_EMAIL_SERVER` is read for its presence only. The auth mail
34
+ (verification, password reset) is sent by `apps/api` with
35
+ `RESEND_API_KEY` from `AUTH_EMAIL_FROM`, so set both for the API, and
36
+ set `AUTH_EMAIL_WEBHOOK_SECRET` to the same random value for both apps.
37
+
38
+ Public sign-up stays closed until you set `AILK_AUTH_SIGNUP_OPEN=1` in
39
+ `.env.local`.
40
+
33
41
  ### `.env.local` entries
34
42
 
35
43
  \`\`\`
@@ -152,7 +160,7 @@ The Client ID stays the same.
152
160
 
153
161
  | Provider | Env vars | Active |
154
162
  | ----------- | ------------------------------------------------- | ------ |
155
- | magic-link | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | <fill> |
163
+ | email | `AUTH_EMAIL_SERVER` + `AUTH_EMAIL_FROM` | <fill> |
156
164
  | Google | `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` | <fill> |
157
165
  | GitHub | `GITHUB_CLIENT_ID` + `GITHUB_CLIENT_SECRET` | <fill> |
158
166
 
@@ -1,17 +1,16 @@
1
- <!-- GENERATED — do not hand-edit. Regenerate with:
2
- cd packages/create-ailk && pnpm page-types:build
3
- Source: packages/schema/src/registry/entries.ts
4
- Generator: packages/create-ailk/scripts/generate-page-types-reference.ts
1
+ <!-- GENERATED — do not hand-edit. AI Launch Kit generates this file
2
+ from its page-type registry and ships it with the scaffold. The
3
+ source of record for this site's own page-type registry is `pageTypeRegistry` in the installed `@working-theory/schema` package.
5
4
  -->
6
5
 
7
6
  # Page-Type → schema.org Registry Reference
8
7
 
9
8
  The full page-type catalog the `add-page` skill reads at runtime to
10
9
  resolve a slug or page-purpose hint to a family, chassis, schema.org
11
- `@type`, and route convention. Generated from
12
- `packages/schema/src/registry/entries.ts` — every registered page type
13
- appears exactly once, list/detail pairs are shown together, and no row
14
- here can name a type the registry doesn't have.
10
+ `@type`, and route convention. Generated from the page-type registry
11
+ `@working-theory/schema` exports — every registered page type appears
12
+ exactly once, list/detail pairs are shown together, and no row here
13
+ can name a type the registry doesn't have.
15
14
 
16
15
  The skill resolves in this order:
17
16
 
@@ -30,8 +29,8 @@ levels). The level is the module's, never a claim about this site's key.
30
29
  `<slug>` in a route below is the page's own slug (e.g. `hello-world`);
31
30
  `<Type>` families using two-layer builders route supplementary schema
32
31
  through the `schema:` frontmatter override — see this skill's
33
- [Adding schema to an existing page](../SKILL.md#adding-schema-to-an-existing-page) section, or `packages/schema/README.md` for the full
34
- override contract.
32
+ [Adding schema to an existing page](../SKILL.md#adding-schema-to-an-existing-page) section, or the installed `@working-theory/schema`
33
+ package's README for the full override contract.
35
34
 
36
35
  ## Core
37
36