@pikku/skills 0.12.52 → 0.12.55

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 (112) hide show
  1. package/README.md +1 -1
  2. package/dist/skills.gen.js +2 -2
  3. package/dist/snippets.js +1 -1
  4. package/package.json +1 -1
  5. package/skills/pikku-a11y/SKILL.md +22 -15
  6. package/skills/pikku-addon/SKILL.md +5 -5
  7. package/skills/pikku-addon/references/addon-package-manifest.md +7 -0
  8. package/skills/pikku-addon/references/openapi.md +11 -0
  9. package/skills/pikku-agent/SKILL.md +6 -6
  10. package/skills/pikku-agent/references/agents.md +8 -1
  11. package/skills/pikku-agent/references/runner-vercel.md +2 -2
  12. package/skills/pikku-agent/references/voice.md +7 -1
  13. package/skills/pikku-architect/SKILL.md +2 -2
  14. package/skills/pikku-architect/references/plan-defects.md +9 -7
  15. package/skills/pikku-auth/SKILL.md +15 -36
  16. package/skills/pikku-auth/references/better-auth.md +106 -133
  17. package/skills/pikku-auth/references/jose.md +6 -0
  18. package/skills/pikku-auth/references/machine-auth.md +6 -0
  19. package/skills/pikku-auth/references/sessions.md +6 -0
  20. package/skills/pikku-build/SKILL.md +37 -34
  21. package/skills/pikku-build/references/app.md +113 -99
  22. package/skills/pikku-build/references/design.md +43 -31
  23. package/skills/pikku-build/references/feature.md +17 -3
  24. package/skills/pikku-build/references/mocks.md +29 -0
  25. package/skills/pikku-build/references/multi-app.md +25 -18
  26. package/skills/pikku-build/references/native-app.md +9 -0
  27. package/skills/pikku-build/references/openapi.md +41 -34
  28. package/skills/pikku-build/references/platform.md +23 -14
  29. package/skills/pikku-build/references/post-clone.md +1 -1
  30. package/skills/pikku-build/references/quick.md +76 -39
  31. package/skills/pikku-build/references/scenarios.md +28 -16
  32. package/skills/pikku-build/references/ship.md +19 -16
  33. package/skills/pikku-build/references/theming.md +76 -127
  34. package/skills/pikku-changes/SKILL.md +7 -10
  35. package/skills/pikku-concepts/SKILL.md +34 -44
  36. package/skills/pikku-concepts/references/concept-mapping.md +18 -0
  37. package/skills/pikku-concepts/references/language.md +6 -6
  38. package/skills/pikku-convert-screen/SKILL.md +45 -0
  39. package/skills/pikku-deploy/references/cloudflare.md +8 -0
  40. package/skills/pikku-deploy/references/lambda.md +8 -0
  41. package/skills/pikku-deploy/references/nextjs.md +1 -1
  42. package/skills/pikku-deploy/references/uws.md +1 -1
  43. package/skills/pikku-deploy/references/ws.md +3 -3
  44. package/skills/pikku-emails/SKILL.md +3 -9
  45. package/skills/pikku-guide/SKILL.md +28 -27
  46. package/skills/pikku-i18n/SKILL.md +7 -7
  47. package/skills/pikku-i18n/references/enum-labels.md +9 -0
  48. package/skills/pikku-i18n/references/messages.md +21 -9
  49. package/skills/pikku-i18n/references/rtl.md +18 -38
  50. package/skills/pikku-knowledge/SKILL.md +12 -13
  51. package/skills/pikku-kysely/SKILL.md +3 -21
  52. package/skills/pikku-list-query/SKILL.md +2 -2
  53. package/skills/pikku-meta/references/audit.md +10 -1
  54. package/skills/pikku-meta/references/meta.md +6 -0
  55. package/skills/pikku-meta/references/versioning.md +10 -0
  56. package/skills/pikku-middleware/SKILL.md +7 -16
  57. package/skills/pikku-n8n-import/SKILL.md +9 -1
  58. package/skills/pikku-n8n-import/references/addon-mapping.md +6 -0
  59. package/skills/pikku-n8n-import/references/code-translation.md +7 -0
  60. package/skills/pikku-permissions/SKILL.md +41 -10
  61. package/skills/pikku-permissions/references/scopes.md +59 -0
  62. package/skills/pikku-react/SKILL.md +20 -22
  63. package/skills/pikku-react/references/client.md +2 -70
  64. package/skills/pikku-react/references/react-query.md +11 -0
  65. package/skills/pikku-react/references/workflows.md +11 -0
  66. package/skills/pikku-realtime/SKILL.md +9 -3
  67. package/skills/pikku-report/SKILL.md +17 -16
  68. package/skills/pikku-scenario/SKILL.md +72 -81
  69. package/skills/pikku-scenario/references/browser.md +5 -5
  70. package/skills/pikku-scenario/references/coverage.md +4 -4
  71. package/skills/pikku-scenario/references/steps.md +31 -30
  72. package/skills/pikku-scenario/references/{persona-run.md → virtual-user-run.md} +47 -42
  73. package/skills/pikku-scenario/references/virtual-users.md +114 -0
  74. package/skills/pikku-seo/SKILL.md +12 -16
  75. package/skills/pikku-service-backends/SKILL.md +0 -10
  76. package/skills/pikku-service-backends/references/aws.md +6 -0
  77. package/skills/pikku-service-backends/references/mongodb.md +7 -0
  78. package/skills/pikku-service-backends/references/redis.md +6 -0
  79. package/skills/pikku-services/references/audit-wire-service.md +2 -2
  80. package/skills/pikku-services/references/audit.md +10 -1
  81. package/skills/pikku-services/references/config.md +6 -0
  82. package/skills/pikku-services/references/services.md +9 -2
  83. package/skills/pikku-software-archaeology/SKILL.md +21 -27
  84. package/skills/pikku-software-archaeology/references/blueprint.schema.json +16 -16
  85. package/skills/pikku-software-archaeology/references/pikku-mapping.md +3 -3
  86. package/skills/pikku-software-archaeology/references/second-opinion.md +13 -1
  87. package/skills/pikku-tailwind/SKILL.md +111 -0
  88. package/skills/pikku-theme/SKILL.md +187 -0
  89. package/skills/pikku-theme/references/from-a-reference.md +44 -0
  90. package/skills/pikku-theme/references/presets.md +40 -0
  91. package/skills/pikku-ui/SKILL.md +41 -0
  92. package/skills/pikku-wiring/SKILL.md +13 -12
  93. package/skills/pikku-wiring/references/channel.md +7 -1
  94. package/skills/pikku-wiring/references/cli.md +7 -1
  95. package/skills/pikku-wiring/references/gateway-slack.md +6 -0
  96. package/skills/pikku-wiring/references/http.md +10 -3
  97. package/skills/pikku-wiring/references/mcp.md +8 -0
  98. package/skills/pikku-wiring/references/queue.md +6 -0
  99. package/skills/pikku-wiring/references/realtime.md +34 -4
  100. package/skills/pikku-wiring/references/rpc.md +6 -0
  101. package/skills/pikku-wiring/references/scheduler.md +6 -0
  102. package/skills/pikku-wiring/references/trigger.md +8 -0
  103. package/skills/pikku-workflow/SKILL.md +9 -7
  104. package/skills/pikku-admin-to-fabric/SKILL.md +0 -212
  105. package/skills/pikku-auth/references/permissions.md +0 -261
  106. package/skills/pikku-blueprint-to-fabric/SKILL.md +0 -377
  107. package/skills/pikku-blueprint-to-fabric/scripts/inventory.mjs +0 -367
  108. package/skills/pikku-fabric/SKILL.md +0 -619
  109. package/skills/pikku-fabric/references/debugging.md +0 -110
  110. package/skills/pikku-mantine/SKILL.md +0 -80
  111. package/skills/pikku-scenario/references/personas.md +0 -117
  112. package/skills/pikku-wiring/references/realtime-other-routes.md +0 -23
@@ -1,619 +0,0 @@
1
- ---
2
- name: pikku-fabric
3
- description: 'Build, convert and debug apps on the Pikku Fabric platform. Covers SQLite/libSQL database setup with Kysely, fabric project layout, deploy provider config, the optional `fabric.projectId` in `pikku.config.json`, the `pikku all` + `tsc` verification loop, and reading logs, traces and metrics from a deployed stage. TRIGGER when: user is working on a Fabric-hosted Pikku project, converting an app to Fabric format, asking about Fabric deployment, database or project conventions, asking about a `pikku fabric validate` finding including app-missing-actor-quick-login, or a deployed stage is erroring, timing out or behaving differently than local ("why is prod failing", "check the logs"). DO NOT TRIGGER when: user is working on a generic (non-Fabric) Pikku deployment — use pikku-deploy instead — or the failure reproduces locally, which is where to debug it.'
4
- installGroups: [fabric]
5
- ---
6
-
7
- # Pikku Fabric
8
-
9
- ## Agent Operating Procedure
10
-
11
- Use this skill as an execution checklist, not reference material.
12
-
13
- 1. **Run structural validation first.** Before any edit, run:
14
- ```bash
15
- pikku fabric validate --json
16
- ```
17
- This prints every missing file, misconfigured field, and dependency gap with a `fixHint`. Address all `error` findings before proceeding — they block deploy. Resolve `warn` findings before testing — they cause runtime failures. `info` findings are best-practice gaps that are safe to defer.
18
- 2. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
19
- 3. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
20
- 4. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
21
- 5. Validate with the narrowest relevant command first, then run `pikku all` when functions, wirings, schemas, or generated clients may have changed.
22
- 6. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
23
-
24
- Fabric is a serverless deployment platform for Pikku apps. Every Fabric app runs on Cloudflare Workers with a SQLite database (via libSQL/Turso). This skill covers what's unique to Fabric. For general Pikku concepts, function authoring, HTTP wiring, and more, see `pikku-concepts`, `pikku-wiring`, `pikku-services`, etc.
25
-
26
- ## Before you start
27
-
28
- Always run project discovery first:
29
-
30
- ```bash
31
- yarn pikku meta context --json
32
- ```
33
-
34
- Run `pikku meta` before grepping or editing a Fabric app.
35
-
36
- - `pikku meta context --json` for the project map: functions, wires, workflows, capabilities, and source files.
37
- - `pikku meta clients --json` before frontend/RPC work.
38
- - `pikku meta functions --json` to list function ids, then `pikku meta functions get <id> --json` for one function.
39
- - `pikku meta schemas --json` to list schema names. Only request a full schema body with `pikku meta schemas get <name> --json` when you need it.
40
-
41
- Do not load every schema body by default; that wastes context and usually makes the model worse.
42
-
43
- For database work:
44
-
45
- - Use `pikku fabric db schema [--branch <branch>]` for the actual attached Fabric database state: tables and columns.
46
- - Use `pikku meta schemas` for code-level JSON Schema contracts, not database introspection.
47
- - Do not inspect database credentials or connect to the database directly; Fabric already exposes the safe introspection surface.
48
-
49
- ## Database: SQLite via libSQL
50
-
51
- Fabric apps use SQLite, accessed via Kysely with the libSQL HTTP adapter. NOT PostgreSQL, NOT D1.
52
-
53
- ### Setup in `services.ts`
54
-
55
- ```typescript
56
- import { Kysely, CamelCasePlugin } from 'kysely'
57
- import { LibsqlWebDialect } from '@pikku/kysely-sqlite'
58
- import type { DB } from '#pikku/db/schema.gen.js'
59
-
60
- const databaseUrl = await variables.get('DATABASE_URL')
61
- let kysely: Kysely<DB>
62
- if (databaseUrl) {
63
- kysely = new Kysely<DB>({
64
- dialect: new LibsqlWebDialect({ url: databaseUrl }),
65
- plugins: [new CamelCasePlugin()],
66
- })
67
- } else if (existingServices?.kysely) {
68
- kysely = existingServices.kysely as Kysely<DB>
69
- } else {
70
- throw new Error('kysely not provided and DATABASE_URL is unset')
71
- }
72
- ```
73
-
74
- Fabric injects `DATABASE_URL` as a variable binding when the stage starts. In local dev, `pikku db migrate` uses a local `dev.db` SQLite file.
75
-
76
- ### Migrations
77
-
78
- Migrations are plain `.sql` files at the **project root**, in a directory named
79
- for the engine — `db/sqlite/` for SQLite/libSQL stages, `db/postgres/` for
80
- Postgres ones. Never `db/migrations/`, and never under `packages/functions/`:
81
- the deploy pipeline stages `db/<engine>/*.sql` from the root and applies them
82
- after upload, so a migration anywhere else is silently never run.
83
-
84
- ```
85
- db/sqlite/
86
- 0001-init.sql
87
- 0002-add-users.sql
88
- ```
89
-
90
- Numbers must be consecutive and gap-free, and an applied migration is frozen —
91
- correct a mistake with a new forward migration, never by editing or renaming one
92
- that has already run (the recorded hash will no longer match).
93
-
94
- **Forward-only rule.** Once a migration exists on the base branch (or any stage
95
- has applied it), never edit, rename or delete it — add a NEW numbered migration
96
- that makes the change. A stage records a migration by name and never re-runs it,
97
- so an edit never reaches a database that already applied it. Two guards enforce
98
- this:
99
-
100
- - `pikku fabric validate` reports `migration-modified-after-base-*` (error) for
101
- any `db/<engine>/*.sql` that exists on the base ref (default `origin/main`, else `main`, `origin/master`, `master`,
102
- compared at the branch's merge-base; override with `--migrations-base <ref>`
103
- or `PIKKU_MIGRATIONS_BASE`) but was modified, deleted or renamed in the working
104
- tree. New files are fine. It is skipped outside a git repo or with no base ref.
105
- In CI use a full clone (`fetch-depth: 0`) so the base ref exists.
106
- - `pikku fabric deploy apply` runs the migration-history checks first and
107
- refuses to create a deployment if any fail. It compares against the stage
108
- being deployed and the production (`main`) stage's applied ledger, and against
109
- the base ref — a branch stage can be reset at will, but main's history reaches
110
- production. Findings: `migration-applied-file-missing-*`, `migration-drift-*`,
111
- `migration-gap`, `migration-modified-after-base-*`. Unlike `validate`, a check
112
- that cannot run refuses too: an unreadable ledger (`migration-drift-unchecked`)
113
- or a base ref that does not resolve (`migration-base-unresolved`). There is no
114
- override flag — fix the history.
115
-
116
- Fix a finding by restoring the file (`git checkout origin/main -- db/sqlite/<file>`)
117
- and putting the change in a new migration.
118
-
119
- Run migrations: `pikku db migrate`. It also regenerates `.pikku/db/schema.gen.ts`
120
- (Kysely types) and `.pikku/db/zod.gen.ts` — there is no separate types step.
121
-
122
- **NEVER hand-edit the generated schema** — write a migration and re-run.
123
-
124
- ### Dev seed data
125
-
126
- Alongside the migrations sits `db/<engine>-dev-seed.sql` — `db/sqlite-dev-seed.sql`
127
- or `db/postgres-dev-seed.sql`. There is no seed command. `pikku db reset` is the
128
- only thing that applies it: wipe, migrate, seed. `--no-seed` stops after the
129
- migration, for working on an empty-state or onboarding flow the test data hides.
130
-
131
- Because reset always arrives at a database it has just wiped, **the seed file is
132
- plain `INSERT`s** — no `INSERT OR IGNORE`, no `ON CONFLICT DO NOTHING`, no
133
- `IF NOT EXISTS`. Nothing applies it twice, so it never has to defend itself. If
134
- you find yourself reaching for an idempotent form, that's a sign the data wants
135
- to be a migration instead.
136
-
137
- This is **local dev data only**: enough rows that a fresh dev database isn't an
138
- empty app. Nothing else ever runs it. A deployed stage applies `db/<engine>/*.sql`
139
- and stops there — the one exception is a disposable stage deployed with
140
- `pikku fabric deploy apply <branch> --reset` (see Deploy), which is never
141
- production. Local reset refuses `NODE_ENV=production` and refuses a database
142
- outside the runtime directory.
143
-
144
- So the test is not "is this row realistic?", it is **"would the app be broken
145
- without it in production?"** If yes, it is configuration and belongs in a
146
- migration, however much it looks like sample data. A venue and its rooms, a
147
- product catalogue, a tenant, a country list, the organization the whole
148
- deployment hangs off — all configuration. Accounts and role grants are
149
- provisioning: the fabric plugin's `personas`, or a migration. What is left
150
- over is the seed's job — the bookings, orders and messages a demo needs and a real
151
- environment starts without.
152
-
153
- Get this wrong and it hides: the app is perfect locally, where reset has just
154
- run, and every deployed environment comes up with empty tables. The signature is
155
- a stage whose pages return 200 — the shell renders fine — while its first data
156
- read throws `no result` or a foreign-key violation on a row the seed was
157
- silently supplying.
158
-
159
- A Better Auth app has a second constraint: the plugins you enable (`pikkuBan()`,
160
- `pikkuActor()`, …) each declare columns, and `pikku db migrate` refuses to run while
161
- the applied schema is missing any of them. `pikku db generate` writes the
162
- migration that closes the gap.
163
-
164
- ### Column conventions
165
-
166
- - Use `SERIAL`/`INTEGER PRIMARY KEY AUTOINCREMENT` for IDs
167
- - Use `TEXT` for strings, `INTEGER` for booleans (0/1) and timestamps (Unix ms)
168
- - Use `CHECK` constraints sparingly — prefer app-level validation
169
- - Table and column names: snake_case in SQL, camelCase in TypeScript (via `CamelCasePlugin`)
170
-
171
- ## Deploy Provider
172
-
173
- `pikku.config.json` (in the project root, not `packages/functions/`) **must** declare the Fabric deploy provider:
174
-
175
- ```json
176
- {
177
- "deploy": {
178
- "providers": {
179
- "cloudflare": "@pikkufabric/deploy-cloudflare"
180
- }
181
- }
182
- }
183
- ```
184
-
185
- Without this, `pikku deploy plan --provider cloudflare` uses the OSS adapter which lacks Fabric's workflow service wiring.
186
-
187
- The Fabric adapter automatically:
188
-
189
- - Injects `SQLiteKyselyWorkflowService` when `DATABASE_URL` is bound
190
- - Sets up the libSQL workflow queue
191
- - Wires `workflowQueues: true` for the scaffold
192
-
193
- No manual workflow service setup is needed.
194
-
195
- ## Project Layout
196
-
197
- ```
198
- packages/functions/
199
- src/
200
- functions/ # Business logic — one pikkuFunc/workflow per file
201
- wirings/ # Transport bindings
202
- *.http.ts # wireHTTP / defineHTTPRoutes / wireHTTPRoutes
203
- *.channel.ts # wireChannel
204
- *.queue.ts # wireQueueWorker
205
- *.schedule.ts # wireScheduler
206
- *.mcp.ts # wireMCPResource / wireMCPPrompt (an MCP tool is just a function with `mcp: true`)
207
- *.cli.ts # wireCLI
208
- services.ts # pikkuServices factory (singleton)
209
- middleware.ts # Shared middleware
210
- permissions.ts # Shared permissions
211
- .pikku/
212
- db/schema.gen.ts # Kysely types, written by `pikku db migrate` — NEVER hand-edit
213
- apps/app/ # Frontend(s)
214
- db/sqlite/ # Plain .sql migrations, numbered, gap-free (project root)
215
- db/sqlite-dev-seed.sql # Dev-only test data, applied by `pikku db reset`
216
- pikku.config.json # Pikku + deploy config, and the frontends (project root)
217
- ```
218
-
219
- ## How a checkout is linked to its Fabric project
220
-
221
- `fabric.projectId` in `pikku.config.json` names the project. It is optional. Order
222
- tried:
223
-
224
- 1. `FABRIC_PROJECT_ID` env var — CI and scripts.
225
- 2. `fabric.projectId` in `pikku.config.json`.
226
- 3. The git remote, matched against Fabric's projects. The id found is written
227
- into `pikku.config.json` so the lookup happens once. It is never committed
228
- for you; commit it or not. A deploy ignores a `pikku.config.json` whose only
229
- change is `fabric.projectId`. If two projects share one repo the CLI refuses; pick
230
- one with `FABRIC_PROJECT_ID=<projectId>`.
231
-
232
- `pikku fabric config` prints which project, api url and login the current
233
- checkout resolves to, and where each came from, and the project's settings.
234
- The settings Fabric needs that `pikku.config.json` does not describe are stored
235
- on the project, not in a file, and set with `key=value` arguments:
236
-
237
- ```bash
238
- pikku fabric config showcase.name="Watering Log" showcase.tags=voice,realtime
239
- pikku fabric config guide.docs=docs/guide guide.theme.primaryColor=teal
240
- pikku fabric config scenarios.env.STRIPE_MODE=test # the scenario run only
241
- pikku fabric config showcase.tint= # an empty value clears it
242
- ```
243
-
244
- The keys are `showcase.name` (≤60), `showcase.description` (≤160),
245
- `showcase.tags` (comma-separated, ≤6, from Fabric's fixed list),
246
- `showcase.tint` (`#rrggbb`), `guide.docs`, `guide.theme.primaryColor`,
247
- `guide.theme.fontFamily`, `guide.theme.headingFontFamily` and
248
- `scenarios.env.<NAME>`. Every assignment is checked before any is applied, so a
249
- refused one changes nothing. Whether the project appears on the public
250
- showcase is Fabric's decision, not a setting.
251
-
252
- `pikku fabric link` creates
253
- `origin` (with `--gitea`) if there is none, imports the project, writes
254
- `projectId`, and queues the first deploy; it commits and pushes nothing. A
255
- custom production domain is set with `pikku fabric domains add`. Production
256
- always maps to `main`; without a domain it lives on the platform
257
- `*.pikkufabric.app` hostnames.
258
-
259
- The apps are the `frontends` in `pikku.config.json`,
260
- the same list `pikku serve`, `pikku app` and native builds read, and
261
- `pikku fabric validate` and `smoke` read them from there:
262
-
263
- ```json
264
- "frontends": {
265
- "app": {
266
- "cwd": "apps/app",
267
- "primary": true,
268
- "deploy": true,
269
- "kind": "ssr",
270
- "dev": {
271
- "command": ["yarn", "dev"],
272
- "port": 7105,
273
- "healthPath": "/"
274
- }
275
- }
276
- }
277
- ```
278
-
279
- Each `frontends` entry declares a frontend app with its dev command and port.
280
-
281
- ## RPC is the default transport
282
-
283
- In Fabric apps, most features don't need HTTP wirings. Just write the function with `expose: true` — Pikku generates an RPC client and React Query hooks automatically.
284
-
285
- ```typescript
286
- export const listTasks = pikkuSessionlessFunc({
287
- expose: true,
288
- readonly: true,
289
- func: async ({ kysely }, {}) => {
290
- return { tasks: await kysely.selectFrom('tasks').selectAll().execute() }
291
- },
292
- })
293
- ```
294
-
295
- Add `wireHTTP` only when you need a specific REST shape (webhooks, third-party callers).
296
-
297
- ### Transport rule
298
-
299
- - Always use RPC first.
300
- - If the function should be callable from the app or other generated clients, prefer `expose: true`.
301
- - Use `expose: true` for public/generated client access unless the user explicitly wants a private function.
302
- - Do not add HTTP routes unless the user explicitly asks for HTTP/REST, or the project settings explicitly require HTTP transport.
303
- - Every new or changed function must have a real description.
304
- - If function metadata would show `missing description`, the work is not finished yet.
305
-
306
- ## Run it locally
307
-
308
- A Fabric app is two processes: the pikku API server (`:3000`) and the frontend
309
- (vite). The starter template's `bun run dev` starts **both** and takes the whole
310
- session down if either dies — a frontend running against a dead API looks like an
311
- app bug and is the single most common way to waste an hour here.
312
-
313
- ```bash
314
- bun run prebuild # pikku all — codegen must be current before the server boots
315
- bun run dev
316
- ```
317
-
318
- Then open the app, sign up as a real user, and click through what you built.
319
- **HTTP 200 is not evidence.** These are client-rendered pages: the server returns
320
- 200 with an empty shell, so a page whose component throws still looks fine to
321
- curl.
322
-
323
- That pass is a smoke check. Anything you would otherwise verify by hand-driving a
324
- browser tool belongs in a scenario's browser step, run with
325
- `pikku scenario run local --spawn --run browser` — a browser session you steered
326
- yourself proves nothing that re-runs.
327
-
328
- Secrets come from `process.env`, which the CLI populates from a `.env` in the
329
- working directory. `BETTER_AUTH_SECRET` is required — without it the first
330
- sign-up fails with `Requested secret not found`, which names no key and points at
331
- no file. The starter template generates one on first `bun run dev`.
332
-
333
- If you are running the two processes yourself rather than through the template's
334
- script, run `pikku dev` from the **project root** (it resolves `srcDirectories`
335
- relative to the config, so a nested cwd yields a doubled watch path and no hot
336
- reload).
337
-
338
- ## Reaching a model
339
-
340
- An agent needs an `agentRunner` in singleton services, and locally you do not
341
- write one: `pikku dev` builds it from env when it finds a **matching pair** —
342
- `OPENAI_BASE_URL` + `OPENAI_API_KEY`, or `LITELLM_PROXY_URL` + `LITELLM_API_KEY`
343
- — and registers it under `'*'`, so every `provider/model` prefix resolves
344
- through it. With neither pair complete it builds nothing and every agent call
345
- fails with `AIProviderNotConfiguredError` (a 503) — which reads like a broken
346
- agent rather than a missing key, so check `.env` first. Mixing halves is worse
347
- than missing them: a URL from one source with a key from the other 401s on every
348
- call, so the pairs are taken whole, OpenAI first.
349
-
350
- Two ways to fill them in:
351
-
352
- **The Fabric AI gateway.** One key, and every model the gateway fronts —
353
- OpenAI, Anthropic, Google, the OpenRouter catalogue — is reachable by id, billed
354
- through your Fabric account rather than per-vendor:
355
-
356
- ```bash
357
- pikku fabric login
358
- pikku fabric llm key --env >> .env # writes both pairs; --shell and --json also exist
359
- ```
360
-
361
- It mints or reuses a developer-scoped key against your Fabric login. `link` is
362
- not required — the key is yours, not the project's.
363
-
364
- **Your own vendor key.** `OPENAI_BASE_URL=https://api.openai.com/v1` with your
365
- `OPENAI_API_KEY`, and model ids are then only the ones that vendor serves.
366
-
367
- A deployed stage takes the same names through `pikku fabric secrets set` /
368
- `variables set` — the agent units get their runner wired by the bundler, from
369
- those values.
370
-
371
- ## Deploy
372
-
373
- ```bash
374
- pikku fabric login # opens a browser; needs a human, wait for it
375
- pikku fabric init https://github.com/<owner>/<repo>
376
- pikku fabric validate # must pass clean
377
- pikku fabric deploy apply --production -y
378
- ```
379
-
380
- `init` and `link` import into whichever organization your session is in. When
381
- you belong to several — a personal one and a company one, say — name the target
382
- with `--organization`, taking a slug, a display name or an id:
383
-
384
- ```bash
385
- pikku fabric link --organization vlandor
386
- ```
387
-
388
- You have to be a member of the organization you name, and its GitHub account
389
- has to be connected already: importing a `github.com/<owner>/<repo>` repo needs
390
- the Fabric GitHub App installed on `<owner>` _and_ linked to that organization,
391
- or the import refuses by name.
392
-
393
- The branch is positional and defaults to the checked-out one, and `-y` is the
394
- short form of `--auto-approve`, so a one-shot deploy is:
395
-
396
- ```bash
397
- pikku fabric deploy apply -y # the branch you are standing on
398
- pikku fabric deploy apply my-branch -y # a named one
399
- ```
400
-
401
- `-y` answers the prompts and nothing more. It does **not** approve migrations
402
- that drop or rewrite data — that stays `--allow-destructive`, typed out on
403
- purpose.
404
-
405
- ### Rebuilding a disposable stage: `--reset`
406
-
407
- A non-production stage whose migration history or schema has drifted (an app's
408
- `develop` branch) can be wiped and rebuilt in one deploy:
409
-
410
- ```bash
411
- pikku fabric deploy apply develop --reset # asks first, naming app + stage
412
- pikku fabric deploy apply develop --reset -y # prints the warning, skips the prompt
413
- ```
414
-
415
- It is the deployed counterpart of `pikku db reset`: **all data on that stage is
416
- deleted**, every migration is re-applied and `db/<engine>-dev-seed.sql` is
417
- loaded. It is refused for `--production`, for `main`, and with `--deployment-id`
418
- (it only applies to a deploy it creates). It needs a fabric server that reports
419
- the reset back on the deployment; against one that does not, the command fails
420
- naming the deployment it created without a reset, and wipes nothing. `-y` does
421
- not imply `--allow-destructive`.
422
-
423
- Inferring the branch is safe because the git safety check refuses any branch
424
- without an upstream or out of sync with it, so it cannot ship an unpushed
425
- commit; the branch it picked is printed before the build starts. A detached
426
- HEAD is refused by name rather than travelling on as a branch called `HEAD`.
427
-
428
- There is no `deploy plan` subcommand — `apply` runs the same auth, git-safety
429
- and ref resolution itself, and fabric produces the real plan server-side.
430
-
431
- `apply` confirms before deploying, and with no TTY to ask — CI, an agent shell —
432
- it refuses rather than hangs. `--auto-approve` (`-y`) supplies that confirmation;
433
- drop it only when a human is at a real terminal.
434
-
435
- `apply` waits for a terminal state and exits non-zero unless the deployment went
436
- live. `--detach` opts out — it queues the deploy, prints the deployment id and
437
- returns 0, which tells you nothing about whether it worked:
438
-
439
- | exit | meaning |
440
- | ---- | ----------------------------------------------------------------------- |
441
- | 0 | live (or queued, under `--detach`) |
442
- | 1 | the command could not run — not logged in, unsafe git state, bad flags |
443
- | 2 | the deployment failed, errored, timed out server-side, or was cancelled |
444
- | 3 | the deployment is blocked and nothing the CLI can do will unblock it |
445
- | 4 | the wait hit `--timeout` with the deployment still in flight |
446
-
447
- On a failure or timeout, `apply` prints the tail of the builder's own log (and
448
- carries `buildLog` / `imageBuildLog` on the `--json` result). Read it before
449
- touching code: `fabric logs` serves the running stage, not the build. When the
450
- builder recorded nothing, the CLI says so — that is usually fabric-side, so run
451
- `pikku fabric smoke` before assuming the project is broken.
452
-
453
- Fabric parks every deploy at a gate after the plan phase (`status: suspended`).
454
- Why it parked is the whole story, and it is `statusReason`, not `status`:
455
-
456
- - `awaiting_approval` — the plan is fine, a human has to publish it.
457
- `-y` does that; without it you get exit 3 and the command to run.
458
- One exception: if fabric marked any pending migration **destructive** — a
459
- drop, a truncate, a rewrite — `-y` alone declines and exits 3,
460
- because a standing yes was given before anyone knew the plan dropped a table.
461
- The CLI lists the migrations and fabric's reasons; `--allow-destructive`
462
- accepts them for that deploy, and `-y` implies it.
463
- - `needs_config` — a declared secret or variable has no value covering the
464
- stage. The CLI names them. `-y` will **not** force this through;
465
- set the values and re-attach — `pikku fabric secrets set <name>` for a
466
- declared secret, `pikku fabric variables set <name> --value <v>` for a declared
467
- variable. They are separate stores: a secret is sealed to the stage and cannot
468
- be read back, a variable is stored plainly and can (`variables get`). `set`
469
- reads the value as JSON when it parses, so `--value true` is the boolean on a
470
- stage exactly as it is from `.env`, and `--value '"true"'` is the string.
471
- - `needs_attention` — the plan is red. Nothing to approve.
472
-
473
- The wait defaults to a 900s ceiling; `--timeout <seconds>` moves it. On timeout
474
- it prints the deployment id and the re-attach command rather than lying about
475
- the outcome.
476
-
477
- Splitting kick-off from waiting across two CI jobs is the reason
478
- `--deployment-id` exists, and what `--detach` is for — the first job here has to
479
- return the id and exit rather than wait:
480
-
481
- ```bash
482
- id=$(pikku fabric deploy apply --production -y --detach --json | jq -r 'select(.event=="result").deploymentId')
483
- # …later, in another job…
484
- pikku fabric deploy apply --deployment-id "$id" -y
485
- ```
486
-
487
- `--deployment-id` skips the git safety check entirely (the deployment already
488
- pins a sha, and the checkout is allowed to have moved on) and refuses to be
489
- combined with a branch or `--production`, which would let the two disagree.
490
-
491
- Under `--json`, the wait emits one NDJSON event per line — `created`/`attached`,
492
- `status` on each transition, `blocked`, `approved` — and the last line is the
493
- terminal result object, tagged `"event": "result"`.
494
-
495
- `init` adopts a **GitHub** repo, and adoption goes through the Pikku Fabric
496
- GitHub App — the app has to be installed on the account or org that owns the
497
- repo, and if it is installed with "selected repositories" this one must be in
498
- the selection. There is no CLI flag that works around a missing installation:
499
- `init` returns "Connect the GitHub account '<owner>'". Send the user to install
500
- it, or create the project in the console instead (which provisions a Fabric-hosted
501
- git repo you push to) and clone it — the remote links the checkout, or put
502
- the id in `fabric.projectId` in `pikku.config.json`.
503
-
504
- Deploy refuses to run unless the target branch equals its upstream — the guard
505
- compares `main` against `main@{upstream}`. So the remote you pushed to must be
506
- the one the branch tracks; a stale `origin` left over from scaffolding blocks
507
- the deploy with "local HEAD … ≠ remote …" even though your code is pushed.
508
- `git branch --set-upstream-to=<remote>/main main` before deploying.
509
-
510
- ### The first user on a deployed stage
511
-
512
- When sign-up is off, the first account has to come from outside the app.
513
- `pikku fabric user add <email>` is the CLI form of the console's Add user:
514
-
515
- ```bash
516
- pikku fabric user add ada@example.com --name Ada # prompts; blank generates one
517
- pikku fabric user add ada@example.com --password '<pw>' -b staging
518
- ```
519
-
520
- It mints a short-lived operator token for the stage and calls the stage's own
521
- `admin:createUser`, so the stage must wire `@pikku/addon-admin` as `admin` —
522
- a 404 is refused by name and nothing is created. A generated password is printed
523
- once; one you passed is never echoed. With no TTY, pass `--password` or pipe it.
524
-
525
- ### Opening a private stage
526
-
527
- A non-production stage is private: without a link it answers "This preview is
528
- private". `pikku fabric stage link` prints the link that opens it:
529
-
530
- ```bash
531
- pikku fabric stage link access -b develop --route /login # use the stage
532
- pikku fabric stage link changes -b develop # use it with the changes panel
533
- pikku fabric stage visibility public -b develop # or: private
534
- ```
535
-
536
- A stage has one live link of each kind, so asking again returns the same one
537
- until it expires. A `changes` link turns the panel on first; if that needs a
538
- deploy, the command says so. `visibility public` opens the stage to anyone with
539
- its URL — hand out an `access` link instead when that is all you need.
540
-
541
- ## Versioning
542
-
543
- Functions with `expose: true` are versioned via `versions.pikku.json`. When you change a function's input or output schema, you must bump its version number — otherwise `pikku all` will report a breaking change and callers' generated clients become stale.
544
-
545
- `pikku all` catches this automatically.
546
-
547
- ## After every code change
548
-
549
- Run `pikku all` after modifying functions, wirings, or schemas, then `tsc --noEmit`:
550
-
551
- 1. `pikku all` — regenerates all codegen, checks version compliance
552
- 2. `tsc --noEmit` — validates TypeScript types
553
-
554
- Breaking changes are reported by the version check in step 1.
555
-
556
- ### `app-missing-actor-quick-login-<app>`
557
-
558
- The `fabric validate` finding people most often misread. It fires when an app has
559
- a **login screen** but no dev actor switcher, and it is not a style nit: a sandbox
560
- reviewer has no seed password, so without the control they are locked out of the
561
- app they were asked to look at.
562
-
563
- Satisfy it with `<DevActorSwitcher />` from `@pikku/mantine/dev`, or with your
564
- own UI built on `useDevActors()` or `signInAsPersona()` from `@pikku/react` —
565
- validate accepts any of those call sites as evidence, so custom rendering
566
- passes. Either way the server needs `personaSignIn` on `pikkuActor`; see
567
- **pikku-scenario** for it and **pikku-react** for the props.
568
-
569
- The validator also accepts the shapes that predate the package — a hand-rolled
570
- `signInAsActor()` or a literal `POST /auth/sign-in/actor` — so an older app does
571
- not fail the build. **Treat that as a grace period, not the target: migrate those
572
- to `<DevActorSwitcher />`.** They put a per-persona credential in the frontend
573
- bundle, which the persona endpoint exists to avoid.
574
-
575
- Do **not** satisfy it with Better Auth's `/dev/quick-login`. That is a different
576
- endpoint with a different purpose — one fixed admin, not the declared personas —
577
- and it does not clear this rule.
578
-
579
- ## Hard rules
580
-
581
- These apply in every Fabric app:
582
-
583
- - **No `process.env`** — use `variables.get('NAME')` and `secrets.getSecret('NAME')`. Declare with `defineVariable` / `defineSecret`.
584
- - **No `as any`** — fix types properly.
585
- - **No generic `Error`** — throw `NotFoundError`, `ConflictError`, `BadRequestError`, `UnauthorizedError` from `#pikku/error`.
586
- - **No auth checks in function bodies** — use `permissions:` field on the function config with a `pikkuPermission` factory.
587
- - **No hand-editing `.pikku/db/schema.gen.ts`** — write a migration and re-run `pikku db migrate`.
588
- - **One runtime unit per file** — never define multiple functions/workflows in a single source file.
589
- - **Workflow steps don't need manual wiring** — `pikkuSessionlessFunc` step functions in `*.steps.ts` files are auto-discovered by codegen.
590
- - **Identifiers are English** — functions, components, types, files, database tables and columns, in every app whatever market it serves. The team's language is `metaLocale` in `pikku.config.json` and reaches `description`/`title`/`template` only; the app's language is the message catalogue, where `baseLocale` stays `en` and `defaultLocale` decides what a visitor opens in. `pikku fabric validate` warns (`app-base-locale-not-english-<app>`) when an app repoints its base.
591
-
592
- ## Converting an existing app to Fabric format
593
-
594
- Start by running the structural validator — it tells you exactly what is missing:
595
-
596
- ```bash
597
- pikku fabric validate --json
598
- ```
599
-
600
- Fix every `error` and `warn` in the output before continuing. Then:
601
-
602
- 1. **Replace the database layer**: swap PostgreSQL/MySQL queries for Kysely + libSQL. Convert schema to SQLite-compatible SQL migrations in `db/sqlite/`.
603
- 2. **Replace route handlers with pikkuFuncs**: extract business logic into `pikkuFunc`/`pikkuSessionlessFunc`, add `wireHTTP` or `expose: true` for transport.
604
- 3. **Replace DI/IoC with pikkuServices**: move service construction to `createSingletonServices` in `services.ts`.
605
- 4. **Replace `process.env` calls**: plain config becomes `defineVariable` + `variables.get()`, anything sensitive becomes `defineSecret` + `secrets.getSecret()`.
606
- 5. **Add `pikku.config.json`** at project root with `srcDirectories`, `outDir`, and `clientFiles` — plus `metaLocale` if the team does not work in English, which is the language every `description`, `title` and step `template` is then authored in.
607
- 6. **Declare the apps** as `frontends` in `pikku.config.json`. There is no fabric config file; `projectId` is optional; without it the CLI finds the project from the git remote.
608
- 7. **Run `pikku all`** — verify codegen succeeds and there are no type errors.
609
- 8. **Run `pikku fabric validate`** once more to confirm no structural issues remain.
610
-
611
- ## A deployed stage misbehaving
612
-
613
- Reproduce locally first — a deployed stage adds cost and latency to every
614
- iteration, and a failure that reproduces locally is a local debugging problem.
615
- When it only happens deployed, read `references/debugging.md`: start from
616
- `errors` rather than `logs` (they are already filtered and carry the traceId),
617
- follow one trace end to end before forming a theory, and confirm the fix against
618
- the same stage. A deploy that *failed* is a build or config problem and belongs
619
- above, not there.