@pikku/skills 0.12.52 → 0.12.54

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 (104) hide show
  1. package/dist/skills.gen.js +2 -2
  2. package/package.json +1 -1
  3. package/skills/pikku-a11y/SKILL.md +22 -15
  4. package/skills/pikku-addon/SKILL.md +5 -5
  5. package/skills/pikku-addon/references/addon-package-manifest.md +7 -0
  6. package/skills/pikku-addon/references/openapi.md +11 -0
  7. package/skills/pikku-admin-to-fabric/SKILL.md +7 -21
  8. package/skills/pikku-agent/SKILL.md +6 -6
  9. package/skills/pikku-agent/references/agents.md +8 -1
  10. package/skills/pikku-agent/references/runner-vercel.md +2 -2
  11. package/skills/pikku-agent/references/voice.md +7 -1
  12. package/skills/pikku-architect/SKILL.md +1 -1
  13. package/skills/pikku-architect/references/plan-defects.md +2 -0
  14. package/skills/pikku-auth/SKILL.md +15 -36
  15. package/skills/pikku-auth/references/better-auth.md +22 -45
  16. package/skills/pikku-auth/references/jose.md +6 -0
  17. package/skills/pikku-auth/references/machine-auth.md +6 -0
  18. package/skills/pikku-auth/references/sessions.md +6 -0
  19. package/skills/pikku-blueprint-to-fabric/SKILL.md +6 -21
  20. package/skills/pikku-blueprint-to-fabric/scripts/inventory.mjs +1 -1
  21. package/skills/pikku-build/SKILL.md +29 -26
  22. package/skills/pikku-build/references/app.md +60 -41
  23. package/skills/pikku-build/references/design.md +31 -19
  24. package/skills/pikku-build/references/feature.md +14 -0
  25. package/skills/pikku-build/references/mocks.md +23 -0
  26. package/skills/pikku-build/references/multi-app.md +9 -2
  27. package/skills/pikku-build/references/native-app.md +9 -0
  28. package/skills/pikku-build/references/openapi.md +7 -0
  29. package/skills/pikku-build/references/platform.md +20 -10
  30. package/skills/pikku-build/references/quick.md +14 -4
  31. package/skills/pikku-build/references/scenarios.md +12 -1
  32. package/skills/pikku-build/references/ship.md +6 -1
  33. package/skills/pikku-build/references/theming.md +74 -125
  34. package/skills/pikku-changes/SKILL.md +6 -6
  35. package/skills/pikku-concepts/SKILL.md +8 -17
  36. package/skills/pikku-concepts/references/concept-mapping.md +18 -0
  37. package/skills/pikku-convert-screen/SKILL.md +45 -0
  38. package/skills/pikku-deploy/references/cloudflare.md +8 -0
  39. package/skills/pikku-deploy/references/lambda.md +8 -0
  40. package/skills/pikku-deploy/references/uws.md +1 -1
  41. package/skills/pikku-deploy/references/ws.md +3 -3
  42. package/skills/pikku-emails/SKILL.md +3 -9
  43. package/skills/pikku-fabric/SKILL.md +7 -295
  44. package/skills/pikku-fabric/references/database.md +128 -0
  45. package/skills/pikku-fabric/references/debugging.md +9 -5
  46. package/skills/pikku-fabric/references/deploy.md +179 -0
  47. package/skills/pikku-guide/SKILL.md +10 -10
  48. package/skills/pikku-i18n/SKILL.md +7 -7
  49. package/skills/pikku-i18n/references/enum-labels.md +9 -0
  50. package/skills/pikku-i18n/references/messages.md +16 -3
  51. package/skills/pikku-i18n/references/rtl.md +18 -38
  52. package/skills/pikku-knowledge/SKILL.md +9 -10
  53. package/skills/pikku-kysely/SKILL.md +3 -21
  54. package/skills/pikku-list-query/SKILL.md +2 -2
  55. package/skills/pikku-meta/references/audit.md +9 -0
  56. package/skills/pikku-meta/references/meta.md +6 -0
  57. package/skills/pikku-meta/references/versioning.md +10 -0
  58. package/skills/pikku-middleware/SKILL.md +7 -16
  59. package/skills/pikku-n8n-import/SKILL.md +9 -1
  60. package/skills/pikku-n8n-import/references/addon-mapping.md +6 -0
  61. package/skills/pikku-n8n-import/references/code-translation.md +7 -0
  62. package/skills/pikku-permissions/SKILL.md +41 -10
  63. package/skills/pikku-permissions/references/scopes.md +59 -0
  64. package/skills/pikku-react/SKILL.md +2 -2
  65. package/skills/pikku-react/references/client.md +1 -34
  66. package/skills/pikku-react/references/react-query.md +11 -0
  67. package/skills/pikku-react/references/workflows.md +11 -0
  68. package/skills/pikku-realtime/SKILL.md +9 -3
  69. package/skills/pikku-report/SKILL.md +10 -9
  70. package/skills/pikku-scenario/SKILL.md +11 -17
  71. package/skills/pikku-scenario/references/persona-run.md +11 -1
  72. package/skills/pikku-scenario/references/personas.md +7 -1
  73. package/skills/pikku-seo/SKILL.md +12 -16
  74. package/skills/pikku-service-backends/SKILL.md +0 -10
  75. package/skills/pikku-service-backends/references/aws.md +6 -0
  76. package/skills/pikku-service-backends/references/mongodb.md +7 -0
  77. package/skills/pikku-service-backends/references/redis.md +6 -0
  78. package/skills/pikku-services/references/audit.md +10 -0
  79. package/skills/pikku-services/references/config.md +6 -0
  80. package/skills/pikku-services/references/services.md +8 -1
  81. package/skills/pikku-software-archaeology/SKILL.md +9 -15
  82. package/skills/pikku-software-archaeology/references/blueprint.schema.json +7 -7
  83. package/skills/pikku-software-archaeology/references/pikku-mapping.md +3 -3
  84. package/skills/pikku-software-archaeology/references/second-opinion.md +13 -1
  85. package/skills/pikku-tailwind/SKILL.md +111 -0
  86. package/skills/pikku-theme/SKILL.md +187 -0
  87. package/skills/pikku-theme/references/from-a-reference.md +44 -0
  88. package/skills/pikku-theme/references/presets.md +40 -0
  89. package/skills/pikku-ui/SKILL.md +41 -0
  90. package/skills/pikku-wiring/SKILL.md +13 -12
  91. package/skills/pikku-wiring/references/channel.md +7 -1
  92. package/skills/pikku-wiring/references/cli.md +7 -1
  93. package/skills/pikku-wiring/references/gateway-slack.md +6 -0
  94. package/skills/pikku-wiring/references/http.md +10 -3
  95. package/skills/pikku-wiring/references/mcp.md +8 -0
  96. package/skills/pikku-wiring/references/queue.md +6 -0
  97. package/skills/pikku-wiring/references/realtime.md +34 -4
  98. package/skills/pikku-wiring/references/rpc.md +6 -0
  99. package/skills/pikku-wiring/references/scheduler.md +6 -0
  100. package/skills/pikku-wiring/references/trigger.md +8 -0
  101. package/skills/pikku-workflow/SKILL.md +8 -6
  102. package/skills/pikku-auth/references/permissions.md +0 -261
  103. package/skills/pikku-mantine/SKILL.md +0 -80
  104. package/skills/pikku-wiring/references/realtime-other-routes.md +0 -23
@@ -1,5 +1,15 @@
1
1
  # Build an app on Pikku, fast
2
2
 
3
+ ## Contents
4
+
5
+ - Agent Operating Procedure
6
+ - 1. One question, then build
7
+ - 2. Personas — 60 seconds, not optional
8
+ - 3. Build
9
+ - 4. Look at it — actually
10
+ - 5. One smoke scenario
11
+ - 6. Hand it over honestly
12
+
3
13
  You have a scaffolded project with skills installed. Get it to working, seeded,
4
14
  signed-in screens in as few steps as possible.
5
15
 
@@ -42,7 +52,7 @@ Identifiers are English in every project, whatever the product's market;
42
52
  `template`, which the Console renders) stays `en` unless the user already told
43
53
  you otherwise. If the request says the app's UI is not English, that is the
44
54
  message catalogue only: add the locale and set `defaultLocale`, and leave
45
- `baseLocale` at `en`. `references/app.md` §1a has the three axes in full; getting
55
+ `baseLocale` at `en`. the app workflow's §1a has the three axes in full; getting
46
56
  them confused is how a project ends up unable to add a second language.
47
57
 
48
58
  ## 2. Personas — 60 seconds, not optional
@@ -186,7 +196,7 @@ taller than the viewport. It is the most likely width your demo gets opened at.
186
196
  If you have five spare minutes, `npx impeccable install` (Node 22.18+) scores
187
197
  each screen against interaction heuristics and names what is wrong. Feed it
188
198
  screenshots, not source. It will polish the default look; it will not give the
189
- app a look — that is `references/app.md` §8a.
199
+ app a look — that is the app workflow's §8a.
190
200
 
191
201
  ## 5. One smoke scenario
192
202
 
@@ -230,7 +240,7 @@ it is seeded with, and that this is a quick build — no knowledge base, no
230
240
  changesets, no design pass, access control clicked-through rather than proven.
231
241
 
232
242
  **Upgrading to a real build is additive, not a rewrite.** If they want it, switch
233
- to `references/app.md` and do this, in order:
243
+ to the app workflow (the app reference, see SKILL.md) and do this, in order:
234
244
 
235
245
  1. Write `knowledge/` for what already exists — `entities/` for what you built,
236
246
  `decisions/` for what you chose silently, `questions/` for what you guessed
@@ -239,7 +249,7 @@ to `references/app.md` and do this, in order:
239
249
  gaps` has something to measure against.
240
250
  3. Write the refusal scenarios — the ones proving one persona cannot reach
241
251
  another's rows. This is the gap that matters most.
242
- 4. Then pick up `references/app.md` at its §4 (apps) or §5 (changes) for
252
+ 4. Then pick up the app workflow at its §4 (apps) or §5 (changes) for
243
253
  anything new.
244
254
 
245
255
  Nothing built here has to be thrown away to do that — which is the whole reason
@@ -1,5 +1,16 @@
1
1
  # Scenarios — writing journeys that stay proven
2
2
 
3
+ ## Contents
4
+
5
+ - The shape of a scenario
6
+ - Extraction: what survives, and what silently does not
7
+ - What to assert
8
+ - There is no state reset
9
+ - Steps rot as the app grows
10
+ - Browser scenarios
11
+ - Running them
12
+ - Coverage — which functions have actually been run
13
+
3
14
  A scenario is a user journey run as one of your personas, over the real transport, with that
4
15
  persona's session. It is the only kind of test worth writing here, because a passing one proves the
5
16
  app works the way a signed-in person experiences it.
@@ -59,7 +70,7 @@ export const tenantReportsAFaultScenario = pikkuScenario<void, { id: string }>({
59
70
  (server-side by default, plus a `browser` one that drives the page). Reaching for an RPC name in a
60
71
  `then` will not resolve.
61
72
 
62
- **`SCENARIO_ACTOR_SECRET` must be in `.env`** (app.md §6, before the first run). Without it
73
+ **`SCENARIO_ACTOR_SECRET` must be in `.env`** (the app workflow's §6, before the first run). Without it
63
74
  `/api/auth/sign-in/actor` is disabled — every scenario then fails at sign-in, before its first step,
64
75
  for a reason that reads like an auth bug. `pikku scenario run` reads it from the environment, so
65
76
  source `.env` first (`set -a && . ./.env && set +a`) when you run outside `bun run dev`.
@@ -1,5 +1,10 @@
1
1
  # Shipping, and staying Fabric-ready
2
2
 
3
+ ## Contents
4
+
5
+ - Ship it — open source, no platform
6
+ - Staying Fabric-ready
7
+
3
8
  Read this when the changes queue is empty and the scenarios are green — it is
4
9
  the last phase, and nothing in it is needed before then.
5
10
 
@@ -114,7 +119,7 @@ one hostname, first-party cookies — give its `frontends` entry `"serve": {}`
114
119
  and a standalone deploy then mount its built `dist`. Pikku never builds it, so
115
120
  build the frontend first. Only one entry may set `serve`.
116
121
 
117
- To ship an app as a desktop or Android app, read `references/native-app.md`.
122
+ To ship an app as a desktop or Android app, read the native-app reference (see SKILL.md).
118
123
 
119
124
  Before shipping, run the full gate:
120
125
 
@@ -1,5 +1,12 @@
1
1
  # Authoring the theme
2
2
 
3
+ ## Contents
4
+
5
+ - Where the look lives
6
+ - The colours the theme has no token for
7
+ - Choose the neutrals; do not inherit them
8
+ - If the user gave you no direction
9
+
3
10
  Read this at the design step, once you have a direction to turn into a theme —
4
11
  whether the user described one in words, handed you a reference, or ran their own
5
12
  design step whose output you are implementing.
@@ -11,180 +18,122 @@ job done in JSON.
11
18
  ## Where the look lives
12
19
 
13
20
  ```
14
- packages/mantine-theme/
21
+ packages/theme/
15
22
  themes/
16
23
  default.json # "Neutral" — the shipped scaffold
17
- index.ts # registers each theme JSON by id
18
24
  active.json # { "id": "default" } — which one is live
19
- index.ts
25
+ theme.css # generated from the active spec — do not edit
20
26
  ```
21
27
 
22
28
  Each theme JSON has two halves — `brand` (colours, fonts) and `structure`
23
- (radius, shadows, spacing, per-component `defaultProps`). To give the product an
24
- identity, add `themes/<name>.json`, register it in `themes/index.ts`, and point
25
- `active.json` at its id.
26
-
27
- `themes/index.ts` carries a `Generated by the fabric-theme tool — do not edit by
28
- hand` banner. **That instruction is about Fabric's generator, not about you.**
29
- Without that tool, hand-authoring is the only route, and the file is a three-line
30
- registry. Edit it, and replace the banner with a line saying the themes here are
31
- hand-authored — otherwise the next agent reads the warning and leaves the app on
32
- Neutral.
29
+ (radius, density, default colour scheme). To give the product an identity, add
30
+ `themes/<name>.json`, point `active.json` at its id, and regenerate theme.css.
31
+ That regenerates `theme.css`, which defines the shadcn tokens (`--background`,
32
+ `--card`, `--border`, `--primary`, `--chart-1` to `--chart-5`, `--radius`) for
33
+ both the light scheme and the `.dark` class.
33
34
 
34
35
  Turning §1's answer into a theme:
35
36
 
36
- - **Colour before anything else.** `brand.colors.primary` plus
37
- `structure.primaryShade` and `autoContrast` carry most of the identity;
38
- `@mantine/colors-generator` (already a dependency) expands one hex into a full
39
- scale.
37
+ - **Colour before anything else.** `brand.colors.primary` carries most of the
38
+ identity; the neutrals, borders and chart colours are derived from its hue.
40
39
  - **Fonts are the other half of the register**, and the half people skip. A serif
41
40
  heading font against a neutral body is a different product from the system
42
41
  stack, and it is one field.
43
- - **`structure.radius` and `structure.shadows` set the temperature.** Sharp
44
- corners and flat surfaces read technical; large radii and soft shadows read
45
- consumer. Neutral's `md: 10px` is the middle of the road on purpose.
46
- - **`structure.components` defaultProps is where a design decision becomes
47
- automatic** — `Card` with `withBorder` everywhere, `NavLink` as `light`. Put
48
- the repeated decision here rather than on every instance.
49
- - **`defaultColorScheme` and `darkColors` are a real choice**, not a toggle to
50
- leave alone. A tool people live in all day is often better dark by default.
42
+ - **`structure.radius` sets the temperature.** Sharp corners read technical;
43
+ large radii read consumer. Neutral's `md` is the middle of the road on purpose.
44
+ - **`defaultColorScheme` is a real choice**, not a toggle to leave alone. A tool
45
+ people live in all day is often better dark by default.
51
46
 
52
47
  Then **write the direction into `knowledge/decisions/design/`** — the words the
53
48
  user gave you, what you chose, and what it rules out. The JSON records what the
54
49
  theme is; only the note records why.
55
50
 
56
- ## The colours the theme has no field for
51
+ ## The colours the theme has no token for
57
52
 
58
53
  `brand` is the product's accent. It is not the only colour a screen needs, and
59
54
  the missing ones are why "don't hardcode colours per component" gets broken by
60
55
  the same agent that wrote it down.
61
56
 
62
- A screen has to say *covered* and *still open*, *fine* and *needs attention* —
57
+ A screen has to say _covered_ and _still open_, _fine_ and _needs attention_ —
63
58
  and those are not the accent. Using the accent for them is worse than a stray
64
59
  hex: the brand colour stops meaning "this product" and starts meaning "good", so
65
60
  it means nothing. But there is no `brand.covered` field, so the value lands
66
61
  inline as `#3f7d5c`, once per component, slightly different each time.
67
62
 
68
- Give them a home. A small stylesheet of custom properties, imported once beside
69
- the Mantine styles, is enough:
63
+ Give them a home. A small stylesheet of custom properties, imported once after
64
+ `theme.css`, exposed to Tailwind through `@theme inline`, is enough:
70
65
 
71
66
  ```css
72
- :root:root:root {
73
- --app-covered: #3f7d5c; --app-covered-bg: #e6f1ea;
74
- --app-open: #a8701a; --app-open-bg: #fbeedb;
75
- --app-sunk: #fdf7f4; /* a recessed surface, for forms and asides */
76
- --app-hairline: #ecdfd9; /* NOT var(--mantine-color-gray-2) — see below */
67
+ :root {
68
+ --covered: #3f7d5c;
69
+ --covered-bg: #e6f1ea;
70
+ --open: #a8701a;
71
+ --open-bg: #fbeedb;
72
+ --sunk: #fdf7f4;
77
73
  }
78
- :root:root[data-mantine-color-scheme='dark'] {
79
- --app-covered: #7fc09a; --app-covered-bg: #1e2f26;
80
- --app-open: #e0ab5c; --app-open-bg: #33271a;
81
- --app-sunk: #241b18;
82
- --app-hairline: #392b26;
74
+ .dark {
75
+ --covered: #7fc09a;
76
+ --covered-bg: #1e2f26;
77
+ --open: #e0ab5c;
78
+ --open-bg: #33271a;
79
+ --sunk: #241b18;
80
+ }
81
+ @theme inline {
82
+ --color-covered: var(--covered);
83
+ --color-covered-bg: var(--covered-bg);
84
+ --color-open: var(--open);
85
+ --color-open-bg: var(--open-bg);
86
+ --color-sunk: var(--sunk);
83
87
  }
84
88
  ```
85
89
 
86
90
  Those values are one app's warm direction, not a palette to copy — derive your
87
- own from yours.
91
+ own from yours. Components then say `bg-covered-bg text-covered`.
88
92
 
89
93
  ## Choose the neutrals; do not inherit them
90
94
 
91
- The two details in that snippet that look like typos are the two things most
92
- likely to make your app look like every other app.
93
-
94
- **The hairline is a literal, not `var(--mantine-color-gray-2)`.** Mantine's grey
95
- ramp is blue-biased — `#f8f9fa`, `#dee2e6`, `#868e96` are all cool — and it is
96
- what draws card borders, dividers, the shell's edges and every disabled control.
97
- The theme JSON has `brand` and `structure` and **no neutral field at all**, so
98
- unless you choose otherwise, every app built from this skill runs its accent on
99
- somebody else's greys.
100
-
101
- If the accent is not itself blue, that mismatch lands on every screen at once:
102
- warm content ruled off in cold lines, off everywhere and wrong nowhere in
103
- particular, which is the hardest kind of wrong to find. It survives a careful
104
- critique because no single screen is broken.
105
-
106
- So bias the whole ramp toward the accent — not just the tokens with obvious
107
- names. Keep Mantine's lightness steps so contrast behaviour and every component
108
- that picks a step by number are unchanged; move only the hue:
109
-
110
- ```css
111
- /* The ramps: hue only. Mantine picks a step by number in either scheme, so
112
- these are scheme-independent and belong in the unscoped block. */
113
- :root:root:root {
114
- --mantine-color-gray-0: #faf7f5; --mantine-color-gray-5: #b8a49d;
115
- --mantine-color-gray-1: #f5efec; --mantine-color-gray-6: #93807a;
116
- --mantine-color-gray-2: #efe6e2; --mantine-color-gray-7: #574a45;
117
- --mantine-color-gray-3: #e6dad5; --mantine-color-gray-8: #3d332f;
118
- --mantine-color-gray-4: #d8c8c2; --mantine-color-gray-9: #2a1f1b;
119
- --mantine-color-dark-0: #f3e9e4; --mantine-color-dark-5: #4a3a34;
120
- --mantine-color-dark-1: #cdbdb6; --mantine-color-dark-6: #392b26;
121
- --mantine-color-dark-2: #a8938c; --mantine-color-dark-7: #241b18;
122
- --mantine-color-dark-3: #7a655e; --mantine-color-dark-8: #1b1512;
123
- --mantine-color-dark-4: #5c4a44; --mantine-color-dark-9: #120d0b;
124
- }
125
-
126
- /* Ground, text and border are a different colour in each scheme, so each one
127
- is set in the scheme it belongs to. A scheme-dependent token left in the
128
- block above is the classic unreadable-in-dark bug. */
129
- :root:root:root[data-mantine-color-scheme='light'] {
130
- --mantine-color-body: #fdfaf8;
131
- --mantine-color-text: #2a1f1b;
132
- --mantine-color-default-border: #ecdfd9;
133
- --mantine-color-dimmed: #7a625c; /* keep AA: ~5.4:1 on the body above */
134
- --mantine-color-placeholder: #826a64; /* ~4.8:1 */
135
- }
136
- :root:root:root[data-mantine-color-scheme='dark'] {
137
- --mantine-color-body: #1b1512;
138
- --mantine-color-text: #f3e9e4;
139
- --mantine-color-default-border: #392b26;
140
- --mantine-color-dimmed: #a8938c; /* ~5.6:1 on the body above */
141
- --mantine-color-placeholder: #8c7a74; /* ~4.7:1 */
142
- }
143
- ```
144
-
145
- Check the four text tokens against your own grounds rather than copying these —
146
- `dimmed` is the most-used text colour in the app and the easiest to drop below
147
- 4.5:1 while making it prettier, and it has to clear the bar on *both* grounds.
148
-
149
- **The selector is tripled on purpose.** Mantine's `cssVariablesResolver` injects
150
- its own `:root` block into `<head>` at runtime, which lands *after* your
151
- stylesheet and wins on source order at equal specificity. A plain `:root` here is
152
- silently reverted: the file reads correct, the app renders Mantine's defaults,
153
- and nothing errors. Repeating the pseudo-class raises specificity without adding
154
- an element to the selector.
155
-
156
- This one costs a whole pass if you meet it without knowing: you diagnose the
157
- colours correctly, write the right values, reload, and see no change — so you
158
- assume the diagnosis was wrong. **The only thing that catches it is looking at a
159
- screenshot and disbelieving the CSS.**
160
-
161
- Name them for what they *mean* in this product, never for the colour — `covered`,
162
- not `green`. The name is the whole value: it survives a change of palette, and it
163
- is the thing that makes the second use agree with the first. Define both colour
164
- schemes at once; a token defined only in light is the classic unreadable-in-dark
165
- bug, and Mantine will happily render it.
95
+ The theme generator derives the neutrals from the primary's hue, so the greys
96
+ already lean toward the accent. That only holds if the primary is chosen first:
97
+ change `brand.colors.primary`, regenerate theme.css, and look at a card
98
+ border against the page, because it is the neutrals that draw card borders,
99
+ dividers, the shell's edges and every disabled control.
100
+
101
+ If the accent is not blue and the greys still read cold, the mismatch lands on
102
+ every screen at once: warm content ruled off in cold lines, off everywhere and
103
+ wrong nowhere in particular, which is the hardest kind of wrong to find. It
104
+ survives a careful critique because no single screen is broken. Fix it in
105
+ `theme.css` inputs, not by overriding `border-gray-200` per component.
106
+
107
+ Check the text tokens against your own grounds rather than trusting them —
108
+ `--muted-foreground` is the most-used secondary text colour in the app and the
109
+ easiest to drop below 4.5:1 while making it prettier, and it has to clear the bar
110
+ on _both_ the light and `.dark` grounds.
111
+
112
+ Name the extra tokens for what they _mean_ in this product, never for the colour
113
+ — `covered`, not `green`. The name is the whole value: it survives a change of
114
+ palette, and it is the thing that makes the second use agree with the first.
115
+ Define both colour schemes at once; a token defined only in light is the classic
116
+ unreadable-in-dark bug.
166
117
 
167
118
  The same file is where a couple of other things belong that the theme JSON has no
168
- field for and every screen otherwise re-invents: the hairline that separates rows
169
- in a list, the recessed surface a form sits on so it does not carry the same
170
- weight as the content it adds to, and the one animation the product is allowed
171
- (behind `prefers-reduced-motion`). Two or three rules, not a framework.
119
+ field for and every screen otherwise re-invents: the recessed surface a form sits
120
+ on so it does not carry the same weight as the content it adds to, and the one
121
+ animation the product is allowed (behind `prefers-reduced-motion`). Two or three
122
+ rules, not a framework.
172
123
 
173
124
  If the app ships template screens you did not write — the error and not-found
174
- pages usually — read them before you call the palette done. They arrive with the
175
- scaffold's colours hardcoded, and a stock blue accent on an app whose direction
176
- says warm is the single loudest contradiction in the build.
125
+ pages usually — read them before you call the palette done. A stock accent on an
126
+ app whose direction says warm is the single loudest contradiction in the build.
177
127
 
178
128
  **Set the theme once, don't hardcode colours per component.** A screen full of
179
- inline `color="blue"` and one-off hex values is why apps look templated. Change
180
- the theme, not the components — and keep it theme-aware for light and dark.
129
+ inline hex values and `bg-blue-500` is why apps look templated. Change the theme,
130
+ not the components — and keep it theme-aware for light and dark.
181
131
 
182
132
  With two apps, **share the theme package and vary the register, not the
183
133
  palette.** A back-office can be denser and more tabular; a customer-facing app
184
134
  can be roomier and warmer — that is `structure` and layout, not a second `brand`.
185
135
  Two unrelated colour schemes read as two products from two companies.
186
136
 
187
-
188
137
  ## If the user gave you no direction
189
138
 
190
139
  Neutral is a legitimate answer for an internal tool. But say so out loud when you
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pikku-changes
3
- description: 'Work a project''s changes queue — the todo list someone filed by circling things on a deployed stage. Covers `pikku changes wait|claim|show|ask|reply|shot|done`: waiting for work without polling, asking instead of guessing, saying why an item is left undone, offering options as images, one commit per item. TRIGGER when: the user says "run the pikkufabric changes", "run the changes against <stage>", "work the changes (queue)", "watch the changes", "pick up the changes", names a change by its #number, or you are otherwise idle in a checkout with open changes (`pikku changes list`). DO NOT TRIGGER for git changes, diffs or changelogs, and not for deploying or debugging a stage — use pikku-fabric for those.'
3
+ description: 'Work a project''s changes queue — the todo list someone filed by circling things on a deployed stage. Covers `pikku changes wait|claim|show|ask|reply|shot|done`: waiting for work without polling, asking instead of guessing, saying why an item is left undone, offering options as images, one commit per item. TRIGGER when: the user says "run the pikkufabric changes", "run the changes against a stage", "work the changes (queue)", "watch the changes", "pick up the changes", names a change by its #number, or you are otherwise idle in a checkout with open changes (`pikku changes list`). DO NOT TRIGGER for git changes, diffs or changelogs, and not for deploying or debugging a stage — use pikku-fabric for those.'
4
4
  installGroups: [fabric]
5
5
  ---
6
6
 
@@ -11,8 +11,7 @@ screenshot of what they saw, and the elements the circle enclosed. You have the
11
11
  Empty the queue without making them regret filing.
12
12
 
13
13
  Run every command from the checkout. The queue lives in it (`.git/pikku-changes.json`, shared by every
14
- worktree).
15
- `--json` works on all of them. Items are addressed as `2`, `#2` or their uuid.
14
+ worktree). `--json` works on all of them. Items are addressed as `2`, `#2` or their uuid.
16
15
 
17
16
  **Launched by `pikku changes next`?** `pikku changes next` picks one agent: a merge conflict or a changeset with no plan
18
17
  goes back to a changes agent; open changes go to a changes agent; a pikku version bump goes to an
@@ -104,8 +103,8 @@ changeset declared no `--creates`/`--alters`.
104
103
 
105
104
  When other agents are working changesets at the same time (your work says so), claim with
106
105
  `--worktree`: it creates `changeset/<slug>` in its own checkout beside the repo and prints the path.
107
- Build and commit there and run `done` there; the merge removes the worktree. If the claim is refused because of a running changeset, claim one that does not
108
- clash, or stop.
106
+ Build and commit there and run `done` there; the merge removes the worktree. If the claim is refused
107
+ because of a running changeset, claim one that does not clash, or stop.
109
108
 
110
109
  ## Reading an item
111
110
 
@@ -184,7 +183,8 @@ Scope names the screen they were looking at, not the file you edited.
184
183
  pikku changes done --change-id 7 --note "What you did, for whoever reads the thread"
185
184
  ```
186
185
 
187
- Branch and commit default to the checkout you are in — run it there, never type a sha. `done` finds the item's commit by its `Change-Id` trailer, so close items in any order.
186
+ Branch and commit default to the checkout you are in — run it there, never type a sha. `done` finds
187
+ the item's commit by its `Change-Id` trailer, so close items in any order.
188
188
  An item you decided not to do is not `done`: `reply` with why and leave it for a
189
189
  human to dismiss.
190
190
 
@@ -13,9 +13,7 @@ installGroups: [core]
13
13
 
14
14
  # Pikku Framework Concepts
15
15
 
16
- ## Agent Operating Procedure
17
-
18
- Use this skill as an execution checklist, not reference material.
16
+ ## Operating procedure
19
17
 
20
18
  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
19
  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.
@@ -43,7 +41,7 @@ that will work anyway.
43
41
  pikku doc --ai
44
42
  ```
45
43
 
46
- ≈480 tokens, giving the 20 `#pikku/*` doors grouped by the job they do, and beside each the
44
+ Prints the `#pikku/*` doors, grouped by the job they do, and beside each the
47
45
  skill that teaches it. Read that routing table as the index to every other pikku skill — it is
48
46
  generated from the installed version, so it never names a skill for a door that no longer exists.
49
47
 
@@ -148,7 +146,7 @@ pikkuFunc (pure business logic)
148
146
  ├── wireChannel → WebSocket (real-time)
149
147
  ├── wireQueueWorker → BullMQ, PgBoss (async jobs)
150
148
  ├── wireScheduler → Cron (scheduled tasks)
151
- ├── wireMCPTool → Model Context Protocol (AI tools)
149
+ ├── mcp: true → Model Context Protocol (AI tools; an option on the function, no wire call)
152
150
  ├── wireCLI → CLI commands
153
151
  ├── wireTrigger → Event-driven (Redis pub/sub, PG LISTEN/NOTIFY)
154
152
  ├── pikkuAgent → AI agents / chatbots
@@ -162,6 +160,8 @@ A `pikkuFunc` receives three things:
162
160
  2. **Data** — input from any source (HTTP body/query/params, WS message, queue payload, CLI args)
163
161
  3. **Wire** — transport context (session, channel, rpc, mcp, http, queue)
164
162
 
163
+ **MCP tools:** always set `mcp: true` on the normal function; HTTP, RPC and agents can still call it. The one exception is wrapping an EXISTING function as an AI tool purely to reshape its data: use `pikkuMCPToolFunc` (calls the original via `rpc.invoke`), which makes the wrapper MCP-only. The alternative is a second normal function with `mcp: true`. See `pikku-wiring`.
164
+
165
165
  The function never imports Express, never reads `req.body`, never touches `ws.send()`. It just works with typed data and services.
166
166
 
167
167
  ## Concept Mapping: Generic Backend → Pikku
@@ -353,7 +353,7 @@ src/
353
353
  ## What Language You Write In
354
354
 
355
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:
356
+ language. Collapsing them is the common mistake:
357
357
 
358
358
  | Axis | Covers | Decided by |
359
359
  | --------------- | ----------------------------------------------------------------------------- | ---------------------------------------------- |
@@ -370,8 +370,8 @@ language is cloned from.
370
370
 
371
371
  **When a brief tells you the product speaks a language, it is telling you about the third axis and
372
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.
373
+ failure to avoid: reading one sentence about a product's users as an instruction about its codebase
374
+ (German RPC names, German tables, no English catalogue to translate from).
375
375
 
376
376
  ## Environment Variables
377
377
 
@@ -408,12 +408,3 @@ expect(result.todos).toHaveLength(3)
408
408
  ## Available Packages
409
409
 
410
410
  Pikku ships runtime adapters (`@pikku/express-server`, `@pikku/fastify-server`, `@pikku/next`, `@pikku/aws-lambda`, `@pikku/cloudflare`, `@pikku/uws-server`, `@pikku/modelcontextprotocol`, ...) and service packages (`@pikku/jose`, `@pikku/schema-ajv`, `@pikku/pino`, `@pikku/kysely`, `@pikku/redis`, `@pikku/queue-bullmq`, `@pikku/queue-pg-boss`, ...). For the full list with use cases, read `references/packages.md`.
411
-
412
- ## Key Differences from Traditional Frameworks
413
-
414
- 1. **No decorators** — plain functions + explicit wiring, not `@Get()` or `@Injectable()`
415
- 2. **No classes required** — everything is functions and objects
416
- 3. **Transport is configuration, not code** — business logic doesn't know about HTTP/WS/etc.
417
- 4. **One function, many transports** — same function can serve HTTP, WebSocket, queue, and MCP simultaneously
418
- 5. **Generated type safety** — clients are auto-generated with full types, not manually maintained
419
- 6. **Schema-first validation** — Standard Schema (Zod/Valibot) replaces class-validator decorators
@@ -1,5 +1,23 @@
1
1
  # Concept Mapping: Generic Backend → Pikku
2
2
 
3
+ ## Contents
4
+
5
+ - Quick Reference Table
6
+ - Route Handler / Controller
7
+ - Route Parameters
8
+ - Middleware
9
+ - Auth Guard
10
+ - Authorization / Role Checks
11
+ - DTO / Request Validation
12
+ - Dependency Injection
13
+ - WebSocket Handlers
14
+ - Job Queue Workers
15
+ - Cron / Scheduled Tasks
16
+ - Module / Feature Grouping
17
+ - Error Handling
18
+ - Session Management
19
+ - API Client Generation
20
+
3
21
  Authoritative mapping table plus side-by-side code examples showing how common backend patterns translate to Pikku.
4
22
 
5
23
  - [Quick Reference Table](#quick-reference-table)
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: pikku-convert-screen
3
+ description: Use when an old screen, page or feature (from an old console, another repo, screenshots, or a description) has to be rebuilt in the current app. Extracts what it does as plain business logic, with no layout or code detail, then designs it fresh in the current design system. TRIGGER on "convert this screen", "port the old console page", "we had this before, bring it back", "redesign X from the old console". DO NOT TRIGGER for whole-repo reverse engineering (use pikku-software-archaeology) or for restyling a screen that already exists in the app.
4
+ installGroups: [core]
5
+ ---
6
+
7
+ # Convert a screen
8
+
9
+ Keep what the screen does. Drop how it looked and how it was built.
10
+
11
+ ## 1. Read the old thing
12
+
13
+ Use whatever is given: a path, a repo, screenshots, a recording, a description. For code, read the page, its hooks, the RPCs or endpoints behind it and any tests. For images, read the labels and states, not the styling. Check whether the app already has it under another name before starting.
14
+
15
+ ## 2. Write the spec
16
+
17
+ Save it as `docs/screens/<name>.md`. Business logic only.
18
+
19
+ - Who uses it and what they are trying to get done.
20
+ - What they can see, in the words a non-technical owner would use.
21
+ - Every action: what triggers it, what must be true first, what changes, what the person is told afterwards.
22
+ - Rules and limits: who may do it, what is refused and why.
23
+ - States: empty, loading, working, done, failed. For each failure, what the person can do next.
24
+ - Data it needs and which existing RPCs provide it. Mark any that are missing.
25
+ - Things you were unsure of, marked as open questions. Never present a guess as fact.
26
+
27
+ Leave out: component names, layout, colours, spacing, library names, file structure, modals versus drawers, table versus cards. If a sentence only makes sense by picturing the old UI, rewrite it.
28
+
29
+ Stop and show the spec. Do not design until it is agreed.
30
+
31
+ ## 3. Build it in the current design system
32
+
33
+ Design from the spec, not from the old screen. Never copy old markup or styles.
34
+
35
+ - Read the project design system (`DESIGN.md`, theme tokens) and the nearest existing screens first. Match their header, spacing, buttons and wording.
36
+ - Use the components the project already uses. No modal dialogs: forms go in the side panel or a new page.
37
+ - Plain words. The client's own vocabulary, never internal jargon.
38
+ - Every error says what happened in plain terms and offers a way out, with an AI fix where it makes sense.
39
+ - No static data. The screen reads through RPC hooks only. Data a function does not return yet comes from `.mocks/` through the stub hooks (see the pikku-build skill, mocks reference), with a populated, an empty and an error scenario.
40
+ - The same component serves every data state: real, mocked or stubbed.
41
+ - Add the route and a rail entry only where the spec says people reach it.
42
+
43
+ ## 4. Check against the spec
44
+
45
+ Walk the spec line by line against the running screen, including the empty and failed states. Say which lines are met, which are not, and which depend on RPCs that do not exist yet. Capture a screenshot from the running screen.
@@ -1,5 +1,13 @@
1
1
  # Cloudflare Workers
2
2
 
3
+ ## Contents
4
+
5
+ - Worker entry
6
+ - Service setup — do not hand-roll this
7
+ - HTTP
8
+ - Scheduled tasks
9
+ - WebSocket (Durable Objects)
10
+
3
11
  ```bash
4
12
  yarn add @pikku/cloudflare
5
13
  ```
@@ -1,5 +1,13 @@
1
1
  # AWS Lambda
2
2
 
3
+ ## Contents
4
+
5
+ - Cold start pattern
6
+ - HTTP handler
7
+ - Scheduled tasks
8
+ - SQS queue worker
9
+ - WebSocket (API Gateway v2)
10
+
3
11
  ```bash
4
12
  yarn add @pikku/lambda
5
13
  ```
@@ -69,4 +69,4 @@ app.ws('/*', pikkuWebsocketHandler({ logger, logRoutes: true }))
69
69
 
70
70
  Both take `{ logger, logRoutes?, loadSchemas? } & RunHTTPWiringOptions`.
71
71
 
72
- For a WebSocket-only server on the `ws` library instead, see `ws.md`.
72
+ For a WebSocket-only server on the `ws` library instead, use the `ws` runtime.
@@ -2,9 +2,9 @@
2
2
 
3
3
  `@pikku/ws` connects Pikku's channel system to a Node.js WebSocket server built
4
4
  on the [ws](https://github.com/websockets/ws) library. Use it for a
5
- WebSocket-only server; for HTTP and WebSocket on one port see `uws.md`, and when
6
- the WebSocket server shares a port with an existing HTTP app see `express.md` or
7
- `fastify.md`.
5
+ WebSocket-only server; for HTTP and WebSocket on one port use the uWebSockets.js runtime, and when
6
+ the WebSocket server shares a port with an existing HTTP app use the Express or
7
+ Fastify runtime.
8
8
 
9
9
  ```bash
10
10
  yarn add @pikku/ws ws
@@ -1,15 +1,9 @@
1
1
  ---
2
2
  name: pikku-emails
3
3
  description: >-
4
- Use when working with Pikku's file-based email templates: authoring HTML/subject/text templates,
5
- locales, partials and theme, running `pikku emails generate`, and rendering/sending them through
6
- an EmailService. TRIGGER when: code uses renderEmailTemplate, EmailTemplateName, EmailService,
7
- SendTemplateEmailInput, LocalEmailService, or imports from .pikku/email/pikku-emails.gen.
8
- TRIGGER when: the project has an emails/ directory (templates/, locales/, partials/, theme.json)
9
- or emailTemplatesDir in pikku.config.json. TRIGGER when: user asks to add/edit a transactional
10
- email (verification, password reset, invitation, receipt), wire email sending, or translate an
11
- email. DO NOT TRIGGER when: user asks about i18n for the app UI (use pikku-i18n) or auth flows
12
- in general (use pikku-auth).
4
+ Use when working with Pikku's file-based email templates: authoring html, subject and text templates, locales, partials and theme, running `pikku emails generate`, and rendering and sending them through an EmailService.
5
+ TRIGGER when: code uses renderEmailTemplate, EmailTemplateName, EmailService, SendTemplateEmailInput or LocalEmailService, or imports from .pikku/email/pikku-emails.gen; the project has an emails/ directory (templates/, locales/, partials/, theme.json) or emailTemplatesDir in pikku.config.json; or the user asks to add, edit or translate a transactional email (verification, password reset, invitation, receipt) or wire email sending.
6
+ DO NOT TRIGGER when: the task is i18n for the app UI (use pikku-i18n) or sign-in flows in general (use pikku-auth).
13
7
  installGroups: [core]
14
8
  ---
15
9