.claude/skills/pikku-ai-agent/SKILL.md
Use when building AI agents, chatbots, or LLM-powered assistants with Pikku. Covers pikkuAIAgent, tool registration, memory, streaming, and agent invocation. TRIGGER when: code uses pikkuAIAgent/runAIAgent/streamAIAgent, user asks about AI agents, chatbots, LLM assistants, tool-calling agents, or agent memory/streaming. DO NOT TRIGGER when: user asks about MCP tool exposure (use pikku-mcp) or general function definitions (use pikku-concepts).
npx skillsauth add pikkujs/pikku pikku-ai-agentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Build AI agents that use Pikku functions as tools. Agents support conversation memory, streaming, and multi-step tool execution.
pikku info functions --verbose # See existing functions that can be used as agent tools
pikku info tags --verbose # Understand project organization
See pikku-concepts for the core mental model.
pikkuAIAgent(config)import { pikkuAIAgent } from '#pikku'
pikkuAIAgent({
name: string, // Unique agent identifier
description: string, // What the agent does
instructions: string | string[], // System prompt / behavior instructions
model: string, // LLM model (e.g. 'openai/gpt-4o-mini')
tools?: PikkuFunc[], // Pikku functions the agent can call
agents?: AIAgentConfig[], // Sub-agents this agent can delegate to
memory?: {
storage?: string, // Service name for persistence (e.g. 'aiStorage')
vector?: string, // Vector store service name
embedder?: string, // Embedding service name
lastMessages?: number, // How many messages to retain in context
workingMemory?: ZodSchema, // Schema for structured working memory
},
maxSteps?: number, // Max tool-call rounds per invocation
temperature?: number, // LLM temperature (0-1)
toolChoice?: 'auto' | 'required' | 'none',
input?: ZodSchema, // Input validation schema
output?: ZodSchema, // Output validation schema
tags?: string[], // For grouping and middleware targeting
aiMiddleware?: PikkuAIMiddlewareHooks[], // AI-specific middleware
middleware?: PikkuMiddleware[],
permissions?: PermissionGroup,
})
runAIAgent(name, input, options) — Non-streamingconst result = await runAIAgent(
agentName,
{
message: string, // User message
threadId: string, // Conversation thread ID
resourceId: string, // User/resource identifier
},
{ singletonServices }
)
result.text // Agent's text response
result.steps // Array of tool calls made
result.usage // Token usage { inputTokens, outputTokens }
streamAIAgent(name, input, channel, options) — Streamingawait streamAIAgent(
agentName,
{
message: string,
threadId: string,
resourceId: string,
},
channel,
{ singletonServices }
)
// Channel receives events:
// { type: 'step-start', stepNumber: 1 }
// { type: 'text-delta', text: '...' }
// { type: 'reasoning-delta', text: '...' }
// { type: 'tool-call', toolCallId, toolName, args }
// { type: 'tool-result', toolCallId, toolName, result }
// { type: 'agent-call', agentName, session, input }
// { type: 'agent-result', agentName, session, result }
// { type: 'approval-request', toolCallId, toolName, args, reason? }
// { type: 'usage', tokens: { input, output }, model }
// { type: 'error', message }
// { type: 'done' }
const todoAssistant = pikkuAIAgent({
name: 'todo-assistant',
description: 'A helpful assistant that manages todos',
instructions:
'You help users manage their todo lists. Be concise and helpful.',
model: 'openai/gpt-4o-mini',
tools: [listTodos, createTodo, completeTodo],
memory: {
storage: 'aiStorage',
lastMessages: 20,
},
maxSteps: 5,
temperature: 0.7,
})
const result = await runAIAgent(
'todo-assistant',
{
message: 'Create a task for tomorrow: buy groceries',
threadId: 'thread-123',
resourceId: 'user-456',
},
{ singletonServices }
)
console.log(result.text) // "I've created a task 'buy groceries' for tomorrow."
console.log(result.steps) // [{ tool: 'createTodo', args: {...}, result: {...} }]
console.log(result.usage) // { inputTokens: 150, outputTokens: 42 }
await streamAIAgent(
'todo-assistant',
{
message: 'Create a task for tomorrow',
threadId: 'thread-123',
resourceId: 'user-456',
},
channel,
{ singletonServices }
)
// functions/todos.functions.ts
export const listTodos = pikkuSessionlessFunc({
description: 'List all todo items',
func: async ({ db }, { status }) => {
return { todos: await db.listTodos(status) }
},
})
export const createTodo = pikkuFunc({
description: 'Create a new todo item',
func: async ({ db }, { text, priority, dueDate }) => {
return await db.createTodo({ text, priority, dueDate })
},
})
export const completeTodo = pikkuFunc({
description: 'Mark a todo as complete',
func: async ({ db }, { todoId }) => {
return await db.completeTodo(todoId)
},
})
// agents/todo-assistant.ts
const todoAssistant = pikkuAIAgent({
name: 'todo-assistant',
description: 'A helpful assistant that manages todos',
instructions: `You help users manage their todo lists.
- Be concise and helpful
- When creating todos, infer priority if not specified
- When listing todos, summarize the results`,
model: 'openai/gpt-4o-mini',
tools: [listTodos, createTodo, completeTodo],
memory: {
storage: 'aiStorage',
lastMessages: 20,
},
maxSteps: 5,
temperature: 0.7,
})
// Wire to HTTP for chat endpoint
wireHTTP({
method: 'post',
route: '/chat',
func: pikkuFunc({
title: 'Chat',
func: async (services, { message, threadId }, wire) => {
const session = await wire.session.get()
return await runAIAgent(
'todo-assistant',
{
message,
threadId,
resourceId: session.userId,
},
{ singletonServices: services }
)
},
}),
})
documentation
Deprecated — use pikku-middleware instead. Tag middleware (addTagMiddleware) is now documented as a section within the pikku-middleware skill, alongside global HTTP middleware, execution order, and the service-to-service bearer auth pattern.
testing
Use when adding authorization checks to Pikku functions or routes — pikkuPermission, pikkuAuth, per-function permissions, pattern-based permissions, or understanding OR/AND permission logic. TRIGGER when: user wants to restrict who can call a function, check resource ownership, add role-based access, or understand where permission checks belong. DO NOT TRIGGER when: user asks about middleware or request interception (use pikku-middleware), authentication strategies (use pikku-security), or session management.
testing
Use when adding any middleware to a Pikku app — global HTTP middleware, tag-scoped middleware (including service-to-service bearer auth), per-route middleware, session-setting middleware, or understanding middleware execution order and priority. TRIGGER when: user wants middleware on some or all routes, machine-to-machine auth, tag-scoped cross-cutting concerns, global interceptors, or middleware priority/order questions. DO NOT TRIGGER when: user asks about permissions/authorization checks (use pikku-permissions), auth strategies like authBearer/authCookie (use pikku-security), or deployment.
documentation
Standard cleanup to run right after a Pikku template is cloned or scaffolded into a new project. TRIGGER when: a Pikku template was just cloned/scaffolded (via `pikku create`, `git clone <template>`, or the user says "I cloned the kanban template / starter / template"), or the working tree still looks like an untouched template (template README, placeholder `@project/*` name in package.json). DO NOT TRIGGER when: working in an established project mid-feature, or editing the template repo itself.