@pikku/skills 0.12.22 → 0.12.25

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 (101) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/dist/skills.gen.js +1 -1
  3. package/package.json +1 -1
  4. package/skills/pikku-addon/SKILL.md +2 -2
  5. package/skills/pikku-agent/SKILL.md +67 -316
  6. package/skills/pikku-agent/references/agents.md +299 -0
  7. package/skills/{pikku-ai-vercel/SKILL.md → pikku-agent/references/runner-vercel.md} +2 -24
  8. package/skills/{pikku-ai-voice/SKILL.md → pikku-agent/references/voice.md} +1 -22
  9. package/skills/pikku-architect/SKILL.md +264 -0
  10. package/skills/pikku-auth/SKILL.md +89 -0
  11. package/skills/{pikku-better-auth/SKILL.md → pikku-auth/references/better-auth.md} +1 -27
  12. package/skills/{pikku-jose/SKILL.md → pikku-auth/references/jose.md} +1 -23
  13. package/skills/{pikku-machine-auth/SKILL.md → pikku-auth/references/machine-auth.md} +0 -23
  14. package/skills/{pikku-permissions/SKILL.md → pikku-auth/references/permissions.md} +1 -20
  15. package/skills/{pikku-security/SKILL.md → pikku-auth/references/sessions.md} +0 -20
  16. package/skills/pikku-build/SKILL.md +87 -0
  17. package/skills/{pikku-build-app/SKILL.md → pikku-build/references/app.md} +75 -23
  18. package/skills/{pikku-feature/SKILL.md → pikku-build/references/feature.md} +1 -8
  19. package/skills/{pikku-build-app → pikku-build}/references/multi-app.md +1 -1
  20. package/skills/{pikku-build-platform/SKILL.md → pikku-build/references/platform.md} +22 -37
  21. package/skills/{pikku-template-clone/SKILL.md → pikku-build/references/post-clone.md} +0 -6
  22. package/skills/{pikku-build-quick/SKILL.md → pikku-build/references/quick.md} +4 -20
  23. package/skills/{pikku-build-app → pikku-build}/references/ship.md +7 -1
  24. package/skills/pikku-concepts/SKILL.md +72 -7
  25. package/skills/pikku-concepts/references/concept-mapping.md +8 -8
  26. package/skills/pikku-deploy/SKILL.md +158 -0
  27. package/skills/{pikku-deploy-azure/SKILL.md → pikku-deploy/references/azure.md} +18 -50
  28. package/skills/pikku-deploy/references/cloudflare.md +104 -0
  29. package/skills/pikku-deploy/references/express.md +92 -0
  30. package/skills/{pikku-deploy-fastify/SKILL.md → pikku-deploy/references/fastify.md} +8 -32
  31. package/skills/{pikku-deploy-lambda/SKILL.md → pikku-deploy/references/lambda.md} +6 -27
  32. package/skills/{pikku-deploy-nextjs/SKILL.md → pikku-deploy/references/nextjs.md} +9 -33
  33. package/skills/pikku-deploy/references/uws.md +72 -0
  34. package/skills/pikku-deploy/references/ws.md +75 -0
  35. package/skills/pikku-emails/SKILL.md +3 -2
  36. package/skills/pikku-fabric/SKILL.md +12 -2
  37. package/skills/{pikku-fabric-debug/SKILL.md → pikku-fabric/references/debugging.md} +0 -6
  38. package/skills/pikku-i18n/SKILL.md +60 -207
  39. package/skills/{pikku-paraglide/SKILL.md → pikku-i18n/references/enum-labels.md} +0 -6
  40. package/skills/pikku-i18n/references/messages.md +218 -0
  41. package/skills/{pikku-rtl/SKILL.md → pikku-i18n/references/rtl.md} +3 -9
  42. package/skills/pikku-knowledge/SKILL.md +14 -0
  43. package/skills/pikku-kysely/SKILL.md +13 -13
  44. package/skills/pikku-meta/SKILL.md +58 -130
  45. package/skills/{pikku-deps/SKILL.md → pikku-meta/references/audit.md} +1 -17
  46. package/skills/pikku-meta/references/meta.md +114 -0
  47. package/skills/{pikku-versioning/SKILL.md → pikku-meta/references/versioning.md} +0 -26
  48. package/skills/pikku-middleware/SKILL.md +5 -5
  49. package/skills/pikku-n8n-import/SKILL.md +0 -1
  50. package/skills/pikku-react/SKILL.md +50 -298
  51. package/skills/pikku-react/references/client.md +293 -0
  52. package/skills/{pikku-react-query/SKILL.md → pikku-react/references/react-query.md} +2 -22
  53. package/skills/{pikku-workflows-client/SKILL.md → pikku-react/references/workflows.md} +1 -22
  54. package/skills/pikku-scenario/SKILL.md +60 -45
  55. package/skills/pikku-scenario/references/persona-run.md +148 -0
  56. package/skills/pikku-service-backends/SKILL.md +154 -0
  57. package/skills/pikku-service-backends/references/aws.md +106 -0
  58. package/skills/pikku-service-backends/references/backblaze.md +57 -0
  59. package/skills/pikku-service-backends/references/mongodb.md +90 -0
  60. package/skills/pikku-service-backends/references/redis.md +75 -0
  61. package/skills/pikku-service-backends/references/schema.md +63 -0
  62. package/skills/pikku-services/SKILL.md +68 -291
  63. package/skills/{pikku-audit/SKILL.md → pikku-services/references/audit.md} +0 -22
  64. package/skills/{pikku-config/SKILL.md → pikku-services/references/config.md} +1 -25
  65. package/skills/{pikku-pino/SKILL.md → pikku-services/references/pino.md} +0 -20
  66. package/skills/pikku-services/references/services.md +272 -0
  67. package/skills/pikku-software-archaeology/README.md +5 -1
  68. package/skills/pikku-software-archaeology/SKILL.md +15 -2
  69. package/skills/{pikku-product-second-opinion/example/sample-report.md → pikku-software-archaeology/example/second-opinion-sample-report.md} +1 -1
  70. package/skills/pikku-software-archaeology/references/blueprint.schema.json +1 -1
  71. package/skills/pikku-software-archaeology/references/pikku-mapping.md +3 -3
  72. package/skills/{pikku-product-second-opinion/SKILL.md → pikku-software-archaeology/references/second-opinion.md} +4 -9
  73. package/skills/pikku-webhook/SKILL.md +199 -0
  74. package/skills/pikku-wiring/SKILL.md +180 -0
  75. package/skills/{pikku-websocket/SKILL.md → pikku-wiring/references/channel.md} +2 -35
  76. package/skills/{pikku-cli/SKILL.md → pikku-wiring/references/cli.md} +1 -33
  77. package/skills/{pikku-gateway-slack/SKILL.md → pikku-wiring/references/gateway-slack.md} +0 -23
  78. package/skills/{pikku-http/SKILL.md → pikku-wiring/references/http.md} +3 -39
  79. package/skills/{pikku-mcp/SKILL.md → pikku-wiring/references/mcp.md} +0 -33
  80. package/skills/{pikku-queue/SKILL.md → pikku-wiring/references/queue.md} +1 -33
  81. package/skills/{pikku-realtime/SKILL.md → pikku-wiring/references/realtime.md} +2 -25
  82. package/skills/{pikku-rpc/SKILL.md → pikku-wiring/references/rpc.md} +0 -32
  83. package/skills/{pikku-schedule/SKILL.md → pikku-wiring/references/scheduler.md} +1 -35
  84. package/skills/{pikku-trigger/SKILL.md → pikku-wiring/references/trigger.md} +0 -43
  85. package/skills/pikku-workflow/SKILL.md +2 -2
  86. package/skills/pikku-aws/SKILL.md +0 -161
  87. package/skills/pikku-backblaze/SKILL.md +0 -104
  88. package/skills/pikku-deploy-cloudflare/SKILL.md +0 -123
  89. package/skills/pikku-deploy-express/SKILL.md +0 -122
  90. package/skills/pikku-deploy-uws/SKILL.md +0 -144
  91. package/skills/pikku-mongodb/SKILL.md +0 -113
  92. package/skills/pikku-product-second-opinion/README.md +0 -43
  93. package/skills/pikku-redis/SKILL.md +0 -99
  94. package/skills/pikku-schema-ajv/SKILL.md +0 -83
  95. package/skills/pikku-schema-cfworker/SKILL.md +0 -82
  96. package/skills/pikku-ws/SKILL.md +0 -87
  97. /package/skills/{pikku-build-app → pikku-build}/references/theming.md +0 -0
  98. /package/skills/{pikku-product-second-opinion/references/report-template.md → pikku-software-archaeology/references/second-opinion-report-template.md} +0 -0
  99. /package/skills/{pikku-cli/references/complete-example.md → pikku-wiring/references/cli-complete-example.md} +0 -0
  100. /package/skills/{pikku-http → pikku-wiring}/references/http-options.md +0 -0
  101. /package/skills/{pikku-realtime/references/other-routes.md → pikku-wiring/references/realtime-other-routes.md} +0 -0
@@ -1,297 +1,74 @@
1
1
  ---
2
2
  name: pikku-services
3
3
  description: >-
4
- Use when setting up dependency injection, creating custom services, or configuring the service
5
- layer in a Pikku app. Covers pikkuServices (singleton), pikkuWireServices (per-request),
6
- pikkuServerLifecycle (startup/shutdown hooks), service typing, built-in services, and
7
- tree-shaking. TRIGGER when: code uses pikkuServices/pikkuWireServices/pikkuServerLifecycle, user
8
- asks about services.ts, lifecycle.ts, dependency injection, service factories, startup or
9
- shutdown work, or built-in services (ConsoleLogger, JoseJWTService). DO NOT TRIGGER when: user asks
10
- about middleware (use pikku-middleware), auth strategies or sessions (use pikku-security),
11
- permissions (use pikku-permissions), or secrets/variables (use pikku-config).
4
+ Use for the service layer of a Pikku app — dependency injection with pikkuServices and
5
+ pikkuWireServices, startup/shutdown work with pikkuServerLifecycle, configuration through the
6
+ secrets, variables and credentials services, the audit sink and buffer, and structured logging.
7
+ TRIGGER when: code uses pikkuServices/pikkuWireServices/pikkuServerLifecycle, defineSecret,
8
+ defineVariable or defineCredential, user asks about services.ts, lifecycle.ts, dependency
9
+ injection, env vars, secrets, API credentials, audit logging, AuditService, PinoLogger, or a
10
+ built-in service. DO NOT TRIGGER when: user asks about middleware (use pikku-middleware),
11
+ authentication or permissions (use pikku-auth), or a third-party backend such as Redis, S3 or
12
+ MongoDB (use pikku-service-backends).
12
13
  installGroups: [core]
13
14
  ---
14
15
 
15
- # Pikku Services (Dependency Injection)
16
-
17
- ## Agent Operating Procedure
18
-
19
- Use this skill as an execution checklist, not reference material.
20
-
21
- 1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
22
- 2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
23
- 3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
24
- 4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
25
- 5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
26
-
27
- Pikku uses factory functions for dependency injection. Singleton services are created once at startup; wire services are created fresh per request/job/command. See `pikku-concepts` for the core mental model.
28
-
29
- ## Before You Start
30
-
31
- ```bash
32
- pikku info functions --verbose # See which services existing functions use
33
- pikku info tags --verbose # Understand project organization
34
- ```
35
-
36
- ## API Reference
37
-
38
- ### `pikkuServices(factory)` — singleton services (created once at startup)
39
-
40
- ```typescript
41
- import { pikkuServices } from '#pikku/setup'
42
- import { ConsoleLogger } from '@pikku/core/services'
43
- import { JoseJWTService } from '@pikku/jose'
44
-
45
- export const createSingletonServices = pikkuServices(
46
- async (config, existingServices?) => {
47
- // config: your CoreConfig object
48
- // existingServices: optional, for chaining factories
49
- const logger = new ConsoleLogger()
50
- const database = new DatabasePool(config.database)
51
- await database.connect()
52
- const jwt = new JoseJWTService(
53
- async () => [{ id: 'my-key', value: config.jwtSecret }],
54
- logger
55
- )
56
- return { config, logger, database, jwt, books: new BookService() }
57
- }
58
- )
59
- ```
60
-
61
- ### `pikkuWireServices(factory)` — per-request services (fresh per HTTP request, queue job, CLI command, etc.)
62
-
63
- ```typescript
64
- import { pikkuWireServices } from '#pikku/setup'
65
-
66
- export const createWireServices = pikkuWireServices(
67
- async (singletonServices, wire) => {
68
- // singletonServices: all singleton services
69
- // wire: transport context (session, channel, etc.)
70
- // Pikku merges these with singleton services automatically
71
- return {
72
- userSession: createUserSessionService(wire),
73
- dbTransaction: new DatabaseTransaction(singletonServices.database),
74
- }
75
- }
76
- )
77
- ```
78
-
79
- ### `pikkuServerLifecycle(hooks)` — startup and shutdown work
80
-
81
- A service factory should **construct** services, not run startup side effects. Seeding a database, warming a cache, starting a background consumer or draining a queue belongs in lifecycle hooks, which receive the singleton services after they are built:
82
-
83
- ```typescript
84
- // src/lifecycle.ts
85
- import { pikkuServerLifecycle } from '@pikku/core'
86
- import type { SingletonServices } from '../types/application-types.js'
87
-
88
- export const lifecycle = pikkuServerLifecycle<SingletonServices>({
89
- beforeStart: async ({ kysely }) => {
90
- await runMigrations(kysely) // before the port opens
91
- },
92
- afterStart: async (services) => {
93
- await seedDevData(services) // server is accepting traffic
94
- },
95
- beforeStop: async ({ queueService }) => {
96
- await queueService.drain() // services are still alive here
97
- },
98
- afterStop: async () => {
99
- await releaseExternalLock() // services are ALREADY stopped
100
- },
101
- })
102
- ```
103
-
104
- Every hook is optional. Order is `beforeStart` → server starts → `afterStart`, then on SIGINT `beforeStop` → services stopped → server stopped → `afterStop`.
105
-
106
- **`afterStop` runs after the singleton services have been stopped.** It still receives the services object, but the services inside it are shut down — using one there is a use-after-close bug. Anything that needs a live service goes in `beforeStop`.
107
-
108
- Export **exactly one** `pikkuServerLifecycle` from anywhere in `srcDirectories`; the inspector finds it by the wrapper call, so the filename is free (`src/lifecycle.ts` by convention). It must be an exported `const` initialized with a direct call to `pikkuServerLifecycle` — a re-export or a conditional wrapper is invisible to the inspector.
109
-
110
- **Only `pikku dev` and `pikku serve` run these hooks.** If you bootstrap your own server (Express, Fastify, uWS, Lambda, Cloudflare, Next.js), no runtime adapter invokes them — put the work in your entrypoint instead.
111
-
112
- ### Auto-Generated Service Manifest
113
-
114
- After `npx pikku all`, Pikku generates `.pikku/pikku-services.gen.ts`, a manifest of which services are actually used by wired functions:
115
-
116
- ```typescript
117
- export const requiredSingletonServices = {
118
- database: true, // used by getUser, deleteUser
119
- audit: true, // used by deleteUser
120
- cache: false, // not used by any wired function
121
- jwt: true, // used by auth middleware
122
- } as const
123
-
124
- export type RequiredSingletonServices = Pick<
125
- SingletonServices,
126
- 'database' | 'audit' | 'jwt'
127
- > &
128
- Partial<Omit<SingletonServices, 'database' | 'audit' | 'jwt'>>
129
- ```
130
-
131
- ## Usage Patterns
132
-
133
- ### Using Services in Functions
134
-
135
- **Every service must be declared in `SingletonServices` (or `Services`) in `application-types.d.ts`.** Never access a service via a body-level cast (`services as typeof services & { myService: MyService }`) — that means the type is missing. Add the import and the field to `SingletonServices`, then destructure inline in the function signature. The inspector emits `SERVICES_NOT_DESTRUCTURED` (`PKU410`) and tree-shaking breaks when the first param is a plain identifier rather than an object pattern. Never `new` a service inside a function — services arrive only via injection.
136
-
137
- ```typescript
138
- // ✅ Correct — inline destructure, no cast
139
- const getUser = pikkuFunc({
140
- title: 'Get User',
141
- func: async ({ db, logger, jwt }, { userId }) => {
142
- logger.info('Fetching user', { userId })
143
- return { user: await db.getUser(userId) }
144
- },
145
- })
146
-
147
- // ❌ Wrong — named param + body cast; inspector warns + tree-shaking breaks
148
- const getUser = pikkuFunc({
149
- func: async (services, { userId }) => {
150
- const { db } = services as typeof services & { db: DbService }
151
- // ...
152
- },
153
- })
154
- ```
155
-
156
- ### Services Are Never Optional Inside a Function
157
-
158
- **Never write a `if (!service) throw ...` existence guard in a function body.** It is dead code, and it defeats the platform.
159
-
160
- Optionality lives in exactly one place — `services.ts` / the `SingletonServices` declaration — and it means _"this may not be created"_, not _"this may be missing at call time"_. A service is optional precisely because **nothing destructures it**, and the generated `requiredSingletonServices` manifest therefore never marks it for creation. The moment any wired function destructures it, Pikku creates it and guarantees it is there.
161
-
162
- The types enforce this rather than merely documenting it. The inspector records the services destructured by every wired `func`, `permissions` **and** `middleware`, and emits them as `RequiredSingletonServices`. The generated function types then default their service parameter to:
163
-
164
- ```typescript
165
- export type WiredSingletonServices = RequiredSingletonServices &
166
- SingletonServices
167
- export type WiredServices = SecretlessServices<
168
- RequiredSingletonServices & Services
169
- >
170
- ```
171
-
172
- The `SecretlessServices<...>` wrapper is why `secrets` never appears in a
173
- function's services: it is stripped at the type level, not merely omitted by
174
- convention. Read secrets in a service factory or middleware and hand the value
175
- to a service instead.
176
-
177
- so a service that is `foo?: Foo` in `SingletonServices` arrives as a non-optional `Foo` in every function, permission and middleware that uses it. There is nothing to guard against.
178
-
179
- ```typescript
180
- // ✅ Correct — destructure and use; creation is guaranteed by the manifest
181
- const listThreads = pikkuFunc({
182
- func: async ({ agentRunService }, { threadId }) => {
183
- return await agentRunService.getThreadMessages(threadId)
184
- },
185
- })
186
-
187
- // ❌ Wrong — unreachable guard; signals a misunderstanding of service wiring
188
- const listThreads = pikkuFunc({
189
- func: async ({ agentRunService }, { threadId }) => {
190
- if (!agentRunService) throw new MissingServiceError('agentRunService')
191
- return await agentRunService.getThreadMessages(threadId)
192
- },
193
- })
194
- ```
195
-
196
- If a service really is conditional at runtime (e.g. an optional integration a deployment may not configure), that is a **configuration** concern: branch on config, or fail fast at startup in `services.ts` — not per-request in every function.
197
-
198
- ### Dynamic Import Optimization
199
-
200
- Use the generated manifest to conditionally import heavy dependencies — only the services actually wired get instantiated:
201
-
202
- ```typescript
203
- import { requiredSingletonServices } from '.pikku/pikku-services.gen.js'
204
-
205
- const createSingletonServices = pikkuServices(async (config) => {
206
- const logger = new ConsoleLogger()
207
-
208
- let jwt: JWTService | undefined
209
- if (requiredSingletonServices.jwt) {
210
- const { JoseJWTService } = await import('@pikku/jose')
211
- jwt = new JoseJWTService(keys, logger)
212
- }
213
-
214
- let database: Database | undefined
215
- if (requiredSingletonServices.database) {
216
- database = await createDatabase(config.databaseUrl)
217
- }
218
-
219
- return { config, logger, jwt, database }
220
- })
221
- ```
222
-
223
- ### Audit Wire Service
224
-
225
- `createInvocationAudit` + `createAuditedKysely` add per-request audit buffering that flushes on request close (no-op if `audit` is unconfigured). For the full pattern, no-op behavior, custom-event usage, and Fabric notes, read `references/audit-wire-service.md`.
226
-
227
- ### Built-in Services
228
-
229
- | Service | Package | Purpose |
230
- | ----------------------- | ---------------------- | --------------------------------------- |
231
- | `ConsoleLogger` | `@pikku/core/services` | Console-based logging |
232
- | `JoseJWTService` | `@pikku/jose` | JWT sign/verify via jose |
233
- | `LocalSecretService` | `@pikku/core/services` | Local development secrets |
234
- | `LocalVariablesService` | `@pikku/core/services` | Local environment variables |
235
- | `PinoLogger` | `@pikku/pino` | Structured logging via Pino |
236
- | `createInvocationAudit` | `@pikku/core/services` | Per-request audit buffer |
237
- | `createAuditedKysely` | `@pikku/kysely` | Auto-capture DB queries as audit events |
238
-
239
- ## Complete Example
240
-
241
- ```typescript
242
- // services.ts
243
- import { pikkuServices, pikkuWireServices } from '#pikku/setup'
244
- import { ConsoleLogger } from '@pikku/core/services'
245
- import { JoseJWTService } from '@pikku/jose'
246
-
247
- // Custom service
248
- class TodoStore {
249
- private todos: Map<string, Todo> = new Map()
250
- async create(title: string, priority: string) {
251
- const todo = { id: crypto.randomUUID(), title, priority, completed: false }
252
- this.todos.set(todo.id, todo)
253
- return todo
254
- }
255
- async get(id: string) {
256
- return this.todos.get(id)
257
- }
258
- async list() {
259
- return [...this.todos.values()]
260
- }
261
- async delete(id: string) {
262
- this.todos.delete(id)
263
- }
264
- }
265
-
266
- export const createSingletonServices = pikkuServices(async (config) => {
267
- const logger = new ConsoleLogger()
268
- const jwt = new JoseJWTService(
269
- async () => [{ id: 'my-key', value: config.jwtSecret }],
270
- logger
271
- )
272
- return {
273
- config,
274
- logger,
275
- jwt,
276
- secrets: new LocalSecretService(),
277
- variables: new LocalVariablesService(),
278
- todoStore: new TodoStore(),
279
- }
280
- })
281
-
282
- export const createWireServices = pikkuWireServices(
283
- async (singletonServices, wire) => ({
284
- scopedLogger: new ScopedLogger(wire.session?.userId),
285
- })
286
- )
287
-
288
- // functions/todos.functions.ts — services are auto-injected
289
- export const createTodo = pikkuFunc({
290
- title: 'Create Todo',
291
- func: async ({ todoStore, logger }, { title, priority }) => {
292
- const todo = await todoStore.create(title, priority)
293
- logger.info('Created todo', { id: todo.id })
294
- return { todo }
295
- },
296
- })
297
- ```
16
+ # Pikku Services
17
+
18
+ Signatures and option keys come from `pikku doc` — run `pikku doc --ai` for the
19
+ installed surface. This skill is the part the compiler cannot tell you: where a
20
+ value is allowed to be read, and what a service's lifetime commits you to.
21
+
22
+ ## Two lifetimes, and that is the whole model
23
+
24
+ **Singleton services** (`pikkuServices`) are built once at startup and live for
25
+ the process. **Wire services** (`pikkuWireServices`) are built fresh per HTTP
26
+ request, queue job, channel message or CLI command, and receive the wire.
27
+
28
+ Everything else follows from that split: a database pool is a singleton, a
29
+ request-scoped logger or audit buffer is a wire service, and startup work that
30
+ needs the singletons goes in `pikkuServerLifecycle` rather than in a module's
31
+ top level.
32
+
33
+ ## Pick the reference
34
+
35
+ | You are… | Read |
36
+ | ---------------------------------------------------------------------------- | ------------------------------------------------------------ |
37
+ | Writing or wiring `services.ts` / `lifecycle.ts`, or adding a custom service | `references/services.md` |
38
+ | Reading config — secrets, env vars, or a per-user API credential | `references/config.md` |
39
+ | Recording audit events, or choosing a sink | `references/audit.md` and `references/audit-wire-service.md` |
40
+ | Setting up structured logging | `references/pino.md` |
41
+ | Reaching for Redis, S3, SQS, MongoDB or a schema backend | `pikku-service-backends` |
42
+ | Sending outgoing webhooks to a customer's endpoint | `pikku-webhook` |
43
+
44
+ ## Where a value may be read
45
+
46
+ - **Never `process.env` inside a Pikku function.** Use `services.variables.get()`
47
+ or `services.secrets`. `process.env` belongs to server bootstrap (`start.ts`)
48
+ — and under `pikku dev` / `pikku serve` there is no `start.ts` at all, so
49
+ startup work goes in a `pikkuServerLifecycle` hook, which receives the
50
+ singletons and reads through `variables` too.
51
+ - **`secrets` never reaches a function.** `WiredServices` is wrapped in
52
+ `SecretlessServices<…>`, so it is stripped at the type level rather than merely
53
+ omitted by convention. Read a secret in a service factory or middleware and
54
+ hand the resulting service the value.
55
+
56
+ ## What NOT to do
57
+
58
+ - **Do not guard a service's existence in a function body.** `if (!db) throw …`
59
+ is dead code. Optionality lives only in the `SingletonServices` declaration and
60
+ means "may not be created" — a service is optional precisely because nothing
61
+ destructures it. The inspector records every service destructured by a wired
62
+ `func`, `permissions` or `middleware` and marks it required, so inside the
63
+ function it is a non-optional value. A genuinely conditional integration is a
64
+ configuration concern: branch in `services.ts` or fail fast at startup.
65
+ - **Do not take `services` as a named parameter and cast in the body.** The
66
+ inspector reads the destructuring pattern to build the manifest; a cast makes
67
+ the service invisible to it, so tree-shaking drops what the function needs.
68
+ - **Do not hand-roll an audit table.** `auditLog.write()` on an `audit: true`
69
+ function enriches the event with the function id, wire type, trace id and user
70
+ identity; an `insertInto('audit_log')` of your own gets none of that, and a
71
+ write inside a transaction that later rolls back records nothing.
72
+ - **Do not log an unrevealed secret.** Every logger argument is `Safe<>`-guarded,
73
+ so a `SecretValue` nested anywhere in the call collapses it to `never` and it
74
+ stops compiling. That is deliberate — it would have printed `[secret]` anyway.
@@ -1,27 +1,5 @@
1
- ---
2
- name: pikku-audit
3
- description: >-
4
- Use when adding audit / activity-history / change-tracking to a Pikku app, or when a function
5
- needs to record who changed what. Covers the built-in AuditService sink, the per-invocation
6
- auditLog buffer (createInvocationAudit / pikkuWireServices), the `audit: true` function flag,
7
- explicit `auditLog.write()` domain events, automatic query-level capture via
8
- createAuditedKysely, and the durable KyselyAuditService sink. TRIGGER when: user asks for an
9
- audit log, change history, activity feed, "who did this", or a custom audit/history table; code
10
- uses auditLog, createInvocationAudit, createAuditedKysely, or AuditService. DO NOT TRIGGER when:
11
- user wants app logging/telemetry (use the logger) or DB migrations in general (use
12
- pikku-kysely).
13
- ---
14
-
15
1
  # Pikku Audit
16
2
 
17
- ## Agent Operating Procedure
18
-
19
- Use this skill as an execution checklist, not reference material.
20
-
21
- 1. Discover before editing. Check how services are wired (`services.ts`) and whether an `audit` table migration exists before adding audit calls.
22
- 2. NEVER hand-roll a custom `audit_log` / history table with direct `insertInto('audit_log')` calls. The framework owns audit. A bespoke table drifts from the runtime (missing user/trace/wire context, hand-written CHECK constraints that reject valid events, no prod sink). Use the built-in path below.
23
- 3. Make the smallest source change: mark the function `audit: true`, inject `auditLog`, call `auditLog.write(...)`. Do not invent a new service.
24
- 4. Validate with `pikku all` (regenerates the service flags) then run the app / e2e.
25
3
 
26
4
  ## Mental model — two layers
27
5
 
@@ -1,29 +1,5 @@
1
- ---
2
- name: pikku-config
3
- description: >-
4
- Use when managing secrets, environment variables, config, or OAuth2 credentials in a Pikku app.
5
- Covers defineSecret, defineVariable, defineCredential, and typed config access. TRIGGER when:
6
- code uses defineSecret/defineVariable/defineCredential, user asks about env vars, secrets,
7
- config, OAuth2, SecretValue/.reveal(), SecretCoercionError, or "how do I access environment
8
- variables". DO NOT TRIGGER when: user asks about API versioning/breaking changes (use
9
- pikku-versioning), service factories (use pikku-services), middleware (use pikku-middleware), or
10
- auth strategies and sessions (use pikku-security).
11
- installGroups: [core]
12
- ---
13
-
14
1
  # Pikku Config, Secrets & OAuth2
15
2
 
16
- ## Agent Operating Procedure
17
-
18
- Use this skill as an execution checklist, not reference material.
19
-
20
- 1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
21
- 2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
22
- 3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
23
- 4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
24
- 5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
25
-
26
- Manage secrets, variables, and OAuth2 credentials. Never use `process.env` in Pikku functions — use typed services instead.
27
3
 
28
4
  ## Before You Start
29
5
 
@@ -228,7 +204,7 @@ const apiKey = process.env.API_KEY
228
204
  const apiKey = services.variables.get('API_KEY')
229
205
  ```
230
206
 
231
- `process.env` belongs only in server bootstrap code (`start.ts`). Under `pikku dev` / `pikku serve` there is no `start.ts` — startup work goes in a `pikkuServerLifecycle` export, and the hooks receive the singleton services, so read configuration through `variables` there too (see pikku-services).
207
+ `process.env` belongs only in server bootstrap code (`start.ts`). Under `pikku dev` / `pikku serve` there is no `start.ts` — startup work goes in a `pikkuServerLifecycle` export, and the hooks receive the singleton services, so read configuration through `variables` there too (see `references/services.md`).
232
208
 
233
209
  ### Lint rules
234
210
 
@@ -1,25 +1,5 @@
1
- ---
2
- name: pikku-pino
3
- description: >-
4
- Use when setting up structured logging with Pino in a Pikku app. Covers PinoLogger setup and log
5
- levels. TRIGGER when: code uses PinoLogger, user asks about structured logging, Pino, or
6
- @pikku/pino. DO NOT TRIGGER when: user asks about ConsoleLogger (use pikku-services) or general
7
- service setup.
8
- ---
9
-
10
1
  # Pikku Pino (Structured Logging)
11
2
 
12
- ## Agent Operating Procedure
13
-
14
- Use this skill as an execution checklist, not reference material.
15
-
16
- 1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
17
- 2. Identify the source files that own the behavior. Do not start by reading generated output, `.pikku`, `node_modules`, vendored packages, or broad build artifacts.
18
- 3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
19
- 4. Validate with the narrowest relevant command first, then run `pikku-verify` or `pikku all` when functions, wirings, schemas, or generated clients may have changed.
20
- 5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
21
-
22
- `@pikku/pino` provides structured JSON logging via [Pino](https://getpino.io/). Implements the `Logger` interface from `@pikku/core`.
23
3
 
24
4
  ## Installation
25
5