ADR-002: Bounded Contexts + Composition Root (Clean Architecture)¶
Status: Accepted
Date: 2026-01-25
Related: docs/_specs/master-vision.md, src/erdos/core/context.py, src/erdos/core/ports.py
Context¶
erdos-banger is a CLI-first system. Historically, CLI command modules can
accumulate orchestration and cross-cutting concerns (configuration reads,
network clients, filesystem paths), leading to:
- "god command" modules that are hard to test and review
- duplicated wiring (constructing the same clients/services in multiple places)
- tight coupling between domain policy and infrastructure adapters
We want the codebase to remain:
- local-first (works with minimal setup; derived stores are regenerable)
- testable (fast unit tests; explicit
requires_networktests for IO) - extensible without constant refactors
Decision¶
Adopt a bounded-context organization under src/erdos/core/ and a single
composition root for dependency wiring:
- Bounded core contexts: group domain logic into subpackages by responsibility
(e.g.,
core/ingest/,core/search/,core/loop/,core/research/). - Stable contracts: define dependency-inversion interfaces as
typing.Protocolports insrc/erdos/core/ports.py(prefer narrow ports over monolithic ones). - Single wiring point: construct concrete dependencies in
AppContext(src/erdos/core/context.py) and have CLI commands request dependencies from the context instead of constructing them directly. - Centralized configuration: prefer
AppConfig.from_env()as the SSOT for configuration reads and thread configuration through the composition root.
Options Considered¶
Option A (Chosen): Bounded Contexts + Ports + Composition Root¶
Pros¶
- Supports SRP: each subpackage has a narrow responsibility
- Improves DIP: policy depends on ports, not concrete adapters
- Improves testability: unit tests can inject fakes via ports/context constructors
- Keeps CLI code thin and consistent
Cons¶
- Adds a small amount of structure/indirection
- Requires discipline to avoid re-introducing "core root" module sprawl
Option B: Keep Logic in Command Modules¶
Pros¶
- Fewer files and layers
Cons¶
- Tends to produce large, coupled modules over time
- Forces tests to monkeypatch boundaries instead of injecting dependencies
Option C: Service Locator / Global Singletons¶
Pros¶
- Easy access to shared dependencies
Cons¶
- Hidden dependencies, harder tests, and unclear lifecycle
Consequences¶
- New core logic should live in an existing bounded context (or a new subpackage
if a truly new domain emerges), not as new
core/*.pytop-level modules. - CLI commands should be thin adapters that:
- parse flags/args
- call a core service/use-case
- emit output via shared presenter helpers
- Ports should remain stable and narrow; prefer adding new ports over growing one mega-interface.