@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,190 +1,139 @@
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.
6
13
 
7
- Nothing in the open-source toolchain authors a theme for you. Fabric has the
8
- `fabric-theme` tool; without it, hand-authoring is the route, and it is a small
14
+ Nothing in the open-source toolchain authors a theme for you. A hosting
15
+ platform may offer a theme tool; without it, hand-authoring is the route, and it is a small
9
16
  job done in JSON.
10
17
 
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,7 +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.'
4
- installGroups: [fabric]
3
+ description: 'Work a project''s changes queue — the todo list someone filed by circling things in the running app. 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 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.'
5
4
  ---
6
5
 
7
6
  # Working a changes queue
@@ -11,8 +10,7 @@ screenshot of what they saw, and the elements the circle enclosed. You have the
11
10
  Empty the queue without making them regret filing.
12
11
 
13
12
  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.
13
+ worktree). `--json` works on all of them. Items are addressed as `2`, `#2` or their uuid.
16
14
 
17
15
  **Launched by `pikku changes next`?** `pikku changes next` picks one agent: a merge conflict or a changeset with no plan
18
16
  goes back to a changes agent; open changes go to a changes agent; a pikku version bump goes to an
@@ -45,7 +43,7 @@ something changed. `wait` does the waiting and exits only when there is work.
45
43
  | ---- | ------------------------------------------------------ | ----------------------------------------------- |
46
44
  | 0 | work printed (claimed, and/or `Answered`) | work it, then step 3 |
47
45
  | 2 | `--timeout`/`--once` found nothing | stop, or restart `wait` |
48
- | 3 | session refused | tell the user to run `pikku fabric login`; stop |
46
+ | 3 | auth refused | relay the CLI's message; stop |
49
47
  | 1 | anything else | report the message; stop |
50
48
 
51
49
  3. For each item: `show` → fix → commit → `done`; or `ask` and move on; or `reply`
@@ -104,8 +102,8 @@ changeset declared no `--creates`/`--alters`.
104
102
 
105
103
  When other agents are working changesets at the same time (your work says so), claim with
106
104
  `--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.
105
+ Build and commit there and run `done` there; the merge removes the worktree. If the claim is refused
106
+ because of a running changeset, claim one that does not clash, or stop.
109
107
 
110
108
  ## Reading an item
111
109
 
@@ -184,8 +182,7 @@ Scope names the screen they were looking at, not the file you edited.
184
182
  pikku changes done --change-id 7 --note "What you did, for whoever reads the thread"
185
183
  ```
186
184
 
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.
185
+ Branch and commit default to the checkout you are in — run it there, never type a sha. `done` finds
186
+ the item's commit by its `Change-Id` trailer, so close items in any order.
188
187
  An item you decided not to do is not `done`: `reply` with why and leave it for a
189
188
  human to dismiss.
190
-
191
- Registering writes with Fabric needs the `changes:project:write` scope.
@@ -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
 
@@ -67,7 +65,7 @@ which is what decides whether a thrown error becomes a 409 or a 500.
67
65
 
68
66
  - **Worked examples are sparse.** Most exports show a signature and keys, not usage.
69
67
  - **`pikkuFunc` lists keys that belong elsewhere.** `before`, `after`, `skip`, `surfaces` and
70
- `requiresActor` apply only to scenarios; `workflowQueued`, `workflowRetries` and
68
+ `requiresVirtualUser` apply only to scenarios; `workflowQueued`, `workflowRetries` and
71
69
  `workflowTimeout` only to a workflow step. One shared config type offers all of them to
72
70
  every function — each key says which it belongs to.
73
71
 
@@ -98,35 +96,34 @@ flags; the "Read" column is the skill that teaches the thing, where one does.
98
96
 
99
97
  **Running**
100
98
 
101
- | Command | What it does | Read |
102
- | ---------------------------- | ------------------------------------------------------------------------------ | --------------------------------------- |
103
- | `dev` | Local dev server, all services wired, watch + HMR | `pikku-build` |
104
- | `serve` | Bundled bun/node runner — no watch, no codegen | `pikku-deploy` |
105
- | `watch` | Regenerate on file change, without a server | — |
106
- | `scenario list\|run` | Scenarios as e2e tests and health checks | `pikku-scenario` |
107
- | `persona run` | A declared persona as a model-driven virtual user against a stage | `pikku-scenario`, persona-run reference |
108
- | `persona list\|sync\|secret` | Who is declared; what an environment will provision; minting their credentials | `pikku-scenario`, persona-run reference |
109
- | `db` | Local development database | `pikku-kysely` |
99
+ | Command | What it does | Read |
100
+ | --------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------- |
101
+ | `dev` | Local dev server, all services wired, watch + HMR | `pikku-build` |
102
+ | `serve` | Bundled bun/node runner — no watch, no codegen | `pikku-deploy` |
103
+ | `watch` | Regenerate on file change, without a server | — |
104
+ | `scenario list\|run` | Scenarios as e2e tests and health checks | `pikku-scenario` |
105
+ | `virtual-user run` | A declared virtual user, model-driven, against a stage | `pikku-scenario`, virtual-user-run reference |
106
+ | `virtual-user list\|sync\|secret` | Who is declared; what an environment will provision; minting their credentials | `pikku-scenario`, virtual-user-run reference |
107
+ | `db` | Local development database | `pikku-kysely` |
110
108
 
111
109
  **Inspecting and evolving**
112
110
 
113
- | Command | What it does | Read |
114
- | --------------------- | ----------------------------------------------------------------------- | ---------------------------- |
115
- | `doc` | The installed API surface | this skill |
116
- | `meta` / `info` | What the project declares, machine- and human-readable | `pikku-meta` |
117
- | `validate` | Every check that applies — app structure, an addon's published file set | `pikku-build`, `pikku-addon` |
118
- | `versions` / `release` | Contract hashes, breaking-change detection, versioned releases | `pikku-meta` |
119
- | `audit` / `update` | Advisories; which `@pikku/*` can move and what peers that needs | `pikku-meta` |
120
- | `scopes` / `roles` | Declared authorization scopes; roles from `defineSystemRole` | `pikku-auth` |
121
- | `knowledge` | The knowledge base — what this app is, in its users' language | `pikku-knowledge` |
122
- | `emails` | Email template generation | `pikku-emails` |
111
+ | Command | What it does | Read |
112
+ | ---------------------- | ----------------------------------------------------------------------- | ---------------------------- |
113
+ | `doc` | The installed API surface | this skill |
114
+ | `meta` / `info` | What the project declares, machine- and human-readable | `pikku-meta` |
115
+ | `validate` | Every check that applies — app structure, an addon's published file set | `pikku-build`, `pikku-addon` |
116
+ | `versions` / `release` | Contract hashes, breaking-change detection, versioned releases | `pikku-meta` |
117
+ | `audit` / `update` | Advisories; which `@pikku/*` can move and what peers that needs | `pikku-meta` |
118
+ | `scopes` / `roles` | Declared authorization scopes; roles from `defineSystemRole` | `pikku-auth` |
119
+ | `knowledge` | The knowledge base — what this app is, in its users' language | `pikku-knowledge` |
120
+ | `emails` | Email template generation | `pikku-emails` |
123
121
 
124
122
  **Shipping, and the CLI itself**
125
123
 
126
124
  | Command | What it does | Read |
127
125
  | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
128
126
  | `deploy` | Deploy to cloud infrastructure | `pikku-deploy` |
129
- | `fabric` | PikkuFabric: login, link, deploy, domains, secrets, logs | `pikku-fabric` |
130
127
  | `binary` | Compile an entrypoint to a native binary (`bun build --compile`) | — |
131
128
  | `dist` | Copy what `tsc` cannot emit — `.gen.json` meta, hand-authored `.d.ts` — into the build output. Run it after `tsc`, as a package's build script | — |
132
129
  | `login` / `logout` / `whoami` | The CLI's session against a pikku server | — |
@@ -148,7 +145,7 @@ pikkuFunc (pure business logic)
148
145
  ├── wireChannel → WebSocket (real-time)
149
146
  ├── wireQueueWorker → BullMQ, PgBoss (async jobs)
150
147
  ├── wireScheduler → Cron (scheduled tasks)
151
- ├── wireMCPTool → Model Context Protocol (AI tools)
148
+ ├── mcp: true → Model Context Protocol (AI tools; an option on the function, no wire call)
152
149
  ├── wireCLI → CLI commands
153
150
  ├── wireTrigger → Event-driven (Redis pub/sub, PG LISTEN/NOTIFY)
154
151
  ├── pikkuAgent → AI agents / chatbots
@@ -162,6 +159,8 @@ A `pikkuFunc` receives three things:
162
159
  2. **Data** — input from any source (HTTP body/query/params, WS message, queue payload, CLI args)
163
160
  3. **Wire** — transport context (session, channel, rpc, mcp, http, queue)
164
161
 
162
+ **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`.
163
+
165
164
  The function never imports Express, never reads `req.body`, never touches `ws.send()`. It just works with typed data and services.
166
165
 
167
166
  ## Concept Mapping: Generic Backend → Pikku
@@ -298,7 +297,7 @@ a Workers or serverless stage needs done belongs on the request path that needs
298
297
  where Pikku is embedded in a server you own. Lifecycle hooks do not run on this path; do the
299
298
  startup work in the entrypoint.
300
299
 
301
- `pikku validate` warns when a project starts a server by hand *and* depends on no runtime adapter,
300
+ `pikku validate` warns when a project starts a server by hand _and_ depends on no runtime adapter,
302
301
  because that means the first path was available and unused.
303
302
 
304
303
  **`references/bootstrap.md`** has both entrypoints in full.
@@ -353,25 +352,25 @@ src/
353
352
  ## What Language You Write In
354
353
 
355
354
  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:
355
+ language. Collapsing them is the common mistake:
357
356
 
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`) |
357
+ | Axis | Covers | Decided by |
358
+ | --------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------- |
359
+ | **Identifiers** | Function, component, type and file names; tables and columns; commit messages | Nothing. **Always English.** There is no setting |
360
+ | **Meta** | Prose authored inside the code — `description`, `title`, step `template` | `metaLocale` in `pikku.config.json` (default `en`) |
362
361
  | **Product UI** | Every string the app shows a user | `messages/<locale>.json`, and `active.json`'s `defaultLocale` |
363
362
 
364
363
  Identifiers are the surface every other tool binds to — the generated clients, the RPC map a
365
364
  scenario is typed over, the SQL types — and unlike a string an identifier cannot be translated
366
365
  later: renaming one is a migration. `metaLocale` exists so a team can read their own Console in
367
366
  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
367
+ `project.inlang/settings.json` stays `en`, because it names the message _source_ every other
369
368
  language is cloned from.
370
369
 
371
370
  **When a brief tells you the product speaks a language, it is telling you about the third axis and
372
371
  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.
372
+ failure to avoid: reading one sentence about a product's users as an instruction about its codebase
373
+ (German RPC names, German tables, no English catalogue to translate from).
375
374
 
376
375
  ## Environment Variables
377
376
 
@@ -408,12 +407,3 @@ expect(result.todos).toHaveLength(3)
408
407
  ## Available Packages
409
408
 
410
409
  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)
@@ -5,11 +5,11 @@ Three different things in a Pikku project have a human language, and they are
5
5
  prevent, and it has already shipped in a real product — the failure is at the
6
6
  bottom.
7
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. |
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/virtual-user 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
13
 
14
14
  ## Identifiers are English, and nothing changes that
15
15
 
@@ -19,7 +19,7 @@ all get `getOverview`, `AttentionStripe`, `case`, `event`.
19
19
 
20
20
  This is not linguistic preference, it is mechanics. Identifiers are the surface
21
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
22
+ `pikku meta`, the RPC map a scenario's `virtualUser.invoke` is typed over, the
23
23
  generated SQL types, every skill and every agent that ever picks the project up.
24
24
  A `vorgang` table types as `Vorgang` in Kysely and reads as noise to everyone who
25
25
  did not name it, and unlike a string it cannot be translated later — renaming an
@@ -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
  ```
@@ -88,7 +88,7 @@ route definitions.
88
88
 
89
89
  - **`PikkuNextJSWorkerRPC({ fetcher })`** — same surface as `PikkuNextJS`, but
90
90
  every call is dispatched through a `Fetcher` (a Cloudflare service binding, a
91
- local HTTP client, a fabric dispatcher) instead of loading function code
91
+ local HTTP client, a dispatcher worker) instead of loading function code
92
92
  in-process. Use it to keep functions out of the SSR bundle. A non-2xx response
93
93
  throws with the status and body text.
94
94
  - **`toNextJsAuthHandler(auth)`** — wraps a better-auth instance or handler