@pikku/skills 0.12.58 → 0.12.59
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/dist/skills.gen.js +2 -2
- package/package.json +10 -7
- package/skills/pikku-a11y/SKILL.md +5 -3
- package/skills/pikku-addon/SKILL.md +8 -9
- package/skills/pikku-agent/SKILL.md +16 -13
- package/skills/pikku-agent/references/runner-vercel.md +1 -1
- package/skills/pikku-architect/SKILL.md +7 -10
- package/skills/pikku-auth/SKILL.md +16 -20
- package/skills/pikku-auth/references/better-auth.md +74 -37
- package/skills/pikku-auth/references/sessions.md +8 -0
- package/skills/pikku-build/SKILL.md +36 -68
- package/skills/pikku-build/references/app.md +27 -828
- package/skills/pikku-build/references/feature.md +3 -5
- package/skills/pikku-build/references/phase-1-what-it-is.md +167 -0
- package/skills/pikku-build/references/phase-2-people-and-apps.md +133 -0
- package/skills/pikku-build/references/phase-3-plan.md +62 -0
- package/skills/pikku-build/references/phase-4-build.md +249 -0
- package/skills/pikku-build/references/phase-5-prove-and-ship.md +148 -0
- package/skills/pikku-build/references/platform.md +5 -6
- package/skills/pikku-build/references/quick.md +2 -2
- package/skills/pikku-build/references/ship.md +4 -5
- package/skills/pikku-changes/SKILL.md +13 -7
- package/skills/pikku-concepts/SKILL.md +19 -258
- package/skills/pikku-concepts/references/cli.md +63 -0
- package/skills/pikku-concepts/references/functions.md +117 -0
- package/skills/pikku-concepts/references/language.md +5 -5
- package/skills/pikku-concepts/references/packages.md +6 -4
- package/skills/pikku-concepts/references/testing.md +14 -0
- package/skills/pikku-convert-screen/SKILL.md +7 -1
- package/skills/pikku-deploy/SKILL.md +29 -30
- package/skills/pikku-deploy/references/ws.md +1 -1
- package/skills/pikku-emails/SKILL.md +7 -3
- package/skills/pikku-guide/SKILL.md +7 -10
- package/skills/pikku-i18n/SKILL.md +18 -19
- package/skills/pikku-i18n/references/messages.md +6 -8
- package/skills/pikku-knowledge/SKILL.md +42 -45
- package/skills/pikku-kysely/SKILL.md +50 -13
- package/skills/pikku-list-query/SKILL.md +27 -14
- package/skills/pikku-meta/SKILL.md +13 -16
- package/skills/pikku-meta/references/audit.md +1 -45
- package/skills/pikku-meta/references/versioning.md +1 -1
- package/skills/pikku-middleware/SKILL.md +23 -13
- package/skills/pikku-middleware/references/middleware-patterns.md +2 -2
- package/skills/pikku-n8n-import/SKILL.md +7 -8
- package/skills/pikku-permissions/SKILL.md +14 -8
- package/skills/pikku-react/SKILL.md +7 -6
- package/skills/pikku-realtime/SKILL.md +16 -11
- package/skills/pikku-report/SKILL.md +8 -10
- package/skills/pikku-scenario/SKILL.md +8 -12
- package/skills/pikku-scenario/references/steps.md +3 -4
- package/skills/pikku-scenario/references/virtual-users.md +1 -1
- package/skills/pikku-seo/SKILL.md +16 -8
- package/skills/pikku-service-backends/SKILL.md +26 -28
- package/skills/pikku-services/SKILL.md +8 -9
- package/skills/pikku-services/references/services.md +1 -1
- package/skills/pikku-software-archaeology/README.md +12 -1
- package/skills/pikku-software-archaeology/SKILL.md +9 -2
- package/skills/pikku-software-archaeology/references/pikku-mapping.md +1 -1
- package/skills/pikku-software-archaeology/references/sources/express.md +75 -0
- package/skills/pikku-software-archaeology/references/sources/laravel.md +77 -0
- package/skills/pikku-software-archaeology/references/sources/nestjs.md +73 -0
- package/skills/pikku-software-archaeology/references/sources/rails.md +72 -0
- package/skills/pikku-software-archaeology/references/tests-to-scenarios.md +72 -0
- package/skills/pikku-tailwind/SKILL.md +15 -16
- package/skills/pikku-theme/SKILL.md +15 -17
- package/skills/pikku-ui/SKILL.md +4 -3
- package/skills/pikku-webhook/SKILL.md +10 -11
- package/skills/pikku-wiring/SKILL.md +45 -47
- package/skills/pikku-wiring/references/channel.md +1 -1
- package/skills/pikku-wiring/references/scheduler.md +1 -1
- package/skills/pikku-wiring/references/trigger.md +24 -1
- package/skills/pikku-workflow/SKILL.md +7 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/skills",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.59",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/pikkujs/pikku.git",
|
|
@@ -16,23 +16,26 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"embed": "bun run scripts/embed.ts",
|
|
18
18
|
"tsc": "bun run embed && tsc",
|
|
19
|
-
"build": "bun run embed && tsc -b",
|
|
19
|
+
"build": "bun run clean && bun run embed && tsc -b",
|
|
20
20
|
"ncu": "npx npm-check-updates",
|
|
21
21
|
"test": "bash run-tests.sh",
|
|
22
22
|
"test:watch": "bash run-tests.sh --watch",
|
|
23
23
|
"test:coverage": "bash run-tests.sh --coverage",
|
|
24
|
-
"prepublishOnly": "bun run build"
|
|
24
|
+
"prepublishOnly": "bun run build",
|
|
25
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo"
|
|
25
26
|
},
|
|
26
27
|
"exports": {
|
|
27
|
-
".": "./dist/index.js"
|
|
28
|
+
".": "./dist/index.js",
|
|
29
|
+
"./package.json": "./package.json"
|
|
28
30
|
},
|
|
29
31
|
"files": [
|
|
30
32
|
"dist",
|
|
31
|
-
"skills"
|
|
33
|
+
"skills",
|
|
34
|
+
"!dist/**/*.tsbuildinfo"
|
|
32
35
|
],
|
|
33
36
|
"devDependencies": {
|
|
34
|
-
"@types/node": "^
|
|
35
|
-
"yaml": "^2.9.
|
|
37
|
+
"@types/node": "^26.6.5",
|
|
38
|
+
"yaml": "^2.9.1"
|
|
36
39
|
},
|
|
37
40
|
"engines": {
|
|
38
41
|
"node": ">=24"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-a11y
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
WCAG 2.2 accessibility rules for shadcn/Tailwind app UI: labeled inputs, real buttons/links,
|
|
5
|
+
keyboard and focus, contrast, modals, reduced motion. TRIGGER when: building forms or interactive
|
|
6
|
+
UI, icon-only buttons, modals/drawers, tables/lists with actions, keyboard/focus work, or the user
|
|
7
|
+
mentions accessibility, screen readers or WCAG. DO NOT TRIGGER when: backend, database or
|
|
8
|
+
deployment work with no UI.
|
|
7
9
|
installGroups: [client]
|
|
8
10
|
---
|
|
9
11
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-addon
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
cross-project function sharing
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
definitions (use pikku-concepts), or importing an n8n export (use pikku-n8n-import).
|
|
4
|
+
Creating or consuming reusable Pikku function packages (addons): wireAddon, ref(),
|
|
5
|
+
pikkuAddonServices/pikkuAddonWireServices, package structure, shipping DB tables (pikku db
|
|
6
|
+
export), generating an addon from an OpenAPI/Swagger spec. TRIGGER when: code uses those APIs, or
|
|
7
|
+
the user asks about addons or cross-project function sharing, or hands over an OpenAPI/Swagger
|
|
8
|
+
spec (file or URL) to build on. DO NOT TRIGGER for internal function composition (use
|
|
9
|
+
pikku-wiring), general function definitions (use pikku-concepts) or n8n imports (use
|
|
10
|
+
pikku-n8n-import).
|
|
12
11
|
installGroups: [core]
|
|
13
12
|
---
|
|
14
13
|
|
|
@@ -393,7 +392,7 @@ calls, one field out of fifty), or when the app adds a permission of its own.
|
|
|
393
392
|
carries middleware, not permissions, so a rule on one addon function lives in
|
|
394
393
|
the `permissions` of an app function that calls it. An addon called with the
|
|
395
394
|
user's own credential is already limited upstream to what that user may do, so
|
|
396
|
-
a data-aware `pikkuPermission` repeating that check (may they read
|
|
395
|
+
a data-aware `pikkuPermission` repeating that check (may they read _this_
|
|
397
396
|
invoice?) adds nothing. A session-only `pikkuAuth` (a role, a tier) is still
|
|
398
397
|
worth it: it can be checked before any input exists, so the functions a user
|
|
399
398
|
can't call drop out of the tools an MCP client, an agent or a workflow is
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-agent
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
or general function definitions (use pikku-concepts).
|
|
4
|
+
Building AI agents, chatbots and LLM assistants with Pikku: pikkuAgent, ref() tools, memory,
|
|
5
|
+
streaming, tool approval, thread ownership, rpc.agent, VercelAgentRunner and its provider map,
|
|
6
|
+
voiceInput/voiceOutput. TRIGGER when: code uses
|
|
7
|
+
pikkuAgent/rpc.agent/runAgent/streamAgent/VercelAgentRunner/voiceInput, or the user asks about
|
|
8
|
+
agents, tool-calling, agent memory, model providers, speech in/out or `pikku enable agent`. DO NOT
|
|
9
|
+
TRIGGER for MCP exposure (use pikku-wiring), workflows (use pikku-workflow), React agent hooks
|
|
10
|
+
(use pikku-react) or general functions (use pikku-concepts).
|
|
12
11
|
installGroups: [core]
|
|
13
12
|
---
|
|
14
13
|
|
|
@@ -21,11 +20,11 @@ than what they look like.
|
|
|
21
20
|
|
|
22
21
|
## Pick the reference
|
|
23
22
|
|
|
24
|
-
| You are…
|
|
25
|
-
|
|
|
26
|
-
| Defining or invoking an agent — tools, memory, streaming, approval, threads, images | `references/agents.md`
|
|
27
|
-
| Wiring the runner, or pointing model strings at a provider or gateway
|
|
28
|
-
| Adding speech in or out of an agent
|
|
23
|
+
| You are… | Read |
|
|
24
|
+
| ----------------------------------------------------------------------------------- | ----------------------------- |
|
|
25
|
+
| Defining or invoking an agent — tools, memory, streaming, approval, threads, images | `references/agents.md` |
|
|
26
|
+
| Wiring the runner, or pointing model strings at a provider or gateway | `references/runner-vercel.md` |
|
|
27
|
+
| Adding speech in or out of an agent | `references/voice.md` |
|
|
29
28
|
|
|
30
29
|
## An agent is a function that reaches other functions
|
|
31
30
|
|
|
@@ -47,6 +46,10 @@ session, the credentials and the RPC depth for you.
|
|
|
47
46
|
schema on a tool-calling agent is silently inert. The pairing that wants it is
|
|
48
47
|
reading an image or a document into typed data — one tool-free agent, an
|
|
49
48
|
`output` schema, and the picture passed as an `attachments` entry.
|
|
49
|
+
- **An `output` the model returns is validated.** The run fails with
|
|
50
|
+
`AgentOutputValidationError` (502, `issues` lists what did not match) rather
|
|
51
|
+
than handing back a malformed object; there is no retry. A `null` the model
|
|
52
|
+
sends for an optional field comes back absent, so `.optional()` holds.
|
|
50
53
|
- **`auth` defaults to `false`**, because agents are normally invoked from an
|
|
51
54
|
already-authenticated `pikkuFunc`. `scopes` and `permissions` are enforced
|
|
52
55
|
either way — see `pikku-permissions`.
|
|
@@ -24,7 +24,7 @@ const runner = new VercelAgentRunner(
|
|
|
24
24
|
**Methods:**
|
|
25
25
|
|
|
26
26
|
- `stream(params: AgentRunnerParams, channel: AgentStreamChannel): Promise<AgentStepResult>` — Stream AI responses with tool calls
|
|
27
|
-
- `run(params: AgentRunnerParams): Promise<AgentStepResult>` — Execute a single AI step (non-streaming)
|
|
27
|
+
- `run(params: AgentRunnerParams): Promise<AgentStepResult>` — Execute a single AI step (non-streaming). Its `object` is `unknown` and unchecked: the runner has no agent, so there is no declared `output` to validate it against
|
|
28
28
|
- `transcribe({ model, audio, … })` / `generateSpeech({ model, text, voice, … })` — what `voiceInput`/`voiceOutput` call; see the voice reference
|
|
29
29
|
- `generateImage`, `embed`, `embedMany`, `rerank` — the remaining AI SDK surfaces
|
|
30
30
|
- `withApiKey(apiKey)` — returns a **new** runner built from `providerFactory`; returns `this` unchanged when no factory was supplied or the key is blank. This is the per-user-credential path
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-architect
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
`pikku
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
themselves are still being written (use pikku-knowledge), the plan already exists and the job is
|
|
12
|
-
to build it (use pikku-changes), or the changeset was claimed with no plan needed.
|
|
4
|
+
Turn one claimed changeset into its technical plan (tables, functions, wires, roles, scopes,
|
|
5
|
+
screens, scenarios, split into passes) via `pikku knowledge plan set`. The plan is the denominator
|
|
6
|
+
`pikku knowledge plan progress` divides by, so write it BEFORE any code and never edit it to match
|
|
7
|
+
the build. TRIGGER when: `pikku changes claim` says a plan is needed, `changes done` or `pikku
|
|
8
|
+
changes next` refuses for lack of one, or the user asks to plan/architect a changeset. DO NOT
|
|
9
|
+
TRIGGER while knowledge notes are still being written (use pikku-knowledge), when the plan exists
|
|
10
|
+
and the job is building it (use pikku-changes), or when no plan was needed.
|
|
13
11
|
installGroups: [core]
|
|
14
12
|
agent:
|
|
15
13
|
tools: read, write, edit, bash, grep
|
|
@@ -20,7 +18,6 @@ agent:
|
|
|
20
18
|
verify:
|
|
21
19
|
- id: knowledge-consistent
|
|
22
20
|
command: pikku knowledge validate
|
|
23
|
-
|
|
24
21
|
---
|
|
25
22
|
|
|
26
23
|
# Plan one changeset
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-auth
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
pikku-permissions
|
|
9
|
-
|
|
10
|
-
or hits InvalidSessionError. DO NOT TRIGGER when: the question is who may call a function,
|
|
11
|
-
such as ownership, roles, per-row checks, scopes or MissingScopeError (use pikku-permissions),
|
|
12
|
-
middleware mechanics with no identity involved (use pikku-middleware), or secrets and env
|
|
13
|
-
vars (use pikku-services).
|
|
4
|
+
Identity in a Pikku app: authenticating a caller via login, logout, sessions, cookies, bearer
|
|
5
|
+
tokens, API keys, JWT, OAuth/social, MFA, Better Auth, machine callers, `pikku login`. TRIGGER
|
|
6
|
+
when: the user asks about those, how a CLI/agent/sandbox authenticates, or hits
|
|
7
|
+
InvalidSessionError. DO NOT TRIGGER for who may call a function: ownership, roles, scopes,
|
|
8
|
+
MissingScopeError (use pikku-permissions); identity-free middleware mechanics (use
|
|
9
|
+
pikku-middleware); secrets and env vars (use pikku-services).
|
|
14
10
|
installGroups: [core]
|
|
15
11
|
---
|
|
16
12
|
|
|
@@ -26,7 +22,7 @@ They are separate gates, and confusing them is the most common mistake in a
|
|
|
26
22
|
Pikku app.
|
|
27
23
|
|
|
28
24
|
**Authentication** answers _who is calling_. It happens in middleware, before the
|
|
29
|
-
function runs, and ends in a call to `
|
|
25
|
+
function runs, and ends in a call to `setInitialSession`.
|
|
30
26
|
|
|
31
27
|
**Authorization** answers _may this caller do this_. It is declared on the
|
|
32
28
|
function — `scopes` and `permissions` — never checked inside its body. All of it is
|
|
@@ -39,19 +35,19 @@ middleware instead.
|
|
|
39
35
|
|
|
40
36
|
## Pick the reference
|
|
41
37
|
|
|
42
|
-
| You are…
|
|
43
|
-
|
|
|
44
|
-
| Restricting who may call a function — ownership, roles, scopes
|
|
45
|
-
| Reading or setting the session, or wiring `authBearer`/`authCookie`/`authAPIKey` | `references/sessions.md`
|
|
46
|
-
| Standing up user sign-in — OAuth, email+password, MFA, organizations
|
|
47
|
-
| Authenticating a CLI, agent, sandbox or worker — API keys, `pikku login`
|
|
48
|
-
| Configuring the JWT service, or rotating a signing secret
|
|
38
|
+
| You are… | Read |
|
|
39
|
+
| -------------------------------------------------------------------------------- | ---------------------------- |
|
|
40
|
+
| Restricting who may call a function — ownership, roles, scopes | the pikku-permissions skill |
|
|
41
|
+
| Reading or setting the session, or wiring `authBearer`/`authCookie`/`authAPIKey` | `references/sessions.md` |
|
|
42
|
+
| Standing up user sign-in — OAuth, email+password, MFA, organizations | `references/better-auth.md` |
|
|
43
|
+
| Authenticating a CLI, agent, sandbox or worker — API keys, `pikku login` | `references/machine-auth.md` |
|
|
44
|
+
| Configuring the JWT service, or rotating a signing secret | `references/jose.md` |
|
|
49
45
|
|
|
50
46
|
## All authentication goes through `@pikku/better-auth`
|
|
51
47
|
|
|
52
48
|
There is no second auth story. A hand-rolled user table, a bespoke password
|
|
53
|
-
hash, a custom OAuth dance — all of them are the wrong answer, and
|
|
54
|
-
will
|
|
49
|
+
hash, a custom OAuth dance — all of them are the wrong answer, and nothing else
|
|
50
|
+
in Pikku will work against them. `references/better-auth.md` has the setup; the
|
|
55
51
|
built-in strategies in `references/sessions.md` are how a resolved credential
|
|
56
52
|
becomes a Pikku session, not a replacement for it.
|
|
57
53
|
|
|
@@ -48,10 +48,6 @@ Better Auth owns its own HTTP surface, database tables, and session cookie. The
|
|
|
48
48
|
|
|
49
49
|
You do NOT hand-write routes, the session middleware, or the secret wiring — `pikkuBetterAuth` + the CLI generate all of it. Re-run `pikku all` to regenerate.
|
|
50
50
|
|
|
51
|
-
### The console requires Better Auth
|
|
52
|
-
|
|
53
|
-
The Pikku console (`@pikku/addon-console`, enabled via `scaffold.console` in `pikku.config.json`) is an admin surface: **every console RPC now requires an authenticated session** (the functions are `pikkuFunc`; unauthenticated calls return `403`). So `scaffold.console` alone is **no longer the minimum** — you also need an auth strategy, and Better Auth is the supported one. `pikku all` **throws** if `scaffold.console` is set but no `pikkuBetterAuth(...)` is found in the project. Baseline is "must be logged in"; finer policy (admin-only, org scoping) is layered host-side via tag/HTTP middleware. See `pikku-meta` for the console's Security screen.
|
|
54
|
-
|
|
55
51
|
---
|
|
56
52
|
|
|
57
53
|
## Standard Setup
|
|
@@ -107,6 +103,38 @@ Enabling `session: { cookieCache: { enabled: true } }` makes the CLI split out a
|
|
|
107
103
|
|
|
108
104
|
**Tradeoff:** server-side session revocation isn't seen until the cookie cache expires (sign-out is still immediate — it deletes the cookie).
|
|
109
105
|
|
|
106
|
+
**Read the cookie the way the app writes it.** The stateless middleware never builds the auth instance, so it cannot see your `betterAuth({ ... })` options. The generated one is given `advanced.cookiePrefix`, `cookieCache.strategy` and `cookieCache.version` when they are **string literals** in the `betterAuth({ ... })` call — keep them literal and there is nothing to do. When one is not (an env var, a constant from elsewhere), the CLI warns and you register your own, which runs before the generated one:
|
|
107
|
+
|
|
108
|
+
- A `jwe` or `jwt` `cookieCache.strategy` is recognised from the cookie's shape. Pin it with `cookieCache: { strategy }` if you prefer.
|
|
109
|
+
- A custom `advanced.cookiePrefix` must be passed as `betterAuthStatelessSession({ cookiePrefix })`.
|
|
110
|
+
- A `cookieCache.version` must be passed as `cookieCache: { version }`, or cookies of an older version still verify.
|
|
111
|
+
- `cookieCache.jwt` (e.g. a JWKS) is never passed through — register your own for it.
|
|
112
|
+
|
|
113
|
+
`pikkuBetterAuth` logs an error at startup when a constructed stateless middleware disagrees with the auth config.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
addGlobalMiddleware([
|
|
117
|
+
betterAuthStatelessSession({
|
|
118
|
+
cookiePrefix: 'my-app',
|
|
119
|
+
cookieCache: { strategy: 'jwe', version: '2' },
|
|
120
|
+
}),
|
|
121
|
+
])
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Store-backed sessions (`secondaryStorage`)
|
|
125
|
+
|
|
126
|
+
With better-auth's `secondaryStorage`, a session token _is_ the store key, so `betterAuthStoreSession` resolves a session with one `get` and no server bundled — and, unlike the stateless path, revocation is immediate. The token arrives on `Authorization: Bearer …` (enable `bearer()`) or on the session cookie; `transports` picks which.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const storage = inMemorySessionStore() // or your own AuthSessionStorage over Redis/KV
|
|
130
|
+
|
|
131
|
+
betterAuth({ secondaryStorage: storage, plugins: [bearer()] /* … */ })
|
|
132
|
+
|
|
133
|
+
addGlobalMiddleware([betterAuthStoreSession({ store: () => storage })])
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`AuthSessionStorage` is better-auth 1.7's `SecondaryStorage` contract: `get`, `set`, `delete`, `getAndDelete` and `increment`. It was called `SessionStore` before 0.13, which clashed with `@pikku/core`'s unrelated `SessionStore`. `prefixedSessionStore(storage, 'app_1/')` namespaces one backing store for several apps.
|
|
137
|
+
|
|
110
138
|
**Don't add a redundant default `addHTTPMiddleware('*', [betterAuthSession()])`** — with cookieCache on, that re-drags the stateful server into every unit and defeats the split (validate flags it as `better-auth-stateful-session-global`). If you don't need to customize the session, the generated middleware is enough.
|
|
111
139
|
|
|
112
140
|
**Customizing the session bridge (`mapSession`, `impersonation`, `apiKey`, …):** you do NOT chain a second middleware on top of the generated one — register your OWN global session middleware and the CLI steps aside (it stops generating its default). This works on both paths and is detected the same way:
|
|
@@ -126,21 +154,21 @@ resolves the caller's scopes through the registered `ScopeService` and checks th
|
|
|
126
154
|
`admin:*` tree (`ADMIN_SCOPES` exports the ids so you never spell them as bare
|
|
127
155
|
strings):
|
|
128
156
|
|
|
129
|
-
| Gate
|
|
130
|
-
|
|
|
131
|
-
| `impersonation` (
|
|
132
|
-
| `credentialOAuth`'s `canLinkSingleton`
|
|
133
|
-
| the
|
|
134
|
-
| create a user out of band
|
|
135
|
-
| ban / unban
|
|
136
|
-
| delete a user and their data
|
|
137
|
-
| revoke a user's sessions
|
|
138
|
-
| set a user's password
|
|
139
|
-
| read credential values and who holds them
|
|
140
|
-
| set and delete credentials
|
|
141
|
-
| view declared scopes, roles, and who holds them
|
|
142
|
-
| create roles, change their scopes, grant them
|
|
143
|
-
| read the audit trail
|
|
157
|
+
| Gate | Scope required |
|
|
158
|
+
| ------------------------------------------------------ | -------------------------- |
|
|
159
|
+
| `impersonation` (any of the three session middlewares) | `admin:impersonate` |
|
|
160
|
+
| `credentialOAuth`'s `canLinkSingleton` | `admin:credentials:link` |
|
|
161
|
+
| the admin user directory | `admin:users:list` |
|
|
162
|
+
| create a user out of band | `admin:users:create` |
|
|
163
|
+
| ban / unban | `admin:users:ban` |
|
|
164
|
+
| delete a user and their data | `admin:users:remove` |
|
|
165
|
+
| revoke a user's sessions | `admin:users:sessions` |
|
|
166
|
+
| set a user's password | `admin:users:password` |
|
|
167
|
+
| read credential values and who holds them | `admin:credentials:read` |
|
|
168
|
+
| set and delete credentials | `admin:credentials:manage` |
|
|
169
|
+
| view declared scopes, roles, and who holds them | `admin:scopes:read` |
|
|
170
|
+
| create roles, change their scopes, grant them | `admin:scopes:manage` |
|
|
171
|
+
| read the audit trail | `admin:audit:read` |
|
|
144
172
|
|
|
145
173
|
Holding the bare `admin` scope satisfies all of them — a parent grant covers
|
|
146
174
|
everything nested beneath it — so `admin` is the direct replacement for the old
|
|
@@ -148,7 +176,7 @@ everything nested beneath it — so `admin` is the direct replacement for the ol
|
|
|
148
176
|
|
|
149
177
|
Declare the tree in your own `defineScope` (the CLI extracts it by AST, so it must
|
|
150
178
|
be an inline literal; `ADMIN_SCOPE_TREE` is exported from `@pikku/better-auth`
|
|
151
|
-
as the reference shape).
|
|
179
|
+
as the reference shape).
|
|
152
180
|
|
|
153
181
|
```typescript
|
|
154
182
|
defineScope({
|
|
@@ -244,15 +272,15 @@ like any other. None is automatic — an app wires the ones it needs.
|
|
|
244
272
|
| Plugin | Plugin `id` | Adds | Use it when |
|
|
245
273
|
| ------------------------ | ------------------ | ----------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
246
274
|
| `pikkuBan()` | `pikku-ban` | `user.banned/banReason/banExpires` | You ban users (the schema + enforcement half of the above) |
|
|
247
|
-
| `pikkuVirtualUser()` | `virtualUser` | `POST /sign-in/virtual-user`, `user.virtualUser` | Scenarios sign in as a virtual user
|
|
275
|
+
| `pikkuVirtualUser()` | `virtualUser` | `POST /sign-in/virtual-user`, `user.virtualUser` | Scenarios sign in as a virtual user |
|
|
248
276
|
| `pikkuCredentialOAuth()` | `credential-oauth` | `POST /credential-oauth/link`, `/credential-oauth/callback/:providerId` | An app links OAuth2 **API credentials** for a user |
|
|
249
277
|
| `pikkuDelegatedAuth()` | `delegated-auth` | `POST /sign-in/delegated` | An imported upstream API is the system of record for identity |
|
|
250
278
|
|
|
251
279
|
Every one carries a `pikku` prefix, because a `plugins: [...]` array mixes these
|
|
252
280
|
with better-auth's own and a bare `virtualUser()` next to `organization()` says
|
|
253
|
-
nothing about where it came from. The unprefixed names
|
|
254
|
-
`credentialOAuth`, `delegatedAuth`
|
|
255
|
-
|
|
281
|
+
nothing about where it came from. The unprefixed names (`ban`, `virtualUser`,
|
|
282
|
+
`credentialOAuth`, `delegatedAuth`) were removed; import the `pikku`-prefixed
|
|
283
|
+
ones.
|
|
256
284
|
|
|
257
285
|
The plugin's `id` is what better-auth stores; the **export name** is what the
|
|
258
286
|
inspector reads off your `plugins` array and what generated metadata is keyed
|
|
@@ -339,6 +367,23 @@ An upstream user with no email gets one made up from the login, and the
|
|
|
339
367
|
identity says so with `syntheticEmail: true`. A made-up address never links to
|
|
340
368
|
an existing user row, so it cannot take over someone else's account.
|
|
341
369
|
|
|
370
|
+
Even a real upstream email does not link to an existing local user unless you
|
|
371
|
+
opt in, because it is still the upstream's word for that address:
|
|
372
|
+
|
|
373
|
+
```typescript
|
|
374
|
+
pikkuDelegatedAuth({
|
|
375
|
+
// false (default): a first sign-in whose email is taken is refused.
|
|
376
|
+
// 'non-admins': link unless the local user holds an admin
|
|
377
|
+
// scope; needs scopeService, and links nobody without it.
|
|
378
|
+
// 'all': link anyone, administrators included.
|
|
379
|
+
linkExistingUsersByEmail: 'non-admins',
|
|
380
|
+
/* … */
|
|
381
|
+
})
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Roles are only ever granted: a role the upstream stops returning is not
|
|
385
|
+
revoked.
|
|
386
|
+
|
|
342
387
|
For an addon generated from an OpenAPI spec, none of this is written by hand:
|
|
343
388
|
`pikku new addon --openapi … --auth-config <file>` generates
|
|
344
389
|
`authenticate<Name>Upstream` in the addon and wires this plugin, the stored
|
|
@@ -446,19 +491,9 @@ Better Auth serves everything under `basePath` (default `/api/auth`). Call these
|
|
|
446
491
|
|
|
447
492
|
The session cookie is `better-auth.session_token` (dev) / `__Secure-better-auth.session_token` (prod).
|
|
448
493
|
|
|
449
|
-
### Dev quick login
|
|
450
|
-
|
|
451
|
-
Set `PIKKU_DEV_QUICK_LOGIN=true` and `${basePath}/dev/quick-login` signs in a
|
|
452
|
-
fixed dev admin (`admin@pikku.dev`), creating the user idempotently and granting
|
|
453
|
-
it the bare `admin` scope. It is guarded twice — the env var _and_ a localhost
|
|
454
|
-
hostname check — because a one-request path to an admin session is exactly the
|
|
455
|
-
thing that must not survive a deploy. An app that has not declared the `admin`
|
|
456
|
-
scope still gets a session, with a warning, since a scopeless dev user is useful.
|
|
457
|
-
|
|
458
494
|
### Virtual user sign-in (`virtualUser` plugin)
|
|
459
495
|
|
|
460
|
-
|
|
461
|
-
someone" means **a particular kind of user** rather than one fixed admin.
|
|
496
|
+
Signs in as **a particular kind of user**, for development and scenario runs.
|
|
462
497
|
Register it explicitly — it is not automatic:
|
|
463
498
|
|
|
464
499
|
```typescript
|
|
@@ -604,7 +639,7 @@ await provisionVirtualUsers(
|
|
|
604
639
|
)
|
|
605
640
|
```
|
|
606
641
|
|
|
607
|
-
It writes the same `banned` column the
|
|
642
|
+
It writes the same `banned` column the ban RPC writes (so it needs the
|
|
608
643
|
`pikkuBan()` plugin wired, and says so if it isn't), revokes the account's sessions,
|
|
609
644
|
and leaves the row, its grants and its history intact — provisioning lifts the
|
|
610
645
|
ban again by itself if the virtual user comes back. Deleting is deliberately not
|
|
@@ -641,7 +676,9 @@ export const auth = pikkuBetterAuth(async ({ secrets, variables, kysely }) => be
|
|
|
641
676
|
```
|
|
642
677
|
|
|
643
678
|
- Export exactly ONE `pikkuBetterAuth` per project; the CLI generates a single catch-all worker for all auth routes.
|
|
644
|
-
- `betterAuthSession(
|
|
679
|
+
- The generated session middleware (`betterAuthSession()` or `betterAuthStatelessSession()`) bridges the better-auth session into the Pikku session on every request — you only register one yourself to customise it (`mapSession`, `impersonation`, `apiKey`; see "Stateless session" above).
|
|
680
|
+
- `createAuthHandler()` takes no arguments: it reads `services.auth`. The CLI generates the catch-all route with it.
|
|
681
|
+
- Outside a pikku function (Next.js route, TanStack loader), `getAuthSession(auth, request, createConfig, createSingletonServices)` reads the session. With a factory it builds the services and the instance once and reuses them across calls.
|
|
645
682
|
- MFA, organizations, passkeys, etc. are better-auth plugins: add them to `betterAuth({ plugins: [...] })`. The catch-all route already forwards their endpoints.
|
|
646
683
|
|
|
647
684
|
---
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
third argument — not on services. `setSession`/`clearSession` may be async
|
|
14
14
|
(cookie and session-store backends write on the way out), so await them.
|
|
15
15
|
|
|
16
|
+
`setSession` means the same in middleware and in a function body: it signs the
|
|
17
|
+
caller in — the session is marked changed, so `authCookie` re-issues the cookie,
|
|
18
|
+
and it is written to the session store under its `userId`. Middleware that only
|
|
19
|
+
works out who the caller is from a credential it was handed (a cookie, a bearer
|
|
20
|
+
token, an API key) calls `setInitialSession` instead: the function sees that
|
|
21
|
+
session, but nothing is persisted and no cookie is re-issued. Calling
|
|
22
|
+
`setSession` there would rewrite the cookie and the store on every request.
|
|
23
|
+
|
|
16
24
|
```typescript
|
|
17
25
|
// Read session in pikkuFunc (session guaranteed to exist)
|
|
18
26
|
const getProfile = pikkuFunc({
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pikku-build
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
or
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
(use pikku-concepts), wants one specific surface explained rather than built (use that surface's
|
|
13
|
-
skill), only needs the technical plan for one claimed changeset (use pikku-architect), or is
|
|
14
|
-
working items off a deployed stage's changes queue (use pikku-changes).
|
|
4
|
+
Owns app-level work on Pikku (new app, feature, conversion); load pikku-concepts first. Turn a fresh scaffold into a working app (spike, real product or showcase), add a
|
|
5
|
+
feature or endpoint to an existing app, and the cleanup after a template is cloned. Covers
|
|
6
|
+
knowledge base, virtual users, changes, proving scenarios, theming, multi-app layouts, deploying.
|
|
7
|
+
TRIGGER when: asked to build an app on Pikku, a scaffold/template was just created or cloned, or
|
|
8
|
+
asked to add a feature or wire a new endpoint in a working app. DO NOT TRIGGER for one-off
|
|
9
|
+
function edits, Pikku concepts (use pikku-concepts), explaining one surface (use that surface's
|
|
10
|
+
skill), planning one claimed changeset (use pikku-architect) or working a stage's changes queue
|
|
11
|
+
(use pikku-changes).
|
|
15
12
|
allowed-tools: Bash(yarn pikku meta *), Bash(yarn pikku all *), Bash(yarn tsc), Bash(git status *), Bash(git diff *), Bash(git switch *), Bash(git checkout *), Bash(git checkout -b *), Bash(git add *), Bash(git commit *), Bash(git rm *), Bash(git mv *), Bash(git log *), Bash(git branch *), Bash(yarn pikku cloud report *), Bash(npx --no pikku cloud report *)
|
|
16
13
|
argument-hint: '[feature description]'
|
|
17
14
|
installGroups: [core]
|
|
@@ -32,29 +29,30 @@ agent:
|
|
|
32
29
|
|
|
33
30
|
## Which mode
|
|
34
31
|
|
|
35
|
-
| The situation | Read
|
|
36
|
-
| ------------------------------------------------------------------------------ |
|
|
37
|
-
| A template was just cloned or scaffolded, and the tree still looks like one | `references/post-clone.md` first, then come back
|
|
38
|
-
| A real product, meant to be picked up by someone else | `references/app.md` — the default
|
|
39
|
-
| A spike, a throwaway demo, an idea nobody has committed to | `references/quick.md`
|
|
40
|
-
| A showcase meant to exercise every Pikku surface | `references/platform.md`, read together with `references/app.md`
|
|
41
|
-
| A feature added to an app that already has its knowledge base | `references/feature.md`
|
|
42
|
-
| Writing or fixing the scenarios that prove a changeset (app §7, §7a) | `references/scenarios.md`
|
|
43
|
-
| Before the first screen is built: a picture of the screens, a design direction | `references/design.md`
|
|
44
|
-
| Authoring or changing the theme (app §8a) | `references/theming.md`
|
|
45
|
-
| A screen needs data no function returns yet | `references/mocks.md`
|
|
46
|
-
| Adding a second frontend (app §4), at the changeset that needs it | `references/multi-app.md`
|
|
47
|
-
| Shipping an app as a desktop or Android app | `references/native-app.md`
|
|
48
|
-
| Deploying, and the deploy-readiness contract (app §9) | `references/ship.md`
|
|
49
|
-
| The request is built on an OpenAPI spec (auth mode, sign-in or connect screen) | `references/openapi.md`
|
|
32
|
+
| The situation | Read |
|
|
33
|
+
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ |
|
|
34
|
+
| A template was just cloned or scaffolded, and the tree still looks like one | `references/post-clone.md` first, then come back |
|
|
35
|
+
| A real product, meant to be picked up by someone else | `references/app.md` (index), then the phase file it names for the phase you are in — the default |
|
|
36
|
+
| A spike, a throwaway demo, an idea nobody has committed to | `references/quick.md` |
|
|
37
|
+
| A showcase meant to exercise every Pikku surface | `references/platform.md`, read together with `references/app.md` |
|
|
38
|
+
| A feature added to an app that already has its knowledge base | `references/feature.md` |
|
|
39
|
+
| Writing or fixing the scenarios that prove a changeset (app §7, §7a) | `references/scenarios.md` |
|
|
40
|
+
| Before the first screen is built: a picture of the screens, a design direction | `references/design.md` |
|
|
41
|
+
| Authoring or changing the theme (app §8a) | `references/theming.md` |
|
|
42
|
+
| A screen needs data no function returns yet | `references/mocks.md` |
|
|
43
|
+
| Adding a second frontend (app §4), at the changeset that needs it | `references/multi-app.md` |
|
|
44
|
+
| Shipping an app as a desktop or Android app | `references/native-app.md` |
|
|
45
|
+
| Deploying, and the deploy-readiness contract (app §9) | `references/ship.md` |
|
|
46
|
+
| The request is built on an OpenAPI spec (auth mode, sign-in or connect screen) | `references/openapi.md` |
|
|
50
47
|
|
|
51
48
|
**App is the default.** A small or toy-sounding app does not make it Quick;
|
|
52
49
|
only an explicit signal of speed or throwaway-ness does. Platform is not "App
|
|
53
50
|
plus more effort" — it is App plus a deliberate surface checklist: read both
|
|
54
51
|
files, follow the base in full, and do not blend the two into one plan.
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
Apart from `app.md`, which indexes its own phase files, each reference names
|
|
54
|
+
the topics it leans on but never tells you to open another file; this table is
|
|
55
|
+
the only routing. Open a reference when its row
|
|
58
56
|
matches, not up front.
|
|
59
57
|
|
|
60
58
|
## Bootstrap before anything else
|
|
@@ -109,7 +107,7 @@ generated functions through `ref()`.
|
|
|
109
107
|
calls for a scheduled task and `capabilities.scheduler` is `false`, check
|
|
110
108
|
`pikku doc` for the door before concluding you cannot build it.
|
|
111
109
|
- **`metaLocale` in `pikku.config.json` is the language of authored meta** —
|
|
112
|
-
every `description`, `title` and step `template`
|
|
110
|
+
every `description`, `title` and step `template` authored in meta.
|
|
113
111
|
Identifiers stay English whatever it says, and the product's own language
|
|
114
112
|
lives in `messages/*.json`.
|
|
115
113
|
- **`pikku all` is the gate.** Run it after touching functions, wirings or
|
|
@@ -146,8 +144,6 @@ generated functions through `ref()`.
|
|
|
146
144
|
- **App** — the frontend's URL (`http://localhost:7104` in the template; each
|
|
147
145
|
frontend in `frontends` in `pikku.config.json` has its own port)
|
|
148
146
|
- **API** — `http://localhost:3000`
|
|
149
|
-
- **Console** — `http://localhost:3000/console`, plus a deep link to each
|
|
150
|
-
page that shows what this turn produced (the paths are below)
|
|
151
147
|
|
|
152
148
|
A person who has to go hunting for the port assumes the app did not start.
|
|
153
149
|
|
|
@@ -166,46 +162,18 @@ again with `--consent <answer>`. If it says reporting is off, do not ask.
|
|
|
166
162
|
## Who you are talking to
|
|
167
163
|
|
|
168
164
|
The prompt asks first how technical the person is: **not technical**,
|
|
169
|
-
**technical, no code**, or **developer** (the default when unsaid).
|
|
170
|
-
|
|
171
|
-
|
|
165
|
+
**technical, no code**, or **developer** (the default when unsaid). Report in
|
|
166
|
+
plain words at that level, and give the links `bun run dev` printed (the app
|
|
167
|
+
and the API). No per-feature deep links.
|
|
172
168
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
|
178
|
-
| ------------------ | --------------------------- | ------------------------ |
|
|
179
|
-
| Not technical | Product pages only | Never |
|
|
180
|
-
| Technical, no code | Product and technical pages | Never |
|
|
181
|
-
| Developer | Product and technical pages | As normal |
|
|
169
|
+
| Level | Code in the conversation |
|
|
170
|
+
| ------------------ | ------------------------ |
|
|
171
|
+
| Not technical | Never |
|
|
172
|
+
| Technical, no code | Never |
|
|
173
|
+
| Developer | As normal |
|
|
182
174
|
|
|
183
175
|
"Never" includes snippets and command lines; say what changed in the person's
|
|
184
|
-
words and
|
|
185
|
-
|
|
186
|
-
**Product pages** — the only ones a non-technical person gets:
|
|
187
|
-
|
|
188
|
-
| Shows | Path |
|
|
189
|
-
| --------------------- | -------------------------------------------------------------------------- |
|
|
190
|
-
| Knowledge, plans | `/console/knowledge`, `/console/knowledge?id=<note path>` |
|
|
191
|
-
| Virtual users | `/console/virtual-users`, `/console/virtual-users?virtual user=<id>` |
|
|
192
|
-
| Roles and permissions | `/console/roles`, `/console/scopes` (only with `@pikku/addon-admin` wired) |
|
|
193
|
-
| Scenarios and runs | `/console/scenarios?id=<id>`, `/console/scenarios?view=runs&run=<run id>` |
|
|
194
|
-
| Workflows | `/console/workflow?id=<id>` |
|
|
195
|
-
| Agents | `/console/agents`, `/console/agents/playground?id=<agent id>` |
|
|
196
|
-
|
|
197
|
-
**Technical pages** — never for a non-technical person: `/console/overview`,
|
|
198
|
-
`/console/functions`, `/console/surface`, `/console/database`,
|
|
199
|
-
`/console/changes`, `/console/wires/http`, `/console/wires/channel`,
|
|
200
|
-
`/console/wires/mcp`, `/console/wires/cli`, `/console/wires/gateway`,
|
|
201
|
-
`/console/async/scheduler`, `/console/async/queue`, `/console/async/trigger`,
|
|
202
|
-
`/console/runtime`, `/console/emails`, `/console/webhooks`, `/console/secrets`,
|
|
203
|
-
`/console/variables`, `/console/security`, `/console/auth-providers`,
|
|
204
|
-
`/console/addons`, `/console/analytics`, `/console/credentials`,
|
|
205
|
-
`/console/users`, `/console/audit`, `/console/flags`, `/console/scorers`.
|
|
206
|
-
|
|
207
|
-
These come from `packages/console/src/App.tsx`; do not link a path that is not
|
|
208
|
-
listed here.
|
|
176
|
+
words and point at the running app.
|
|
209
177
|
|
|
210
178
|
## What NOT to do
|
|
211
179
|
|