Entities
How entities work in the Almadar architecture - from schema definition to runtime execution.
Overview
In Almadar, an Entity is the data model at the core of each Orbital Unit. The fundamental composition is:
Orbital Unit = Entity + Traits + Pages
Entities define the shape of data, while Traits define behavior (state machines) that operate on that data. The binding between them is explicit and type-safe.
Entity Definition
An entity is defined in the .orb schema with the following structure:
{
"name": "Task",
"collection": "tasks",
"fields": [
{ "name": "id", "type": "string", "required": true, "primaryKey": true },
{ "name": "title", "type": "string", "required": true },
{ "name": "status", "type": "enum", "values": ["pending", "active", "done"] },
{ "name": "assigneeId", "type": "relation", "relation": { "entity": "User", "cardinality": "one" } },
{ "name": "dueDate", "type": "date" },
{ "name": "tags", "type": "array", "items": { "type": "string" } }
]
}
Entity Properties
| Property | Required | Description |
|---|---|---|
name | Yes | PascalCase identifier (e.g., Task, User, GameState) |
collection | For persistent | Database collection name (e.g., tasks, users) |
persistence | No | Storage mode: persistent, runtime, or singleton |
fields | Yes | Array of field definitions |
Field Types
Almadar supports the following field types:
| Type | Description | Example | TypeScript | Storage |
|---|---|---|---|---|
string | Text data | "hello" | string | String |
number | Numeric values (float) | 42.5 | number | Number |
boolean | True/false | true | boolean | Boolean |
date | Date without time | "2026-03-01" | Date | ISO string |
datetime | Date with time | "2026-03-01T10:30:00Z" | Date | ISO string |
timestamp | Milliseconds since epoch | 1709312400000 | number | Number |
array | Collection of values | ["a", "b"] | T[] | Array |
object | Structured data | { key: "value" } | Record<string, unknown> | JSON |
enum | Named constants | "pending" | Union type | String |
relation | Entity reference | "user_123" | string (FK) | String |
Field Properties
{
"name": "status",
"type": "enum",
"required": true,
"values": ["pending", "active", "done"],
"default": ["quote", "pending"]
}
| Property | Description |
|---|---|
name | camelCase field identifier |
type | One of the supported field types |
required | Whether the field must have a value |
primaryKey | Designates the primary key field |
unique | Enforces uniqueness constraint |
default | Default value (as S-expression) |
values | For enum type - array of allowed values |
items | For array type - element type definition |
properties | For object type - nested field definitions |
relation | For relation type - target entity and cardinality |
Relation Fields
Relations link entities together:
{
"name": "assigneeId",
"type": "relation",
"relation": {
"entity": "User",
"cardinality": "one"
},
"required": false
}
Cardinality options:
one- Single reference (foreign key)many- Multiple references (array of IDs)
Entity Persistence Types
Entities have three persistence modes that fundamentally change their storage and sharing behavior:
1. Persistent Entities
Storage: Database (Firestore, PostgreSQL, etc.)
Lifetime: Survives restarts, shared across sessions
Collection: Required - explicit naming
Default: If persistence is not specified, it defaults to persistent
{
"name": "Task",
"persistence": "persistent", // Optional - defaults to "persistent" if omitted
"collection": "tasks",
"fields": [...]
}
Characteristics:
- All orbitals referencing the same entity name share the same collection
- CRUD operations go through the persistence adapter
- Suitable for domain objects (Task, User, Order, Product)
2. Runtime Entities
Storage: Memory only (JavaScript/Python objects) Lifetime: Lost on restart/session end Collection: None
{
"name": "Enemy",
"persistence": "runtime",
"fields": [...]
}
Characteristics:
- Isolated per orbital - each orbital gets its own instances
- No database operations
- Suitable for temporary state (Enemy, Projectile, Particle)
- Common in games where entities spawn/despawn frequently