@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.
- package/README.md +1 -1
- package/dist/skills.gen.js +2 -2
- package/dist/snippets.js +1 -1
- package/package.json +1 -1
- package/skills/pikku-a11y/SKILL.md +22 -15
- package/skills/pikku-addon/SKILL.md +5 -5
- package/skills/pikku-addon/references/addon-package-manifest.md +7 -0
- package/skills/pikku-addon/references/openapi.md +11 -0
- package/skills/pikku-agent/SKILL.md +6 -6
- package/skills/pikku-agent/references/agents.md +8 -1
- package/skills/pikku-agent/references/runner-vercel.md +2 -2
- package/skills/pikku-agent/references/voice.md +7 -1
- package/skills/pikku-architect/SKILL.md +2 -2
- package/skills/pikku-architect/references/plan-defects.md +9 -7
- package/skills/pikku-auth/SKILL.md +15 -36
- package/skills/pikku-auth/references/better-auth.md +106 -133
- package/skills/pikku-auth/references/jose.md +6 -0
- package/skills/pikku-auth/references/machine-auth.md +6 -0
- package/skills/pikku-auth/references/sessions.md +6 -0
- package/skills/pikku-build/SKILL.md +37 -34
- package/skills/pikku-build/references/app.md +113 -99
- package/skills/pikku-build/references/design.md +43 -31
- package/skills/pikku-build/references/feature.md +17 -3
- package/skills/pikku-build/references/mocks.md +29 -0
- package/skills/pikku-build/references/multi-app.md +25 -18
- package/skills/pikku-build/references/native-app.md +9 -0
- package/skills/pikku-build/references/openapi.md +41 -34
- package/skills/pikku-build/references/platform.md +23 -14
- package/skills/pikku-build/references/post-clone.md +1 -1
- package/skills/pikku-build/references/quick.md +76 -39
- package/skills/pikku-build/references/scenarios.md +28 -16
- package/skills/pikku-build/references/ship.md +19 -16
- package/skills/pikku-build/references/theming.md +76 -127
- package/skills/pikku-changes/SKILL.md +7 -10
- package/skills/pikku-concepts/SKILL.md +34 -44
- package/skills/pikku-concepts/references/concept-mapping.md +18 -0
- package/skills/pikku-concepts/references/language.md +6 -6
- package/skills/pikku-convert-screen/SKILL.md +45 -0
- package/skills/pikku-deploy/references/cloudflare.md +8 -0
- package/skills/pikku-deploy/references/lambda.md +8 -0
- package/skills/pikku-deploy/references/nextjs.md +1 -1
- package/skills/pikku-deploy/references/uws.md +1 -1
- package/skills/pikku-deploy/references/ws.md +3 -3
- package/skills/pikku-emails/SKILL.md +3 -9
- package/skills/pikku-guide/SKILL.md +28 -27
- package/skills/pikku-i18n/SKILL.md +7 -7
- package/skills/pikku-i18n/references/enum-labels.md +9 -0
- package/skills/pikku-i18n/references/messages.md +21 -9
- package/skills/pikku-i18n/references/rtl.md +18 -38
- package/skills/pikku-knowledge/SKILL.md +12 -13
- package/skills/pikku-kysely/SKILL.md +3 -21
- package/skills/pikku-list-query/SKILL.md +2 -2
- package/skills/pikku-meta/references/audit.md +10 -1
- package/skills/pikku-meta/references/meta.md +6 -0
- package/skills/pikku-meta/references/versioning.md +10 -0
- package/skills/pikku-middleware/SKILL.md +7 -16
- package/skills/pikku-n8n-import/SKILL.md +9 -1
- package/skills/pikku-n8n-import/references/addon-mapping.md +6 -0
- package/skills/pikku-n8n-import/references/code-translation.md +7 -0
- package/skills/pikku-permissions/SKILL.md +41 -10
- package/skills/pikku-permissions/references/scopes.md +59 -0
- package/skills/pikku-react/SKILL.md +20 -22
- package/skills/pikku-react/references/client.md +2 -70
- package/skills/pikku-react/references/react-query.md +11 -0
- package/skills/pikku-react/references/workflows.md +11 -0
- package/skills/pikku-realtime/SKILL.md +9 -3
- package/skills/pikku-report/SKILL.md +17 -16
- package/skills/pikku-scenario/SKILL.md +72 -81
- package/skills/pikku-scenario/references/browser.md +5 -5
- package/skills/pikku-scenario/references/coverage.md +4 -4
- package/skills/pikku-scenario/references/steps.md +31 -30
- package/skills/pikku-scenario/references/{persona-run.md → virtual-user-run.md} +47 -42
- package/skills/pikku-scenario/references/virtual-users.md +114 -0
- package/skills/pikku-seo/SKILL.md +12 -16
- package/skills/pikku-service-backends/SKILL.md +0 -10
- package/skills/pikku-service-backends/references/aws.md +6 -0
- package/skills/pikku-service-backends/references/mongodb.md +7 -0
- package/skills/pikku-service-backends/references/redis.md +6 -0
- package/skills/pikku-services/references/audit-wire-service.md +2 -2
- package/skills/pikku-services/references/audit.md +10 -1
- package/skills/pikku-services/references/config.md +6 -0
- package/skills/pikku-services/references/services.md +9 -2
- package/skills/pikku-software-archaeology/SKILL.md +21 -27
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +16 -16
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +3 -3
- package/skills/pikku-software-archaeology/references/second-opinion.md +13 -1
- package/skills/pikku-tailwind/SKILL.md +111 -0
- package/skills/pikku-theme/SKILL.md +187 -0
- package/skills/pikku-theme/references/from-a-reference.md +44 -0
- package/skills/pikku-theme/references/presets.md +40 -0
- package/skills/pikku-ui/SKILL.md +41 -0
- package/skills/pikku-wiring/SKILL.md +13 -12
- package/skills/pikku-wiring/references/channel.md +7 -1
- package/skills/pikku-wiring/references/cli.md +7 -1
- package/skills/pikku-wiring/references/gateway-slack.md +6 -0
- package/skills/pikku-wiring/references/http.md +10 -3
- package/skills/pikku-wiring/references/mcp.md +8 -0
- package/skills/pikku-wiring/references/queue.md +6 -0
- package/skills/pikku-wiring/references/realtime.md +34 -4
- package/skills/pikku-wiring/references/rpc.md +6 -0
- package/skills/pikku-wiring/references/scheduler.md +6 -0
- package/skills/pikku-wiring/references/trigger.md +8 -0
- package/skills/pikku-workflow/SKILL.md +9 -7
- package/skills/pikku-admin-to-fabric/SKILL.md +0 -212
- package/skills/pikku-auth/references/permissions.md +0 -261
- package/skills/pikku-blueprint-to-fabric/SKILL.md +0 -377
- package/skills/pikku-blueprint-to-fabric/scripts/inventory.mjs +0 -367
- package/skills/pikku-fabric/SKILL.md +0 -619
- package/skills/pikku-fabric/references/debugging.md +0 -110
- package/skills/pikku-mantine/SKILL.md +0 -80
- package/skills/pikku-scenario/references/personas.md +0 -117
- 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.
|
|
8
|
-
|
|
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/
|
|
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
|
-
|
|
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,
|
|
24
|
-
|
|
25
|
-
`
|
|
26
|
-
|
|
27
|
-
|
|
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`
|
|
37
|
-
|
|
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`
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
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
|
|
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
|
|
69
|
-
|
|
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
|
|
73
|
-
--
|
|
74
|
-
--
|
|
75
|
-
--
|
|
76
|
-
--
|
|
67
|
+
:root {
|
|
68
|
+
--covered: #3f7d5c;
|
|
69
|
+
--covered-bg: #e6f1ea;
|
|
70
|
+
--open: #a8701a;
|
|
71
|
+
--open-bg: #fbeedb;
|
|
72
|
+
--sunk: #fdf7f4;
|
|
77
73
|
}
|
|
78
|
-
|
|
79
|
-
--
|
|
80
|
-
--
|
|
81
|
-
--
|
|
82
|
-
--
|
|
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
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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.
|
|
175
|
-
|
|
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
|
|
180
|
-
|
|
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
|
|
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 |
|
|
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
|
|
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
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
`
|
|
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
|
|
102
|
-
|
|
|
103
|
-
| `dev`
|
|
104
|
-
| `serve`
|
|
105
|
-
| `watch`
|
|
106
|
-
| `scenario list\|run`
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `db`
|
|
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
|
|
114
|
-
|
|
|
115
|
-
| `doc`
|
|
116
|
-
| `meta` / `info`
|
|
117
|
-
| `validate`
|
|
118
|
-
| `versions` / `release` | Contract hashes, breaking-change detection, versioned releases
|
|
119
|
-
| `audit` / `update`
|
|
120
|
-
| `scopes` / `roles`
|
|
121
|
-
| `knowledge`
|
|
122
|
-
| `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
|
-
├──
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
374
|
-
RPC names, German tables,
|
|
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
|
|
9
|
-
| --------------- |
|
|
10
|
-
| **Identifiers** | Function, component, type, variable and file names. Database tables and columns. Branch names and commit messages.
|
|
11
|
-
| **Meta** | The prose authored _inside_ the code: `description` on functions and steps, `name`/`title` on features and scenarios, step `template`, role/
|
|
12
|
-
| **Product UI** | Every string the app shows a user.
|
|
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 `
|
|
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.
|
|
@@ -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
|
|
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
|