Getting Started
What is SMRT?
SMRT is a full-stack TypeScript framework that generates database schemas, REST APIs, MCP
tools, and CLI commands from simple object definitions. Define your data models once with the @smrt decorator, and the framework handles the rest.
Prerequisites
- Node.js 24+ (the framework's
enginesrequirenode >=24) - pnpm 9+ (npm also works)
- Basic TypeScript knowledge
Installation
Option 1: Clone the SaaS starter (recommended)
The fastest way to see the whole framework in one place is the smrt-saas-starter — a reference SvelteKit app wired up with the SMRT packages, auth, and admin UI. Clone it and run the dev server:
git clone https://github.com/happyvertical/smrt-saas-starter.git
cd smrt-saas-starter
pnpm install
pnpm devOption 2: Add SMRT to an existing SvelteKit project
Run smrt init inside an existing SvelteKit project to scaffold a smrt.config.ts and the wiring SMRT needs:
npx smrt initOption 3: Install packages by hand
Start from just the core package, then add what you need:
pnpm add @happyvertical/smrt-coreMost projects also pull in the shared types and the config loader, plus any domain packages for the problem you're solving (for example agents and background jobs):
pnpm add @happyvertical/smrt-types @happyvertical/smrt-config
pnpm add @happyvertical/smrt-agents @happyvertical/smrt-jobsYour First SmrtObject
Step 1: Define Your Model
Create a file src/models/Task.ts:
import { SmrtObject, smrt } from '@happyvertical/smrt-core';
@smrt({
api: true, // Generate REST API
cli: true, // Generate CLI commands
mcp: true // Generate MCP tools
})
export class Task extends SmrtObject {
title: string = '';
description: string = '';
status: string = 'todo';
dueDate: string = '';
complete() {
this.status = 'done';
}
}Step 2: Create the Collection
import { SmrtCollection } from '@happyvertical/smrt-core';
import { Task } from './Task.js';
export class TaskCollection extends SmrtCollection<Task> {
static readonly _itemClass = Task;
async findByStatus(status: string) {
return this.list({ where: { status } });
}
async findOverdue() {
return this.list({
where: {
'status !=': 'done',
'dueDate <': new Date().toISOString()
}
});
}
}Step 3: Use Your Object
import { TaskCollection } from './models/TaskCollection.js';
// Create collection via static factory
const tasks = await TaskCollection.create({
db: 'tasks.db'
});
// Create
const task = await tasks.create({
title: 'Learn SMRT Framework',
description: 'Read the getting started guide',
dueDate: '2025-01-20'
});
await task.save();
// Query
const allTasks = await tasks.list();
const todoTasks = await tasks.findByStatus('todo');
const overdue = await tasks.findOverdue();
// Update
task.status = 'in_progress';
await task.save();
// Custom method
task.complete();
await task.save();
// Delete
await task.delete();Auto-Generated Interfaces
With the @smrt decorator, you get:
REST API Endpoints
GET /api/tasks # List tasks
GET /api/tasks/:id # Get task by ID
POST /api/tasks # Create task
PATCH /api/tasks/:id # Update task
DELETE /api/tasks/:id # Delete taskCLI Commands
smrt tasks list
smrt tasks get <id>
smrt tasks create --title "My Task"
smrt tasks update <id> --status done
smrt tasks delete <id>MCP Tools
Claude Code can interact with your objects using natural language via MCP.
Configuration
Create smrt.config.ts in your project root:
import { defineConfig } from '@happyvertical/smrt-config';
export default defineConfig({
smrt: {
logLevel: 'info',
environment: 'development',
embeddings: { provider: 'local' }
},
modules: {
// Module-scoped configs keyed by module name
'my-agent': {
cronSchedule: '0 2 * * *',
maxRetries: 3
}
},
packages: {
// Package-scoped configs keyed by package name
ai: { defaultModel: 'gpt-4o' }
}
});Note:
The config top-level keys are smrt (global options), modules (module-scoped config), packages (package-scoped config), site (site templates), and export (SSG export). Use getModuleConfig() and getPackageConfig() to retrieve them at runtime.
Common Patterns
Relationships
import { SmrtObject, smrt, foreignKey, manyToMany } from '@happyvertical/smrt-core';
@smrt()
class Project extends SmrtObject {
name: string = '';
@foreignKey(User)
ownerId: string = '';
@manyToMany(Tag, { through: 'project_tags' })
tags: Tag[] = [];
}Computed Properties
@smrt()
class Order extends SmrtObject {
subtotal: number = 0.0;
taxRate: number = 0.08;
get total(): number {
return this.subtotal * (1 + this.taxRate);
}
}AI-Powered Methods
Every SmrtObject exposes three AI methods: is() (boolean check), do() (freeform action), and describe() (generate a description).
// is() — evaluate criteria, returns boolean
const isValid = await product.is(`
- Has a non-empty description
- Price is greater than $10
- Name does not contain profanity
`);
// do() — perform an action based on instructions, returns string
const summary = await product.do(`
Write a 50-word marketing description.
Highlight key features and target audience.
`);
// describe() — generate a concise description, returns string
const blurb = await product.describe();