The reference app · every kit, wired

The whole stack, wired into one app

One app you can read and run: identity-kit issues the user, tenant-kit scopes every row, billing-kit meters and bills the usage, and ai-member answers questions about it — all over the same SqlExecutor. The keystone is the stone that locks the arch: proof the four compose.

Get started$ npx degit quxkit/keystone
Reference app
keystone crystal
0
kits composed into one app — identity, tenancy, billing, memory
1
SqlExecutor and one pool shared by every layer
0
lines of glue you write to make them agree on a user or a tenant
0 min
from clone to a running, fully-wired stack on localhost
What it is

One library, whole — not a platform you rent

Identity issues the user

A signup on identity-kit mints the opaque UserId. Every other layer keys on it — no second notion of who someone is.

Tenancy scopes the row

tenant-kit resolves the request to a tenant and binds the scoped executor, so every query the demo runs is already isolated by RLS.

Billing meters the event

Each action the demo takes is metered idempotently and priced to exact Money; the double-entry ledger and the invoice update live.

Memory answers about it

ai-member reads the same state and answers plain questions — “what does this tenant owe?” — grounded in the ledger it can see.

One SqlExecutor

The whole app runs on a single executor and pool. The kits compose because they share the seam, not because glue code forces them to.

Readable end to end

It is a demo, not a black box: open any file and follow a request from sign-in through the bill it produces.

By the shape of it

Four libraries, one seam. The demo is the proof that they compose instead of colliding.

4 → 1
25% identity-kit
25% tenant-kit
25% billing-kit
25% ai-member

Four kits, one SqlExecutor. The keystone locks the arch — they compose, not collide.

How it works

Three moves, in order

01
Sign in

identity-kit verifies the credential and issues a revocable session bound to the opaque UserId.

02
Enter a workspace

tenant-kit checks membership and scopes the transaction — from here every row belongs to one tenant.

03
Meter & bill

billing-kit meters each event idempotently, prices it to exact Money, posts the balanced ledger entry and updates the invoice.

04
Ask the member

ai-member answers questions about the running state — the total, the isolation, the idempotency — from the same data.

keystone.ts
import { login } from 'identity-kit';
import { resolve, protect } from 'tenant-kit';
import { meter, price, post, accrual } from 'billing-kit';
import { ground } from 'ai-member';

// one signed-in user, one tenant, one executor — the whole arch
const session = await login(sql, { email, password, pepper });
const tenant  = await resolve(sql, { host, user: session.userId });

await protect(sql, tenant, async (db) => {
  await meter(db, { subject: session.userId, event: 'api.call', quantity: 1n, key });
  await post(db, accrual(price(usage, plan), { debit: 'ar', credit: 'revenue' }));
});

const answer = await ground('what does this tenant owe?', { ledger });

Four libraries, one seam. The demo is the proof that they compose instead of colliding.

keystone

Embed it in the app you already run