Example Apps
Run and explore the built-in example applications to learn ObjectStack hands-on
The monorepo ships three ready-to-run examples in examples/ that progressively demonstrate ObjectStack features — from a simple Todo app to a full CRM and a kitchen-sink reference. For a larger external enterprise reference, see the HotCRM repository.
Read these as reference, then build your own with an agent. Each example is the same
kind of typed metadata Claude Code authors for you — so they double as a catalog of
patterns to point your agent at ("build me a CRM like app-crm, but for support
tickets"). To extend one, describe the change in plain language, let the agent edit the
metadata, run os validate, and verify in the Console — the loop in
Build with Claude Code.
app-todo
The simplest starting point. One object, basic CRUD, dashboards, seed data.
app-crm
A full CRM example (in-repo): multiple objects, views, apps, and seed data.
app-showcase
The kitchen-sink reference. Exercises most metadata types in one app.
Looking for a production server shape? Build an artifact with os compile,
then run it with os start or os serve. The framework repo no
longer contains a separate apps/objectos production host.
Quick Run
The fastest way to explore all examples at once:
git clone https://github.com/objectstack-ai/objectstack.git
cd objectstack
pnpm install # Node 22+, pnpm 8+ (corepack enable)
pnpm build # REQUIRED — nothing builds the workspace implicitly
pnpm dev:showcase # or: pnpm dev:todo / pnpm dev:crmEach script starts one example's dev server. pnpm dev is an alias for pnpm dev:showcase.
pnpm build is not optional. The root dev:* scripts begin with
node scripts/check-dev-prereqs.mjs, which refuses to boot an unbuilt workspace —
every package's dist/ entry point has to be on disk. There is no postinstall, so
pnpm install alone leaves the workspace unbuilt. This is the same sequence
README.md documents.
pnpm build still does not produce the Console SPA at /_console/ — that is built
separately by pnpm objectui:build.
app-todo — Your First App
Path: examples/app-todo/
The simplest complete ObjectStack application. Perfect for understanding the basics.
What's Inside
examples/app-todo/
├── objectstack.config.ts # App manifest + metadata wiring
├── src/
│ ├── objects/
│ │ └── task.object.ts # todo_task object: fields, validations, indexes
│ ├── actions/
│ │ └── task.actions.ts # Complete, Start, Defer, Delete batch
│ ├── apps/
│ │ └── todo.app.ts # Navigation: Tasks, Analytics
│ ├── views/ # List / form views
│ ├── dashboards/
│ │ └── task.dashboard.ts # Widget grid: stats, charts, lists
│ ├── reports/
│ │ └── task.report.ts # Tabular + summary reports
│ ├── datasets/ # Saved query datasets for charts
│ ├── flows/
│ │ └── task.flow.ts # Reminder, escalation & recurrence flows
│ ├── translations/ # Locale bundles
│ └── data/
│ └── index.ts # Seed data via defineSeed()Key Concepts Demonstrated
| Concept | File | What You'll Learn |
|---|---|---|
| Object & Fields | task.object.ts | Field.text(), Field.select(), field options, indexes |
| Seed Data | src/data/index.ts | defineSeed() with upsert mode, 8 sample records |
| Actions | task.actions.ts | Script actions, modal actions with params |
| App Navigation | todo.app.ts | Navigation groups, object links, dashboard links |
| Automation | task.flow.ts | Autolaunched flow with record-triggered logic |
Run It
# From a freshly cloned monorepo, build it once first — `objectstack dev` runs
# against the workspace's dist/ output and the root prereq gate does not guard
# this path: pnpm install && pnpm build
cd examples/app-todo
pnpm devCode Walkthrough
1. Define an object — src/objects/task.object.ts:
import { ObjectSchema, Field } from '@objectstack/spec/data';
export const Task = ObjectSchema.create({
name: 'todo_task',
sharingModel: 'public_read_write', // OWD — required on every custom object
label: 'Task',
pluralLabel: 'Tasks',
icon: 'check-square',
fields: {
subject: Field.text({
label: 'Subject',
required: true,
searchable: true,
}),
status: Field.select({
label: 'Status',
required: true,
options: [
{ label: 'Not Started', value: 'not_started', color: '#808080', default: true },
{ label: 'In Progress', value: 'in_progress', color: '#3B82F6' },
{ label: 'Completed', value: 'completed', color: '#10B981' },
],
}),
due_date: Field.date({ label: 'Due Date' }),
priority: Field.select({
label: 'Priority',
required: true,
options: [
{ label: 'Low', value: 'low', color: '#60A5FA', default: true },
{ label: 'Normal', value: 'normal', color: '#10B981' },
{ label: 'High', value: 'high', color: '#F59E0B' },
{ label: 'Urgent', value: 'urgent', color: '#EF4444' },
],
}),
},
});2. Wire it up — objectstack.config.ts:
import { defineStack } from '@objectstack/spec';
import * as objects from './src/objects';
import * as actions from './src/actions';
import * as apps from './src/apps';
import { TodoSeedData } from './src/data';
export default defineStack({
manifest: {
id: 'com.example.todo',
namespace: 'todo',
version: '2.0.0',
type: 'app',
name: 'Todo Manager',
},
objects: Object.values(objects),
actions: Object.values(actions),
apps: Object.values(apps),
// Seed data authored with defineSeed() in src/data/
data: TodoSeedData,
});Seed data is authored separately with defineSeed() and wired in via the data
key. For example, src/data/index.ts:
import { defineSeed } from '@objectstack/spec/data';
import { Task } from '../objects/task.object';
const tasks = defineSeed(Task, {
mode: 'upsert',
externalId: 'subject',
records: [
{ subject: 'Learn ObjectStack', status: 'completed', priority: 'high' },
{ subject: 'Build a cool app', status: 'in_progress', priority: 'normal' },
],
});
export const TodoSeedData = [tasks];3. The server auto-detects what you need: ObjectQL engine → SQLite driver → Hono HTTP server → REST API at /api/v1/data/todo_task.
HotCRM — Enterprise Scale (external repo)
Repo: github.com/objectstack-ai/hotcrm
A production-grade CRM demonstrating every ObjectStack feature. Use this as a reference for building real enterprise apps. It lives in a dedicated repository so it can evolve independently of the framework.
What's Inside
hotcrm/
├── objectstack.config.ts
├── src/
│ ├── objects/ # 10 objects: Account, Contact, Lead, Opportunity, ...
│ ├── actions/ # 15+ actions per domain
│ ├── agents/ # 5 AI agents: Sales, Service, Lead Enrichment, ...
│ ├── apis/ # Custom REST endpoints: lead-convert, pipeline-stats
│ ├── apps/ # CRM app with full navigation tree
│ ├── dashboards/ # Executive, Sales, Service dashboards
│ ├── data/ # Seed data for all objects
│ ├── flows/ # 5 automation flows: case escalation, approval, ...
│ ├── security/ # 5 permission sets: admin, sales rep, manager, ...
│ ├── rag/ # 4 RAG pipelines: product info, competitive intel, ...
│ ├── reports/ # 7 reports with tabular, summary, matrix formats
│ └── sharing/ # Sharing rules, business-unit hierarchy, org defaultsFeatures Showcased
| Feature | Description |
|---|---|
| 10 Business Objects | Account, Contact, Lead, Opportunity, Case, Campaign, Product, Quote, Contract, Task |
| State Machine | Lead lifecycle: new → contacted → qualified → converted with Lead.state.ts |
| AI Agents | Sales Assistant, Service Agent, Revenue Intelligence, Email Campaign, Lead Enrichment |
| RAG Pipelines | Product info, competitive intel, sales knowledge, support knowledge |
| Security Model | 5 permission sets (Admin, Manager, Rep, Agent, Marketing), sharing rules, business-unit hierarchy |
| Automation | Lead conversion, case escalation, opportunity approval, campaign enrollment, quote generation |
| Custom APIs | POST /lead-convert, GET /pipeline-stats |
| Seed Data | 50+ realistic records across all objects |
Run It
git clone https://github.com/objectstack-ai/hotcrm.git
cd hotcrm
pnpm install
pnpm dev # Starts with auto-detected pluginsOr inspect its metadata without starting a server:
cd hotcrm
os info # Show object/field/flow/agent counts
os validate # Check schema correctness
os compile # Build to dist/objectstack.jsonapp-showcase — Kitchen-Sink Reference
Path: examples/app-showcase/
A kitchen-sink workspace built for demonstration and debugging. It exercises nearly every metadata type, view type, and chart type in a single app — objects, views, apps, pages, dashboards, reports, datasets, flows, jobs, agents, security profiles, translations, webhooks, and more. Use it as a living reference when you want to see how a particular metadata type is authored.
# From a freshly cloned monorepo, build it once first — `objectstack dev` runs
# against the workspace's dist/ output and the root prereq gate does not guard
# this path: pnpm install && pnpm build
cd examples/app-showcase
pnpm devIt is also the target of pnpm dev / pnpm dev:showcase from the monorepo root.
Composition Pattern
Compose apps and plugins in objectstack.config.ts, compile them into one
artifact, then boot that artifact with the CLI.
import { composeStacks } from '@objectstack/spec';
import CrmApp from '../examples/app-crm/objectstack.config';
import TodoApp from '../examples/app-todo/objectstack.config';
// composeStacks merges objects, apps, and other metadata from each stack.
// The combined manifest is selected per the `manifest` option; the last
// stack's manifest is used by default. Duplicate object names throw unless
// you pass an `objectConflict` strategy ('override' | 'merge').
export default composeStacks([CrmApp, TodoApp]);Single-valued configuration keys — i18n, api, server, runtimeModule —
are neither overridden nor merged: identical declarations pass through, and two
stacks declaring different values throw an error naming both stacks. The two
apps above ship different i18n.supportedLocales (CRM ['en','zh-CN'], Todo
['en','zh-CN','ja-JP']), so composing them means reconciling the two i18n
blocks first — make them identical, or declare i18n in only one of the
stacks. Composition never picks a locale set for you: each stack's
translations bundles are written against the locales that stack declares.
Short Names Are Canonical
Each app declares a namespace in its manifest, but the short object name is what you use everywhere — in engine.find(), hooks, formulas, lookups, REST URLs, and physical tables. The namespace is internal metadata used only for package provenance and cross-package disambiguation.
| App | Namespace | Object name | Physical table |
|---|---|---|---|
| Todo | todo | todo_task | todo_task |
| CRM | crm | crm_account | crm_account |
If two packages contribute objects with the same short name, the registry logs a warning. Resolve the collision by giving one object a package-prefixed short name (the convention the examples follow, e.g. crm_account, todo_task) rather than using FQN strings in user code.
Run It
os compile
OS_ARTIFACT_PATH=./dist/objectstack.json os startProject Structure Conventions
All examples follow the same pattern. The recommended project layout — used by
every example in examples/ — looks like this:
my-app/
├── objectstack.config.ts # ← Entry point: manifest + metadata wiring
├── package.json
├── tsconfig.json
├── src/
│ ├── objects/ # Data models (required)
│ │ ├── index.ts # Barrel export
│ │ └── *.object.ts # One file per object
│ ├── actions/ # Buttons, batch operations (optional)
│ ├── flows/ # Automation logic (optional)
│ ├── apps/ # Navigation definitions (optional)
│ ├── dashboards/ # Analytics dashboards (optional)
│ ├── reports/ # Report definitions (optional)
│ ├── agents/ # AI agents (optional)
│ └── data/ # Seed data via defineSeed() (optional)
└── test/ # Testsos init scaffolds a minimal starter, not this full tree. It emits
objectstack.config.ts plus a single object under
src/objects/{namespace}_item.object.ts (e.g. my_app_item.object.ts) with a
matching barrel src/objects/index.ts — the same {name}.object.ts spelling
the convention list below states. Add the other directories above as your app
grows.
Naming conventions:
- Directories: plural (
objects/,actions/,flows/) - Files:
{name}.object.ts,{name}.actions.ts,{name}.flow.ts - Object names:
snake_caseshort names with a package prefix (todo_task,crm_account) - Config keys:
camelCase(maxLength,defaultValue,pluralLabel)
What's Next
- CLI Reference — All available commands
- Data Modeling Guide — Deep dive into objects and fields
- Developer Guide — Full learning path from objects to AI agents