Entity architecture is object-oriented only when inheritance, ownership, and dependency direction are strict. Generic Entity infrastructure must not know concrete Entity children, daemon registries, runtime adapters, or provider-specific services.
This ADR makes that rule explicit because prior implementation drift allowed generic Entity modules to become closed-set dispatchers and daemon service bags.
Decision
Generic Entity infrastructure is child-independent.
The base Entity layer may define only behavior and contracts that apply to every Entity class. It may depend on shared Entity schemas, shared Entity contract types, and generic storage/factory interfaces. It must not import concrete child Entities, child Entity contracts, daemon registries, daemon runtime services, adapters, terminal runtime modules, code intelligence services, platform adapters, or provider-specific implementations.
Concrete Entity classes may depend on their own schema and contract modules. A concrete Entity may depend on another concrete Entity only when the domain model gives it aggregate authority over that child Entity or an explicit ADR records the relationship. Such dependencies must remain domain dependencies, not daemon wiring dependencies.
Daemon-owned dispatch, registry lookup, runtime supervision, adapter creation, terminal runtime management, code intelligence indexing, and process orchestration live outside the generic Entity infrastructure. The daemon may invoke Entity contracts and provide capabilities to Entity methods, but the base Entity layer must not construct, import, or select daemon implementations.
Dependency Direction
Allowed direction:
daemon / host / adapter layer
-> Entity contracts
-> concrete Entity classes
-> Entity schemas
-> generic Entity infrastructure
Forbidden direction:
generic Entity infrastructure
-> concrete Entity contracts
-> concrete Entity classes
-> daemon registries
-> daemon runtime services
-> adapters or providers
The generic Entity layer is an abstraction parent. Children must not be required to register themselves by editing parent infrastructure. A new Entity may require daemon dispatch registration in daemon-owned code, but it must not require generic Entity base classes or generic Entity remote helpers to import the new child.
Entity Execution Context
EntityExecutionContext is a narrow invocation envelope, not a service locator and not a daemon runtime container.
The base context may include only capabilities that are truly generic to Entity invocation, such as auth token and an Entity factory or store abstraction. Capability names for daemon-owned services may be passed through at daemon-owned seams, but they must be validated and narrowed by the consuming domain or daemon module. The base Entity module must not import daemon types to describe those capabilities.
Generic Entity context must not contain path-based identity. Legacy fields such as surfacePath may exist only as temporary daemon/client compatibility while callers converge to explicit Entity ids and domain-named filesystem locations. A path can be a working directory or file root, but it is not a Repository id, Mission id, owner id, or instance invocation target.
When a concrete Entity method needs a daemon-owned capability, one of these must be true:
- the capability is provided through an explicit interface owned by that Entity or by a daemon-owned dispatcher;
- the capability is consumed behind a domain-specific method that validates the context shape locally;
- the behavior is moved to a daemon orchestrator because it is not Entity-owned behavior.
Direct dynamic imports from Entity classes into daemon modules are forbidden. They hide the dependency while preserving the coupling.
Entity Remote Dispatch
Entity remote dispatch is not generic if it imports every child Entity contract or constructs daemon registries. Concrete contract catalogues, daemon registry instances, post-command hydration, and runtime capability injection are daemon-owned dispatch responsibilities.
Generic Entity remote infrastructure may provide reusable invocation mechanics only when it receives contract resolvers and capabilities from the caller. A daemon Entity dispatcher may compose concrete contracts and daemon services, but that dispatcher must live in a daemon-owned module and be named as daemon dispatch infrastructure.
Storage Driver Rule
Entity persistence is enabled through registered Entity classes and canonical storage schemas. Tests and daemon code must not bypass the Entity factory with a raw storage driver when they are storing an Entity-owned record. Raw stores are adapter internals; Entity code and Entity tests should save and read through the Entity factory unless the test is specifically validating the store adapter itself.
Implementation Rules
- Do keep
Entity.ts,EntitySchema.ts,EntityFactory.ts, and generic invocation helpers independent of concrete child Entities. - Do put concrete contract catalogues and daemon capability wiring in daemon-owned dispatch modules.
- Do define daemon runtime interfaces at daemon seams or concrete Entity seams, not in the base Entity class.
- Do pass storage through registered Entity classes and storage schemas.
- Do treat child-to-child Entity imports as aggregate/domain decisions that require a named owner.
- Do use
typeimports only when they do not pull daemon ownership into Entity contracts; type-only imports are still architectural dependencies. - Do not import child Entity contracts from generic Entity infrastructure.
- Do not import daemon registries, runtime services, terminal runtime modules, code intelligence services, or adapters from generic Entity infrastructure.
- Do not hide forbidden dependencies with
await import(...)inside Entity classes. - Do not add daemon-owned service fields to
EntityExecutionContextin the base Entity module. - Do not make the base Entity package a closed registry of all concrete Entity types.
Validation
Entity dependency direction must be reviewed with every Entity-layer change. A simple grep for ../../daemon, runtime, Registry, concrete child contracts, and dynamic daemon imports under packages/core/src/entities should be treated as an architecture check, not merely a lint check.
Passing tests are necessary but not sufficient. The dependency graph must also preserve single responsibility: generic parents remain generic, concrete Entities own domain behavior, and daemon modules own runtime wiring.
Consequences
Generic Entity infrastructure remains reusable and understandable.
Adding a new Entity does not require editing base Entity code.
Daemon runtime services can evolve without leaking into Entity inheritance.
Entity tests prove domain behavior through Entity classes and Entity factories, while adapter tests prove storage drivers and daemon runtime services at their own seams.