Skip to main content
Core Concept

Evolve functions.
Keep workflows running.

Pikku hashes every function's contract — name, input schema, output schema — so your workflows and AI agents keep running even as functions evolve.

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.

versions.jsonmanifest
{
"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.

CI Pipelinefailed
$ 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.ymlGitHub Actions
# .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.

getBook.func.tsversion: 1 → 2
// 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.

1

Develop

Change function inputs or outputs

2

Check

Detect the contract change

npx pikku versions-check
3

Bump

Increment version in your function

version: 2
4

Update

Record the new contract hash

npx pikku versions-update
5

Commit

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.

$ npx pikku versions-init

MIT Licensed  ·  Works with Express, Fastify, Lambda & Cloudflare