@pikku/skills 0.12.52 → 0.12.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/README.md +1 -1
  2. package/dist/skills.gen.js +2 -2
  3. package/dist/snippets.js +1 -1
  4. package/package.json +1 -1
  5. package/skills/pikku-a11y/SKILL.md +22 -15
  6. package/skills/pikku-addon/SKILL.md +5 -5
  7. package/skills/pikku-addon/references/addon-package-manifest.md +7 -0
  8. package/skills/pikku-addon/references/openapi.md +11 -0
  9. package/skills/pikku-agent/SKILL.md +6 -6
  10. package/skills/pikku-agent/references/agents.md +8 -1
  11. package/skills/pikku-agent/references/runner-vercel.md +2 -2
  12. package/skills/pikku-agent/references/voice.md +7 -1
  13. package/skills/pikku-architect/SKILL.md +2 -2
  14. package/skills/pikku-architect/references/plan-defects.md +9 -7
  15. package/skills/pikku-auth/SKILL.md +15 -36
  16. package/skills/pikku-auth/references/better-auth.md +106 -133
  17. package/skills/pikku-auth/references/jose.md +6 -0
  18. package/skills/pikku-auth/references/machine-auth.md +6 -0
  19. package/skills/pikku-auth/references/sessions.md +6 -0
  20. package/skills/pikku-build/SKILL.md +37 -34
  21. package/skills/pikku-build/references/app.md +113 -99
  22. package/skills/pikku-build/references/design.md +43 -31
  23. package/skills/pikku-build/references/feature.md +17 -3
  24. package/skills/pikku-build/references/mocks.md +29 -0
  25. package/skills/pikku-build/references/multi-app.md +25 -18
  26. package/skills/pikku-build/references/native-app.md +9 -0
  27. package/skills/pikku-build/references/openapi.md +41 -34
  28. package/skills/pikku-build/references/platform.md +23 -14
  29. package/skills/pikku-build/references/post-clone.md +1 -1
  30. package/skills/pikku-build/references/quick.md +76 -39
  31. package/skills/pikku-build/references/scenarios.md +28 -16
  32. package/skills/pikku-build/references/ship.md +19 -16
  33. package/skills/pikku-build/references/theming.md +76 -127
  34. package/skills/pikku-changes/SKILL.md +7 -10
  35. package/skills/pikku-concepts/SKILL.md +34 -44
  36. package/skills/pikku-concepts/references/concept-mapping.md +18 -0
  37. package/skills/pikku-concepts/references/language.md +6 -6
  38. package/skills/pikku-convert-screen/SKILL.md +45 -0
  39. package/skills/pikku-deploy/references/cloudflare.md +8 -0
  40. package/skills/pikku-deploy/references/lambda.md +8 -0
  41. package/skills/pikku-deploy/references/nextjs.md +1 -1
  42. package/skills/pikku-deploy/references/uws.md +1 -1
  43. package/skills/pikku-deploy/references/ws.md +3 -3
  44. package/skills/pikku-emails/SKILL.md +3 -9
  45. package/skills/pikku-guide/SKILL.md +28 -27
  46. package/skills/pikku-i18n/SKILL.md +7 -7
  47. package/skills/pikku-i18n/references/enum-labels.md +9 -0
  48. package/skills/pikku-i18n/references/messages.md +21 -9
  49. package/skills/pikku-i18n/references/rtl.md +18 -38
  50. package/skills/pikku-knowledge/SKILL.md +12 -13
  51. package/skills/pikku-kysely/SKILL.md +3 -21
  52. package/skills/pikku-list-query/SKILL.md +2 -2
  53. package/skills/pikku-meta/references/audit.md +10 -1
  54. package/skills/pikku-meta/references/meta.md +6 -0
  55. package/skills/pikku-meta/references/versioning.md +10 -0
  56. package/skills/pikku-middleware/SKILL.md +7 -16
  57. package/skills/pikku-n8n-import/SKILL.md +9 -1
  58. package/skills/pikku-n8n-import/references/addon-mapping.md +6 -0
  59. package/skills/pikku-n8n-import/references/code-translation.md +7 -0
  60. package/skills/pikku-permissions/SKILL.md +41 -10
  61. package/skills/pikku-permissions/references/scopes.md +59 -0
  62. package/skills/pikku-react/SKILL.md +20 -22
  63. package/skills/pikku-react/references/client.md +2 -70
  64. package/skills/pikku-react/references/react-query.md +11 -0
  65. package/skills/pikku-react/references/workflows.md +11 -0
  66. package/skills/pikku-realtime/SKILL.md +9 -3
  67. package/skills/pikku-report/SKILL.md +17 -16
  68. package/skills/pikku-scenario/SKILL.md +72 -81
  69. package/skills/pikku-scenario/references/browser.md +5 -5
  70. package/skills/pikku-scenario/references/coverage.md +4 -4
  71. package/skills/pikku-scenario/references/steps.md +31 -30
  72. package/skills/pikku-scenario/references/{persona-run.md → virtual-user-run.md} +47 -42
  73. package/skills/pikku-scenario/references/virtual-users.md +114 -0
  74. package/skills/pikku-seo/SKILL.md +12 -16
  75. package/skills/pikku-service-backends/SKILL.md +0 -10
  76. package/skills/pikku-service-backends/references/aws.md +6 -0
  77. package/skills/pikku-service-backends/references/mongodb.md +7 -0
  78. package/skills/pikku-service-backends/references/redis.md +6 -0
  79. package/skills/pikku-services/references/audit-wire-service.md +2 -2
  80. package/skills/pikku-services/references/audit.md +10 -1
  81. package/skills/pikku-services/references/config.md +6 -0
  82. package/skills/pikku-services/references/services.md +9 -2
  83. package/skills/pikku-software-archaeology/SKILL.md +21 -27
  84. package/skills/pikku-software-archaeology/references/blueprint.schema.json +16 -16
  85. package/skills/pikku-software-archaeology/references/pikku-mapping.md +3 -3
  86. package/skills/pikku-software-archaeology/references/second-opinion.md +13 -1
  87. package/skills/pikku-tailwind/SKILL.md +111 -0
  88. package/skills/pikku-theme/SKILL.md +187 -0
  89. package/skills/pikku-theme/references/from-a-reference.md +44 -0
  90. package/skills/pikku-theme/references/presets.md +40 -0
  91. package/skills/pikku-ui/SKILL.md +41 -0
  92. package/skills/pikku-wiring/SKILL.md +13 -12
  93. package/skills/pikku-wiring/references/channel.md +7 -1
  94. package/skills/pikku-wiring/references/cli.md +7 -1
  95. package/skills/pikku-wiring/references/gateway-slack.md +6 -0
  96. package/skills/pikku-wiring/references/http.md +10 -3
  97. package/skills/pikku-wiring/references/mcp.md +8 -0
  98. package/skills/pikku-wiring/references/queue.md +6 -0
  99. package/skills/pikku-wiring/references/realtime.md +34 -4
  100. package/skills/pikku-wiring/references/rpc.md +6 -0
  101. package/skills/pikku-wiring/references/scheduler.md +6 -0
  102. package/skills/pikku-wiring/references/trigger.md +8 -0
  103. package/skills/pikku-workflow/SKILL.md +9 -7
  104. package/skills/pikku-admin-to-fabric/SKILL.md +0 -212
  105. package/skills/pikku-auth/references/permissions.md +0 -261
  106. package/skills/pikku-blueprint-to-fabric/SKILL.md +0 -377
  107. package/skills/pikku-blueprint-to-fabric/scripts/inventory.mjs +0 -367
  108. package/skills/pikku-fabric/SKILL.md +0 -619
  109. package/skills/pikku-fabric/references/debugging.md +0 -110
  110. package/skills/pikku-mantine/SKILL.md +0 -80
  111. package/skills/pikku-scenario/references/personas.md +0 -117
  112. package/skills/pikku-wiring/references/realtime-other-routes.md +0 -23
@@ -0,0 +1,44 @@
1
+ # Building from a reference
2
+
3
+ These apply only when the user names something that already exists: a live site, a W3C design
4
+ tokens file, a site to rebuild. With no reference, choose a preset from the domain instead. The CLI
5
+ has no extractor: you read the design off the source and pass it to `pikku ui theme apply`.
6
+
7
+ ## Match an existing design
8
+
9
+ 1. **Read the design off the source.** Open the site (or the tokens file) and note the primary,
10
+ secondary and accent colours, the page background and text colour, and the heading and body
11
+ fonts. Note the structure hints: radius, shadow strength, density, borders.
12
+
13
+ 2. **Pick the structure the hints describe.** Soft shadow and large radius: `aurora` or `breeze`.
14
+ Bold borders and hard shadows: `brutalist`. Compact density: `monopro`. Near-black background:
15
+ a dark-first preset.
16
+
17
+ 3. **Apply.** The page background maps to `--page` and the text to `--ink`:
18
+
19
+ ```bash
20
+ pikku ui theme apply --preset breeze --primary '#0B6E99' --font-heading 'Manrope' --font-body 'Manrope' --page '#F7F5F0' --ink '#1C2A33'
21
+ ```
22
+
23
+ You are the art director: what you read is signal, not a finished theme. Check page and ink
24
+ against each other and against the primary for 4.5:1 before applying.
25
+
26
+ 4. **Build the layout craft the reference shows.** Colours, fonts, radius and shadow travel through
27
+ the theme. What no token carries (an asymmetric grid, a bespoke type scale, a masked image edge,
28
+ a hover reveal) goes in utility classes on shadcn components (or a small CSS file for what utilities cannot express), with theme variables
29
+ for every colour.
30
+
31
+ ## Rebuild an existing site
32
+
33
+ When the user wants their site rebuilt or improved, not just matched:
34
+
35
+ 1. **Take the copy from the user.** Ask for the pages' text and images, or read the live pages
36
+ yourself. The CLI does not crawl or fetch stock photography; do not invent content or images.
37
+
38
+ 2. **Match the brand** with the recipe above.
39
+
40
+ 3. **Build the pages** from the shadcn components in `src/components/ui/`, filling them with the real
41
+ copy and the images the user supplied. Keep the meaning, discard the dated layout.
42
+
43
+ If there is no copy and no imagery to work from, say so and rebuild from the brief rather than
44
+ inventing content.
@@ -0,0 +1,40 @@
1
+ # Presets
2
+
3
+ Each preset pairs a brand and a structure that share its id. `pikku ui theme list` shows the
4
+ **listed** ones; **hidden** ones are left out of the list (they are niche or loud) but
5
+ `pikku ui theme apply --preset <id>` and `--structure <id>` still accept them. The scheme column is
6
+ the structure's `defaultColorScheme`; trust it over any "Dark." in a preset's description text.
7
+
8
+ | id | list | scheme | radius | heading / body | primary | suits |
9
+ | --- | --- | --- | --- | --- | --- | --- |
10
+ | `aurora` | listed | light | lg | Sora / Inter | `#6366f1` | saas, startup, dashboard, b2b, ai |
11
+ | `linear` | listed | light | sm | Inter | `#6366f1` | productivity, issues, dev-tools, internal tools |
12
+ | `glass` | listed | light | lg | Inter | `#38bdf8` | dashboard, analytics, fintech, premium |
13
+ | `breeze` | listed | light | xl | Nunito | `#14b8a6` | health, wellness, booking, clinic, fitness |
14
+ | `monopro` | listed | light | sm | Inter | `#3b82f6` | admin, console, internal tools, CRM, enterprise |
15
+ | `quorum` | listed | light | sm | Source Serif 4 / Public Sans | `#2E6F54` | finance, tax, legal, accounting, civic |
16
+ | `storybook` | listed | light | xl | Baloo 2 / Lora | `#6B4E8F` | kids, stories, bedtime, family (page `#FBF5EA`) |
17
+ | `stillness` | listed | light | lg | Spectral / Karla | `#5E7C74` | meditation, journal, sleep, habit (page `#F5F2EB`) |
18
+ | `terminal` | listed | dark | 0 | JetBrains Mono | `#22c55e` | dev-tools, CLI, logs, monitoring |
19
+ | `blueprint` | listed | dark | xs | Space Mono / Inter | `#38bdf8` | engineering, data, IoT, infrastructure |
20
+ | `brutalist` | hidden | light | 0 | Space Grotesk / Inter | `#f59e0b` | marketing, agency, portfolio, landing |
21
+ | `pop` | hidden | light | md | Poppins / Inter | `#ef4444` | campaign, sports, social, community |
22
+ | `editorial` | hidden | light | xs | Merriweather / Inter | `#b91c1c` | blog, news, magazine, docs |
23
+ | `neon` | hidden | dark | md | Sora / Inter | `#a855f7` | gaming, nightlife, music, events |
24
+ | `matrix` | hidden | dark | 0 | JetBrains Mono | `#22c55e` | dev-tools, security, monitoring |
25
+
26
+ ## What a structure carries
27
+
28
+ | Lever | Key | Effect |
29
+ | --- | --- | --- |
30
+ | Shadow scale | `shadows.xs`..`xl` | diffuse, hard-offset or glow; the biggest "bespoke" signal |
31
+ | Radius | `defaultRadius`, per-component `radius` | square (brutalist, terminal) to pill (breeze, storybook) |
32
+ | Borders | per-component `defaultProps.withBorder` / `styles.root` | hairline, thick, dashed, glow |
33
+ | Density | `spacing` | compact (monopro) to very wide (stillness) |
34
+ | Component defaults | `components.<Name>.defaultProps` | e.g. `Button` `variant: 'gradient'`, `Card` `shadow: 'md'` |
35
+ | Scheme | `defaultColorScheme` | light-first or dark-first boot |
36
+ | Dark ramp | `darkColors` | exact dark background (true black, deep navy, purple-black) |
37
+ | Page and ink | `white`, `black` | light-mode page material and text colour |
38
+ | Gradient | `defaultGradient` | on-brand `variant="gradient"`; derived from primary and secondary |
39
+
40
+ Fonts must be Google Fonts families; the theme package loads them through `googleFontsHref`.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: pikku-ui
3
+ description: >-
4
+ How a screen gets made: it is delegated to a subagent, which is handed the project's design rules and designs it with the impeccable skill.
5
+ TRIGGER when: the user asks for a screen, page, view, form, dashboard or empty/error state, or asks for an existing screen to be redone or restyled.
6
+ DO NOT TRIGGER when: the change is backend only, copy only (use pikku-i18n), or a one-line fix to a screen that already looks right.
7
+ installGroups: [client]
8
+ ---
9
+
10
+ # Screens go to a subagent
11
+
12
+ A screen the main thread draws by hand comes out generic and gets rejected. Every request for
13
+ a screen is handed to a subagent that is told the rules and designs with `impeccable`.
14
+
15
+ ## Steps
16
+
17
+ 1. Find the design rules for this project: `DESIGN.md` and the UI section of `AGENTS.md` at the
18
+ repo root, and the shared component package the screens are built from. If a project has
19
+ none, say so and stop. Do not invent a look.
20
+ 2. Start one subagent per screen. Its prompt must contain:
21
+ - the screen and its route or file, and the content it has to show or do;
22
+ - an instruction to read `DESIGN.md` in full and the UI section of `AGENTS.md` before drawing;
23
+ - an instruction to build only from the shared components, and to copy the closest existing screen;
24
+ - an instruction to invoke the `impeccable` skill and run its design workflow before writing code,
25
+ with the output landing in the existing theme tokens and variants, never new styles;
26
+ - who the audience is, and that jargon is a defect;
27
+ - the checks to run (typecheck), and how to commit (path-scoped, never sweep other work in).
28
+ 3. A redesign refines what is there. The subagent keeps the hero, imagery, illustrations, copy tone
29
+ and composition unless the user named one of them as the problem. Fewer controls and more feeling is
30
+ the direction; never trade a hero or images for forms, toggles and buttons. The prompt must list what
31
+ must not change and quote the user's actual complaint. A result with less visual character than the
32
+ original is a failure. If it is not clear what is wrong, ask the user before starting.
33
+ 4. Do not draw or restyle the screen in the main thread, even for a small screen.
34
+ 5. When the subagent reports, look at the screen before telling the user it is done (one render or DOM
35
+ check; `pikku ui pages list` names the route and `pikku ui pages screenshot --base-url <url>` photographs it). Check that it did what it was told. If it only loaded `impeccable`
36
+ and skipped its workflow, send it back. Tell the user what changed and what it decided.
37
+
38
+ ## What stays in the main thread
39
+
40
+ Wiring: routes, data hooks, state, redirects, and what a screen should contain. The subagent owns
41
+ how it looks.
@@ -3,14 +3,15 @@ name: pikku-wiring
3
3
  description: >-
4
4
  Use when exposing a Pikku function over a transport — HTTP routes and SSE, WebSocket channels,
5
5
  typed realtime pub/sub, internal and exposed RPC, queue workers, cron schedules, event triggers,
6
- MCP tools/resources/prompts, CLI commands, or a Slack gateway. Covers choosing the wiring, the
7
- model every wiring shares, and what differs: which function type each needs, where a session
8
- comes from, and which calls throw instead of returning. TRIGGER when: code uses wireHTTP,
9
- defineHTTPRoutes, wireChannel, wireQueueWorker, wireScheduler, wireTrigger, wireTriggerSource,
10
- wireCLI, wireMCPResource, wireMCPPrompt, `mcp: true`, `sse: true`, `expose: true`, rpc.invoke,
11
- SlackGatewayAdapter, or the user asks how to expose, route, schedule, queue, stream or publish a
12
- function. DO NOT TRIGGER when: writing the function body itself (use pikku-concepts), declaring
13
- authorization (use pikku-auth), or serving the app on a runtime (use pikku-deploy).
6
+ MCP tools/resources/prompts, CLI commands, or a Slack gateway. Covers choosing the wiring, what
7
+ every wiring shares, and what differs: function type, session source, and which calls throw
8
+ instead of returning. TRIGGER when: code uses wireHTTP, defineHTTPRoutes, wireChannel,
9
+ wireQueueWorker, wireScheduler, wireTrigger, wireTriggerSource, wireCLI, wireMCPResource,
10
+ wireMCPPrompt, `mcp: true`, `sse: true`, `expose: true`, rpc.invoke, SlackGatewayAdapter, or the
11
+ user asks how to expose, route, schedule, queue, stream or publish a function. DO NOT TRIGGER
12
+ when: writing the function body (use pikku-concepts), authorization (use pikku-permissions), serving on
13
+ a runtime (use pikku-deploy), building a live-updating view (use pikku-realtime), or sending
14
+ outgoing webhooks (use pikku-webhook).
14
15
  installGroups: [core]
15
16
  ---
16
17
 
@@ -53,7 +54,7 @@ Three consequences that hold for every wiring below:
53
54
  are merged into the function's `data` argument.
54
55
  - **Permissions are never declared on the wiring.** Wire-level permissions were
55
56
  removed in #972 — declare them on the function (`pikkuFunc({ permissions })`,
56
- see `pikku-auth`) or app-wide via `addGlobalPermission`. Tags and
57
+ see `pikku-permissions`) or app-wide via `addGlobalPermission`. Tags and
57
58
  patterns now target *middleware* only.
58
59
  - **The wire is the third argument**, not a service. `channel`, `rpc`, `session`,
59
60
  `setSession`, `mcp`, `queue`, `scheduledTask` and `cli` all live there.
@@ -83,15 +84,15 @@ subpath it exempts — the service implementations bootstrap picks.
83
84
 
84
85
  | Reach for | When | Reference |
85
86
  | --- | --- | --- |
86
- | **HTTP** | REST endpoints, web APIs, and SSE streams (`sse: true`, `get` only) | `references/http.md` |
87
+ | **HTTP** | REST endpoints, web APIs, and SSE streams (`sse: true`, `get` only) | `references/http.md`; every field in `references/http-options.md` |
87
88
  | **Channel** | A hand-designed WebSocket protocol with your own action routing | `references/channel.md` |
88
- | **Realtime** | Typed pub/sub push — the scaffolded `/events` channel and SSE topics | `references/realtime.md` |
89
+ | **Realtime** | Typed pub/sub push — the scaffolded `/events` channel and SSE topics, plus subscribing to any other `sse: true` route or channel from the client | `references/realtime.md` |
89
90
  | **RPC** | One function calling another, or dispatching a name from outside | `references/rpc.md` |
90
91
  | **Queue** | Reliable background work that must survive a crash and retry | `references/queue.md` |
91
92
  | **Scheduler** | Recurring work on a cron expression | `references/scheduler.md` |
92
93
  | **Trigger** | Reacting in-process to an external event source (Redis pub/sub, PG LISTEN) | `references/trigger.md` |
93
94
  | **MCP** | Exposing functions to an AI assistant as tools, resources or prompts | `references/mcp.md` |
94
- | **CLI** | A terminal program with commands, subcommands and options | `references/cli.md` |
95
+ | **CLI** | A terminal program with commands, subcommands and options | `references/cli.md`; end-to-end walkthrough in `references/cli-complete-example.md` |
95
96
  | **Gateway** | An inbound integration from a third-party product — Slack is the shipped adapter | `references/gateway-slack.md` |
96
97
 
97
98
  Realtime and Channel are the pair most often confused. If the shape is "server
@@ -1,5 +1,11 @@
1
1
  # Pikku WebSocket Wiring
2
2
 
3
+ ## Contents
4
+
5
+ - API Reference
6
+ - Usage Patterns
7
+ - Complete Example
8
+
3
9
  ## API Reference
4
10
 
5
11
  ### `wireChannel(config)`
@@ -33,7 +39,7 @@ wireChannel({
33
39
 
34
40
  Note there is **no `permissions` key on a message wiring** — wire-level
35
41
  permissions were removed in #972. Authorization lives on the function's own
36
- `permissions` field (see `pikku-auth`).
42
+ `permissions` field (see `pikku-permissions`).
37
43
 
38
44
  ### `pikkuChannelMiddleware(fn)`
39
45
 
@@ -1,5 +1,11 @@
1
1
  # Pikku CLI Wiring
2
2
 
3
+ ## Contents
4
+
5
+ - API Reference
6
+ - Usage Patterns
7
+ - Complete Example
8
+
3
9
  ## API Reference
4
10
 
5
11
  ### `wireCLI(config)`
@@ -212,4 +218,4 @@ session for local runs. Don't hand-write or edit the generated channel file.
212
218
 
213
219
  ## Complete Example
214
220
 
215
- For a full functions + renderers + nested-subcommand wiring walkthrough, see `cli-complete-example.md`.
221
+ For a full functions + renderers + nested-subcommand wiring walkthrough, see the CLI complete example listed in `SKILL.md`.
@@ -1,5 +1,11 @@
1
1
  # Pikku Gateway Slack
2
2
 
3
+ ## Contents
4
+
5
+ - Installation
6
+ - API Reference
7
+ - Usage Patterns
8
+
3
9
  ## Installation
4
10
 
5
11
  ```bash
@@ -1,5 +1,12 @@
1
1
  # Pikku HTTP Wiring
2
2
 
3
+ ## Contents
4
+
5
+ - API Reference
6
+ - Data Flow
7
+ - Usage Patterns
8
+ - Complete Example
9
+
3
10
  ## API Reference
4
11
 
5
12
  All three come from `#pikku/http` (the generated `.pikku/http/index.ts`), which
@@ -14,7 +21,7 @@ Function input/output types come from the function's own `input:`/`output:` zod
14
21
 
15
22
  Config cascading across groups: `basePath` concatenates down the chain, `tags` merge (union), `auth` child overrides parent.
16
23
 
17
- For the full option tables (every `wireHTTP` field, the `defineHTTPRoutes`/`wireHTTPRoutes` config shape), read `http-options.md`.
24
+ For the full option tables (every `wireHTTP` field, the `defineHTTPRoutes`/`wireHTTPRoutes` config shape), read the HTTP options reference listed in `SKILL.md`.
18
25
 
19
26
  ### `addHTTPMiddleware(pattern, middlewares)`
20
27
 
@@ -23,7 +30,7 @@ addHTTPMiddleware('*', [authBearer()]) // All routes
23
30
  addHTTPMiddleware('/api/*', [rateLimit()]) // Pattern match
24
31
  ```
25
32
 
26
- > HTTP-route-level permissions (`addHTTPPermission`, a `permissions` field on the wiring) were removed in #972. Declare authorization on the function definition (`pikkuFunc({ permissions })`, see `pikku-auth`), or app-wide via `addGlobalPermission`. Tags/patterns are for _middleware_ only now.
33
+ > HTTP-route-level permissions (`addHTTPPermission`, a `permissions` field on the wiring) were removed in #972. Declare authorization on the function definition (`pikkuFunc({ permissions })`, see `pikku-permissions`), or app-wide via `addGlobalPermission`. Tags/patterns are for _middleware_ only now.
27
34
 
28
35
  ## Data Flow
29
36
 
@@ -86,7 +93,7 @@ wireHTTP({ method: 'get', route: '/books', func: listBooks, auth: false })
86
93
  wireHTTP({ method: 'delete', route: '/books/:bookId', func: deleteBook })
87
94
  ```
88
95
 
89
- Authorization is not a wiring concern — declare it on the function via `permissions` (see `pikku-auth`), or app-wide via `addGlobalPermission`.
96
+ Authorization is not a wiring concern — declare it on the function via `permissions` (see `pikku-permissions`), or app-wide via `addGlobalPermission`.
90
97
 
91
98
  ### Middleware
92
99
 
@@ -1,5 +1,13 @@
1
1
  # Pikku MCP Wiring
2
2
 
3
+ ## Contents
4
+
5
+ - The shape of MCP in Pikku
6
+ - API Reference
7
+ - Reaching the server
8
+ - Authentication
9
+ - Red flags
10
+
3
11
  ## The shape of MCP in Pikku
4
12
 
5
13
  MCP has three surfaces, and Pikku wires them differently:
@@ -1,5 +1,11 @@
1
1
  # Pikku Queue Wiring
2
2
 
3
+ ## Contents
4
+
5
+ - API Reference
6
+ - Usage Patterns
7
+ - Complete Example
8
+
3
9
  ## API Reference
4
10
 
5
11
  ### `wireQueueWorker(config)`
@@ -1,5 +1,17 @@
1
1
  # Pikku Realtime
2
2
 
3
+ ## Contents
4
+
5
+ - 1. Declare your topics
6
+ - 2. Enable the server side
7
+ - 3. Generate the typed client
8
+ - 4. Publish events from a function
9
+ - 5. Wire it up — share fetch with PikkuRPC
10
+ - 6. Subscribe from React
11
+ - Other SSE / WebSocket routes
12
+ - When to pick which transport
13
+ - What NOT to do
14
+
3
15
  ## 1. Declare your topics
4
16
 
5
17
  In your project's types file (e.g. `types/eventhub-topics.d.ts`):
@@ -95,7 +107,7 @@ export class PikkuRealtime {
95
107
  handler: (data: EventHubTopics[K]) => void
96
108
  ): { close: () => void }
97
109
 
98
- // generic escape hatches — see realtime-other-routes.md
110
+ // generic escape hatches — see "Other SSE / WebSocket routes" below
99
111
  subscribeToSSE<T>(
100
112
  path: string,
101
113
  handler: (data: T) => void
@@ -236,9 +248,27 @@ function TodoList() {
236
248
 
237
249
  ## Other SSE / WebSocket routes
238
250
 
239
- The same client also subscribes to generic `sse: true` routes and raw `wireChannel`
240
- sockets (`subscribeToSSE`, `connectToChannel`). See
241
- [realtime-other-routes.md](realtime-other-routes.md).
251
+ The same client also handles generic SSE + channel routes (not just
252
+ `/events` topics). Use the path; the base URL is inherited from `PikkuFetch`.
253
+
254
+ ```ts
255
+ // Any `sse: true` HTTP route
256
+ const sub = realtime.subscribeToSSE<{ progress: number }>(
257
+ `/workflow-run/${runId}/stream`,
258
+ (event) => setProgress(event.progress)
259
+ )
260
+ // later: sub.close()
261
+
262
+ // Any wireChannel — open a raw socket, wrap in PikkuWebSocket for typed I/O
263
+ const ws = realtime.connectToChannel('/ws/kanban')
264
+ const typed = new PikkuWebSocket<'kanban-live'>(ws)
265
+ typed.getRoute('command').subscribe('message', (data) => {
266
+ /* ... */
267
+ })
268
+ ```
269
+
270
+ Discover what's available with `pikku meta clients --json` — `channels` and any HTTP
271
+ `sse: true` routes are listed there.
242
272
 
243
273
  ## When to pick which transport
244
274
 
@@ -1,5 +1,11 @@
1
1
  # Pikku RPC Wiring
2
2
 
3
+ ## Contents
4
+
5
+ - API Reference
6
+ - Usage Patterns
7
+ - Complete Example
8
+
3
9
  ## API Reference
4
10
 
5
11
  ### RPC Methods (on `wire.rpc`)
@@ -1,5 +1,11 @@
1
1
  # Pikku Scheduled Tasks
2
2
 
3
+ ## Contents
4
+
5
+ - API Reference
6
+ - Usage Patterns
7
+ - Complete Example
8
+
3
9
  ## API Reference
4
10
 
5
11
  ### `wireScheduler(config)`
@@ -1,5 +1,13 @@
1
1
  # Pikku Trigger Wiring
2
2
 
3
+ ## Contents
4
+
5
+ - API Reference
6
+ - Starting triggers
7
+ - Webhook sources
8
+ - Usage Patterns
9
+ - Complete Example
10
+
3
11
  ## API Reference
4
12
 
5
13
  All three come from `#pikku`. A trigger is deliberately split in two: the
@@ -1,12 +1,14 @@
1
1
  ---
2
2
  name: pikku-workflow
3
3
  description: >-
4
- Use when building multi-step workflows, state machines, or orchestration pipelines with Pikku.
5
- Covers pikkuWorkflowFunc, workflow steps (do, sleep, suspend), graph workflows, and HTTP wiring.
6
- TRIGGER when: code uses pikkuWorkflowFunc/pikkuWorkflowGraph, user asks about workflows,
7
- multi-step processes, durable execution, suspend/resume, or DAG orchestration. DO NOT TRIGGER
8
- when: user asks about simple background jobs (use pikku-wiring) or scheduled tasks (use
9
- pikku-wiring).
4
+ Use when building multi-step, durable workflows with Pikku — pikkuWorkflowFunc,
5
+ pikkuWorkflowGraph, workflow.do / sleep / suspend / approval, retries, compensate, sub-workflows,
6
+ and starting or resuming runs. Includes deciding whether something should be a workflow at all.
7
+ TRIGGER when: code uses pikkuWorkflowFunc or pikkuWorkflowGraph, or the user asks about
8
+ workflows, multi-step processes, durable execution, suspend/resume, approval gates, sagas or DAG
9
+ orchestration. DO NOT TRIGGER when: the user wants a single background job (use the queue
10
+ reference in pikku-wiring) or a cron task (use the scheduler reference in pikku-wiring), or is
11
+ converting an n8n export (use pikku-n8n-import).
10
12
  installGroups: [core]
11
13
  ---
12
14
 
@@ -282,7 +284,7 @@ compensated. The error arrives as `wire.graph.recoveringFrom`
282
284
  object (`{ success: false, reason }`) instead.
283
285
 
284
286
  Full step options: `description`, `retries`, `retryDelay`, `compensate: false`
285
- (plus `actor`, which is scenario-only — see `pikku-scenario`).
287
+ (plus `virtualUser`, which is scenario-only — see `pikku-scenario`).
286
288
 
287
289
  ### Parallel fan-out
288
290
 
@@ -1,212 +0,0 @@
1
- ---
2
- name: pikku-admin-to-fabric
3
- description: 'Port a legacy back-office admin (ActiveAdmin, Django admin, Rails Admin, Laravel Nova, Filament) to Fabric admin screens, driven by a `.knowledge/` Product Blueprint. Covers the admin-DSL→Fabric mapping (resources→screens, index/column→tables, filter→query params, scope→query variants, member_action/collection_action→pikkuFuncs, permit_params→input schemas), the "the admin is half your app" audit, and admin-specific permissions. TRIGGER when: porting/rebuilding a legacy app that has a generated/DSL-driven admin, or the user says "port the admin screens" / "implement the admin". DO NOT TRIGGER when: no legacy admin exists (use pikku-fabric to build screens fresh), or the app is being extended rather than ported (use pikku-build).'
4
- installGroups: [fabric]
5
- argument-hint: '<path to .knowledge/> [resource to port next]'
6
- ---
7
-
8
- # Legacy admin → Fabric admin screens
9
-
10
- ## Agent Operating Procedure
11
-
12
- 1. **Count first.** How many commands cite the admin? That number decides whether this is a chore or a third of the project.
13
- 2. **The blueprint already has the commands.** Do not re-derive them from the DSL. Map to them.
14
- 3. **Port the actions before the screens.** A screen with no action behind it is a table; the actions are the product.
15
- 4. **One resource per slice**, same as `pikku-blueprint-to-fabric`. Verify green before the next.
16
- 5. **An admin permission is not a checkbox.** Legacy admins routinely authenticate and do not authorize. Do not port that.
17
- 6. **Record what you did NOT port**, per resource, in the parity report.
18
-
19
- ## The mistake this skill exists to prevent
20
-
21
- > "It's just the admin — CRUD screens over the same tables. We'll scaffold it at the end."
22
-
23
- This is wrong in a specific, measurable way, and you can check it in one command
24
- before you believe anything else in this file:
25
-
26
- ```bash
27
- node -e "
28
- const c = require('./.knowledge/commands.json').commands
29
- const admin = c.filter(x => (x.evidence||[]).some(e => (e.file||'').match(/admin/)))
30
- console.log(admin.length + ' of ' + c.length + ' commands live in the admin')
31
- "
32
- ```
33
-
34
- On a real Rails app (Applause, 39 ActiveAdmin resources, 5,545 lines of DSL) the
35
- answer was **82 of 187 — 44%**, plus 71 of 223 API surfaces. The admin was not a
36
- side panel over the customer-facing app. It was nearly **half the application's
37
- write surface**, and a large share of those commands existed *nowhere else*:
38
- issue a refund, retrigger a payment, queue a sync, impersonate a user, mark a
39
- blade returned, reassign a company. There is no customer screen for any of them.
40
-
41
- So: the admin is not the last 10% of the port. Budget it as what the count says.
42
-
43
- **Corollary — the admin is where the unguarded capabilities live.** A
44
- `member_action :impersonate` or `:create_stripe_refund` is a command that moves
45
- money or identity, defended in legacy by nothing more than "you reached an
46
- `/admin` URL". Every one of these needs a real `pikkuPermission` in the rebuild,
47
- and writing them is the point of the port, not overhead on top of it.
48
-
49
- ## Stage 0 — Preflight
50
-
51
- - The `.knowledge/` blueprint must exist and validate (`0 error(s)`). If not, run
52
- **pikku-software-archaeology** first. This skill maps to the blueprint; it does
53
- not parse Ruby.
54
- - Read `parity-*.md` for the domains you are about to touch. Renames decided in an
55
- earlier slice (a `tenant` that became a `Market`, a `membership_level` that
56
- became a `certification_level`) are binding here. An admin screen that reintroduces
57
- the old word undoes the decision.
58
- - Run the count above and say the number out loud in your plan.
59
-
60
- ## Stage 1 — Inventory the DSL
61
-
62
- Every generated admin is the same six ideas under different syntax. Inventory
63
- them, do not read them line by line:
64
-
65
- ```bash
66
- # ActiveAdmin
67
- grep -rhoE "^\s{0,4}(index|show|form|filter|scope|action_item|member_action|collection_action|batch_action|permit_params|csv|sidebar|panel|actions)\b" app/admin/*.rb | sort | uniq -c | sort -rn
68
- grep -rhoE "(member_action|collection_action) :[a-z_]+" app/admin/*.rb | sort -u
69
- ```
70
-
71
- | Legacy | Also called | Becomes in Fabric |
72
- |---|---|---|
73
- | `ActiveAdmin.register X` / `class XAdmin` | resource, ModelAdmin, Nova Resource | one TanStack route + one screen |
74
- | `index do … column :x` | `list_display`, `columns()` | a Mantine `Table`/`DataTable`, columns from the query's return type |
75
- | `filter :x` | `list_filter`, `searchable` | typed input fields on the list query |
76
- | `scope :active` | `get_queryset` variants, `Nova::Filters` | a named variant of the list query — NOT a new function per scope |
77
- | `form do f.input …` | `fields()`, `fieldsets` | a Mantine form; inputs from the command's zod input schema |
78
- | `permit_params` | `fields`, `$fillable` | you already have this: it is the command's input schema. Cross-check, don't re-derive. |
79
- | `member_action :foo` | custom action, `Nova::Actions` | **a `pikkuFunc`** — almost always already in `commands.json` |
80
- | `collection_action :foo` | bulk action | a `pikkuFunc` taking a set |
81
- | `batch_action` | admin action | a `pikkuFunc` taking ids[] |
82
- | `csv do … end` | export | a readonly func returning rows; render client-side |
83
- | `panel`/`sidebar` | inlines, `relations` | a section on the show screen, fed by a related query |
84
- | `action_item` | — | a button. It is not a capability; find the action it calls. |
85
-
86
- **`action_item` vs `member_action` is the distinction that matters.** An
87
- `action_item` is a *button*; a `member_action` is a *capability*. Legacy files
88
- pair them, and a fast reader counts the buttons. Count the capabilities.
89
-
90
- ## Stage 2 — Map actions to blueprint commands (do this before any UI)
91
-
92
- For each `member_action`/`collection_action`, find its command in
93
- `commands.json`. Three outcomes, and the third is the valuable one:
94
-
95
- 1. **Found** — the archaeology already lifted it (`ArchiveProduct`,
96
- `CancelInvoice`). Wire the screen to it. Nothing to build.
97
- 2. **Found under a different name** — the blueprint names concepts in domain
98
- language, the DSL names them after routes. `member_action :rerun` may be
99
- `RetryWebhookDelivery`. Match on behaviour, not spelling. **Use the blueprint's
100
- name.**
101
- 3. **Not found** — stop. Either the archaeology missed a command (fix
102
- `.knowledge/`, do not paper over it here) or the action is dead code. Both are
103
- findings. Do not quietly invent a command to fill the gap: a command with no
104
- blueprint entry has no evidence, no policy and no actor, and you will not
105
- notice which.
106
-
107
- Two legacy shapes to expect and *not* reproduce:
108
-
109
- - **`*_form` + `*` action pairs** (`create_stripe_refund_form` +
110
- `create_stripe_refund`, `issue_payment_form` + `issue_payment`). The `_form` half
111
- is a GET that renders a modal — it is a *screen*, not a capability. It collapses
112
- into the screen; only the second half is a `pikkuFunc`. Porting both doubles your
113
- command count with phantoms.
114
- - **A `member_action` that only redirects** to another action. That is routing.
115
- - **An action disabled in the production environment is not a live capability.**
116
- Grep the environment guards before porting:
117
- ```bash
118
- grep -rn "env.production?\|env\.development?\|ENV\[" app/admin/*.rb
119
- ```
120
- On Applause, both halves of `create_stripe_refund` open with
121
- `return redirect_to … if Rails.env.production?` — the admin refund screen has
122
- never run in production, and refunds are actually issued in the Stripe dashboard.
123
- Porting it faithfully would ship a prominent button for a capability the business
124
- does not use through this app, and quietly move refunds into a surface nobody has
125
- ever tested. Whether it should now exist is a **product decision**, not a port.
126
- Check the guard is on the *mutating* half too: if the form is blocked and the POST
127
- is not, you have found a hole rather than a dead feature.
128
-
129
- ## Stage 3 — Permissions (the part legacy skipped)
130
-
131
- Generated admins authenticate and then trust. The whole admin sits behind one
132
- "is an admin" check, and every action inside it is equally reachable — refunds,
133
- impersonation and editing an FAQ all guarded identically.
134
-
135
- - Read `policies.json` for the real rule per command. If the blueprint says the
136
- policy is `enforcedBy: nothing`, that is a **gap you are now closing**, not a
137
- behaviour to port.
138
- - With Better Auth's `admin()` plugin, `user.role` is the platform role and
139
- `session.impersonated_by` is set during impersonation. Both are yours already.
140
- - **Money and identity actions deserve their own permission**, not the blanket one.
141
- If the blueprint offers no rule, that is a `decisionsNeeded` entry — ask, do not
142
- invent.
143
- - **Impersonation:** Better Auth's `impersonateUser`/`stopImpersonating` replace the
144
- hand-rolled version. If the legacy audit table recorded only the *start* of an
145
- impersonation (no `ended_at`, no session id), do not port it — the Fabric audit
146
- table already answers "what did they do while impersonating", which was the whole
147
- question it failed to answer.
148
-
149
- ## Stage 4 — Screens
150
-
151
- - The list query is `pikkuSessionlessFunc` + `readonly: true`; filters and scopes
152
- are **input fields on one function**, not one function per scope. Legacy needs a
153
- method per scope because the DSL has no parameters. You do not.
154
- - Columns come from the query's return type. If a column exists in the DSL but not
155
- in the type, the DSL was computing it in Ruby per row — that is an N+1 wearing a
156
- column, and it belongs in the query.
157
- - Reuse the app's Mantine theme. An admin styled differently from the product is
158
- how design systems fork.
159
- - **Server-computed charts** (chartkick/groupdate and friends) do not port. The
160
- aggregation becomes a real query; the plot becomes a chart component. This is the
161
- one genuinely expensive screen in most admins — cost it separately.
162
- - **Drag-and-drop reordering** (`acts_as_list`, sortable tables) is custom logic,
163
- not a table. Port the position semantics deliberately.
164
-
165
- ## Stage 5 — Verify and report
166
-
167
- ```bash
168
- pikku all && pikku fabric validate --json
169
- ```
170
-
171
- Per resource, the parity report records:
172
-
173
- - **Ported** — screens + which blueprint commands back them.
174
- - **Deliberately not ported** — with the reason. Expect: `*_form` halves, dead
175
- actions, single-member enums, screens over dropped tables.
176
- - **Now authorized** — every action that was guarded by "reached an /admin URL"
177
- and now has a real permission. This is the port's dividend; name it.
178
- - **Still open** — actions whose rule the blueprint could not settle.
179
-
180
- ## Red Flags
181
-
182
- | Thought | Reality |
183
- |---|---|
184
- | "The admin is just CRUD, scaffold it last" | Run the count. It was 44% of commands on a real app, and those commands exist nowhere else. |
185
- | "I'll read the DSL and write the commands" | The blueprint already has them, with evidence, actors and policies. Map; don't re-derive. |
186
- | "One function per scope" | A scope is a filter argument. The DSL needed a method because it has no parameters. |
187
- | "`action_item` count = capability count" | Buttons aren't capabilities. Count `member_action`/`collection_action`. |
188
- | "Port `create_stripe_refund_form` too" | It is a GET that renders a modal. It is a screen. Only the non-`_form` half is a command. |
189
- | "Admins are admins; one permission is fine" | That is the legacy bug. Refunds and FAQ edits are not the same risk. |
190
- | "The admin action isn't in commands.json, I'll add it" | Stop. Either the archaeology missed it (fix the blueprint) or it is dead. Both are findings. |
191
- | "I'll restyle the admin, it's internal" | An admin off the product's theme is how a design system forks. |
192
-
193
- ## Quick Reference
194
-
195
- ```bash
196
- # 1. how much of the app is actually the admin?
197
- node -e "const c=require('./.knowledge/commands.json').commands;console.log(c.filter(x=>(x.evidence||[]).some(e=>(e.file||'').match(/admin/))).length+'/'+c.length)"
198
-
199
- # 2. inventory the capabilities (not the buttons)
200
- grep -rhoE "(member_action|collection_action) :[a-z_]+" app/admin/*.rb | sort -u
201
-
202
- # 3. per resource: map actions -> commands.json, then build the screen
203
- # 4. verify
204
- pikku all && pikku fabric validate --json
205
- ```
206
-
207
- ## Related skills
208
-
209
- - **pikku-software-archaeology** — produces the `.knowledge/` blueprint this needs.
210
- - **pikku-blueprint-to-fabric** — the parent port; run this per-domain alongside it.
211
- - **pikku-auth** — roles, ban and impersonation, and the scopes that gate them.
212
- - **pikku-fabric** — screens, theme, Mantine conventions.