Role
Owns all business rules — session lifecycle, agent execution, pipeline orchestration, analysis, and tooling. Never touches raw I/O (files, processes, APIs) directly; always delegates to repository interfaces or functions.
Import Rules
| May import | Must NOT import |
|---|---|
domains/ports (intra), repositories/ports, types, errors, utils, constants |
cli, services, infrastructures |
Injection Styles
Style A — interface injection (repository is class-based with IXxxRepository)
import type { ISessionRepository } from '@src/repositories/ports/session'
export class SessionDomain implements ISessionDomain {
constructor(private sessionRepo: ISessionRepository) {} // inject interface, not concrete class
}
Style B — function-based (repository exposes plain exported functions)
import { saveSession, loadSession } from '@src/repositories/sessions'
export class SomeDomain implements ISomeDomain {
constructor(private dir: string) {}
async get(id: string) { return loadSession(this.dir, id) }
}
Choose Style A when the repository is a class; Style B when it exposes plain functions. Never call filesystem APIs or spawn processes directly.
Port Placement
- Domain ports →
src/domains/ports/<name>.ts(consumed byservices/) - Repository ports →
src/repositories/ports/<name>.ts(consumed bydomains/) - Never define
IXxxinside a domain implementation file
Intra-Domain Composition
Inject other domains by their port type from domains/ports/, never the concrete class:
import type { ISessionDomain } from '@src/domains/ports/session'
export class AnalyzeDomain implements IAnalyzeDomain {
constructor(private sessionDomain: ISessionDomain) {} // ✓ port type
}
// ✗ Bad: import { SessionDomain } from '@src/domains/session' + new SessionDomain(...)
A domain with pure business logic may inject only other domain ports and no repository — both patterns are valid.
Prohibitions
- Never import from
cli,services, orinfrastructures - Never import
zod— validation belongs invalidators/ - Never access the filesystem, spawn processes, or call external APIs directly
- Never read
process.env - Never expose transport variants in a repository port — single abstract method only
- Never define
IXxxin a domain implementation file - Never import or instantiate a concrete repository class (
new XxxRepository()) - Never call into
services/— domains sit below services in the dependency chain
References
references/session-field-migration.md— lazynormalize()pattern for renaming a persisted session JSON field