diff --git a/.idea/modules.xml b/.idea/modules.xml
index b8d8fc8f0481..63ba8a827487 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -10,6 +10,7 @@
+
diff --git a/build/bazel-generated-file-list.txt b/build/bazel-generated-file-list.txt
index b744f8606c68..8aa52101a965 100644
--- a/build/bazel-generated-file-list.txt
+++ b/build/bazel-generated-file-list.txt
@@ -227,6 +227,7 @@ fleet/junit4
fleet/kernel
fleet/ktor/network/tls
fleet/lsp.protocol
+fleet/modules/api
fleet/multiplatform.shims
fleet/preferences
fleet/reporting/api
diff --git a/fleet/modules/api/BUILD.bazel b/fleet/modules/api/BUILD.bazel
new file mode 100644
index 000000000000..d5f5633f0041
--- /dev/null
+++ b/fleet/modules/api/BUILD.bazel
@@ -0,0 +1,21 @@
+### auto-generated section `build fleet.modules.api` start
+load("//build:compiler-options.bzl", "create_kotlinc_options")
+load("@rules_jvm//:jvm.bzl", "jvm_library")
+
+create_kotlinc_options(
+ name = "custom_api",
+ x_consistent_data_class_copy_visibility = True,
+ x_context_parameters = True,
+ x_jvm_default = "all-compatibility",
+ x_lambdas = "class"
+)
+
+jvm_library(
+ name = "api",
+ module_name = "fleet.modules.api",
+ visibility = ["//visibility:public"],
+ srcs = glob(["srcCommonMain/**/*.kt", "srcCommonMain/**/*.java", "srcCommonMain/**/*.form"], allow_empty = True, exclude = ["**/module-info.java"]),
+ kotlinc_opts = ":custom_api",
+ deps = ["@lib//:kotlin-stdlib"]
+)
+### auto-generated section `build fleet.modules.api` end
\ No newline at end of file
diff --git a/fleet/modules/api/fleet.modules.api.iml b/fleet/modules/api/fleet.modules.api.iml
new file mode 100644
index 000000000000..cee02d3dac9b
--- /dev/null
+++ b/fleet/modules/api/fleet.modules.api.iml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/fleet/modules/api/gradlebuild/build.gradle.kts b/fleet/modules/api/gradlebuild/build.gradle.kts
new file mode 100644
index 000000000000..14b3f5f5f828
--- /dev/null
+++ b/fleet/modules/api/gradlebuild/build.gradle.kts
@@ -0,0 +1,58 @@
+// IMPORT__MARKER_START
+import fleet.buildtool.conventions.configureAtMostOneJvmTargetOrThrow
+import fleet.buildtool.conventions.withJavaSourceSet
+// IMPORT__MARKER_END
+plugins {
+ alias(libs.plugins.kotlin.multiplatform)
+ id("fleet.project-module-conventions")
+ id("fleet.toolchain-conventions")
+ id("fleet.module-publishing-conventions")
+ id("fleet.sdk-repositories-publishing-conventions")
+ id("fleet.open-source-module-conventions")
+ alias(libs.plugins.dokka)
+ // GRADLE_PLUGINS__MARKER_START
+ id("fleet-module")
+ // GRADLE_PLUGINS__MARKER_END
+}
+
+fleetModule {
+ module {
+ name = "fleet.modules.api"
+ importedFromJps {}
+ }
+}
+
+@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
+kotlin {
+ // KOTLIN__MARKER_START
+ compilerOptions.freeCompilerArgs = listOf(
+ "-Xlambdas=class",
+ "-Xconsistent-data-class-copy-visibility",
+ "-Xcontext-parameters",
+ "-XXLanguage:+AllowEagerSupertypeAccessibilityChecks",
+ )
+ jvm {}
+ wasmJs {
+ browser {}
+ }
+ sourceSets.commonMain.configure { kotlin.srcDir(layout.projectDirectory.dir("../srcCommonMain")) }
+ sourceSets.commonMain.configure { resources.srcDir(layout.projectDirectory.dir("../resourcesCommonMain")) }
+ sourceSets.commonTest.configure { kotlin.srcDir(layout.projectDirectory.dir("../srcCommonTest")) }
+ sourceSets.commonTest.configure { resources.srcDir(layout.projectDirectory.dir("../resourcesCommonTest")) }
+ sourceSets.jvmMain.configure { kotlin.srcDir(layout.projectDirectory.dir("../srcJvmMain")) }
+ configureAtMostOneJvmTargetOrThrow { compilations.named("main") { withJavaSourceSet { javaSourceSet -> javaSourceSet.java.srcDir(layout.projectDirectory.dir("../srcJvmMain")) } } }
+ sourceSets.jvmMain.configure { resources.srcDir(layout.projectDirectory.dir("../resourcesJvmMain")) }
+ sourceSets.jvmTest.configure { kotlin.srcDir(layout.projectDirectory.dir("../srcJvmTest")) }
+ configureAtMostOneJvmTargetOrThrow { compilations.named("test") { withJavaSourceSet { javaSourceSet -> javaSourceSet.java.srcDir(layout.projectDirectory.dir("../srcJvmTest")) } } }
+ sourceSets.jvmTest.configure { resources.srcDir(layout.projectDirectory.dir("../resourcesJvmTest")) }
+ sourceSets.wasmJsMain.configure { kotlin.srcDir(layout.projectDirectory.dir("../srcWasmJsMain")) }
+ sourceSets.wasmJsMain.configure { resources.srcDir(layout.projectDirectory.dir("../resourcesWasmJsMain")) }
+ sourceSets.wasmJsTest.configure { kotlin.srcDir(layout.projectDirectory.dir("../srcWasmJsTest")) }
+ sourceSets.wasmJsTest.configure { resources.srcDir(layout.projectDirectory.dir("../resourcesWasmJsTest")) }
+ sourceSets.commonMain.dependencies {
+ implementation(jps.org.jetbrains.kotlin.kotlin.stdlib1993400674.get().let { "${it.group}:${it.name}:${it.version}" }) {
+ exclude(group = "org.jetbrains", module = "annotations")
+ }
+ }
+ // KOTLIN__MARKER_END
+}
\ No newline at end of file
diff --git a/fleet/modules/api/srcCommonMain/.pseudoCommonKotlinSourceSet b/fleet/modules/api/srcCommonMain/.pseudoCommonKotlinSourceSet
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModule.kt b/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModule.kt
new file mode 100644
index 000000000000..f5b45a8b72bb
--- /dev/null
+++ b/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModule.kt
@@ -0,0 +1,16 @@
+package fleet.modules.api
+
+import kotlin.reflect.KClass
+
+interface FleetModule {
+ val name: String
+ val layer: FleetModuleLayer
+
+ @Deprecated("Get rid of it as soon as we drop entities auto-registration")
+ fun getEntityTypeProvider(providerName: String): Any?
+
+ fun getResource(path: String): ByteArray?
+
+ fun findServices(service: KClass, requestor: KClass<*>): Iterable
+}
+
diff --git a/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleInfo.kt b/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleInfo.kt
new file mode 100644
index 000000000000..a5f12117402b
--- /dev/null
+++ b/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleInfo.kt
@@ -0,0 +1,6 @@
+package fleet.modules.api
+
+sealed interface FleetModuleInfo {
+ data class WithDescriptor(val serializedModuleDescriptor: String, val path: String) : FleetModuleInfo
+ data class Path(val path: String) : FleetModuleInfo
+}
\ No newline at end of file
diff --git a/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleLayer.kt b/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleLayer.kt
new file mode 100644
index 000000000000..af211cbd24be
--- /dev/null
+++ b/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleLayer.kt
@@ -0,0 +1,11 @@
+package fleet.modules.api
+
+import kotlin.reflect.KClass
+
+interface FleetModuleLayer {
+ val modules: Set
+
+ fun findModule(name: String): FleetModule?
+
+ fun findServices(service: KClass, requestor: KClass<*>): Iterable
+}
\ No newline at end of file
diff --git a/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleLayerLoader.kt b/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleLayerLoader.kt
new file mode 100644
index 000000000000..d87ff9542ead
--- /dev/null
+++ b/fleet/modules/api/srcCommonMain/fleet/modules/api/FleetModuleLayerLoader.kt
@@ -0,0 +1,5 @@
+package fleet.modules.api
+
+fun interface FleetModuleLayerLoader {
+ fun moduleLayer(parentLayers: List, modulePath: Set): FleetModuleLayer
+}
\ No newline at end of file