Framework
One application definition supplies every interface.
smrt-core supplies the model, collection, registry, persistence, and generation foundation. A model describes the fields, relationships, operations, and interface choices for one kind of record.
The framework uses that shared description for storage, collections, forms, APIs, commands, tools, and permission names. Application modules use the same foundation. They do not add parallel definitions that can drift.
Model to surfaces
Describe the record once.
This Article model selects four REST actions and one MCP action. It disables CLI access. Field metadata also marks one required value, one read-only value, and one sensitive value.import {
field, smrt, SmrtObject
} from '@happyvertical/smrt-core';
@smrt({
api: {
include: ['list', 'get', 'create', 'update']
},
mcp: { include: ['publish'] },
cli: false,
ui: {
label: 'Articles',
description: 'Stories your team publishes.'
}
})
export class Article extends SmrtObject {
title = '';
body = '';
featured = false;
@field({ required: true })
author = '';
@field({
readonly: true,
description: 'Server-set; writes cannot touch it.'
})
viewCount = 0;
@field({
sensitive: true,
exported: false,
description: 'Editorial notes for the team.',
ui: { group: 'Editorial', order: 10 }
})
authorNotes = '';
async publish() {
return true;
}
}- Storage and collections A database table and a typed collection store and query articles. →
- Forms Form controls use the model fields, descriptions, validation, and field rules. →
- REST API Generated routes and clients expose only the actions selected on the model. →
- Commands Application commands use the same declared actions when the model enables CLI access. →
- Agent tools The publish action becomes a described tool at an enabled MCP boundary. →
- Permissions Named operation permissions apply at each network and application boundary. →
Persons and software agents can reach the same permitted application operations. This is Software as Agentic Domain Logic (SAADL). The shared model keeps the human and agent interfaces on one contract. It does not give an agent authority.
Concept families
Follow the framework from meaning to operation.
These pages explain concepts and guarantees. The Reference section holds exhaustive contracts and API details.- 01 →
Models and collections
Write one TypeScript class for a record such as an Article or Invoice. The framework uses that class to understand its data and operations.
- 02 →
Persistence and live data
The framework prepares storage from the model. It can render server data first, give the same rows to the browser, and report later changes.
- 03 →
Tenancy and identity
A login account, a person, and an organization are different records. A membership states which account can act in which organization.
- 04 →
Permissions and security
Knowing who made a request is not enough. The application must also check the tenant, the operation, and protected fields.
- 05 →
Generated interfaces
The framework creates several ways to use the application. They share one description, so their names and field rules stay consistent.
- 06 →
Agent awareness and introspection
An application can describe its models and permitted tools. Coding tools can describe the project source. These descriptions do not give either kind of agent more authority.
Framework 01
Describe application logic with models and collections
A model describes one kind of application record. Its collection supplies the standard read and write operations for those records.The model is the application definition
The class fields describe stored values. Decorators add relationships, tenant scope, interface actions, permissions, and UI descriptions. Methods hold application operations beside the data they use.
- Field names and types become stable metadata.
- Relationship decorators connect models without a second relationship schema.
- Interface include lists select the operations that each generated surface can expose.
- Sensitive and read-protected fields stay outside generated public descriptions.
Collections keep read behavior consistent
A normal collection list returns model instances with their methods. A selected list returns smaller plain rows. Both paths use the same field mapping, interceptors, tenant rules, and query limits.
Framework 02
Keep server and browser data on one contract
The manifest supplies the database shape and generated data clients. Server collections and browser collections use that shared description.The manifest drives persistence
The scanner records model fields, relationships, table strategy, indexes, and tenant scope. Database migration uses that manifest. Runtime code does not create missing application tables in response to a request.
- Migrations prepare SQLite or PostgreSQL before application traffic starts.
- Server collections map TypeScript field names to database columns.
- Interceptors apply tenant and application rules to the normal collection path.
Hydration passes the first result to the browser
SvelteKit can load rows on the server and seed a generated browser collection with those rows. The first browser read can use the seed instead of making a duplicate request.
- A shared browser client lets collections share cache entries.
- Generated fetchers use the same REST route scheme as the model surface.
- Manifest hashes separate client data that belongs to incompatible definitions.
Change records support live and offline work
Writes append durable records to _smrt_changes. The _events stream can signal a browser to read from its last cursor. Polling is the fallback when the signal path is not available.
- The change feed stores durable order and resume cursors.
- The signal path is a prompt to read the durable feed, not a second data source.
- An offline outbox replays writes through the same server contract with idempotency keys.
System facilities have narrow jobs
Tables with the _smrt_ prefix support framework operations. For example, _smrt_changes stores change records, _smrt_contexts stores scoped memory, and _smrt_embeddings stores retrieval vectors. They do not replace application models.
Framework 03
Separate identity, organization, and membership
Users authenticate. Profiles describe persons. Tenants define organization boundaries. Memberships connect these records for access decisions.Each identity record has one job
A User is an authentication identity. A Profile is the application identity for a person or organization. A Tenant is an account or organization boundary. These records can change independently.
- Identity-provider bindings attach external sign-in identities to a User.
- Profile relationships describe application meaning such as client, supplier, or representative.
- Tenant parent and child links describe an organization hierarchy.
Membership connects a user to a tenant
A Membership joins one User, one Tenant, and one Role. A direct membership takes precedence in its tenant. A role can opt in to authority for descendant tenants.
- An inactive direct membership denies access for that tenant.
- Ancestor membership authority is opt-in and uses the nearest valid ancestor.
- Group roles and tenant overrides stay inside their defined tenant boundary.
Tenant context scopes data operations
Tenant context adds the tenant identifier to normal collection reads and writes for a tenant-scoped model. Missing required context fails closed. System and super-admin bypasses are explicit server operations.
Framework 04
Resolve authority at each operation boundary
Authentication identifies a caller. Tenant scope limits the data boundary. Operation permissions decide whether that caller can perform an action.The manifest supplies stable operation names
The permission catalog derives names from the model and its exposed actions. A standard read maps to a name such as articles.read. A custom action maps to its own stable name.
- Application guards check the catalog before hand-written actions run.
- Generated routes enforce authentication, tenant scope, writable fields, and operation rules.
- PostgreSQL row-level policies can apply the same resolved permission set at the data layer.
Descriptions do not grant access
An agent can know that a model, field, or operation exists without permission to read or change its data. Sensitive fields stay out of public model descriptions. The server resolves every requested operation as the active principal.
Framework 05
Generate each interface from the same model
One model can supply storage, forms, REST routes, commands, MCP tools, WebMCP tools, and permission names. Each surface can expose a different action set.Generation starts with declared actions
Each model selects its REST, MCP, and CLI actions. The generator reads the merged manifest and emits only the selected surface. The shared model description prevents a route schema and a tool schema from changing independently.
- REST routes and clients serve application code.
- MCP tools serve connected application agents.
- WebMCP tools serve agents through an active browser page.
- CLI resources serve operators and scripts.
- Generated web collections serve browser data and forms.
Stable descriptions prevent interface drift
Model, field, relationship, operation, and permission names come from the same manifest entries. Descriptions and JSON Schema inputs travel with the operation. A model change is therefore visible to each regenerated interface.
- Fields use the same logical names across generated clients and tools.
- Relationship metadata identifies linked models without page-specific inference.
- Writable, sensitive, and permission-protected field rules apply before execution.
Framework 06
Give agents stable application descriptions
Source manifests, the runtime ObjectRegistry, generated operations, and version-matched knowledge help agents understand an application without guessing from files or pixels.Source and runtime answer different questions
The source manifest describes declared objects, fields, relationships, methods, permissions, and generated interfaces. ObjectRegistry describes the model and collection classes registered in the active process.
- .smrt/manifest.json is the runtime-focused source artifact.
- .smrt/smrt-knowledge.json is the deterministic review and architecture artifact.
- ObjectRegistry holds active constructors, collections, field metadata, relationships, and decorator configuration.
- Generated REST, MCP, WebMCP, and CLI descriptions use stable names and structured inputs.
System facilities add operational context
Relevant _smrt_ facilities hold framework state with defined contracts. Change records, memory, embeddings, dispatch records, migrations, and field policies each have a narrow role. Agents must use the public framework operation for that role instead of treating the tables as an open data API.
- _smrt_changes provides resumable change records.
- _smrt_contexts and _smrt_embeddings support scoped memory and retrieval.
- _smrt_dispatch stores durable application signals.
- _smrt_migrations and _smrt_backfills record framework maintenance work.
Application agents and coding agents are different
An application agent operates the running application through a host-selected tool surface. A coding agent works on source, configuration, tests, and generated project knowledge. The two audiences use related descriptions but different authority boundaries.
- Application agents act as a resolved principal and remain inside tenant, permission, and tool limits.
- Coding agents use installed package instructions, workspace manifests, and development introspection.
- A coding tool does not become an application data principal because it can read project metadata.
- An application tool does not gain source-edit authority because it can describe a model.
Runtime development introspection has a release boundary
The current development MCP reads workspace and installed-package artifacts. A bridge to a running ObjectRegistry is available only when the installed development MCP explicitly supplies that integration. Do not infer a live connection from source introspection alone.
SAADL joins meaning and governed operations
Software as Agentic Domain Logic describes an application where persons and software agents reach the same permitted application operations. The application does not maintain a separate, reduced agent definition that can drift from the human interface.
Continue by task