Architecture
This page explains system design and boundaries. Open the architecture overview
Layers¶
This page describes the main codebase layers and what each one owns. It is maintainer-facing: the goal is to keep the implementation aligned with the product model rather than letting responsibilities blur together.
The layer model¶
At a high level, envctl is organized like this:
Why the layers matter¶
The point of the layers is not ceremony. The point is to make the codebase easier to change without collapsing orchestration, domain semantics, persistence, and IO into one hard-to-maintain blob.
Layer ownership¶
CLI¶
Owns:
- Typer commands
- argument and selector validation
- prompts and output routing
- terminal vs JSON presentation choices
Should not own:
- core resolution rules
- persistence logic
- reusable domain semantics
Services¶
Own:
- use-case orchestration
- workflow coordination
- command-to-domain glue
Should not become:
- a second domain layer
- a formatting layer
- a dumping ground for CLI concerns
Domain¶
Owns:
- contract semantics
- resolution rules
- stable product models
- normalization logic
Should not know about:
- Typer
- terminal presentation
- repository-specific orchestration
Repository / Config / Adapters¶
Own:
- stored project and vault state
- user config
- external IO and integrations
Should not become:
- hidden service logic
- interactive CLI flows
- a second domain layer
Utils¶
Own:
- small generic helpers
- shared low-level utilities
If a helper starts expressing product semantics, it probably no longer belongs here.
Dependency direction¶
The important rule is directional:
- CLI can depend on services
- services can depend on domain, repository, config, adapters, and utils
- deeper layers must not depend upward on CLI concerns