@everystack/mcp 0.3.0 → 0.3.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.
package/dist/index.cjs CHANGED
@@ -23053,7 +23053,9 @@ function registerClaudeMdPrompt(server) {
23053
23053
  ' hand-written migrations, "pass your Drizzle schema") instead of the v3 Model flow',
23054
23054
  " (`defineModel` \u2192 `everystack db:generate`)? Suggest the current conventions.",
23055
23055
  "2. **Project drift** \u2014 do the Structure / Commands / package list match what is actually",
23056
- " installed now (new packages, a new tier, a new models/ dir)? Suggest updates.",
23056
+ " installed now (new packages, a new tier, a new models/ dir)? Suggest updates. Also",
23057
+ " check the operations manual: if docs/RUNBOOK.md is missing, or stale per",
23058
+ " `everystack runbook --check`, suggest the `runbook` prompt.",
23057
23059
  "3. **Contract-vs-gates drift** \u2014 is it missing any Non-negotiable the cheat gates enforce",
23058
23060
  " (data\u2192DB, generated migrations, declared authz, reuse @everystack/ui, secrets boundary)?",
23059
23061
  " Suggest adding it, so the human contract and the enforced rules agree.",
@@ -23078,6 +23080,73 @@ function registerClaudeMdPrompt(server) {
23078
23080
  );
23079
23081
  }
23080
23082
 
23083
+ // src/prompts/runbook.ts
23084
+ function registerRunbookPrompt(server) {
23085
+ server.prompt(
23086
+ "runbook",
23087
+ "Generate or refresh docs/RUNBOOK.md \u2014 the operations manual compiled from the app's detected reality (tier, Models, handlers). Runs `everystack runbook`, then fills empty slots with app narrative (confirm-first). Regenerate after the app grows or an everystack upgrade.",
23088
+ {
23089
+ projectPath: external_exports.string().optional().describe("Absolute path to the project root (where docs/RUNBOOK.md lives)")
23090
+ },
23091
+ async ({ projectPath }) => {
23092
+ const root = projectPath ?? ".";
23093
+ return {
23094
+ messages: [
23095
+ {
23096
+ role: "user",
23097
+ content: {
23098
+ type: "text",
23099
+ text: [
23100
+ `Generate or refresh docs/RUNBOOK.md for the project at ${root}.`,
23101
+ "",
23102
+ "## What this is",
23103
+ "",
23104
+ "docs/RUNBOOK.md is the per-app operations manual \u2014 how to configure, extend, deploy,",
23105
+ "monitor, and maintain THIS app. It is COMPILED, not authored: `everystack runbook`",
23106
+ "derives it from the app's detected reality (installed packages \u2192 tier, Models,",
23107
+ "handlers, crons) and regenerating after a change diffs in what's new. The division",
23108
+ "of labor: CLAUDE.md is the terse contract (rules); the runbook is procedures.",
23109
+ "",
23110
+ "## Step 1 \u2014 run the compiler",
23111
+ "",
23112
+ `- If ${root}/docs/RUNBOOK.md exists, run \`everystack runbook --diff\` first and show`,
23113
+ " the human which sections would change.",
23114
+ "- Then run `everystack runbook` to write it. If it reports hand-edited generated",
23115
+ " sections (a conflict), do NOT reach for --force \u2014 help the human move those words",
23116
+ " into a slot or the Notes section first, then regenerate. --force only with their",
23117
+ " explicit ok.",
23118
+ "",
23119
+ "## Step 2 \u2014 fill the EMPTY slots (and only the slots)",
23120
+ "",
23121
+ "The document has two kinds of content, mechanically marked:",
23122
+ "- `<!-- es:gen section=... -->` blocks belong to the compiler. NEVER write inside one \u2014",
23123
+ " your words would be overwritten on the next regeneration, and the hash check flags it.",
23124
+ "- `<!-- es:slot name=... -->` blocks are the human/agent seam and survive every",
23125
+ " regeneration. A slot still holding its `_(Fill in: ...)_` placeholder is empty.",
23126
+ "",
23127
+ "For each empty slot, draft content from what you know of the project:",
23128
+ "- `overview` \u2014 what the app is, who it serves, what an operator should know first.",
23129
+ "- `stage-notes` \u2014 deployed URLs per stage, channel-to-stage mapping, release cadence",
23130
+ " (read `.sst/outputs.json` or ask; do not guess URLs).",
23131
+ "- `notes` \u2014 anything project-specific that fits nowhere else. Leave it if nothing real.",
23132
+ "",
23133
+ "Show the human your draft slot content and let them approve before writing \u2014 the",
23134
+ "runbook is theirs; you assist, you do not own it.",
23135
+ "",
23136
+ "## Step 3 \u2014 verify",
23137
+ "",
23138
+ "Run `everystack runbook --check`: it must exit clean (slot edits never make it stale).",
23139
+ "Tell the human: regenerate any time with `everystack runbook`; CI can enforce currency",
23140
+ "with `--check`; after an everystack upgrade the diff reads as release notes for this app."
23141
+ ].join("\n")
23142
+ }
23143
+ }
23144
+ ]
23145
+ };
23146
+ }
23147
+ );
23148
+ }
23149
+
23081
23150
  // src/prompts/index.ts
23082
23151
  function registerPrompts(server) {
23083
23152
  registerNewAppPrompt(server);
@@ -23088,6 +23157,7 @@ function registerPrompts(server) {
23088
23157
  registerSecurePrompt(server);
23089
23158
  registerGovernanceSetupPrompt(server);
23090
23159
  registerClaudeMdPrompt(server);
23160
+ registerRunbookPrompt(server);
23091
23161
  }
23092
23162
 
23093
23163
  // src/governance/grounding.ts
@@ -23341,9 +23411,9 @@ var handWrittenMigration = {
23341
23411
  id: "hand-written-migration",
23342
23412
  tier: "framework",
23343
23413
  severity: "deny",
23344
- guide: "Schema and migrations are generated from your Models \u2014 edit the Model and run db:generate, never hand-write SQL migrations or edit the generated schema.",
23345
- conform: "everystack db:generate",
23346
- verify: "everystack db:generate produces no diff (a clean no-op)",
23414
+ guide: "Schema changes have two homes, neither is a hand-written migration: tables/constraints/authz are generated from your Models (edit the Model, run db:generate); functions, views, and matviews are authored in db/sql/ and DEPLOYED with db:reconcile \u2014 no migration file either way.",
23415
+ conform: "everystack db:generate (tables) \xB7 everystack db:reconcile (functions/views/matviews in db/sql)",
23416
+ verify: "everystack db:generate produces no diff AND everystack db:reconcile --check exits 0",
23347
23417
  detect(ctx) {
23348
23418
  if (ctx.tool !== "Write" && ctx.tool !== "Edit") return null;
23349
23419
  const p = ctx.filePath;
@@ -23635,7 +23705,7 @@ async function runGovernanceCli(argv) {
23635
23705
  }
23636
23706
 
23637
23707
  // src/index.ts
23638
- var version2 = (true ? "0.3.0" : null) ?? "0.3.0-dev";
23708
+ var version2 = (true ? "0.3.2" : null) ?? "0.3.0-dev";
23639
23709
  var INSTRUCTIONS = [
23640
23710
  "You govern how any agent builds everystack \u2014 a self-hosted application stack for Expo apps on AWS.",
23641
23711
  "Your job is not only to advise but to keep the build on-script: the architecture the maintainer",
@@ -23697,7 +23767,7 @@ var INSTRUCTIONS = [
23697
23767
  "1. Read everystack://core for architecture and conventions.",
23698
23768
  "2. Read everystack://security before any deployment or auth guidance.",
23699
23769
  "3. Load detail resources on demand when the user asks about specific features.",
23700
- "4. Data lives in PostgreSQL via Models/Modules and is served through the API \u2014 never bundle large computed data into the app. Schema changes go through generated migrations (`db:generate`), never hand-written DDL. Reuse `@everystack/ui` components; never put secret values behind `EXPO_PUBLIC_*`.",
23770
+ "4. Data lives in PostgreSQL via Models/Modules and is served through the API \u2014 never bundle large computed data into the app. Schema changes have two homes: tables/authz are generated from Models (`db:generate`); functions, views, and matviews are authored in `db/sql/` and deployed with `db:reconcile` \u2014 never a hand-written migration either way. Reuse `@everystack/ui` components; never put secret values behind `EXPO_PUBLIC_*`.",
23701
23771
  '5. When the user wants to start a new project, run check_environment (phase "local" for dev, "deploy" for deployment) to verify prerequisites.',
23702
23772
  "6. When the user needs to interact with deployed infrastructure, guide them to use the everystack CLI."
23703
23773
  ].join("\n");
@@ -19,9 +19,12 @@ These are enforced (everystack cheat gates) and load-bearing. Do not work around
19
19
  - **Data lives in PostgreSQL, served through the API — never bundle data into the app.** A
20
20
  large `.json`/`.csv` of computed data in the bundle is wrong; model it and serve it, or
21
21
  render an empty state if it does not exist yet.
22
- - **Schema and migrations are generated from Models.** Declare tables with `defineModel`
23
- (in `models/`), run `everystack db:generate`. Never hand-write a SQL migration, never edit
24
- the generated `db/schema.ts`. After any change, `db:generate` must be a clean no-op.
22
+ - **Schema changes have two homes; neither is a hand-written migration.** Tables and authz
23
+ are generated from Models: declare with `defineModel` (in `db/models/`), run
24
+ `everystack db:generate` never hand-write a SQL migration, never edit the generated
25
+ `db/schema.ts`; after any change `db:generate` must be a clean no-op. Functions, views,
26
+ and matviews are **authored** in `db/sql/` and **deployed** with `everystack db:reconcile`
27
+ — edit the SQL file, reconcile, done; `db:reconcile --check` must exit 0.
25
28
  - **Authorization is declared, not hand-written.** Use `can()` abilities on the Model; they
26
29
  compile to RLS + grants. Never hand-write `CREATE POLICY`/`GRANT`. RLS is required.
27
30
  - **Reuse `@everystack/ui`.** Do not hand-roll a component that already exists there. Style
@@ -32,12 +35,14 @@ These are enforced (everystack cheat gates) and load-bearing. Do not work around
32
35
 
33
36
  ## Start Here
34
37
 
35
- - `models/` — `defineModel` tables (the source of truth for schema + authz)
38
+ - `db/models/` — `defineModel` tables (the source of truth for schema + authz)
39
+ - `db/sql/` — functions, views, matviews (authored SQL; deploys via `db:reconcile`)
36
40
  - `app/` — Expo Router pages (screens, navigation, API routes)
37
41
  - `server/` — Lambda handlers (api.ts, worker.ts, image.ts)
38
- - `db/` — generated Drizzle schema + migrations (do not edit by hand)
42
+ - `db/schema.generated.ts`, `drizzle/` — generated artifacts (do not edit by hand)
39
43
  - `lib/` — shared code (auth context, API client)
40
44
  - `sst.config.ts` — AWS infrastructure definition
45
+ - `docs/RUNBOOK.md` — how to operate this app; regenerate with `everystack runbook`
41
46
 
42
47
  ## Structure
43
48
 
@@ -50,6 +55,7 @@ pnpm install # Install dependencies
50
55
  pnpm dev # Start the Expo dev server
51
56
  pnpm test # Run all tests (TDD)
52
57
  everystack db:generate # Models → next migration (data + authz)
58
+ everystack db:reconcile --apply # Deploy functions/views/matviews from db/sql (no migrations)
53
59
  everystack db:migrate # Apply migrations on the deployed Lambda
54
60
  everystack db:seed # Seed the database (dev only)
55
61
  everystack deploy --stage dev # Deploy infrastructure (SST)
@@ -66,7 +72,9 @@ Declare tables with `defineModel` (`field`, `can`, relations). A package's full
66
72
  `defineModule`; the app composes Modules. `everystack db:generate` compiles them to one
67
73
  migration (schema + RLS + grants); `deriveHandlerConfig(models)` derives the API config. You
68
74
  never hand-write migrations, RLS, or handler access-control — they are derived, so they cannot
69
- drift.
75
+ drift. The derived layer (functions, views, matviews) is the exception that proves the rule:
76
+ that SQL is authored, in `db/sql/`, and *deployed* with `db:reconcile` — hand-edits straight
77
+ against the database surface as drift, and a comment-only edit is a no-op.
70
78
 
71
79
  ### Security over all else
72
80
 
@@ -95,7 +103,8 @@ Every feature starts with a failing test. Tests in `__tests__/` mirroring source
95
103
  ## What NOT to Do
96
104
 
97
105
  - Don't bundle large data into the app — it lives in the DB, served by the API.
98
- - Don't hand-write migrations or edit `db/schema.ts` — edit the Model, run `db:generate`.
106
+ - Don't hand-write migrations or edit `db/schema.ts` — edit the Model, run `db:generate`;
107
+ for functions/views/matviews edit `db/sql/` and run `db:reconcile`.
99
108
  - Don't hand-write RLS — declare `can()` abilities.
100
109
  - Don't hand-roll a component that exists in `@everystack/ui`; don't use inline `StyleSheet`.
101
110
  - Don't put a secret behind `EXPO_PUBLIC_*` — that ships to the client.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@everystack/mcp",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Governance layer that governs how any agent builds everystack — grounding, cheat gates, and Model-aware tooling over MCP",
5
5
  "license": "AGPL-3.0-only",
6
6
  "author": "Scalable Technology, Inc. <licensing@scalable.technology>",
@@ -40,8 +40,8 @@
40
40
  "tsx": "4.21.0",
41
41
  "typescript": "5.9.3",
42
42
  "zod": "3.25.67",
43
- "@everystack/cli": "0.3.6",
44
- "@everystack/model": "0.3.3"
43
+ "@everystack/cli": "0.3.14",
44
+ "@everystack/model": "0.3.4"
45
45
  },
46
46
  "scripts": {
47
47
  "test": "jest",
@@ -5,6 +5,10 @@
5
5
  * (`db:generate`). A hand-written `.sql` migration or a hand-edit to the generated
6
6
  * `db/schema.ts` drifts the database from the Models — the migration the CLI would
7
7
  * write next is no longer a clean no-op. Pure path check; no IO.
8
+ *
9
+ * Note the layer split: SQL under `db/sql/` is the DERIVED layer (functions,
10
+ * views, matviews) and is legitimately authored — it deploys via `db:reconcile`,
11
+ * not through migrations, so this gate deliberately does not match it.
8
12
  */
9
13
 
10
14
  import { relative } from 'path';
@@ -28,9 +32,9 @@ export const handWrittenMigration: CheatGate = {
28
32
  tier: 'framework',
29
33
  severity: 'deny',
30
34
  guide:
31
- 'Schema and migrations are generated from your Models edit the Model and run db:generate, never hand-write SQL migrations or edit the generated schema.',
32
- conform: 'everystack db:generate',
33
- verify: 'everystack db:generate produces no diff (a clean no-op)',
35
+ 'Schema changes have two homes, neither is a hand-written migration: tables/constraints/authz are generated from your Models (edit the Model, run db:generate); functions, views, and matviews are authored in db/sql/ and DEPLOYED with db:reconcile — no migration file either way.',
36
+ conform: 'everystack db:generate (tables) · everystack db:reconcile (functions/views/matviews in db/sql)',
37
+ verify: 'everystack db:generate produces no diff AND everystack db:reconcile --check exits 0',
34
38
  detect(ctx: ToolCallContext): string | null {
35
39
  if (ctx.tool !== 'Write' && ctx.tool !== 'Edit') return null;
36
40
  const p = ctx.filePath;
package/src/index.ts CHANGED
@@ -71,7 +71,7 @@ const INSTRUCTIONS = [
71
71
  '1. Read everystack://core for architecture and conventions.',
72
72
  '2. Read everystack://security before any deployment or auth guidance.',
73
73
  '3. Load detail resources on demand when the user asks about specific features.',
74
- '4. Data lives in PostgreSQL via Models/Modules and is served through the API — never bundle large computed data into the app. Schema changes go through generated migrations (`db:generate`), never hand-written DDL. Reuse `@everystack/ui` components; never put secret values behind `EXPO_PUBLIC_*`.',
74
+ '4. Data lives in PostgreSQL via Models/Modules and is served through the API — never bundle large computed data into the app. Schema changes have two homes: tables/authz are generated from Models (`db:generate`); functions, views, and matviews are authored in `db/sql/` and deployed with `db:reconcile` — never a hand-written migration either way. Reuse `@everystack/ui` components; never put secret values behind `EXPO_PUBLIC_*`.',
75
75
  '5. When the user wants to start a new project, run check_environment (phase "local" for dev, "deploy" for deployment) to verify prerequisites.',
76
76
  '6. When the user needs to interact with deployed infrastructure, guide them to use the everystack CLI.',
77
77
  ].join('\n');
@@ -64,7 +64,9 @@ export function registerClaudeMdPrompt(server: McpServer): void {
64
64
  ' hand-written migrations, "pass your Drizzle schema") instead of the v3 Model flow',
65
65
  ' (`defineModel` → `everystack db:generate`)? Suggest the current conventions.',
66
66
  '2. **Project drift** — do the Structure / Commands / package list match what is actually',
67
- ' installed now (new packages, a new tier, a new models/ dir)? Suggest updates.',
67
+ ' installed now (new packages, a new tier, a new models/ dir)? Suggest updates. Also',
68
+ ' check the operations manual: if docs/RUNBOOK.md is missing, or stale per',
69
+ ' `everystack runbook --check`, suggest the `runbook` prompt.',
68
70
  '3. **Contract-vs-gates drift** — is it missing any Non-negotiable the cheat gates enforce',
69
71
  ' (data→DB, generated migrations, declared authz, reuse @everystack/ui, secrets boundary)?',
70
72
  ' Suggest adding it, so the human contract and the enforced rules agree.',
@@ -7,6 +7,7 @@ import { registerDebugPrompt } from './debug.js';
7
7
  import { registerSecurePrompt } from './secure.js';
8
8
  import { registerGovernanceSetupPrompt } from './governance-setup.js';
9
9
  import { registerClaudeMdPrompt } from './claude-md.js';
10
+ import { registerRunbookPrompt } from './runbook.js';
10
11
 
11
12
  export function registerPrompts(server: McpServer): void {
12
13
  registerNewAppPrompt(server);
@@ -17,4 +18,5 @@ export function registerPrompts(server: McpServer): void {
17
18
  registerSecurePrompt(server);
18
19
  registerGovernanceSetupPrompt(server);
19
20
  registerClaudeMdPrompt(server);
21
+ registerRunbookPrompt(server);
20
22
  }
@@ -0,0 +1,77 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod';
3
+
4
+ /**
5
+ * `runbook` — generate or refresh docs/RUNBOOK.md, the per-app operations manual.
6
+ *
7
+ * The compiler lives in the CLI (`everystack runbook` — db:generate for docs:
8
+ * detection → sections keyed by the app's reality → es:gen/es:slot merge). This
9
+ * prompt is the thin agent layer on top: run the compiler, then fill the EMPTY
10
+ * slots with app-specific narrative the compiler cannot know. Generated blocks
11
+ * belong to the compiler — the agent never writes inside them.
12
+ */
13
+ export function registerRunbookPrompt(server: McpServer): void {
14
+ server.prompt(
15
+ 'runbook',
16
+ 'Generate or refresh docs/RUNBOOK.md — the operations manual compiled from the app\'s detected reality (tier, Models, handlers). Runs `everystack runbook`, then fills empty slots with app narrative (confirm-first). Regenerate after the app grows or an everystack upgrade.',
17
+ {
18
+ projectPath: z.string().optional().describe('Absolute path to the project root (where docs/RUNBOOK.md lives)'),
19
+ },
20
+ async ({ projectPath }) => {
21
+ const root = projectPath ?? '.';
22
+ return {
23
+ messages: [
24
+ {
25
+ role: 'user' as const,
26
+ content: {
27
+ type: 'text' as const,
28
+ text: [
29
+ `Generate or refresh docs/RUNBOOK.md for the project at ${root}.`,
30
+ '',
31
+ '## What this is',
32
+ '',
33
+ 'docs/RUNBOOK.md is the per-app operations manual — how to configure, extend, deploy,',
34
+ 'monitor, and maintain THIS app. It is COMPILED, not authored: `everystack runbook`',
35
+ 'derives it from the app\'s detected reality (installed packages → tier, Models,',
36
+ 'handlers, crons) and regenerating after a change diffs in what\'s new. The division',
37
+ 'of labor: CLAUDE.md is the terse contract (rules); the runbook is procedures.',
38
+ '',
39
+ '## Step 1 — run the compiler',
40
+ '',
41
+ `- If ${root}/docs/RUNBOOK.md exists, run \`everystack runbook --diff\` first and show`,
42
+ ' the human which sections would change.',
43
+ '- Then run `everystack runbook` to write it. If it reports hand-edited generated',
44
+ ' sections (a conflict), do NOT reach for --force — help the human move those words',
45
+ ' into a slot or the Notes section first, then regenerate. --force only with their',
46
+ ' explicit ok.',
47
+ '',
48
+ '## Step 2 — fill the EMPTY slots (and only the slots)',
49
+ '',
50
+ 'The document has two kinds of content, mechanically marked:',
51
+ '- `<!-- es:gen section=... -->` blocks belong to the compiler. NEVER write inside one —',
52
+ ' your words would be overwritten on the next regeneration, and the hash check flags it.',
53
+ '- `<!-- es:slot name=... -->` blocks are the human/agent seam and survive every',
54
+ ' regeneration. A slot still holding its `_(Fill in: ...)_` placeholder is empty.',
55
+ '',
56
+ 'For each empty slot, draft content from what you know of the project:',
57
+ '- `overview` — what the app is, who it serves, what an operator should know first.',
58
+ '- `stage-notes` — deployed URLs per stage, channel-to-stage mapping, release cadence',
59
+ ' (read `.sst/outputs.json` or ask; do not guess URLs).',
60
+ '- `notes` — anything project-specific that fits nowhere else. Leave it if nothing real.',
61
+ '',
62
+ 'Show the human your draft slot content and let them approve before writing — the',
63
+ 'runbook is theirs; you assist, you do not own it.',
64
+ '',
65
+ '## Step 3 — verify',
66
+ '',
67
+ 'Run `everystack runbook --check`: it must exit clean (slot edits never make it stale).',
68
+ 'Tell the human: regenerate any time with `everystack runbook`; CI can enforce currency',
69
+ 'with `--check`; after an everystack upgrade the diff reads as release notes for this app.',
70
+ ].join('\n'),
71
+ },
72
+ },
73
+ ],
74
+ };
75
+ },
76
+ );
77
+ }
@@ -19,9 +19,12 @@ These are enforced (everystack cheat gates) and load-bearing. Do not work around
19
19
  - **Data lives in PostgreSQL, served through the API — never bundle data into the app.** A
20
20
  large `.json`/`.csv` of computed data in the bundle is wrong; model it and serve it, or
21
21
  render an empty state if it does not exist yet.
22
- - **Schema and migrations are generated from Models.** Declare tables with `defineModel`
23
- (in `models/`), run `everystack db:generate`. Never hand-write a SQL migration, never edit
24
- the generated `db/schema.ts`. After any change, `db:generate` must be a clean no-op.
22
+ - **Schema changes have two homes; neither is a hand-written migration.** Tables and authz
23
+ are generated from Models: declare with `defineModel` (in `db/models/`), run
24
+ `everystack db:generate` never hand-write a SQL migration, never edit the generated
25
+ `db/schema.ts`; after any change `db:generate` must be a clean no-op. Functions, views,
26
+ and matviews are **authored** in `db/sql/` and **deployed** with `everystack db:reconcile`
27
+ — edit the SQL file, reconcile, done; `db:reconcile --check` must exit 0.
25
28
  - **Authorization is declared, not hand-written.** Use `can()` abilities on the Model; they
26
29
  compile to RLS + grants. Never hand-write `CREATE POLICY`/`GRANT`. RLS is required.
27
30
  - **Reuse `@everystack/ui`.** Do not hand-roll a component that already exists there. Style
@@ -32,12 +35,14 @@ These are enforced (everystack cheat gates) and load-bearing. Do not work around
32
35
 
33
36
  ## Start Here
34
37
 
35
- - `models/` — `defineModel` tables (the source of truth for schema + authz)
38
+ - `db/models/` — `defineModel` tables (the source of truth for schema + authz)
39
+ - `db/sql/` — functions, views, matviews (authored SQL; deploys via `db:reconcile`)
36
40
  - `app/` — Expo Router pages (screens, navigation, API routes)
37
41
  - `server/` — Lambda handlers (api.ts, worker.ts, image.ts)
38
- - `db/` — generated Drizzle schema + migrations (do not edit by hand)
42
+ - `db/schema.generated.ts`, `drizzle/` — generated artifacts (do not edit by hand)
39
43
  - `lib/` — shared code (auth context, API client)
40
44
  - `sst.config.ts` — AWS infrastructure definition
45
+ - `docs/RUNBOOK.md` — how to operate this app; regenerate with `everystack runbook`
41
46
 
42
47
  ## Structure
43
48
 
@@ -50,6 +55,7 @@ pnpm install # Install dependencies
50
55
  pnpm dev # Start the Expo dev server
51
56
  pnpm test # Run all tests (TDD)
52
57
  everystack db:generate # Models → next migration (data + authz)
58
+ everystack db:reconcile --apply # Deploy functions/views/matviews from db/sql (no migrations)
53
59
  everystack db:migrate # Apply migrations on the deployed Lambda
54
60
  everystack db:seed # Seed the database (dev only)
55
61
  everystack deploy --stage dev # Deploy infrastructure (SST)
@@ -66,7 +72,9 @@ Declare tables with `defineModel` (`field`, `can`, relations). A package's full
66
72
  `defineModule`; the app composes Modules. `everystack db:generate` compiles them to one
67
73
  migration (schema + RLS + grants); `deriveHandlerConfig(models)` derives the API config. You
68
74
  never hand-write migrations, RLS, or handler access-control — they are derived, so they cannot
69
- drift.
75
+ drift. The derived layer (functions, views, matviews) is the exception that proves the rule:
76
+ that SQL is authored, in `db/sql/`, and *deployed* with `db:reconcile` — hand-edits straight
77
+ against the database surface as drift, and a comment-only edit is a no-op.
70
78
 
71
79
  ### Security over all else
72
80
 
@@ -95,7 +103,8 @@ Every feature starts with a failing test. Tests in `__tests__/` mirroring source
95
103
  ## What NOT to Do
96
104
 
97
105
  - Don't bundle large data into the app — it lives in the DB, served by the API.
98
- - Don't hand-write migrations or edit `db/schema.ts` — edit the Model, run `db:generate`.
106
+ - Don't hand-write migrations or edit `db/schema.ts` — edit the Model, run `db:generate`;
107
+ for functions/views/matviews edit `db/sql/` and run `db:reconcile`.
99
108
  - Don't hand-write RLS — declare `can()` abilities.
100
109
  - Don't hand-roll a component that exists in `@everystack/ui`; don't use inline `StyleSheet`.
101
110
  - Don't put a secret behind `EXPO_PUBLIC_*` — that ships to the client.