@pikku/skills 0.12.52 → 0.12.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/skills.gen.js +2 -2
- package/dist/snippets.js +1 -1
- package/package.json +1 -1
- package/skills/pikku-a11y/SKILL.md +22 -15
- package/skills/pikku-addon/SKILL.md +5 -5
- package/skills/pikku-addon/references/addon-package-manifest.md +7 -0
- package/skills/pikku-addon/references/openapi.md +11 -0
- package/skills/pikku-agent/SKILL.md +6 -6
- package/skills/pikku-agent/references/agents.md +8 -1
- package/skills/pikku-agent/references/runner-vercel.md +2 -2
- package/skills/pikku-agent/references/voice.md +7 -1
- package/skills/pikku-architect/SKILL.md +2 -2
- package/skills/pikku-architect/references/plan-defects.md +9 -7
- package/skills/pikku-auth/SKILL.md +15 -36
- package/skills/pikku-auth/references/better-auth.md +106 -133
- package/skills/pikku-auth/references/jose.md +6 -0
- package/skills/pikku-auth/references/machine-auth.md +6 -0
- package/skills/pikku-auth/references/sessions.md +6 -0
- package/skills/pikku-build/SKILL.md +37 -34
- package/skills/pikku-build/references/app.md +113 -99
- package/skills/pikku-build/references/design.md +43 -31
- package/skills/pikku-build/references/feature.md +17 -3
- package/skills/pikku-build/references/mocks.md +29 -0
- package/skills/pikku-build/references/multi-app.md +25 -18
- package/skills/pikku-build/references/native-app.md +9 -0
- package/skills/pikku-build/references/openapi.md +41 -34
- package/skills/pikku-build/references/platform.md +23 -14
- package/skills/pikku-build/references/post-clone.md +1 -1
- package/skills/pikku-build/references/quick.md +76 -39
- package/skills/pikku-build/references/scenarios.md +28 -16
- package/skills/pikku-build/references/ship.md +19 -16
- package/skills/pikku-build/references/theming.md +76 -127
- package/skills/pikku-changes/SKILL.md +7 -10
- package/skills/pikku-concepts/SKILL.md +34 -44
- package/skills/pikku-concepts/references/concept-mapping.md +18 -0
- package/skills/pikku-concepts/references/language.md +6 -6
- package/skills/pikku-convert-screen/SKILL.md +45 -0
- package/skills/pikku-deploy/references/cloudflare.md +8 -0
- package/skills/pikku-deploy/references/lambda.md +8 -0
- package/skills/pikku-deploy/references/nextjs.md +1 -1
- package/skills/pikku-deploy/references/uws.md +1 -1
- package/skills/pikku-deploy/references/ws.md +3 -3
- package/skills/pikku-emails/SKILL.md +3 -9
- package/skills/pikku-guide/SKILL.md +28 -27
- package/skills/pikku-i18n/SKILL.md +7 -7
- package/skills/pikku-i18n/references/enum-labels.md +9 -0
- package/skills/pikku-i18n/references/messages.md +21 -9
- package/skills/pikku-i18n/references/rtl.md +18 -38
- package/skills/pikku-knowledge/SKILL.md +12 -13
- package/skills/pikku-kysely/SKILL.md +3 -21
- package/skills/pikku-list-query/SKILL.md +2 -2
- package/skills/pikku-meta/references/audit.md +10 -1
- package/skills/pikku-meta/references/meta.md +6 -0
- package/skills/pikku-meta/references/versioning.md +10 -0
- package/skills/pikku-middleware/SKILL.md +7 -16
- package/skills/pikku-n8n-import/SKILL.md +9 -1
- package/skills/pikku-n8n-import/references/addon-mapping.md +6 -0
- package/skills/pikku-n8n-import/references/code-translation.md +7 -0
- package/skills/pikku-permissions/SKILL.md +41 -10
- package/skills/pikku-permissions/references/scopes.md +59 -0
- package/skills/pikku-react/SKILL.md +20 -22
- package/skills/pikku-react/references/client.md +2 -70
- package/skills/pikku-react/references/react-query.md +11 -0
- package/skills/pikku-react/references/workflows.md +11 -0
- package/skills/pikku-realtime/SKILL.md +9 -3
- package/skills/pikku-report/SKILL.md +17 -16
- package/skills/pikku-scenario/SKILL.md +72 -81
- package/skills/pikku-scenario/references/browser.md +5 -5
- package/skills/pikku-scenario/references/coverage.md +4 -4
- package/skills/pikku-scenario/references/steps.md +31 -30
- package/skills/pikku-scenario/references/{persona-run.md → virtual-user-run.md} +47 -42
- package/skills/pikku-scenario/references/virtual-users.md +114 -0
- package/skills/pikku-seo/SKILL.md +12 -16
- package/skills/pikku-service-backends/SKILL.md +0 -10
- package/skills/pikku-service-backends/references/aws.md +6 -0
- package/skills/pikku-service-backends/references/mongodb.md +7 -0
- package/skills/pikku-service-backends/references/redis.md +6 -0
- package/skills/pikku-services/references/audit-wire-service.md +2 -2
- package/skills/pikku-services/references/audit.md +10 -1
- package/skills/pikku-services/references/config.md +6 -0
- package/skills/pikku-services/references/services.md +9 -2
- package/skills/pikku-software-archaeology/SKILL.md +21 -27
- package/skills/pikku-software-archaeology/references/blueprint.schema.json +16 -16
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +3 -3
- package/skills/pikku-software-archaeology/references/second-opinion.md +13 -1
- package/skills/pikku-tailwind/SKILL.md +111 -0
- package/skills/pikku-theme/SKILL.md +187 -0
- package/skills/pikku-theme/references/from-a-reference.md +44 -0
- package/skills/pikku-theme/references/presets.md +40 -0
- package/skills/pikku-ui/SKILL.md +41 -0
- package/skills/pikku-wiring/SKILL.md +13 -12
- package/skills/pikku-wiring/references/channel.md +7 -1
- package/skills/pikku-wiring/references/cli.md +7 -1
- package/skills/pikku-wiring/references/gateway-slack.md +6 -0
- package/skills/pikku-wiring/references/http.md +10 -3
- package/skills/pikku-wiring/references/mcp.md +8 -0
- package/skills/pikku-wiring/references/queue.md +6 -0
- package/skills/pikku-wiring/references/realtime.md +34 -4
- package/skills/pikku-wiring/references/rpc.md +6 -0
- package/skills/pikku-wiring/references/scheduler.md +6 -0
- package/skills/pikku-wiring/references/trigger.md +8 -0
- package/skills/pikku-workflow/SKILL.md +9 -7
- package/skills/pikku-admin-to-fabric/SKILL.md +0 -212
- package/skills/pikku-auth/references/permissions.md +0 -261
- package/skills/pikku-blueprint-to-fabric/SKILL.md +0 -377
- package/skills/pikku-blueprint-to-fabric/scripts/inventory.mjs +0 -367
- package/skills/pikku-fabric/SKILL.md +0 -619
- package/skills/pikku-fabric/references/debugging.md +0 -110
- package/skills/pikku-mantine/SKILL.md +0 -80
- package/skills/pikku-scenario/references/personas.md +0 -117
- package/skills/pikku-wiring/references/realtime-other-routes.md +0 -23
|
@@ -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,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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-
|
|
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-
|
|
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
|
|
221
|
+
For a full functions + renderers + nested-subcommand wiring walkthrough, see the CLI complete example listed in `SKILL.md`.
|
|
@@ -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 `
|
|
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-
|
|
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-
|
|
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,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
|
|
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
|
|
240
|
-
|
|
241
|
-
|
|
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,12 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-workflow
|
|
3
3
|
description: >-
|
|
4
|
-
Use when building multi-step
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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 `
|
|
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.
|