diff --git a/src/main/java/io/moderne/devcenter/DevCenter.java b/src/main/java/io/moderne/devcenter/DevCenter.java
index 8b363c6..5ca4ba1 100644
--- a/src/main/java/io/moderne/devcenter/DevCenter.java
+++ b/src/main/java/io/moderne/devcenter/DevCenter.java
@@ -15,6 +15,8 @@
*/
package io.moderne.devcenter;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import io.moderne.devcenter.table.SecurityIssues;
import io.moderne.devcenter.table.UpgradesAndMigrations;
import lombok.EqualsAndHashCode;
@@ -29,6 +31,7 @@
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
@@ -122,6 +125,55 @@ public Card getCard(String name) {
throw new IllegalArgumentException("No card found with name: " + name);
}
+ /**
+ * Returns a stable JSON description of this DevCenter's structure for
+ * cross-classloader consumption by tools (e.g. the Moderne CLI). The
+ * format carries an {@code apiVersion} so consumers can detect schema
+ * compatibility. Schema (v1):
+ *
{@code
+ * {
+ * "apiVersion": "v1",
+ * "upgradesAndMigrations": [
+ * {"name": "...", "fixRecipeId": "...", "measures": ["...", ...]},
+ * ...
+ * ],
+ * "security": {"name": "...", "fixRecipeId": "...", "measures": [...]} | null
+ * }
+ * }
+ * Card and measure ordering is preserved.
+ */
+ public String getSpec() {
+ Map spec = new LinkedHashMap<>();
+ spec.put("apiVersion", "v1");
+
+ List