@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,5 +1,17 @@
|
|
|
1
1
|
# Design
|
|
2
2
|
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Commit to a direction before the first screen
|
|
6
|
+
- Offer to draw the screens before you build them
|
|
7
|
+
- One screen, designed properly, before the rest exist
|
|
8
|
+
- Judge it — and don't grade your own homework
|
|
9
|
+
- The kit is a floor, not a ceiling
|
|
10
|
+
- Design is a gate on the changeset, not a phase at the end
|
|
11
|
+
- Facts, not taste
|
|
12
|
+
- Two screens that get skipped
|
|
13
|
+
- Symptoms of a screen nobody designed
|
|
14
|
+
|
|
3
15
|
Your job here is to design something worth the product — not to apply a house
|
|
4
16
|
style. **There is no house style, and this file is not one.** Two apps built from
|
|
5
17
|
this skill should not look like each other; if they do, something has gone wrong
|
|
@@ -16,14 +28,14 @@ nearest to hand, on every screen, in every app. Not because it lacks taste, but
|
|
|
16
28
|
because there is nothing to be wrong against. A direction fixes that: state one,
|
|
17
29
|
in words, before any screen exists.
|
|
18
30
|
|
|
19
|
-
Say what this product
|
|
31
|
+
Say what this product _is_ — its register, its reference points, what it feels
|
|
20
32
|
like to use, what it is deliberately not. "A warm, food-forward thing you use
|
|
21
33
|
standing at an open fridge door, closer to a recipe card than to a dashboard, and
|
|
22
34
|
never clinical" is a direction. "Clean and modern" is not — it rules nothing out,
|
|
23
35
|
so it cannot be departed from.
|
|
24
36
|
|
|
25
37
|
Write it to `knowledge/decisions/design/`, then build the theme from it
|
|
26
|
-
(
|
|
38
|
+
(the theming reference, see SKILL.md). **From that point you are accountable to your own
|
|
27
39
|
direction, not to this file.** That is the whole mechanism: the freedom is real,
|
|
28
40
|
and so is the commitment.
|
|
29
41
|
|
|
@@ -34,13 +46,13 @@ chosen — it has been defaulted to in words instead of in components.
|
|
|
34
46
|
|
|
35
47
|
Being ambitious is easier against a list of specific things to not be. Generated
|
|
36
48
|
interfaces cluster hard, and these are the attractors — not because any is ugly,
|
|
37
|
-
but because arriving at one
|
|
49
|
+
but because arriving at one _by default_ means no choice was made:
|
|
38
50
|
|
|
39
|
-
- **Stock
|
|
51
|
+
- **Stock component-library defaults.** The strongest pull, and the hardest to see: a component
|
|
40
52
|
library's untouched defaults do not look broken, they look finished. Blue
|
|
41
|
-
accent,
|
|
53
|
+
accent, grey borders, one radius on everything, `Card` + stacked text
|
|
42
54
|
down every page. An app can be entirely this and never trip a critique, because
|
|
43
|
-
nothing on any screen is
|
|
55
|
+
nothing on any screen is _wrong_.
|
|
44
56
|
- Warm cream ground with a serif display face and a terracotta accent.
|
|
45
57
|
- Near-black with one acid-green or vermilion pop.
|
|
46
58
|
- A purple-to-blue gradient header on white.
|
|
@@ -71,29 +83,29 @@ screens costs a fraction of eight built screens, and it is the only point where
|
|
|
71
83
|
"that is not what I meant" is free.
|
|
72
84
|
|
|
73
85
|
**Author the theme first, then draw the mock from it.** This order is the whole
|
|
74
|
-
point. A beautiful page in hand-rolled CSS sets a bar
|
|
86
|
+
point. A beautiful page in hand-rolled CSS sets a bar the real components then miss, and
|
|
75
87
|
what the user approved is not what ships — they signed off on a picture and
|
|
76
88
|
received an approximation of it. So write `themes/<name>.json` first
|
|
77
|
-
(
|
|
89
|
+
(the theming reference, see SKILL.md), and let the mock take its every value from that file:
|
|
78
90
|
the palette, `structure.radius`, the spacing scale, the fonts, the component
|
|
79
91
|
`defaultProps`. Approving the mock then approves the theme, and the built screens
|
|
80
92
|
inherit it rather than chase it.
|
|
81
93
|
|
|
82
|
-
**The mock has two halves, and only one of them is
|
|
94
|
+
**The mock has two halves, and only one of them is the component library's.** This is the same
|
|
83
95
|
split the built screen lives under, applied a step earlier so the two agree by
|
|
84
96
|
construction. The PAGE — the shell, the regions, the columns, the rhythm, the
|
|
85
97
|
material behind the content, what overlaps what — is plain HTML and your own
|
|
86
98
|
CSS, arranged however the layout decision demands; that half is free, and it is
|
|
87
99
|
where the design actually happens. The COMPONENTS — anything a person would
|
|
88
100
|
point at and call a control, and that the app will adopt as itself: buttons,
|
|
89
|
-
inputs, selects, tables, badges, menus, modals — are drawn as
|
|
90
|
-
metrics
|
|
101
|
+
inputs, selects, tables, badges, menus, modals — are drawn as _shadcn's_, at the
|
|
102
|
+
metrics shadcn actually uses: its control heights, its input shapes, its table
|
|
91
103
|
and menu behaviour. The test is the one the build will apply too: is this thing
|
|
92
104
|
the SHAPE OF THE PAGE, or a COMPONENT someone would point at?
|
|
93
105
|
|
|
94
106
|
Getting that second half wrong is what makes a mock a lie. A control the mock
|
|
95
107
|
invents is a promise the app cannot keep, and a beautiful hand-rolled input sets
|
|
96
|
-
a bar the real one misses on screen one. If the mock wants something
|
|
108
|
+
a bar the real one misses on screen one. If the mock wants something shadcn
|
|
97
109
|
does not do, that is a real finding, and finding it here is the point: change the
|
|
98
110
|
theme so it does, or change the mock, and say which.
|
|
99
111
|
|
|
@@ -102,7 +114,7 @@ needs — not a prototype, not a click-through. Static markup, real content from
|
|
|
102
114
|
their domain (never lorem), the empty and error states beside the happy path,
|
|
103
115
|
laid out so the whole app is legible by scrolling. Its CSS is custom properties
|
|
104
116
|
on `:root` carrying the theme JSON's values, so a change to either is a change
|
|
105
|
-
to one number in both.
|
|
117
|
+
to one number in both. The components themselves will not load here — they are React
|
|
106
118
|
and a page like this has no bundler, and on hosts that sandbox the page (a Claude
|
|
107
119
|
Artifact) external stylesheets are blocked outright — so do not try; the mock
|
|
108
120
|
reproduces the theme's values by hand, which is why they have to be written down
|
|
@@ -126,29 +138,29 @@ stating:
|
|
|
126
138
|
mock was wrong. Update it, and say you did. Do not let the app and the mock
|
|
127
139
|
drift and then quietly prefer the app.
|
|
128
140
|
- The knowledge graph still owns the domain — objects, roles, rules. The mock
|
|
129
|
-
owns what the screens look like. When they disagree about a
|
|
130
|
-
wins; when they disagree about a
|
|
141
|
+
owns what the screens look like. When they disagree about a _fact_, knowledge
|
|
142
|
+
wins; when they disagree about a _layout_, the mock wins.
|
|
131
143
|
|
|
132
144
|
**Building it is then a transcription, not a translation.** Because the theme
|
|
133
|
-
already exists and the mock was drawn from it, the screen is
|
|
145
|
+
already exists and the mock was drawn from it, the screen is shadcn components
|
|
134
146
|
arranged the way the mock arranges them — the look arrives with the theme. Two
|
|
135
147
|
rules keep it that way:
|
|
136
148
|
|
|
137
|
-
- **Layout is yours to write; components are
|
|
149
|
+
- **Layout is yours to write; components are shadcn's.** The page shape — the
|
|
138
150
|
regions, the columns, the rhythm, what sits beside what — is ordinary markup
|
|
139
151
|
and your own CSS. Anything a person would point at and call a control comes
|
|
140
|
-
from
|
|
152
|
+
from shadcn: buttons, inputs, selects, tables, badges, menus. Those carry
|
|
141
153
|
focus rings, keyboard behaviour and i18n, and hand-rolling one throws all of
|
|
142
154
|
it away.
|
|
143
155
|
- **A gap goes back to the theme, never into a component override.** If a screen
|
|
144
156
|
does not match the mock, the fix is a value in `themes/<name>.json`. A stack of
|
|
145
|
-
one-off `className`s and `!important` fighting
|
|
157
|
+
one-off `className`s and `!important` fighting the component defaults looks like
|
|
146
158
|
progress on screen one and is unmaintainable by screen five, and the screens
|
|
147
159
|
drift apart because nothing central holds them together.
|
|
148
160
|
|
|
149
161
|
**Checking the built screen against the mock** is a structural comparison, not a
|
|
150
162
|
pixel one: the same regions in the same order, the same hierarchy, the same
|
|
151
|
-
states present, the same tokens used. Do not chase pixel equality —
|
|
163
|
+
states present, the same tokens used. Do not chase pixel equality — shadcn's
|
|
152
164
|
components have their own metrics and the mock was drawn without them. A built
|
|
153
165
|
screen that reads as the same screen has passed.
|
|
154
166
|
|
|
@@ -192,9 +204,9 @@ the thing that made it is always yes. Use evidence.
|
|
|
192
204
|
Then drive it over CDP from a script: `Page.navigate`,
|
|
193
205
|
`Emulation.setDeviceMetricsOverride` for the two widths,
|
|
194
206
|
`Page.captureScreenshot`, write the PNG, and open it. Sign in the way a person
|
|
195
|
-
does —
|
|
196
|
-
|
|
197
|
-
|
|
207
|
+
does — through the login page — rather than reaching for the secret the
|
|
208
|
+
client uses; the UI path also proves the login screen works. Keep the script; you will run it at every changeset.
|
|
209
|
+
|
|
198
210
|
- **Run `impeccable`** (`npx impeccable install`, Node 22.18+) and feed it the
|
|
199
211
|
screenshots. It is external, it does not flatter, and it scores execution
|
|
200
212
|
against interaction heuristics. But it audits how well you executed the design
|
|
@@ -228,7 +240,7 @@ inventory, and it produces the wall of identical boxes further down this file.
|
|
|
228
240
|
list.** A product has objects of its own, and the ones that carry its meaning are
|
|
229
241
|
the ones no generic kit ships:
|
|
230
242
|
|
|
231
|
-
- the thing the product is
|
|
243
|
+
- the thing the product is _about_, rendered as itself — a funding meter, a
|
|
232
244
|
streak, a seat map, a run's status over time. If a decision note says the
|
|
233
245
|
progress toward a goal is the primary object, then a component that draws that
|
|
234
246
|
progress has to exist, or the note is describing an app you did not build.
|
|
@@ -243,7 +255,7 @@ Adding them is not hand-rolling, and they are the difference between an app that
|
|
|
243
255
|
uses a design system and an app that looks like one.
|
|
244
256
|
|
|
245
257
|
The tell that you skipped this: your `components/` directory maps one-to-one onto
|
|
246
|
-
your data model and contains nothing that names a
|
|
258
|
+
your data model and contains nothing that names a _quality_ of the product.
|
|
247
259
|
|
|
248
260
|
## Design is a gate on the changeset, not a phase at the end
|
|
249
261
|
|
|
@@ -269,7 +281,7 @@ repaint is a rewrite.
|
|
|
269
281
|
### The seed is part of the gate
|
|
270
282
|
|
|
271
283
|
A screenshot is only evidence if the screen has something on it. Before the gate
|
|
272
|
-
runs, the dev seed must populate what each screen
|
|
284
|
+
runs, the dev seed must populate what each screen _is for_ — not one row, and not
|
|
273
285
|
an empty state.
|
|
274
286
|
|
|
275
287
|
This is a real and quiet failure: a list app whose seed has no list, a countdown
|
|
@@ -280,7 +292,7 @@ designing and is not what the changeset is about.
|
|
|
280
292
|
Seed enough to be judged against: several rows, not three identical ones, and a
|
|
281
293
|
deliberate spread of the cases the screen has to hold — a long title that wraps,
|
|
282
294
|
a missing optional field, a picture and no picture, one item in each state the
|
|
283
|
-
screen can show. Anything derived from
|
|
295
|
+
screen can show. Anything derived from _today_ — a countdown, "3 days ago", an
|
|
284
296
|
expiry — is seeded as an interval from `now`, never as a fixed date: fixed dates
|
|
285
297
|
are correct on the afternoon they are written and meaningless a month later.
|
|
286
298
|
|
|
@@ -308,8 +320,8 @@ These are not design opinions and are not open to a different answer.
|
|
|
308
320
|
- **Empty, loading and error are states that exist.** The empty state is what a
|
|
309
321
|
new user meets first and the one most often skipped entirely.
|
|
310
322
|
- **Contrast and tap targets are measured, not judged.** `pikku-a11y` covers it.
|
|
311
|
-
One trap worth knowing: a
|
|
312
|
-
|
|
323
|
+
One trap worth knowing: a tinted badge paints its label in the
|
|
324
|
+
accent, which lands just under AA on its own tint — name the
|
|
313
325
|
darker ink once and reuse it.
|
|
314
326
|
|
|
315
327
|
## Two screens that get skipped
|
|
@@ -351,7 +363,7 @@ first one.
|
|
|
351
363
|
and a display font applied to a default layout is a well-dressed default.
|
|
352
364
|
- Every border, divider and disabled control is a cool blue-grey while the
|
|
353
365
|
accent is not — the surest sign the neutrals were inherited rather than
|
|
354
|
-
chosen.
|
|
366
|
+
chosen. The theming reference (see SKILL.md) covers it.
|
|
355
367
|
- It looks like the last app you built.
|
|
356
|
-
- It looks like
|
|
368
|
+
- It looks like stock shadcn. Not _built with_ shadcn, which it is and should be —
|
|
357
369
|
but indistinguishable from a component gallery with the brand hue swapped in.
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Pikku Create-a-Feature
|
|
2
2
|
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Agent Operating Procedure
|
|
6
|
+
- Stage 1 — Discover
|
|
7
|
+
- Stage 2 — State intent in plain English (BEFORE writing code)
|
|
8
|
+
- Stage 3 — Branch off
|
|
9
|
+
- Stage 4 — Implement
|
|
10
|
+
- Stage 5 — Verify
|
|
11
|
+
- Stage 6 — Commit
|
|
12
|
+
- Stage 7 — Hand off
|
|
13
|
+
- Report what fought you
|
|
14
|
+
- Hard constraints
|
|
15
|
+
- Output discipline
|
|
16
|
+
|
|
3
17
|
The stages, in order:
|
|
4
18
|
|
|
5
19
|
- [Agent Operating Procedure](#agent-operating-procedure)
|
|
@@ -257,8 +271,8 @@ Do not push without explicit confirmation. Do not merge.
|
|
|
257
271
|
## Report what fought you
|
|
258
272
|
|
|
259
273
|
When pikku itself is what cost you time — a wrong generated type, a check that
|
|
260
|
-
passed when it should not, a skill that misled you — file it
|
|
261
|
-
|
|
274
|
+
passed when it should not, a skill that misled you — file it as the
|
|
275
|
+
`pikku-report` skill describes. That skill owns the ladder, the two kinds, the JSON-on-
|
|
262
276
|
stdin form and asking the user at hand-over; read it before filing.
|
|
263
277
|
|
|
264
278
|
Filing is permitted here (see **Hard constraints**), and sending what was filed
|
|
@@ -276,7 +290,7 @@ The skill's `allowed-tools` does **not** permit:
|
|
|
276
290
|
- `pikku deploy apply` (never deploy)
|
|
277
291
|
- secret writes
|
|
278
292
|
- network calls beyond what the implementation requires, except
|
|
279
|
-
`pikku
|
|
293
|
+
filing a finding as `pikku-report` describes, which is explicitly permitted
|
|
280
294
|
|
|
281
295
|
If the feature genuinely needs any of these, **stop and ask** with a clear
|
|
282
296
|
explanation of why and what would change.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Data the backend does not have yet
|
|
2
|
+
|
|
3
|
+
Read this when a screen needs data no function returns yet, or returns in a different shape. Real functions come first; mock only what is missing.
|
|
4
|
+
|
|
5
|
+
## Three ways to get data
|
|
6
|
+
|
|
7
|
+
- `usePikkuQuery('rpc:name')` and `usePikkuMutation('rpc:name')` take only RPCs that exist, with the function's own types. `api.gen.ts` lists them. Use these whenever a function fits.
|
|
8
|
+
- Mocks are files, not code: `.mocks/<rpc.name>/<scenario>.json` is exactly what the RPC answers, and `<scenario>.meta.json` beside it holds `label`, `description`, `state` (healthy, empty, error or slow), `default`, `delayMs` and `status`. Exactly one scenario per RPC has `default: true`. Add an empty and an error scenario for every list and every mutation.
|
|
9
|
+
- `usePikkuQueryStub('rpc:name')` and `usePikkuMutationStub('rpc:name')` always answer from the mock, and their output type is inferred from the mock files. Use a stub only when the function's types are not enough: no function exists, or the shape the screen needs differs from the function's output. If the mock already fits the function, use `usePikkuQuery`.
|
|
10
|
+
|
|
11
|
+
The app loads its mocks with `registerPikkuMocks()` from the generated `mocks.gen.ts` beside `api.gen.ts`, called when `import.meta.env.DEV || import.meta.env.VITE_MOCK`. It covers the app's `.mocks/` and every wired addon's, so never glob `.mocks` or `node_modules` by hand.
|
|
12
|
+
|
|
13
|
+
## Addon mocks
|
|
14
|
+
|
|
15
|
+
An addon ships default mocks in its own package as `.mocks/<function>/<scenario>.json`, named without a namespace, and lists `.mocks` in `files`. An app that wires the addon as `studio` gets them as `studio:<function>`. The app's `.mocks/studio.<function>/` adds scenarios; one with the same name replaces the addon's, and a `default: true` in the app wins over the addon's default. Put mocks for an addon's functions in the addon, and only the app's own variations in the app.
|
|
16
|
+
|
|
17
|
+
With `VITE_MOCK` set the plain hooks answer from the default mock too, so every state of every screen can be looked at without a backend.
|
|
18
|
+
|
|
19
|
+
## Publishing
|
|
20
|
+
|
|
21
|
+
A stub with no `{ featureFlag }` works in development and cannot be published. `usePikkuQueryStub('rpc:name', { featureFlag: 'flag' })` can, as long as the flag is declared in the project. Production never ships mock data; a stub there is a plain call that gets a 404.
|
|
22
|
+
|
|
23
|
+
## Making a screen real
|
|
24
|
+
|
|
25
|
+
`pikku mocks check` lists every stub and blocks the unflagged ones. For each stub: implement the function so its output matches the mock, replace the stub with `usePikkuQuery`, delete the flag if nothing else uses it. `pikku mocks diff` shows what changed, what is unused and what is dead; delete a mock directory it reports as removed.
|
|
26
|
+
|
|
27
|
+
## Screens built on mocks
|
|
28
|
+
|
|
29
|
+
The screens are the real app's: real components, `m.*()` for every string, the theme tokens. Only the data is sample. Make it look lived in: at least six realistic records where a page lists things, real copy, tinted and textured placeholder images instead of flat grey boxes. A button that leads nowhere real stays inert.
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Adding a second frontend
|
|
2
2
|
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Deciding it is two apps, not one
|
|
6
|
+
- The second app
|
|
7
|
+
- Sessions across two origins
|
|
8
|
+
- Building the second app's screens
|
|
9
|
+
|
|
3
10
|
Read this when the split you recorded in Phase 2 is "separate apps" and you have
|
|
4
11
|
reached the changeset that needs the second one. **Not before.** Cloning
|
|
5
12
|
`apps/app` materialises a directory of copied screens; doing it during planning
|
|
@@ -14,7 +21,7 @@ The split you are acting on should already be recorded, but this is the reasonin
|
|
|
14
21
|
behind it — and the place people get it wrong is the third case at the bottom.
|
|
15
22
|
|
|
16
23
|
**A group that comes in through its own front door gets its own app.** A role
|
|
17
|
-
|
|
24
|
+
_inside_ an app is not that: it changes which nav items and which buttons a person
|
|
18
25
|
sees, and lives in `useNavItems()` and the `permissions` on the function, not in a
|
|
19
26
|
route subtree.
|
|
20
27
|
|
|
@@ -24,7 +31,7 @@ across the counter with an account of their own gets their own — the customer,
|
|
|
24
31
|
tenant, the patient. One app is a real answer and often the right one.
|
|
25
32
|
|
|
26
33
|
**The asymmetry that forces a split is sign-up.** Where staff accounts are created
|
|
27
|
-
|
|
34
|
+
_for_ people and customers create their own, the two need different sign-up, different
|
|
28
35
|
onboarding and different session shape, and bending one app around both costs more
|
|
29
36
|
than the second app does. Do not collapse two audiences into one app to save a build.
|
|
30
37
|
|
|
@@ -34,7 +41,7 @@ Never invent a person the notes do not name in order to reach two.
|
|
|
34
41
|
|
|
35
42
|
Some people use the product with no account at all — ordering from a menu, booking a
|
|
36
43
|
table, opening an invitation. They are not a third case, and **they do not get their
|
|
37
|
-
own frontend**: an app is built around the
|
|
44
|
+
own frontend**: an app is built around the virtual users who sign into it. What they get is
|
|
38
45
|
the public route space every app already has.
|
|
39
46
|
|
|
40
47
|
- **`/app/*` is the signed-in application.** One `beforeLoad` on `/app` bounces a
|
|
@@ -60,19 +67,19 @@ and someone else's record: if the invoices nav item is hidden but `listAllInvoic
|
|
|
60
67
|
has no `permissions`, the app is wide open and the nav is decoration.
|
|
61
68
|
|
|
62
69
|
Worth a scenario each, because they are two different claims: that a mechanic cannot
|
|
63
|
-
|
|
70
|
+
_see_ the invoices nav item, and that their call to an invoices RPC is _refused_. The
|
|
64
71
|
second is the one that catches a `permissions` field nobody wired.
|
|
65
72
|
|
|
66
73
|
## The second app
|
|
67
74
|
|
|
68
75
|
```bash
|
|
69
|
-
pikku app new admin --serves staff --
|
|
76
|
+
pikku app new admin --serves staff --virtual-users manager,mechanic
|
|
70
77
|
```
|
|
71
78
|
|
|
72
79
|
One command does every step this section used to list by hand: it fetches
|
|
73
80
|
`pikkujs/starter-template`'s `apps/app`, re-points its `package.json` at the
|
|
74
81
|
new name, its own dev/preview port and its own `--tsBuildInfoFile`, stamps
|
|
75
|
-
`app: '<slug>'` onto each named
|
|
82
|
+
`app: '<slug>'` onto each named virtual user in `defineVirtualUsers({…})`, adds the
|
|
76
83
|
`frontends` entry to `pikku.config.json`, and re-runs `bun install`. `pikku app
|
|
77
84
|
list` shows every app afterwards.
|
|
78
85
|
|
|
@@ -101,12 +108,12 @@ second app nobody needed, so the command will not create one when:
|
|
|
101
108
|
- **An existing app already serves that audience.** People sharing an audience
|
|
102
109
|
share ONE app and differ by nav and permitted actions. A new app is for a
|
|
103
110
|
group the first app is not for.
|
|
104
|
-
- **A named
|
|
111
|
+
- **A named virtual user already signs into another app.** A person signs into one
|
|
105
112
|
app; move them out first if they really belong here.
|
|
106
113
|
- **The slug is what the plan calls an app that already exists.** The plan's
|
|
107
114
|
FIRST app is the one the project starts with — only the apps after it get
|
|
108
115
|
created.
|
|
109
|
-
- **A
|
|
116
|
+
- **A virtual user is not in `defineVirtualUsers({…})`.** The app is built around who
|
|
110
117
|
signs into it, so it is not created for people who do not exist yet.
|
|
111
118
|
|
|
112
119
|
It also repairs its own half-states: a run that died between writing the
|
|
@@ -121,14 +128,14 @@ supervisor, a dev runner, a deploy target — belongs to whatever is hosting it.
|
|
|
121
128
|
On a plain checkout, `bun --filter @project/<slug> dev` is enough.
|
|
122
129
|
|
|
123
130
|
Packaging it as a desktop or Android app is a separate step, on the same
|
|
124
|
-
`frontends` entry: `pikku app native init <slug>`.
|
|
125
|
-
|
|
131
|
+
`frontends` entry: `pikku app native init <slug>`. The native-app reference
|
|
132
|
+
(see SKILL.md) covers it.
|
|
126
133
|
|
|
127
134
|
### Scenarios across the two apps
|
|
128
135
|
|
|
129
|
-
`pikku app new` stamps `app: '<slug>'` onto each
|
|
130
|
-
field — not the `
|
|
131
|
-
`@pikku/playwright` resolves a
|
|
136
|
+
`pikku app new` stamps `app: '<slug>'` onto each virtual user it is given, and that
|
|
137
|
+
field — not the `virtualUsers` array on the `frontends` entry — is what
|
|
138
|
+
`@pikku/playwright` resolves a virtual user's base url from at sign-in. A virtual user
|
|
132
139
|
with no `app` lands on the fallback frontend, which is the other app's screens
|
|
133
140
|
with the right session on them.
|
|
134
141
|
|
|
@@ -145,15 +152,15 @@ single `appUrl` fallback, and the CLI takes `--app-url <app>=<url>,<app>=<url>`:
|
|
|
145
152
|
|
|
146
153
|
Three things follow, and each one has cost a run:
|
|
147
154
|
|
|
148
|
-
- **
|
|
149
|
-
at sign-in. A staff
|
|
150
|
-
something is absent from it — drive that assertion with a
|
|
155
|
+
- **A virtual user is bound to ONE app for the whole run.** The resolution happens once,
|
|
156
|
+
at sign-in. A staff virtual user cannot be walked through the customer app to check
|
|
157
|
+
something is absent from it — drive that assertion with a virtual user who lives
|
|
151
158
|
there, and say in the scenario's docblock why the witness is who it is. This
|
|
152
159
|
binds a SIGNED-OUT scenario too, and that is where it bites: 'a visitor with no
|
|
153
|
-
session cannot open the admin desk' driven by a customer-app
|
|
160
|
+
session cannot open the admin desk' driven by a customer-app virtual user points the
|
|
154
161
|
browser at a router with no such route at all, so what the assertion measures is
|
|
155
162
|
a 404, not the guard — and on an app with a catch-all redirect to login it
|
|
156
|
-
passes while proving nothing. Pick the
|
|
163
|
+
passes while proving nothing. Pick the virtual user by which app owns the ROUTE, not by
|
|
157
164
|
who should be refused, and drop their session instead.
|
|
158
165
|
- **Every frontend needs its API proxy pointed at the API you are actually
|
|
159
166
|
running.** `vite.config.ts` reads a variable (`VITE_API_PROXY`) with a default
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Shipping an app as a desktop or Android app
|
|
2
2
|
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- The commands
|
|
6
|
+
- Pick the mode first
|
|
7
|
+
- What pikku owns and what you own
|
|
8
|
+
- Plugins
|
|
9
|
+
- The identifier
|
|
10
|
+
- Building
|
|
11
|
+
|
|
3
12
|
Read this when an app in `frontends` has to be installed rather than visited: a
|
|
4
13
|
desktop app, an Android APK, later an iPhone app. The app is still the same
|
|
5
14
|
frontend. A native app is that frontend packaged in a Tauri shell, configured on
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# An app on top of an OpenAPI spec
|
|
2
2
|
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Pick the auth mode
|
|
6
|
+
- The auth-config file
|
|
7
|
+
- The screens
|
|
8
|
+
- Scenarios
|
|
9
|
+
|
|
3
10
|
The spec becomes an addon first — the `pikku-addon` skill's
|
|
4
11
|
`references/openapi.md` covers generating, verifying and checking it against
|
|
5
12
|
the real API. This reference is the decision that shapes the app around it:
|
|
@@ -7,13 +14,13 @@ the real API. This reference is the decision that shapes the app around it:
|
|
|
7
14
|
|
|
8
15
|
## Pick the auth mode
|
|
9
16
|
|
|
10
|
-
| The upstream…
|
|
11
|
-
|
|
|
12
|
-
| Is where the users already have accounts, and has a login endpoint
|
|
13
|
-
| Takes a per-user API key, bearer token or basic auth
|
|
14
|
-
| Uses OAuth2
|
|
15
|
-
| Is used on everyone's behalf with one key the business owns
|
|
16
|
-
| Takes no auth
|
|
17
|
+
| The upstream… | Mode | Command | Who signs in, and how |
|
|
18
|
+
| ------------------------------------------------------------------ | -------------- | ---------------------- | ------------------------------------------------------- |
|
|
19
|
+
| Is where the users already have accounts, and has a login endpoint | Delegated | `--auth-config <file>` | Users sign in with their upstream login; no new account |
|
|
20
|
+
| Takes a per-user API key, bearer token or basic auth | Per-user key | (the default) | App account, then a Connect screen for the key |
|
|
21
|
+
| Uses OAuth2 | Per-user OAuth | (the default) | App account, then Connect via the OAuth consent |
|
|
22
|
+
| Is used on everyone's behalf with one key the business owns | Shared secret | `--auth shared` | App account only; the key is a secret |
|
|
23
|
+
| Takes no auth | None | `--auth none` | App account only |
|
|
17
24
|
|
|
18
25
|
Per-user is the default because the upstream then enforces each person's own
|
|
19
26
|
permissions. A shared secret acts with one identity for everyone, so the
|
|
@@ -62,30 +69,30 @@ JSON, passed with `--auth-config`. Every field is optional except where noted.
|
|
|
62
69
|
|
|
63
70
|
Top level — how every call authenticates:
|
|
64
71
|
|
|
65
|
-
| Field | Meaning
|
|
66
|
-
| -------------- |
|
|
67
|
-
| `headerName` | The header the API reads the token or key from. Setting it alone means a per-user API key
|
|
72
|
+
| Field | Meaning |
|
|
73
|
+
| -------------- | ------------------------------------------------------------------------------------------------------ |
|
|
74
|
+
| `headerName` | The header the API reads the token or key from. Setting it alone means a per-user API key |
|
|
68
75
|
| `headerFormat` | `raw` sends the bare value, `bearer` prefixes `Bearer `. Default: bearer for `Authorization`, else raw |
|
|
69
|
-
| `extraHeaders` | Static headers on every request, login included — for upstreams that route on a header
|
|
70
|
-
| `delegated` | Present when users sign in with their upstream login
|
|
76
|
+
| `extraHeaders` | Static headers on every request, login included — for upstreams that route on a header |
|
|
77
|
+
| `delegated` | Present when users sign in with their upstream login |
|
|
71
78
|
|
|
72
79
|
`delegated`:
|
|
73
80
|
|
|
74
|
-
| Field
|
|
75
|
-
|
|
|
76
|
-
| `loginPath`
|
|
77
|
-
| `loginMethod`
|
|
78
|
-
| `credentials`
|
|
79
|
-
| `fields`
|
|
80
|
-
| `encoding`
|
|
81
|
-
| `apiKeyHeader`
|
|
82
|
-
| `tokenPath`
|
|
83
|
-
| `expiresAtPath`
|
|
84
|
-
| `identity`
|
|
85
|
-
| `claims.source`
|
|
86
|
-
| `claims.*`
|
|
87
|
-
| `emailTemplate`
|
|
88
|
-
| `roles`
|
|
81
|
+
| Field | Meaning |
|
|
82
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
83
|
+
| `loginPath` | Required. The spec-relative login operation |
|
|
84
|
+
| `loginMethod` | Default `post` |
|
|
85
|
+
| `credentials` | What the sign-in form collects: `login` (a username or email), `email`, `password`, `apiKey`. Default `["email","password"]` |
|
|
86
|
+
| `fields` | The upstream's name for each credential, e.g. `{ "login": "username" }` |
|
|
87
|
+
| `encoding` | `json`, `form` or `query` — how the login fields travel. Default `json` |
|
|
88
|
+
| `apiKeyHeader` | The header an `apiKey` credential is sent in. Default `x-api-key` |
|
|
89
|
+
| `tokenPath` | Required. Dot-path to the token in the login response |
|
|
90
|
+
| `expiresAtPath` | Dot-path to an epoch-seconds expiry. Defaults to the JWT's `exp` when claims come from the JWT |
|
|
91
|
+
| `identity` | An operation that returns the signed-in user, called with the new token — for logins that return only a token |
|
|
92
|
+
| `claims.source` | `jwt`, `response` or `identity`. Default `identity` when `identity` is set, else `response` |
|
|
93
|
+
| `claims.*` | Dot-paths to `externalId`, `email`, `name` (one path or several joined with a space), `role`, `tenantId` |
|
|
94
|
+
| `emailTemplate` | Builds an email for an upstream user who has none: `{login}`, `{externalId}`, `{host}`. Such an address never claims an existing user |
|
|
95
|
+
| `roles` | Maps the raw `claims.role` value onto an app role; an unmapped value gets no role |
|
|
89
96
|
|
|
90
97
|
Check it before building on it: start `pikku dev`, sign in once with
|
|
91
98
|
`POST /api/auth/sign-in/delegated` as a real upstream user, and call an exposed
|
|
@@ -93,7 +100,7 @@ operation with the session. A wrong password must be refused. Keep real
|
|
|
93
100
|
credentials in the environment, never in the config or a test.
|
|
94
101
|
|
|
95
102
|
What the install wires for delegated mode — `pikkuDelegatedAuth` in
|
|
96
|
-
`src/auth.ts`, the token stored per user,
|
|
103
|
+
`src/auth.ts`, the token stored per user, virtual users carrying it into scenarios — is
|
|
97
104
|
in the `pikku-auth` skill's `references/better-auth.md`.
|
|
98
105
|
|
|
99
106
|
## The screens
|
|
@@ -107,13 +114,13 @@ in the `pikku-auth` skill's `references/better-auth.md`.
|
|
|
107
114
|
call fails with `missing_credential`.
|
|
108
115
|
- A `credential_rejected` error (`CredentialRejectedError`, 403) means the
|
|
109
116
|
upstream refused the stored token: show the sign-in again (`reauth:
|
|
110
|
-
|
|
117
|
+
'sign-in'`) or the Connect screen (`reauth: 'connect'`), not a generic error.
|
|
111
118
|
|
|
112
119
|
## Scenarios
|
|
113
120
|
|
|
114
|
-
A
|
|
115
|
-
act with. The install adds `credentials` to `
|
|
116
|
-
at sign-in each
|
|
117
|
-
environment (e.g. `
|
|
121
|
+
A virtual user that signs in through the upstream needs an upstream credential to
|
|
122
|
+
act with. The install adds `credentials` to `pikkuVirtualUser` in `src/auth.ts`, and
|
|
123
|
+
at sign-in each virtual user stores `VIRTUAL_USER_CREDENTIAL_<VIRTUAL_USER>_<NAME>` from the
|
|
124
|
+
environment (e.g. `VIRTUAL_USER_CREDENTIAL_SALES_REP_DOLIBARR`). Without it every
|
|
118
125
|
scenario step that reaches the upstream fails with `missing_credential`. The
|
|
119
|
-
`pikku-scenario` skill's `references/
|
|
126
|
+
`pikku-scenario` skill's `references/virtual-users.md` has the details.
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
# Build a platform showcase on Pikku
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- What "platform" means here
|
|
6
|
+
- Choosing surfaces — during app workflow §5 (planning)
|
|
7
|
+
- The surfaces
|
|
8
|
+
- Coverage — where the bar is higher than the base workflow
|
|
9
|
+
- The full gate
|
|
10
|
+
- Deploy
|
|
11
|
+
- Reference
|
|
12
|
+
|
|
13
|
+
**This file is a delta: it adds to the app workflow, which stays the base and is
|
|
14
|
+
followed in full.** Everything there applies: knowledge base first, virtual users and roles,
|
|
5
15
|
changes grouped into changesets, planned then built one at a time, scenarios, design pass, deploy
|
|
6
|
-
gates,
|
|
16
|
+
gates, deploy-readiness. This file adds the surfaces that turn an app into a
|
|
7
17
|
demonstration of the platform, and says where each one slots into that workflow.
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
Do not blend the two into one plan —
|
|
10
20
|
the phases below hang off its phases by number.
|
|
11
21
|
|
|
12
22
|
## What "platform" means here
|
|
@@ -23,7 +33,7 @@ or agent page, never the queue, scheduler or wire pages behind it.
|
|
|
23
33
|
Budget the extra surfaces at one changeset each. They are not free, and a
|
|
24
34
|
half-wired workflow engine is worse than no workflow engine.
|
|
25
35
|
|
|
26
|
-
## Choosing surfaces — during
|
|
36
|
+
## Choosing surfaces — during app workflow §5 (planning)
|
|
27
37
|
|
|
28
38
|
When you file the work, each surface below becomes its own changeset, ordered
|
|
29
39
|
after the spine it depends on.
|
|
@@ -76,7 +86,7 @@ on a human or a timer and must survive a restart.
|
|
|
76
86
|
gap in the middle? If every operation completes in one request, you do not need
|
|
77
87
|
workflows and forcing one is noise.
|
|
78
88
|
- **Prove it:** a scenario that starts the workflow, advances it as a second
|
|
79
|
-
|
|
89
|
+
virtual user, and asserts the end state. `pikku-react` covers driving it
|
|
80
90
|
from the UI.
|
|
81
91
|
- Three workflows ship with the template. Read them before writing yours.
|
|
82
92
|
|
|
@@ -123,7 +133,7 @@ generated typed client.
|
|
|
123
133
|
- **Motivation test:** two people looking at the same thing at the same time, or
|
|
124
134
|
a long operation whose progress matters.
|
|
125
135
|
- **Prove it:** a browser scenario is the only honest proof — assert the second
|
|
126
|
-
|
|
136
|
+
virtual user's screen changed without a reload.
|
|
127
137
|
|
|
128
138
|
### MCP — `pikku-wiring`
|
|
129
139
|
|
|
@@ -137,7 +147,7 @@ correct rather than a smell: a third-party caller needs a real REST shape.
|
|
|
137
147
|
|
|
138
148
|
### Locales — `pikku-i18n`
|
|
139
149
|
|
|
140
|
-
|
|
150
|
+
The app workflow already requires every string to be a key. **Here, ship three
|
|
141
151
|
locales, and make one of them RTL** (`pikku-i18n`). Two LTR locales prove the
|
|
142
152
|
plumbing; an RTL one proves the layout, and it will find real bugs — mirrored
|
|
143
153
|
icons, hardcoded `marginLeft`, a nav that opens on the wrong side.
|
|
@@ -150,7 +160,7 @@ every added locale is cloned from, so three locales is `locales: ["en", …]` an
|
|
|
150
160
|
never a repointed base. Shipping locales is also not a reason for anything in
|
|
151
161
|
the code to stop being English: identifiers are English in every project, and
|
|
152
162
|
the language of `description`/`title`/`template` is `metaLocale` in
|
|
153
|
-
`pikku.config.json`.
|
|
163
|
+
`pikku.config.json`. The app workflow's §1a covers it.
|
|
154
164
|
|
|
155
165
|
### Emails — `pikku-emails`
|
|
156
166
|
|
|
@@ -177,7 +187,7 @@ the domain has a piece that genuinely belongs to no single app.
|
|
|
177
187
|
|
|
178
188
|
## Coverage — where the bar is higher than the base workflow
|
|
179
189
|
|
|
180
|
-
|
|
190
|
+
The app workflow's §7a already has the mechanics and the per-changeset habit:
|
|
181
191
|
run the server instrumented, run the scenarios against it, read
|
|
182
192
|
`coverage/scenario-coverage.json`, and triage every gap as a missing scenario, a
|
|
183
193
|
function that should not exist, or a documented deferral. Do all of that here.
|
|
@@ -196,7 +206,7 @@ Two things change in a showcase:
|
|
|
196
206
|
|
|
197
207
|
## The full gate
|
|
198
208
|
|
|
199
|
-
Everything in
|
|
209
|
+
Everything in the app workflow's §9, plus the checks a showcase should be able to
|
|
200
210
|
survive:
|
|
201
211
|
|
|
202
212
|
```sh
|
|
@@ -218,7 +228,7 @@ bunx --bun pikku scenario run local --spawn --run browser
|
|
|
218
228
|
|
|
219
229
|
## Deploy
|
|
220
230
|
|
|
221
|
-
|
|
231
|
+
The app workflow's §9 covers the open-source paths (`--provider standalone`,
|
|
222
232
|
`cloudflare`, `aws`). One thing specific to this mode: **the extra surfaces are
|
|
223
233
|
extra deploy units.** Workflow workers, queue workers, schedules and the events
|
|
224
234
|
channel each appear in `pikku deploy plan` as their own entries. Read the plan
|
|
@@ -227,8 +237,7 @@ built.
|
|
|
227
237
|
|
|
228
238
|
## Reference
|
|
229
239
|
|
|
230
|
-
- Base workflow:
|
|
240
|
+
- Base workflow: the app workflow, which this file adds to
|
|
231
241
|
- Per-surface skills: `pikku-workflow`, `pikku-wiring`, `pikku-agent`,
|
|
232
242
|
`pikku-i18n`, `pikku-emails`,
|
|
233
243
|
`pikku-meta`, `pikku-addon`, `pikku-auth`, `pikku-services`
|
|
234
|
-
- Every feature, end to end: https://pikkufabric.com/llm-all-features.txt
|