domain — Architecture
The @mnemose/domain package is the authoritative type layer for the Mnemose platform. It contains all Zod schemas for commands, domain events, and shared identifiers. No runtime logic — only schemas, type aliases, and the persona definition.
Responsibilities
- Define the 50 domain events (
AnyDomainEventSchemadiscriminated union) that represent all state changes in the platform - Define the 50 commands (
AnyCommandSchemadiscriminated union) that represent all intent signals - Provide shared identifier types (
TenantId,OrgId,WorkspaceId,ProjectId,GroupId,KernelId, etc.) and enum schemas - Model the ownership hierarchy aggregates (
Org,Workspace,Project,Group) — see Ownership hierarchy - Export the
MnemoseAgentpersona definition used by the agent service and loop-host
Package Structure
src/├── commands/│ └── index.ts — AnyCommandSchema + all individual command schemas├── events/│ └── index.ts — AnyDomainEventSchema + all individual event schemas├── schemas/│ ├── tenant.ts — TenantId, CloudProvider (carries optional orgId)│ ├── org.ts — OrgId, Org (ownership root)│ ├── workspace.ts — WorkspaceId, Workspace (tenant-scoped)│ ├── project.ts — ProjectId, Project (workspace-scoped)│ ├── group.ts — GroupId, Group, GroupMemberRef, GroupMembership│ ├── iam.ts — IamRole, ResourceScope, EscalationStatus│ ├── resource.ts — ResourceType│ ├── kernel.ts — KernelId, KernelSessionId, PermissionTier, FleetMode│ ├── kms-key.ts — KmsKey schemas│ └── user.ts — User identity schemas├── personas/│ └── mnemose-agent.ts — MnemoseAgent persona definition└── index.ts — Re-exports everythingContracts
All schemas are exported as committed JSON Schema files via scripts/export-contracts.ts. The generated files live in contracts/ and are the language-agnostic API contract for event/command integration.
pnpm --filter @mnemose/domain contracts:export # regeneratepnpm --filter @mnemose/domain contracts:check # CI gateEvent Envelope
Every domain event carries a standard envelope defined in EventBase:
{ eventId: string(UUID); // unique event identity aggregateId: string(UUID); // identity of the aggregate this event belongs to aggregateType: string; // e.g. "Tenant", "Kernel", "IamEscalation" sequence: number; // position in the aggregate's event stream tenantId: TenantId; // tenant scope correlationId: string(UUID); // links all events from one user action causationId: string(UUID); // ID of the command that caused this event actor: string; // agent persona name or user sub recordedAt: Date;}Control-plane events (bootstrap, org setup) use ControlPlaneEventBase which omits tenantId.
Ownership hierarchy
The platform’s ownership and containment model is expressed by four aggregates
plus the existing Tenant:
Platform└── Org ──────────────► Tenant ──► Workspace ──► Project │ (Org → Tenant via tenant.orgId) └── Group ──┬──► User ├──► Workspace └──► Project (many-to-many via GroupMembership)- Org (
org.ts) — top-level ownership root beneath the platform. Owns tenants and groups. Created/managed by control-plane commands (no tenant scope). - Tenant (
tenant.ts) — billing and cloud boundary. Carries an optionalorgIdmodeling theOrg → Tenantedge (nulluntil attached). - Workspace (
workspace.ts) — tenant-scoped container for projects. - Project (
project.ts) — workspace-scoped container; carries the denormalizedtenantIdof its workspace. Distinct fromCloudProject. - Group (
group.ts) — org-scoped, cross-cutting collection. Members are a polymorphicGroupMemberRef(user|workspace|project) attached viaGroupMembershiprecords.
Org and Group lifecycle commands/events extend the control-plane bases
(ControlPlaneCommandBase / ControlPlaneEventBase); Workspace and Project
commands/events are tenant-scoped.
This hierarchy is the basis for sandbox ownership: a sandbox is owned by exactly
one of these nodes (org, tenant, workspace, or project). The sandbox schema’s
SandboxOwnerRef discriminated union carries the owner; a null owner denotes
implicit tenant ownership, and resolveSandboxOwner() makes ownership total by
falling back to { kind: "tenant", id: tenantId }.