Quickstart
Build and ship an app: declare a schema, deploy it with the CLI, and talk to it with the TypeScript SDK. Nothing else — no servers, no billing code, no secrets, and no waiting list: anyone can create and deploy apps.
1. Sign in with the CLI#
bunx tallpond login
This opens a browser approval page (sign in to your tallpond account if you aren't
already — new accounts get a welcome credit). Confirm the code shown in your terminal
and the CLI saves a developer token to ~/.config/tallpond/credentials.json.
2. Create your app#
bunx tallpond apps create "My App"
One command registers everything an app needs:
- an OAuth client id — what your frontend passes to the SDK,
- a hosted subdomain —
https://my-app.tallpond.app, - an isolated Postgres deployment for your schema,
- a
tallpond.jsonin the current directory tying this repo to the app (commit it — it holds no secrets).
3. Declare your app's schema#
An app's entire backend is one file, .tallpond.schema.ts — tables, resource types, and
default-deny access rules. This is the demo chat app's real schema, trimmed:
import { defineSchema } from "@tallpond/schema";
export default defineSchema({
tables: {
// Top-level tables are creator-owned: each row lives in its
// author's namespace and can be published into resources.
messages: (table) => {
table.text("body").notNull();
table.timestamps();
table.index(["createdAt"]);
},
},
resources: {
// A "room" anyone can discover and join.
room: (room) => {
room.visibility("discoverable");
room.defaultRole("writer");
// Messages are shared into rooms: authors keep ownership,
// admins can unlink (moderate) without deleting the author's copy.
room.shares("messages", (m) => {
m.onMemberRemove("remove");
m.onOwnerDelete("tombstone");
m.access({
read: "reader",
create: "writer",
update: "creator",
delete: "creator",
unlink: "admin",
});
});
},
},
});
Access is default-deny — a verb you don't grant is denied. See Schema & deploy for the full DSL.
4. Deploy#
bunx tallpond deploy
One command does both halves:
- Schema — compiled locally and applied to your deployment. Safe changes (new tables/columns) apply automatically on redeploy; destructive ones are blocked until you write an explicit migration.
- Frontend — if a built
./distexists, it's uploaded as an immutable version and the live pointer flips atomically. Your app is now serving athttps://my-app.tallpond.app.
Optionally generate row types for end-to-end type safety:
bunx tallpond typegen # → tallpond-env.d.ts
5. Talk to it from your app#
import { createClient } from "@tallpond/sdk";
// Zero config on the platform: the serving domain identifies your app, and
// the gateway injects { gatewayUrl, clientId } into the page at serve time.
// (During local dev, pass them explicitly: createClient({ gatewayUrl, clientId }).)
const tallpond = createClient();
// Sign in (OAuth + PKCE; tokens stay in httpOnly cookies).
await tallpond.auth.signIn();
// Private data — scoped to the signed-in user, paid by them.
await tallpond.table("notes").insert({ title: "Hello" });
// Shared data — create a room, post into it.
const room = await tallpond.resource.create("room", { name: "General" });
await tallpond.resource(room.id).table("messages").insert({ body: "hi!" });
// Read across every room you're a member of, as one query.
const latest = await tallpond
.resources({ type: "room" })
.table("messages")
.orderBy("createdAt", "desc")
.limit(50);
// AI — no key in your app; the caller pays their own tokens.
const res = await tallpond.ai.chat({
model: "openai/gpt-4o",
messages: [{ role: "user", content: "Hello" }],
});
Every call above is authenticated, access-checked, and metered by the gateway. If the
user's balance can't cover an operation, it fails with 402 before any spend.
What you didn't write#
No auth pages, no session handling, no billing integration, no API keys, no row-level security bugs, no servers, no hosting config. The user's dashboard — balance, itemized spend, exports, per-app spend caps — exists already and is the same for every app.
Running the platform locally (optional)#
The whole platform is one repo; you can run your own gateway with Bun and a local Postgres:
git clone https://github.com/CarsonJoe/tallpond.git
cd tallpond && bun install
cp packages/gateway/.env.example packages/gateway/.env # Postgres + Ory config
bun run db:migrate
bun run dev:gateway # gateway on http://localhost:3000
Point the CLI and SDK at it with --gateway-url http://localhost:3000 /
gatewayUrl: "http://localhost:3000".
Next steps#
- CLI — login, app registration, deploys, and the underlying HTTP surface.
- Database — scopes, ownership models, filters, pagination.
- Resources & membership — invites, roles, moderation.
- TypeScript SDK — the full client surface.
- A complete worked example lives in the repo:
apps/demo-chat.