Vobase
ERP engine for AI agents. Validated skills replace configuration. Evals replace hope.
Ask AI about Vobase
Powered by Claude Β· Grounded in docs
I know everything about Vobase. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
vobase
The app framework built for AI coding agents.
Own every line. Your AI already knows how to build on it.
what you get Β· get started Β· code Β· skills Β· compare Β· docs Β· discord
A full-stack TypeScript framework that gives you auth, database, storage, and jobs in a single process with a single SQLite file. Like a self-hosted Supabase β but you own every line of code. Like Pocketbase β but it's TypeScript you can read and modify.
AI coding agents (Claude Code, Cursor, Codex) understand vobase out of the box. Strict conventions and agent skills mean generated code works on the first try β not the third.
You own the code. You own the data. You own the infrastructure.
what you get
One vobase init and you have a working full-stack app:
| Primitive | What it does |
|---|---|
| Database | SQLite via Drizzle. Real SQL with JOINs, transactions, migrations. One .db file. |
| Auth | better-auth. Sessions, passwords, CSRF, RBAC. Works out of the box. |
| Storage | File uploads, downloads, deletions. Audit-ready. |
| Jobs | Background tasks with retries, cron, and job chains. SQLite-backed, no Redis. |
| Frontend | React + TanStack Router + shadcn/ui. Type-safe routing, code-splitting, you own the components. |
| Skills | Domain knowledge packs that teach AI agents your app's patterns and conventions. |
| MCP | Optional introspection server. AI tools can read your schema and modules before generating code. |
Everything runs in one Bun process. No Docker fleet. No external services. bun run dev and you're building.
quick start
bunx @vobase/cli@latest init my-app
cd my-app
bun run dev
Backend on :3000, frontend on :5173. Ships with a dashboard and audit log viewer out of the box.
what you can build
Every module is a self-contained directory: schema, handlers, jobs, pages. No plugins, no marketplace. Just TypeScript you own.
| Use Case | What Ships |
|---|---|
| SaaS Starter | User accounts, billing integration, subscription management, admin dashboard. Auth + jobs + webhooks handle the plumbing. |
| Internal Tools | Admin panels, operations dashboards, approval workflows. Status machines enforce business logic. Audit trails track every change. |
| CRM & Contacts | Companies, contacts, interaction timelines, deal tracking. Cross-module references keep things decoupled. |
| Project Tracker | Tasks, assignments, status workflows, notifications. Background jobs handle reminders and escalations. |
| Billing & Invoicing | Invoices, line items, payments, aging reports. Integer money ensures exact arithmetic. Gap-free numbering via transactions. |
| Your Vertical | Property management, fleet tracking, field services β whatever the business needs. Describe it to your AI tool. It generates the module. |
Module starters ship with the CLI: vobase add <module>. Like npx shadcn add button β files get copied, you own the code.
how it works
Vobase makes itself legible to every AI coding tool on the market.
The framework ships with strict conventions and agent skills β domain knowledge packs that teach AI tools how your app works. When you need a new capability:
- Open your AI tool and describe the requirement
- The AI reads your existing schema, module conventions, and the relevant skills
- It generates a complete module β schema, handlers, jobs, pages, tests, seed data
- You review the diff, run
bun run dev, and it works
Skills cover the parts where apps get tricky: money stored as integer cents (never floats), status transitions as explicit state machines (not arbitrary string updates), gap-free business numbers generated inside database transactions (not auto-increment IDs that leave holes).
These conventions are what make AI-generated modules work on the first try.
The thesis: your specs and domain knowledge are the asset. AI tools are the compiler. The compiler improves every quarter. Your skills compound forever.
what a module looks like
Every module declares itself through defineModule(). This convention is what AI tools rely on to generate correct code.
// modules/projects/index.ts
import { defineModule } from '@vobase/core'
import * as schema from './schema'
import { routes } from './handlers'
import { jobs } from './jobs'
import * as pages from './pages'
import seed from './seed'
export default defineModule({
name: 'projects',
schema,
routes,
jobs,
pages,
seed,
})
modules/projects/
schema.ts β Drizzle table definitions
handlers.ts β Hono routes (HTTP API)
handlers.test.ts β colocated tests (bun test)
jobs.ts β background tasks (SQLite-backed, no Redis)
pages/ β React pages (list, detail, create)
seed.ts β sample data for dev
index.ts β defineModule()
schema example β Drizzle + SQLite with typed columns, timestamps, status enums
// modules/projects/schema.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
import { nanoidPrimaryKey } from '@vobase/core'
export const projects = sqliteTable('projects', {
id: nanoidPrimaryKey(),
name: text('name').notNull(),
description: text('description'),
status: text('status').notNull().default('active'), // active -> archived -> deleted
owner_id: text('owner_id').notNull(),
created_at: integer('created_at', { mode: 'timestamp_ms' })
.notNull().$defaultFn(() => new Date()),
})
export const tasks = sqliteTable('tasks', {
id: nanoidPrimaryKey(),
project_id: text('project_id').references(() => projects.id),
title: text('title').notNull(),
status: text('status').notNull().default('todo'), // todo -> in_progress -> done
assignee_id: text('assignee_id'),
priority: integer('priority').notNull().default(0),
})
handler example β Hono routes with typed context and authorization
// modules/projects/handlers.ts
import { Hono } from 'hono'
import { getCtx } from '@vobase/core'
import { projects } from './schema'
export const routes = new Hono()
routes.get('/projects', async (c) => {
const ctx = getCtx(c)
return c.json(await ctx.db.select().from(projects))
})
routes.post('/projects', async (c) => {
const ctx = getCtx(c)
const body = await c.req.json()
const project = await ctx.db.insert(projects).values({
...body,
owner_id: ctx.user.id,
})
return c.json(project)
})
The frontend gets typed API calls for free via Hono RPC:
import { hc } from 'hono/client'
import type { AppType } from '../server'
const client = hc<AppType>('/')
const res = await client.api.projects.$get()
const projects = await res.json() // fully typed, no codegen
job example β background tasks, SQLite-backed, no Redis
// modules/projects/jobs.ts
import { defineJob } from '@vobase/core'
import { tasks } from './schema'
import { eq } from 'drizzle-orm'
export const sendReminder = defineJob('projects:sendReminder',
async (data: { taskId: string }) => {
const task = await db.select().from(tasks)
.where(eq(tasks.id, data.taskId))
// send notification, update status, log the action
}
)
Schedule from handlers: ctx.scheduler.add('projects:sendReminder', { taskId }, { delay: '1d' })
Retries, cron scheduling, and job dependencies via FlowProducer (chains, DAGs, parallel fan-out/fan-in) β all SQLite-backed, 286K ops/sec.
the ctx object
Every HTTP handler gets a context object with runtime capabilities. Current surface:
| Property | What it does |
|---|---|
ctx.db | Drizzle instance. Full SQL via bun:sqlite β reads, writes, transactions, migrations. |
ctx.user | { id, email, name, role }. From better-auth session. Used for authorization checks. |
ctx.scheduler | Job queue. add(jobName, data, options) to schedule background work. |
ctx.storage | File ops with audit logging. Upload, download, delete. |
For jobs, pass dependencies through closures/factories (or import what you need) when calling defineJob(...).
ctx extensions for external integrations
Beyond local capabilities (database, user, scheduler, storage), ctx provides outbound connectivity and inbound event handling:
| Property | What it does |
|---|---|
ctx.http | Typed fetch wrapper with retries, timeouts, circuit breakers, and structured error responses. Configurable per-app via http in vobase.config.ts. |
webhooks (app-level) | Inbound webhook receiver with HMAC signature verification, deduplication, and automatic enqueue-to-job. Configured in vobase.config.ts, mounted as /webhooks/* routes β not a ctx property. |
// vobase.config.ts
export default defineConfig({
database: './data/vobase.db',
http: {
timeout: 10_000,
retries: 3,
retryDelay: 500,
circuitBreaker: { threshold: 5, resetTimeout: 30_000 },
},
webhooks: {
'stripe-events': {
path: '/webhooks/stripe',
secret: process.env.STRIPE_WEBHOOK_SECRET,
handler: 'system:processWebhook',
signatureHeader: 'stripe-signature',
dedup: true,
},
},
})
Credentials stay in .env. Config declares the shape.
agent skills
Agent skills are the domain knowledge layer. AI tools load skills before generating code. Skill quality determines code quality β these conventions are what separate working modules from broken ones.
Vobase skills use the same format as Claude's native skill system. A skill is a SKILL.md file in .agents/skills/<name>/ with optional bundled resources. Claude (and any compatible AI tool) automatically discovers and loads them through progressive disclosure.
Skills fall into two layers:
core skills β app patterns that apply across every module
These are the rules that prevent the most common mistakes. Every module follows them.
| Skill | What it encodes |
|---|---|
gap-free-sequences | Transaction-safe gap-free sequence generation for business numbers (INV-0001, PO-0042). Never use auto-increment IDs as business numbers β they leave holes when transactions roll back. |
integer-money | All money as integer cents. Column: amount_cents. Display: (cents / 100).toFixed(2). Safe to $90 billion. Never floats β IEEE 754 rounding will cost real money at scale. |
status-machines | Explicit finite state machines for document workflows (draft β sent β paid β void) with validated transitions in handler code. No arbitrary string updates. |
domain skills β industry and vertical-specific logic
These encode domain knowledge for a particular business function, industry, or regulatory environment. Each skill teaches the AI how that domain actually works.
| Skill | What it encodes |
|---|---|
sg-gst | Singapore GST 9% rate, reverse charge, exemption handling, IRAS filing requirements, rounding policy. |
sg-invoicing | Tax invoice mandatory fields, credit note linkage, InvoiceNow/Peppol readiness, UEN validation. |
sg-payroll | CPF contribution rates, SDL/SHG levies, deduction ordering, payslip requirements, IR8A preparation. |
More verticals coming. See vobase add skill --list for what's available. Write your own following the same format.
skill quality β test, measure, refine
Skills are only as good as the code they produce. Vobase uses Claude's skill-creator system to test and improve skills systematically.
The process:
- Write the skill β
SKILL.mdwith instructions, references, scripts - Write test prompts β real requests users would make
- Define assertions β concrete checks on the generated code
- Run evals β Claude generates code with the skill loaded, assertions grade the output
- Benchmark β pass rate, token usage, elapsed time across multiple runs
- Iterate β rewrite the skill, run again, compare
vobase eval run gap-free-sequences # run all test prompts against the skill
vobase eval benchmark gap-free-sequences # 5 runs with variance analysis
vobase eval compare gap-free-sequences # blind A/B: skill vs no-skill
The comparator runs blind A/B tests β one agent with the skill, one without, a third agent grades which output is better without knowing which had the skill. If the skill doesn't consistently win, it needs rewriting.
vs the alternatives
| Vobase | Supabase | Pocketbase | Rails / Laravel | |
|---|---|---|---|---|
| What you get | Full-stack scaffold (backend + frontend + skills) | Backend-as-a-service (db + auth + storage + functions) | Backend binary (db + auth + storage + API) | Full-stack framework |
| Language | TypeScript end-to-end | TypeScript (client) + PostgreSQL | Go (closed binary) | Ruby / PHP |
| Database | SQLite (one file) | PostgreSQL (managed) | SQLite (embedded) | PostgreSQL / MySQL |
| Self-hosted | One process, one container | 10+ Docker containers | One binary | Multi-process |
| You own the code | Yes β all source in your project | No β managed service | No β compiled binary | Yes β but no AI conventions |
| AI integration | Agent skills + MCP + strict conventions | None | None | None |
| How you customize | Edit the code. AI reads it. | Dashboard + RLS policies | Admin UI + hooks | Edit the code |
| Hosting cost | As low as $15/mo | $25/mo+ (or complex self-host) | Free (self-host) | Varies |
| Data isolation | Physical (one db per app) | Logical (RLS) | Physical | Varies |
| License | MIT | Apache 2.0 | MIT | MIT |
vs Supabase: Self-hosted Supabase is 10+ Docker containers. RLS policies are hard to reason about. You don't own the backend code. Vobase is one process, one SQLite file, and you own every line β AI agents can read and modify everything.
vs Pocketbase: Pocketbase is a Go binary. You can see the admin UI, but you can't read or modify the internals. When you need custom business logic, you're writing Go plugins or calling external services. Vobase is TypeScript you own β AI agents understand and extend it natively.
vs Rails / Laravel: Great frameworks, but they weren't designed for AI coding agents. Vobase's strict conventions and agent skills mean AI-generated code follows your patterns consistently. Plus: simpler stack (SQLite, no Redis, single process, TypeScript end-to-end).
runtime architecture
One Bun process. One Docker container. One app.
Docker container (--restart=always)
βββ Bun process (PID 1)
βββ Hono server
β βββ /auth/* β better-auth (sessions, passwords, CSRF)
β βββ /api/* β module handlers (JWT-validated)
β βββ /mcp β MCP server (same process, shared port)
β βββ /webhooks/* β inbound event receiver (signature verified, dedup)
β βββ /* β frontend (static, from dist/)
βββ Drizzle (bun:sqlite, single file in /data/)
β βββ WAL mode, 5s busy timeout, foreign keys ON
βββ bunqueue (SQLite-backed job queue, 286K ops/sec)
βββ Outbound HTTP (typed fetch, retries, circuit breakers)
βββ Audit middleware (all mutations β _audit_log)
tech stack
| Layer | Choice | Why this, not that |
|---|---|---|
| Runtime | Bun | Native TypeScript, ~50ms startup, built-in SQLite via bun:sqlite, built-in test runner. |
| Database | SQLite via Drizzle | Real SQL with JOINs and aggregations. ACID transactions. One .db file. Zero external dependencies. |
| Auth | better-auth | 12K+ stars, SQLite-native, session/JWT, password hashing, CSRF. Org/RBAC/SSO/2FA as plugins. |
| API | Hono | ~14KB, typed routing, Bun-first. Every AI coding tool already knows Hono. |
| ORM | Drizzle | Type-safe SQL, bun-sqlite adapter, migration generation via drizzle-kit. |
| Jobs | bunqueue | Bun-native, SQLite-backed, BullMQ-compatible API. 286K ops/sec, retries, cron, FlowProducer. No Redis. |
| MCP | @modelcontextprotocol/sdk | Official SDK. Tools, resources, prompts, SSE. Same process, shared port. |
| Frontend | React + TanStack | Router (virtual file routes), Query, Table. Pure SPA, no SSR. Auto code-splitting. |
| Components | shadcn/ui + Tailwind v4 | You own the component source. v4's CSS-based config means no tailwind.config.js. |
| Backups | Litestream | Continuous WAL streaming to S3. ~1 second RPO. Point-in-time recovery. ~$0.03/month. |
why sqlite
At 10-200 concurrent users per instance, SQLite with WAL mode outperforms Postgres. PocketBase, Directus, and Strapi all run on it. This isn't a prototype choice β it's an architecture decision.
Backup your entire system:
cp vobase.db backup.db
Clone production for staging:
cp data/vobase.db data/staging.db
DATABASE=./data/staging.db PORT=3001 bunx vobase dev
One file copy. Exact production clone. No database dump/restore, no connection string changes.
Disaster recovery via Litestream β continuous WAL streaming to S3, roughly one second of lag:
litestream restore -o /data/vobase.db -timestamp 2026-03-01T10:00:00Z s3://my-backups/instance-id
Cost: $0.03-0.05/month. Point-in-time recovery to any second.
mcp server
Runs in the same Bun process on the same port. When you connect Claude Code, Codex, Cursor, or any MCP-compatible tool, it sees everything:
| Category | What's Exposed |
|---|---|
| Read | list_modules, read_module, get_schema, view_logs, get_migration_status |
| Write | deploy_module, install_package |
| Query | query_db, run_smoke_test |
| Context | Schema definitions, module signatures, ctx API docs, recent errors, domain knowledge from skills |
The AI sees your exact data model, your existing modules, and the conventions before it writes a single line of code.
deployment
Ship a Docker image. Add Caddy for HTTPS. Done.
# docker-compose.yml
services:
vobase:
image: your-registry/my-vobase:latest
restart: always
volumes:
- vobase_data:/data
ports:
- "3000:3000"
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "3"
caddy:
image: caddy:latest
ports:
- "80:80"
- "443:443"
Litestream wraps the Bun process for continuous backup:
COPY litestream.yml /etc/litestream.yml
ENTRYPOINT ["litestream", "replicate", "-exec", "bun run server.ts"]
Every app gets its own container, its own database, its own backup stream. Physical isolation, not row-level security policies.
cli commands
| Command | What it does |
|---|---|
vobase init | Scaffold a new project with system module, AGENTS.md, and config. |
vobase dev | Start Bun backend with --watch and Vite frontend. Auto-restarts on changes. |
vobase migrate | Run drizzle-kit migrate. Backs up the database first, automatically. |
vobase migrate:generate | Generate migration files via drizzle-kit generate. |
vobase generate | Rebuild route tree and system schemas from module definitions. |
vobase add skill <name> | Install an agent skill into .agents/skills/. Use --list to see available skills. |
project structure
my-app/
.env
.env.example
package.json β depends on @vobase/core
drizzle.config.ts
vobase.config.ts β database path, auth, connections, webhooks
vite.config.ts β Vite + TanStack Router + path aliases
index.html
server.ts β createApp() entry + export type AppType
AGENTS.md β project context and guardrails
.agents/
skills/
integer-money/
SKILL.md β core: all money as integer cents
modules/
system/ β admin dashboard (scaffolded)
schema.ts
pages/
layout.tsx
list.tsx
logs.tsx
index.ts β module registry
projects/ β example module you add
index.ts β defineModule()
schema.ts
handlers.ts
jobs.ts
pages/
src/
main.tsx
home.tsx
root.tsx
routes.ts β generated route definitions
routeTree.gen.ts β generated TanStack route tree
lib/
api-client.ts
auth-client.ts
utils.ts
components/
ui/ β shadcn/ui (owned by you)
shell/
layout.tsx
sidebar.tsx
auth/
login.tsx
signup.tsx
styles/
app.css
data/
vobase.db β your entire database
vobase.db-wal
vobase.db-shm
files/ β optional, created on first upload
backups/
license
MIT. Own everything.
