Build Full-Stack & Native Mobile Apps at Agent Speed
Pand is an end-to-end application platform engineered for both human developers and autonomous AI agents. Define an entity once—Pand generates your PostgreSQL schema, OpenAPI 3.1 microservice routes, gateway wiring, typed TypeScript/Swift/Kotlin SDKs, Next.js pages, SwiftUI screens, and Jetpack Compose views.
Single Source of Truth
Drizzle PostgreSQL tables → Zod schemas → OpenAPI 3.1 → TS, Swift & Kotlin SDKs with zero manual glue.
Deterministic Architecture
FNV-1a port hashing, per-service PG schemas, and HS256 gateway identity JWTs prevent integration drift.
13 Built-In MCP Tools
First-class Model Context Protocol server with destructive-operation guardrails and structured JSON outputs.
Single-Box Production
Deploy to any Ubuntu VPS with Caddy auto-TLS, Restic S3 backups, Prometheus, Loki, Tempo & Grafana.
⚡ 60-Second Quickstart
Install the workspace or run the pand CLI directly to scaffold a complete multi-service, multi-platform application:
# 1. Create a new Pand project with Web, Admin, iOS, and Android apps
pand new acme-cloud --web --admin --ios --android
cd acme-cloud
# 2. Add a microservice (automatically assigned deterministic port)
pand add service billing
# 3. Add a full-stack entity across DB, Service, SDK, Web, iOS, and Android
pand add entity subscription \
--service billing \
--fields "organizationId:uuid,plan:enum(free|pro|enterprise)=free,seats:int=1,active:boolean=true,renewsAt:datetime?" \
--web --ios --android
# 4. Generate and apply SQL migrations (isolated in the "billing" PG schema)
pand db generate
pand db migrate
# 5. Generate TypeScript, Swift, and Kotlin SDKs from merged OpenAPI specs
pand sdk gen
# 6. Run the 5-stage verification pipeline
pand check
# 7. Start local dev stack (Postgres, Redis, MinIO, Services, Gateway, Web)
pand dev
--json)
Every CLI command accepts --json and returns a deterministic JSON payload with status, filesCreated, migrationsApplied, or structured error diagnostics.
🌟 Official Demo Application — Todo Pand
Explore Todo Pand (todo-pand), a full-stack, multi-tenant task and project management workspace built from scratch on the Pand platform.
Full-Stack Contract Wiring
Drizzle PostgreSQL schemas, OpenAPI 3.1 microservice routes, and auto-generated TypeScript SDK clients with zero drift.
Multi-Tenant Row-Level Scoping
Every project and task is strictly isolated by ownerId via gateway-injected internal identity JWTs (c.get("actor")!.sub).
Guest Workspace & Sync
Seamless transition from anonymous browser localStorage to authenticated database accounts via POST /todos/import-guest.
Dynamic Admin Console
Reactive entity CRUD and Better Auth administrative user management powered by @pands/admin-ui.
Clone, inspect, and run the complete demo app on GitHub: github.com/MehdiNosrati/todo-pand →
🏗️ Architecture & Core Invariants
Pand enforces five strict architectural contracts across all generated services and packages so neither humans nor AI agents can introduce configuration drift.
1. Deterministic Port Allocation
Services never hardcode port numbers. Every service name is hashed using 32-bit FNV-1a into one of 50 collision-checked slots in 4000..8900:
// Port formula in @pands/config:
// slot = fnv1a32(serviceName) % 50
// port = 4000 + slot * 100
import { resolveServicePort, allocateServicePorts } from "@pands/config";
const corePort = resolveServicePort("core"); // e.g. 6300
const billingPort = resolveServicePort("billing"); // e.g. 4700
// Fixed platform ports:
// Gateway: 3000 | Web: 3001 | Admin: 3002 | Postgres: 5432 | Redis: 6379
2. Gateway Routing & Internal Identity JWT
Clients only talk to @pands/gateway on port 3000. The gateway authenticates cookies, bearer tokens, or API keys, enforces sliding-window rate limits, and forwards requests to /api/v1/<service>/* with a short-lived (60s TTL) HS256-signed x-pand-identity JWT:
// Decoded x-pand-identity JWT payload verified by @pands/service:
interface PandIdentityPayload {
sub: string; // Authenticated user ID
orgId?: string; // Active organization / tenant ID
roles: string[]; // Assigned RBAC roles
scopes: string[]; // Granted API key or OAuth scopes
iat: number;
exp: number; // iat + 60 seconds
}
3. Per-Service PostgreSQL Schema Isolation
All microservices share a single PostgreSQL cluster in development and single-box production, but each service is strictly isolated inside its own PostgreSQL schema (pgSchema(serviceName)) and tracks migrations in __drizzle_migrations_<service>. Cross-schema SQL joins are forbidden by convention and linted via pand check.
4. Standard Error Envelope
All services and the gateway return errors in a single canonical format:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request payload",
"details": { "fieldErrors": { "email": ["Invalid email"] } },
"requestId": "req_01J9Z8K2M4X8P"
}
}
🧬 Field DSL Reference
When running pand add entity <name> --fields "..." or invoking the MCP pand_add_entity tool, Pand parses a concise field DSL and generates Drizzle columns, Zod validators, OpenAPI schemas, and native UI inputs.
# Syntax: name:type[?][!][=default]
# ? = nullable / optional
# ! = unique constraint
# =val = default value
--fields "sku:string!,title:string,priceCents:int=0,status:enum(draft|active|archived)=draft,metadata:json?,publishedAt:datetime?"
| DSL Type | Drizzle Column (Postgres) | Zod Schema | TypeScript | Swift (iOS) | Kotlin (Android) |
|---|---|---|---|---|---|
string |
varchar({ length: 255 }) |
z.string() |
string |
String |
String |
text |
text() |
z.string() |
string |
String |
String |
int |
integer() |
z.number().int() |
number |
Int |
Int |
float |
doublePrecision() |
z.number() |
number |
Double |
Double |
boolean |
boolean() |
z.boolean() |
boolean |
Bool |
Boolean |
datetime |
timestamp({ withTimezone: true }) |
z.string().datetime() |
string |
String |
String |
uuid |
uuid() |
z.string().uuid() |
string |
String |
String |
json |
jsonb() |
z.record(z.unknown()) |
Record<string, unknown> |
[String: AnyCodable] |
Map<String, Any?> |
enum(a|b|c) |
varchar({ length: 64 }) |
z.enum(["a", "b", "c"]) |
"a" | "b" | "c" |
enum { case a, b, c } |
enum class { A, B, C } |
Every table automatically includes standardColumns(): id (UUIDv4 primary key), createdAt, and updatedAt.
⌨️ CLI Reference — Scaffolding, DB & SDK
The @pands/cli binary (pand) orchestrates the full lifecycle of a Pand workspace. Pass --json to any command for structured JSON output.
| Command | Flags | Description |
|---|---|---|
pand new <name> |
--web --admin --ios --android --box |
Scaffolds a complete Pand monorepo with pand.config.ts, services/core, packages/sdk, AGENTS.md, and .agents/skills/*. |
pand add service <name> |
--json |
Creates services/<name> with its own PG schema, health/OpenAPI endpoints, Vitest suite, and registers it in pand.config.ts. |
pand add entity <name> |
--service <svc> --fields <dsl> --web --ios --android |
Generates Drizzle schema, CRUD routes, integration tests, and optional Next.js, SwiftUI, and Jetpack Compose screens. |
Database, SDK & Verification Commands
| Command | Flags | Description |
|---|---|---|
pand db generate |
--service <svc> |
Generates idempotent SQL migrations (CREATE SCHEMA IF NOT EXISTS / CREATE TABLE IF NOT EXISTS) per service. |
pand db migrate |
--service <svc> |
Applies pending migrations for each service using its isolated __drizzle_migrations_<svc> table. |
pand db seed |
--service <svc> |
Runs src/db/seed.ts for one or all services. |
pand db reset |
--force |
Drops service schemas and re-runs migrations + seeds (blocked in production). |
pand db studio |
--service <svc> |
Launches Drizzle Studio for inspecting service tables. |
pand sdk gen |
--ts-only --ios --android |
Extracts OpenAPI 3.1 specs from all services, merges them, and compiles TS, Swift, and Kotlin SDKs. |
pand check |
--json |
Runs the 5-stage verification gate: TypeScript typecheck, Biome lint, OpenAPI spec validation, SDK drift check, and Vitest test suite. |
pand dev |
--no-docker |
Starts Docker dev infra (Postgres, Redis, MinIO), runs migrations, watches services for SDK hot-reload, and boots the gateway. |
Box, Secrets, Deployment, Preview & Observability Commands
| Command | Flags | Description |
|---|---|---|
pand secret set <KEY=VAL> |
--env <dev|prod> |
Encrypts secrets with AES-256-GCM in .pand/secrets.<env>.enc using master key in ~/.pand/master.key. Also supports list and rm. |
pand box init |
--host <ip> --user <u> --domain <d> |
Registers a single-box Ubuntu VPS in ~/.pand/boxes.json and generates infra/box Docker Compose + Caddyfile. Also supports list and status. |
pand deploy |
--env prod --dry-run |
Runs pand check, builds container images, syncs encrypted secrets, runs DB migrations, and performs zero-downtime rollout. |
pand pause / resume |
--box <name> |
Stops or restarts application containers on the target Box while preserving persistent volumes. |
pand backup create |
--output <dir> |
Runs pg_dump + Restic snapshot to S3/R2/local storage. Also supports pand backup list and pand backup restore <id>. |
pand preview create <branch> |
--ttl 24h |
Creates an isolated PostgreSQL database clone and ephemeral preview deployment at https://<branch>.preview.<domain>. Also supports list and destroy. |
pand logs / metrics / traces / usage |
--service <svc> --since 1h |
Queries Loki structured logs, Prometheus golden-signal metrics (RPS, P95, error rate), Tempo distributed traces, and container/disk usage. |
pand upgrade |
--target <ver> |
Upgrades all @pands/* dependencies and runs AST/config codemods. |
📦 Core Packages API Reference
@pands/config
Configuration & Port Hashing
Defines and validates pand.config.ts and computes deterministic FNV-1a service ports.
import { defineConfig, loadPandConfig, resolveServicePort, allocateServicePorts } from "@pands/config";
export default defineConfig({
name: "acme-cloud",
pandVersion: "0.1.1",
services: {
core: { path: "services/core" },
billing: { path: "services/billing" },
},
apps: {
web: { path: "apps/web", framework: "nextjs" },
admin: { path: "apps/admin", framework: "nextjs" },
ios: { path: "ios", bundleId: "com.acme.cloud" },
android: { path: "android", packageName: "com.acme.cloud" },
},
gateway: {
port: 3000,
corsOrigins: ["http://localhost:3001", "http://localhost:3002"],
rateLimit: { windowMs: 60_000, max: 120 },
},
});
@pands/service
Microservice Runtime & Auto-CRUD
Wraps @hono/zod-openapi with correlation IDs, structured request logging, Prometheus metrics, HS256 gateway identity verification, and one-line Drizzle CRUD route generation.
import { createService, defineEntity, registerCrudRoutes } from "@pands/service";
import { createServiceDb, standardColumns } from "@pands/db";
import { z } from "zod";
const { db, schema } = createServiceDb("billing");
export const invoices = schema.table("invoices", {
...standardColumns(),
customerId: schema.uuid("customer_id").notNull(),
amountCents: schema.integer("amount_cents").notNull(),
status: schema.varchar("status", { length: 32 }).notNull().default("draft"),
});
export const invoiceEntity = defineEntity({
name: "invoice",
plural: "invoices",
table: invoices,
createSchema: z.object({
customerId: z.string().uuid(),
amountCents: z.number().int().nonnegative(),
status: z.enum(["draft", "open", "paid", "void"]).default("draft"),
}),
});
export const service = createService({
name: "billing",
version: "0.1.1",
db,
entities: [invoiceEntity],
});
// Registers GET /, POST /, GET /:id, PATCH /:id, DELETE /:id with cursor pagination & OpenAPI 3.1 metadata
registerCrudRoutes(service.app, invoiceEntity, db);
Every service automatically exposes GET /health, GET /ready, GET /metrics, GET /openapi.json, and GET /_meta.
@pands/gateway
Edge Reverse Proxy & Identity Signer
Routes /api/v1/<service>/* to downstream services, merges service OpenAPI specs at GET /api/v1/openapi.json, exposes entity metadata at GET /api/v1/_meta, and streams real-time Server-Sent Events at GET /api/v1/events/stream.
import { createGateway, signInternalIdentity, verifyInternalIdentity } from "@pands/gateway";
const gateway = createGateway({
services: {
core: { url: "http://localhost:6300" },
billing: { url: "http://localhost:4700" },
},
internalSecret: process.env.PAND_INTERNAL_SECRET!,
corsOrigins: ["http://localhost:3001"],
rateLimit: { windowMs: 60_000, max: 200 },
resolveSession: async (req) => auth.verifyRequest(req),
});
@pands/db
Per-Service Drizzle ORM & Multi-Tenancy
Provides per-service PostgreSQL schema builders, UUIDv4 + timestamp standard columns, cursor pagination helpers, and organization-scoped query wrappers.
import { createServiceDb, standardColumns, scopeToOrg, decodeCursor, encodeCursor } from "@pands/db";
const { db, pgSchema, close } = createServiceDb("core", process.env.DATABASE_URL);
// Multi-tenant row scoping helper:
const tenantFilter = scopeToOrg(projects.organizationId, ctx.var.identity?.orgId);
const rows = await db.select().from(projects).where(tenantFilter);
@pands/auth
Sessions, JWT, OAuth, API Keys & RBAC
Full authentication and authorization suite for Web (HttpOnly cookies) and Native Mobile (Bearer access + refresh tokens), with built-in PBKDF2 password hashing, OAuth state/code exchange, API key management, and role/permission guards.
import { createPandAuth, createAuthClient } from "@pands/auth";
// Server setup (mounts /register, /login, /logout, /refresh, /me, /api-keys)
export const auth = createPandAuth({
secret: process.env.PAND_AUTH_SECRET!,
accessTokenTtlSeconds: 900,
refreshTokenTtlSeconds: 60 * 60 * 24 * 30,
});
// Universal client for Web & React Native / Mobile
const authClient = createAuthClient({ baseUrl: "http://localhost:3000/api/v1/auth" });
const session = await authClient.login({ email: "dev@acme.io", password: "correct-horse-battery" });
@pands/sdk-gen
OpenAPI 3.1 → TS, Swift & Kotlin Compiler
Merges per-service OpenAPI 3.1 documents and generates zero-dependency, strongly-typed clients for TypeScript, Swift, and Kotlin.
import { mergeOpenApiSpecs, generateTypeScriptSdk, generateSwiftSdk, generateKotlinSdk } from "@pands/sdk-gen";
const merged = mergeOpenApiSpecs([
{ serviceName: "core", spec: coreOpenApi },
{ serviceName: "billing", spec: billingOpenApi },
]);
const tsCode = generateTypeScriptSdk(merged);
const swiftCode = generateSwiftSdk(merged);
const kotlinCode = generateKotlinSdk(merged, "com.acme.pand.sdk");
🎨 UI Primitives, Admin Console & Mobile SDKs
@pands/ui & @pands/admin-ui
React Components & Auto-Admin
@pands/ui provides accessible, zero-configuration React components (Button, Input, Select, Badge, Card, Dialog, DataTable, AutoForm, ToastProvider). @pands/admin-ui introspects GET /api/v1/_meta to render a full CRUD Admin Console automatically.
import { DataTable, AutoForm, Button } from "@pands/ui";
import { AdminDashboard } from "@pands/admin-ui";
// Render an entire multi-service Admin Console with search, pagination, and Zod-backed create/edit modals:
export default function AdminPage() {
return <AdminDashboard gatewayUrl="http://localhost:3000" />;
}
Native iOS (SwiftUI) & Android (Jetpack Compose)
Mobile SDKs & ScaffoldingWhen you run pand add entity task --service core --fields "title:string,done:boolean=false" --ios --android, Pand generates:
- iOS (Swift 5.9 / SwiftUI):
ios/Sources/PandSDK/PandSDK.swiftwithURLSessionasync/await methods,KeychainTokenStorewith automatic401token refresh retry, and a complete SwiftUI List + Create Sheet View and@MainActor ObservableObjectViewModel. - Android (Kotlin / Jetpack Compose):
android/pand-sdk/src/main/kotlin/.../PandSDK.ktwith Kotlin Coroutines,SharedPreferencesTokenStore, automatic401refresh retry, and a Material 3 Compose screen +StateFlowViewModel.
// Swift (iOS) generated usage:
let client = PandClient(
baseURL: URL(string: "https://api.acme.io")!,
tokenStore: KeychainTokenStore(service: "com.acme.app")
)
let tasks = try await client.coreListTasks(limit: 25)
let created = try await client.coreCreateTask(input: CreateTaskInput(title: "Ship v1", done: false))
⚙️ Platform Services — Events, Storage, Push, Analytics & Testing
@pands/events
BullMQ Event Bus & Cron Jobs
Typed domain events and background jobs backed by Redis + BullMQ in production and an instant in-memory bus in tests.
import { defineEvent, createEventBus } from "@pands/events";
import { z } from "zod";
export const InvoicePaid = defineEvent("billing.invoice.paid", z.object({
invoiceId: z.string().uuid(),
amountCents: z.number().int(),
}));
const bus = createEventBus({ driver: "memory" }); // or { driver: "bullmq", redisUrl: process.env.REDIS_URL }
bus.subscribe(InvoicePaid, async (payload) => {
console.log("Invoice paid:", payload.invoiceId);
});
await bus.publish(InvoicePaid, { invoiceId: "550e8400-e29b-41d4-a716-446655440000", amountCents: 4900 });
@pands/storage
S3 / MinIO / Cloudflare R2 Object Storage
import { createStorageClient } from "@pands/storage";
const storage = createStorageClient({
driver: "s3", // or "memory" for unit tests
endpoint: process.env.S3_ENDPOINT,
bucket: "acme-uploads",
region: "auto",
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
});
await storage.putObject("avatars/u1.png", imageBuffer, "image/png");
const uploadUrl = await storage.presignUpload("avatars/u2.png", { expiresInSeconds: 300 });
@pands/push & @pands/analytics
Mobile Push & Product Telemetry
import { createPushClient } from "@pands/push";
import { createAnalyticsClient } from "@pands/analytics";
const push = createPushClient({ driver: "expo", accessToken: process.env.EXPO_ACCESS_TOKEN });
await push.send({
to: "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
title: "Deployment Complete",
body: "acme-cloud v0.1.1 is live.",
});
const analytics = createAnalyticsClient({ endpoint: "/api/v1/analytics/events", batchSize: 10 });
analytics.track("invoice_created", { amountCents: 9900 });
await analytics.flush();
@pands/logger, @pands/telemetry & @pands/testing
Observability & Integration Testing
import { createLogger } from "@pands/logger";
import { createMetricsRegistry } from "@pands/telemetry";
import { createTestContext, testService } from "@pands/testing";
const logger = createLogger({ service: "billing" });
logger.info({ invoiceId: "inv_123", apiKey: "secret" }, "Processed invoice"); // apiKey automatically "[REDACTED]"
// In Vitest integration tests:
const client = testService(service);
const res = await client.request("/invoices", {
method: "POST",
body: { customerId: "550e8400-e29b-41d4-a716-446655440000", amountCents: 2500 },
identity: { sub: "user_1", roles: ["admin"], scopes: ["*"] },
});
🤖 Agent Layer & Model Context Protocol (@pands/mcp)
Pand includes a native MCP server (@pands/mcp) over stdio or in-process calls, giving AI coding agents 13 structured tools with built-in safety guardrails (blocking destructive database resets in production and enforcing secret redaction).
| MCP Tool Name | Description |
|---|---|
pand_project_info |
Returns parsed pand.config.ts, allocated service ports, apps, and workspace topology. |
pand_list_entities |
Lists all entities across all services along with their fields and API endpoints. |
pand_add_service |
Scaffolds a new microservice and registers it in pand.config.ts. |
pand_add_entity |
Scaffolds a full-stack entity across Drizzle, Hono OpenAPI, Web, iOS, and Android. |
pand_db_generate |
Generates Drizzle SQL migrations for all or selected services. |
pand_db_migrate |
Applies pending PostgreSQL migrations safely. |
pand_sdk_gen |
Regenerates TypeScript, Swift, and Kotlin SDKs from live/static OpenAPI specs. |
pand_check |
Runs the 5-stage verification suite and returns structured pass/fail diagnostics. |
pand_logs |
Queries recent structured JSON logs filtered by service, level, or correlation ID. |
pand_metrics |
Returns RPS, error rate, and latency percentiles per service. |
pand_traces |
Fetches OpenTelemetry distributed traces across Gateway → Service → Postgres. |
pand_deploy_status |
Inspects active Box deployments, container health, and preview environments. |
pand_secret_list |
Lists configured secret keys (values are strictly redacted from agent context). |
Built-In Agent Skills (skills/ & .agents/skills/)
Pand includes 6 agent skills in the repository root (skills/ and .agents/skills/) and automatically scaffolds them into every project created with pand new:
| Skill | Path | Description |
|---|---|---|
pand |
skills/pand/SKILL.md |
Master platform skill covering the CLI, Field DSL, all @pands/* packages, multi-tenancy, and Box deployment. |
add-feature |
skills/add-feature/SKILL.md |
End-to-end runbook for scaffolding a full-stack feature across DB, API, SDK, Web, iOS, and Android. |
add-endpoint |
skills/add-endpoint/SKILL.md |
How to author custom non-CRUD OpenAPI routes with @hono/zod-openapi and integration tests. |
modify-schema |
skills/modify-schema/SKILL.md |
How to safely alter Drizzle tables, generate SQL migrations, and verify zero contract drift. |
add-mobile-screen |
skills/add-mobile-screen/SKILL.md |
How to build or customize SwiftUI (iOS) and Jetpack Compose (Android) screens using PandSDK. |
debug-production |
skills/debug-production/SKILL.md |
How to triage production errors via Loki logs, Tempo traces, Prometheus RED metrics, and read-only SQL. |
🖥️ Single-Box Production Infrastructure & Monitoring
infra/box packages an entire production cloud onto a single Ubuntu VPS with automatic HTTPS via Caddy, daily encrypted Restic backups, and a pre-wired Grafana observability stack:
- Caddy Reverse Proxy: Automatic Let's Encrypt TLS certificates for your primary domain and wildcard
*.preview.<domain>branches. - Observability Stack: Prometheus (metrics scraping), Loki (log aggregation), Tempo (OTLP trace collector), Grafana (pre-provisioned golden-signal dashboards), and
ntfypush notifications for high error rate or disk pressure alerts. - Automated Backups:
pand backup createsnapshots PostgreSQL and MinIO volumes via Restic with configurable retention policies (7 daily, 4 weekly, 6 monthly).