Core Concepts
The foundational ideas behind ObjectStack — metadata-driven development, protocol-first design, and the principles that shape every decision
Core Concepts
Before diving into code, understanding these foundational ideas will make everything else click.
Metadata-Driven Development
Metadata-driven development is a paradigm shift where application logic is defined by declarative data (metadata), not imperative code.
The Problem with Code-First
In traditional development, the "Intent" (e.g., "This field is a required email address") is scattered across multiple layers:
- Database: SQL constraints (
NOT NULL,CHECK) - Backend: ORM validation (TypeORM decorators, Prisma schemas)
- Frontend: UI validation (React Hook Form + Zod)
- Documentation: API specs (OpenAPI/Swagger)
When a business requirement changes, you must update code in three or four places. This is Implementation Coupling.
The ObjectStack Way
ObjectStack centralizes the "Intent" into a single Protocol Definition:
// ONE definition — everything else derives from it
import { defineStack } from '@objectstack/spec';
export default defineStack({
objects: [{
name: 'user',
label: 'User',
fields: {
phone: { label: 'Phone Number', type: 'phone', required: true },
},
}],
});// Map keys become the `name` field automatically
import { defineStack } from '@objectstack/spec';
export default defineStack({
objects: {
user: {
label: 'User',
fields: {
phone: { label: 'Phone Number', type: 'phone', required: true },
},
},
},
});Array or Map? defineStack() accepts both formats for all named metadata collections (objects, apps, flows, etc.). Map keys are injected as the name field — pick whichever style you prefer.
From this single definition, ObjectStack automatically:
✅ Generates database schema ✅ Creates validation rules ✅ Builds CRUD APIs ✅ Renders form fields ✅ Produces API documentation
The Three Truths
- The UI is a Projection — The form is generated from the schema, not hand-coded
- The API is a Consequence — REST/GraphQL endpoints appear automatically from object definitions
- The Schema is the Application — Your entire business logic lives in metadata files
When to Use Metadata-Driven
✅ Great for: CRUD apps, SaaS platforms, admin panels, rapid prototyping, multi-tenant systems
❌ Not ideal for: Pixel-perfect custom UIs, real-time 3D/games, highly unique domains
Design Principles
ObjectStack is governed by four unshakable principles:
I. Protocol Neutrality
The Protocol is law. The Implementation is merely an opinion.
II. Mechanism over Policy
Provide the tools to build rules, do not hardcode the rules themselves.
III. Single Source of Truth
There is no 'Code'. There is only Schema.
IV. Agent-Ready Boundaries
Agents may act only through typed, permission-aware, auditable surfaces.
Protocol Neutrality
"The Protocol is neutral. The Engine is replaceable."
- Spec before Engine: Features must be defined in the Specification layer before any engine code is written
- Zero Leakage: Implementation details (React, SQL, etc.) never leak into Protocol definitions
This ensures ObjectStack apps can run on Node.js + PostgreSQL today, Python + SQLite tomorrow, or Rust WASM in the browser.
Mechanism over Policy
"Give them the physics, not the simulation."
| Layer | Responsibility | Example |
|---|---|---|
| Protocol | Defines capabilities | A row-level-security policy slot (operation + using clause) |
| App | Defines business logic | { operation: 'select', using: "owner_id == current_user.id" } |
| Engine | Enforces the logic | Compiles the using condition into a query filter |
CRUD permissions (allowRead, allowEdit, …) are simple booleans — they grant or deny an operation. Record-level conditional access is a separate mechanism: Row-Level Security policies, whose using clause is a CEL predicate over context variables such as current_user.positions and current_user.id.
Single Source of Truth
In ObjectStack, the Object Protocol is the only truth:
- The Database is a derivative of the Protocol
- The UI is a projection of the Protocol
- The API is a consequence of the Protocol
- The Agent tool surface is a bounded capability set derived from the Protocol
Change the Protocol → the entire system adapts automatically.
Agent-Ready Boundaries
AI agents should not bypass the application model by calling raw SQL, scraping UI state, or executing arbitrary glue code. They should act through typed, permission-aware capabilities derived from the same metadata artifact that powers the application.
Traditional AI app: Database schema -> App code -> Custom query -> Hand-written MCP tool
ObjectStack: Zod metadata -> Metadata registry -> ObjectStack runtime -> API / UI / MCP toolsNaming Conventions
ObjectStack enforces strict naming rules for consistency:
| Element | Convention | Examples |
|---|---|---|
| Object names (machine) | snake_case | todo_task, user_profile |
| Field names (machine) | snake_case | first_name, is_active |
| Export names (constants) | PascalCase | TodoTask, UserProfile |
| Config keys (properties) | camelCase | maxLength, defaultValue |
Summary
| Aspect | Traditional | Metadata-Driven |
|---|---|---|
| Definition | Code in multiple files | Single metadata definition |
| Changes | Update 3-4 places | Update once |
| Type Safety | Manual synchronization | Automatic from Zod |
| Flexibility | Locked to tech stack | Technology agnostic |
| Boilerplate | High (300+ lines) | Low (30 lines) |
| Agent Tools | Hand-written and drift-prone | Generated from metadata and permissions |
Next Steps
- Architecture — How the protocol layers work together
- Build with Claude Code — Build your first app end-to-end with an agent
- Glossary — Key terminology