Domain Decompose
ASecurityDecompose a domain into bounded contexts, aggregates, entities, value objects, and domain events with ubiquitous-language naming, mapping bounded contexts to candidate microservice boundaries. Use whenever the user wants to decompose a domain, split a system into bounded contexts, identify aggregates / value objects / domain events, define clean domain entities, draw clear boundaries, or plan a monolith-to-microservices breakup. Also use when an already-decomposed domain has evolved and the u...
- 4 stars
- 0 votes
- 0 copies
- 3 views
- Added August 31, 2026
Security analysis
100/100Pro scans all 5 files and shows the line behind each finding
npx -y skills add baodq97/open-plugin --skill domain-decompose --agent claude-codeAre you the author of Domain Decompose?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/baodq97-domain-decompose)---
name: domain-decompose
description: >
Decompose a domain into bounded contexts, aggregates, entities, value objects, and domain
events with ubiquitous-language naming, mapping bounded contexts to candidate microservice
boundaries. Use whenever the user wants to decompose a domain, split a system into bounded
contexts, identify aggregates / value objects / domain events, define clean domain entities,
draw clear boundaries, or plan a monolith-to-microservices breakup. Also use when an
already-decomposed domain has evolved and the user wants to update, extend, re-run, or
"read existing and update" an existing `docs/domain` model rather than start over — re-running
delta-merges into the existing docs (stable ids, preserves human edits, flags drops) instead of
overwriting. Works from a prose domain/requirements description, not existing code. Trigger even
when the user never says "DDD", as long as they are carving a domain into boundaries, modelling
entities/aggregates/events, or updating a model they already have.
---
# Domain Decompose
Turn a prose domain/requirements description into a Domain-Driven Design decomposition — bounded
contexts → aggregates → entities, value objects, and domain events — named in the business's
ubiquitous language; each context doubles as a candidate service boundary on the monolith →
microservices path.
**Strategic-then-tactical** and **hybrid**: produce a first-pass model from what you're given,
then ask targeted questions only where boundaries or ownership are genuinely ambiguous — don't
re-ask what the description already settles, and never invent business rules.
## Inputs
A domain description: feature list, PRD, process narrative, key capabilities, actors, notable
events. If the user points at code instead, say this skill models from domain knowledge, not
code, and ask for a description (or the key capabilities and rules) — reverse-engineering a
codebase is out of scope.
**Brownfield** (the model lives only in code, nothing written down): don't reverse it from the
code. Ask for a one-page sketch — main capabilities, key events (past-tense things that happen),
any hard rules — enough for a first-pass model; step 5 refines the rest. If domain docs/PRDs *do*
exist, step 1 already picks them up.
## Reference files (read as needed)
- `references/ddd-methodology.md` — theory and heuristics behind every step (sub-domain types,
boundary heuristics, aggregate/entity/VO/event criteria, naming). Read when a judgement call
needs grounding.
- `references/bounded-context-canvas.md` — template + guidance for each context's `README.md`.
- `references/aggregate-design-canvas.md` — template + rules for modelling each aggregate.
- `references/output-template.md` — **the exact output contract** (where to write, file layout,
schemas, frontmatter, hard rules). Read before emitting anything.
## Process
### 1. Find & reconcile existing domain artifacts
Before modelling, look for existing domain knowledge — re-deriving it wastes effort and risks
contradicting what the team already agreed. Look for PRDs, specs, design docs (`docs/specs/`,
`docs/**/prd/`, anything titled "… domain model"), code carrying a domain layer (`*/domain/`,
`*/ports/`), and **this skill's own prior output** in `docs/domain/`. Treat any you find as
**authoritative input**: build on them, preserve their names and stated rules verbatim, reconcile
rather than re-invent. Prior `docs/domain/` output puts you in **update mode** — you're merging a
delta, not writing from scratch; step 6 handles it.
**When two sources disagree** — e.g. a *draft* PRD models a `Fact` as `key`/`value` but shipped
code uses `content`/`source` — this is the highest-risk moment of the skill. Do **not** blend
their fields into one hybrid that exists in neither source: that is invention disguised as
reconciliation, the failure to avoid. Prefer the **running/shipped code** over a draft doc as
authoritative, but **always record each divergence explicitly** (source A says X, source B says Y,
chosen Z, why) in the Conflicts section of `context-map.md` and flag it for a human. Surfacing a
conflict is mandatory — a silently swallowed conflict is worse than an openly unresolved one.
### 2. Frame the input (event-storming style)
Skim the description and extract, in business language: **domain events** (past-tense things that
happen), the **commands/actors** that cause them, and the recurring **nouns**. Raw material — see
ddd-methodology.md §3. Don't formalize yet.
### 3. First-pass strategic decomposition
- Group events/nouns into **bounded contexts** by the boundary heuristics — a boundary is where
the *language changes meaning*, cohesion high and coupling low (ddd-methodology.md §2.2, §2.4).
- Classify each **core / supporting / generic** — core = competitive differentiator; generic =
commodity you could buy (§2.1).
- Sketch **relationships** between contexts (upstream/downstream, ACL, shared kernel, etc.).
- Name the **load-bearing extraction seam** — the boundary that decouples the system most if
split first, often a *Published Language* artifact (an exported pack, a contract, a shared
document) crossing contexts. State it explicitly and consider elevating it to its own context;
it's usually the first service to extract on the monolith→microservices path — don't leave it
buried inside a large context.
### 4. First-pass tactical model (per context)
For each context, identify **aggregates** (consistency boundaries) — each with its root entity,
member **entities** (identity), **value objects** (no identity, equal by value), and the **domain
events** it emits. Apply the aggregate rules in aggregate-design-canvas.md; name from the
ubiquitous language (see Naming below). A concept with an id, its own lifecycle/status, or
(brownfield) its own table/repository is an **entity** even if it looks data-like — don't demote
an identified concept to a value object.
Then run an **event-flow continuity check**: every emitted domain event should have at least one
consumer (a handler/policy in some context), and every cross-context arrow on the map should
correspond to an emitted event. Flag orphan emits and unconsumed events before finalizing — a
dropped or unconsumed edge is a real modeling bug, not a stylistic gap.
### 5. Ask targeted questions (only where ambiguous)
Surface the model, then ask **only** about genuine ambiguities — batch them:
- a term appears to mean different things in two candidate contexts (confirm the split),
- a context's core/supporting/generic classification isn't clear,
- two pieces of state may need atomic consistency across candidate aggregates,
- a concept's entity-vs-value-object nature is unstated,
- an invariant is implied but never stated (ask — do **not** fabricate it).
If the description already answers something, don't ask. If nothing is ambiguous, skip to step 6.
### 6. Emit the docs (create or delta-merge)
Follow `references/output-template.md` exactly. Detect the project's `docs/domain` convention (or
ask if none), then check whether it **already holds generated artifacts** (`DOMAIN-NNNN`
frontmatter, `INDEX.md` rows, per-context `model.yaml`):
- **Create mode** (empty/new): write `context-map.md` (Mermaid map + Core Domain Chart) and, per
context, a folder with `README.md` (Bounded Context Canvas) + `model.yaml`. Fresh docs start
`status: draft`, `owner: TBD`, with `DOMAIN-NNNN` ids; create `INDEX.md`.
- **Update mode** (prior output exists): **read it first**, then merge the new model in as a
*delta* — same reconcile discipline as step 1, now pointed at your own past output. Reuse each
existing context's `DOMAIN-NNNN` id, add/update only what changed, **preserve human edits**
(escalated status, assigned owner, hand-written rules), **never delete** a context that's no
longer in the model — flag it instead, and record real disagreements in the Conflicts table.
Close with a short **changelog** (added / updated / preserved / flagged). The exact merge rules
are in output-template.md §"Delta merge".
## Naming conventions
| Element | Convention | Example |
|---|---|---|
| Bounded Context | capability noun | `Booking`, `Inventory` |
| Aggregate | = its root entity | `Order` |
| Entity | singular domain noun | `Customer` |
| Value Object | descriptive noun, no id | `Money`, `DateRange` |
| Command | imperative | `PlaceOrder` |
| Domain Event | past tense | `OrderPlaced` |
The same word in two contexts is kept in both, qualified by context — that polysemy is the
*point* of bounded contexts, not a naming clash.
## Hard rules
- **Never invent business rules, invariants, or domain events.** Capture only what the user
stated; flag gaps rather than filling them. Naming an event the prose *implies*
(`AppointmentBooked` from "patients book appointments") is the job; inventing one for a flow the
input never describes (an `AppointmentCancelled` when nothing is ever cancelled) is fabrication —
don't. Fresh docs start `status: draft`, `owner: TBD`. In update mode,
**preserve** whatever a human set — never reset an escalated status, assigned owner, or
hand-written rule back to draft/TBD. Setting status (or reverting it) is a human act, not yours.
- Model from the **domain description, not code**.
- Boundaries and aggregates **will change** as understanding deepens — present the model as a
draft to iterate, not a final truth.
## Worked example
**Input:** "Students browse our course catalog and enrol in courses. Enrolment requires payment;
we email a receipt and a welcome message. Instructors create and publish courses."
**First-pass contexts + classification (`context-map.md`):**
```mermaid
graph LR
Enrolment -->|downstream of| Catalog
Enrolment -->|requests| Payments
Enrolment -->|publishes events to| Notifications
```
| Bounded Context | Sub-domain type | Why |
|---|---|---|
| Enrolment | core | the differentiating capability |
| Catalog | supporting | needed, not differentiating |
| Payments | generic | commodity — could be outsourced |
| Notifications | generic | commodity |
**Enrolment context (`docs/domain/enrolment/model.yaml`)** — tactical block (full schema in
output-template.md §4):
```yaml
context: Enrolment
subdomain_type: core
aggregates:
- name: Enrolment
root: Enrolment
entities:
- { name: Enrolment, attributes: [studentId, courseId, status] }
value_objects:
- { name: Money, attributes: [amount, currency] }
domain_events:
- { name: EnrolmentRequested, payload: [studentId, courseId] }
- { name: EnrolmentConfirmed, payload: [enrolmentId] }
relationships:
- { to: Payments, type: downstream }
- { to: Catalog, type: downstream }
```
Note what the example does **not** do: it doesn't assert a rule like "a student may enrol in at
most 5 courses" because the input never said so. If that mattered, the skill would ask.
Files in this skill
- SKILL.md
- references/aggregate-design-canvas.md
- references/bounded-context-canvas.md
- references/ddd-methodology.md
- references/output-template.md
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.