Entities
The foundational data objects that your system operates on
What are Entities?
Entities are the domain objects in your system. A user, a workspace, a subscription, an invoice — each is an entity with typed fields, constraints, and a module assignment. Entities are declared in YAML and become nodes in the AI System Graph, giving AI agents and the compiler a formal understanding of your data model.
Unlike database schemas or ORM models, entity specs are framework-agnostic. They describe what the data looks like and what rules it must follow, not how it is stored. The compiler and runtime use entity specs to generate types, validate inputs, and enforce invariants.
EntitySpec Structure
interface EntitySpec {
name: string; // unique entity name, e.g. "user"
description: string; // human-readable description
fields: EntityField[]; // typed fields with constraints
module: string; // owning module, e.g. "users"
invariants?: string[]; // invariant names bound to this entity
} Field Types
Each field has a name, a type, a required flag, an optional description, and optional constraints.
interface EntityField {
name: string;
type: string; // string, number, boolean, date, enum, reference
required: boolean;
description?: string;
constraints?: FieldConstraint[];
} Supported field types include:
string— text valuesnumber— numeric values (integers or decimals)boolean— true/false valuesdate— date/datetime valuesenum— a value from a fixed setreference— a reference to another entity's ID
Field Constraints
Constraints are declarative rules attached to individual fields. They are checked by the runtime and surfaced in generated metadata.
| Constraint Type | Value Type | Example |
|---|---|---|
min | number | Amount must be at least 0 |
max | number | Quantity must not exceed 1000 |
minLength | number | Name must be at least 1 character |
maxLength | number | Name must not exceed 255 characters |
pattern | string (regex) | Email must match a valid email pattern |
enum | string[] | Status must be one of [active, cancelled, past_due] |
unique | boolean | Email must be unique across all records |
Each constraint can also carry an optional message string for custom error messages.
Module Assignment
Every entity belongs to exactly one module, declared via the module field. This assignment creates a belongs_to edge in the AI System Graph from the entity node to the module node. Module boundaries control which capabilities can access which entities — a capability in the billing module can only reference entities from billing or from modules listed in billing's allowedDependencies.
Invariant Binding
Entities can declare a list of invariant names via the invariants field. These are business rules that must hold for the entity — for example, "email must be unique across all users" or "invoice amount must be positive." Each invariant binding creates an enforces edge in the graph from the invariant node to the entity node.
YAML Example: SaaS Billing
Here are the user and subscription entities from the SaaS billing example app:
entities:
- name: user
description: A registered user who can own workspaces and subscriptions
module: users
fields:
- name: id
type: string
required: true
description: Unique user identifier
- name: email
type: string
required: true
description: User email address
- name: name
type: string
required: true
description: Display name
- name: role
type: string
required: true
description: System role (admin, member, billing_admin)
- name: created_at
type: date
required: true
description: Account creation timestamp
invariants:
- email_must_be_unique
- name: subscription
description: A billing subscription linked to a workspace
module: billing
fields:
- name: id
type: string
required: true
description: Subscription identifier
- name: workspace_id
type: string
required: true
description: Workspace this subscription belongs to
- name: plan
type: string
required: true
description: Subscription plan (free, pro, enterprise)
- name: status
type: string
required: true
description: Subscription status (active, cancelled, past_due, trialing)
- name: billing_cycle
type: string
required: true
description: Billing cycle (monthly, yearly)
- name: current_period_start
type: date
required: true
description: Start of current billing period
- name: current_period_end
type: date
required: true
description: End of current billing period
invariants:
- subscription_must_have_workspace
- no_duplicate_active_subscription How Entities Participate in the Graph
Each entity creates the following relationships in the AI System Graph:
entity:user--belongs_to-->module:userscapability:create_user--uses_entity-->entity:userinvariant:email_must_be_unique--enforces-->entity:user
These edges let AI agents trace from an entity to everything that touches it: which capabilities read or write it, which invariants constrain it, which module owns it, and which flows involve it.
AI-Safe Change Workflows
When an AI agent proposes to modify an entity (adding a field, changing a type, removing a constraint), the Change Protocol uses the AI System Graph to compute the full impact. Every capability that uses_entity on the modified entity is flagged. Every invariant that enforces on it is checked. Every generated route handler, test scaffold, and metadata file that references the entity is listed for refresh. This ensures the agent understands the full blast radius before making the change.