How It Works
Three steps. Bulletproof contracts.
Every function's API surface is tracked, versioned, and enforced automatically.
Hash
Function name + input schema + output schema are hashed into a deterministic 16-character hex contract hash.
Track
Hashes are stored in a versions.json manifest, committed to Git alongside your code. Every version has its own hash.
Guard
The CLI compares current contracts against the manifest on every build. Changed contract without a version bump? Build fails.
{
"manifestVersion": 1,
"contracts": {
"createTodo": {
"latest": 1,
"versions": {
"1": "a1b2c3d4e5f6g7h8"
}
},
"getTodos": {
"latest": 2,
"versions": {
"1": "i9j0k1l2m3n4o5p6",
"2": "q7r8s9t0u1v2w3x4"
}
}
}
}
CI Integration
One line in CI. Zero accidental breaking changes.
Add pikku versions-check to your pipeline. Breaking changes fail the build with an actionable fix — before they reach production.
$ npx pikku versions-check ✗ getBook — contract changed without version bump Input schema hash: a1b2c3d4 → f9e8d7c6 Output schema hash: i9j0k1l2 → z5y4x3w2 Run: npx pikku versions-update after bumping to version 2
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx pikku versions-check
Side-by-Side Versions
v1 and v2 coexist.
Running workflows and AI agents keep working. New code gets the latest version. Both run across every wire — no migration needed.
// v1 — kept for running workflows and agents
const getBookV1 = pikkuFunc({
title: 'Get Book',
version: 1,
input: z.object({ bookId: z.string() }),
output: z.object({ title: z.string() }),
func: async ({ db }, { bookId }) => {
return await db.getBook(bookId)
}
})
// v2 — the latest version, called by default
const getBook = pikkuFunc({
title: 'Get Book',
input: z.object({
bookId: z.string(),
format: z.enum(['full', 'summary'])
}),
output: z.object({
title: z.string(),
author: z.string(),
isbn: z.string()
}),
func: async ({ db }, { bookId, format }) => {
return await db.getBook(bookId, format)
}
})
Latest by default
New workflows and agents use the newest version automatically.
Old versions stay available
Running workflows and AI agents keep calling v1 as long as you keep it.
Works across all wires
HTTP, WebSocket, queue, CLI, MCP — both versions are available everywhere.
Schema hashes in Git
Contract hashes are deterministic and diffable — every change is visible in your commit history.
Guarantees
What the system promises you.
Versioning you can trust — so you can evolve fast without worrying about what breaks.
Shipped means locked
Once a version is published, its contract can never silently change. Running workflows get exactly what they expect.
Changes are caught automatically
Modify a schema and the CLI knows immediately. No manual diffing, no guessing — it tells you exactly what changed.
Every bump is intentional
You decide when to create a new version. The system won't let you accidentally ship a breaking change — you have to mean it.
Developer Workflow
Five steps. Every time.
A repeatable workflow that makes breaking changes intentional — never accidental.
Develop
Change function inputs or outputs
Check
Detect the contract change
npx pikku versions-checkBump
Increment version in your function
version: 2Update
Record the new contract hash
npx pikku versions-updateCommit
Check in the updated manifest
git commit -am "bump getBook v2"Start versioning in 30 seconds
One command to initialize the manifest. Every function contract is tracked from that moment on.
MIT Licensed · Works with Express, Fastify, Lambda & Cloudflare