@pikku/skills 0.12.35 → 0.12.38

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 (41) hide show
  1. package/README.md +9 -4
  2. package/dist/index.d.ts +7 -4
  3. package/dist/index.js +9 -5
  4. package/dist/skills.gen.d.ts +1 -0
  5. package/dist/skills.gen.js +5 -3
  6. package/dist/snippets.d.ts +26 -0
  7. package/dist/snippets.js +148 -0
  8. package/package.json +2 -2
  9. package/skills/pikku-addon/SKILL.md +70 -24
  10. package/skills/pikku-addon/references/addon-package-manifest.md +9 -4
  11. package/skills/pikku-addon/references/openapi.md +130 -0
  12. package/skills/pikku-agent/references/agents.md +3 -1
  13. package/skills/pikku-auth/references/better-auth.md +33 -2
  14. package/skills/pikku-build/SKILL.md +94 -6
  15. package/skills/pikku-build/references/app.md +82 -12
  16. package/skills/pikku-build/references/design.md +16 -5
  17. package/skills/pikku-build/references/feature.md +23 -96
  18. package/skills/pikku-build/references/openapi.md +119 -0
  19. package/skills/pikku-build/references/platform.md +4 -0
  20. package/skills/pikku-build/references/quick.md +16 -6
  21. package/skills/pikku-changes/SKILL.md +172 -0
  22. package/skills/pikku-concepts/SKILL.md +33 -138
  23. package/skills/pikku-concepts/references/bootstrap.md +58 -0
  24. package/skills/pikku-concepts/references/concept-mapping.md +16 -0
  25. package/skills/pikku-concepts/references/language.md +87 -0
  26. package/skills/pikku-deploy/SKILL.md +1 -1
  27. package/skills/pikku-fabric/SKILL.md +13 -13
  28. package/skills/pikku-guide/SKILL.md +264 -0
  29. package/skills/pikku-kysely/SKILL.md +1 -1
  30. package/skills/pikku-n8n-import/SKILL.md +4 -3
  31. package/skills/pikku-react/references/client.md +12 -0
  32. package/skills/pikku-realtime/SKILL.md +6 -6
  33. package/skills/pikku-report/SKILL.md +143 -0
  34. package/skills/pikku-scenario/SKILL.md +71 -562
  35. package/skills/pikku-scenario/references/browser.md +59 -0
  36. package/skills/pikku-scenario/references/coverage.md +70 -0
  37. package/skills/pikku-scenario/references/personas.md +149 -0
  38. package/skills/pikku-scenario/references/steps.md +366 -0
  39. package/skills/pikku-service-backends/SKILL.md +1 -1
  40. package/skills/pikku-wiring/SKILL.md +1 -1
  41. package/skills/pikku-workflow/SKILL.md +7 -8
@@ -0,0 +1,172 @@
1
+ ---
2
+ name: pikku-changes
3
+ description: 'Work a project''s changes queue — the todo list someone filed by walking a deployed stage. Covers `pikku fabric changes list|claim|show|ask|shot|done`, when to ask a question instead of guessing, and how to offer options as images. TRIGGER when: the user says "work the changes", "pick up the changes queue", names a change by its #number, or you are otherwise idle in a repo that has a pikkufabric.config.json. DO NOT TRIGGER for git changes, diffs or changelogs, and not for deploying or debugging a stage — use pikku-fabric for those.'
4
+ installGroups: [fabric]
5
+ ---
6
+
7
+ # Working a changes queue
8
+
9
+ Someone walked the deployed app and circled twenty things. Each one is a row with their
10
+ words, a picture of what they were looking at, and the elements the circle enclosed. You
11
+ have the repo and the app running locally. Your job is to empty the queue without making
12
+ them regret filing.
13
+
14
+ ## The loop
15
+
16
+ Every argument is a flag; nothing is positional. `--json` works on any of them. The
17
+ project comes from the local `pikkufabric.config.json`, so `--project-id` is only needed
18
+ when you are not in the checkout.
19
+
20
+ ```bash
21
+ pikku fabric changes list --pickup-only --json
22
+ pikku fabric changes claim --change-ids <id>,<id> --title "Checkout pass" --claimed-by claude-code
23
+ pikku fabric changes show --change-id <id>
24
+ pikku fabric changes ask --change-id <id> --question "…" --option "…" --option "…" --author-name claude-code
25
+ pikku fabric changes shot --change-id <id> --label "Bigger" --kind option --image a.png
26
+ pikku fabric changes done --change-id <id> --note "What you did"
27
+ ```
28
+
29
+ `list --pickup-only` is the one a harness wants: it skips items still inside the grace
30
+ window, so a batch someone is mid-way through typing is picked up together rather than item
31
+ by item as it lands.
32
+
33
+ Deciding what belongs together is yours: `claim` with `--change-ids` and no `--group-id`
34
+ forms the group. Claim an existing one with `--group-id`.
35
+
36
+ Claim before working. The lease expires (30 minutes by default, `--lease-minutes` to
37
+ change it), so an abandoned claim returns to the queue rather than parking the work
38
+ forever — but a second harness picking up something you are halfway through is the failure
39
+ this prevents.
40
+
41
+ ## Reading an item
42
+
43
+ `show` gives you four things, in descending order of trustworthiness:
44
+
45
+ 1. **Their words.** The title and body are the requirement. Everything else is evidence.
46
+ 2. **The screenshot.** What they actually saw, at their width, with their data. When the
47
+ other addresses disagree with the picture, the picture is right.
48
+ 3. **The circled elements** — a testid, a source anchor, a CSS path. The testid greps
49
+ straight to a component because it is the i18n message key.
50
+ 4. **The source anchor**, printed as `src/routes/app.orders.tsx:42 as of a91c4e2`. That line
51
+ number is where the JSX was **at that commit**. Read it as a starting point and find
52
+ today's equivalent; never edit line 42 of today's file because the anchor said 42.
53
+
54
+ Resolution is a guess and the panel says so. If the circle and the anchor point at
55
+ different things, believe the circle.
56
+
57
+ ## When to ask
58
+
59
+ Ask when the item admits more than one reasonable implementation and you would be **picking
60
+ for them**. Do not ask to confirm something the item already says.
61
+
62
+ Ask:
63
+ - "Make the total stand out" — bigger, bolder, coloured, or moved above the fold?
64
+ - "This should be faster" — is it the spinner, the request, or the number of steps?
65
+ - Anything that changes what data is stored, what an existing user sees, or what something costs.
66
+
67
+ Do not ask:
68
+ - "Should I use flexbox or grid?" — that is yours.
69
+ - "Do you want me to fix the typo?" — they filed it; fix it.
70
+ - "Can you confirm you want the button blue?" — they said blue.
71
+
72
+ A question costs them a context switch, not typing. That is the budget you are spending.
73
+
74
+ ## What a good question looks like
75
+
76
+ One decision. Their vocabulary, not the codebase's. And the choices in `--option`, not in
77
+ the sentence.
78
+
79
+ > **Bad:** "How would you like me to handle the ambiguity in the checkout total component's
80
+ > emphasis requirement?"
81
+ >
82
+ > **Good:** `--question "Make the total stand out — which way?"`
83
+ > `--option "Bigger" --option "Move it above the delivery line"`
84
+
85
+ **A choice written into the prose is not a choice.** Every `--option` becomes a button in
86
+ the panel and the console, and clicking one records the answer; a question that says
87
+ "(a) build it, (b) leave existing bookings, (c) hold" makes them re-type in free text what
88
+ they should have been able to click, and leaves you parsing prose to find out which one
89
+ they meant. If you can enumerate them in the sentence, you can pass them as flags.
90
+
91
+ Pass them even when there are only two, and even when one is "hold until I check" — that
92
+ last one is a real option and it is the one most often left off. The filer can always
93
+ choose "say something else", so the list constrains nothing.
94
+
95
+ Batch per group. Three questions about one checkout flow go out together; three separate
96
+ asks about the same screen is three interruptions for one context switch.
97
+
98
+ Then **park it**. `ask` flips the item to `needs_answer` and you move to the next item. Do
99
+ not sit waiting — pick answers up on your next `show`, and bound your polling so an
100
+ unanswered item does not spin forever.
101
+
102
+ ## When to show instead of ask
103
+
104
+ If the answer is visual and you can build it, build all of them and attach images:
105
+
106
+ ```bash
107
+ pikku fabric changes shot --change-id <id> --label "Bigger" --kind option --image a.png
108
+ pikku fabric changes shot --change-id <id> --label "Above the line" --kind option --image b.png
109
+ ```
110
+
111
+ The panel turns a set of `option` attachments into a pick-one they open full-screen, and
112
+ picking one writes the choice into the thread. Capture every variant in **one pass at one
113
+ width**, including the baseline — variants shot at different sizes are not comparable, and
114
+ comparing is the whole point.
115
+
116
+ `--kind evidence` is the other use: a picture that proves something, rendered inline rather
117
+ than as a choice.
118
+
119
+ ## Committing
120
+
121
+ One item, one commit. `done` records a single `head_commit`, and that sha is what a human
122
+ reverts when they change their mind — so an item folded in with three others cannot be
123
+ undone without taking the other three with it. Land unrelated work separately.
124
+
125
+ The subject carries the short id the way a GitHub issue number does, and the uuid goes in a
126
+ trailer so `git log --grep` has an exact handle:
127
+
128
+ ```
129
+ feat(login): #4 make the sign-in heading brown
130
+
131
+ Change-Id: 0f3c8a12-9b44-4d2e-8f01-27c6a1d9e5b3
132
+ ```
133
+
134
+ Both ids come from `show`. The type and scope are the usual conventional-commit ones —
135
+ `feat`, `fix`, `style`, `refactor` — with the scope naming the screen or area they were
136
+ looking at, not the file you edited.
137
+
138
+ More:
139
+
140
+ ```
141
+ fix(booking): #7 stop the date picker closing on the first click
142
+ style(nav): #12 tighten the spacing around the logo
143
+ ```
144
+
145
+ Reverting one later is then:
146
+
147
+ ```bash
148
+ git revert $(git log --grep="Change-Id: <uuid>" --format=%H -1)
149
+ ```
150
+
151
+ ## Finishing
152
+
153
+ `done` records the branch and commit that closed it, which is what strikes the item through
154
+ on the page it was filed on and tells them where the fix landed. Both default to the
155
+ checkout you are standing in, so run it from there and let it read git:
156
+
157
+ ```bash
158
+ pikku fabric changes done --change-id <id> \
159
+ --note "What you did, for whoever reads the thread later"
160
+ ```
161
+
162
+ `--branch` and `--head-commit` override them, for the case where the fix landed somewhere
163
+ other than where you are. Never type a sha by hand — one that does not exist points the
164
+ filer at nothing.
165
+
166
+ An item you decided not to do is not `done`. Say why in the thread and leave it for a human
167
+ to dismiss.
168
+
169
+ ## Scope
170
+
171
+ Writes need the `changes:project:write` scope on your bearer. `list` and `show` are reads.
172
+ The project comes from the local `pikkufabric.config.json`, so run these from the checkout.
@@ -20,7 +20,7 @@ Use this skill as an execution checklist, not reference material.
20
20
  1. Discover before editing. Run `pikku doc --ai` for the installed API surface, and the relevant `pikku meta ... --json` for what this project has wired.
21
21
  2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
22
22
  3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
23
- 4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
23
+ 4. Validate with the narrowest relevant command first, then run `pikku all` when functions, wirings, schemas, or generated clients may have changed.
24
24
  5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
25
25
 
26
26
  Pikku is a TypeScript framework that separates business logic from transport mechanisms. You define a function once, then wire it to HTTP, WebSocket, queues, schedulers, MCP, CLI, or RPC — without the function knowing how it's being called.
@@ -286,62 +286,22 @@ Schemas serve triple duty: runtime validation, TypeScript types, and OpenAPI doc
286
286
 
287
287
  ## Server Bootstrap
288
288
 
289
- There are two ways to start a Pikku app. Pick based on whether you need to own the HTTP server.
289
+ Two ways to start a Pikku app, and the choice is whether you need to own the HTTP server.
290
290
 
291
- **1. Let Pikku own the server (preferred when you don't need a specific runtime)**
291
+ **Let Pikku own it** — `pikku dev` and `pikku serve` create the config and singleton services,
292
+ start the server and shut it down cleanly, so you write no bootstrap code at all. Startup and
293
+ shutdown work goes in one exported `pikkuServerLifecycle` (`beforeStart` / `afterStart` /
294
+ `beforeStop`). **Only `dev` and `serve` invoke those hooks** — no deploy runtime does, so anything
295
+ a Workers or serverless stage needs done belongs on the request path that needs it.
292
296
 
293
- `pikku dev` and `pikku serve` create the config and singleton services, start the server, and shut it down cleanly. You write no bootstrap code at all — startup and shutdown work goes in lifecycle hooks:
297
+ **Bootstrap it yourself** — required for Express, Fastify, uWS, Lambda, Cloudflare and Next.js,
298
+ where Pikku is embedded in a server you own. Lifecycle hooks do not run on this path; do the
299
+ startup work in the entrypoint.
294
300
 
295
- ```typescript
296
- // src/lifecycle.ts
297
- import { pikkuServerLifecycle } from '@pikku/core'
298
- import type { SingletonServices } from '../types/application-types.js'
299
-
300
- export const lifecycle = pikkuServerLifecycle<SingletonServices>({
301
- beforeStart: async ({ kysely }) => {
302
- await runMigrations(kysely)
303
- },
304
- afterStart: async ({ logger }) => {
305
- logger.info('accepting traffic')
306
- },
307
- beforeStop: async ({ queueService }) => {
308
- await queueService.drain()
309
- },
310
- })
311
- ```
312
-
313
- Export exactly one `pikkuServerLifecycle` from anywhere in `srcDirectories` — the inspector finds it by the wrapper call. Every hook is optional and receives the already-created singleton services. See pikku-services for the ordering and the `afterStop` caveat.
314
-
315
- **Only `pikku dev` and `pikku serve` invoke these hooks.** No deploy runtime does, so anything a Workers or serverless stage needs done cannot live here — put it on the request path that needs it, guarded by a cheap check.
316
-
317
- **2. Bootstrap it yourself (required for a specific runtime)**
301
+ `pikku validate` warns when a project starts a server by hand *and* depends on no runtime adapter,
302
+ because that means the first path was available and unused.
318
303
 
319
- Express, Fastify, uWS, Lambda, Cloudflare and Next.js need their own entrypoint, because Pikku is embedded in a server you own:
320
-
321
- ```typescript
322
- import '../../functions/.pikku/pikku-bootstrap.gen.js' // Generated — registers all wirings
323
-
324
- const config = await createConfig()
325
- const singletonServices = await createSingletonServices(config)
326
-
327
- // Pick your runtime:
328
- const server = new PikkuFastifyServer(
329
- config,
330
- singletonServices,
331
- createWireServices
332
- )
333
- // or: new PikkuExpressServer(config, singletonServices, createWireServices)
334
- // or: pikkuAWSLambdaHandler(singletonServices)
335
- // or: PikkuCloudflareHandler(singletonServices)
336
- // or: pikkuNextHandler(singletonServices)
337
-
338
- await server.init()
339
- await server.start()
340
- ```
341
-
342
- **Lifecycle hooks do not run on this path** — only `pikku dev` and `pikku serve` invoke them. Do your startup work directly in the entrypoint instead.
343
-
344
- `pikku validate` warns when a project starts a server by hand _and_ depends on no runtime adapter, since that combination means path 1 was available and unused. Silence it with `"lint": { "customServerBootstrap": "off" }` in `pikku.config.json`.
304
+ **`references/bootstrap.md`** has both entrypoints in full.
345
305
 
346
306
  ## Code Generation
347
307
 
@@ -392,91 +352,26 @@ src/
392
352
 
393
353
  ## What Language You Write In
394
354
 
395
- Three different things in a Pikku project have a human language, and they are
396
- **not** the same language. Collapsing them is the mistake this section exists to
397
- prevent, and it has already shipped in a real product — the failure is at the
398
- bottom.
399
-
400
- | Axis | What it covers | What decides it |
401
- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
402
- | **Identifiers** | Function, component, type, variable and file names. Database tables and columns. Branch names and commit messages. | Nothing. **Always English.** There is no setting. |
403
- | **Meta** | The prose authored _inside_ the code: `description` on functions and steps, `name`/`title` on features and scenarios, step `template`, role/persona descriptions. | `metaLocale` in `pikku.config.json`. Defaults to `en`. |
404
- | **Product UI** | Every string the app shows a user. | `messages/<locale>.json`, with `active.json`'s `defaultLocale` choosing what a first-time visitor opens in. |
405
-
406
- ### Identifiers are English, and nothing changes that
407
-
408
- Not the product's market, not the team's working language, and **not `metaLocale`**.
409
- A German medical practice, an Arabic marketplace and a Japanese logistics tool
410
- all get `getOverview`, `AttentionStripe`, `case`, `event`.
411
-
412
- This is not linguistic preference, it is mechanics. Identifiers are the surface
413
- every other tool binds to: the generated `#pikku/*` clients, `pikku info` and
414
- `pikku meta`, the RPC map a scenario's `actor.invoke` is typed over, the
415
- generated SQL types, every skill and every agent that ever picks the project up.
416
- A `vorgang` table types as `Vorgang` in Kysely and reads as noise to everyone who
417
- did not name it, and unlike a string it cannot be translated later — renaming an
418
- identifier is a migration, not an edit.
419
-
420
- ### Meta follows `metaLocale`, and that is what the field is for
421
-
422
- ```json
423
- { "metaLocale": "de" }
424
- ```
425
-
426
- Meta is the one part of a project the **Pikku Console** renders back to a human.
427
- A team reviewing their own functions, features and scenario reports in the
428
- Console is reading meta and nothing else, so a team whose working language is
429
- German should be able to read their Console in German. That is the entire reason
430
- the field exists.
431
-
432
- Read it before you author meta, and write descriptions, titles and templates in
433
- it. Absent, it is `en`. It is a BCP-47 tag (`en`, `de`, `pt-BR` — a hyphen, not
434
- an underscore), and the CLI rejects anything else by name.
435
-
436
- `metaLocale` is **not** licence to rename anything. `metaLocale: "de"` buys a German
437
- `description: 'Zeigt die Arbeitsliste'` on a function still called
438
- `getWorklist`.
439
-
440
- ### Product UI language lives in the catalogue, and only there
441
-
442
- What the app says to its users is a translation concern, not a code concern. It
443
- belongs in `messages/<locale>.json`; `pikku-i18n` owns the details. The one rule
444
- worth repeating here: **`baseLocale` in `project.inlang/settings.json` stays
445
- `en`.** It names the message _source_ — the catalogue every other language is
446
- cloned from and translated against — so a project that sets it to anything else
447
- has no English catalogue to translate from and can never gain a second language
448
- without re-authoring every key.
449
-
450
- ### The failure this comes from
451
-
452
- An agent was asked to build a doctor's portal for a German practice. The brief
453
- said "the entire UI is German, no English strings visible anywhere". The agent
454
- read one sentence about the product's users as an instruction about the
455
- codebase, and produced:
456
-
457
- - `project.inlang/settings.json` with `baseLocale: "de"` and `locales: ["de"]`,
458
- no `en.json` at all — which silently broke `--add-locale` forever
459
- - RPC functions `getUebersicht` and `getPatientendetail`
460
- - React components `Zeitstrahl` and `AufmerksamkeitStreifen`
461
- - database tables `vorgang` and `ereignis`, with German columns
462
-
463
- Every one of those is wrong, and the brief was satisfied by none of them: a
464
- German UI needs German _messages_. What that project actually wanted was three
465
- settings, each on its own axis:
466
-
467
- ```jsonc
468
- // project.inlang/settings.json — the message source stays English
469
- { "baseLocale": "en", "locales": ["en", "de"] }
470
-
471
- // apps/app/src/i18n/active.json — what a first-time visitor opens in
472
- { "defaultLocale": "de" }
473
-
474
- // pikku.config.json — the language the team reads their Console in
475
- { "metaLocale": "de" }
476
- ```
477
-
478
- Identifiers stay English throughout. When a brief tells you the product speaks a
479
- language, it is telling you about axis three and nothing else.
355
+ Three different things in a Pikku project have a human language, and they are **not** the same
356
+ language. Collapsing them has already shipped in a real product:
357
+
358
+ | Axis | Covers | Decided by |
359
+ | --------------- | ----------------------------------------------------------------------------- | ---------------------------------------------- |
360
+ | **Identifiers** | Function, component, type and file names; tables and columns; commit messages | Nothing. **Always English.** There is no setting |
361
+ | **Meta** | Prose authored inside the code — `description`, `title`, step `template` | `metaLocale` in `pikku.config.json` (default `en`) |
362
+ | **Product UI** | Every string the app shows a user | `messages/<locale>.json`, and `active.json`'s `defaultLocale` |
363
+
364
+ Identifiers are the surface every other tool binds to — the generated clients, the RPC map a
365
+ scenario is typed over, the SQL types — and unlike a string an identifier cannot be translated
366
+ later: renaming one is a migration. `metaLocale` exists so a team can read their own Console in
367
+ their own language; it is not licence to rename anything. And `baseLocale` in
368
+ `project.inlang/settings.json` stays `en`, because it names the message *source* every other
369
+ language is cloned from.
370
+
371
+ **When a brief tells you the product speaks a language, it is telling you about the third axis and
372
+ nothing else.** `references/language.md` has the three settings that satisfy such a brief, and the
373
+ build that read one sentence about a product's users as an instruction about its codebase — German
374
+ RPC names, German tables, and no English catalogue to ever translate from.
480
375
 
481
376
  ## Environment Variables
482
377
 
@@ -0,0 +1,58 @@
1
+ # Server bootstrap
2
+
3
+ There are two ways to start a Pikku app. Pick based on whether you need to own the HTTP server.
4
+
5
+ **1. Let Pikku own the server (preferred when you don't need a specific runtime)**
6
+
7
+ `pikku dev` and `pikku serve` create the config and singleton services, start the server, and shut it down cleanly. You write no bootstrap code at all — startup and shutdown work goes in lifecycle hooks:
8
+
9
+ ```typescript
10
+ // src/lifecycle.ts
11
+ import { pikkuServerLifecycle } from '@pikku/core'
12
+ import type { SingletonServices } from '../types/application-types.js'
13
+
14
+ export const lifecycle = pikkuServerLifecycle<SingletonServices>({
15
+ beforeStart: async ({ kysely }) => {
16
+ await runMigrations(kysely)
17
+ },
18
+ afterStart: async ({ logger }) => {
19
+ logger.info('accepting traffic')
20
+ },
21
+ beforeStop: async ({ queueService }) => {
22
+ await queueService.drain()
23
+ },
24
+ })
25
+ ```
26
+
27
+ Export exactly one `pikkuServerLifecycle` from anywhere in `srcDirectories` — the inspector finds it by the wrapper call. Every hook is optional and receives the already-created singleton services. See pikku-services for the ordering and the `afterStop` caveat.
28
+
29
+ **Only `pikku dev` and `pikku serve` invoke these hooks.** No deploy runtime does, so anything a Workers or serverless stage needs done cannot live here — put it on the request path that needs it, guarded by a cheap check.
30
+
31
+ **2. Bootstrap it yourself (required for a specific runtime)**
32
+
33
+ Express, Fastify, uWS, Lambda, Cloudflare and Next.js need their own entrypoint, because Pikku is embedded in a server you own:
34
+
35
+ ```typescript
36
+ import '../../functions/.pikku/pikku-bootstrap.gen.js' // Generated — registers all wirings
37
+
38
+ const config = await createConfig()
39
+ const singletonServices = await createSingletonServices(config)
40
+
41
+ // Pick your runtime:
42
+ const server = new PikkuFastifyServer(
43
+ config,
44
+ singletonServices,
45
+ createWireServices
46
+ )
47
+ // or: new PikkuExpressServer(config, singletonServices, createWireServices)
48
+ // or: pikkuAWSLambdaHandler(singletonServices)
49
+ // or: PikkuCloudflareHandler(singletonServices)
50
+ // or: pikkuNextHandler(singletonServices)
51
+
52
+ await server.init()
53
+ await server.start()
54
+ ```
55
+
56
+ **Lifecycle hooks do not run on this path** — only `pikku dev` and `pikku serve` invoke them. Do your startup work directly in the entrypoint instead.
57
+
58
+ `pikku validate` warns when a project starts a server by hand _and_ depends on no runtime adapter, since that combination means path 1 was available and unused. Silence it with `"lint": { "customServerBootstrap": "off" }` in `pikku.config.json`.
@@ -2,6 +2,22 @@
2
2
 
3
3
  Authoritative mapping table plus side-by-side code examples showing how common backend patterns translate to Pikku.
4
4
 
5
+ - [Quick Reference Table](#quick-reference-table)
6
+ - [Route Handler / Controller → pikkuFunc](#route-handler--controller--pikkufunc)
7
+ - [Route Parameters → Merged into Data](#route-parameters--merged-into-data)
8
+ - [Middleware → pikkuMiddleware](#middleware--pikkumiddleware)
9
+ - [Auth Guard → Built-in Auth Middleware](#auth-guard--built-in-auth-middleware)
10
+ - [Authorization / Role Checks → pikkuPermission](#authorization--role-checks--pikkupermission)
11
+ - [DTO / Request Validation → Standard Schema](#dto--request-validation--standard-schema)
12
+ - [Dependency Injection → Service Factories](#dependency-injection--service-factories)
13
+ - [WebSocket Handlers → wireChannel](#websocket-handlers--wirechannel)
14
+ - [Job Queue Workers → wireQueueWorker](#job-queue-workers--wirequeueworker)
15
+ - [Cron / Scheduled Tasks → wireScheduler](#cron--scheduled-tasks--wirescheduler)
16
+ - [Module / Feature Grouping → Tags + File Organization](#module--feature-grouping--tags--file-organization)
17
+ - [Error Handling → Typed Errors](#error-handling--typed-errors)
18
+ - [Session Management](#session-management)
19
+ - [API Client Generation](#api-client-generation)
20
+
5
21
  ## Quick Reference Table
6
22
 
7
23
  | Generic Backend Concept | Pikku Equivalent | Skill |
@@ -0,0 +1,87 @@
1
+ # What language you write in
2
+
3
+ Three different things in a Pikku project have a human language, and they are
4
+ **not** the same language. Collapsing them is the mistake this section exists to
5
+ prevent, and it has already shipped in a real product — the failure is at the
6
+ bottom.
7
+
8
+ | Axis | What it covers | What decides it |
9
+ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
10
+ | **Identifiers** | Function, component, type, variable and file names. Database tables and columns. Branch names and commit messages. | Nothing. **Always English.** There is no setting. |
11
+ | **Meta** | The prose authored _inside_ the code: `description` on functions and steps, `name`/`title` on features and scenarios, step `template`, role/persona descriptions. | `metaLocale` in `pikku.config.json`. Defaults to `en`. |
12
+ | **Product UI** | Every string the app shows a user. | `messages/<locale>.json`, with `active.json`'s `defaultLocale` choosing what a first-time visitor opens in. |
13
+
14
+ ## Identifiers are English, and nothing changes that
15
+
16
+ Not the product's market, not the team's working language, and **not `metaLocale`**.
17
+ A German medical practice, an Arabic marketplace and a Japanese logistics tool
18
+ all get `getOverview`, `AttentionStripe`, `case`, `event`.
19
+
20
+ This is not linguistic preference, it is mechanics. Identifiers are the surface
21
+ every other tool binds to: the generated `#pikku/*` clients, `pikku info` and
22
+ `pikku meta`, the RPC map a scenario's `actor.invoke` is typed over, the
23
+ generated SQL types, every skill and every agent that ever picks the project up.
24
+ A `vorgang` table types as `Vorgang` in Kysely and reads as noise to everyone who
25
+ did not name it, and unlike a string it cannot be translated later — renaming an
26
+ identifier is a migration, not an edit.
27
+
28
+ ## Meta follows `metaLocale`, and that is what the field is for
29
+
30
+ ```json
31
+ { "metaLocale": "de" }
32
+ ```
33
+
34
+ Meta is the one part of a project the **Pikku Console** renders back to a human.
35
+ A team reviewing their own functions, features and scenario reports in the
36
+ Console is reading meta and nothing else, so a team whose working language is
37
+ German should be able to read their Console in German. That is the entire reason
38
+ the field exists.
39
+
40
+ Read it before you author meta, and write descriptions, titles and templates in
41
+ it. Absent, it is `en`. It is a BCP-47 tag (`en`, `de`, `pt-BR` — a hyphen, not
42
+ an underscore), and the CLI rejects anything else by name.
43
+
44
+ `metaLocale` is **not** licence to rename anything. `metaLocale: "de"` buys a German
45
+ `description: 'Zeigt die Arbeitsliste'` on a function still called
46
+ `getWorklist`.
47
+
48
+ ## Product UI language lives in the catalogue, and only there
49
+
50
+ What the app says to its users is a translation concern, not a code concern. It
51
+ belongs in `messages/<locale>.json`; `pikku-i18n` owns the details. The one rule
52
+ worth repeating here: **`baseLocale` in `project.inlang/settings.json` stays
53
+ `en`.** It names the message _source_ — the catalogue every other language is
54
+ cloned from and translated against — so a project that sets it to anything else
55
+ has no English catalogue to translate from and can never gain a second language
56
+ without re-authoring every key.
57
+
58
+ ## The failure this comes from
59
+
60
+ An agent was asked to build a doctor's portal for a German practice. The brief
61
+ said "the entire UI is German, no English strings visible anywhere". The agent
62
+ read one sentence about the product's users as an instruction about the
63
+ codebase, and produced:
64
+
65
+ - `project.inlang/settings.json` with `baseLocale: "de"` and `locales: ["de"]`,
66
+ no `en.json` at all — which silently broke `--add-locale` forever
67
+ - RPC functions `getUebersicht` and `getPatientendetail`
68
+ - React components `Zeitstrahl` and `AufmerksamkeitStreifen`
69
+ - database tables `vorgang` and `ereignis`, with German columns
70
+
71
+ Every one of those is wrong, and the brief was satisfied by none of them: a
72
+ German UI needs German _messages_. What that project actually wanted was three
73
+ settings, each on its own axis:
74
+
75
+ ```jsonc
76
+ // project.inlang/settings.json — the message source stays English
77
+ { "baseLocale": "en", "locales": ["en", "de"] }
78
+
79
+ // apps/app/src/i18n/active.json — what a first-time visitor opens in
80
+ { "defaultLocale": "de" }
81
+
82
+ // pikku.config.json — the language the team reads their Console in
83
+ { "metaLocale": "de" }
84
+ ```
85
+
86
+ Identifiers stay English throughout. When a brief tells you the product speaks a
87
+ language, it is telling you about axis three and nothing else.
@@ -21,7 +21,7 @@ Use this skill as an execution checklist, not reference material.
21
21
  1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
22
22
  2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
23
23
  3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
24
- 4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
24
+ 4. Validate with the narrowest relevant command first, then run `pikku all` when functions, wirings, schemas, or generated clients may have changed.
25
25
  5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
26
26
 
27
27
  Signatures and option keys come from `pikku doc` — run `pikku doc --ai` for the
@@ -1,6 +1,6 @@
1
1
  ---
2
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, `fabric.config.json`, the pikku-verify workflow, 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.'
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, `pikkufabric.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
4
  installGroups: [fabric]
5
5
  ---
6
6
 
@@ -18,7 +18,7 @@ Use this skill as an execution checklist, not reference material.
18
18
  2. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
19
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
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-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
21
+ 5. Validate with the narrowest relevant command first, then run `pikku all` when functions, wirings, schemas, or generated clients may have changed.
22
22
  6. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
23
23
 
24
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.
@@ -31,20 +31,20 @@ Always run project discovery first:
31
31
  yarn pikku meta context --json
32
32
  ```
33
33
 
34
- Call the `pikku-meta` tool before grepping or editing a Fabric app.
34
+ Run `pikku meta` before grepping or editing a Fabric app.
35
35
 
36
- - Use `section: "context"` for the project map: functions, wires, workflows, capabilities, and source files.
37
- - Use `section: "clients"` before frontend/RPC work.
38
- - Use `section: "functions"` to list function ids, then `section: "function", id: "<functionId>"` for one function.
39
- - Use `section: "schemas"` to list schema names. Only request full JSON Schema bodies with `schemas: ["SchemaName"]` for the specific schemas needed.
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
40
 
41
41
  Do not load every schema body by default; that wastes context and usually makes the model worse.
42
42
 
43
43
  For database work:
44
44
 
45
- - Use `pikku-db` for the actual attached Fabric database state: tables, columns, foreign keys, and applied migrations.
46
- - Use `pikku-meta` `section: "schemas"` for code-level JSON Schema contracts, not database introspection.
47
- - Do not inspect database credentials or connect to the database directly; Fabric Control already exposes the safe introspection surface.
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
48
 
49
49
  ## Database: SQLite via libSQL
50
50
 
@@ -437,16 +437,16 @@ the deploy with "local HEAD … ≠ remote …" even though your code is pushed.
437
437
 
438
438
  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.
439
439
 
440
- The `pikku-verify` tool catches this automatically.
440
+ `pikku all` catches this automatically.
441
441
 
442
442
  ## After every code change
443
443
 
444
- Always call the `pikku-verify` tool after modifying functions, wirings, or schemas. It runs:
444
+ Run `pikku all` after modifying functions, wirings, or schemas, then `tsc --noEmit`:
445
445
 
446
446
  1. `pikku all` — regenerates all codegen, checks version compliance
447
447
  2. `tsc --noEmit` — validates TypeScript types
448
448
 
449
- The output card shows whether any breaking changes were detected.
449
+ Breaking changes are reported by the version check in step 1.
450
450
 
451
451
  ### `app-missing-actor-quick-login-<app>`
452
452