@pikku/skills 0.12.35 → 0.12.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.js +9 -5
- package/dist/skills.gen.d.ts +1 -0
- package/dist/skills.gen.js +5 -3
- package/dist/snippets.d.ts +26 -0
- package/dist/snippets.js +148 -0
- package/package.json +2 -2
- package/skills/pikku-addon/SKILL.md +70 -24
- package/skills/pikku-addon/references/addon-package-manifest.md +9 -4
- package/skills/pikku-addon/references/openapi.md +130 -0
- package/skills/pikku-agent/references/agents.md +3 -1
- package/skills/pikku-auth/references/better-auth.md +33 -2
- package/skills/pikku-build/SKILL.md +94 -6
- package/skills/pikku-build/references/app.md +82 -12
- package/skills/pikku-build/references/design.md +16 -5
- package/skills/pikku-build/references/feature.md +23 -96
- package/skills/pikku-build/references/openapi.md +119 -0
- package/skills/pikku-build/references/platform.md +4 -0
- package/skills/pikku-build/references/quick.md +16 -6
- package/skills/pikku-changes/SKILL.md +172 -0
- package/skills/pikku-concepts/SKILL.md +33 -138
- package/skills/pikku-concepts/references/bootstrap.md +58 -0
- package/skills/pikku-concepts/references/concept-mapping.md +16 -0
- package/skills/pikku-concepts/references/language.md +87 -0
- package/skills/pikku-deploy/SKILL.md +1 -1
- package/skills/pikku-fabric/SKILL.md +13 -13
- package/skills/pikku-guide/SKILL.md +264 -0
- package/skills/pikku-kysely/SKILL.md +1 -1
- package/skills/pikku-n8n-import/SKILL.md +4 -3
- package/skills/pikku-react/references/client.md +12 -0
- package/skills/pikku-realtime/SKILL.md +6 -6
- package/skills/pikku-report/SKILL.md +143 -0
- package/skills/pikku-scenario/SKILL.md +71 -562
- package/skills/pikku-scenario/references/browser.md +59 -0
- package/skills/pikku-scenario/references/coverage.md +70 -0
- package/skills/pikku-scenario/references/personas.md +149 -0
- package/skills/pikku-scenario/references/steps.md +366 -0
- package/skills/pikku-service-backends/SKILL.md +1 -1
- package/skills/pikku-wiring/SKILL.md +1 -1
- package/skills/pikku-workflow/SKILL.md +7 -8
|
@@ -24,7 +24,6 @@ agent:
|
|
|
24
24
|
command: pikku knowledge validate
|
|
25
25
|
- id: typechecks
|
|
26
26
|
command: pikku all --tsc-summary
|
|
27
|
-
|
|
28
27
|
---
|
|
29
28
|
|
|
30
29
|
# Build on Pikku
|
|
@@ -45,12 +44,14 @@ plus more effort" — it is App plus a deliberate surface checklist, so read the
|
|
|
45
44
|
base first and follow it in full rather than blending the two into one plan.
|
|
46
45
|
|
|
47
46
|
The supporting references belong to whichever mode sends you to them:
|
|
48
|
-
`references/multi-app.md` (a second frontend), `references/design.md` (
|
|
49
|
-
|
|
50
|
-
the screens realise it — read before the first screen is built, not
|
|
51
|
-
last), `references/theming.md`
|
|
47
|
+
`references/multi-app.md` (a second frontend), `references/design.md` (showing
|
|
48
|
+
a picture of the screens first, committing to a design direction, and judging
|
|
49
|
+
whether the screens realise it — read before the first screen is built, not
|
|
50
|
+
after the last), `references/theming.md`
|
|
52
51
|
(authoring the theme),
|
|
53
|
-
`references/ship.md` (deploying, and the Fabric-readiness contract)
|
|
52
|
+
`references/ship.md` (deploying, and the Fabric-readiness contract),
|
|
53
|
+
`references/openapi.md` (an app on an OpenAPI spec: the auth mode, the
|
|
54
|
+
auth-config format, and the sign-in or connect screen it implies).
|
|
54
55
|
|
|
55
56
|
## Bootstrap before anything else
|
|
56
57
|
|
|
@@ -63,6 +64,24 @@ generated code depends on, and on a fresh scaffold **every command that touches
|
|
|
63
64
|
codegen fails until it has run**, including ones you would reasonably reach for
|
|
64
65
|
while still planning. Those failures look alarming and are nothing but this.
|
|
65
66
|
|
|
67
|
+
## Start from what you were handed
|
|
68
|
+
|
|
69
|
+
When the request comes with a file or a URL, look at it before planning
|
|
70
|
+
anything. Two kinds are converted first and then built on:
|
|
71
|
+
|
|
72
|
+
| Handed | Say, then do |
|
|
73
|
+
| ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
74
|
+
| An **OpenAPI / Swagger spec** — top-level `openapi` or `swagger` key, a `paths` object | "This is an OpenAPI spec — I'll turn it into an addon first." Pick the auth mode in `references/openapi.md`, then follow the `pikku-addon` skill's OpenAPI reference. |
|
|
75
|
+
| An **n8n export** — an object with `nodes` and `connections`, an array of them, or a `{ workflows: [...] }` wrapper | "This is an n8n workflow — I'll import it first." Follow `pikku-n8n-import`. |
|
|
76
|
+
|
|
77
|
+
Say it at once, in one line, and start: this is the obvious first move, not a
|
|
78
|
+
question for the user. Generate the whole spec, however large.
|
|
79
|
+
|
|
80
|
+
Neither is the app. When the conversion compiles, come back here and carry on
|
|
81
|
+
in the mode the request calls for — App by default — planning milestones around
|
|
82
|
+
what the user wants to do with the API or the workflow, and reaching the
|
|
83
|
+
generated functions through `ref()`.
|
|
84
|
+
|
|
66
85
|
## What holds in every mode
|
|
67
86
|
|
|
68
87
|
- **The branch and the diff are the contract.** A reviewer sees real, compiled,
|
|
@@ -86,6 +105,75 @@ while still planning. Those failures look alarming and are nothing but this.
|
|
|
86
105
|
`pikku knowledge plan progress` measures the build against it from the
|
|
87
106
|
generated meta. You plan it and you build it; what you never do is edit the
|
|
88
107
|
plan afterwards to match what you built — that is grading yourself.
|
|
108
|
+
- **Print the links whenever the stack comes up, and in every hand-over.** Full,
|
|
109
|
+
clickable URLs, with the ports taken from what `bun run dev` actually printed:
|
|
110
|
+
- **App** — the frontend's URL (`http://localhost:7104` in the template; each
|
|
111
|
+
frontend in `pikkufabric.config.json` has its own port)
|
|
112
|
+
- **API** — `http://localhost:3000`
|
|
113
|
+
- **Console** — `http://localhost:3000/console`, plus a deep link to each
|
|
114
|
+
page that shows what this turn produced (the paths are below)
|
|
115
|
+
|
|
116
|
+
A person who has to go hunting for the port assumes the app did not start.
|
|
117
|
+
|
|
118
|
+
## Keep a BUILD-REPORT.md
|
|
119
|
+
|
|
120
|
+
Whenever pikku or a skill costs you time — a command that failed on a fresh
|
|
121
|
+
tree, a skill that described a flag the CLI does not have, generated code you
|
|
122
|
+
had to fix by hand — add an entry to `BUILD-REPORT.md` at the repo root as it
|
|
123
|
+
happens: what you ran, what you expected, what happened, and the workaround.
|
|
124
|
+
Leave out secrets, tokens and customer data.
|
|
125
|
+
|
|
126
|
+
At hand-over, show the file and ask the user whether to send it. Only with
|
|
127
|
+
their okay, send each entry with `pikku fabric report --stdin` (JSON on stdin;
|
|
128
|
+
`"kind": "product"` when pikku behaved wrongly, `"kind": "harness"` with
|
|
129
|
+
`"skill"` and `"passage"` when a skill misled you). The `pikku-report` skill
|
|
130
|
+
has the fields. When the CLI is not signed in to Fabric, the report is queued
|
|
131
|
+
locally rather than sent: say so, and that `pikku fabric findings flush` sends
|
|
132
|
+
the queue once they sign in. Do not retry or file it twice.
|
|
133
|
+
|
|
134
|
+
## Who you are talking to
|
|
135
|
+
|
|
136
|
+
The prompt asks first how technical the person is: **not technical**,
|
|
137
|
+
**technical, no code**, or **developer** (the default when unsaid). Whenever the
|
|
138
|
+
build makes or changes something the console can show, give the
|
|
139
|
+
`http://localhost:<port>/console/...` link instead of describing it.
|
|
140
|
+
|
|
141
|
+
Until the app is deployed that is the local open-source console, on the port
|
|
142
|
+
`pikku dev` printed. Once it is on Fabric, link the Fabric console for the stage
|
|
143
|
+
you are talking about instead; the `pikku-fabric` skill says which.
|
|
144
|
+
|
|
145
|
+
| Level | Links | Code in the conversation |
|
|
146
|
+
| ------------------ | --------------------------- | ------------------------ |
|
|
147
|
+
| Not technical | Product pages only | Never |
|
|
148
|
+
| Technical, no code | Product and technical pages | Never |
|
|
149
|
+
| Developer | Product and technical pages | As normal |
|
|
150
|
+
|
|
151
|
+
"Never" includes snippets and command lines; say what changed in the person's
|
|
152
|
+
words and link to where they can see it.
|
|
153
|
+
|
|
154
|
+
**Product pages** — the only ones a non-technical person gets:
|
|
155
|
+
|
|
156
|
+
| Shows | Path |
|
|
157
|
+
| --------------------- | -------------------------------------------------------------------------- |
|
|
158
|
+
| Knowledge, plans | `/console/knowledge`, `/console/knowledge?id=<note path>` |
|
|
159
|
+
| Personas | `/console/personas`, `/console/virtual-users?persona=<id>` |
|
|
160
|
+
| Roles and permissions | `/console/roles`, `/console/scopes` (only with `@pikku/addon-admin` wired) |
|
|
161
|
+
| Scenarios and runs | `/console/scenarios?id=<id>`, `/console/scenarios?view=runs&run=<run id>` |
|
|
162
|
+
| Workflows | `/console/workflow?id=<id>` |
|
|
163
|
+
| Agents | `/console/agents`, `/console/agents/playground?id=<agent id>` |
|
|
164
|
+
|
|
165
|
+
**Technical pages** — never for a non-technical person: `/console/overview`,
|
|
166
|
+
`/console/functions`, `/console/surface`, `/console/database`,
|
|
167
|
+
`/console/changes`, `/console/wires/http`, `/console/wires/channel`,
|
|
168
|
+
`/console/wires/mcp`, `/console/wires/cli`, `/console/wires/gateway`,
|
|
169
|
+
`/console/async/scheduler`, `/console/async/queue`, `/console/async/trigger`,
|
|
170
|
+
`/console/runtime`, `/console/emails`, `/console/webhooks`, `/console/secrets`,
|
|
171
|
+
`/console/variables`, `/console/security`, `/console/auth-providers`,
|
|
172
|
+
`/console/addons`, `/console/analytics`, `/console/credentials`,
|
|
173
|
+
`/console/users`, `/console/audit`, `/console/flags`, `/console/scorers`.
|
|
174
|
+
|
|
175
|
+
These come from `packages/console/src/App.tsx`; do not link a path that is not
|
|
176
|
+
listed here.
|
|
89
177
|
|
|
90
178
|
## What NOT to do
|
|
91
179
|
|
|
@@ -24,6 +24,9 @@ project shaped so `pikku fabric init` later adopts it with zero rework.
|
|
|
24
24
|
wirings, schemas or generated clients may have changed.
|
|
25
25
|
4. If validation fails, fix the source cause and rerun. Do not paper over
|
|
26
26
|
generated errors by editing generated files.
|
|
27
|
+
5. Report at the person's level (SKILL.md, "Who you are talking to"): a console
|
|
28
|
+
link for everything the console can show, and no code unless they are a
|
|
29
|
+
developer.
|
|
27
30
|
|
|
28
31
|
## 0. Bootstrap, before anything else
|
|
29
32
|
|
|
@@ -62,11 +65,18 @@ in one message. Then stop; do not interview the user.
|
|
|
62
65
|
a reference (brand guide, screenshots, a site whose register they want); or
|
|
63
66
|
their own design agent/prompt, whose output you take as the direction.
|
|
64
67
|
- **Do they want to see the screens before you build them?** Offer it here, in
|
|
65
|
-
this same round,
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
this same round, with yes marked recommended, in the words of
|
|
69
|
+
`references/design.md` — "a picture of the main screens so you can say 'yes,
|
|
70
|
+
like that' or 'no, move this'", never "mock" or "wireframe". Behind it is one
|
|
71
|
+
HTML page mocking the main screens, a few minutes of work. On a yes, or no
|
|
72
|
+
answer at all, `references/design.md` owns what to make and what it then binds — the
|
|
68
73
|
approved page becomes source of truth for the screens, and the theme is written
|
|
69
|
-
before it so what they approve is what ships.
|
|
74
|
+
before it so what they approve is what ships. Only an explicit no skips it.
|
|
75
|
+
- **May I write test records into the system it talks to?** Ask only when the
|
|
76
|
+
app reads a live system through an addon (an ERP, a CRM) and a milestone needs
|
|
77
|
+
data that isn't there yet: an unpaid invoice, a closed ticket. Say what you
|
|
78
|
+
would create and that it will be marked "Test". A no means building those
|
|
79
|
+
screens against their empty states.
|
|
70
80
|
- **What language should the app speak, and what language does the team work
|
|
71
81
|
in?** Two answers, not one — see §1a, which is where they go. Ask only if the
|
|
72
82
|
request is not obviously English; a brief written in English about an English
|
|
@@ -343,8 +353,9 @@ What a milestone is:
|
|
|
343
353
|
persona. If you cannot write the gherkin, you cannot build it yet — that is a
|
|
344
354
|
`questions/` note, not a milestone.
|
|
345
355
|
|
|
346
|
-
If §1's screen mock was made
|
|
347
|
-
screen on that page belongs to some milestone,
|
|
356
|
+
If §1's screen mock was made — approved, or drawn because nobody answered — the
|
|
357
|
+
milestones are read off it: every screen on that page belongs to some milestone,
|
|
358
|
+
and a screen no milestone builds
|
|
348
359
|
is a hole in this plan. Say which milestone covers which screen.
|
|
349
360
|
|
|
350
361
|
How to order them:
|
|
@@ -363,8 +374,17 @@ How to order them:
|
|
|
363
374
|
Number the files (`01-…`, `02-…`) so the order is visible in the tree. Then
|
|
364
375
|
`knowledge index && knowledge validate` before you write a line of code.
|
|
365
376
|
|
|
366
|
-
**
|
|
367
|
-
|
|
377
|
+
**One approval, then build to the end.** Show the picture of the screens and
|
|
378
|
+
the milestone list together, in one message, as the plan: which milestone builds
|
|
379
|
+
which screen, in what order. That is the only approval you ask for. It is the
|
|
380
|
+
last cheap moment to reorder: after §6 the migrations are numbered and the order
|
|
381
|
+
is concrete.
|
|
382
|
+
|
|
383
|
+
Once they approve it, or don't answer, build every milestone in order without
|
|
384
|
+
stopping to ask between them. Post one line as each milestone closes, with its
|
|
385
|
+
console links, and carry on. Stop only for what is theirs to decide: a
|
|
386
|
+
credential you don't have, spending money, posting in public, deleting or
|
|
387
|
+
overwriting their data, or a finding that changes the plan.
|
|
368
388
|
|
|
369
389
|
## 5a. The technical plan — one milestone at a time, before you build it
|
|
370
390
|
|
|
@@ -399,6 +419,8 @@ no plan, and everything after the current milestone is still allowed to move.
|
|
|
399
419
|
|
|
400
420
|
## 6. Implement milestones, one at a time
|
|
401
421
|
|
|
422
|
+
All of them, one after another, on the one approval from §5.
|
|
423
|
+
|
|
402
424
|
**Per milestone** — plan it (§5a), set its note to `status: dispatched`, do the
|
|
403
425
|
six steps, close it out (§6a), set it to `built`. Do not start the next one
|
|
404
426
|
until §6a passes, §7 is green for this one _and §7a shows its functions
|
|
@@ -494,6 +516,35 @@ Rules that are not optional:
|
|
|
494
516
|
render the failure inline next to the control that triggered it — not a toast.
|
|
495
517
|
- An exposed function with no session and no permission is reachable by anyone
|
|
496
518
|
over `POST /rpc/:rpcName` (PKU574). Either gate it or drop `expose: true`.
|
|
519
|
+
- A public, signed-out read (a homepage's programme, a price list) is a
|
|
520
|
+
`pikkuSessionlessFunc`. `pikkuFunc` with `auth: false` still answers
|
|
521
|
+
`MissingSessionError` over `/rpc` to a caller with no session.
|
|
522
|
+
- Better Auth already owns the `user`, `session`, `account` and `verification`
|
|
523
|
+
tables. A domain table with one of those names — a class _session_, a drop-in
|
|
524
|
+
_session_ — collides in the migration. Name it for the domain instead
|
|
525
|
+
(`evening`, `class_meeting`) and keep the word in the UI copy.
|
|
526
|
+
- The template's `/` redirects to `/app`, so the login screen — and its "Sign in
|
|
527
|
+
as …" switcher — is what a signed-out visitor sees first. Replace `/` with a
|
|
528
|
+
public homepage and that stops being true: mount `<DevActorSwitcher />` in the
|
|
529
|
+
public layout as well, or a reviewer lands on a site with no way in.
|
|
530
|
+
|
|
531
|
+
Before the first run, make sure `.env` at the project root holds the two
|
|
532
|
+
secrets the local stack needs. `bun run dev` appends whichever is missing, but
|
|
533
|
+
check anyway — a project scaffolded from an older template, or a `.env` copied
|
|
534
|
+
in from elsewhere, can lack one, and neither failure names the variable:
|
|
535
|
+
|
|
536
|
+
- `BETTER_AUTH_SECRET` — without it the first sign-up is a 500.
|
|
537
|
+
- `SCENARIO_ACTOR_SECRET` — without it `/api/auth/sign-in/actor` is disabled:
|
|
538
|
+
every scenario fails at sign-in before its first step, and the "Sign in as …"
|
|
539
|
+
switcher renders nothing.
|
|
540
|
+
|
|
541
|
+
```sh
|
|
542
|
+
grep -q '^BETTER_AUTH_SECRET=' .env 2>/dev/null || echo "BETTER_AUTH_SECRET=$(openssl rand -base64 32)" >> .env
|
|
543
|
+
grep -q '^SCENARIO_ACTOR_SECRET=' .env 2>/dev/null || echo "SCENARIO_ACTOR_SECRET=$(openssl rand -base64 32)" >> .env
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
`.env` is gitignored and local only — never commit it. A deployed stage gets its
|
|
547
|
+
secrets from the platform (`pikku fabric secrets`), not from this file.
|
|
497
548
|
|
|
498
549
|
Then run it:
|
|
499
550
|
|
|
@@ -505,6 +556,19 @@ That starts the API on :3000 and every frontend in `pikkufabric.config.json`. A
|
|
|
505
556
|
frontend running against a dead API looks exactly like an app bug, so if every
|
|
506
557
|
request fails, check that both halves came up.
|
|
507
558
|
|
|
559
|
+
**Start the stack through `bun run dev`, not by launching `vite` or `pikku dev`
|
|
560
|
+
yourself.** The dev script reads the personas, derives one credential per
|
|
561
|
+
persona from `SCENARIO_ACTOR_SECRET`, and hands both to the frontend as
|
|
562
|
+
`VITE_DEV_ACTORS` / `VITE_DEV_ACTOR_SECRETS`. Vite reads those once, at boot. A
|
|
563
|
+
frontend started any other way — or restarted by hand later — has an empty
|
|
564
|
+
actor list, and the switcher silently disappears from every page. If you do
|
|
565
|
+
start the frontend on its own (say :3000 is taken by another project), you owe
|
|
566
|
+
it three things: the two `VITE_DEV_*` values the dev script would have computed,
|
|
567
|
+
and `VITE_API_PROXY` pointing at your API — the dev proxy defaults to
|
|
568
|
+
`http://localhost:3000`, so beside another project's server your sign-ins go to
|
|
569
|
+
_its_ API and come back `401 Invalid actor secret`, which reads like a bad
|
|
570
|
+
credential rather than the wrong server.
|
|
571
|
+
|
|
508
572
|
The `--bun` in `bunx --bun pikku …` is load-bearing — keep it. Without it the
|
|
509
573
|
CLI's `#!/usr/bin/env node` shebang hands the process to whatever Node is on
|
|
510
574
|
PATH, which fails below Node 24 with `ERR_UNKNOWN_BUILTIN_MODULE: No such
|
|
@@ -614,10 +678,11 @@ export const tenantReportsAFaultScenario = pikkuScenario<void, { id: string }>({
|
|
|
614
678
|
- **Write the refusals.** The third step above is the whole point of §4: one
|
|
615
679
|
persona reaching for another's row has to be rejected, and that rejection is a
|
|
616
680
|
scenario. It is how you prove access control instead of asserting it.
|
|
617
|
-
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
681
|
+
- **`SCENARIO_ACTOR_SECRET` must be in `.env`** (§6, before the first run).
|
|
682
|
+
Without it `/api/auth/sign-in/actor` is disabled — every scenario then fails
|
|
683
|
+
at sign-in, before its first step, for a reason that reads like an auth bug.
|
|
684
|
+
`pikku scenario run` reads it from the environment, so source `.env` first
|
|
685
|
+
(`set -a && . ./.env && set +a`) when you run outside `bun run dev`.
|
|
621
686
|
- **There is no state reset.** A scenario runs against a live server: scope what
|
|
622
687
|
you create to your own rows and unique ids, and never assume a clean database.
|
|
623
688
|
|
|
@@ -786,6 +851,11 @@ standalone`, `cloudflare`, `aws`), how to serve several frontends behind one
|
|
|
786
851
|
API, the pre-release gate to run, and the contract that keeps `pikku fabric init`
|
|
787
852
|
a one-command import later rather than a migration.
|
|
788
853
|
|
|
854
|
+
The app is not handed over without its user guide. The scenarios you wrote are
|
|
855
|
+
already its skeleton: read **pikku-guide**, write one page per audience citing
|
|
856
|
+
every feature, and build it from a full, passing `--run browser --screenshots`
|
|
857
|
+
run.
|
|
858
|
+
|
|
789
859
|
Two things from it are worth knowing before you get there, because they are
|
|
790
860
|
cheaper to honour than to retrofit:
|
|
791
861
|
|
|
@@ -54,13 +54,18 @@ allowed is landing on one because it was nearest to hand.
|
|
|
54
54
|
## Offer to draw the screens before you build them
|
|
55
55
|
|
|
56
56
|
Before the first milestone, **ask** whether they want to see the screens first.
|
|
57
|
-
One question, in §1's round, not a gate of its own
|
|
57
|
+
One question, in §1's round, not a gate of its own, with yes marked
|
|
58
|
+
recommended every time:
|
|
58
59
|
|
|
59
|
-
>
|
|
60
|
-
>
|
|
61
|
-
> than a built
|
|
60
|
+
> Before I build, shall I show you a picture of the main screens so you can say
|
|
61
|
+
> "yes, like that" or "no, move this"? (Recommended: it takes a few minutes and
|
|
62
|
+
> changing a picture is much cheaper than changing a built app.)
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
Never say "mock", "mockup" or "wireframe" to the person; most people do not
|
|
65
|
+
know the words. They stay the technical terms in this file only.
|
|
66
|
+
|
|
67
|
+
If they do not answer, draw it anyway and build from it. Only an explicit no
|
|
68
|
+
skips it; then build, and the direction in words is enough to be accountable to.
|
|
64
69
|
If they accept, this is the cheapest decision in the project — a picture of eight
|
|
65
70
|
screens costs a fraction of eight built screens, and it is the only point where
|
|
66
71
|
"that is not what I meant" is free.
|
|
@@ -105,6 +110,12 @@ first. Whatever your host offers for showing a page is how you show it: an
|
|
|
105
110
|
Artifact, a file they open, a preview server. The page is the deliverable; how it
|
|
106
111
|
gets in front of them is not this file's business.
|
|
107
112
|
|
|
113
|
+
**Say it is a picture, on the page and in the message.** A well-drawn screen
|
|
114
|
+
reads as a finished app, and a person who thinks it is already built asks why
|
|
115
|
+
nothing works. The page opens with a banner that stays in view: "A picture of
|
|
116
|
+
the planned screens. Nothing is built yet." The message that shows it says the
|
|
117
|
+
same, then says what happens next: "Once you're happy with it, I'll build it."
|
|
118
|
+
|
|
108
119
|
Write it to `knowledge/decisions/design/screens.html` and treat it as **source of
|
|
109
120
|
truth for the screens** once they approve it. That has consequences worth
|
|
110
121
|
stating:
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Pikku Create-a-Feature
|
|
2
2
|
|
|
3
|
+
The stages, in order:
|
|
4
|
+
|
|
5
|
+
- [Agent Operating Procedure](#agent-operating-procedure)
|
|
6
|
+
- [Stage 1 — Discover](#stage-1--discover)
|
|
7
|
+
- [Stage 2 — State intent in plain English (BEFORE writing code)](#stage-2--state-intent-in-plain-english-before-writing-code)
|
|
8
|
+
- [Stage 3 — Branch off](#stage-3--branch-off)
|
|
9
|
+
- [Stage 4 — Implement](#stage-4--implement)
|
|
10
|
+
- [Stage 5 — Verify](#stage-5--verify)
|
|
11
|
+
- [Stage 6 — Commit](#stage-6--commit)
|
|
12
|
+
- [Stage 7 — Hand off](#stage-7--hand-off)
|
|
13
|
+
- [Report what fought you](#report-what-fought-you)
|
|
14
|
+
- [Hard constraints](#hard-constraints)
|
|
15
|
+
- [Output discipline](#output-discipline)
|
|
16
|
+
|
|
3
17
|
## Agent Operating Procedure
|
|
4
18
|
|
|
5
19
|
Use this skill as an execution checklist, not reference material.
|
|
@@ -7,7 +21,7 @@ Use this skill as an execution checklist, not reference material.
|
|
|
7
21
|
1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
|
|
8
22
|
2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
|
|
9
23
|
3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
|
|
10
|
-
4. Validate with the narrowest relevant command first, then run `pikku
|
|
24
|
+
4. Validate with the narrowest relevant command first, then run `pikku all` when functions, wirings, schemas, or generated clients may have changed.
|
|
11
25
|
5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
|
|
12
26
|
6. Report anything about pikku itself that cost you time, the moment it happens — see **Report what fought you**.
|
|
13
27
|
|
|
@@ -242,103 +256,16 @@ Do not push without explicit confirmation. Do not merge.
|
|
|
242
256
|
|
|
243
257
|
## Report what fought you
|
|
244
258
|
|
|
245
|
-
When pikku itself is what cost you time
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
**Report at the moment it happens**, not at the end from memory — a run that
|
|
250
|
-
falls over never reaches its end. One finding per thing that fought you.
|
|
251
|
-
|
|
252
|
-
### The ladder
|
|
253
|
-
|
|
254
|
-
1. **Find the quicker workaround.** The user is paying for their feature, not
|
|
255
|
-
for pikku's health.
|
|
256
|
-
2. **Investigate** only when there is no workaround, or when the user asks why
|
|
257
|
-
something is slow or wrong.
|
|
258
|
-
3. **Report at the depth you already reached.** Never spend extra effort to
|
|
259
|
-
file; never throw away effort you already spent. If the investigation took
|
|
260
|
-
you to the mechanism, the finding says so — named file, named function, what
|
|
261
|
-
is actually happening, and what pikku should do instead.
|
|
262
|
-
|
|
263
|
-
**Never fix pikku itself.** Not a patch in `node_modules`, not a linked
|
|
264
|
-
checkout, not a branch in the framework repo. Many agents each patching pikku to
|
|
265
|
-
unblock themselves is many divergent copies and a merge problem nobody signed up
|
|
266
|
-
for. Work around it in the app, report it, and let the fix happen once.
|
|
267
|
-
|
|
268
|
-
### What counts
|
|
269
|
-
|
|
270
|
-
Anything that cost you time and would cost the next person the same. Most of
|
|
271
|
-
these never produce an error: output that is quietly wrong, a generated type
|
|
272
|
-
that disagrees with the runtime, a check that passes when it should not, a
|
|
273
|
-
narrowing you had to write by hand because the framework should have written it.
|
|
274
|
-
**Having to write code the framework should have written for you is a finding.**
|
|
275
|
-
|
|
276
|
-
So is anything that only shows up in one place — invisible locally, fatal
|
|
277
|
-
deployed, or the reverse. Say which, with `--surface`.
|
|
278
|
-
|
|
279
|
-
Not a finding: a preference, a thing you would have designed differently, or
|
|
280
|
-
baseline noise that was already failing before you started.
|
|
281
|
-
|
|
282
|
-
### Two kinds
|
|
283
|
-
|
|
284
|
-
- `--kind product` — pikku behaved wrongly. Fixing it is a change to the
|
|
285
|
-
framework.
|
|
286
|
-
- `--kind harness` — a skill misled you: it told you to run something that does
|
|
287
|
-
not exist, described a flag that is spelled differently, or contradicted what
|
|
288
|
-
the CLI actually did. Pass `--skill <name>` and `--passage "<the line or
|
|
289
|
-
section>"`. This is the most useful kind to file, because it is fixable
|
|
290
|
-
immediately — so file it even when the cost was small.
|
|
291
|
-
|
|
292
|
-
### When there was no workaround
|
|
293
|
-
|
|
294
|
-
Report it anyway with `--unresolved`, and put what you tried and how each
|
|
295
|
-
attempt failed in `--tried`. That is what stops the next person walking the same
|
|
296
|
-
dead ends. Tell the user what you did instead — abandoned it, shipped something
|
|
297
|
-
degraded, or stopped.
|
|
298
|
-
|
|
299
|
-
`--unresolved` means **no workaround was found**. It does not mean the
|
|
300
|
-
workaround was unpleasant.
|
|
301
|
-
|
|
302
|
-
### The command
|
|
303
|
-
|
|
304
|
-
Send it as JSON on stdin. Most of a finding is prose, and prose carries
|
|
305
|
-
apostrophes, quotes, backticks and newlines — each one a shell metacharacter
|
|
306
|
-
before it is a character in your sentence. A stack trace passed to `--error`
|
|
307
|
-
breaks the command at its first newline; a backtick in `--actual` runs whatever
|
|
308
|
-
follows it. Quote the heredoc delimiter (`<<'EOF'`, never `<<EOF`) so the shell
|
|
309
|
-
leaves the body alone.
|
|
310
|
-
|
|
311
|
-
```bash
|
|
312
|
-
pikku fabric report --stdin <<'EOF'
|
|
313
|
-
{
|
|
314
|
-
"title": "<one-line title>",
|
|
315
|
-
"kind": "product",
|
|
316
|
-
"model": "<the model you are>",
|
|
317
|
-
"expected": "<what you expected pikku to do>",
|
|
318
|
-
"actual": "<what it did instead>",
|
|
319
|
-
"command": "<the command you ran>",
|
|
320
|
-
"workaround": "<what you did instead, inside the app>"
|
|
321
|
-
}
|
|
322
|
-
EOF
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
Add whichever of these you actually have: `error` (the error's message line,
|
|
326
|
-
verbatim), `repro` (the shortest way to reach it again), `proposal` (what pikku
|
|
327
|
-
should do), `area`, `surface` (`local`, `deployed` or `both`), `cost` (measured
|
|
328
|
-
if you measured it — "98s vs 20s steady" ranks; "slow" does not), `run` (an id
|
|
329
|
-
shared by every finding from this build), `deployTarget`.
|
|
330
|
-
|
|
331
|
-
The same fields exist as flags — `--kind`, `--expected` and so on — for a
|
|
332
|
-
finding short enough to type. Anything with a newline or a quote in it goes
|
|
333
|
-
through `--stdin`.
|
|
259
|
+
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 with `pikku fabric
|
|
261
|
+
report`. The `pikku-report` skill owns the ladder, the two kinds, the JSON-on-
|
|
262
|
+
stdin form and the local spool; read it before filing.
|
|
334
263
|
|
|
335
|
-
|
|
336
|
-
|
|
264
|
+
Reporting at all is permitted here (see **Hard constraints**) and is the one
|
|
265
|
+
network call a build may make. Nothing is written to the repo. Never patch pikku
|
|
266
|
+
itself — not `node_modules`, not a linked checkout — work around it in the app,
|
|
267
|
+
report it, and let the fix happen once.
|
|
337
268
|
|
|
338
|
-
Reporting never fails a build. A finding that cannot be sent — logged out, or
|
|
339
|
-
fabric unreachable — is held on the machine and goes out with the next report
|
|
340
|
-
that succeeds, so nothing you file is lost. If it says the finding was queued,
|
|
341
|
-
carry on with the feature; do not try to fix it, and do not file it again.
|
|
342
269
|
|
|
343
270
|
## Hard constraints
|
|
344
271
|
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# An app on top of an OpenAPI spec
|
|
2
|
+
|
|
3
|
+
The spec becomes an addon first — the `pikku-addon` skill's
|
|
4
|
+
`references/openapi.md` covers generating, verifying and checking it against
|
|
5
|
+
the real API. This reference is the decision that shapes the app around it:
|
|
6
|
+
**whose credentials reach the upstream**, and what the person signs in with.
|
|
7
|
+
|
|
8
|
+
## Pick the auth mode
|
|
9
|
+
|
|
10
|
+
| The upstream… | Mode | Command | Who signs in, and how |
|
|
11
|
+
| ------------------------------------------------------------------------ | ----------------- | ----------------------------- | ------------------------------------------------------- |
|
|
12
|
+
| 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 |
|
|
13
|
+
| 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 |
|
|
14
|
+
| Uses OAuth2 | Per-user OAuth | (the default) | App account, then Connect via the OAuth consent |
|
|
15
|
+
| Is used on everyone's behalf with one key the business owns | Shared secret | `--auth shared` | App account only; the key is a secret |
|
|
16
|
+
| Takes no auth | None | `--auth none` | App account only |
|
|
17
|
+
|
|
18
|
+
Per-user is the default because the upstream then enforces each person's own
|
|
19
|
+
permissions. A shared secret acts with one identity for everyone, so the
|
|
20
|
+
install exposes only its reads; widen that deliberately, never by default.
|
|
21
|
+
|
|
22
|
+
The mode comes from the spec's `securitySchemes` unless a flag overrides it.
|
|
23
|
+
Many real specs describe auth only in prose. The generator then refuses rather
|
|
24
|
+
than guessing. Read the API's docs and pass the flag that is true.
|
|
25
|
+
|
|
26
|
+
**Delegated is the right call whenever the upstream is the system of record for
|
|
27
|
+
who the users are** — an ERP, a CRM, a helpdesk the whole team already logs in
|
|
28
|
+
to. The app then has no separate sign-up, the upstream token is stored per user
|
|
29
|
+
at sign-in, and every call acts as that user.
|
|
30
|
+
|
|
31
|
+
## The auth-config file
|
|
32
|
+
|
|
33
|
+
JSON, passed with `--auth-config`. Every field is optional except where noted.
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"headerName": "DOLAPIKEY",
|
|
38
|
+
"headerFormat": "raw",
|
|
39
|
+
"extraHeaders": { "Origin": "https://tenant.example.com" },
|
|
40
|
+
"delegated": {
|
|
41
|
+
"loginPath": "/login",
|
|
42
|
+
"loginMethod": "post",
|
|
43
|
+
"credentials": ["login", "password"],
|
|
44
|
+
"fields": { "login": "login", "password": "password" },
|
|
45
|
+
"encoding": "json",
|
|
46
|
+
"tokenPath": "success.token",
|
|
47
|
+
"expiresAtPath": "success.expires",
|
|
48
|
+
"identity": { "path": "/users/info", "method": "get" },
|
|
49
|
+
"claims": {
|
|
50
|
+
"source": "identity",
|
|
51
|
+
"externalId": "id",
|
|
52
|
+
"email": "email",
|
|
53
|
+
"name": ["firstname", "lastname"],
|
|
54
|
+
"role": "admin",
|
|
55
|
+
"tenantId": "entity"
|
|
56
|
+
},
|
|
57
|
+
"emailTemplate": "{login}@{host}",
|
|
58
|
+
"roles": { "1": "dolibarr-admin" }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Top level — how every call authenticates:
|
|
64
|
+
|
|
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 |
|
|
68
|
+
| `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 |
|
|
71
|
+
|
|
72
|
+
`delegated`:
|
|
73
|
+
|
|
74
|
+
| Field | Meaning |
|
|
75
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------- |
|
|
76
|
+
| `loginPath` | Required. The spec-relative login operation |
|
|
77
|
+
| `loginMethod` | Default `post` |
|
|
78
|
+
| `credentials` | What the sign-in form collects: `login` (a username or email), `email`, `password`, `apiKey`. Default `["email","password"]` |
|
|
79
|
+
| `fields` | The upstream's name for each credential, e.g. `{ "login": "username" }` |
|
|
80
|
+
| `encoding` | `json`, `form` or `query` — how the login fields travel. Default `json` |
|
|
81
|
+
| `apiKeyHeader` | The header an `apiKey` credential is sent in. Default `x-api-key` |
|
|
82
|
+
| `tokenPath` | Required. Dot-path to the token in the login response |
|
|
83
|
+
| `expiresAtPath` | Dot-path to an epoch-seconds expiry. Defaults to the JWT's `exp` when claims come from the JWT |
|
|
84
|
+
| `identity` | An operation that returns the signed-in user, called with the new token — for logins that return only a token |
|
|
85
|
+
| `claims.source` | `jwt`, `response` or `identity`. Default `identity` when `identity` is set, else `response` |
|
|
86
|
+
| `claims.*` | Dot-paths to `externalId`, `email`, `name` (one path or several joined with a space), `role`, `tenantId` |
|
|
87
|
+
| `emailTemplate` | Builds an email for an upstream user who has none: `{login}`, `{externalId}`, `{host}`. Such an address never claims an existing user |
|
|
88
|
+
| `roles` | Maps the raw `claims.role` value onto an app role; an unmapped value gets no role |
|
|
89
|
+
|
|
90
|
+
Check it before building on it: start `pikku dev`, sign in once with
|
|
91
|
+
`POST /api/auth/sign-in/delegated` as a real upstream user, and call an exposed
|
|
92
|
+
operation with the session. A wrong password must be refused. Keep real
|
|
93
|
+
credentials in the environment, never in the config or a test.
|
|
94
|
+
|
|
95
|
+
What the install wires for delegated mode — `pikkuDelegatedAuth` in
|
|
96
|
+
`src/auth.ts`, the token stored per user, actors carrying it into scenarios — is
|
|
97
|
+
in the `pikku-auth` skill's `references/better-auth.md`.
|
|
98
|
+
|
|
99
|
+
## The screens
|
|
100
|
+
|
|
101
|
+
**If the app has a UI, build the sign-in or connect screen that matches the chosen auth mode (Sign in with <X> for delegated, a Connect <X> screen for per-user keys/OAuth, nothing for a shared secret), labelling fields in the upstream's terms (e.g. 'Dolibarr login', not 'Email').**
|
|
102
|
+
|
|
103
|
+
- **Delegated** — the sign-in page posts to `POST /api/auth/sign-in/delegated`
|
|
104
|
+
with the fields named in `credentials` (`login` or `username`, `password`).
|
|
105
|
+
It replaces email sign-up; there is no "create account".
|
|
106
|
+
- **Per-user key or OAuth** — a Connect screen after sign-in, and wherever a
|
|
107
|
+
call fails with `missing_credential`.
|
|
108
|
+
- A `credential_rejected` error (`CredentialRejectedError`, 403) means the
|
|
109
|
+
upstream refused the stored token: show the sign-in again (`reauth:
|
|
110
|
+
'sign-in'`) or the Connect screen (`reauth: 'connect'`), not a generic error.
|
|
111
|
+
|
|
112
|
+
## Scenarios
|
|
113
|
+
|
|
114
|
+
A persona that signs in through the upstream needs an upstream credential to
|
|
115
|
+
act with. The install adds `credentials` to `pikkuActor` in `src/auth.ts`, and
|
|
116
|
+
at sign-in each actor stores `ACTOR_CREDENTIAL_<PERSONA>_<NAME>` from the
|
|
117
|
+
environment (e.g. `ACTOR_CREDENTIAL_SALES_REP_DOLIBARR`). Without it every
|
|
118
|
+
scenario step that reaches the upstream fails with `missing_credential`. The
|
|
119
|
+
`pikku-scenario` skill's `references/personas.md` has the details.
|
|
@@ -16,6 +16,10 @@ failed; a showcase where every surface is a stub has also failed. The bar for
|
|
|
16
16
|
each surface below: **it does something the app genuinely needs, and a scenario
|
|
17
17
|
proves it.** A cron job that logs "tick" is not a schedule — it is a comment.
|
|
18
18
|
|
|
19
|
+
Each surface lands with its console link, filtered by the person's level
|
|
20
|
+
(SKILL.md, "Who you are talking to"): a non-technical person sees the workflow
|
|
21
|
+
or agent page, never the queue, scheduler or wire pages behind it.
|
|
22
|
+
|
|
19
23
|
Budget the extra surfaces at one milestone each. They are not free, and a
|
|
20
24
|
half-wired workflow engine is worse than no workflow engine.
|
|
21
25
|
|
|
@@ -149,7 +149,17 @@ than they save:
|
|
|
149
149
|
keystroke now and a rewrite later.
|
|
150
150
|
- Never hardcode a host or port — the API base resolves to same-origin `/api`.
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
Before the first run, make sure `.env` holds both local secrets — `bun run dev`
|
|
153
|
+
appends missing ones, but an older scaffold or a copied `.env` may not have them:
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
grep -q '^BETTER_AUTH_SECRET=' .env 2>/dev/null || echo "BETTER_AUTH_SECRET=$(openssl rand -base64 32)" >> .env
|
|
157
|
+
grep -q '^SCENARIO_ACTOR_SECRET=' .env 2>/dev/null || echo "SCENARIO_ACTOR_SECRET=$(openssl rand -base64 32)" >> .env
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Never commit `.env`. Then run it — through `bun run dev`, never `vite` on its
|
|
161
|
+
own, because the dev script is what hands the frontend the persona list for the
|
|
162
|
+
"Sign in as …" switcher; without it the switcher silently renders nothing:
|
|
153
163
|
|
|
154
164
|
```sh
|
|
155
165
|
bun run prebuild && bun run dev
|
|
@@ -200,8 +210,7 @@ export const ownerCreatesAndSeesItScenario = pikkuScenario<void, { id: string }>
|
|
|
200
210
|
`pikkuScenarioStep`.** An RPC name in a `then` will not resolve.
|
|
201
211
|
- **Every scenario must assert.** A ladder with no `then` is a PKU680 critical —
|
|
202
212
|
it fails `pikku all`, stopping codegen rather than a test.
|
|
203
|
-
-
|
|
204
|
-
only a `BETTER_AUTH_SECRET`; without the actor secret
|
|
213
|
+
- **`SCENARIO_ACTOR_SECRET` must be in `.env`** (above). Without it
|
|
205
214
|
`/api/auth/sign-in/actor` is disabled and every scenario fails at sign-in, for
|
|
206
215
|
a reason that reads like an auth bug.
|
|
207
216
|
- **There is no state reset** — scope what you create to unique ids.
|
|
@@ -214,9 +223,10 @@ bunx --bun pikku scenario run local --spawn
|
|
|
214
223
|
|
|
215
224
|
## 6. Hand it over honestly
|
|
216
225
|
|
|
217
|
-
Tell the user, in one short paragraph
|
|
218
|
-
|
|
219
|
-
|
|
226
|
+
Tell the user, in one short paragraph and at their level (SKILL.md, "Who you
|
|
227
|
+
are talking to"), with console links rather than descriptions: what runs, what
|
|
228
|
+
it is seeded with, and that this is a quick build — no knowledge base, no
|
|
229
|
+
milestones, no design pass, access control clicked-through rather than proven.
|
|
220
230
|
|
|
221
231
|
**Upgrading to a real build is additive, not a rewrite.** If they want it, switch
|
|
222
232
|
to `references/app.md` and do this, in order:
|