Aleph
Concepts

Domain Model

Domain-Driven Design layer with Entity, AggregateRoot, and ValueObject traits. Pure domain logic with no platform dependencies.

The domain module implements Aleph's domain model using Domain-Driven Design (DDD) principles. It defines the core vocabulary of the system — what a Session is, what a Task means, how Intent is structured — independent of any infrastructure or framework concerns.

Design Philosophy

The domain layer follows three DDD principles:

  1. Pure domain logic — No database queries, no HTTP calls, no file I/O
  2. Type-safe boundaries — Invalid states are unrepresentable via the type system
  3. Explicit invariants — Domain rules are enforced at construction time, not checked later

This module has no dependencies on tokio, axum, or any async runtime. It can be tested with plain #[test] functions, no runtime needed.


Core Traits

The domain layer ships only three minimal marker traits (src/domain/mod.rs) that establish the ubiquitous language — they specify identity and equality semantics, not fields.

Entity

Objects with a unique, immutable identity that remains constant through state changes.

pub trait Entity {
    type Id: Eq + Clone + std::fmt::Display;
    fn id(&self) -> &Self::Id;
}

Entities are compared by identity, not by attributes. Two Session objects with the same session_id are the same entity, even if their other fields differ.

Examples: Session, Task, Agent

AggregateRoot

The entry point of an aggregate — a consistency boundary that enforces domain invariants across multiple entities.

pub trait AggregateRoot: Entity {}

The AggregateRoot is the only object that outside code can reference directly. All other objects in the aggregate are accessed through it. Note: the actual trait does not carry a version() method — version numbers are provided by individual aggregate implementations when needed; the trait itself does not require one.

Examples: TaskGraph (contains Tasks and Dependencies), MemoryFact (contains ContextAnchors)

ValueObject

Immutable objects defined entirely by their attributes. Two ValueObjects with the same attributes are equal and interchangeable.

pub trait ValueObject: Eq + Clone {}

ValueObjects have no identity — they are pure data. Changing any attribute creates a new ValueObject. Note: the actual trait does not carry a validate() method — validation lives in the constructing function (parse, don't validate) or in the use-site that needs the rule, not in the trait contract.

Examples: TaskStatus, FactType, GuestScope, FileContent


Domain Types

Credentials

Credentials is an enum, not a struct (src/a2a/domain/security.rs).

pub enum Credentials {
    BearerToken(String),
    ApiKey(String),
    OAuth2Token(String),
    None,
}

The Debug impl prints every variant as [REDACTED] so secrets never reach logs. Credentials is consumed by the A2A protocol adapters during remote handshakes; it does not live in this crate's domain module.

TrustLevel

The skill module uses TrustLevel to decide whether a skill can be installed (src/skill/guard.rs).

pub enum TrustLevel {
    Builtin,    // Shipped with Aleph — always trusted.
    Trusted,    // From a curated/known publisher.
    Community,  // Arbitrary third-party (clawhub default).
}

The decision is made by install_allowed(ThreatLevel, TrustLevel); it is not auto-inferred from network origin.

FileContent

The A2A payload form for file content (src/a2a/domain/message.rs).

pub struct FileContent {
    pub name: Option<String>,
    pub mime_type: Option<String>,
    pub bytes: Option<String>,  // Base64-encoded
    pub uri: Option<String>,
}

validate() (pub const, returns Result<(), &'static str>) only enforces that exactly one of bytes or uri is set — neither nor both is rejected. MIME parsing, filename escaping, and non-empty checks are handled at the serialization layer, not here.


Bounded Contexts

Aleph's domain is organized into bounded contexts, each with its own ubiquitous language:

ContextKey TypesLocation
MemoryMemoryFact, ContextAnchor, NoteRelationArgsrc/memory/
IdentityIdentityContext, GuestScope, Roleshared/protocol/src/auth.rs, src/gateway/session_manager/
SkillTrustLevel, ThreatLevelsrc/skill/guard.rs
A2ACredentials, FileContent, SecuritySchemesrc/a2a/domain/
Loop-Graph GovernanceNodeKind, EdgeKindsrc/loop_graph/types.rs
GoalGoal, GoalStatus, PursuitMode, GateOutcomesrc/goal/types.rs
ArtifactArtifactRecordsrc/artifacts/store.rs
TeamTaskStatus, ArtifactTypesrc/teams/artifacts.rs

Cross-context references go through explicit mapping layers — IdentityContext lives in aleph_protocol (cross-process), while src/memory/ carries its own MemoryFact and ContextAnchor; the two do not share types directly.


Design Patterns in Practice

Newtype for Type Safety

pub struct SessionId(String);
pub struct TaskId(String);

// Cannot accidentally pass a TaskId where SessionId is expected
fn load_session(id: SessionId) -> Option<Session> { ... }

Enum State Machines

TaskStatus (src/teams/artifacts.rs) takes the form:

pub enum TaskStatus {
    Pending,
    InProgress,
    Completed,
    Blocked,
    Failed,
}

Illegal states are unrepresentable — a Task cannot be both Pending and Completed.

Parse, Don't Validate

impl Email {
    pub fn parse(input: &str) -> Result<Self, ValidationError> {
        // Rejects invalid input at the boundary
        // Returns a typed Email that is guaranteed valid
    }
}

Code Location

  • src/domain/ — Three marker traits plus the skill submodule
  • docs/reference/DOMAIN_MODELING.md — Extended domain modeling guide

See Also


26.7.x Addendum

POE Context Retired

The POE (Principle-Operation-Evaluation) runtime architecture was retired in 26.5+. Its "intelligence" migrated to system prompt templates (R9); success definition, validation, and evaluation are now naturally covered by a single LLM call. The Harness does not judge completion (R10 "Don't #3") or participate in evaluation.

Historical POE types have been removed from the current source tree. Use Git history for the corresponding version rather than referring to a current module path.

New Bounded Contexts

  • Loop-Graph Governance context (src/loop_graph/) — team nodes / audit ring / objective ACLs / victory-claim watchers / built-in loop-auditor
  • Goal context (src/goal/) — persistent goals managed by GoalStore, with the maker/checker GateOutcome split
  • Artifact context (src/artifacts/) — deliverables produced by artifact_publish, MAX_ARTIFACT_BYTES = 50 MiB / MAX_ARTIFACTS_PER_SESSION = 200
  • Signing context (src/identity/) — per-agent Ed25519 key (AgentKeystore) plus hash-chained signed ledger (AgentLedger), verified by verify_chain

Harness File and Line-Count Ratchets

In 26.7.x, src/harness/ is locked at 12 files, and its line count is gated by CEILING in src/harness/tests/budget.rs. The source constant is the only authority; this page does not copy a current count that will drift. See Architectural Redlines R10.

On this page