@pikku/skills 0.12.13 → 0.12.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/skills.gen.js +1 -1
  3. package/package.json +1 -1
  4. package/skills/pikku-ai-vercel/SKILL.md +0 -1
  5. package/skills/pikku-ai-voice/SKILL.md +1 -0
  6. package/skills/pikku-audit/SKILL.md +0 -1
  7. package/skills/pikku-better-auth/SKILL.md +0 -1
  8. package/skills/pikku-build-app/SKILL.md +0 -1
  9. package/skills/pikku-build-platform/SKILL.md +3 -4
  10. package/skills/pikku-build-quick/SKILL.md +0 -1
  11. package/skills/pikku-concepts/SKILL.md +58 -16
  12. package/skills/pikku-concepts/references/concept-mapping.md +1 -1
  13. package/skills/pikku-deploy-cloudflare/SKILL.md +0 -1
  14. package/skills/pikku-deps/SKILL.md +0 -1
  15. package/skills/pikku-emails/SKILL.md +0 -1
  16. package/skills/pikku-fabric/SKILL.md +55 -4
  17. package/skills/pikku-feature/SKILL.md +0 -1
  18. package/skills/pikku-gateway-slack/SKILL.md +1 -0
  19. package/skills/pikku-i18n/SKILL.md +1 -1
  20. package/skills/pikku-info/SKILL.md +0 -1
  21. package/skills/pikku-knowledge/SKILL.md +0 -1
  22. package/skills/pikku-kysely/SKILL.md +0 -1
  23. package/skills/pikku-paraglide/SKILL.md +1 -1
  24. package/skills/pikku-product-second-opinion/SKILL.md +0 -1
  25. package/skills/pikku-queue/SKILL.md +1 -1
  26. package/skills/pikku-react/SKILL.md +1 -1
  27. package/skills/pikku-react-query/SKILL.md +1 -1
  28. package/skills/pikku-realtime/SKILL.md +0 -1
  29. package/skills/pikku-rpc/SKILL.md +0 -1
  30. package/skills/pikku-rtl/SKILL.md +1 -1
  31. package/skills/pikku-scenario/SKILL.md +29 -2
  32. package/skills/pikku-schedule/SKILL.md +178 -50
  33. package/skills/pikku-schema-ajv/SKILL.md +0 -1
  34. package/skills/pikku-schema-cfworker/SKILL.md +0 -1
  35. package/skills/pikku-security/SKILL.md +2 -2
  36. package/skills/pikku-software-archaeology/SKILL.md +0 -1
  37. package/skills/pikku-template-clone/SKILL.md +0 -1
  38. package/skills/pikku-trigger/SKILL.md +1 -1
  39. package/skills/pikku-versioning/SKILL.md +0 -1
  40. package/skills/pikku-workflow/SKILL.md +1 -1
  41. package/skills/pikku-workflows-client/SKILL.md +1 -1
  42. package/skills/pikku-cron/SKILL.md +0 -221
  43. package/skills/pikku-tag-middleware/SKILL.md +0 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/skills",
3
- "version": "0.12.13",
3
+ "version": "0.12.14",
4
4
  "description": "The Pikku agent skills — the instruction set coding agents read to build, wire and deploy Pikku projects",
5
5
  "author": "yasser.fadl@gmail.com",
6
6
  "license": "MIT",
@@ -6,7 +6,6 @@ description: >-
6
6
  VercelAgentRunner, user asks about Vercel AI SDK integration, AI agent runners, or
7
7
  @pikku/ai-vercel. DO NOT TRIGGER when: user asks about AI agent wiring (use pikku-agent) or
8
8
  voice I/O (use pikku-ai-voice).
9
- installGroups: [core]
10
9
  ---
11
10
 
12
11
  # Pikku AI Vercel (Agent Runner)
@@ -7,6 +7,7 @@ description: >-
7
7
  agents, speech-to-text, text-to-speech, transcription, or @pikku/ai-voice. DO NOT TRIGGER when:
8
8
  user asks about AI agent wiring generally (use pikku-agent) or the runner itself (use
9
9
  pikku-ai-vercel).
10
+ installGroups: [fabric]
10
11
  ---
11
12
 
12
13
  # Pikku AI Voice (Speech I/O)
@@ -10,7 +10,6 @@ description: >-
10
10
  uses auditLog, createInvocationAudit, createAuditedKysely, or AuditService. DO NOT TRIGGER when:
11
11
  user wants app logging/telemetry (use the logger) or DB migrations in general (use
12
12
  pikku-kysely).
13
- installGroups: [core]
14
13
  ---
15
14
 
16
15
  # Pikku Audit
@@ -10,7 +10,6 @@ description: >-
10
10
  user asks about ANY form of authentication, login, logout, sessions, or user identity — always
11
11
  answer with this skill. DO NOT TRIGGER when: user asks about JWT middleware (use pikku-security)
12
12
  or custom session services (use pikku-services).
13
- installGroups: [core]
14
13
  ---
15
14
 
16
15
  # Pikku Better Auth Integration
@@ -10,7 +10,6 @@ description: >-
10
10
  something quick or throwaway (use pikku-build-quick), wants every platform surface demonstrated
11
11
  (use pikku-build-platform), or is adding one feature to an app that already has its knowledge
12
12
  base and milestones (use pikku-feature).
13
- installGroups: [core]
14
13
  ---
15
14
 
16
15
  # Build a product on open-source Pikku
@@ -8,8 +8,7 @@ description: >-
8
8
  app, or asked to demonstrate what Pikku can do. DO NOT TRIGGER when: the user wants a product
9
9
  built (use pikku-build-app), something quick (use pikku-build-quick), or one specific surface
10
10
  wired into an existing app — a single workflow, cron job or agent (use that surface's own skill,
11
- e.g. pikku-workflow, pikku-cron, pikku-agent).
12
- installGroups: [core]
11
+ e.g. pikku-workflow, pikku-schedule, pikku-agent).
13
12
  ---
14
13
 
15
14
  # Build a platform showcase on Pikku
@@ -90,7 +89,7 @@ on a human or a timer and must survive a restart.
90
89
  from the UI.
91
90
  - Three workflows ship with the template. Read them before writing yours.
92
91
 
93
- ### Schedules — `pikku-schedule` / `pikku-cron`
92
+ ### Schedules — `pikku-schedule`
94
93
 
95
94
  Recurring work: a nightly rollup, a reminder sweep, an expiry pass.
96
95
 
@@ -231,7 +230,7 @@ built.
231
230
  ## Reference
232
231
 
233
232
  - Base workflow: `pikku-build-app` — read it first, follow it in full
234
- - Per-surface skills: `pikku-workflow`, `pikku-schedule`, `pikku-cron`,
233
+ - Per-surface skills: `pikku-workflow`, `pikku-schedule`,
235
234
  `pikku-queue`, `pikku-agent`, `pikku-ai-vercel`, `pikku-realtime`,
236
235
  `pikku-websocket`, `pikku-mcp`, `pikku-trigger`, `pikku-i18n`, `pikku-rtl`,
237
236
  `pikku-emails`, `pikku-versioning`, `pikku-addon`, `pikku-security`,
@@ -12,7 +12,6 @@ description: >-
12
12
  workflows, queues, realtime or i18n (use pikku-build-platform); or the user is adding a feature
13
13
  to an app that already exists rather than building one from a fresh scaffold (use
14
14
  pikku-feature).
15
- installGroups: [core]
16
15
  ---
17
16
 
18
17
  # Build an app on Pikku, fast
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: pikku-concepts
3
3
  description: >-
4
- Foundational guide to Pikku framework concepts. Use this skill when working with any Pikku
5
- codebase, starting a new Pikku project, or migrating a backend to Pikku. Covers the core mental
6
- model, function types, project structure, code generation, testing, and how Pikku maps to
7
- traditional backend patterns. TRIGGER when: user asks "what is Pikku?", starts a new Pikku
8
- project, migrates from Express/NestJS/Hono, or needs to understand how Pikku works. DO NOT
9
- TRIGGER when: user is doing a specific wiring task (use the specific skill instead, e.g.
10
- pikku-http, pikku-websocket).
4
+ Use FIRST in any Pikku codebase, before writing an import or reaching for another pikku skill.
5
+ Covers the core mental model, function types, project structure, code generation and testing,
6
+ and how to read `pikku doc` — the API surface of the pikku actually installed here, which also
7
+ indexes which skill teaches each door. TRIGGER when: starting any Pikku task, about to import
8
+ from `#pikku/*`, unsure whether an export exists or what its options are called, choosing which
9
+ pikku skill to load, a build failed on an unknown import or option, or migrating an existing
10
+ backend to Pikku. DO NOT TRIGGER when: the task is not a Pikku project.
11
11
  installGroups: [core]
12
12
  ---
13
13
 
@@ -17,7 +17,7 @@ installGroups: [core]
17
17
 
18
18
  Use this skill as an execution checklist, not reference material.
19
19
 
20
- 1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
20
+ 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
21
  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.
22
22
  3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
23
23
  4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
@@ -25,12 +25,54 @@ Use this skill as an execution checklist, not reference material.
25
25
 
26
26
  Pikku is a TypeScript framework that separates business logic from transport mechanisms. You define a function once, then wire it to HTTP, WebSocket, queues, schedulers, MCP, CLI, or RPC — without the function knowing how it's being called.
27
27
 
28
- For deep-dive on each topic, see the dedicated skills:
28
+ ## Ask The Installed Pikku, Don't Guess
29
29
 
30
- - **Wiring**: `pikku-http`, `pikku-websocket`, `pikku-rpc`, `pikku-mcp`, `pikku-queue`, `pikku-cron`, `pikku-trigger`, `pikku-cli`, `pikku-agent`, `pikku-workflow`
31
- - **Authorization**: `pikku-security` (authentication/sessions), `pikku-permissions` (permission checks, scopes), `pikku-middleware` (global/tag/route middleware)
32
- - **Infrastructure**: `pikku-services`, `pikku-config`
33
- - **Project introspection**: `pikku-info`
30
+ Pikku generates `#pikku/*` imports per project and changes between versions. Anything you
31
+ remember about its API may be from a different version than the one in this directory.
32
+ Everything below is the mental model; `pikku doc` is the API surface, computed when the
33
+ installed CLI was built. It needs no config and works outside a project.
34
+
35
+ **Do not write an import, an export name, or an option key you have not seen in `pikku doc`.**
36
+ A name that looks right and is not costs a full build cycle to discover. If the doc does not
37
+ list it, it does not exist here — do not reach into `node_modules` or `.pikku` for something
38
+ that will work anyway.
39
+
40
+ ### Start here, every time
41
+
42
+ ```
43
+ pikku doc --ai
44
+ ```
45
+
46
+ ≈480 tokens, giving the 20 `#pikku/*` doors grouped by the job they do, and beside each the
47
+ skill that teaches it. Read that routing table as the index to every other pikku skill — it is
48
+ generated from the installed version, so it never names a skill for a door that no longer exists.
49
+
50
+ Then go one of two ways. For **what exists** — the exact export name, its options, its
51
+ signature — stay in the doc:
52
+
53
+ ```
54
+ pikku doc http one door: its exports, each with a signature or a key count
55
+ pikku doc wireHTTP one export: signature, every key with what it is for
56
+ pikku doc wireHTTP pikkuFunc several topics in one call, rather than one call each
57
+ ```
58
+
59
+ For **how it fits together** — composition, lifecycle, the generated client — load the skill
60
+ the routing table named. The doc lists keys; it does not teach patterns.
61
+
62
+ On a door screen, `N keys — pikku doc X` means a second call buys you something; an inlined
63
+ signature means it does not. Error classes carry the HTTP status they are registered with,
64
+ which is what decides whether a thrown error becomes a 409 or a 500.
65
+
66
+ ### Two things the doc will not give you
67
+
68
+ - **Worked examples are sparse.** Most exports show a signature and keys, not usage.
69
+ - **`pikkuFunc` lists keys that belong elsewhere.** `before`, `after`, `skip`, `surfaces` and
70
+ `requiresActor` apply only to scenarios; `workflowQueued`, `workflowRetries` and
71
+ `workflowTimeout` only to a workflow step. One shared config type offers all of them to
72
+ every function — each key says which it belongs to.
73
+
74
+ `pikku doc` needs `@pikku/cli` 0.12.115 or newer. On an older pin, fall back to the door's
75
+ skill and `pikku meta --json`, and do not guess at names the doc would have given you.
34
76
 
35
77
  ## Core Mental Model
36
78
 
@@ -59,7 +101,7 @@ The function never imports Express, never reads `req.body`, never touches `ws.se
59
101
 
60
102
  ## Concept Mapping: Generic Backend → Pikku
61
103
 
62
- Controllers/routes → `pikkuFunc`; auth/sessions → `pikku-security`; authorization checks → `pikku-permissions`; request interception → `pikku-middleware`; DI → `pikku-services`; transports (HTTP/WS/queue/cron) → their `wire*` + skill. For the full Generic Backend → Pikku mapping table (with side-by-side code examples), read `references/concept-mapping.md`.
104
+ Controllers/routes → `pikkuFunc`; auth/sessions → `pikku-security`, a separate install; authorization checks → `pikku-permissions`; request interception → `pikku-middleware`; DI → `pikku-services`; transports (HTTP/WS/queue/cron) → their `wire*` + skill. For the full Generic Backend → Pikku mapping table (with side-by-side code examples), read `references/concept-mapping.md`.
63
105
 
64
106
  ## Functions
65
107
 
@@ -270,8 +312,8 @@ src/
270
312
  ├── schemas.ts # Zod/Valibot schemas
271
313
  ├── services.ts # Service factories (see pikku-services)
272
314
  ├── lifecycle.ts # Server lifecycle hooks (pikku dev/serve only)
273
- ├── middleware.ts # Middleware definitions (see pikku-security)
274
- ├── permissions.ts # Permission definitions (see pikku-security)
315
+ ├── middleware.ts # Middleware definitions (see pikku-middleware)
316
+ ├── permissions.ts # Permission definitions (see pikku-permissions)
275
317
  └── .pikku/ # Generated (gitignored)
276
318
  ├── function/ # #pikku/function
277
319
  ├── http/ # #pikku/http
@@ -15,7 +15,7 @@ Authoritative mapping table plus side-by-side code examples showing how common b
15
15
  | **Dependency Injection** | `pikkuServices` (singleton) + `pikkuWireServices` (per-request) | `pikku-services` |
16
16
  | **WebSocket handlers** | `wireChannel` | `pikku-websocket` |
17
17
  | **Job Queue workers** | `wireQueueWorker` | `pikku-queue` |
18
- | **Cron / Scheduled tasks** | `wireScheduler` | `pikku-cron` |
18
+ | **Cron / Scheduled tasks** | `wireScheduler` | `pikku-schedule` |
19
19
  | **Module / Feature grouping** | Tags + wiring files | `pikku-concepts` |
20
20
  | **Error handling** | Throw typed errors (`NotFoundError`, `ForbiddenError`) | `pikku-concepts` |
21
21
  | **Type-safe API client** | `npx pikku all` generates clients | `pikku-concepts` |
@@ -5,7 +5,6 @@ description: >-
5
5
  tasks, and WebSocket via Durable Objects. TRIGGER when: code imports @pikku/cloudflare, user
6
6
  mentions Cloudflare Workers deployment, or worker entry uses ExportedHandler/wrangler.toml. DO
7
7
  NOT TRIGGER when: just defining functions/wirings without Cloudflare-specific code.
8
- installGroups: [fabric]
9
8
  ---
10
9
 
11
10
  # Pikku Cloudflare Workers Deployment
@@ -12,7 +12,6 @@ description: >-
12
12
  reading/rendering audit.json. DO NOT TRIGGER when: user asks about authentication/sessions/JWT
13
13
  (use pikku-security), permissions (use pikku-permissions), or secrets/env vars (use
14
14
  pikku-config).
15
- installGroups: [core]
16
15
  ---
17
16
 
18
17
  # Pikku Dependency Audit
@@ -10,7 +10,6 @@ description: >-
10
10
  email (verification, password reset, invitation, receipt), wire email sending, or translate an
11
11
  email. DO NOT TRIGGER when: user asks about i18n for the app UI (use pikku-i18n) or auth flows
12
12
  in general (use pikku-better-auth).
13
- installGroups: [core]
14
13
  ---
15
14
 
16
15
  # Pikku Emails
@@ -273,13 +273,64 @@ reload).
273
273
  pikku fabric login # opens a browser; needs a human, wait for it
274
274
  pikku fabric init https://github.com/<owner>/<repo>
275
275
  pikku fabric validate # must pass clean
276
- pikku fabric deploy plan --production
277
- pikku fabric deploy apply --production --auto-apply
276
+ pikku fabric deploy apply --production --sync --auto-approve
278
277
  ```
279
278
 
279
+ There is no `deploy plan` subcommand — `apply` runs the same auth, git-safety
280
+ and ref resolution itself, and fabric produces the real plan server-side.
281
+
280
282
  `apply` confirms before deploying, and with no TTY to ask — CI, an agent shell —
281
- it refuses rather than hangs. `--auto-apply` supplies that confirmation; drop it
282
- only when a human is at a real terminal.
283
+ it refuses rather than hangs. `--auto-approve` supplies that confirmation; drop
284
+ it only when a human is at a real terminal.
285
+
286
+ By default `apply` queues the deploy, prints the deployment id and returns. That
287
+ tells you nothing about whether it worked. `--sync` waits for a terminal state
288
+ and exits non-zero unless the deployment went live, which is the only form worth
289
+ running in CI:
290
+
291
+ | exit | meaning |
292
+ | ---- | ------- |
293
+ | 0 | live (or queued, without `--sync`) |
294
+ | 1 | the command could not run — not logged in, unsafe git state, bad flags |
295
+ | 2 | the deployment failed, errored, timed out server-side, or was cancelled |
296
+ | 3 | the deployment is blocked and nothing the CLI can do will unblock it |
297
+ | 4 | the wait hit `--timeout` with the deployment still in flight |
298
+
299
+ Fabric parks every deploy at a gate after the plan phase (`status: suspended`).
300
+ Why it parked is the whole story, and it is `statusReason`, not `status`:
301
+
302
+ - `awaiting_approval` — the plan is fine, a human has to publish it.
303
+ `--auto-approve` does that; without it you get exit 3 and the command to run.
304
+ One exception: if fabric marked any pending migration **destructive** — a
305
+ drop, a truncate, a rewrite — `--auto-approve` alone declines and exits 3,
306
+ because a standing yes was given before anyone knew the plan dropped a table.
307
+ The CLI lists the migrations and fabric's reasons; `--allow-destructive`
308
+ accepts them for that deploy.
309
+ - `needs_config` — a declared secret or variable has no value covering the
310
+ stage. The CLI names them. `--auto-approve` will **not** force this through;
311
+ set the values (`pikku fabric secrets set <name>`) and re-attach.
312
+ - `needs_attention` — the plan is red. Nothing to approve.
313
+
314
+ `--sync` defaults to a 900s ceiling; `--timeout <seconds>` moves it. On timeout
315
+ it prints the deployment id and the re-attach command rather than lying about
316
+ the outcome.
317
+
318
+ Splitting kick-off from waiting across two CI jobs is the reason
319
+ `--deployment-id` exists:
320
+
321
+ ```bash
322
+ id=$(pikku fabric deploy apply --production --auto-approve --json | jq -r 'select(.event=="result").deploymentId')
323
+ # …later, in another job…
324
+ pikku fabric deploy apply --deployment-id "$id" --sync --auto-approve
325
+ ```
326
+
327
+ `--deployment-id` skips the git safety check entirely (the deployment already
328
+ pins a sha, and the checkout is allowed to have moved on) and refuses to be
329
+ combined with `--branch`/`--production`, which would let the two disagree.
330
+
331
+ Under `--json`, `--sync` emits one NDJSON event per line — `created`/`attached`,
332
+ `status` on each transition, `blocked`, `approved` — and the last line is the
333
+ terminal result object, tagged `"event": "result"`.
283
334
 
284
335
  `init` adopts a **GitHub** repo, and adoption goes through the Pikku Fabric
285
336
  GitHub App — the app has to be installed on the account or org that owns the
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: pikku-feature
3
3
  description: 'Drive create-a-feature work inside a Pikku project that already exists: discover project context, work on a feature branch, implement + verify + commit, and ask the user to review via the diff. TRIGGER when: the user asks to "create a feature", "add X to my Pikku project", "wire up a new endpoint", or anything that implies turning a natural-language request into Pikku functions/wirings/migrations within a working app. DO NOT TRIGGER when: the user asks for a one-off code edit in an existing function, asks about Pikku concepts (use pikku-concepts), or is building a whole app from a fresh scaffold rather than extending one (use pikku-build-app, or pikku-build-quick / pikku-build-platform).'
4
- installGroups: [core]
5
4
  allowed-tools: Bash(yarn pikku meta *), Bash(yarn pikku all *), Bash(yarn tsc), Bash(git status *), Bash(git diff *), Bash(git switch *), Bash(git checkout *), Bash(git checkout -b *), Bash(git add *), Bash(git commit *), Bash(git log *), Bash(git branch *)
6
5
  argument-hint: '<feature description>'
7
6
  ---
@@ -6,6 +6,7 @@ description: >-
6
6
  parseSlashCommand, buildSlackInstallUrl, or user asks about Slack integration, Slack bots, or
7
7
  @pikku/gateway-slack. DO NOT TRIGGER when: user asks about general gateway/webhook patterns (use
8
8
  pikku-trigger).
9
+ installGroups: [core]
9
10
  ---
10
11
 
11
12
  # Pikku Gateway Slack
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pikku-i18n
3
3
  description: 'Wire i18n into a Pikku frontend with Paraglide JS (inlang). English by default, every user-facing string is a typed message function (`m.some__key()`) compiled from `messages/<locale>.json`, and additional languages are served under `/fr` `/de` URL prefixes. TRIGGER when: scaffolding or editing a frontend and writing user-facing text, adding a second language, or asked to "make this translatable / use tokens / add i18n". DO NOT TRIGGER for backend functions, error messages thrown from functions, or log output.'
4
- installGroups: [core]
4
+ installGroups: [client]
5
5
  ---
6
6
 
7
7
  # Pikku i18n (Paraglide JS)
@@ -8,7 +8,6 @@ description: >-
8
8
  routes/middleware/permissions", or needs to understand an existing Pikku codebase. DO NOT
9
9
  TRIGGER when: user is writing new code (use the specific wiring skill) or asking about Pikku
10
10
  concepts (use pikku-concepts).
11
- installGroups: [core]
12
11
  allowed-tools: Bash(yarn pikku info *)
13
12
  argument-hint: '[functions|tags|middleware|permissions] [--verbose] [--limit N]'
14
13
  ---
@@ -13,7 +13,6 @@ description: >-
13
13
  brief to record. DO NOT TRIGGER when: user asks what
14
14
  functions, routes, tables or permissions exist (that is `pikku meta` / `pikku info`, never a
15
15
  note), or to write a scenario test (use pikku-scenario).
16
- installGroups: [core]
17
16
  ---
18
17
 
19
18
  # Pikku Knowledge
@@ -11,7 +11,6 @@ description: >-
11
11
  PikkuKysely, KyselyChannelStore, KyselyWorkflowService, KyselySecretService, or the user asks
12
12
  about SQL setup with Pikku. DO NOT TRIGGER when: user asks about MongoDB (use pikku-mongodb) or
13
13
  Redis (use pikku-redis).
14
- installGroups: [core]
15
14
  ---
16
15
 
17
16
  # Pikku Kysely (SQL Database Services)
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pikku-paraglide
3
3
  description: 'Generate typed, static enum-label maps for a Paraglide i18n frontend with `@pikku/paraglide`, and reconcile them against the database enum columns so a label can never silently drift from a DB value. Enum-valued labels live under a reserved `enum__<group>__<member>` message namespace; the generator emits `i18n-enum.gen.ts` typed `satisfies EnumLabel<DbEnum>`. TRIGGER when: labelling an enum/status/kind/role value in a Paraglide app, replacing a dynamic `mKey(...)`/`m[...]` lookup with a static map, wiring `@pikku/paraglide` into Vite, or reconciling i18n against `CHECK (col IN (...))` / Postgres enum columns. DO NOT TRIGGER for plain free-text UI copy (that is a normal `m.some_key()` message), backend errors, or logs.'
4
- installGroups: [core]
4
+ installGroups: [client]
5
5
  ---
6
6
 
7
7
  # Pikku Paraglide enum labels
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: pikku-product-second-opinion
3
3
  description: 'Use when a non-technical owner (founder, PM, operator) wants a plain-language report on an app they hold but did not build — explaining how it works and how it could be better. Reads the .knowledge/ blueprint from pikku-software-archaeology and produces a layered, jargon-free report that credits what works, names what does not (with business impact + effort), and argues an opinionated better design. TRIGGER: "explain how my app works", "what would you do differently", "review my app for a non-technical audience", "I inherited/am stuck with an agency-built app", "is this built well?". DO NOT TRIGGER for: extracting the machine-readable blueprint itself (use pikku-software-archaeology), or an engineer-facing technical code review.'
4
- installGroups: [fabric]
5
4
  ---
6
5
 
7
6
  # Product Second Opinion
@@ -5,7 +5,7 @@ description: >-
5
5
  app. Covers wireQueueWorker, job enqueuing, progress tracking, retries, BullMQ and PgBoss
6
6
  adapters. TRIGGER when: code uses wireQueueWorker, user asks about background jobs, task queues,
7
7
  async processing, BullMQ, PgBoss, or job retries. DO NOT TRIGGER when: user asks about scheduled
8
- cron tasks (use pikku-cron) or event-driven triggers (use pikku-trigger).
8
+ cron tasks (use pikku-schedule) or event-driven triggers (use pikku-trigger).
9
9
  installGroups: [core]
10
10
  ---
11
11
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pikku-react
3
3
  description: 'Set up @pikku/react in a React app: PikkuProvider context, createPikku factory, and the usePikkuRPC / usePikkuFetch hooks for direct (non-React-Query) calls. TRIGGER when: the user is bootstrapping a React frontend that talks to a Pikku backend, asks how to wire `PikkuProvider`, or needs to make one-off RPC calls outside of useQuery/useMutation. TRIGGER when: user asks about the dev actor switcher, "sign in as" / quick-login UI, useDevActors, VITE_DEV_ACTORS, or the app-missing-actor-quick-login validate finding. DO NOT TRIGGER when: the user is asking about useQuery/useMutation hooks (use pikku-react-query) or about workflows (use pikku-workflows-client).'
4
- installGroups: [core]
4
+ installGroups: [client]
5
5
  ---
6
6
 
7
7
  # Pikku React
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pikku-react-query
3
3
  description: 'Use the Pikku auto-generated React Query hooks (`usePikkuQuery`, `usePikkuMutation`, `usePikkuInfiniteQuery`) to call backend RPC functions from a React frontend with full type safety. TRIGGER when: writing React components that need to call a Pikku function, fetch data, mutate data, or paginate; user mentions React Query, useQuery, useMutation, or building a frontend that talks to a Pikku backend. DO NOT TRIGGER when: working on the backend (use pikku-rpc / pikku-feature) or wiring a non-React frontend.'
4
- installGroups: [core]
4
+ installGroups: [client]
5
5
  ---
6
6
 
7
7
  # Pikku React Query Hooks
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  name: pikku-realtime
3
3
  description: 'Use Pikku''s realtime feature — typed pub/sub events over WebSocket (multi-topic) or SSE (single-topic, auto-cleanup). Covers declaring EventHubTopics, scaffolding the /events channel, the auto-generated `PikkuRealtime` client, and publishing events from a function. TRIGGER when: the user asks for realtime updates, pub/sub, push notifications, server-sent events, websocket events, eventhub, or "live" data on the frontend. DO NOT TRIGGER when: the user wants RPC-style request/response (use pikku-rpc / pikku-react-query) or a custom one-off WebSocket channel (use pikku-websocket).'
4
- installGroups: [core]
5
4
  ---
6
5
 
7
6
  # Pikku Realtime
@@ -6,7 +6,6 @@ description: >-
6
6
  TRIGGER when: code uses wire.rpc or expose: true, user asks about calling one Pikku function
7
7
  from another, function composition, or RPC endpoints. DO NOT TRIGGER when: user asks about HTTP
8
8
  routes (use pikku-http) or addon cross-package calls (use pikku-addon).
9
- installGroups: [core]
10
9
  ---
11
10
 
12
11
  # Pikku RPC Wiring
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: pikku-rtl
3
3
  description: 'Make a Pikku frontend work in both English (LTR) and Arabic / right-to-left languages. Direction is derived from the active locale, applied once at the document root, and the layout mirrors itself — but only if styling is written flow-relative (margin-inline-start, text-align: start, Mantine ms/me) instead of left/right. TRIGGER when: adding Arabic (or Hebrew/Farsi/Urdu), asked to "support RTL / right-to-left / bidi / mirror the layout", or writing layout styles in an app that may run RTL. Builds on pikku-i18n (an RTL language is just another locale file). DO NOT TRIGGER for backend functions or for LTR-only copy changes.'
4
- installGroups: [core]
4
+ installGroups: [client]
5
5
  ---
6
6
 
7
7
  # Pikku RTL (Arabic + English)
@@ -534,6 +534,32 @@ export const opensTheCart = pikkuScenarioStep<
534
534
  - `pikku scenario run <env> --no-browser` **skips** scenarios containing browser steps and reports them as skipped — it does not fail them. That is how a machine with no browser stays green.
535
535
  - Playwright auto-waits; do not wrap `page.click` in `expectEventually`.
536
536
 
537
+ #### Locate by message key, never by rendered copy
538
+
539
+ If the app is translated, **no step may contain a user-visible string.** `getByLabel('Full Name')` passes only while the browser happens to render the base locale, and any copy edit turns it into a selector timeout that points at the wizard rather than at the rename that caused it — the test looks broken where it is merely stale.
540
+
541
+ The message catalogue already holds the string under a key. Read it from there. Type the lookup off the catalogue JSON so a renamed or misspelled key is a **compile** error rather than a run-time timeout:
542
+
543
+ ```typescript
544
+ // tests/scenarios/i18n.ts
545
+ import type messages from '../../../../apps/web/messages/en.json'
546
+
547
+ export type MessageKey = keyof typeof messages
548
+
549
+ export const t = (key: MessageKey, locale = baseLocale): string => { /* … */ }
550
+ ```
551
+
552
+ ```typescript
553
+ await page.getByLabel(t('jobs_apply_fullname')).fill(identity.name)
554
+ await page.getByRole('button', { name: t('jobs_apply_submit'), exact: true }).click()
555
+ ```
556
+
557
+ - Type off `messages/<baseLocale>.json`, **not** the generated Paraglide output — `i18n/paraglide/` is build output, so typing against it makes the tests unbuildable until the app has been built. The JSON is the tracked source.
558
+ - Fall back to the base locale for a key a locale has not translated. That is what Paraglide does at run time, so a helper that throws instead would disagree with the screen the test is looking at.
559
+ - This is not only about locators. A copy literal passed to a **project helper** (`pick('Where would you like to work?', …)`) reaches the DOM the same way, and so does a pane name quoted back in a failure message. `pikku fabric validate` scans every string in a `*.steps.ts` / `*.scenario.ts` against the base catalogue and errors on any verbatim match, wherever it sits.
560
+ - A regex locator (`{ name: /^Next$/i }`) hides the literal but not the problem. `{ name: t('key'), exact: true }` is both stricter and locale-correct.
561
+ - Strings the catalogue does not own — a test id, a fixture filename, a seeded value — stay literal. The catalogue is the test for whether something is copy.
562
+
537
563
  ## Configuration
538
564
 
539
565
  Personas, actors and environments live in `pikku.config.json`:
@@ -628,7 +654,7 @@ An actor with no `persona` is its own persona, so a project that never declares
628
654
  ### The same actors sign a human in
629
655
 
630
656
  Declared actors are not only for automated runs. `signInPath` is Better Auth's
631
- `actor` plugin (see `pikku-better-auth`), which any caller can post to — so the
657
+ `actor` plugin (see `pikku-better-auth`, a separate install), which any caller can post to — so the
632
658
  frontend gets a one-click "Sign in as …" switcher over the **same** list, and an
633
659
  app can be reviewed as each kind of user without anyone knowing a seed password.
634
660
 
@@ -639,7 +665,7 @@ control renders nothing there — but gate the reads on your bundler's dev flag
639
665
  anyway (`import.meta.env.DEV ? … : undefined`) so the secret never reaches a
640
666
  production bundle in the first place.
641
667
 
642
- Do not hand-roll the switcher: `useDevActors()` (`pikku-react`) is the logic and
668
+ Do not hand-roll the switcher: `useDevActors()` (`pikku-react`, a separate install) is the logic and
643
669
  `<DevActorSwitcher />` from `@pikku/mantine/dev` is a ready rendering of it.
644
670
  `pikku fabric validate` **requires** any frontend with a login screen to ship
645
671
  one — without it a reviewer is locked out of their own sandbox.
@@ -758,6 +784,7 @@ Services are plain objects — a Pikku function is pure business logic, so a moc
758
784
  | `sleep()` before asserting | Use `expectEventually`. |
759
785
  | A step named `clicksAddToBasket` / `opensThePage` | That is an action, not an intent. Name the step for what the actor wanted; put the clicking in a utility. |
760
786
  | A browser step that assumes it is already on a page | It can then only run mid-flow. Arrive first — check the URL, navigate if needed. |
787
+ | `getByLabel('Full Name')` in a translated app | Passes only in the base locale, and a copy edit breaks it as an unexplained timeout. Locate by message key. |
761
788
  | A `browser` binding guarding `if (!browser)` | The binding guarantees it. The guard hides the real error, which is a missing actor (`PKU677`). |
762
789
  | A step with a `func:` instead of a surface binding | There is no `func` on a step. Bodies live under `default` / `browser` / `cli`; a step with none throws at load. |
763
790
  | `expectEventually` in a `pikkuWorkflowFunc` | `PKU675` — scenario-only. |