.agents/skills/portability/SKILL.md
How to keep template code database-agnostic and hosting-agnostic. Use when defining schemas, writing raw SQL, creating server routes, or anything that could leak a SQLite-only, Postgres-only, or Node-only assumption.
npx skillsauth add BuilderIO/agent-native portabilityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Never write code that only works on one database or one hosting platform. Templates must run on any SQL database (SQLite, Postgres, D1, Turso, Supabase, Neon) and any Nitro deploy target (Node, Cloudflare, Netlify, Vercel, Deno, Lambda, Bun) without code changes.
Use the dialect-agnostic schema helpers from @agent-native/core/db/schema:
import {
table,
text,
integer,
real,
now,
sql,
} from "@agent-native/core/db/schema";
export const meals = table("meals", {
id: text("id").primaryKey(),
name: text("name").notNull(),
calories: integer("calories").notNull(),
weight: real("weight"),
archived: integer("archived", { mode: "boolean" }).notNull().default(false),
createdAt: text("created_at").notNull().default(now()),
});
| Helper | Purpose |
| --------- | ----------------------------------------------------------------------------------------- |
| table | Delegates to pgTable or sqliteTable based on dialect |
| text | Works in both dialects, supports { enum: [...] } |
| integer | { mode: "boolean" } maps to Postgres boolean automatically |
| real | real on SQLite, double precision on Postgres |
| now | Dialect-agnostic current timestamp — use with .default(now()) on text timestamp columns |
| sql | Re-exported from drizzle-orm for raw SQL expressions |
Never import from drizzle-orm/sqlite-core or drizzle-orm/pg-core directly in template code. Always use @agent-native/core/db/schema instead.
getDbExec() — auto-converts ? params to $1 for PostgresisPostgres() — runtime dialect checkintType() — returns correct integer type for the dialectNever write SQLite-only syntax: INSERT OR REPLACE, AUTOINCREMENT, datetime('now'). When writing docs, say "SQL database" — not "SQLite".
The server runs on Nitro with H3 as the HTTP framework. Templates must be deployable to any Nitro-supported target.
All server code uses H3/Nitro: defineEventHandler, readBody, getMethod, setResponseHeader, etc. Express is not a dependency. If you see Express types or patterns anywhere, replace them with H3 equivalents.
Files like netlify.toml, wrangler.toml, vercel.json, and netlify/functions/ do not belong in template source. Platform configuration lives in CI/hosting dashboards or in deployment-specific repos.
Never use fs, child_process, or path in server routes and plugins. Use Nitro abstractions. (Actions in actions/ run in Node.js and can use Node APIs freely.)
Never assume a persistent server process. Use the SQL database for all state.
storing-data — Schema patterns and the core SQL storesserver-plugins — Framework routes and H3 handler patternssecurity — SQL injection prevention via parameterized queriestools
Public booking flow — the state machine, animations, and URL/app-state sync.
tools
Trigger-based automations — reminders, follow-ups, webhooks — across the booking lifecycle.
tools
Team event types, round-robin assignment, collective bookings, host weights, and no-show calibration.
development
The pure `computeAvailableSlots` function — inputs, outputs, invariants, and debugging guide.