agentleFS
NTCodingNTCoding/living-architecture/.agents/skills/ddd/SKILL.md

ddd

Skill139 starsChanged 3 months agoApache-2.0View on GitHub

Explore and evaluate domain models collaboratively before implementation. Use for DDD modelling, domain concepts, aggregates, lifecycles, invariants, ownership, subdomain boundaries, or Rivière role questions where domain expertise and repository evidence must shape the model.

21 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use convention-learner, opentelemetry and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • codewithmukeshSkill

    convention-learner

    Detects and enforces project-specific coding conventions by analyzing existing codebase patterns. Learns naming conventions, folder structure, test organization, and coding style from the existing code. Load when: "conventions", "coding standards", "project patterns", "enforce style", "detect patterns", "learn conventions", "code consistency".

    Also in 3 projects that use this

  • codewithmukeshSkill

    opentelemetry

    OpenTelemetry observability for .NET 10 applications. Covers traces, metrics, and logs using the OpenTelemetry SDK with OTLP export. Includes custom ActivitySource, IMeterFactory metrics, resource configuration, and Aspire Dashboard integration. Load this skill when setting up distributed tracing, custom metrics, OTLP export, or when the user mentions "OpenTelemetry", "OTLP", "traces", "spans", "Activity", "ActivitySource", "metrics", "IMeterFactory", "Meter", "Counter", "Histogram", "Gauge", "telemetry", "observability", "distributed tracing", "OTEL", or "Aspire Dashboard".

    Also in 3 projects that use this

  • MovGP0Skill

    modern-csharp

    Modern C# style guidance for Bendex and MicroSea code changes, including primary constructors, expression-bodied members, var usage, target-typed new, lambdas, and pattern matching.

    Also in 3 projects that use this

  • MicrosoftSkill

    resilience

    Apply resilience patterns (retry, backoff, circuit breaking) when writing or reviewing code that makes outbound HTTP/REST calls, database operations, or any I/O that can experience transient failures. Use this skill when: (1) writing new code that calls external services or APIs, (2) reviewing code that uses fetch, HTTP clients, or service-to-service calls, (3) adding queue consumers or workers that interact with remote systems, (4) debugging intermittent failures in production.

    Also in 3 projects that use this

  • hongyuancSkill

    vertical-slice

    Build and evaluate a production-quality vertical slice before advancing from Pre-Production to Production.

    Also in 3 projects that use this

  • wpankSkill

    caching

    Caching strategies, invalidation, eviction policies, HTTP caching, distributed caching, and anti-patterns. Use when designing cache layers, choosing eviction policies, debugging stale data, or optimizing read-heavy workloads.

    Also in 3 projects that use this

The file

Show its rules and text

We split this skill into the rules it gives an agent

38 rules. 0 are common, 34 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 19 edited versions we read keep these.

  • 34

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before presenting the first problem interpretation:

    line 14
  2. Distinctive:

    Read the contents and subdomain overview in the generated domain guide.

    line 16
  3. Distinctive:

    Use the descriptions, package kinds, aggregates, and use case counts to identify the subdomains that may own or use the affected capability.

    line 18
  4. Distinctive:

    Read the detailed guide sections for those subdomains.

    line 20
  5. Distinctive:

    Follow the aggregate or domain service operations invoked by those use cases.

    line 25
  6. Distinctive:

    Read the relevant tests as evidence of behaviour that works under the tested conditions.

    line 28
  7. Distinctive:

    Use domain language. Do not frame the problem as a class, interface, role, or other implementation task.

    line 54
  8. Distinctive:

    Do not skip a familiar model because it appears likely to fail.

    line 71
  9. Distinctive:

    Use one important modelling question per turn by default.

    line 89
  10. Distinctive:

    When exploring a new role, begin by presenting multiple genuinely different configurations.

    line 96
  11. Distinctive:

    Start each option with this format:

    line 100
  12. Very specific:

    never use placeholders such as new role candidate.

    line 114
  13. Distinctive:

    use horizontal space when it makes independent relationships easier to compare.

    line 119
  14. Distinctive:

    do not dump several figures into one unlabelled vertical sequence that makes independent relationships look sequential.

    line 124
  15. Distinctive:

    Only discuss detailed trade-offs or identify a leading option after the user can compare the structural configurations.

    line 170
  16. Distinctive:

    If a concept owns state and enforces invariants, test it as an aggregate.

    line 195
  17. Distinctive:

    If a concept has identity and a lifecycle inside an aggregate, test it as an entity.

    line 196
  18. Distinctive:

    If a concept is immutable and defined by its attributes, test it as a value object.

    line 198
  19. Distinctive:

    Consider a domain service only after aggregate, entity, and value object ownership have been ruled out.

    line 200
  20. Distinctive:

    Before presenting an option, verify all of these points:

    line 208
  21. Distinctive:

    every fixed user constraint is satisfied.

    line 210
  22. Distinctive:

    every proposed concept name accurately describes the data or behaviour it owns rather than copying a possibly misleading code identifier.

    line 216
  23. Distinctive:

    every primitive result states what the value represents, and every operation name states the relationship or decision it performs.

    line 218
  24. Distinctive:

    every declaration has a concrete role that fits its responsibility.

    line 220
  25. Distinctive:

    every dependency and consumer relationship is legal.

    line 221
  26. Distinctive:

    If any check fails, do not show the option.

    line 230
  27. Very specific:

    Treat an unexplained primitive or broad verb as missing domain language.

    line 235
  28. Very specific:

    Prefer an API such as positionRelativeTo(other): 'before' | 'same' | 'after', then translate that meaning into the numeric Array.sort …

    line 239
  29. Distinctive:

    When no domain expert is present, identify the assumptions that require domain expert confirmation.

    line 258
  30. Distinctive:

    Test candidates against credible changes, such as a different product, market, interface, rule, workflow, integration, or source of …

    line 264
  31. Very specific:

    When role classification matters, read .riviere/role-selection-guide.md and the complete definitions for every role under consideration.

    line 281
  32. Distinctive:

    When code does not fit, re-examine the model.

    line 286
  33. Distinctive:

    Prefer the strongest constraints supported by current evidence when introducing a role.

    line 292
  34. Distinctive:

    When the user asks to converge, identify the model that currently appears most suitable and explain why it leads.

    line 298
  35. Distinctive:

    Keep the leading model open to challenge.

    line 302
  36. Distinctive:

    Only the user decides when convergence is complete.

    line 307
  37. Distinctive:

    After the user declares convergence complete, draft a concise model summary for their approval.

    line 313
  38. Distinctive:

    Use lowercase words separated by hyphens, with no date prefix.

    line 328

“Common” is measured: kept by at least 6 in 10 of the 19 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Domain modelling

Act as an exploratory domain modeller. Build a shared understanding with the user before converging on a model. Do not optimise for the design that is quickest to implement.

Start with repository evidence

Before presenting the first problem interpretation:

  1. Read the contents and subdomain overview in the generated domain guide.
  2. Use the descriptions, package kinds, aggregates, and use case counts to identify the subdomains that may own or use the affected capability.
  3. Read the detailed guide sections for those subdomains. Do not read every subdomain section by default. Expand the scope only when repository evidence reveals another relevant boundary or the overview leaves ownership unclear.
  4. Inspect the affected use cases, or the use cases closest in domain purpose when the capability is new.
  5. Follow the aggregate or domain service operations invoked by those use cases. Inspect repositories, ports, and neighbouring concepts when they clarify ownership, lifecycle, rules, or boundaries.
  6. Read the relevant tests as evidence of behaviour that works under the tested conditions.

The guide is a map of the implemented model. It is not proof that the current model is correct. Do not regenerate it during a modelling discussion.

Consult docs/architecture/domain-terminology/contextive/definitions.glossary.yml for the domain language encountered during the investigation. Claim a glossary match only when the identifier exactly matches a glossary name. Do not change case, split identifiers, infer synonyms, or use semantic similarity. Record <no glossary match> when there is no exact match. Do not change the glossary unless the user separately asks for that change.

Establish a challengeable problem interpretation

Explain what you currently think the domain problem is before introducing a model. Give the user something concrete to correct.

Separate:

  • repository observations;
  • your interpretation of those observations;
  • assumptions and missing domain knowledge;
  • decisions already confirmed by the user.

Use domain language. Do not frame the problem as a class, interface, role, or other implementation task. Ask the user to correct what is wrong, incomplete, or framed at the wrong level.

Explore before converging

Remain in exploration until the user explicitly asks to recommend, converge, or choose a model. Treat candidate models as probes, not proposals.

Start with familiar domain concepts

Explore existing concepts and standard DDD building blocks before introducing new roles or unusual structures. Start with the current aggregate and its owned state, then test existing entities and value objects, followed by the standard aggregate, entity, value object, and domain service tests. Leave new roles and more exotic structures until the end.

Do not skip a familiar model because it appears likely to fail. Validate it against the fixed constraints so the discussion has concrete proof of why it works or does not work. If it fails, show it explicitly as a ruled-out baseline, not as one of the admitted valid options.

For a useful candidate:

  • tell the domain story in plain language before showing code or roles;
  • explain the evidence it fits and what it fails to explain;
  • expose its assumptions;
  • examine identity, ownership, lifecycle, state changes, invariants, and boundaries;
  • identify the domain evidence that would distinguish it from another candidate.

Renaming the same design does not create a different option. Explore genuinely different domain interpretations or ownership of behaviour.

Use one important modelling question per turn by default. Each turn should advance the shared understanding by surfacing one tension, bringing relevant evidence, exploring a different angle, and asking one focused question. Do not front load a questionnaire or race several decisions ahead of the user.

Start new-role exploration with structural options

When exploring a new role, begin by presenting multiple genuinely different configurations. Do not lead with a preferred configuration or define precise implementation details before the structural alternatives are visible.

Start each option with this format:

  1. Option: <configuration name>
  2. One brief description.
  3. A prominent statement of the key idea.
  4. Lightweight diagrams before detailed prose.
  5. A short RISKS FOR ABUSE section that answers whether the proposed role or configuration could become an escape hatch, how it could be abused, and which enforceable constraints limit that abuse. State plainly when the risk cannot be constrained safely.

Every diagram must:

  • name every node and show its concrete current or proposed role;
  • never use placeholders such as new role candidate; if a proposed concept does not yet have a defined role, the option is not ready to present;
  • define each proposed role sufficiently to show that the relationships in the option are permitted; a role name without a role contract is not an option;
  • label every arrow with the relationship it represents;
  • use horizontal space when it makes independent relationships easier to compare;
  • figures may be stacked vertically when each has a clear figure heading, there is clear separation between them, and the option heading makes clear that they belong to the same option;
  • do not dump several figures into one unlabelled vertical sequence that makes independent relationships look sequential;
  • distinguish current roles, concrete proposed roles, external types or systems, and private data that needs no role;
  • show structural differences between options rather than renaming the same design.

For example:

***** Option: aggregate with owned value objects *****

One aggregate owns workflow state, event application, and its immutable registry.

KEY IDEA: Start from the state and invariants before considering services or new roles.

CONCRETE ROLES:
aggregate: owns mutable workflow state and enforces workflow invariants.
value-object: represents the immutable registry and each immutable workflow state definition.

RISKS FOR ABUSE: The aggregate could become a large file or construct its own
collaborators. Keep each value object in the file for its domain concept and
inject the registry through the aggregate constructor.

FIGURE: Aggregate ownership                          FIGURE: Application construction

┌─────────────────────────┐                           ┌─────────────────────────┐
│ MaintainerWorkflow      │                           │ ConfigureWorkflow       │
│ role: aggregate         │                           │ role: command-use-case  │
└─────────────────────────┘                           └─────────────────────────┘
            │                                                     │
            │ owns                                                │ parses and injects
            ▼                                                     ▼
┌─────────────────────────┐                           ┌─────────────────────────┐
│ WorkflowRegistry        │                           │ WorkflowRegistry        │
│ role: value-object      │                           │ role: value-object      │
└─────────────────────────┘                           └─────────────────────────┘
            │
            │ contains
            ▼
┌─────────────────────────┐
│ ImplementingState       │
│ role: value-object      │
└─────────────────────────┘

Only discuss detailed trade-offs or identify a leading option after the user can compare the structural configurations.

Admit options before presenting them

Explore the candidate space until further candidates only repeat an existing structure, break an agreed constraint, or add no meaningful trade-off. Reject invalid candidates privately. Let the number of visible options follow from the strong, distinct candidates that remain; never target an arbitrary or user-mentioned count. Never pad the visible options with renamed versions of the same structure or with designs that break an agreed constraint.

Validate every candidate concept name against the represented data and behaviour before presenting it. Treat existing code names as evidence, not as proof of a domain concept. Inspect what the code accepts, what it returns, what state it materialises, and which invariants it protects. Distinguish the source evidence, the process that interprets it, and the domain result. Do not propose a value object named after an algorithm or intermediate mechanism when the code does not materialise that value. For example, a function called buildCallGraph that returns detected architectural links does not establish a CallGraph value object unless it actually produces and protects a graph of code calls.

Apply the basic domain model tests first:

  1. If a concept owns state and enforces invariants, test it as an aggregate.
  2. If a concept has identity and a lifecycle inside an aggregate, test it as an entity.
  3. If a concept is immutable and defined by its attributes, test it as a value object.
  4. Consider a domain service only after aggregate, entity, and value object ownership have been ruled out.

An identifier passed separately from the objects linked to that identifier is a basic entity signal. Before preserving a map, tuple, or parallel parameters with that shape, test whether they are a flattened entity that should own the identity and the relationship.

Before presenting an option, verify all of these points:

  • every fixed user constraint is satisfied;
  • consumers do not copy variant names, identifiers, or lookup tables owned by a published language into string-typed switches, maps, or default branches; resolve extensible strings through the published language API, and make closed variant handling exhaustive against the imported published language union with a never check or an exhaustive satisfies Record<Union, ...>;
  • every proposed concept name accurately describes the data or behaviour it owns rather than copying a possibly misleading code identifier;
  • every primitive result states what the value represents, and every operation name states the relationship or decision it performs;
  • every declaration has a concrete role that fits its responsibility;
  • every dependency and consumer relationship is legal;
  • the option solves the complete error cluster rather than moving the error;
  • each file stays within the 400 line limit for a real domain reason;
  • aggregate ownership has not been confused with putting all code in one file;
  • dependencies are supplied to the aggregate rather than constructed by it;
  • fresh construction is not implemented by abusing rehydration;
  • the option is structurally different from the other visible options;
  • escape hatch risks and enforceable limits are explicit.

If any check fails, do not show the option. If a required fact is unknown, stop and inspect the code or ask the user instead of filling the gap with a sketch.

Make primitive meanings and operations explicit

Treat an unexplained primitive or broad verb as missing domain language. Ask what a number, boolean, or string represents and what an operation such as compare means before approving the API. For example, compare(other): number hides both the ordering relationship and the meaning of -1, 0, and 1. Prefer an API such as positionRelativeTo(other): 'before' | 'same' | 'after', then translate that meaning into the numeric Array.sort protocol only at the technical boundary.

Apply this test to every domain model decision. A type can be technically correct while still concealing the concept that a reader needs to understand, use, and change the model safely.

Apply the domain expert test

Challenge every candidate with these questions:

  • Would a domain expert recognise and use these concepts and this language?
  • Would they describe the process, decisions, and boundaries this way?
  • Does the model separate things that the expert considers different?
  • Does it group responsibilities because they belong to one domain lifecycle, or because one class would be easier to implement?
  • Can each concept be justified without referring to a technical pattern?

When no domain expert is present, identify the assumptions that require domain expert confirmation. Plausible code vocabulary is not confirmed domain language.

Stress test future evolution

Test candidates against credible changes, such as a different product, market, interface, rule, workflow, integration, or source of information.

For each relevant change, ask what stays stable, what changes, where the change lands, and whether the domain language and invariants remain honest. Prefer a model when likely changes stay local and its concepts retain their meaning. Challenge a model when change spreads across unrelated responsibilities, weakens invariants, stretches an aggregate, or requires exceptions.

Future scenarios test a model. They do not justify speculative abstractions. State why a scenario is credible before allowing it to influence the model.

Treat role enforcement as a quality constraint

Rivière roles express responsibility and protect architectural quality. They do not exist to provide somewhere convenient for code to go.

When role classification matters, read .riviere/role-selection-guide.md and the complete definitions for every role under consideration. Inspect the end to end flow before assigning a role. Responsibility determines the role; the role does not create the responsibility.

When code does not fit, re-examine the model. Do not invent generic helpers, managers, orchestrators, services, roles, folders, exemptions, or other escape hatches. A new role needs a distinct, durable architectural responsibility. Changes inside .riviere and new aggregate classifications require explicit user approval.

Prefer the strongest constraints supported by current evidence when introducing a role. Loosen them only when a concrete valid case shows that a constraint rejects legitimate code.

Converge gradually

When the user asks to converge, identify the model that currently appears most suitable and explain why it leads. Base the recommendation on domain expertise, repository evidence, credible future changes, and role constraints.

Keep the leading model open to challenge. State its important weaknesses, assumptions, and unresolved questions. Compare it with the strongest remaining alternative when that distinction is useful. New evidence can return the discussion to exploration.

Only the user decides when convergence is complete. Do not infer completion from confidence, silence, or implementation convenience. Agreement on a model does not authorise planning or implementation.

Record the approved model

After the user declares convergence complete, draft a concise model summary for their approval. It should cover:

  • the domain problem and story;
  • concepts and responsibilities;
  • identity, ownership, lifecycle, and invariants where relevant;
  • boundaries and collaborations;
  • supported operations;
  • the credible future changes used to test the model;
  • role implications;
  • remaining risks and unresolved questions.

The summary is not an implementation plan. After the user approves it, store it at docs/architecture/ddd/explorations/<stable-descriptive-slug>/model-summary.md. Use lowercase words separated by hyphens, with no date prefix. Update the same summary when the approved model evolves.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.