diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/Aggregate.java b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/Aggregate.java
new file mode 100644
index 0000000..5774cea
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/Aggregate.java
@@ -0,0 +1,28 @@
+package {{root-package}}.{{module}};
+
+import java.util.UUID;
+
+import org.jmolecules.ddd.types.AggregateRoot;
+import org.jmolecules.ddd.types.Identifier;
+
+import {{root-package}}.{{module}}.{{capitalizeFirst name}}.{{capitalizeFirst name}}Identifier;
+
+
+/**
+ * A {{capitalizeFirst name}}.
+ */
+public class {{capitalizeFirst name}} implements AggregateRoot<{{capitalizeFirst name}}, {{capitalizeFirst name}}Identifier> {
+
+ private final {{capitalizeFirst name}}Identifier id;
+
+ public {{capitalizeFirst name}}() {
+ this.id = new {{capitalizeFirst name}}Identifier(UUID.randomUUID());
+ }
+
+ @Override
+ public {{capitalizeFirst name}}Identifier getId() {
+ return id;
+ }
+
+ record {{capitalizeFirst name}}Identifier(UUID id) implements Identifier {}
+}
diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/AggregateUnitTests.java b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/AggregateUnitTests.java
new file mode 100644
index 0000000..401da09
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/AggregateUnitTests.java
@@ -0,0 +1,19 @@
+package {{root-package}}.{{module}};
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {{capitalizeFirst name}}.
+ */
+class {{capitalizeFirst name}}UnitTests {
+
+ @Test
+ void createsSimple{{capitalizeFirst name}}Instance() {
+
+ var {{name}} = new {{capitalizeFirst name}}();
+
+ assertThat({{name}}.getId()).isNotNull();
+ }
+}
diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/Repository.java b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/Repository.java
new file mode 100644
index 0000000..849bedc
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/Repository.java
@@ -0,0 +1,11 @@
+package {{root-package}}.{{module}};
+
+import org.jmolecules.ddd.types.Repository;
+import {{root-package}}.{{module}}.{{capitalizeFirst name}}.{{capitalizeFirst name}}Identifier;
+
+/**
+ * A repository to manage {{capitalizeFirst name}} instances.
+ */
+interface {{capitalizeFirst name}}Repository extends Repository<{{capitalizeFirst name}}, {{capitalizeFirst name}}Identifier> {
+
+}
diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/RepositoryIntegrationTests.java b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/RepositoryIntegrationTests.java
new file mode 100644
index 0000000..d77270c
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/RepositoryIntegrationTests.java
@@ -0,0 +1,21 @@
+package {{root-package}}.{{module}};
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+/**
+ * Integration tests for {{capitalizeFirst name}}Repository.
+ */
+@SpringBootTest
+class {{capitalizeFirst name}}RepositoryIntegrationTests {
+
+ @Autowired {{capitalizeFirst name}}Repository repository;
+
+ @Test
+ void repositoryBootstrapped() {
+ assertThat(repository).isNotNull();
+ }
+}
diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/command.yaml b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/command.yaml
new file mode 100644
index 0000000..46bd60b
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/command.yaml
@@ -0,0 +1,15 @@
+command:
+ description: Add a jMolecules aggregate
+ options:
+
+ - name: name
+ description: The name of the aggregate (camel case)
+ dataType: string
+ inputType: text
+ required: true
+
+ - name: module
+ description: The name of the module to create the aggregate in.
+ dataType: string
+ inputType: text
+ required: true
diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/create-aggregate-and-repository.yaml b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/create-aggregate-and-repository.yaml
new file mode 100644
index 0000000..76eabb5
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/add-aggregate/create-aggregate-and-repository.yaml
@@ -0,0 +1,13 @@
+actions:
+ - generate:
+ to: src/main/java/{{root-package-dir}}/{{module}}/{{capitalizeFirst name}}.java
+ from: Aggregate.java
+ - generate:
+ to: src/test/java/{{root-package-dir}}/{{module}}/{{capitalizeFirst name}}UnitTests.java
+ from: AggregateUnitTests.java
+ - generate:
+ to: src/main/java/{{root-package-dir}}/{{module}}/{{capitalizeFirst name}}Repository.java
+ from: Repository.java
+ - generate:
+ to: src/test/java/{{root-package-dir}}/{{module}}/{{capitalizeFirst name}}RepositoryIntegrationTests.java
+ from: RepositoryIntegrationTests.java
diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/init/command.yaml b/jmolecules-spring-cli/.spring/commands/jmolecules/init/command.yaml
new file mode 100644
index 0000000..0c232ae
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/init/command.yaml
@@ -0,0 +1,15 @@
+command:
+ description: Initializes the project to use jMolecules
+ options:
+
+ - name: with-architecture
+ description: Which architectural stype to use (onion, hexagonal, clean)
+ dataType: string
+
+ - name: with-ddd
+ description: Whether to enable the Domain-Driven Design support
+ dataType: boolean
+
+ - name: with-codegen
+ description: Whether to enable the ByteBuddy based code generation for boilerplate persistence
+ dataType: boolean
diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/init/init-jmolecules.yaml b/jmolecules-spring-cli/.spring/commands/jmolecules/init/init-jmolecules.yaml
new file mode 100644
index 0000000..05b59a4
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/init/init-jmolecules.yaml
@@ -0,0 +1,24 @@
+actions:
+ - inject-maven-dependency-management:
+ text: |
+
+ org.jmolecules
+ jmolecules-bom
+ 2022.3.0
+ pom
+ import
+
+ - inject-maven-dependency:
+ text: |
+ {{#if with-ddd}}
+
+ org.jmolecules.integrations
+ jmolecules-starter-ddd
+
+ {{/if}}
+ {{#if with-architecture}}
+
+ org.jmolecules
+ jmolecules-{{with-architecture}}-architecture
+
+ {{/if}}
diff --git a/jmolecules-spring-cli/.spring/commands/jmolecules/init/setup-bytebuddy.yaml b/jmolecules-spring-cli/.spring/commands/jmolecules/init/setup-bytebuddy.yaml
new file mode 100644
index 0000000..7bc4842
--- /dev/null
+++ b/jmolecules-spring-cli/.spring/commands/jmolecules/init/setup-bytebuddy.yaml
@@ -0,0 +1,40 @@
+actions:
+ - exec:
+ command: ./mvnw dependency:list | grep 'jakarta.persistence-api' -q
+ define:
+ name: jpa-present
+ - inject-maven-build-plugin:
+ text: |
+ {{#if with-codegen}}
+
+ net.bytebuddy
+ byte-buddy-maven-plugin
+ 1.14.4
+
+ true
+
+
+
+
+ transform-extended
+
+
+
+
+ {{/if}}
+ - inject-maven-dependency:
+ text: |
+ {{#if with-codegen}}
+ {{#if jpa-present = 0}}
+
+ org.jmolecules.integrations
+ jmolecules-jpa
+ runtime
+
+ {{/if}}
+
+ org.jmolecules.integrations
+ jmolecules-bytebuddy-nodep
+ provided
+
+ {{/if}}
diff --git a/jmolecules-spring-cli/readme.adoc b/jmolecules-spring-cli/readme.adoc
new file mode 100644
index 0000000..8f5e55a
--- /dev/null
+++ b/jmolecules-spring-cli/readme.adoc
@@ -0,0 +1,74 @@
+= Spring CLI Integration
+
+This module of jMolecules Integration provides integration with https://github.com/spring-projects-experimental/spring-cli[Spring CLI].
+
+== Installation
+
+Run Spring CLI and issue the `command add` command pointing it to this particular module of the repository.
+
+```
+$ spring
+spring:> command add …
+```
+
+== Usage
+
+The integration provides the following commands.
+
+=== Initializing jMolecules
+
+`jmolecules init` adds all artifacts necessary to the POM of the project, depending on which features you'd like to use.
+
+```
+NAME
+ jmolecules init - Initializes the project to use jMolecules
+
+SYNOPSIS
+ jmolecules init --with-architecture String --with-ddd Boolean --with-codegen Boolean --help
+
+OPTIONS
+ --with-architecture String
+ Which architectural stype to use (onion, hexagonal, clean)
+ [Optional]
+
+ --with-ddd Boolean
+ Whether to enable the Domain-Driven Design support
+ [Optional]
+
+ --with-codegen Boolean
+ Whether to enable the ByteBuddy based code generation for boilerplate persistence
+ [Optional]
+
+ --help or -h
+ help for jmolecules init
+ [Optional]
+```
+
+=== Adding a DDD aggregate to the project
+
+Adding an aggregate to the project results in three new files generated in the project:
+
+* The aggregate file implementing `AggregateRoot` using a custom, record-based `Identifier` implementation backed by a `UUID`.
+* A repository declaration to persist instances of the aggregate.
+* A unit test class for the aggregate itself
+
+```
+NAME
+ jmolecules add-aggregate - Add a jMolecules aggregate
+
+SYNOPSIS
+ jmolecules add-aggregate [--name String] [--module String] --help
+
+OPTIONS
+ --name String
+ The name of the aggregate (camel case)
+ [Mandatory]
+
+ --module String
+ The name of the module to create the aggregate in.
+ [Mandatory]
+
+ --help or -h
+ help for jmolecules add-aggregate
+ [Optional]
+```