diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/Adr.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/Adr.java
new file mode 100644
index 0000000000..52760ad76f
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/Adr.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr;
+
+import com.tngtech.archunit.PublicAPI;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+/**
+ * Represents an Architecture Decision Record (ADR)
+ * such as these templates.
+ */
+@PublicAPI(usage = ACCESS)
+public interface Adr {
+ @PublicAPI(usage = ACCESS)
+ Optional metadata();
+
+ @PublicAPI(usage = ACCESS)
+ Adr withMetadata(final Metadata metadata);
+
+ @PublicAPI(usage = ACCESS)
+ String contextAndProblemStatement();
+
+ @PublicAPI(usage = ACCESS)
+ String title();
+
+ @PublicAPI(usage = ACCESS)
+ Optional> decisionDrivers();
+
+ @PublicAPI(usage = ACCESS)
+ Adr withDecisionDrivers(final List decisionDrivers);
+
+ @PublicAPI(usage = ACCESS)
+ List consideredOptions();
+
+ @PublicAPI(usage = ACCESS)
+ String decisionOutcome();
+
+ @PublicAPI(usage = ACCESS)
+ Optional> consequences();
+
+ @PublicAPI(usage = ACCESS)
+ Adr withConsequences(final List consequences);
+
+ @PublicAPI(usage = ACCESS)
+ Optional confirmation();
+
+ @PublicAPI(usage = ACCESS)
+ Adr withConfirmation(final String confirmation);
+
+ @PublicAPI(usage = ACCESS)
+ Optional> optionProsAndCons();
+
+ @PublicAPI(usage = ACCESS)
+ Adr withOptionProsAndCons(final List optionProsAndCons);
+
+ @PublicAPI(usage = ACCESS)
+ Optional moreInformation();
+
+ @PublicAPI(usage = ACCESS)
+ Adr withMoreInformation(final String moreInformation);
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/Metadata.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/Metadata.java
new file mode 100644
index 0000000000..b363a622a9
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/Metadata.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr;
+
+import com.tngtech.archunit.PublicAPI;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+/**
+ * Metadata of the ADR.
+ */
+@PublicAPI(usage = ACCESS)
+public interface Metadata {
+ @PublicAPI(usage = ACCESS)
+ Optional status();
+
+ @PublicAPI(usage = ACCESS)
+ Metadata withStatus(final String status);
+
+ @PublicAPI(usage = ACCESS)
+ Optional date();
+
+ @PublicAPI(usage = ACCESS)
+ Metadata withDate(final String date);
+
+ @PublicAPI(usage = ACCESS)
+ Optional> decisionMakers();
+
+ @PublicAPI(usage = ACCESS)
+ Metadata withDecisionMakers(final List decisionMakers);
+
+ @PublicAPI(usage = ACCESS)
+ Optional> consulted();
+
+ @PublicAPI(usage = ACCESS)
+ Metadata withConsulted(final List consulted);
+
+ @PublicAPI(usage = ACCESS)
+ Optional> informed();
+
+ @PublicAPI(usage = ACCESS)
+ Metadata withInformed(final List informed);
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/OptionProsAndCons.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/OptionProsAndCons.java
new file mode 100644
index 0000000000..9756840375
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/OptionProsAndCons.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr;
+
+import com.tngtech.archunit.PublicAPI;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+/**
+ * Represents an option of an ADR with its pros and cons.
+ */
+@PublicAPI(usage = ACCESS)
+public interface OptionProsAndCons {
+ @PublicAPI(usage = ACCESS)
+ String title();
+
+ @PublicAPI(usage = ACCESS)
+ Optional description();
+
+ @PublicAPI(usage = ACCESS)
+ OptionProsAndCons withDescription(final String description);
+
+ @PublicAPI(usage = ACCESS)
+ Optional example();
+
+ @PublicAPI(usage = ACCESS)
+ OptionProsAndCons withExample(final String example);
+
+ @PublicAPI(usage = ACCESS)
+ List prosAndCons();
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/AdrEnvelope.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/AdrEnvelope.java
new file mode 100644
index 0000000000..1b7c8ce5e2
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/AdrEnvelope.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.envelopes;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.Adr;
+import com.tngtech.archunit.library.adr.Metadata;
+import com.tngtech.archunit.library.adr.OptionProsAndCons;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+import static com.tngtech.archunit.PublicAPI.Usage.INHERITANCE;
+
+@PublicAPI(usage = INHERITANCE)
+public abstract class AdrEnvelope implements Adr {
+ private final Adr delegate;
+
+ @PublicAPI(usage = ACCESS)
+ public AdrEnvelope(final Adr delegate) {
+ this.delegate = delegate;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional metadata() {
+ return this.delegate.metadata();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withMetadata(final Metadata metadata) {
+ return this.delegate.withMetadata(metadata);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String contextAndProblemStatement() {
+ return this.delegate.contextAndProblemStatement();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String title() {
+ return this.delegate.title();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> decisionDrivers() {
+ return this.delegate.decisionDrivers();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withDecisionDrivers(final List decisionDrivers) {
+ return this.delegate.withDecisionDrivers(decisionDrivers);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public List consideredOptions() {
+ return this.delegate.consideredOptions();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String decisionOutcome() {
+ return this.delegate.decisionOutcome();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> consequences() {
+ return this.delegate.consequences();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withConsequences(final List consequences) {
+ return this.delegate.withConsequences(consequences);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional confirmation() {
+ return this.delegate.confirmation();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withConfirmation(final String confirmation) {
+ return this.delegate.withConfirmation(confirmation);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> optionProsAndCons() {
+ return this.delegate.optionProsAndCons();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withOptionProsAndCons(final List optionProsAndCons) {
+ return this.delegate.withOptionProsAndCons(optionProsAndCons);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional moreInformation() {
+ return this.delegate.moreInformation();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withMoreInformation(final String moreInformation) {
+ return this.delegate.withMoreInformation(moreInformation);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String toString() {
+ return this.delegate.toString();
+ }
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/MetadataEnvelope.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/MetadataEnvelope.java
new file mode 100644
index 0000000000..47a82ddbea
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/MetadataEnvelope.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.envelopes;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.Metadata;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+import static com.tngtech.archunit.PublicAPI.Usage.INHERITANCE;
+
+@PublicAPI(usage = INHERITANCE)
+public abstract class MetadataEnvelope implements Metadata {
+ private final Metadata delegate;
+
+ @PublicAPI(usage = ACCESS)
+ public MetadataEnvelope(final Metadata delegate) {
+ this.delegate = delegate;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional status() {
+ return this.delegate.status();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withStatus(final String status) {
+ return this.delegate.withStatus(status);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional date() {
+ return this.delegate.date();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withDate(final String date) {
+ return this.delegate.withDate(date);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> decisionMakers() {
+ return this.delegate.decisionMakers();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withDecisionMakers(final List decisionMakers) {
+ return this.delegate.withDecisionMakers(decisionMakers);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> consulted() {
+ return this.delegate.consulted();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withConsulted(final List consulted) {
+ return this.delegate.withConsulted(consulted);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> informed() {
+ return this.delegate.informed();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withInformed(final List informed) {
+ return this.delegate.withInformed(informed);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String toString() {
+ return this.delegate.toString();
+ }
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/OptionProsAndConsEnvelope.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/OptionProsAndConsEnvelope.java
new file mode 100644
index 0000000000..8a59c09990
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/envelopes/OptionProsAndConsEnvelope.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.envelopes;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.OptionProsAndCons;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+import static com.tngtech.archunit.PublicAPI.Usage.INHERITANCE;
+
+@PublicAPI(usage = INHERITANCE)
+public abstract class OptionProsAndConsEnvelope implements OptionProsAndCons {
+ private final OptionProsAndCons delegate;
+
+ @PublicAPI(usage = ACCESS)
+ public OptionProsAndConsEnvelope(final OptionProsAndCons delegate) {
+ this.delegate = delegate;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String title() {
+ return this.delegate.title();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional description() {
+ return this.delegate.description();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public OptionProsAndCons withDescription(final String description) {
+ return this.delegate.withDescription(description);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional example() {
+ return this.delegate.example();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public OptionProsAndCons withExample(final String example) {
+ return this.delegate.withExample(example);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public List prosAndCons() {
+ return this.delegate.prosAndCons();
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String toString() {
+ return this.delegate.toString();
+ }
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdAdr.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdAdr.java
new file mode 100644
index 0000000000..fa9878f9e4
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdAdr.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.markdown;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.Adr;
+import com.tngtech.archunit.library.adr.envelopes.AdrEnvelope;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+@PublicAPI(usage = ACCESS)
+public final class MdAdr extends AdrEnvelope {
+
+ @PublicAPI(usage = ACCESS)
+ public MdAdr(final Adr delegate) {
+ super(delegate);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ metadata().ifPresent(m -> sb.append(m).append("\n"));
+ sb.append("\n# ").append(title()).append("\n");
+ sb.append("\n## Context and Problem Statement\n");
+ sb.append("\n").append(contextAndProblemStatement()).append("\n");
+ decisionDrivers().ifPresent(d -> {
+ sb.append("\n## Decision Drivers");
+ sb.append("\n\n");
+ d.forEach(s -> sb.append("* ").append(s).append("\n"));
+ });
+ sb.append("\n## Considered Options\n\n");
+ consideredOptions().forEach(o -> sb.append("* ").append(o).append("\n"));
+ sb.append("\n## Decision Outcome\n\n");
+ sb.append(decisionOutcome()).append("\n");
+ consequences().ifPresent(c -> {
+ sb.append("\n### Consequences\n\n");
+ c.forEach(s -> sb.append("* ").append(s).append("\n"));
+ });
+ confirmation().ifPresent(c -> sb.append("\n### Confirmation\n\n").append(c).append("\n"));
+ optionProsAndCons().ifPresent(opc -> {
+ sb.append("\n## Pros and Cons of the Options\n\n");
+ opc.forEach(s -> sb.append(s.toString()).append("\n"));
+ });
+ moreInformation().ifPresent(mi -> sb.append("## More Information\n\n").append(mi));
+ return sb.toString();
+ }
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdMetadata.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdMetadata.java
new file mode 100644
index 0000000000..5d86193c37
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdMetadata.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.markdown;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.Metadata;
+import com.tngtech.archunit.library.adr.envelopes.MetadataEnvelope;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+@PublicAPI(usage = ACCESS)
+public final class MdMetadata extends MetadataEnvelope {
+
+ @PublicAPI(usage = ACCESS)
+ public MdMetadata(final Metadata delegate) {
+ super(delegate);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("---\n");
+ status().ifPresent(s -> sb.append("status: ").append(s).append("\n"));
+ date().ifPresent(d -> sb.append("date: ").append(d).append("\n"));
+ decisionMakers().ifPresent(d -> sb.append("decision-makers: ").append(String.join(", ", d)).append("\n"));
+ consulted().ifPresent(c -> sb.append("consulted: ").append(String.join(", ", c)).append("\n"));
+ informed().ifPresent(i -> sb.append("informed: ").append(String.join(", ", i)).append("\n"));
+ sb.append("---");
+ return sb.toString();
+ }
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdOptionProsAndCons.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdOptionProsAndCons.java
new file mode 100644
index 0000000000..078e956648
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/markdown/MdOptionProsAndCons.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.markdown;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.OptionProsAndCons;
+import com.tngtech.archunit.library.adr.envelopes.OptionProsAndConsEnvelope;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+@PublicAPI(usage = ACCESS)
+public final class MdOptionProsAndCons extends OptionProsAndConsEnvelope {
+
+ @PublicAPI(usage = ACCESS)
+ public MdOptionProsAndCons(final OptionProsAndCons delegate) {
+ super(delegate);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("### ").append(title()).append("\n\n");
+ description().ifPresent(d -> sb.append(d).append("\n\n"));
+ example().ifPresent(e -> sb.append(e).append("\n\n"));
+ prosAndCons().forEach(pc ->
+ sb.append("* ").append(pc).append("\n")
+ );
+ return sb.toString();
+ }
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleAdr.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleAdr.java
new file mode 100644
index 0000000000..977d5871cd
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleAdr.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.simples;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.Adr;
+import com.tngtech.archunit.library.adr.Metadata;
+import com.tngtech.archunit.library.adr.OptionProsAndCons;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+@PublicAPI(usage = ACCESS)
+public final class SimpleAdr implements Adr {
+
+ private Metadata metadata;
+ private final String title;
+ private final String contextAndProblemStatement;
+ private List decisionDrivers;
+ private final List consideredOptions;
+ private final String decisionOutcome;
+ private List consequences;
+ private String confirmation;
+ private List optionProsAndCons;
+ private String moreInformation;
+
+ @PublicAPI(usage = ACCESS)
+ public SimpleAdr(final String title, final String contextAndProblemStatement, final List consideredOptions, final String decisionOutcome) {
+ this.title = title;
+ this.contextAndProblemStatement = contextAndProblemStatement;
+ this.consideredOptions = consideredOptions;
+ this.decisionOutcome = decisionOutcome;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional metadata() {
+ return Optional.ofNullable(this.metadata);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withMetadata(final Metadata metadata) {
+ this.metadata = metadata;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String title() {
+ return this.title;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String contextAndProblemStatement() {
+ return this.contextAndProblemStatement;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> decisionDrivers() {
+ return Optional.ofNullable(this.decisionDrivers);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withDecisionDrivers(final List decisionDrivers) {
+ this.decisionDrivers = decisionDrivers;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public List consideredOptions() {
+ return this.consideredOptions;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String decisionOutcome() {
+ return this.decisionOutcome;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> consequences() {
+ return Optional.ofNullable(this.consequences);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withConsequences(final List consequences) {
+ this.consequences = consequences;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional confirmation() {
+ return Optional.ofNullable(this.confirmation);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withConfirmation(final String confirmation) {
+ this.confirmation = confirmation;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> optionProsAndCons() {
+ return Optional.ofNullable(this.optionProsAndCons);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withOptionProsAndCons(final List optionProsAndCons) {
+ this.optionProsAndCons = optionProsAndCons;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional moreInformation() {
+ return Optional.ofNullable(this.moreInformation);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Adr withMoreInformation(final String moreInformation) {
+ this.moreInformation = moreInformation;
+ return this;
+ }
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleMetadata.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleMetadata.java
new file mode 100644
index 0000000000..2f6d9bf059
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleMetadata.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.simples;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.Metadata;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+@PublicAPI(usage = ACCESS)
+public final class SimpleMetadata implements Metadata {
+
+ private String status;
+ private String date;
+ private List decisionMakers;
+ private List consulted;
+ private List informed;
+
+ @PublicAPI(usage = ACCESS)
+ public SimpleMetadata() {}
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional status() {
+ return Optional.ofNullable(this.status);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withStatus(final String status) {
+ this.status = status;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional date() {
+ return Optional.ofNullable(this.date);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withDate(final String date) {
+ this.date = date;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> decisionMakers() {
+ return Optional.ofNullable(this.decisionMakers);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withDecisionMakers(final List decisionMakers) {
+ this.decisionMakers = decisionMakers;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> consulted() {
+ return Optional.ofNullable(this.consulted);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withConsulted(final List consulted) {
+ this.consulted = consulted;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional> informed() {
+ return Optional.ofNullable(this.informed);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Metadata withInformed(final List informed) {
+ this.informed = informed;
+ return this;
+ }
+}
diff --git a/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleOptionProsAndCons.java b/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleOptionProsAndCons.java
new file mode 100644
index 0000000000..ecb33604a8
--- /dev/null
+++ b/archunit/src/main/java/com/tngtech/archunit/library/adr/simples/SimpleOptionProsAndCons.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014-2025 TNG Technology Consulting GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.tngtech.archunit.library.adr.simples;
+
+import com.tngtech.archunit.PublicAPI;
+import com.tngtech.archunit.library.adr.OptionProsAndCons;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.tngtech.archunit.PublicAPI.Usage.ACCESS;
+
+@PublicAPI(usage = ACCESS)
+public final class SimpleOptionProsAndCons implements OptionProsAndCons {
+ private final String title;
+ private String description;
+ private String example;
+ private final List prosAndCons;
+
+ @PublicAPI(usage = ACCESS)
+ public SimpleOptionProsAndCons(final String title, final List prosAndCons) {
+ this.title = title;
+ this.prosAndCons = prosAndCons;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public String title() {
+ return this.title;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional description() {
+ return Optional.ofNullable(this.description);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public OptionProsAndCons withDescription(final String description) {
+ this.description = description;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public Optional example() {
+ return Optional.ofNullable(this.example);
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public OptionProsAndCons withExample(final String example) {
+ this.example = example;
+ return this;
+ }
+
+ @PublicAPI(usage = ACCESS)
+ @Override
+ public List prosAndCons() {
+ return this.prosAndCons;
+ }
+}
diff --git a/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/ExampleAdr.java b/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/ExampleAdr.java
new file mode 100644
index 0000000000..3954e0ea67
--- /dev/null
+++ b/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/ExampleAdr.java
@@ -0,0 +1,89 @@
+package com.tngtech.archunit.library.adr.markdown;
+
+import com.tngtech.archunit.library.adr.envelopes.AdrEnvelope;
+import com.tngtech.archunit.library.adr.simples.SimpleAdr;
+import com.tngtech.archunit.library.adr.simples.SimpleMetadata;
+import com.tngtech.archunit.library.adr.simples.SimpleOptionProsAndCons;
+
+import java.util.Arrays;
+
+public final class ExampleAdr extends AdrEnvelope {
+ public ExampleAdr() {
+ super(
+ new MdAdr(
+ new SimpleAdr(
+ "{short title, representative of solved problem and found solution}",
+ "{Describe the context and problem statement, e.g., in free form using two to three sentences or in the form of an illustrative story. You may want to articulate the problem in form of a question and add links to collaboration boards or issue management systems.}",
+ Arrays.asList(
+ "{title of option 1}",
+ "{title of option 2}",
+ "{title of option 3}"
+ ),
+ "Chosen option: \"{title of option 1}\", because {justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force {force} | ... | comes out best (see below)}."
+ ).withMetadata(
+ new MdMetadata(
+ new SimpleMetadata().withStatus(
+ "accepted"
+ ).withDate(
+ "YYYY-MM-DD"
+ ).withDecisionMakers(
+ Arrays.asList(
+ "John Doe",
+ "Romain Rochegude"
+ )
+ ).withConsulted(
+ Arrays.asList(
+ "John Doe",
+ "Romain Rochegude"
+ )
+ ).withInformed(
+ Arrays.asList(
+ "John Doe",
+ "Romain Rochegude"
+ )
+ )
+ )
+ ).withDecisionDrivers(
+ Arrays.asList(
+ "{decision driver 1, e.g., a force, facing concern, ...}",
+ "{decision driver 2, e.g., a force, facing concern, ...}"
+ )
+ ).withConsequences(
+ Arrays.asList(
+ "Good, because {positive consequence, e.g., improvement of one or more desired qualities, ...}",
+ "Bad, because {negative consequence, e.g., compromising one or more desired qualities, ...}"
+ )
+ ).withConfirmation(
+ "{Describe how the implementation / compliance of the ADR can/will be confirmed. Is there any automated or manual fitness function? If so, list it and explain how it is applied. Is the chosen design and its implementation in line with the decision? E.g., a design/code review or a test with a library such as ArchUnit can help validate this. Note that although we classify this element as optional, it is included in many ADRs.}"
+ ).withOptionProsAndCons(
+ Arrays.asList(
+ new MdOptionProsAndCons(
+ new SimpleOptionProsAndCons(
+ "{title of option 1}",
+ Arrays.asList(
+ "Good, because {argument a}",
+ "Good, because {argument b}",
+ "Neutral, because {argument c}",
+ "Bad, because {argument d}"
+ )
+ ).withDescription("{description}").withExample("{example}")
+ ),
+ new MdOptionProsAndCons(
+ new SimpleOptionProsAndCons(
+ "{title of other option}",
+ Arrays.asList(
+ "Good, because {argument a}",
+ "Good, because {argument b}",
+ "Neutral, because {argument c}",
+ "Bad, because {argument d}"
+ )
+ ).withDescription("{description}").withExample("{example}")
+ )
+ )
+ ).withMoreInformation(
+ "{You might want to provide additional evidence/confidence for the decision outcome here and/or document the team agreement on the decision and/or define when/how this decision the decision should be realized and if/when it should be re-visited. Links to other decisions and resources might appear here as well.}"
+ )
+ )
+ );
+ }
+}
diff --git a/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/ExpectedExampleAdr.java b/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/ExpectedExampleAdr.java
new file mode 100644
index 0000000000..0562e76fc1
--- /dev/null
+++ b/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/ExpectedExampleAdr.java
@@ -0,0 +1,29 @@
+package com.tngtech.archunit.library.adr.markdown;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.stream.Collectors;
+
+public final class ExpectedExampleAdr {
+ private final String resource;
+
+ public ExpectedExampleAdr(final String resource) {
+ this.resource = resource;
+ }
+
+ @Override
+ public String toString() {
+ try (final InputStream is = getClass().getClassLoader().getResourceAsStream(this.resource)) {
+ assert is != null;
+ return new BufferedReader(
+ new InputStreamReader(is)
+ ).lines().collect(
+ Collectors.joining("\n")
+ );
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/MdAdrTest.java b/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/MdAdrTest.java
new file mode 100644
index 0000000000..eb146a4290
--- /dev/null
+++ b/archunit/src/test/java/com/tngtech/archunit/library/adr/markdown/MdAdrTest.java
@@ -0,0 +1,17 @@
+package com.tngtech.archunit.library.adr.markdown;
+
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.core.IsEqual;
+import org.junit.jupiter.api.Test;
+
+class MdAdrTest {
+ @Test
+ void testMdGeneration() {
+ MatcherAssert.assertThat(
+ new ExampleAdr().toString(),
+ new IsEqual<>(
+ new ExpectedExampleAdr("data/expected_example_adr.md").toString()
+ )
+ );
+ }
+}
diff --git a/archunit/src/test/resources/data/expected_example_adr.md b/archunit/src/test/resources/data/expected_example_adr.md
new file mode 100644
index 0000000000..a85bd92f5c
--- /dev/null
+++ b/archunit/src/test/resources/data/expected_example_adr.md
@@ -0,0 +1,65 @@
+---
+status: accepted
+date: YYYY-MM-DD
+decision-makers: John Doe, Romain Rochegude
+consulted: John Doe, Romain Rochegude
+informed: John Doe, Romain Rochegude
+---
+
+# {short title, representative of solved problem and found solution}
+
+## Context and Problem Statement
+
+{Describe the context and problem statement, e.g., in free form using two to three sentences or in the form of an illustrative story. You may want to articulate the problem in form of a question and add links to collaboration boards or issue management systems.}
+
+## Decision Drivers
+
+* {decision driver 1, e.g., a force, facing concern, ...}
+* {decision driver 2, e.g., a force, facing concern, ...}
+
+## Considered Options
+
+* {title of option 1}
+* {title of option 2}
+* {title of option 3}
+
+## Decision Outcome
+
+Chosen option: "{title of option 1}", because {justification. e.g., only option, which meets k.o. criterion decision driver | which resolves force {force} | ... | comes out best (see below)}.
+
+### Consequences
+
+* Good, because {positive consequence, e.g., improvement of one or more desired qualities, ...}
+* Bad, because {negative consequence, e.g., compromising one or more desired qualities, ...}
+
+### Confirmation
+
+{Describe how the implementation / compliance of the ADR can/will be confirmed. Is there any automated or manual fitness function? If so, list it and explain how it is applied. Is the chosen design and its implementation in line with the decision? E.g., a design/code review or a test with a library such as ArchUnit can help validate this. Note that although we classify this element as optional, it is included in many ADRs.}
+
+## Pros and Cons of the Options
+
+### {title of option 1}
+
+{description}
+
+{example}
+
+* Good, because {argument a}
+* Good, because {argument b}
+* Neutral, because {argument c}
+* Bad, because {argument d}
+
+### {title of other option}
+
+{description}
+
+{example}
+
+* Good, because {argument a}
+* Good, because {argument b}
+* Neutral, because {argument c}
+* Bad, because {argument d}
+
+## More Information
+
+{You might want to provide additional evidence/confidence for the decision outcome here and/or document the team agreement on the decision and/or define when/how this decision the decision should be realized and if/when it should be re-visited. Links to other decisions and resources might appear here as well.}
\ No newline at end of file