Sound Familiar?
You've written this function
more times than you'd admit.
Every time you add a protocol, you copy-paste, re-wire auth, and pray the handlers don't drift. It's not lazy engineering — it's a missing abstraction.
"So many places in my code base have like three entry points: CLI, public HTTP API and internally from within the API. Would be so nice having everything just an invoke away."— Alex Harley, Co-founder @ Superbridge
Same logic, five handlers
Your getCard function lives in your HTTP handler, your WebSocket handler, your queue worker, and your CLI. They started as copies. Now they've drifted apart.
New protocol, new framework
Want AI agents? That's Vercel AI SDK. Workflows? Inngest or Temporal. MCP? Another adapter. Each one brings its own auth layer, schema format, and deploy pipeline.
Switching runtimes means rewriting
Moving from Express to Lambda touches every handler. Your business logic is tangled with framework APIs you never wanted to think about.
The Fix
One function that doesn't drift.
Fix a bug once, it's fixed everywhere.
// HTTP
app.get('/cards/:id', auth, validate, async (req, res) => {
const card = await db.getCard(req.params.id)
res.json(card)
})
// WebSocket
ws.on('getCard', auth, validate, async (msg, socket) => {
const card = await db.getCard(msg.cardId)
socket.send(JSON.stringify(card))
})
// Queue worker — same logic, third copy
// CLI command — same logic, fourth copy
// AI agent tool — new SDK, new auth, fifth copy
// Write it once
const getCard = pikkuFunc({
func: async ({ db }, { cardId }) => db.getCard(cardId),
permissions: { user: isAuthenticated }
})
// Wire it to everything — same auth, same validation
wireHTTP({ method: 'get', route: '/cards/:cardId', func: getCard })
wireChannel({ name: 'cards', onMessage: { getCard } })
wireQueueWorker({ queue: 'fetch-card', func: getCard })
wireCLI({ program: 'cards', commands: { get: getCard } })
12 protocols total — all with the same pattern. See every wiring in action
The Mental Model
A lot of moving parts.
One coherent system.
Functions, services, auth, transports, workflows, agents, gateways, and generated metadata — all built from the same model.
Functions
Typed, testable units of business logic. No framework coupling.
Learn more about functions →import { pikkuFunc } from '#pikku'
export const getBook = pikkuFunc<{ bookId: string }, Book>({
func: async ({ database }, data) => {
return await database.query('book', { bookId: data.bookId })
},
title: 'Fetch a book by ID',
description: 'Returns a book from the database',
tags: ['books']
})
More Than a Router
AI agents and durable workflows —
built in.
tRPC stops at HTTP. Hono gives you a fast router. NestJS buries you in decorators. Pikku gives you agents and workflows using the same functions you've already written.
Your functions are already agent tools
Most frameworks need adapters, schema re-definitions, and a separate auth layer for AI agents. With Pikku, pass your existing functions directly. Types, permissions, and middleware carry over.
const support = pikkuAgent({
instructions: 'You are a support agent...',
tools: [getCustomer, getOrders, createTicket],
model: 'claude-sonnet-4-5'
})
Multi-step processes that survive restarts
No separate workflow engine. Write sequential steps like normal code. Pikku persists each step, retries on failure, and resumes exactly where it left off.
await workflow.do('Create profile', 'createProfile', { userId })
await workflow.sleep('Wait', '5min')
await workflow.do('Send welcome', 'sendEmail', { to: email })
Browse functions, run agents, manage secrets, and trigger workflows — without writing tooling code.

Change your runtime. Keep your functions.
Same code runs on Express, Fastify, AWS Lambda, Cloudflare Workers, Next.js, and more.
Plus any custom runtime via the adapter interface. Build your own →
Built For Production
Type-Safe Clients
Auto-generated HTTP, WebSocket, and RPC clients with full IntelliSense.
Auth & Permissions
Cookie, bearer, API key auth with fine-grained permissions — built in.
Services
Singleton and per-request dependency injection, type-safe and testable.
Middleware
Before/after hooks for logging, metrics, tracing — work across all protocols.
Schema Validation
Runtime validation against TypeScript input schemas. Supports Zod.
Zero Lock-In
Standard TypeScript, tiny runtime, MIT licensed. Bring your own everything.
MIT licensed. Standard TypeScript. No VC-backed lock-in.
What Developers Say
"So many places in my code base have like three entry points: CLI, public (sometimes protected) HTTP API and internally from within the API. Would be so nice having everything just an invoke away. With Nest it's a pain because you basically have to start the whole API up just to run CLI command."
Alex Harley
Co-founder @ Superbridge
"Ever been annoyed at having to write your code different in a Lambda than in an express handler? Pikku fixes that."
Christoph Sitter
CTO @ spot
Stop copying functions across protocols.
Write it once. Pikku wires it everywhere.
5-minute setup · MIT Licensed · Open Source
