@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
@@ -1,110 +0,0 @@
1
- # Debugging a deployed Fabric stage
2
-
3
- ## Agent Operating Procedure
4
-
5
- Use this skill as an execution checklist, not reference material.
6
-
7
- 1. Reproduce locally first. If it fails locally too, debug it there — the
8
- deployed stage adds cost and latency to every iteration.
9
- 2. Start from `errors`, not `logs`. Errors are already filtered and carry the
10
- traceId that unlocks the rest.
11
- 3. Follow one trace end-to-end before forming a theory. A single failing request
12
- tells you more than a hundred unrelated log lines.
13
- 4. Fix the source cause and redeploy. Never leave the diagnosis at "it is flaky".
14
- 5. Confirm the fix against the same stage — recheck `errors` for the function.
15
-
16
- Every command below requires a logged-in CLI and a linked project. Both fail
17
- with the exact remediation if not:
18
-
19
- ```
20
- Not logged in. Run `pikku fabric login` first.
21
- No fabric project linked. Run `pikku fabric link` first.
22
- ```
23
-
24
- ## The loop
25
-
26
- **1 — What is broken?**
27
-
28
- ```bash
29
- pikku fabric errors -b main # branch defaults to main
30
- pikku fabric errors -b main --function createOrder
31
- ```
32
-
33
- Prints a `WHEN | FUNCTION | TRACE | MESSAGE` table. The message is **truncated
34
- to 100 characters** — treat it as a label, not the full error. The TRACE column
35
- is the input to the next step.
36
-
37
- **2 — What happened in that one request?**
38
-
39
- ```bash
40
- pikku fabric trace <traceId> -b main
41
- pikku fabric trace <traceId> -b main --json
42
- ```
43
-
44
- `--branch` is **required** here (no default). Each event prints as:
45
-
46
- ```
47
- <timestamp> <scriptName> <wireType>:<wireId> <duration>ms — <error|message|outcome>
48
- ```
49
-
50
- This is the whole request across the stage — every unit it touched, in order,
51
- with per-event durations. The last event before the failure is where to look.
52
-
53
- **3 — Is it one request or the whole stage?**
54
-
55
- ```bash
56
- pikku fabric metrics -b main # last 24h
57
- pikku fabric metrics -b main --hours 2 --function createOrder
58
- ```
59
-
60
- `--branch` is **required** here too; `--hours` defaults to 24.
61
-
62
- Rows are `reqs= err= (rate%) avg= min= max=` per bucket. A single bad request
63
- with a healthy error rate is a data problem; a climbing error rate is a
64
- deployment or dependency problem. `--json` additionally returns a `wireTypes`
65
- breakdown (requests per http/queue/scheduler/…) that the table output omits.
66
-
67
- **4 — Wider context around the failure**
68
-
69
- ```bash
70
- pikku fabric logs -b main
71
- pikku fabric logs -b main --level warn
72
- pikku fabric logs -b main -f # follow
73
- ```
74
-
75
- `--branch` is **required** — `logs` throws `Specify --branch <branch-name>.`
76
- without it, even though the flag reads as optional.
77
-
78
- **5 — Is the running code the code you think it is?**
79
-
80
- ```bash
81
- pikku fabric status # active + in-flight deployment, per stage, with gitSha
82
- ```
83
-
84
- Check this _before_ deep-diving. A stage still serving an older `gitSha`, or a
85
- deploy stuck in flight, explains a whole class of "my fix did nothing".
86
-
87
- ## Known gaps — do not misread these as bugs in your app
88
-
89
- - **`pikku fabric logs --since` and `--deployment` are accepted and ignored.**
90
- They are declared as options but the command never reads them, so
91
- `--since 15m` silently returns the same default window as no flag at all. Do
92
- not conclude "nothing happened in the last 15 minutes" from it. Narrow by
93
- `--level`, or by `--function` via `errors`, instead.
94
- - **`--follow` is a 2-second client-side poll, not a server stream** — despite
95
- its own help text reading "Stream new logs (SSE)". Server-side SSE is planned;
96
- the backend doesn't push natively today. It
97
- dedups against what it already printed, so it behaves like `tail -f`, but new
98
- entries can appear up to ~2s late and it holds the process open until killed.
99
-
100
- ## What NOT to do
101
-
102
- - **Do not SSH anywhere or query the telemetry backend directly.** These
103
- commands are the supported surface; anything lower-level is Fabric-internal
104
- and will not exist for your project.
105
- - **Do not debug by redeploying with added `console.log`s.** Get the traceId,
106
- read the trace. A deploy cycle per hypothesis is the slow path.
107
- - **Do not read the truncated `errors` message as the full error.** Always
108
- confirm against `trace` before changing code.
109
- - **Do not treat an empty `errors` table as "the app is fine"** — a request that
110
- returns a wrong 200 logs nothing. Check `metrics` for the outcome mix.
@@ -1,80 +0,0 @@
1
- ---
2
- name: pikku-mantine
3
- description: >-
4
- Use when building a Mantine UI on top of a Pikku backend — rendering dates that came back from a
5
- generated client, keeping layout flow-relative so the app survives an RTL locale, and branching on
6
- colour scheme without hardcoding a shade. TRIGGER when: putting a value from usePikkuQuery or an
7
- RPC response on screen, writing margins/padding/alignment in Mantine props or CSS, choosing a date
8
- input, or handling light/dark. DO NOT TRIGGER when: the data does not come from a Pikku client
9
- (this is only about what the generated clients hand you), or for user-facing copy (use pikku-i18n).
10
- installGroups: [client]
11
- ---
12
-
13
- # Mantine on a Pikku client
14
-
15
- ## Dates — always format before rendering
16
-
17
- The generated clients run `transformDates`, which revives **fully-zoned ISO-8601 instants** —
18
- `2026-03-14T08:12:00Z`, `2026-03-14T08:12:00.000+01:00` — into `Date` objects and touches nothing
19
- else. A bare `2026-03-14`, a zoneless `2026-03-14T08:12:00` and an impossible `2026-02-31T00:00:00Z`
20
- all stay the strings the server sent. So a field's runtime type follows the VALUE, not the schema:
21
- one column can arrive as a `Date` from one row and a string from the next.
22
-
23
- Two consequences, and both compile:
24
-
25
- - **A string method on one white-screens the page.** `row.createdAt.split('T')[0]` type-checks
26
- against nothing useful and blows up at runtime. There is no string to slice.
27
- - **A raw `Date` dropped into JSX crashes the route.** `<Text>{row.createdAt}</Text>`, a table cell,
28
- a `<Badge>` — React throws `Objects are not valid as a React child (found: [object Date])` and the
29
- page falls into its error boundary. Nothing catches it before the screen is white, which makes it
30
- the most common broken page in a build.
31
-
32
- **Format with dayjs.** It is Mantine's own date library, already shipped alongside `@mantine/dates`,
33
- and it takes either a `Date` or a string. Never `toLocaleDateString`, `date-fns` or `luxon`.
34
-
35
- ```tsx
36
- import dayjs from 'dayjs'
37
-
38
- <Text>{dayjs(row.dueOn).format('D MMM YYYY')}</Text> // 15 Jun 2026
39
- <Text>{dayjs(row.createdAt).format('D MMM YYYY, HH:mm')}</Text>
40
- ```
41
-
42
- A relative "2 days ago" via dayjs `relativeTime` is fine. Coercing instead of formatting
43
- (`` `${d}` ``, `String(d)`, `d + ''`) does not crash but prints
44
- `Mon Jun 15 2026 02:00:00 GMT+0200` — a different bug, equally wrong.
45
-
46
- Date **inputs** are `@mantine/dates` — `DatePickerInput`, `DatePicker`, `Calendar` — never a raw
47
- `<TextInput type="date">`. Those are pickers and they are not a schedule: Mantine ships no
48
- week/time-grid component, so a diary, rota, timetable or booking week is a grid you build, not a
49
- `Calendar` with the time-of-day left out. `Calendar` with `renderDay` IS right for "a few things on
50
- each day of a month", like a content calendar or a holiday planner.
51
-
52
- All of this applies to stub and fixture dates exactly as it does to real data.
53
-
54
- ## RTL-safe styles
55
-
56
- Write layout styles flow-relative so the UI works in both LTR and RTL languages. Pikku's i18n ships
57
- Arabic, Hebrew, Farsi and Urdu support, and a physical margin is what breaks under it.
58
-
59
- | Avoid | Use instead |
60
- | ----------------------------- | ------------------------------------------ |
61
- | `ml`, `mr`, `pl`, `pr` | `ms`, `me`, `ps`, `pe` |
62
- | `text-align: left/right` | `text-align: start/end` |
63
- | `margin-left`, `margin-right` | `margin-inline-start`, `margin-inline-end` |
64
- | `flex-direction: row-reverse` | `dir` attribute or logical properties |
65
-
66
- Mantine shorthand: `ms` = margin-inline-start, `me` = margin-inline-end, `ps` = padding-inline-start,
67
- `pe` = padding-inline-end.
68
-
69
- ## Dark mode
70
-
71
- Use Mantine's `light-dark()` utility or `useMantineColorScheme`, and only with colours that already
72
- come from the theme — never introduce a literal colour or a shade string for one scheme.
73
-
74
- ```tsx
75
- // Correct
76
- <Box bg="var(--mantine-color-body)">
77
-
78
- // Wrong — scheme branch with hardcoded Mantine shades
79
- <Box bg={theme.colorScheme === 'dark' ? 'dark.6' : 'gray.0'}>
80
- ```
@@ -1,117 +0,0 @@
1
- # Personas and actors
2
-
3
- A **persona** is a person your product is for; an **actor** is one body that signs in as them. Every entry materialises exactly one actor, so `actors.<id>` exists for each declared persona and there is no second way to declare a login.
4
-
5
- - Two people of the same kind are two entries, not one persona with two logins — "you see yours, not theirs" is only testable with two customers.
6
- - Never write an email address: each is derived from the persona id and `scenarios.emailDomain`, and a hand-written one signs in as somebody who was never created.
7
- - `roles` is typechecked against `defineSystemRole`; an undeclared role is a build error.
8
- - A person who is only ever acted _upon_ — the account an admin bans — sets `runnable: false`: declared and seeded, never signed in, because a run as them would race the scenario that acts on them.
9
- - A persona holds only what is true of that kind of person for the app's whole lifetime (`name`, `jobTitle`, `description`, `personality`, `roles`, `goals`, `disposition`). What someone is trying to get done, and the circumstances they are doing it in, belong to the **scenario**, not to them.
10
-
11
- ## Declaring personas in TypeScript
12
-
13
- There may be **one `definePersonas` call in the whole codebase** — one place to
14
- read the set from, one place to add to it. A second anywhere, including in the
15
- same file, is a critical. Generated files are exempt and never claim the slot.
16
-
17
- > [!WARNING]
18
- > The declaration is **read from source, never evaluated** — the CLI writes it
19
- > to JSON that a deployed stage carries without the app. So every value has to
20
- > be statically knowable, and a value that is not comes out as `undefined`
21
- > rather than as an error. Only `name` is checked, so a computed `personality`,
22
- > `jobTitle` or `description` is dropped in silence and the persona runs with a
23
- > blank temperament.
24
-
25
- What that admits and what it does not:
26
-
27
- ```typescript
28
- personality: 'Wound up and short with it.' // read
29
- personality: `Wound up and short with it.
30
- Says what she wants in a few blunt words.` // read — no ${} in it
31
- personality: 'Wound up. ' + 'Short with it.' // dropped, silently
32
- personality: TEMPERAMENTS.impatient // dropped, silently
33
- ```
34
-
35
- A no-substitution template literal is a string literal as far as the reader is
36
- concerned, so it is the way to write a long personality across several lines —
37
- not a concatenation, and not a `prettier-ignore`d single line. Its newlines and
38
- leading indentation are kept verbatim and reach the model that way, which is
39
- harmless but worth knowing before you align it to the surrounding code.
40
-
41
- One more thing worth knowing before writing a rich persona: **`actor.converse`
42
- builds its prompt from `name`, `jobTitle`, `personality` and the scenario's
43
- `task` only.** Fields like `disposition`, `goals` and `roles` are read and
44
- stored, and the console shows them, but they do not reach the conversing
45
- persona's instructions. Anything that must shape how someone talks belongs in
46
- `personality` or in the task.
47
-
48
- A project that never declares a persona keeps working: a scenario that names no actor needs none.
49
-
50
- - `environments.<name>.apiUrl` is required. `signInPath` defaults to `/auth/sign-in/actor`, `rpcPath` to `/rpc`.
51
- - **`SCENARIO_ACTOR_SECRET` is an environment variable and never goes in `pikku.config.json`.** It signs actors in. `pikku scenario run` throws without it; a server auto-building actors warns and runs without them.
52
-
53
- ## Actors that call a third-party API
54
-
55
- An addon generated from an upstream API (Dolibarr, a CRM, a calendar) calls it
56
- with the signed-in user's own credential. An actor has none until one is stored
57
- for it, so every step that reaches the addon fails with `No <X> session`. Give
58
- the `actor` plugin a `credentials` option, and each actor carries its upstream
59
- credential into every session:
60
-
61
- - `names: ['dolibarr']` — the credentials to carry
62
- - `store: (name, value, userId) => credentialService.set(name, value, userId)`
63
- - `remove: (name, userId) => credentialService.delete(name, userId)`
64
-
65
- At each actor sign-in the plugin reads `ACTOR_CREDENTIAL_<PERSONA>_<NAME>` —
66
- `dan` + `dolibarr` is `ACTOR_CREDENTIAL_DAN_DOLIBARR` — and stores it with
67
- `credentialService.set` for that actor. A bare value is stored as `{ token }`
68
- (what a delegated or bearer credential holds); a JSON object is stored as-is,
69
- e.g. `{"apiKey":"…"}` for an API-key credential. Unset means the actor has no
70
- upstream credential: `remove` drops one stored at an earlier sign-in.
71
-
72
- - **Values live in `.env` (or CI secrets), never in `personas.ts` or code.**
73
- Use a dedicated upstream test account per persona, not a real person's.
74
- - `read` defaults to `process.env`; a Worker passes `(key) => variables.get(key)`.
75
- - A malformed JSON value refuses the sign-in with a 500 that names the variable.
76
- - A delegated token expires upstream like any other; re-signing the actor
77
- in re-stores whatever the variable holds now.
78
-
79
- ## The same actors sign a human in
80
-
81
- Declared actors are not only for automated runs. `signInPath` is Better Auth's
82
- `actor` plugin (see `pikku-auth`, a separate install), which any caller can post to — so the
83
- frontend gets a one-click "Sign in as …" switcher over the **same** list, and an
84
- app can be reviewed as each kind of user without anyone knowing a seed password.
85
-
86
- The switcher holds no credential. It lists personas from
87
- `/auth/sign-in/personas` and signs in by posting only a persona id to
88
- `/auth/sign-in/persona`; the server resolves the address. One server piece
89
- serves both, in the auth config:
90
-
91
- ```ts snippet:personaSignIn
92
- ```
93
-
94
- It is always open under `pikku dev`. A deployed stage needs actor
95
- sign-in opted in **and** its `devSwitcher` feature flag on; production never
96
- has the opt-in, so it lists nobody and refuses every persona sign-in.
97
-
98
- Do not hand-roll the switcher: `useDevActors()` (`pikku-react`, a separate install) is the logic and
99
- `<DevActorSwitcher />` from `@pikku/mantine/dev` is a ready rendering of it.
100
- `pikku fabric validate` **requires** any frontend with a login screen to ship
101
- one — without it a reviewer is locked out of their own sandbox.
102
- When the switcher is missing, it is one of three things, and none of them
103
- errors:
104
-
105
- - **The list is empty.** On a deployed stage that is the gate
106
- doing its job — check the opt-in and the `devSwitcher` flag. Locally, check
107
- the personas declare an `email` (via `scenarios.emailDomain`) and are not
108
- `runnable: false`.
109
- - **`personaSignIn` is missing, or the frontend calls another API.** A dev
110
- proxy (`VITE_API_PROXY`, default `http://localhost:3000`) that points at
111
- another project's API lists that project's personas, or none.
112
- - **It is not mounted on the page you are looking at.** The template mounts it
113
- on the login screen. A public homepage that replaces the `/` → `/app`
114
- redirect needs its own `<DevActorSwitcher />` in the public layout.
115
-
116
- When the switcher lists personas but a click 404s, that persona has no `email`
117
- or is `runnable: false`.
@@ -1,23 +0,0 @@
1
- # Subscribing to other SSE / WebSocket routes
2
-
3
- The same `PikkuRealtime` client also handles generic SSE + channel routes (not just
4
- `/events` topics). Use the path; the base URL is inherited from `PikkuFetch`.
5
-
6
- ```ts
7
- // Any `sse: true` HTTP route
8
- const sub = realtime.subscribeToSSE<{ progress: number }>(
9
- `/workflow-run/${runId}/stream`,
10
- (event) => setProgress(event.progress)
11
- )
12
- // later: sub.close()
13
-
14
- // Any wireChannel — open a raw socket, wrap in PikkuWebSocket for typed I/O
15
- const ws = realtime.connectToChannel('/ws/kanban')
16
- const typed = new PikkuWebSocket<'kanban-live'>(ws)
17
- typed.getRoute('command').subscribe('message', (data) => {
18
- /* ... */
19
- })
20
- ```
21
-
22
- Discover what's available with `pikku meta clients --json` — `channels` and any HTTP
23
- `sse: true` routes are listed there.