@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/skills",
3
- "version": "0.12.22",
3
+ "version": "0.12.25",
4
4
  "description": "The Pikku agent skills — the instruction set coding agents read to build, wire and deploy Pikku projects",
5
5
  "author": "yasser.fadl@gmail.com",
6
6
  "license": "MIT",
@@ -5,7 +5,7 @@ description: >-
5
5
  ref(), pikkuAddonServices, pikkuAddonWireServices, addon package structure, and cross-project
6
6
  function sharing. TRIGGER when: code uses wireAddon/ref()/pikkuAddonServices, user asks about
7
7
  addons, reusable function packages, cross-project sharing, or addon package structure. DO NOT
8
- TRIGGER when: user asks about internal function composition (use pikku-rpc) or general function
8
+ TRIGGER when: user asks about internal function composition (use pikku-wiring) or general function
9
9
  definitions (use pikku-concepts).
10
10
  installGroups: [core]
11
11
  ---
@@ -159,7 +159,7 @@ export const createSingletonServices = pikkuAddonServices(
159
159
 
160
160
  `secrets` and `variables` arrive **typed against the addon's own declarations**,
161
161
  and a secret is a `SecretValue` — `.reveal()` is the only way to the plaintext
162
- (see `pikku-config`). `pikkuAddonConfig` is the matching factory for the addon's
162
+ (see `pikku-services`). `pikkuAddonConfig` is the matching factory for the addon's
163
163
  config object.
164
164
 
165
165
  ### `pikkuAddonWireServices(factory)`
@@ -1,322 +1,73 @@
1
1
  ---
2
2
  name: pikku-agent
3
3
  description: >-
4
- Use when building AI agents, chatbots, or LLM-powered assistants with Pikku. Covers
5
- pikkuAgent, ref() tool registration, memory, streaming, tool approval, thread ownership, and
6
- invocation via rpc.agent. TRIGGER when: code uses pikkuAgent/rpc.agent/runAgent/
7
- streamAgent, user asks about AI agents, chatbots, LLM assistants, tool-calling agents, agent
8
- memory/streaming, or `pikku enable agent`. DO NOT TRIGGER when: user asks about MCP tool
9
- exposure (use pikku-mcp) or general function definitions (use pikku-concepts).
4
+ Use when building AI agents, chatbots or LLM-powered assistants with Pikku — pikkuAgent, ref()
5
+ tool registration, memory, streaming, tool approval, thread ownership, invocation via rpc.agent,
6
+ the VercelAgentRunner and its provider map, and the voiceInput/voiceOutput middlewares. TRIGGER
7
+ when: code uses pikkuAgent/rpc.agent/runAgent/streamAgent/VercelAgentRunner/voiceInput, user asks
8
+ about AI agents, chatbots, tool-calling, agent memory or streaming, model providers, speech in or
9
+ out, or `pikku enable agent`. DO NOT TRIGGER when: user asks about MCP tool exposure (use
10
+ pikku-wiring), workflows (use pikku-workflow), or general function definitions (use
11
+ pikku-concepts).
10
12
  installGroups: [core]
11
13
  ---
12
14
 
13
- # Pikku AI Agent Wiring
14
-
15
- ## Agent Operating Procedure
16
-
17
- Use this skill as an execution checklist, not reference material.
18
-
19
- 1. Discover before editing. Run the relevant `pikku meta ... --json` command and inspect only the focused output you need.
20
- 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.
21
- 3. Make the smallest source change that satisfies the task. Keep generated files generated, and avoid hand-editing SDKs, schema output, or typegen.
22
- 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.
23
- 5. If validation fails, fix the source cause and rerun validation. Do not paper over generated errors by editing generated files.
24
-
25
- Build AI agents that use Pikku functions as tools. Agents support conversation memory, streaming, and multi-step tool execution.
26
-
27
- ## Before You Start
28
-
29
- ```bash
30
- pikku info functions --verbose # See existing functions that can be used as agent tools
31
- pikku info tags --verbose # Understand project organization
32
- ```
33
-
34
- See `pikku-concepts` for the core mental model.
35
-
36
- ## API Reference
37
-
38
- ### `pikkuAgent(config)`
39
-
40
- Import it from the generated agent types file — `#pikku` does not re-export it:
41
-
42
- ```typescript
43
- import { pikkuAgent } from '#pikku/agent/pikku-agent-types.gen.js'
44
- import { ref } from '#pikku/function'
45
-
46
- pikkuAgent({
47
- name: string, // Unique agent identifier
48
- description: string, // What the agent does (shown in agent listings)
49
- summary?: string,
50
- errors?: string[],
51
-
52
- // --- system prompt: three fields, joined role → personality → goal ---
53
- role?: string, // Who it is: 'You are a support engineer triaging bugs.'
54
- personality?: string, // How it sounds: tone, verbosity
55
- goal: string, // REQUIRED — what it is for
56
-
57
- model: string, // e.g. 'openai/gpt-5-mini'
58
- temperature?: number,
59
- providerOptions?: { // passed through untouched, keyed by provider
60
- openai?: { reasoningEffort?: 'minimal' | ... },
61
- },
62
-
63
- // --- capabilities: all three take ref() handles, not imported values ---
64
- tools?: unknown[], // ref('todos:addTodo'), ref('graph:sleep'), …
65
- agents?: unknown[], // sub-agents to delegate to
66
- workflows?: unknown[], // workflows callable as a tool
67
- agentMode?: 'delegate' | 'supervise',
68
-
69
- memory?: {
70
- storage?: string, // Service name for persistence (e.g. 'agentStorage')
71
- vector?: string, // Vector store service name
72
- embedder?: string, // Embedding service name
73
- lastMessages?: number, // How many messages to retain in context
74
- workingMemory?: ZodSchema, // Schema for structured working memory
75
- },
76
-
77
- maxSteps?: number, // Max tool-call rounds per invocation
78
- toolChoice?: 'auto' | 'required' | 'none',
79
- prepareStep?: (ctx) => void, // See "Narrowing tools per step"
80
- input?: ZodSchema,
81
- output?: ZodSchema, // Structured output — only honoured with NO tools
82
- tags?: string[],
83
-
84
- sessionScope?: 'user' | 'org', // Who owns this agent's threads. Default 'user'
85
- auth?: boolean, // Default false — see below
86
- scopes?: ScopeId[], // AND gate, checked before permissions
87
- permissions?: PermissionGroup,
88
-
89
- middleware?: PikkuMiddleware[],
90
- channelMiddleware?: PikkuChannelMiddleware[],
91
- agentMiddleware?: PikkuAgentMiddlewareHooks[],
92
- })
93
- ```
94
-
95
- **`goal` is the required prompt field, not `instructions`** — there is no
96
- `instructions` key. `role`/`personality`/`goal` are concatenated in that order,
97
- and nothing validates which text lands in which, so the split is purely for
98
- legibility: prose in the "wrong" one still reaches the model.
99
-
100
- **Tools are `ref('domain:funcName')` handles, not imported function values.** The
101
- inspector resolves the ref against the generated function map, which is what lets
102
- an agent reach a function in another package (or a `graph:*` builtin) without an
103
- import cycle.
104
-
105
- `auth` defaults to `false` because agents are usually invoked from an
106
- already-authenticated `pikkuFunc`. `scopes` and `permissions` are enforced either
107
- way — see `pikku-permissions`.
108
-
109
- ### Invoking an agent
110
-
111
- From inside a Pikku function, go through `wire.rpc.agent` — it carries the
112
- session, credentials, and RPC depth for you:
113
-
114
- ```typescript
115
- const result = await rpc.agent.run('todo-agent', {
116
- message, threadId, resourceId, // required
117
- attachments?, model?, temperature?, context?,
118
- })
119
-
120
- await rpc.agent.stream('todo-agent', input) // writes to the wire's channel
121
- await rpc.agent.approve(runId, [{ toolCallId, approved }], expectedAgentName?)
122
- await rpc.agent.resume(runId, { toolCallId, approved })
123
- await rpc.agent.interrupt(runId, 'user' | 'speech' | 'timeout')
124
- ```
125
-
126
- `context` is a string injected into the system prompt for this request only —
127
- use it for upfront state (current org, project, deployment) so the agent stops
128
- asking the user for identifiers it could have been handed.
129
-
130
- `run` resolves to:
131
-
132
- ```typescript
133
- {
134
- runId, threadId, text,
135
- object?, // set when the agent has an `output` schema
136
- steps, // tool calls made
137
- usage: { inputTokens, outputTokens },
138
- status?: 'completed' | 'suspended',
139
- pendingApprovals?: [{ toolCallId, toolName, args, reason?, runId }],
140
- }
141
- ```
142
-
143
- `runAgent` / `streamAgent` from `@pikku/core/agent` are the layer beneath
144
- this. Their third argument is `RunAgentParams` (`{ sessionService?,
145
- getCredential?, anonymousOwnerResourceId? }`) — **not** `{ singletonServices }`.
146
- Reach for them only outside a wired function; inside one, `rpc.agent` is the
147
- supported path.
148
-
149
- ### Stream events
150
-
151
- `rpc.agent.stream` pushes `AgentStreamEvent`s onto the channel:
152
-
153
- ```typescript
154
- // { type: 'step-start', stepNumber }
155
- // { type: 'text-delta' | 'reasoning-delta', text }
156
- // { type: 'tool-call', toolCallId, toolName, args }
157
- // { type: 'tool-result', toolCallId, toolName, result }
158
- // { type: 'agent-call' | 'agent-result', agentName, session, input | result }
159
- // { type: 'approval-request', toolCallId, toolName, args, reason?, runId? }
160
- // { type: 'credential-request', toolCallId, toolName, credentialName,
161
- // credentialType: 'oauth2' | 'apikey', connectUrl?, runId }
162
- // { type: 'usage', tokens: { input, output }, model }
163
- // { type: 'transcript', text } // what the user was heard to say
164
- // { type: 'audio-delta', data, format, text? } | { type: 'audio-done' }
165
- // { type: 'data', name, data } | { type: 'generative-ui', spec }
166
- // { type: 'suspended', reason: 'rpc-missing', missingRpcs }
167
- // { type: 'interrupted', runId, text, reason }
168
- // { type: 'error', message }
169
- // { type: 'done' }
170
- ```
171
-
172
- Every event except `agent-call`/`agent-result`/`suspended` also carries optional
173
- `agent` and `session` fields, so a UI can attribute output to a sub-agent rather
174
- than folding it into the parent's transcript.
175
-
176
- ## Usage Patterns
177
-
178
- ### Define an Agent
179
-
180
- ```typescript
181
- import { pikkuAgent } from '#pikku/agent/pikku-agent-types.gen.js'
182
- import { ref } from '#pikku/function'
183
-
184
- export const todoAgent = pikkuAgent({
185
- name: 'todo-agent',
186
- description: 'Manages a todo list',
187
- goal: 'You help users manage their todos. You can list, add, complete and delete them.',
188
- model: 'openai/gpt-5-mini',
189
- tools: [
190
- ref('todos:listTodos'),
191
- ref('todos:addTodo'),
192
- ref('todos:completeTodo'),
193
- ref('graph:sleep'),
194
- ],
195
- memory: { storage: 'agentStorage', lastMessages: 20 },
196
- maxSteps: 10,
197
- toolChoice: 'auto',
198
- })
199
- ```
200
-
201
- ### Scaffold the HTTP surface
202
-
203
- ```bash
204
- pikku enable agent
205
- ```
206
-
207
- The next `pikku all` generates `agent.gen.ts` — run/stream/approve/resume
208
- callers plus thread listing endpoints, with thread ownership already enforced
209
- against the session. Don't hand-write these routes.
210
-
211
- ### Structured output
212
-
213
- An `output` schema fills `result.object`, but **only when the agent exposes no
214
- tools** — with a tool present the runner falls back to free text, silently. If
215
- you need both, split the classification into its own tool-free agent.
216
-
217
- ```typescript
218
- export const structuredAgent = pikkuAgent({
219
- name: 'structured-agent',
220
- description: 'Classifies a message and returns a structured verdict',
221
- goal: 'You classify the sentiment of the user message.',
222
- model: 'openai/gpt-5-mini',
223
- output: z.object({ sentiment: z.string(), score: z.number() }),
224
- })
225
- ```
226
-
227
- ### Narrowing tools per step
228
-
229
- `prepareStep` runs before each step with the live tool array for that step, so
230
- mutating it in place changes what the model is offered from there on. `stop()`
231
- ends the loop — called before step 0 the run completes with an empty result
232
- rather than signalling that it was short-circuited.
233
-
234
- ```typescript
235
- prepareStep: ({ stepNumber, tools }) => {
236
- if (stepNumber >= 1) tools.length = 0 // withdraw tools after the first step
237
- }
238
- ```
239
-
240
- ### Tool approval
241
-
242
- A tool that should pause for a human sets `approvalRequired: true` (with an
243
- optional `approvalDescription`) on the _function_, not on the agent. The run then
244
- resolves with `status: 'suspended'` and `pendingApprovals`, and streaming emits
245
- `approval-request`. Answer with `rpc.agent.approve(runId, approvals)`.
246
-
247
- Authorization around tools is two-layer: an agent only sees tools its session can
248
- reach, and the function's own `permissions` still guard the call when the model
249
- picks one.
250
-
251
- ### Thread ownership
252
-
253
- `resourceId` is caller-supplied but never trusted as an owner. The session's
254
- principal (`userId`, or `orgId` when `sessionScope: 'org'`) is prefixed onto it,
255
- so a client can sub-partition inside its own boundary and cannot read across one.
256
- A sessionless run gets an ephemeral anonymous owner instead.
257
-
258
- ## Complete Example
259
-
260
- ```typescript
261
- // functions/todos.functions.ts
262
- export const listTodos = pikkuSessionlessFunc({
263
- description: 'List all todo items',
264
- func: async ({ db }, { status }) => {
265
- return { todos: await db.listTodos(status) }
266
- },
267
- })
268
-
269
- export const createTodo = pikkuFunc({
270
- description: 'Create a new todo item',
271
- func: async ({ db }, { text, priority, dueDate }) => {
272
- return await db.createTodo({ text, priority, dueDate })
273
- },
274
- })
275
-
276
- export const completeTodo = pikkuFunc({
277
- description: 'Mark a todo as complete',
278
- func: async ({ db }, { todoId }) => {
279
- return await db.completeTodo(todoId)
280
- },
281
- })
282
-
283
- // agents/todo-assistant.agent.ts
284
- import { pikkuAgent } from '#pikku/agent/pikku-agent-types.gen.js'
285
- import { ref } from '#pikku/function'
286
-
287
- export const todoAssistant = pikkuAgent({
288
- name: 'todo-assistant',
289
- description: 'A helpful assistant that manages todos',
290
- role: 'You are an assistant that manages a user’s todo list.',
291
- personality: 'Concise. One short paragraph unless asked for detail.',
292
- goal: `Keep the user's todos accurate.
293
- - When creating todos, infer priority if not specified
294
- - When listing todos, summarize the results`,
295
- model: 'openai/gpt-5-mini',
296
- tools: [
297
- ref('todos:listTodos'),
298
- ref('todos:createTodo'),
299
- ref('todos:completeTodo'),
300
- ],
301
- memory: { storage: 'agentStorage', lastMessages: 20 },
302
- maxSteps: 5,
303
- temperature: 0.7,
304
- })
305
-
306
- // Wire to HTTP for a chat endpoint — or skip this entirely and run
307
- // `pikku enable agent`, which scaffolds run/stream/approve/resume for you.
308
- wireHTTP({
309
- method: 'post',
310
- route: '/chat',
311
- func: pikkuFunc({
312
- title: 'Chat',
313
- func: async (_services, { message, threadId }, { session, rpc }) => {
314
- return await rpc.agent.run('todo-assistant', {
315
- message,
316
- threadId,
317
- resourceId: session.userId,
318
- })
319
- },
320
- }),
321
- })
322
- ```
15
+ # Pikku AI Agents
16
+
17
+ Signatures and option keys come from `pikku doc` — run `pikku doc --ai` for the
18
+ installed surface. This skill is the part the compiler cannot tell you: how an
19
+ agent reaches the rest of the app, and which of its knobs mean something other
20
+ than what they look like.
21
+
22
+ ## Pick the reference
23
+
24
+ | You are… | Read |
25
+ | --- | --- |
26
+ | Defining or invoking an agent — tools, memory, streaming, approval, threads | `references/agents.md` |
27
+ | Wiring the runner, or pointing model strings at a provider or gateway | `references/runner-vercel.md` |
28
+ | Adding speech in or out of an agent | `references/voice.md` |
29
+
30
+ ## An agent is a function that reaches other functions
31
+
32
+ Tools, sub-agents and workflows are all supplied as `ref('domain:funcName')`
33
+ handles rather than imported values. The inspector resolves each ref against the
34
+ generated function map, which is what lets an agent call into another package or
35
+ a `graph:*` builtin without an import cycle — and what lets the tool menu be
36
+ filtered per session before the model ever sees it.
37
+
38
+ Invoke through `wire.rpc.agent` from inside a Pikku function; it carries the
39
+ session, the credentials and the RPC depth for you.
40
+
41
+ ## The knobs that do not mean what they look like
42
+
43
+ - **`goal` is the prompt field, and it is required.** There is no `instructions`
44
+ key. `role`, `personality` and `goal` are concatenated in that order and
45
+ nothing validates which text lands where, so the split buys legibility only.
46
+ - **`output` is honoured only when the agent has no tools.** A structured-output
47
+ schema on a tool-calling agent is silently inert.
48
+ - **`auth` defaults to `false`**, because agents are normally invoked from an
49
+ already-authenticated `pikkuFunc`. `scopes` and `permissions` are enforced
50
+ either way — see `pikku-auth`.
51
+ - **`approvalRequired` sits on the tool function, not on the agent.** The run
52
+ then resolves `status: 'suspended'` with `pendingApprovals`; answer with
53
+ `rpc.agent.approve(runId, approvals)`.
54
+ - **Model strings split on the first slash only** — `provider/model`, so
55
+ `'ollama/qwen2.5:7b'` is fine and a string with no slash throws rather than
56
+ defaulting to a provider.
57
+
58
+ ## What NOT to do
59
+
60
+ - **Do not trust a caller-supplied `resourceId` as an owner.** It never is: the
61
+ session's principal (`userId`, or `orgId` under `sessionScope: 'org'`) is
62
+ prefixed onto it, so a client sub-partitions inside its own boundary and cannot
63
+ read across one. A sessionless run gets an ephemeral anonymous owner.
64
+ - **Do not rely on the tool menu alone for authorization.** It is two-layer — the
65
+ session decides which tools an agent can see, and the function's own
66
+ `permissions` still guard the call when the model picks one.
67
+ - **Do not point the `'*'` provider at a single vendor.** It resolves every
68
+ provider name with no exact entry, so aimed at one vendor an `anthropic/…`
69
+ string silently reaches OpenAI. Point it at a gateway or a scripted test
70
+ provider — something that genuinely accepts arbitrary model names.
71
+ - **Do not add `@pikku/ai-voice` as a dependency.** It still publishes but its
72
+ entire source is `export {}`. Voice is two middlewares in `@pikku/core/agent`,
73
+ with the speech models reached through the `agentRunner`.