Imported from C3EQUALZz/agate (
.claude/skills/add-bounded-context/SKILL.md). Install upstream withnpx skills add C3EQUALZz/agate --skill add-bounded-context. Copyright stays with the author.
Add a bounded context (crate)
Each bounded context is its own crate under crates/. It owns its aggregates and domain.
There is no shared kernel; if two contexts need the same technical capability, publish it
as a generic-subdomain library crate (like agate-crypto), not a shared domain model.
Steps
-
Create the crate
crates/agate-<context>/withCargo.toml:[package] name = "agate-<context>" version.workspace = true edition.workspace = true license.workspace = true description = "<one line>" [dependencies] # only inward deps: other domain/generic-subdomain crates. NO async runtimes, # NO hyper/axum/reqwest/extism in a crate that exposes a pure domain. [lints] workspace = trueIf other crates depend on it, register it in root
[workspace.dependencies]with a version ({ path = "...", version = "0.1.0" }) to avoid a cargo-deny wildcard. -
Lay out layers as modules inside the crate:
src/lib.rs # pub mod domain; (then application/infrastructure as they appear) src/domain/ common/ # seedwork: entities/ values/ services/ factories/ errors/ events/ <subdomain>/ # values/ entities/ services/ factories/ events.rs tests/ # integration / scenario testscommon/mirrorsagate-audit's seedwork (baseEntity,AggregateRoot,ValueObject,DomainService,Factory,DomainError, event machinery). Keep it per-crate — do not extract a cross-crate kernel. -
Preserve the dependency rule. Dependencies flow inward only:
presentation → infrastructure → application → domain. The crate graph is acyclic (Cargo enforces it); keep the domain modules free of async/I/O/framework imports. -
Wire modules: every file is declared
pub mod ..in its parentmod.rsand re-exported. -
Verify with the
check-architectureskill, thenjust ci.
See add-domain-object for populating the new context, and AGENTS.md for the conventions.