CLI — build, create, deploy
The tallpond CLI is the whole developer workflow: sign in once, register an app, and
ship schema + frontend with one command. No dashboard steps, no hand-provisioned OAuth
clients, no shared secrets.
tallpond login # sign in (browser approval), saves a developer token
tallpond apps create "My App" # registers the app + its OAuth client, writes tallpond.json
tallpond deploy # applies .tallpond.schema.ts and publishes ./dist
A deployed app is served at https://<slug>.tallpond.app with the schema live
behind the gateway. That's the entire path from empty directory to production.
tallpond login#
Starts a device-flow sign-in:
- The CLI prints (and opens) an approval URL containing a short confirmation code.
- You approve in the browser using your existing tallpond session.
- The CLI receives a developer token (
osgd_…) and saves it to~/.config/tallpond/credentials.json(mode 600), keyed by gateway URL.
The code in the URL can only approve — it can never mint a token, so a leaked link doesn't compromise the login. Tokens are stored server-side only as a SHA-256 hash.
TALLPOND_DEV_TOKEN overrides the saved token (CI). tallpond logout forgets it.
tallpond whoami prints the signed-in user.
tallpond apps create <name> [--slug my-app]#
Registers an app under your account:
- provisions the app's OAuth client (PKCE public client) at the platform IdP — this is
the
client_idyour app passes to the SDK, and the identity spend caps key on; - reserves the hosted subdomain
<slug>.tallpond.app(slug derived from the name unless--slugis given: 3–30 chars, lowercase letters/digits/hyphens); - allocates the app's stable deployment (its isolated Postgres schema);
- writes
tallpond.jsoninto the current directory:
{
"appId": "…",
"slug": "my-app",
"name": "My App",
"gatewayUrl": "https://api.tallpond.com",
"url": "https://my-app.tallpond.app"
}
Commit this file — it's how tallpond deploy knows which app this repo is. It contains
no secrets. tallpond apps list shows everything you own (20 apps per account).
tallpond deploy [schemaFile] [--dir dist] [--no-bundle]#
Two steps, both idempotent, run in order:
- Schema — if
.tallpond.schema.ts(or the given file) exists, it is compiled locally and applied to the app's deployment. Safe changes apply automatically; destructive ones are blocked (409) pending an explicit migration — see Schema & deploy. - Bundle — if
./dist(or--dir) exists, every file uploads under a new immutable version, then one activate call flips the live pointer. A failed upload can never leave the site half-updated. The directory must containindex.html; files are capped at 25 MB each.
Hosting behavior: content-hashed files under assets/ are cached immutably, HTML
revalidates on every request (activations are instant), and extensionless paths fall
back to index.html for client-side routing.
Served HTML also gets the app's identity injected as window.__TALLPOND__ = { gatewayUrl, clientId }, so hosted apps call createClient() with no arguments —
there is no client id to copy into app code, and nothing in the bundle decides which
app it is (the serving domain does). On hosted origins the injected gatewayUrl is
"/_osg", so SDK traffic is same-origin and does not use credentialed CORS.
Deploys are authorized by ownership: your developer token can only deploy to apps you created. There is nothing to configure.
Platform/CI escape hatch#
The original shared-token path still exists for platform-managed deploys:
tallpond deploy --app-id <id> --deployment-id <id> --token $DEPLOY_TOKEN
If a deploy token is supplied (flag or TALLPOND_DEPLOY_TOKEN), the CLI uses the
legacy /deploy endpoint and skips the self-serve path entirely.
tallpond typegen [schemaFile] [--out tallpond-env.d.ts]#
Generates row types from the schema for end-to-end type safety. Unchanged.
HTTP surface (for tooling)#
Everything the CLI does is plain HTTP on the gateway, under /dev:
| Method & path | Auth | Purpose |
|---|---|---|
POST /dev/cli/start | none | begin device flow → { device_code, user_code, verification_url } |
GET/POST /dev/cli/approve | browser session | approval page + form |
POST /dev/cli/token | device_code | poll; 428 pending, then { token } once |
GET /dev/me | dev token | { user_id } |
GET /dev/apps / POST /dev/apps | dev token | list / create apps |
POST /dev/apps/:appId/deploy | dev token (owner) | apply a compiled SchemaIR |
PUT /dev/apps/:appId/bundle/:version/:path | dev token (owner) | upload one bundle file |
POST /dev/apps/:appId/bundle/:version/activate | dev token (owner) | flip the live version |
Dev tokens go in Authorization: Bearer osgd_…. Owner checks return 404 for apps
that aren't yours, so app existence is not leaked.