Merge pull request #44 from tjwatson/readme

Readme
diff --git a/README.md b/README.md
index dd1f087..34b1a98 100644
--- a/README.md
+++ b/README.md
@@ -2,32 +2,242 @@
 
 Atomos - A Java Module Runtime using OSGi Connect
 
-Atomos requires an OSGi Framework implementation that supports the OSGi Connect Specification. The Connect Specification is part of the OSGi Core Release 8 Specification which is currently available as a proposed final draft [here](https://docs.osgi.org/specification/osgi.core/8.0.0/). The Connect Specification can be found in chapter [60](https://docs.osgi.org/specification/osgi.core/8.0.0/framework.connect.html).
+With the release of [OSGi Core Release 8](https://docs.osgi.org/specification/osgi.core/8.0.0/), the [Connect](https://docs.osgi.org/specification/osgi.core/8.0.0/framework.connect.html) Specification enables OSGi frameworks to be extended to support environments not previously possible in a standard way. Atomos uses the Connect specification to extend the use of the OSGi framework into many different environments.
 
-Currently snapshots of the Equinox and Felix OSGi Frameworks are being used that implement the proposed OSGi Connect specification. Source for the snapshots can be found at:
-1. Equinox - The `master` branch in the git repo https://git.eclipse.org/c/equinox/rt.equinox.framework.git
-1. Felix - https://github.com/apache/felix-dev/tree/connect
+# Examples
 
-The snapshot JARs and source JARs are pushed to https://github.com/tjwatson/atomos-temp-m2repo for Atomos. The Atomos build is currently configured to use this as a repository for getting the OSGi Framework implementations: https://github.com/tjwatson/atomos-temp-m2repo/raw/master/repository
+A number of example projects are contained in the Atomos git repository under the folder `atomos.examples`. 
 
-Atomos is an implementation of an OSGi `ModuleConnector` which is defined by the Connect specification. A `ModuleConnector` can be used to create an OSGi Framework instance that allows a Framework to connect bundles installed in the framework to content managed outside of the Framework. Framework instances created with the Atomos `ModuleConnector` add support to the OSGi Framework that enables bundles to be connected to four different sources of content from outside the OSGi module layer:
+1. Run from the [class path](atomos.examples/atomos.examples.springloader/README.md)
+1. Run from the module path with [jlink](atomos.examples/atomos.examples.jlink/README.md)
+1. Run with a [native image](atomos.examples/atomos.examples.substrate.maven/README.md)
 
-1. Module Path:  Using the Java Platform Module System (JPMS) Atomos will discover the modules on the module path and will make any modules found available for installation into the Framework as connected bundles.  This also allows for Atomos and a set of OSGi bundles to be packaged into a jlink image resulting in a small fit-for-purpose JVM.
-1. Class Path:  When loaded from the class path Atomos will discover the JARs on the class path and will make any OSGi bundles found available for installation into the Framework.
+See Atomos examples [README](atomos.examples/README.md) for more information.
+
+# Module Path and Class Path Usage
+
+Two simple ways to use Atomos is with the flat class path or the module path. Typically an OSGi framework requires complete control over loading classes and resources out of bundles. This allows the framework to provide the isolation defined by the OSGi specification through the use of its own class loader implementation. For example, only allowing a bundle to load classes and resources which are either local to the bundle or imported with the `Import-Package` or `Require-Bundle` header. Using Atomos with the module path or the class path takes that control away from the framework and delegates it to the class loader implementation provided by the JVM for the module path or class path. This will result in different behavior with respect to class loading which may reduce the level of isolation enforced at runtime. This is particularly true when using the class path. Use of the module path will use the enforcement rules of the Java Platform Module System (JPMS), which has some differences with the OSGi Module Layer.
+
+The `Atomos` class provides a convenient way to launch an OSGi framework implementation with support for the module path or the class path. For example, to load all bundles included in a directory called `bundles` the following `java` command can be run using the class path:
+
+`java -cp "bundles/*" org.apache.felix.atomos.Atomos`
+
+The following `java` command can be run using the module path:
+
+`java -p bundles -m org.apache.felix.atomos`
+
+In both cases Atomos will discover all the JARs contained in the `bundles/` directory.  For each bundle JAR included in `bundles/` the launcher will install and start each bundle in an OSGi framework instance. The bundles are loaded using the class loader provided by the JVM itself. In this case the framework is not in control of the class loading for the bundles contained on the class path or the module path. 
+
+Atomos requires a compliant OSGi R8 framework implementation. In addition, when running on the module path, Atomos requires a module named `osgi.core` to represent the framework implementation. Atomos provides two `osgi.core` modules to represent Equinox (`org.apache.felix.atomos:osgi.core:8.0.0:jar:AtomosEquinox`) and Felix (`org.apache.felix.atomos:osgi.core:8.0.0:jar:AtomosFelix`). One of these modules along with the corresponding framework implementation JAR (`org.eclipse.osgi` or `org.apache.felix.framework`) need to be included on the module path.
+
+For example, consider a `bundles/` folder containing the necessary bundles to run the Gogo console:
+
+```
+jline-3.13.3.jar
+org.apache.felix.atomos-1.0.0.jar
+org.apache.felix.gogo.command-1.1.2.jar
+org.apache.felix.gogo.jline-1.1.8.jar
+org.apache.felix.gogo.runtime-1.1.4.jar
+org.eclipse.osgi-3.16.100.jar
+osgi.core-8.0.0-AtomosEquinox.jar
+```
+The JARs `osgi.core-8.0.0-AtomosEquinox.jar` and `org.eclipse.osgi-3.16.100.jar` provide the framework implementation for Equinox.  When running on Java 11 or higher, regardless of using the class path or module path, Atomos will discover the available modules from the boot layer and represent them as bundles in the framework. For example, running `java -p bundles -m org.apache.felix.atomos` on the above `bundles/` folder will get you this result for the Gogo `lb -s` command:
+
+```
+g! lb -s
+START LEVEL 1
+   ID|State      |Level|Symbolic name
+    0|Active     |    0|org.eclipse.osgi (3.16.100.v20201030-1916)|3.16.100.v20201030-1916
+    1|Active     |    1|java.base (11.0.8)|11.0.8
+    2|Active     |    1|java.compiler (11.0.8)|11.0.8
+    3|Active     |    1|java.datatransfer (11.0.8)|11.0.8
+    4|Active     |    1|java.desktop (11.0.8)|11.0.8
+   ...
+   71|Active     |    1|org.apache.felix.atomos (1.0.0)|1.0.0
+   72|Active     |    1|org.apache.felix.gogo.command (1.1.2)|1.1.2
+   73|Active     |    1|org.apache.felix.gogo.jline (1.1.8)|1.1.8
+   74|Active     |    1|org.apache.felix.gogo.runtime (1.1.4)|1.1.4
+   75|Active     |    1|org.jline (3.13.3)|3.13.3
+   76|Active     |    1|osgi.core (0.0.0)|0.0.0
+```
+
+Running with the module path will load all modules discovered within the `bundles/` folder and the JVM modules in the boot layer as bundles in the framework. This is true even for modules that do not contain an OSGi bundle manifest. Running with `java -cp "bundles/*" org.apache.felix.atomos.Atomos` will produce nearly identical results with the exception that the `osgi.core` module will not be installed. This is because the `osgi.core` module from Atomos does not contain a bundle manifest and therefore it is not recognized as something to represent as a bundle in the framework. Only the modules contained in the boot layer will be represented as bundles installed in the framework when using the class path.
+
+Atomos currently can support Java 8 as well which does not have support for the module path. When using Java 8, the module path mode is not available.
+
+# Connecting Content
+
+The OSGi Connect specification allows an implementation of a [ModuleConnector](https://docs.osgi.org/javadoc/osgi.core/8.0.0/org/osgi/framework/connect/ModuleConnector.html) to be used to create a new framework instance with the [ConnectFrameworkFactory.newFramework](https://docs.osgi.org/javadoc/osgi.core/8.0.0/org/osgi/framework/connect/ConnectFrameworkFactory.html#newFramework-java.util.Map-org.osgi.framework.connect.ModuleConnector-) method.
+
+Atomos provides a `ModuleConnector` that adds support to enable bundles to be connected to four different sources of content:
+
+1. Module Path:  Using the Java Platform Module System (JPMS) Atomos will discover the modules on the module path and will make any modules found available for installation into the framework as bundles.  This also allows for Atomos and a set of bundles to be packaged into a jlink image resulting in a small fit-for-purpose JVM.
+1. Class Path:  When loaded from the class path Atomos will discover the JARs on the class path and will make any bundles found available for installation into the framework.
 1. Graal Substrate Native Image:  When compiled into a Substrate native image Atomos will discover the bundles that were included into the image.  This requires configuration to enable the necessary reflection for things like bundle activators and declarative service components.
-1. Atomos Bundle Index: Allows a single executable JAR to contain multiple bundles.  The bundles included in the executable JAR have their resources indexed to allow for duplicate resource names to be included in each bundle.  For example, the `META-INF/MANIFEST.MF` bundle manifest file.
+1. Atomos Bundle Index: Allows a single executable JAR to contain multiple bundles.  The bundles included in the executable JAR have their resources indexed to allow for duplicate resource names to be included in each bundle.  For example, the `META-INF/MANIFEST.MF` bundle manifest file. One usecase for the bundle index is in the creation Android applications.
 
+# Atomos API
+
+The `Atomos` class provides convenient methods to create and launch an OSGi framework implementation with Atomos support. The `main` method can be used to discover, install and start all the bundles found into a framework instance. In some scenarios more control is necessary to configure the framework and its set of installed bundles. The `Atomos` class allows more control over the configuration, bundle installation and launching of the framework instance.
+
+## Creating A Framework
+
+Atomos provides a [ModuleConnector](https://docs.osgi.org/javadoc/osgi.core/8.0.0/org/osgi/framework/connect/ModuleConnector.html)
+implemenation that can be used to create a [Framework](https://docs.osgi.org/javadoc/osgi.core/8.0.0/org/osgi/framework/Framework.html) instance. The following is an example of how to use a [ConnectFrameworkFactory](https://docs.osgi.org/javadoc/osgi.core/8.0.0/org/osgi/framework/connect/ConnectFrameworkFactory.html) to create a framework instance that uses Atomos:
+
+```java
+     ServiceLoader<ConnectFrameworkFactory> loader = ServiceLoader.load(ConnectFrameworkFactory.class);
+     ConnectFrameworkFactory factory = loader.findFirst().get();
+     Framework framework = factory.newFramework(
+                               Map.of(
+                                  Constants.FRAMEWORK_SYSTEMPACKAGES, ""),
+                               AtomosRuntime.newAtomos().getModuleConnector())
+```
+
+The framework must be configured with `org.osgi.framework.system.packages=""` when running on Java 9+ to configure the `system.bundle` to not export any of the packages provided by the JVM boot layer. Alternatively, a framework can be constructed using the `Atomos.newFramework` method like the following:
+
+```java
+     Framework framework = Atomos.newAtomos().newFramework(Map.of());
+```
+
+In this case the `org.osgi.framework.system.packages` configuration will be set appropriately for the running Java version. In most all cases the `Atomos.newFramework` method can be used.
+
+When the framework is initialized Atomos will install and start all bundles that have been discovered by default. To disable starting the bundles on framework initialization the `atomos.content.start` framework configuration property can be used:
+
+```java
+     Framework framework = Atomos.newAtomos().newFramework(Map.of("atomos.content.start", "false"));
+```
+
+To disable installing the bundles on framework initialization the `atomos.content.install` framework configuration property can be used:
+
+```java
+     Framework framework = Atomos.newAtomos().newFramework(Map.of("atomos.content.install", "false"));
+```
+## Installing Bundles
+
+Special handling is needed to install content discovered by Atomos as bundles in a framework. Atomos has layers which are used to contain content it discovers.  For example, the modules on the module path or the JARs on the class path are considered content. When an `Atomos` instance is created it discovers the available content in the environment it is running (e.g. the module path or class path).  This initial content is placed into an `AtomosLayer` that is called the boot layer. Each content that is discovered is represented by an `AtomosContent` instance. An `AtomosContent` can be used to install a connected bundle.
+
+### Connected Bundles
+
+As mentioned, `AtomosContent` is contained with an `AtomosLayer`. The following code can be used to install and start all the content discovered by Atomos from the boot layer:
+
+```java
+    Atomos atomos = Atomos.newAtomos();
+    // Set atomos.content.install to false to prevent automatic bundle installation
+    Framework framework = atomos.newFramework(Map.of("atomos.content.install", "false"));
+    // framework must be initialized before any bundles can be installed
+    framework.init();
+    List<Bundle> bundles = new ArrayList<>();
+    for (AtomosContent content: atomos.getBootLayer().getAtomosContents()) {
+        // The parameter to install is a prefix that will be used for the bundle
+        // location Atomos designates for the installed bundle.  If null
+        // is used then the prefix of "atomos" is used.
+        bundles.add(content.install(null));
+    }
+    for (Bundle b : bundles) {
+        b.start();
+    }
+    // The installed bundles will not actually activate until the framework is started
+    framework.start();
+```
+
+This allows for control over what gets exposed as a bundle from the discovered Atomos content.  An alternative to using the `AtomosContent.install` method is to use a `BundleContext` to install the bundles. Before this can be done the `AtomosContent` must be connected with the bundle location that will be used to install the bundle. The following code can be used to do that instead:
+
+```java
+    Atomos atomos = Atomos.newAtomos();
+    // Set atomos.content.install to false to prevent automatic bundle installation
+    Framework framework = atomos.newFramework(Map.of("atomos.content.install", "false"));
+    // framework must be initialized before any bundles can be installed
+    framework.init();
+    BundleContext systemContext = framework.getBundleContext();
+    List<Bundle> bundles = new ArrayList<>();
+    Random random = new Random();
+    for (AtomosContent content: atomos.getBootLayer().getAtomosContents()) {
+        String location = String.valueOf(new Random().nextLong()) + "-location";
+        // Connect the content to a specific location.
+        content.connect(location);
+        // Use the same location to install the bundle.
+        // Note that an input stream cannot be provided for installing connected bundles,
+        // only the location string can be used.
+        bundles.add(systemContext.installBundle(location));
+    }
+    for (Bundle b : bundles) {
+        b.start();
+    }
+    // The installed bundles will not actually activate until the framework is started
+    framework.start();
+```
+
+This allows for complete control over the bundle location string used to install the bundles.
+
+### Standard Bundles
+
+Bundles may be installed which are not contained in an `AtomosLayer`. This is done by using one of the [BundleContext.install](https://docs.osgi.org/javadoc/osgi.core/8.0.0/org/osgi/framework/BundleContext.html#installBundle-java.lang.String-) methods using a location string which has not been connected with an `AtomosContent`. In this case the bundle class loading and resource access is under the complete control of the framework. Standard bundles may depend on any other bundles installed in the framework, including the connected bundles contained in an `AtomosLayer`. However, bundles contained in an `AtomosLayer` cannot depend on standard bundles.
+
+## Adding Layers
+
+When running on Java 9+ additional JPMS layers can be added and removed dynamically using the `AtomosLayer` API. An `AtomosLayer` is added as a child layer to one or more existing `AtomosLayer` instances. The following can be used to install two different sibling layers as a child of the boot layer:
+
+```java
+    Atomos atomos = Atomos.newAtomos();
+    AtomosLayer bootLayer = atomos.getBootLayer();
+
+    // Add a layer that loads all modules contained in "modules-child1" directory
+    Path modulesChild1 = new File("modules-child1").toPath();
+    AtomosLayer child1 = bootLayer.addLayer("child1", LoaderType.SINGLE, modulesChild1);
+
+    // Add a layer that loads all modules contained in "modules-child1" directory
+    Path modulesChild2 = new File("modules-child2").toPath();
+    AtomosLayer child2 = bootLayer.addLayer("child2", LoaderType.SINGLE, modulesChild2);
+
+    // Create a new framework to use the layers configured with Atomos
+    Framework framework = atomos.newFramework(Map.of());
+    // Starting the framework will automatically install and start the content from all
+    // Atomos layers known.  This will include the content in child1 and child2.
+    // The "atomos.content.install" configuration can be used to disable that.
+    framework.start();
+
+    // stopping the framework will persist the added layers in the framework storage area
+    framework.stop();
+```
+
+A layer can be added before or after creating and starting the framework instance with Atomos. If added before initializing the framework then all of the known layers configured with Atomos will have their bundles installed and started according to the `atomos.content.install` framework configuration setting.
+
+When adding a layer there is a choice of the loader type.  This refers to the class loader behavior.  Atomos has three different loader types available.
+
+1. `SINGLE` - All modules in the layer will be loaded with a single class loader
+1. `MANY` - All modules in the layer will get their own individual class loader
+1. `OSGI` - All modules in the layer will get their own individual class loader that behaves the same as `MANY` except the class loader will implement the `BundleReference` interface.
+
+Once a layer is added the content can be installed just like the example above with the boot layer.  When a framework is initialized, the storage area for the framework will be used to save the layer information to persistent storage.  When the framework is created again, using the same framework storage location, the Atomos layers will be loaded back into Atomos.
+
+A layer can be dynamically uninstalled using the AtomosLayer.uninstall() method. This will result in the layer and all of its children layers being removed from Atomos.  Any bundles that are installed from the removed layers will also be uninstalled from the framework.
+
+It is possible to get the `Module` that backs an `AtomosContent` by calling the method `AtomosContent.adapt(Module.class)`.  Similarly it is possible to get the `ModuleLayer` that backs an `AtomosLayer` by calling the method `AtomosLayer.adapt(ModuleLayer.class)`.
+
+The examples above demostrate the commonly used hierarchy with single parent layers. More advanced scenarios that require multi-parent layers must use the `Atomos.addLayer(List<AtomosLayer>, String, LoaderType, Path...)` method instead of the `AtomosLayer.addLayer` method.
+
+## OSGi Capability Resolution and Service Visibility
+
+When running Atomos on the module path the class loading rules are defined by the Java Platform Module System (JPMS). This implies that there is a resolution step done within JPMS when configuring the `ModuleLayer` that backs the `AtomosLayer`. When an OSGi bundle is connected to `AtomosContent`, the framework will attempt to resolve the bundle within the framework as well. The resolution done by JPMS for the modules contained in an `AtomosLayer` will influence how the bundle connected to the JPMS module will resolve within the OSGi framework.
+
+### OSGi Bundle Resolution
+
+The OSGi bundles that are connected to `AtomosContent` located in a JPMS layer will resolve against capabilities for the namespaces `osgi.wiring.package`  and `osgi.wiring.bundle` according the behavior of the `java.lang.Module.canRead(Module)` method.  All other namespaces are resolved against capabilities provided by modules within the same layer or modules contained in the parent layer hierarchy. This implies that the requirements for an AtomosContent bundle cannot be resolved against capabilities from standard installed bundles or from bundles contained in child or peer layers.
+
+### OSGi Service Visibility
+
+The service availability in the OSGi service registry is not influenced by the layer hierarchy. Standard bundles are able to use OSGi services registered by connected bundles and vise versa as long as the consumer and producer bundles are using the same source for the service package.  There is no additional isolation of OSGi services between the different layers in Atomos.
 
 # Build
 
-Java 11 or higher must be used to build Atomos.  Atomos build uses the 1.0.0.Beta2 version of the moditect plugin (https://github.com/moditect/moditect.git). This plugin provides some utilities for adding module-infos to existing dependency JARs and building `jlink` images.  You can build the Atomos with the following:
+Java 11 or higher must be used to build Atomos.  Atomos build uses the 1.0.0.RC1 version of the moditect plugin (https://github.com/moditect/moditect.git). This plugin provides some utilities for adding module-infos to existing dependency JARs and building `jlink` images.  You can build the Atomos with the following:
 
 `./mvnw clean install -Pjava8 -Pequinox`
 
-Or if you want to use the Felix Framework
+Or if you want to use the Felix framework
 
 `./mvnw clean install -Pjava8 -Pfelix`
 
-If you build with no profile specified then the default will build with Equinox and the resulting Atomos runtime will only work with Java 11+. The build also includes a number of example projects that demonstrate how Atomos can be used in different modes. The Graal Substrate native-image examples are not built by default. For information on how to build the native-image examples see the substrate [README](atomos.examples/SUBSTRATE.md)
+To build you must specify one of the framework implementation profiles (`equinox` or `felix`). If you build without the `java8` profile then the resulting Atomos runtime will only work with Java 11+. The build also includes a number of example projects that demonstrate how Atomos can be used in different modes. The Graal Substrate native-image examples are not built by default. For information on how to build the native-image examples see the substrate [README](atomos.examples/SUBSTRATE.md)
 
-For more information on each example see Atomos examples [README](atomos.examples/README.md)
diff --git a/atomos.examples/atomos.examples.android/app/src/main/java/org/apache/felix/atomos/examples/android/MainActivity.java b/atomos.examples/atomos.examples.android/app/src/main/java/org/apache/felix/atomos/examples/android/MainActivity.java
index 66f0480..88d5e8a 100644
--- a/atomos.examples/atomos.examples.android/app/src/main/java/org/apache/felix/atomos/examples/android/MainActivity.java
+++ b/atomos.examples/atomos.examples.android/app/src/main/java/org/apache/felix/atomos/examples/android/MainActivity.java
@@ -13,7 +13,7 @@
  */
 package org.apache.felix.atomos.examples.android;
 
-import static org.apache.felix.atomos.launch.AtomosLauncher.getConfiguration;
+import static org.apache.felix.atomos.Atomos.getConfiguration;
 
 import androidx.appcompat.app.AppCompatActivity;
 
@@ -23,7 +23,7 @@
 import android.widget.TextView;
 
 
-import org.apache.felix.atomos.launch.AtomosLauncher;
+import org.apache.felix.atomos.Atomos;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.launch.Framework;
@@ -67,8 +67,7 @@
                                         } else {
                                             setText("Starting Atomos!\n", output);
                                         }
-
-                                        f = AtomosLauncher.launch(getConfiguration(args));
+                                        f = Atomos.newAtomos().newFramework(getConfiguration(args));
                                         return f;
                                     } catch (InterruptedException | BundleException e) {
                                         throw new RuntimeException(e);
diff --git a/atomos.examples/atomos.examples.index/README.md b/atomos.examples/atomos.examples.index/README.md
index 60473dc..e8c1278 100644
--- a/atomos.examples/atomos.examples.index/README.md
+++ b/atomos.examples/atomos.examples.index/README.md
@@ -2,7 +2,7 @@
 
 This example uses the `atomos-maven-plugin` to create an Atomos index. An Atomos index contains all the bundle entry resources of the bundles that are required by the example.  For this example the necessary bundles are included to have a functional Felix Gogo console and a Felix WebConsole.  The Atomos index can then be included into the final JAR along with all the required packages from all the bundles included in the JAR.
 
-This example uses `maven-assembly-plugin` to package all the dependent bundles into a single executable JAR which also includes the Atomos index. The Atomos launcher class `org.apache.felix.atomos.launch.AtomosLauncher` is used as the `main-class` for the executable JAR. If you introspect the JAR produced by this example you will notice it includes an `atomos/` folder which includes all the bundle entry resources for all the dependent bundles. This allows for duplicate bundle entry paths to be included in the JAR which Atomos can discover for each bundle included in the single JAR.
+This example uses `maven-assembly-plugin` to package all the dependent bundles into a single executable JAR which also includes the Atomos index. The Atomos class `org.apache.felix.atomos.Atomos` is used as the `main-class` for the executable JAR. If you introspect the JAR produced by this example you will notice it includes an `atomos/` folder which includes all the bundle entry resources for all the dependent bundles. This allows for duplicate bundle entry paths to be included in the JAR which Atomos can discover for each bundle included in the single JAR.
 
 The following command should produce a gogo shell prompt:
 
diff --git a/atomos.examples/atomos.examples.index/pom.xml b/atomos.examples/atomos.examples.index/pom.xml
index 370b2d4..62e746e 100644
--- a/atomos.examples/atomos.examples.index/pom.xml
+++ b/atomos.examples/atomos.examples.index/pom.xml
@@ -45,7 +45,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
             <exclusions>
                 <exclusion>
@@ -89,7 +89,7 @@
                         <configuration>
                             <transformers>
                                 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
-                                    <mainClass>org.apache.felix.atomos.launch.AtomosLauncher</mainClass>
+                                    <mainClass>org.apache.felix.atomos.Atomos</mainClass>
                                 </transformer>
                             </transformers>
                             <filters>
diff --git a/atomos.examples/atomos.examples.jaxrs/pom.xml b/atomos.examples/atomos.examples.jaxrs/pom.xml
index 3c7ee75..a721a48 100644
--- a/atomos.examples/atomos.examples.jaxrs/pom.xml
+++ b/atomos.examples/atomos.examples.jaxrs/pom.xml
@@ -55,7 +55,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
         <dependency>
@@ -164,8 +164,7 @@
                     <nativeImage>
                         <debug>true</debug>
                         <additionalInitializeAtBuildTime>
-                            <additionalInitializeAtBuildTime>org.apache.felix.atomos.runtime</additionalInitializeAtBuildTime>
-                            <additionalInitializeAtBuildTime>org.apache.felix.atomos.impl</additionalInitializeAtBuildTime>
+                            <additionalInitializeAtBuildTime>org.apache.felix.atomos</additionalInitializeAtBuildTime>
                             <additionalInitializeAtBuildTime>javax.servlet</additionalInitializeAtBuildTime>
                             <additionalInitializeAtBuildTime>org.apache.felix.service.command.Converter</additionalInitializeAtBuildTime>
                             <additionalInitializeAtBuildTime>org.eclipse.jetty.util.TypeUtil</additionalInitializeAtBuildTime>
@@ -227,7 +226,7 @@
                         <configuration>
                             <transformers>
                                 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
-                                    <mainClass>org.apache.felix.atomos.launch.AtomosLauncher</mainClass>
+                                    <mainClass>org.apache.felix.atomos.Atomos</mainClass>
                                 </transformer>
                             </transformers>
                             <filters>
diff --git a/atomos.examples/atomos.examples.jaxrs/reflectAgentConfig.json b/atomos.examples/atomos.examples.jaxrs/reflectAgentConfig.json
index b35ac69..0dee691 100644
--- a/atomos.examples/atomos.examples.jaxrs/reflectAgentConfig.json
+++ b/atomos.examples/atomos.examples.jaxrs/reflectAgentConfig.json
@@ -359,14 +359,14 @@
   "allPublicConstructors":true
 },
 {
-  "name":"org.apache.felix.atomos.impl.runtime.base.AtomosCommands"
+  "name":"org.apache.felix.atomos.impl.base.AtomosCommands"
 },
 {
-  "name":"org.apache.felix.atomos.impl.runtime.modules.AtomosRuntimeModules",
+  "name":"org.apache.felix.atomos.impl.modules.AtomosModules",
   "methods":[{"name":"<init>","parameterTypes":["java.util.Map"] }]
 },
 {
-  "name":"org.apache.felix.atomos.runtime.AtomosRuntime"
+  "name":"org.apache.felix.atomos.Atomos"
 },
 {
   "name":"org.apache.felix.gogo.command.Activator",
diff --git a/atomos.examples/atomos.examples.jaxrs/reflectConfig_felix_atomos.json b/atomos.examples/atomos.examples.jaxrs/reflectConfig_felix_atomos.json
index 9751c7a..efd1cd1 100644
--- a/atomos.examples/atomos.examples.jaxrs/reflectConfig_felix_atomos.json
+++ b/atomos.examples/atomos.examples.jaxrs/reflectConfig_felix_atomos.json
@@ -1,6 +1,6 @@
 [
    {
-    "name" : "org.apache.felix.atomos.impl.runtime.base.AtomosCommands",
+    "name" : "org.apache.felix.atomos.impl.base.AtomosCommands",
     "allPublicMethods" : true,
     "allDeclaredMethods" : true,
     "allPublicFields" : true,
diff --git a/atomos.examples/atomos.examples.jlink/pom.xml b/atomos.examples/atomos.examples.jlink/pom.xml
index a8be6cb..0a86da1 100644
--- a/atomos.examples/atomos.examples.jlink/pom.xml
+++ b/atomos.examples/atomos.examples.jlink/pom.xml
@@ -15,7 +15,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
         <dependency>
@@ -109,7 +109,7 @@
             <plugin>
                 <groupId>org.moditect</groupId>
                 <artifactId>moditect-maven-plugin</artifactId>
-                <version>1.0.0.Beta2</version>
+                <version>1.0.0.RC1</version>
                 <executions>
                     <execution>
                         <id>add-module-infos</id>
@@ -453,7 +453,7 @@
                             </modulePath>
                             <modules>
                                 <module>osgi.core</module>
-                                <module>org.apache.felix.atomos.runtime</module>
+                                <module>org.apache.felix.atomos</module>
                                 <module>org.apache.felix.gogo.command</module>
                                 <module>org.apache.felix.gogo.runtime</module>
                                 <module>org.apache.felix.gogo.shell</module>
@@ -494,7 +494,7 @@
                             <excludeTransitive>true</excludeTransitive>
                             <includeArtifactIds>
                                 osgi.core,
-                                org.apache.felix.atomos.runtime,
+                                org.apache.felix.atomos,
                                 org.apache.felix.atomos.tests.testbundles.service.contract,
                                 org.apache.felix.atomos.tests.testbundles.service.impl,
                                 org.apache.felix.atomos.tests.testbundles.service.impl.activator
diff --git a/atomos.examples/atomos.examples.jlink/src/main/java/module-info.java b/atomos.examples/atomos.examples.jlink/src/main/java/module-info.java
index 6b9219d..f65916a 100644
--- a/atomos.examples/atomos.examples.jlink/src/main/java/module-info.java
+++ b/atomos.examples/atomos.examples.jlink/src/main/java/module-info.java
@@ -12,10 +12,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.apache.felix.atomos.Atomos;
 module org.apache.felix.atomos.examples.jlink
 {
-    requires org.apache.felix.atomos.runtime;
+    requires org.apache.felix.atomos;
     requires org.apache.felix.atomos.tests.testbundles.service.impl;
     requires org.apache.felix.atomos.tests.testbundles.service.impl.activator;
     requires org.apache.felix.scr;
@@ -24,5 +24,5 @@
     requires org.apache.felix.gogo.shell;
     requires jdk.jdwp.agent;
 
-    uses AtomosRuntime;
+    uses Atomos;
 }
diff --git a/atomos.examples/atomos.examples.jlink/src/main/java/org/apache/felix/atomos/examples/jlink/GogoConsole.java b/atomos.examples/atomos.examples.jlink/src/main/java/org/apache/felix/atomos/examples/jlink/GogoConsole.java
index dd96330..3b577d3 100644
--- a/atomos.examples/atomos.examples.jlink/src/main/java/org/apache/felix/atomos/examples/jlink/GogoConsole.java
+++ b/atomos.examples/atomos.examples.jlink/src/main/java/org/apache/felix/atomos/examples/jlink/GogoConsole.java
@@ -13,18 +13,38 @@
  */
 package org.apache.felix.atomos.examples.jlink;
 
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.felix.atomos.launch.AtomosLauncher;
+import org.apache.felix.atomos.Atomos;
 import org.osgi.framework.BundleException;
+import org.osgi.framework.launch.Framework;
 
 public class GogoConsole
 {
     public static void main(String[] args) throws BundleException
     {
         long start = System.nanoTime();
-        AtomosLauncher.main(args);
+        launch(args);
         long total = System.nanoTime() - start;
         System.out.println("Total time: " + TimeUnit.NANOSECONDS.toMillis(total));
     }
+
+    private static void launch(String[] args) throws BundleException
+    {
+        Map<String, String> config = Atomos.getConfiguration(args);
+        Atomos atomos = Atomos.newAtomos(config);
+        if (atomos.getBootLayer().isAddLayerSupported())
+        {
+            String modulesDirPath = config.get("atomos.modules");
+            Path modulesPath = modulesDirPath == null ? null
+                : new File(modulesDirPath).toPath();
+            atomos.getBootLayer().addModules("modules", modulesPath);
+        }
+
+        Framework framework = atomos.newFramework(config);
+        framework.start();
+    }
 }
diff --git a/atomos.examples/atomos.examples.springloader/README.md b/atomos.examples/atomos.examples.springloader/README.md
index 920992f..c0a3060 100644
--- a/atomos.examples/atomos.examples.springloader/README.md
+++ b/atomos.examples/atomos.examples.springloader/README.md
@@ -4,7 +4,7 @@
 
 This is not a Spring Boot example itself. It only Spring Boot loader which understands how to discover and load all the included JAR files with a single class loader. This class loader is able to load content from the embedded JAR files without requiring them to be extracted to disk first.
 
-The Atomos launcher class `org.apache.felix.atomos.launch.AtomosLauncher` is used as the `Start-Class` for the executable JAR. If you introspect the JAR produced by this example you will notice it includes a `BOOT-INF/lib/` folder which includes all the embedded JARs for all the dependent bundles. Atomos is able to discover all the included JARs and load the bundle entry resources from them.
+The Atomos class `org.apache.felix.atomos.Atomos` is used as the `Start-Class` for the executable JAR. If you introspect the JAR produced by this example you will notice it includes a `BOOT-INF/lib/` folder which includes all the embedded JARs for all the dependent bundles. Atomos is able to discover all the included JARs and load the bundle entry resources from them.
 
 The following command should produce a gogo shell prompt:
 
diff --git a/atomos.examples/atomos.examples.springloader/pom.xml b/atomos.examples/atomos.examples.springloader/pom.xml
index 9e938c2..ea367df 100644
--- a/atomos.examples/atomos.examples.springloader/pom.xml
+++ b/atomos.examples/atomos.examples.springloader/pom.xml
@@ -45,7 +45,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
         <dependency>
@@ -63,7 +63,7 @@
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <version>2.2.5.RELEASE</version>
                 <configuration>
-                    <mainClass>org.apache.felix.atomos.launch.AtomosLauncher</mainClass>
+                    <mainClass>org.apache.felix.atomos.Atomos</mainClass>
                 </configuration>
                 <executions>
                   <execution>
diff --git a/atomos.examples/atomos.examples.substrate.lib/graal_class_config.json b/atomos.examples/atomos.examples.substrate.lib/graal_class_config.json
index ec0747a..36d5890 100644
--- a/atomos.examples/atomos.examples.substrate.lib/graal_class_config.json
+++ b/atomos.examples/atomos.examples.substrate.lib/graal_class_config.json
@@ -116,7 +116,7 @@
     "allDeclaredFields" : true
   },
   {
-    "name" : "org.apache.felix.atomos.impl.runtime.base.AtomosCommands",
+    "name" : "org.apache.felix.atomos.impl.base.AtomosCommands",
     "allPublicMethods" : true,
     "allDeclaredMethods" : true,
     "allPublicFields" : true,
diff --git a/atomos.examples/atomos.examples.substrate.lib/pom.xml b/atomos.examples/atomos.examples.substrate.lib/pom.xml
index 25ff074..0f593a7 100644
--- a/atomos.examples/atomos.examples.substrate.lib/pom.xml
+++ b/atomos.examples/atomos.examples.substrate.lib/pom.xml
@@ -52,7 +52,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
             <exclusions>
                 <exclusion>
@@ -157,12 +157,12 @@
                 </executions>
                 <configuration>
                     <imageName>atomos</imageName>
-                    <mainClass>org.apache.felix.atomos.launch.AtomosLauncher</mainClass>
+                    <mainClass>org.apache.felix.atomos.Atomos</mainClass>
                     <buildArgs>
                         --no-server
                         --allow-incomplete-classpath
                         --no-fallback
-                        --initialize-at-build-time=org.eclipse.jetty.util.TypeUtil,org.eclipse.jetty.http.HttpTokens,org.eclipse.jetty.util.log.Log,org.eclipse.jetty.util.log.StdErrLog,org.eclipse.jetty.util.Uptime,org.eclipse.jetty.server.HttpOutput,org.apache.felix.atomos.runtime,org.apache.felix.atomos.runtime.launch,org.apache.felix.atomos.impl,javax.servlet,org.apache.felix.service.command.Converter
+                        --initialize-at-build-time=org.eclipse.jetty.util.TypeUtil,org.eclipse.jetty.http.HttpTokens,org.eclipse.jetty.util.log.Log,org.eclipse.jetty.util.log.StdErrLog,org.eclipse.jetty.util.Uptime,org.eclipse.jetty.server.HttpOutput,org.apache.felix.atomos,javax.servlet,org.apache.felix.service.command.Converter
                         -H:ReflectionConfigurationFiles=${project.basedir}/graal_class_config.json
                         -H:ResourceConfigurationFiles=${project.basedir}/graal_resource_config.json
                         -H:DynamicProxyConfigurationFiles=${project.basedir}/graal_proxy_config.json
diff --git a/atomos.examples/atomos.examples.substrate.maven/pom.xml b/atomos.examples/atomos.examples.substrate.maven/pom.xml
index 8f77151..1f1bd64 100644
--- a/atomos.examples/atomos.examples.substrate.maven/pom.xml
+++ b/atomos.examples/atomos.examples.substrate.maven/pom.xml
@@ -47,7 +47,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
             <exclusions>
                 <exclusion>
@@ -79,8 +79,7 @@
                     <nativeImage>
                         <debug>true</debug>
                         <additionalInitializeAtBuildTime>
-                            <additionalInitializeAtBuildTime>org.apache.felix.atomos.runtime</additionalInitializeAtBuildTime>
-                            <additionalInitializeAtBuildTime>org.apache.felix.atomos.impl</additionalInitializeAtBuildTime>
+                            <additionalInitializeAtBuildTime>org.apache.felix.atomos</additionalInitializeAtBuildTime>
                             <additionalInitializeAtBuildTime>javax.servlet</additionalInitializeAtBuildTime>
                             <additionalInitializeAtBuildTime>org.apache.felix.service.command.Converter</additionalInitializeAtBuildTime>
                             <additionalInitializeAtBuildTime>org.eclipse.jetty.util.TypeUtil</additionalInitializeAtBuildTime>
@@ -89,7 +88,6 @@
                             <additionalInitializeAtBuildTime>org.eclipse.jetty.util.log.StdErrLog</additionalInitializeAtBuildTime>
                             <additionalInitializeAtBuildTime>org.eclipse.jetty.util.Uptime</additionalInitializeAtBuildTime>
                             <additionalInitializeAtBuildTime>org.eclipse.jetty.server.HttpOutput</additionalInitializeAtBuildTime>
-                            <!-- <additionalInitializeAtBuildTime>org.apache.felix.atomos.impl.runtime.base</additionalInitializeAtBuildTime> -->
                         </additionalInitializeAtBuildTime>
                         <resourceConfigurationFiles>
                             <resourceConfigurationFile>additionalResourceConfig.json</resourceConfigurationFile>
@@ -105,7 +103,7 @@
                             <reflectionConfigurationFile>reflectConfig_jdk.json</reflectionConfigurationFile>
                             <reflectionConfigurationFile>reflectConfig_jetty.json</reflectionConfigurationFile>
                         </reflectionConfigurationFiles>
-                        <!-- <mainClass>org.apache.felix.atomos.launch.AtomosLauncher</mainClass> -->
+                        <!-- <mainClass>org.apache.felix.atomos.Atomos</mainClass> -->
                     </nativeImage>
                 </configuration>
                 <executions>
diff --git a/atomos.examples/atomos.examples.substrate.maven/reflectConfig_felix_atomos.json b/atomos.examples/atomos.examples.substrate.maven/reflectConfig_felix_atomos.json
index 9751c7a..efd1cd1 100644
--- a/atomos.examples/atomos.examples.substrate.maven/reflectConfig_felix_atomos.json
+++ b/atomos.examples/atomos.examples.substrate.maven/reflectConfig_felix_atomos.json
@@ -1,6 +1,6 @@
 [
    {
-    "name" : "org.apache.felix.atomos.impl.runtime.base.AtomosCommands",
+    "name" : "org.apache.felix.atomos.impl.base.AtomosCommands",
     "allPublicMethods" : true,
     "allDeclaredMethods" : true,
     "allPublicFields" : true,
diff --git a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/LauncherBuilderUtil.java b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/LauncherBuilderUtil.java
index e1fa0c0..2085224 100644
--- a/atomos.maven/src/main/java/org/apache/felix/atomos/maven/LauncherBuilderUtil.java
+++ b/atomos.maven/src/main/java/org/apache/felix/atomos/maven/LauncherBuilderUtil.java
@@ -224,7 +224,7 @@
                 if (nativeImageConfig.mainClass == null
                     || nativeImageConfig.mainClass.isEmpty())
                 {
-                    return "org.apache.felix.atomos.launch.AtomosLauncher";
+                    return "org.apache.felix.atomos.Atomos";
                 }
                 return nativeImageConfig.mainClass;
             }
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/launch/AtomosLauncher.java b/atomos.runtime/src/main/java/org/apache/felix/atomos/launch/AtomosLauncher.java
deleted file mode 100644
index 2765e45..0000000
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/launch/AtomosLauncher.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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 org.apache.felix.atomos.launch;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ServiceLoader;
-
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosRuntime;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.connect.ConnectFrameworkFactory;
-import org.osgi.framework.launch.Framework;
-
-/**
- * The Atomos launcher contains convenience methods for creating and launching
- * an OSGi {@link Framework} instance with the Atomos runtime.
- */
-@org.osgi.annotation.bundle.Header(name = "Main-Class", value = org.apache.felix.atomos.launch.AtomosLauncher.ATOMOS_LAUNCHER)
-public class AtomosLauncher
-{
-    // package private constant use to specify the main class
-    static final String ATOMOS_LAUNCHER = "org.apache.felix.atomos.launch.AtomosLauncher";
-    /**
-     * A main method that can be used by executable jars to initialize and start an
-     * Atomos Runtime with an available OSGi {@link Framework} implementation.
-     * Each string in the arguments array may contain a key=value
-     * pair that will be used for the framework configuration.
-     * 
-     * @param args the args will be converted into a {@code Map<String, String>} to
-     *             use as configuration parameters for the OSGi Framework.
-     * @throws BundleException when an error occurs
-     * @see AtomosLauncher#launch(Map)
-     */
-    public static void main(String[] args) throws BundleException
-    {
-        launch(getConfiguration(args));
-    }
-
-    /**
-     * A configuration option used by {@link #launch(Map)} which can be used to
-     * configuration a modules folder to load additional Atomos contents from.
-     */
-    public static final String ATOMOS_MODULES_DIR = "atomos.modules";
-
-    /**
-     * Convenience method that creates an AtomosRuntime in order to load the Atomos
-     * contents discovered in the environment. If additional layers are supported by the
-     * environment (see {@link AtomosLayer#isAddLayerSupported()} then additional modules
-     * may be loaded into a child layer by looking for a
-     * modules folder. The path to the modules folder can be configured by using the
-     * {@link #ATOMOS_MODULES_DIR atomos.modules} launch option. 
-     * If the {@link #ATOMOS_MODULES_DIR atomos.modules}
-     * option is not specified in the frameworkConfig then the default will try to
-     * determine the location on disk of the Atomos runtime module and look for a
-     * folder called "modules". If the location of the Atomos Runtime module
-     * cannot be determined then no additional modules folder will be searched.
-     * 
-     * @param frameworkConfig the framework configuration
-     * @return a new framework instance which has been started with the Atomos runtime.
-     * @throws BundleException if an error occurred creating and starting the framework
-     * @see AtomosLauncher#newFramework(Map, AtomosRuntime)
-     */
-    public static Framework launch(Map<String, String> frameworkConfig)
-        throws BundleException
-    {
-        frameworkConfig = new HashMap<>(frameworkConfig);
-        // default to reporting resolution issues from launcher
-        frameworkConfig.putIfAbsent(AtomosRuntimeBase.ATOMOS_REPORT_RESOLUTION_PROP,
-            "true");
-        AtomosRuntime atomosRuntime = AtomosRuntime.newAtomosRuntime(frameworkConfig);
-        if (atomosRuntime.getBootLayer().isAddLayerSupported())
-        {
-            String modulesDirPath = frameworkConfig.get(ATOMOS_MODULES_DIR);
-            Path modulesPath = modulesDirPath == null ? null
-                : new File(modulesDirPath).toPath();
-            atomosRuntime.getBootLayer().addModules("modules", modulesPath);
-        }
-
-        Framework framework = newFramework(frameworkConfig, atomosRuntime);
-        framework.start();
-        return framework;
-    }
-
-    /**
-     * Converts a string array into a {@code  Map<String,String>}
-     * 
-     * @param args the arguments where each element has key=string value, the key
-     *             cannot contain an '=' (equals) character.
-     * @return a map of the configuration specified by the args
-     */
-    public static Map<String, String> getConfiguration(String[] args)
-    {
-        Map<String, String> config = new HashMap<>();
-        if (args != null)
-        {
-            for (String arg : args)
-            {
-                int equals = arg.indexOf('=');
-                if (equals != -1)
-                {
-                    String key = arg.substring(0, equals);
-                    String value = arg.substring(equals + 1);
-                    config.put(key, value);
-                }
-            }
-        }
-        return config;
-    }
-
-    /**
-     * Creates a new {@link Framework} instance that uses the specified Atomos runtime,
-     * or creates a new Atomos runtime to use if a runtime is not specified. The
-     * {@link ServiceLoader} is used to load an implementation of a {@link ConnectFrameworkFactory}
-     * which is used to create a new {@link Framework} instance with the specified Atomos runtime.
-     * The supplied framework configuration is used to create the new {@code Framework} instance.
-     * Additional configuration options maybe configured automatically in order to correctly configure
-     * the system packages for the {@code Framework} instance.
-     * @param frameworkConfig The framework configuration options, or {@code null} if the defaults should be used
-     * @param atomosRuntime The Atomos runtime, or {@code null} will create a new Atomos runtime
-     * @return The new uninitialized Framework instance which uses the Atomos runtime
-     */
-    public static Framework newFramework(Map<String, String> frameworkConfig,
-        AtomosRuntime atomosRuntime)
-    {
-        if (atomosRuntime == null)
-        {
-            atomosRuntime = AtomosRuntime.newAtomosRuntime();
-        }
-
-        frameworkConfig = frameworkConfig == null ? new HashMap<>()
-            : new HashMap<>(frameworkConfig);
-
-        ((AtomosRuntimeBase) atomosRuntime).populateConfig(frameworkConfig);
-
-        // Always allow the console to work
-        frameworkConfig.putIfAbsent("osgi.console", "");
-
-        return ((AtomosRuntimeBase) atomosRuntime).findFrameworkFactory().newFramework(
-            frameworkConfig, atomosRuntime.getModuleConnector());
-    }
-}
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/launch/package-info.java b/atomos.runtime/src/main/java/org/apache/felix/atomos/launch/package-info.java
deleted file mode 100644
index 56cc0dc..0000000
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/launch/package-info.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * 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.
- */
-@org.osgi.annotation.bundle.Export
-@org.osgi.annotation.versioning.Version("1.0.0")
-package org.apache.felix.atomos.launch;
\ No newline at end of file
diff --git a/atomos.substrate.config/pom.xml b/atomos.substrate.config/pom.xml
index 069db99..69839fe 100644
--- a/atomos.substrate.config/pom.xml
+++ b/atomos.substrate.config/pom.xml
@@ -22,7 +22,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
         <dependency>
diff --git a/atomos.tests/atomos.tests.classpath.service/pom.xml b/atomos.tests/atomos.tests.classpath.service/pom.xml
index d48700e..f0bcdb8 100644
--- a/atomos.tests/atomos.tests.classpath.service/pom.xml
+++ b/atomos.tests/atomos.tests.classpath.service/pom.xml
@@ -36,7 +36,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
         <dependency>
diff --git a/atomos.tests/atomos.tests.classpath.service/src/test/java/org/apache/felix/atomos/tests/classpath/service/test/ClasspathLaunchTest.java b/atomos.tests/atomos.tests.classpath.service/src/test/java/org/apache/felix/atomos/tests/classpath/service/test/ClasspathLaunchTest.java
index 998e48d..9851280 100644
--- a/atomos.tests/atomos.tests.classpath.service/src/test/java/org/apache/felix/atomos/tests/classpath/service/test/ClasspathLaunchTest.java
+++ b/atomos.tests/atomos.tests.classpath.service/src/test/java/org/apache/felix/atomos/tests/classpath/service/test/ClasspathLaunchTest.java
@@ -29,12 +29,11 @@
 import java.util.Map;
 import java.util.Optional;
 
-import org.apache.felix.atomos.impl.runtime.base.AtomosCommands;
-import org.apache.felix.atomos.launch.AtomosLauncher;
-import org.apache.felix.atomos.runtime.AtomosContent;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosLayer.LoaderType;
-import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.apache.felix.atomos.Atomos;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.felix.atomos.AtomosLayer;
+import org.apache.felix.atomos.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.impl.base.AtomosCommands;
 import org.apache.felix.atomos.tests.testbundles.service.contract.Echo;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
@@ -76,8 +75,9 @@
     void testClassPathGogo(@TempDir Path storage)
         throws BundleException, InvalidSyntaxException
     {
-        testFramework = AtomosLauncher.launch(Collections.singletonMap(
-            Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework = Atomos.newAtomos().newFramework(
+            Map.of(Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework.start();
         BundleContext bc = testFramework.getBundleContext();
 
         String filter = "(osgi.command.scope=atomos)";
@@ -96,23 +96,24 @@
     void testClassPathServices(@TempDir Path storage)
         throws BundleException, InvalidSyntaxException
     {
-        testFramework = AtomosLauncher.launch(Collections.singletonMap(
-            Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework = Atomos.newAtomos().newFramework(
+            Map.of(Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework.start();
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
         checkBundleStates(bc.getBundles());
 
         checkServices(bc, 4);
-        AtomosRuntime runtime = getRuntime(bc);
+        Atomos runtime = getRuntime(bc);
         assertNull(runtime.getBootLayer().adapt(ModuleLayer.class).orElse(null),
             "Found a ModuleLayer.");
     }
 
-    private AtomosRuntime getRuntime(BundleContext bc)
+    private Atomos getRuntime(BundleContext bc)
     {
-        ServiceReference<AtomosRuntime> ref = bc.getServiceReference(AtomosRuntime.class);
+        ServiceReference<Atomos> ref = bc.getServiceReference(Atomos.class);
         assertNotNull(ref, "No reference found.");
-        AtomosRuntime runtime = bc.getService(ref);
+        Atomos runtime = bc.getService(ref);
         assertNotNull(runtime, "No service found.");
         return runtime;
     }
@@ -120,7 +121,7 @@
     @Test
     void testInvalidCreateLayer(@TempDir Path storage) throws BundleException
     {
-        AtomosRuntime runtime = AtomosRuntime.newAtomosRuntime();
+        Atomos runtime = Atomos.newAtomos();
         try
         {
             runtime.getBootLayer().addLayer("invalid", LoaderType.OSGI, storage);
@@ -135,12 +136,13 @@
     @Test
     void testFindBundle(@TempDir Path storage) throws BundleException
     {
-        testFramework = AtomosLauncher.launch(Collections.singletonMap(
-            Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework = Atomos.newAtomos().newFramework(
+            Map.of(Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework.start();
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        AtomosRuntime runtime = getRuntime(bc);
+        Atomos runtime = getRuntime(bc);
         assertFindBundle("java.base", runtime.getBootLayer(), runtime.getBootLayer(),
             true);
         assertFindBundle(TESTBUNDLES_SERVICE_IMPL, runtime.getBootLayer(),
@@ -153,12 +155,13 @@
     @Test
     void testGetEntry(@TempDir Path storage) throws BundleException
     {
-        testFramework = AtomosLauncher.launch(Collections.singletonMap(
-            Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework = Atomos.newAtomos().newFramework(
+            Map.of(Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework.start();
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        AtomosRuntime runtime = getRuntime(bc);
+        Atomos runtime = getRuntime(bc);
         Bundle b = assertFindBundle(TESTBUNDLES_SERVICE_IMPL_A, runtime.getBootLayer(),
             runtime.getBootLayer(), true).getBundle();
         assertNotNull(b, "No bundle found.");
@@ -268,8 +271,9 @@
     @Test
     void testSystemPackages(@TempDir Path storage) throws BundleException
     {
-        testFramework = AtomosLauncher.launch(Collections.singletonMap(
-            Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework = Atomos.newAtomos().newFramework(
+            Map.of(Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        testFramework.start();
         // this test assumes it is running on Java 11+
         Collection<BundleCapability> javaLangPackages = testFramework.adapt(
             FrameworkWiring.class).findProviders(new Requirement()
diff --git a/atomos.tests/atomos.tests.index.bundles/pom.xml b/atomos.tests/atomos.tests.index.bundles/pom.xml
index d5c019f..eef339c 100644
--- a/atomos.tests/atomos.tests.index.bundles/pom.xml
+++ b/atomos.tests/atomos.tests.index.bundles/pom.xml
@@ -36,7 +36,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
         <dependency>
diff --git a/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/IndexLaunchTest.java b/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/IndexLaunchTest.java
index 91f0162..1cd32bd 100644
--- a/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/IndexLaunchTest.java
+++ b/atomos.tests/atomos.tests.index.bundles/src/test/java/org/apache/felix/atomos/tests/index/bundles/IndexLaunchTest.java
@@ -30,11 +30,10 @@
 import java.util.Optional;
 import java.util.stream.Collectors;
 
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase;
-import org.apache.felix.atomos.launch.AtomosLauncher;
-import org.apache.felix.atomos.runtime.AtomosContent;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.apache.felix.atomos.Atomos;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.felix.atomos.AtomosLayer;
+import org.apache.felix.atomos.impl.base.AtomosBase;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
@@ -66,11 +65,11 @@
         }
     }
 
-    private AtomosRuntime getRuntime(BundleContext bc)
+    private Atomos getRuntime(BundleContext bc)
     {
-        ServiceReference<AtomosRuntime> ref = bc.getServiceReference(AtomosRuntime.class);
+        ServiceReference<Atomos> ref = bc.getServiceReference(Atomos.class);
         assertNotNull(ref, "No reference found.");
-        AtomosRuntime runtime = bc.getService(ref);
+        Atomos runtime = bc.getService(ref);
         assertNotNull(runtime, "No service found.");
         return runtime;
     }
@@ -78,26 +77,30 @@
     private Framework getTestFramework(Path storage, String indexPath)
         throws BundleException
     {
+        Framework f;
         if (indexPath == null)
         {
-            return AtomosLauncher.launch(
+            f = Atomos.newAtomos().newFramework(
                 Map.of(Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
         }
         else
         {
-            return AtomosLauncher.launch(
-                Map.of(Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath(),
-                    AtomosRuntimeBase.ATOMOS_INDEX_PATH_PROP, indexPath));
+            Map<String, String> config = Map.of(Constants.FRAMEWORK_STORAGE,
+                storage.toFile().getAbsolutePath(),
+                AtomosBase.ATOMOS_INDEX_PATH_PROP, indexPath);
+            f = Atomos.newAtomos(config).newFramework(config);
         }
+        f.start();
+        return f;
     }
 
     @Test
     void testIgnoreIndex(@TempDir Path storage) throws BundleException
     {
-        testFramework = getTestFramework(storage, AtomosRuntimeBase.ATOMOS_IGNORE_INDEX);
+        testFramework = getTestFramework(storage, AtomosBase.ATOMOS_IGNORE_INDEX);
         BundleContext bc = testFramework.getBundleContext();
 
-        AtomosRuntime runtime = getRuntime(bc);
+        Atomos runtime = getRuntime(bc);
         assertFindBundle("java.base", runtime.getBootLayer(), runtime.getBootLayer(),
             true);
         assertFindBundle(TESTBUNDLES_SERVICE_IMPL, runtime.getBootLayer(),
@@ -132,7 +135,7 @@
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        AtomosRuntime runtime = getRuntime(bc);
+        Atomos runtime = getRuntime(bc);
         assertFindBundle("java.base", runtime.getBootLayer(), runtime.getBootLayer(),
             true);
         assertFindBundle(TESTBUNDLES_SERVICE_IMPL, runtime.getBootLayer(),
@@ -210,7 +213,7 @@
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        AtomosRuntime runtime = getRuntime(bc);
+        Atomos runtime = getRuntime(bc);
         Bundle b = assertFindBundle(TESTBUNDLES_SERVICE_IMPL,
             runtime.getBootLayer(),
             runtime.getBootLayer(), true).getBundle();
@@ -258,7 +261,7 @@
         testFramework = getTestFramework(storage, indexPath);
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
-        AtomosRuntime runtime = getRuntime(bc);
+        Atomos runtime = getRuntime(bc);
 
         for (int i : expected)
         {
diff --git a/atomos.tests/atomos.tests.modulepath.service/pom.xml b/atomos.tests/atomos.tests.modulepath.service/pom.xml
index 48ac860..3e9e2eb 100644
--- a/atomos.tests/atomos.tests.modulepath.service/pom.xml
+++ b/atomos.tests/atomos.tests.modulepath.service/pom.xml
@@ -59,7 +59,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
         <dependency>
diff --git a/atomos.tests/atomos.tests.modulepath.service/src/main/java/module-info.java b/atomos.tests/atomos.tests.modulepath.service/src/main/java/module-info.java
index dfb4639..bdde920 100644
--- a/atomos.tests/atomos.tests.modulepath.service/src/main/java/module-info.java
+++ b/atomos.tests/atomos.tests.modulepath.service/src/main/java/module-info.java
@@ -12,18 +12,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.osgi.framework.connect.ConnectFrameworkFactory;
 
 module org.apache.felix.atomos.tests.modulepath.service
 {
-    requires org.apache.felix.atomos.runtime;
+    requires org.apache.felix.atomos;
     requires org.apache.felix.atomos.tests.testbundles.service.contract;
     requires org.apache.felix.atomos.tests.testbundles.service.impl;
     requires org.apache.felix.atomos.tests.testbundles.service.impl.activator;
     requires org.apache.felix.scr;
     requires osgi.promise;
 
-    uses AtomosRuntime;
+    uses ConnectFrameworkFactory;
 
     opens org.apache.felix.atomos.tests.modulepath.service;
 
diff --git a/atomos.tests/atomos.tests.modulepath.service/src/test/java/org/apache/felix/atomos/tests/modulepath/service/ModulepathLaunchTest.java b/atomos.tests/atomos.tests.modulepath.service/src/test/java/org/apache/felix/atomos/tests/modulepath/service/ModulepathLaunchTest.java
index 97d82ad..fe2dc65 100644
--- a/atomos.tests/atomos.tests.modulepath.service/src/test/java/org/apache/felix/atomos/tests/modulepath/service/ModulepathLaunchTest.java
+++ b/atomos.tests/atomos.tests.modulepath.service/src/test/java/org/apache/felix/atomos/tests/modulepath/service/ModulepathLaunchTest.java
@@ -35,14 +35,14 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.stream.Collectors;
 
-import org.apache.felix.atomos.launch.AtomosLauncher;
-import org.apache.felix.atomos.runtime.AtomosContent;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosLayer.LoaderType;
-import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.apache.felix.atomos.Atomos;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.felix.atomos.AtomosLayer;
+import org.apache.felix.atomos.AtomosLayer.LoaderType;
 import org.apache.felix.atomos.tests.testbundles.service.contract.Echo;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
@@ -55,6 +55,7 @@
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.connect.ConnectFrameworkFactory;
 import org.osgi.framework.launch.Framework;
 import org.osgi.framework.namespace.BundleNamespace;
 import org.osgi.framework.wiring.BundleWiring;
@@ -106,7 +107,7 @@
         return result.orElse(null);
     }
 
-    private void checkBundleStates(AtomosRuntime atomos, Bundle[] bundles)
+    private void checkBundleStates(Atomos atomos, Bundle[] bundles)
     {
         assertTrue(bundles.length > 0, "No bundles: " + Arrays.toString(bundles));
         for (final Bundle b : bundles)
@@ -171,7 +172,7 @@
         assertEquals(loaderType.toString(), atomosLayer.getName(), "Wrong name.");
     }
 
-    private void checkLoader(AtomosRuntime runtime, AtomosLayer layer,
+    private void checkLoader(Atomos runtime, AtomosLayer layer,
         LoaderType loaderType) throws ClassNotFoundException
     {
         final Set<AtomosContent> atomosBundles = layer.getAtomosContents();
@@ -235,22 +236,29 @@
         }
     }
 
-    private Framework getFramework(String... args) throws BundleException
+    private Framework getFramework(Path modules, String... args) throws BundleException
     {
-        return AtomosLauncher.launch(AtomosLauncher.getConfiguration(args));
+        Map<String, String> config = Atomos.getConfiguration(args);
+        Atomos atomos = Atomos.newAtomos(config);
+        if (modules != null)
+        {
+            atomos.getBootLayer().addModules("modules", modules);
+        }
+        Framework framework = atomos.newFramework(config);
+        framework.start();
+        return framework;
     }
+
     private ClassLoader getCLForResourceTests(Path storage) throws BundleException
     {
         Path[] testBundle = findModulePaths(TESTBUNDLES_RESOURCE_A);
-        testFramework = getFramework(
-                Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath(),
-                AtomosLauncher.ATOMOS_MODULES_DIR
-                + "=" + testBundle[0].toString());
+        testFramework = getFramework(testBundle[0],
+            Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
-        final ServiceReference<AtomosRuntime> atomosRef = bc.getServiceReference(
-            AtomosRuntime.class);
-        final AtomosRuntime atomos = bc.getService(atomosRef);
+        final ServiceReference<Atomos> atomosRef = bc.getServiceReference(
+            Atomos.class);
+        final Atomos atomos = bc.getService(atomosRef);
         checkBundleStates(atomos, bc.getBundles());
 
         final AtomosLayer bootLayer = atomos.getBootLayer();
@@ -320,7 +328,7 @@
     }
 
     private AtomosLayer installChild(AtomosLayer parent, String name,
-        AtomosRuntime atomosRuntime, LoaderType loaderType) throws BundleException
+        Atomos atomos, LoaderType loaderType) throws BundleException
     {
         final File modules = new File("target/modules");
         assertTrue(modules.isDirectory(), "Modules directory does not exist: " + modules);
@@ -336,9 +344,9 @@
     void testAddNewLayers(@TempDir Path storage)
         throws BundleException, InvalidSyntaxException, InterruptedException
     {
-        testFramework = getFramework(
-                Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath(),
-            AtomosLauncher.ATOMOS_MODULES_DIR + "=target/modules");
+        Path modules = new File("target/modules").toPath();
+        testFramework = getFramework(modules,
+            Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
         final Bundle[] bundles = bc.getBundles();
@@ -347,18 +355,18 @@
 
         checkServices(bc, 4);
 
-        final AtomosRuntime atomosRuntime = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
+        final Atomos atomos = bc.getService(
+            bc.getServiceReference(Atomos.class));
 
         final Collection<AtomosLayer> layers = new ArrayList<>();
         for (int i = 0; i < 20; i++)
         {
-            layers.add(installChild(atomosRuntime.getBootLayer(), "services-" + i,
-                atomosRuntime, LoaderType.OSGI));
+            layers.add(installChild(atomos.getBootLayer(), "services-" + i,
+                atomos, LoaderType.OSGI));
         }
         checkServices(bc, 44);
 
-        checkBundleStates(atomosRuntime, bc.getBundles());
+        checkBundleStates(atomos, bc.getBundles());
 
         final List<Bundle> allChildBundles = layers.stream().flatMap(
             (l) -> l.getAtomosContents().stream()).map(
@@ -387,7 +395,7 @@
 
         // note that doing a bundle uninstall forces the location to be disconnected
         firstChildBundles.forEach((b) -> {
-            assertNull(atomosRuntime.getConnectedContent(b.getLocation()),
+            assertNull(atomos.getConnectedContent(b.getLocation()),
                 "Atomos content not expected.");
         });
 
@@ -410,7 +418,7 @@
         checkServices(bc, 4);
 
         // uninstalling the layer forces all of its content to get disconnected
-        allChildBundles.forEach((b) -> assertNull(atomosRuntime.getConnectedContent(b.getLocation()),
+        allChildBundles.forEach((b) -> assertNull(atomos.getConnectedContent(b.getLocation()),
             "Atomos content not expected."));
 
         assertEquals(originalNum, bc.getBundles().length,
@@ -418,38 +426,85 @@
     }
 
     @Test
+    void testAddLayerBeforeNewFrameworkAtomos(@TempDir Path storage)
+        throws BundleException
+    {
+        doAddLayerBeforeFramework(storage, true);
+    }
+
+    @Test
+    void testAddLayerBeforeFrameworkFactory(@TempDir Path storage) throws BundleException
+    {
+        doAddLayerBeforeFramework(storage, false);
+    }
+
+    void doAddLayerBeforeFramework(Path storage, boolean useAtomosNewFramework)
+        throws BundleException
+    {
+        Atomos atomos = Atomos.newAtomos();
+        final File modules = new File("target/modules");
+        assertTrue(modules.isDirectory(), "Modules directory does not exist: " + modules);
+        final AtomosLayer child = atomos.getBootLayer().addLayer("SINGLE",
+            LoaderType.SINGLE, modules.toPath());
+
+        if (useAtomosNewFramework)
+        {
+            testFramework = atomos.newFramework(
+                Map.of(Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath()));
+        }
+        else
+        {
+            testFramework = ServiceLoader.load(
+                ConnectFrameworkFactory.class).findFirst().map(
+                    f -> f.newFramework( //
+                        Map.of(//
+                            Constants.FRAMEWORK_STORAGE, //
+                            storage.toFile().getAbsolutePath(), //
+                            Constants.FRAMEWORK_SYSTEMPACKAGES, //
+                            ""),
+                        atomos.getModuleConnector())).get();
+        }
+        testFramework.start();
+
+        assertFindBundle("java.base", child, atomos.getBootLayer(), true);
+        assertFindBundle(TESTBUNDLES_SERVICE_IMPL_A, child, child, true);
+        assertFindBundle(TESTBUNDLES_SERVICE_IMPL, child, atomos.getBootLayer(), true);
+        assertFindBundle(TESTBUNDLES_SERVICE_IMPL_A, atomos.getBootLayer(), null, false);
+    }
+
+    @Test
     void testFindBundle(@TempDir Path storage) throws BundleException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        final AtomosRuntime atomosRuntime = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
-        final AtomosLayer child = installChild(atomosRuntime.getBootLayer(), "SINGLE",
-            atomosRuntime, LoaderType.SINGLE);
-        assertFindBundle("java.base", child, atomosRuntime.getBootLayer(), true);
+        final Atomos atomos = bc.getService(
+            bc.getServiceReference(Atomos.class));
+        final AtomosLayer child = installChild(atomos.getBootLayer(), "SINGLE",
+            atomos, LoaderType.SINGLE);
+        assertFindBundle("java.base", child, atomos.getBootLayer(), true);
         assertFindBundle(TESTBUNDLES_SERVICE_IMPL_A, child, child, true);
         assertFindBundle(TESTBUNDLES_SERVICE_IMPL, child,
-            atomosRuntime.getBootLayer(), true);
+            atomos.getBootLayer(), true);
         assertFindBundle(TESTBUNDLES_SERVICE_IMPL_A,
-            atomosRuntime.getBootLayer(), null, false);
+            atomos.getBootLayer(), null, false);
     }
 
     @Test
     void testGetEntry(@TempDir Path storage) throws BundleException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        final AtomosRuntime atomosRuntime = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
-        final AtomosLayer child = installChild(atomosRuntime.getBootLayer(), "SINGLE",
-            atomosRuntime, LoaderType.SINGLE);
+        final Atomos atomos = bc.getService(
+            bc.getServiceReference(Atomos.class));
+        final AtomosLayer child = installChild(atomos.getBootLayer(), "SINGLE",
+            atomos, LoaderType.SINGLE);
         final Bundle b = child.findAtomosContent(
             TESTBUNDLES_SERVICE_IMPL_A).get().getBundle();
         assertNotNull(b, "No bundle found.");
@@ -462,16 +517,16 @@
     @Test
     void testInstallDifferentPrefix(@TempDir Path storage) throws BundleException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        final AtomosRuntime atomosRuntime = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
-        final AtomosLayer child = installChild(atomosRuntime.getBootLayer(), "SINGLE",
-            atomosRuntime, LoaderType.SINGLE);
+        final Atomos atomos = bc.getService(
+            bc.getServiceReference(Atomos.class));
+        final AtomosLayer child = installChild(atomos.getBootLayer(), "SINGLE",
+            atomos, LoaderType.SINGLE);
         final AtomosContent ab = child.findAtomosContent(
             TESTBUNDLES_SERVICE_IMPL_A).get();
         Bundle b = ab.getBundle();
@@ -509,22 +564,21 @@
         final File storage2 = new File(storage.toFile(), "s2");
         storage2.mkdirs();
 
-        testFramework = getFramework(
+        testFramework = getFramework(null,
                 Constants.FRAMEWORK_STORAGE + '='
                 + storage1.getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        final AtomosRuntime atomosRuntime = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
+        final Atomos atomos = bc.getService(
+            bc.getServiceReference(Atomos.class));
 
         Framework f = null;
         try
         {
-            f = AtomosLauncher.newFramework(
-                Map.of(Constants.FRAMEWORK_STORAGE, storage2.getAbsolutePath()),
-                atomosRuntime);
+            f = atomos.newFramework(
+                Map.of(Constants.FRAMEWORK_STORAGE, storage2.getAbsolutePath()));
             f.start();
             fail();
         }
@@ -546,37 +600,37 @@
     void testLoaderType(@TempDir Path storage) throws BundleException,
     ClassNotFoundException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        final AtomosRuntime atomosRuntime = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
-        checkLoader(atomosRuntime, installChild(atomosRuntime.getBootLayer(), "SINGLE",
-            atomosRuntime, LoaderType.SINGLE), LoaderType.SINGLE);
-        checkLoader(atomosRuntime, installChild(atomosRuntime.getBootLayer(), "MANY",
-            atomosRuntime, LoaderType.MANY), LoaderType.MANY);
-        checkLoader(atomosRuntime, installChild(atomosRuntime.getBootLayer(), "OSGI",
-            atomosRuntime, LoaderType.OSGI), LoaderType.OSGI);
+        final Atomos atomos = bc.getService(
+            bc.getServiceReference(Atomos.class));
+        checkLoader(atomos, installChild(atomos.getBootLayer(), "SINGLE",
+            atomos, LoaderType.SINGLE), LoaderType.SINGLE);
+        checkLoader(atomos, installChild(atomos.getBootLayer(), "MANY",
+            atomos, LoaderType.MANY), LoaderType.MANY);
+        checkLoader(atomos, installChild(atomos.getBootLayer(), "OSGI",
+            atomos, LoaderType.OSGI), LoaderType.OSGI);
     }
 
     @Test
     void testLoadFromModule(@TempDir Path storage)
         throws BundleException
     {
-        testFramework = getFramework(
-                Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath(),
-            AtomosLauncher.ATOMOS_MODULES_DIR + "=target/modules");
+        Path modules = new File("target/modules").toPath();
+        testFramework = getFramework(modules,
+            Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
-        final ServiceReference<AtomosRuntime> atomosRef = bc.getServiceReference(
-            AtomosRuntime.class);
+        final ServiceReference<Atomos> atomosRef = bc.getServiceReference(
+            Atomos.class);
         assertNotNull(atomosRef, "No Atomos runtime.");
 
-        final AtomosRuntime atomos = bc.getService(atomosRef);
+        final Atomos atomos = bc.getService(atomosRef);
         checkBundleStates(atomos, bc.getBundles());
 
         assertNotNull(atomos, "Null Atomos runtime.");
@@ -614,17 +668,17 @@
     void testModuleDirServices(@TempDir Path storage)
         throws BundleException, InvalidSyntaxException
     {
-        testFramework = getFramework(
-                Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath(),
-            AtomosLauncher.ATOMOS_MODULES_DIR + "=target/modules");
+        Path modules = new File("target/modules").toPath();
+        testFramework = getFramework(modules,
+            Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
-        final ServiceReference<AtomosRuntime> atomosRef = bc.getServiceReference(
-            AtomosRuntime.class);
+        final ServiceReference<Atomos> atomosRef = bc.getServiceReference(
+            Atomos.class);
         assertNotNull(atomosRef, "No Atomos runtime.");
 
-        final AtomosRuntime atomos = bc.getService(atomosRef);
+        final Atomos atomos = bc.getService(atomosRef);
         checkBundleStates(atomos, bc.getBundles());
 
         checkServices(bc, 4);
@@ -634,16 +688,16 @@
     void testModulePathServices(@TempDir Path storage)
         throws BundleException, InvalidSyntaxException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
-        final ServiceReference<AtomosRuntime> atomosRef = bc.getServiceReference(
-            AtomosRuntime.class);
+        final ServiceReference<Atomos> atomosRef = bc.getServiceReference(
+            Atomos.class);
         assertNotNull(atomosRef, "No Atomos runtime.");
 
-        final AtomosRuntime atomos = bc.getService(atomosRef);
+        final Atomos atomos = bc.getService(atomosRef);
         checkBundleStates(atomos, bc.getBundles());
 
         checkServices(bc, 2);
@@ -653,22 +707,22 @@
     void testPersistLayers(@TempDir Path storage)
         throws BundleException, InvalidSyntaxException, InterruptedException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        final AtomosRuntime atomosRuntime1 = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
-        installChild(atomosRuntime1.getBootLayer(), "SINGLE", atomosRuntime1,
+        final Atomos atomos1 = bc.getService(
+            bc.getServiceReference(Atomos.class));
+        installChild(atomos1.getBootLayer(), "SINGLE", atomos1,
             LoaderType.SINGLE);
-        installChild(atomosRuntime1.getBootLayer(), "MANY", atomosRuntime1,
+        installChild(atomos1.getBootLayer(), "MANY", atomos1,
             LoaderType.MANY);
-        installChild(atomosRuntime1.getBootLayer(), "OSGI", atomosRuntime1,
+        installChild(atomos1.getBootLayer(), "OSGI", atomos1,
             LoaderType.OSGI);
 
-        checkBundleStates(atomosRuntime1, bc.getBundles());
+        checkBundleStates(atomos1, bc.getBundles());
         checkServices(bc, 8);
 
         testFramework.stop();
@@ -678,8 +732,8 @@
         testFramework.start();
         bc = testFramework.getBundleContext();
 
-        final AtomosLayer child1 = installChild(atomosRuntime1.getBootLayer(), "SINGLE2",
-            atomosRuntime1, LoaderType.SINGLE);
+        final AtomosLayer child1 = installChild(atomos1.getBootLayer(), "SINGLE2",
+            atomos1, LoaderType.SINGLE);
 
         checkServices(bc, 10);
 
@@ -697,7 +751,7 @@
         testFramework.waitForStop(10000);
 
         // test persistent load with a new Runtime
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         bc = testFramework.getBundleContext();
@@ -705,9 +759,9 @@
 
         checkServices(bc, 8);
 
-        final AtomosRuntime atomosRuntime2 = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
-        final AtomosLayer bootLayer = atomosRuntime2.getBootLayer();
+        final Atomos atomos2 = bc.getService(
+            bc.getServiceReference(Atomos.class));
+        final AtomosLayer bootLayer = atomos2.getBootLayer();
         assertEquals(3, bootLayer.getChildren().size(), "Wrong number of children.");
 
         final List<AtomosLayer> children = bootLayer.getChildren().stream().sorted(
@@ -729,9 +783,9 @@
         testFramework.waitForStop(10000);
 
         // startup with the option not to force install all atomos contents
-        testFramework = getFramework(
+        testFramework = getFramework(null,
                 Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath(),
-            AtomosRuntime.ATOMOS_CONTENT_INSTALL + "=false");
+            Atomos.ATOMOS_CONTENT_INSTALL + "=false");
 
         bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
@@ -743,16 +797,16 @@
     void testReferenceUser(@TempDir Path storage)
         throws BundleException, InvalidSyntaxException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        final AtomosRuntime atomosRuntime = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
-        final AtomosLayer child = installChild(atomosRuntime.getBootLayer(), "testRef",
-            atomosRuntime, LoaderType.MANY);
+        final Atomos atomos = bc.getService(
+            bc.getServiceReference(Atomos.class));
+        final AtomosLayer child = installChild(atomos.getBootLayer(), "testRef",
+            atomos, LoaderType.MANY);
         checkServices(bc, 4);
         final AtomosContent ab = child.findAtomosContent(
             TESTBUNDLES_SERVICE_USER).get();
@@ -851,16 +905,16 @@
     {
         String[] args = new String[] {
                 Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath(),
-                AtomosRuntime.ATOMOS_CONTENT_INSTALL + "=false" };
+                Atomos.ATOMOS_CONTENT_INSTALL + "=false" };
 
-        testFramework = getFramework(args);
+        testFramework = getFramework(null, args);
         BundleContext bc = testFramework.getBundleContext();
 
         assertNotNull(bc, "No context found.");
         assertEquals(1, bc.getBundles().length, "Wrong number of bundles.");
 
-        AtomosRuntime runtime = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
+        Atomos runtime = bc.getService(
+            bc.getServiceReference(Atomos.class));
 
         AtomosContent systemContent = runtime.getConnectedContent(
             Constants.SYSTEM_BUNDLE_LOCATION);
@@ -943,11 +997,10 @@
         testFramework.waitForStop(5000);
 
         // start over from persistence
-        runtime = AtomosRuntime.newAtomosRuntime();
+        runtime = Atomos.newAtomos();
         implContent = runtime.getBootLayer().findAtomosContent(BSN_SERVICE_IMPL).get();
 
-        testFramework = AtomosLauncher.newFramework(AtomosLauncher.getConfiguration(args),
-            runtime);
+        testFramework = runtime.newFramework(Atomos.getConfiguration(args));
         testFramework.start();
         bc = testFramework.getBundleContext();
 
@@ -989,7 +1042,7 @@
     @Test
     void testModuleNameBSNDiffer(@TempDir Path storage) throws BundleException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
 
         // make sure the contract names are correct
@@ -1015,13 +1068,13 @@
     @Test
     void testMultiParentResolve(@TempDir Path storage) throws BundleException
     {
-        testFramework = getFramework(
+        testFramework = getFramework(null,
             Constants.FRAMEWORK_STORAGE + '=' + storage.toFile().getAbsolutePath());
         final BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No context found.");
 
-        final AtomosRuntime atomos = bc.getService(
-            bc.getServiceReference(AtomosRuntime.class));
+        final Atomos atomos = bc.getService(
+            bc.getServiceReference(Atomos.class));
         AtomosLayer layer1 = installChild(atomos, "layer1",
             List.of(atomos.getBootLayer()), TESTBUNDLES_DEPENDENCY_A);
         AtomosLayer layer2 = installChild(atomos, "layer2",
@@ -1047,7 +1100,7 @@
         assertEquals(Set.of(), layer2.getChildren(), "Wrong children for layer2.");
     }
 
-    private AtomosLayer installChild(AtomosRuntime atomos, String layerName,
+    private AtomosLayer installChild(Atomos atomos, String layerName,
         List<AtomosLayer> parents, String... moduleNames) throws BundleException
     {
         AtomosLayer layer = atomos.addLayer(parents, layerName, LoaderType.SINGLE,
diff --git a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/pom.xml b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/pom.xml
index 28c1da2..3c6700b 100644
--- a/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/pom.xml
+++ b/atomos.tests/atomos.tests.testbundles/atomos.tests.testbundles.service.user/pom.xml
@@ -10,7 +10,7 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.atomos.runtime</artifactId>
+            <artifactId>org.apache.felix.atomos</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
         <dependency>
diff --git a/atomos.runtime/bnd.bnd b/atomos/bnd.bnd
similarity index 100%
rename from atomos.runtime/bnd.bnd
rename to atomos/bnd.bnd
diff --git a/atomos.runtime/pom.xml b/atomos/pom.xml
similarity index 98%
rename from atomos.runtime/pom.xml
rename to atomos/pom.xml
index a59afe5..a593ede 100644
--- a/atomos.runtime/pom.xml
+++ b/atomos/pom.xml
@@ -7,8 +7,8 @@
         <version>1.0.0-SNAPSHOT</version>
         <relativePath>../atomos-parent/pom.xml</relativePath>
     </parent>
-    <artifactId>org.apache.felix.atomos.runtime</artifactId>
-    <name>atomos.runtime</name>
+    <artifactId>org.apache.felix.atomos</artifactId>
+    <name>atomos</name>
     <scm>
         <connection>scm:git:https://github.com/apache/felix-atomos.git</connection>
         <developerConnection>scm:git:https://github.com/apache/felix-atomos.git</developerConnection>
diff --git a/atomos.runtime/src/main/java/module-info.java b/atomos/src/main/java/module-info.java
similarity index 77%
rename from atomos.runtime/src/main/java/module-info.java
rename to atomos/src/main/java/module-info.java
index 73c76c6..b3ecb56 100644
--- a/atomos.runtime/src/main/java/module-info.java
+++ b/atomos/src/main/java/module-info.java
@@ -12,18 +12,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import org.apache.felix.atomos.impl.runtime.base.AtomosFrameworkUtilHelper;
-import org.apache.felix.atomos.impl.runtime.base.AtomosModuleConnector;
+import org.apache.felix.atomos.impl.base.AtomosFrameworkUtilHelper;
+import org.apache.felix.atomos.impl.base.AtomosModuleConnector;
 import org.osgi.framework.connect.ConnectFrameworkFactory;
 import org.osgi.framework.connect.FrameworkUtilHelper;
 import org.osgi.framework.connect.ModuleConnector;
 
-open module org.apache.felix.atomos.runtime
+open module org.apache.felix.atomos
 {
-    exports org.apache.felix.atomos.runtime;
-    exports org.apache.felix.atomos.launch;
+    exports org.apache.felix.atomos;
 
-    requires osgi.core;
+    requires transitive osgi.core;
     requires static osgi.annotation;
     requires static jdk.unsupported;
     requires static org.apache.felix.gogo.runtime;
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosRuntime.java b/atomos/src/main/java/org/apache/felix/atomos/Atomos.java
similarity index 67%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosRuntime.java
rename to atomos/src/main/java/org/apache/felix/atomos/Atomos.java
index 15bdc88..edd2000 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosRuntime.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/Atomos.java
@@ -11,25 +11,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.runtime;
+package org.apache.felix.atomos;
 
 import java.nio.file.Path;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.ServiceLoader;
 
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase;
-import org.apache.felix.atomos.launch.AtomosLauncher;
-import org.apache.felix.atomos.runtime.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.impl.base.AtomosBase;
+import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.connect.ConnectFrameworkFactory;
 import org.osgi.framework.connect.ModuleConnector;
 import org.osgi.framework.launch.Framework;
-import org.osgi.framework.launch.FrameworkFactory;
 
 /**
- * The Atomos runtime can be used for creating new OSGi
- * {@link Framework} instances with bundles loaded from the module or class
+ * Atomos can be used for creating new OSGi {@link Framework} instances 
+ * with bundles loaded from the module or class
  * path. The Framework instance will have a set of contents discovered and
  * installed as connected bundles automatically when the Framework is
  * {@link Framework#init() initialized}.
@@ -75,18 +76,14 @@
  * boot layer is also searched and loads all boot modules as bundles similar to
  * when loading from the module path.
  * <p>
- * The Framework can be created using the {@link FrameworkFactory} APIs like a
- * normal OSGi Framework or for more advanced scenarios the Atomos runtime can
- * be used to setup additional module layer configurations before launching the
- * framework.
- * <p>
+ * The Framework can be created using the {@link ConnectFrameworkFactory} APIs.
  * The following will launch using the standard {@link ConnectFrameworkFactory}:
  * 
  * <pre>
  * {@code Map<String, String>} config = getConfiguration();
  * config.put(Constants.FRAMEWORK_SYSTEMPACKAGES, "");
- * ModuleConnector atomosConnect = AtomosRuntime.newAtomosRuntime().newModuleConnector();
- * Framework framework = ServiceLoader.load(ConnectFrameworkFactory.class).iterator().next().newFramework(config, atomosConnect);
+ * ModuleConnector atomosConnector = Atomos.newAtomos().newModuleConnector();
+ * Framework framework = ServiceLoader.load(ConnectFrameworkFactory.class).iterator().next().newFramework(config, atomosConnector);
  * framework.start();
  * </pre>
  * 
@@ -106,24 +103,22 @@
  * create an {@link AtomosContent Atomos content} for each module contained in
  * the {@link ModuleLayer#boot() boot} layer.
  * <p>
- * The following code uses the AtomosRuntime to first create a child layer which
+ * The following code uses the Atomos to first create a child layer which
  * is then used to load more modules in addition to the ones included on the
  * module path.
  * 
  * <pre>
- * AtomosRuntime atomosRuntime = AtomosRuntime.newAtomosRuntime();
+ * Atomos atomos = Atomos.newAtomos();
  * 
  * // Add a new layer using a Path that contains a set of modules to load
  * Path modulesDir = getModulesDir();
- * atomosRuntime.getBootLayer.addLayer("child", LoaderType.OSGI, modulesDir);
+ * atomos.getBootLayer().addLayer("child", LoaderType.OSGI, modulesDir);
  *
- * // The Atomos runtime must be used to create the framework in order
- * // use the additional children layers added
- * Framework framework = AtomosLauncher.newFramework(frameworkConfig, atomosRuntime);
+ * Framework framework = atomos.newFramework(frameworkConfig);
  * framework.start();
  * </pre>
  * 
- * When using the {@link AtomosLauncher#newFramework(Map, AtomosRuntime)} to create a 
+ * When using the {@link Atomos#newFramework(Map)} to create a 
  * new Framework the {@link Constants#FRAMEWORK_SYSTEMPACKAGES}
  * is set to the empty value automatically.
  * 
@@ -135,24 +130,25 @@
  * selectively install Atomos contents. If {@link #ATOMOS_CONTENT_START
  * atomos.content.start} is set to <code>false</code> in the framework
  * configuration then the Atomos bundles will not be started by default. The
- * system.bundle of the initialized framework will also have an AtomosRuntime
+ * system.bundle of the initialized framework will also have an Atomos
  * service registered with its bundle context.
  */
-public interface AtomosRuntime
+@org.osgi.annotation.bundle.Header(name = "Main-Class", value = "org.apache.felix.atomos.Atomos")
+public interface Atomos
 {
     /**
      * Framework launching property specifying if the Atomos contents
      * will not be automatically installed as bundles. Default is true, which
      * will install all discovered Atomos content as bundles.
      */
-    String ATOMOS_CONTENT_INSTALL = AtomosRuntimeBase.ATOMOS_PROP_PREFIX
+    String ATOMOS_CONTENT_INSTALL = AtomosBase.ATOMOS_PROP_PREFIX
         + "content.install";
     /**
      * Framework launching property specifying if the Atomos contents installed
      * as connected bundles will not be marked for start. Default is true, which
      * will start all discovered Atomos content that are installed as bundles.
      */
-    String ATOMOS_CONTENT_START = AtomosRuntimeBase.ATOMOS_PROP_PREFIX + "content.start";
+    String ATOMOS_CONTENT_START = AtomosBase.ATOMOS_PROP_PREFIX + "content.start";
 
     /**
      * Returns the Atomos content that is connected with the specified bundle location.
@@ -200,20 +196,80 @@
         Path... modulePaths);
 
     /**
-     * Creates a new AtomosRuntime that can be used to create a new OSGi framework
-     * instance. Same as calling {@code newAtomosRuntime(Map)} with a {@code null} 
-     * configuration.
-     * 
-     * @return a new AtomosRuntime.
+     * Creates a new {@link Framework} instance that uses this Atomos instance. The
+     * {@link ServiceLoader} is used to load an implementation of a {@link ConnectFrameworkFactory}
+     * which is used to create a new {@link Framework} instance with the specified Atomos runtime.
+     * The supplied framework configuration is used to create the new {@code Framework} instance.
+     * Additional configuration options maybe configured automatically in order to correctly configure
+     * the system packages for the {@code Framework} instance.
+     * @param frameworkConfig The framework configuration options, or {@code null} if the defaults should be used
+     * @return The new uninitialized Framework instance which uses this Atomos instance
      */
-    static AtomosRuntime newAtomosRuntime()
+    public Framework newFramework(Map<String, String> frameworkConfig);
+
+    /**
+     * A main method that can be used by executable jars to initialize and start
+     * Atomos with an available OSGi {@link Framework} implementation.
+     * Each string in the arguments array may contain a key=value
+     * pair that will be used for the framework configuration.
+     * 
+     * @param args the args will be converted into a {@code Map<String, String>} to
+     *             use as configuration parameters for the OSGi Framework.
+     * @throws BundleException when an error occurs
+     * @see #newAtomos(Map)
+     * @see #newFramework(Map)
+     */
+    static void main(String... args) throws BundleException
     {
-        return newAtomosRuntime(Collections.emptyMap());
+        Map<String, String> config = getConfiguration(args);
+        // default to reporting resolution issues from main
+        config.putIfAbsent(AtomosBase.ATOMOS_REPORT_RESOLUTION_PROP, "true");
+        Atomos atomos = Atomos.newAtomos(config);
+        Framework framework = atomos.newFramework(config);
+        framework.start();
     }
 
     /**
-     * Creates a new AtomosRuntime that can be used to create a new OSGi framework
-     * instance. If Atomos is running as a Java Module then this AtomosRuntime can
+     * Converts a string array into a {@code  Map<String,String>}
+     * 
+     * @param args the arguments where each element has key=string value, the key
+     *             cannot contain an '=' (equals) character.
+     * @return a map of the configuration specified by the args
+     */
+    public static Map<String, String> getConfiguration(String... args)
+    {
+        Map<String, String> config = new HashMap<>();
+        if (args != null)
+        {
+            for (String arg : args)
+            {
+                int equals = arg.indexOf('=');
+                if (equals != -1)
+                {
+                    String key = arg.substring(0, equals);
+                    String value = arg.substring(equals + 1);
+                    config.put(key, value);
+                }
+            }
+        }
+        return config;
+    }
+
+    /**
+     * Creates a new Atomos that can be used to create a new OSGi framework
+     * instance. Same as calling {@code newAtomos(Map)} with an empty 
+     * configuration.
+     * 
+     * @return a new Atomos.
+     */
+    static Atomos newAtomos()
+    {
+        return newAtomos(Collections.emptyMap());
+    }
+
+    /**
+     * Creates a new Atomos that can be used to create a new OSGi framework
+     * instance. If Atomos is running as a Java Module then this Atomos can
      * be used to create additional layers by using the
      * {@link AtomosLayer#addLayer(String, AtomosLayer.LoaderType, Path...)} method. If the additional layers are added
      * before {@link ConnectFrameworkFactory#newFramework(Map, ModuleConnector)}  creating} and {@link Framework#init()
@@ -221,15 +277,15 @@
      * will be automatically installed and started according to the
      * {@link #ATOMOS_CONTENT_INSTALL} and {@link #ATOMOS_CONTENT_START} options.
      * <p>
-     * Note that this {@code AtomosRuntime} must be used for creating a new
+     * Note that this {@code Atomos} must be used for creating a new
      * {@link ConnectFrameworkFactory#newFramework(Map, ModuleConnector)} instance to use
-     * the layers added to this {@code AtomosRuntime}.
+     * the layers added to this {@code Atomos}.
      * 
      * @param configuration the properties to configure the new runtime
-     * @return a new AtomosRuntime.
+     * @return a new Atomos.
      */
-    static AtomosRuntime newAtomosRuntime(Map<String, String> configuration)
+    static Atomos newAtomos(Map<String, String> configuration)
     {
-        return AtomosRuntimeBase.newAtomosRuntime(configuration);
+        return AtomosBase.newAtomos(configuration);
     }
 }
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosContent.java b/atomos/src/main/java/org/apache/felix/atomos/AtomosContent.java
similarity index 96%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosContent.java
rename to atomos/src/main/java/org/apache/felix/atomos/AtomosContent.java
index b33c279..59ba39f 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosContent.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/AtomosContent.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.runtime;
+package org.apache.felix.atomos;
 
 import java.util.Optional;
 
@@ -60,7 +60,7 @@
      * @param type Class object for the type to which this Atomos content is to be
      *        adapted.
      * @return The object, of the specified type, to which this Atomos content has been
-     *         adapted or {@code null} if this content cannot be adapted to the
+     *         adapted or {@code empty} if this content cannot be adapted to the
      *         specified type.
      */
     <T> Optional<T> adapt(Class<T> type);
@@ -90,8 +90,8 @@
      *     throw new BundleException();
      *   }
      * }
-     * atomosBundle.disconnect();
-     * atomosBundle.connect(osgiLocation);
+     * atomosContent.disconnect();
+     * atomosContent.connect(osgiLocation);
      * b = bc.installBundle(osgiLocation);
      * </pre>
      * @param prefix the prefix to use, if {@code null} then the prefix "atomos" will be used
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosLayer.java b/atomos/src/main/java/org/apache/felix/atomos/AtomosLayer.java
similarity index 94%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosLayer.java
rename to atomos/src/main/java/org/apache/felix/atomos/AtomosLayer.java
index 57e1d87..0fc64da 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/AtomosLayer.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/AtomosLayer.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.runtime;
+package org.apache.felix.atomos;
 
 import java.nio.file.Path;
 import java.util.List;
@@ -25,8 +25,8 @@
 
 /**
  * An Atomos Layer may represents a {@link ModuleLayer} that was added to
- * a {@link AtomosRuntime} using the {@link AtomosLayer#addLayer(String, LoaderType, Path...)}  addLayer}
- * method or the Atomos Layer could represent the {@link AtomosRuntime#getBootLayer() boot layer}.
+ * a {@link Atomos} using the {@link AtomosLayer#addLayer(String, LoaderType, Path...)}  addLayer}
+ * method or the Atomos Layer could represent the {@link Atomos#getBootLayer() boot layer}.
  * An Atomos Layer will contain one or more {@link AtomosContent Atomos contents} which can
  * then be used to {@link AtomosContent#install(String) install } them as OSGi connected bundles into the
  * {@link ConnectFrameworkFactory#newFramework(Map, ModuleConnector)}  framework}.
@@ -55,6 +55,7 @@
          */
         MANY
     }
+    
     /**
      * Adapt this Atomos layer to the specified type. For example,
      * if running in a module layer then the layer can be adapted
@@ -63,7 +64,7 @@
      * @param type Class object for the type to which this Atomos layer is to be
      *        adapted.
      * @return The object, of the specified type, to which this Atomos layer has been
-     *         adapted or {@code null} if this layer cannot be adapted to the
+     *         adapted or {@code empty} if this layer cannot be adapted to the
      *         specified type.
      */
     <T> Optional<T> adapt(Class<T> type);
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosRuntimeBase.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosBase.java
similarity index 95%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosRuntimeBase.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosBase.java
index 3c945e0..727b9be 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosRuntimeBase.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosBase.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.base;
+package org.apache.felix.atomos.impl.base;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -46,16 +46,16 @@
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
 
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase.AtomosLayerBase.AtomosContentBase;
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase.AtomosLayerBase.AtomosContentIndexed;
-import org.apache.felix.atomos.impl.runtime.content.ConnectContentCloseableJar;
-import org.apache.felix.atomos.impl.runtime.content.ConnectContentFile;
-import org.apache.felix.atomos.impl.runtime.content.ConnectContentIndexed;
-import org.apache.felix.atomos.impl.runtime.content.ConnectContentJar;
-import org.apache.felix.atomos.runtime.AtomosContent;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosLayer.LoaderType;
-import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.apache.felix.atomos.Atomos;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.felix.atomos.AtomosLayer;
+import org.apache.felix.atomos.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.impl.base.AtomosBase.AtomosLayerBase.AtomosContentBase;
+import org.apache.felix.atomos.impl.base.AtomosBase.AtomosLayerBase.AtomosContentIndexed;
+import org.apache.felix.atomos.impl.content.ConnectContentCloseableJar;
+import org.apache.felix.atomos.impl.content.ConnectContentFile;
+import org.apache.felix.atomos.impl.content.ConnectContentIndexed;
+import org.apache.felix.atomos.impl.content.ConnectContentJar;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
@@ -72,6 +72,7 @@
 import org.osgi.framework.connect.ModuleConnector;
 import org.osgi.framework.hooks.bundle.CollisionHook;
 import org.osgi.framework.hooks.resolver.ResolverHookFactory;
+import org.osgi.framework.launch.Framework;
 import org.osgi.framework.namespace.IdentityNamespace;
 import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.wiring.BundleCapability;
@@ -80,7 +81,7 @@
 
 import sun.misc.Signal;
 
-public abstract class AtomosRuntimeBase implements AtomosRuntime, SynchronousBundleListener, FrameworkUtilHelper, FrameworkListener
+public abstract class AtomosBase implements Atomos, SynchronousBundleListener, FrameworkUtilHelper, FrameworkListener
 {
     static final String JAR_PROTOCOL = "jar";
     static final String FILE_PROTOCOL = "file";
@@ -93,9 +94,8 @@
     public static final String ATOMOS_BUNDLES_INDEX_DEFAULT = "/atomos/bundles.index";
     public static final String ATOMOS_BUNDLE = "ATOMOS_BUNDLE";
     public static final String ATOMOS_LIB_DIR_PROP = ATOMOS_PROP_PREFIX + "lib.dir";
-    public static final String ATOMOS_RUNTIME_CLASS_PROP = ATOMOS_PROP_PREFIX
-        + "runtime.class";
-    public static final String ATOMOS_RUNTIME_MODULES_CLASS = "org.apache.felix.atomos.impl.runtime.modules.AtomosRuntimeModules";
+    public static final String ATOMOS_CLASS_PROP = ATOMOS_PROP_PREFIX + ".class";
+    public static final String ATOMOS_RUNTIME_MODULES_CLASS = "org.apache.felix.atomos.impl.modules.AtomosModules";
     public static final String ATOMOS_LIB_DIR = "atomos_lib";
     public static final String GRAAL_NATIVE_IMAGE_KIND = "org.graalvm.nativeimage.kind";
 
@@ -107,7 +107,7 @@
     private final AtomicReference<File> storeRoot = new AtomicReference<>();
 
     private ServiceRegistration<?> atomosCommandsReg = null;
-    private ServiceRegistration<?> atomosRuntimeReg = null;
+    private ServiceRegistration<?> atomosReg = null;
     protected final Map<String, String> config = new ConcurrentHashMap<String, String>();
 
     private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@@ -137,9 +137,9 @@
         IGNORE, FIRST
     }
 
-    public static AtomosRuntime newAtomosRuntime(Map<String, String> config)
+    public static Atomos newAtomos(Map<String, String> config)
     {
-        String runtimeClass = config.get(ATOMOS_RUNTIME_CLASS_PROP);
+        String runtimeClass = config.get(ATOMOS_CLASS_PROP);
         if (runtimeClass != null)
         {
             return loadRuntime(runtimeClass, config);
@@ -148,7 +148,7 @@
             ATOMOS_LIB_DIR_PROP) != null
             || System.getProperty(GRAAL_NATIVE_IMAGE_KIND) != null)
         {
-            return new AtomosRuntimeClassPath(config);
+            return new AtomosClassPath(config);
         }
         try
         {
@@ -160,15 +160,15 @@
             // ignore
         }
         // default to classpath
-        return new AtomosRuntimeClassPath(config);
+        return new AtomosClassPath(config);
     }
 
-    private static AtomosRuntime loadRuntime(String runtimeClass,
+    private static Atomos loadRuntime(String runtimeClass,
         Map<String, String> config)
     {
         try
         {
-            return (AtomosRuntimeBase) Class.forName(
+            return (AtomosBase) Class.forName(
                 runtimeClass).getConstructor(Map.class).newInstance(config);
         }
         catch (Exception e)
@@ -184,7 +184,7 @@
         return new File(libDirProp, ATOMOS_LIB_DIR);
     }
 
-    protected AtomosRuntimeBase(Map<String, String> config)
+    protected AtomosBase(Map<String, String> config)
     {
         saveConfig(config);
         DEBUG = Boolean.parseBoolean(this.config.get(ATOMOS_DEBUG_PROP));
@@ -409,6 +409,20 @@
         return new AtomosModuleConnector(this);
     }
 
+    @Override
+    public Framework newFramework(Map<String, String> frameworkConfig)
+    {
+        frameworkConfig = frameworkConfig == null ? new HashMap<>()
+            : new HashMap<>(frameworkConfig);
+
+        populateConfig(frameworkConfig);
+
+        // Always allow the console to work
+        frameworkConfig.putIfAbsent("osgi.console", "");
+
+        return findFrameworkFactory().newFramework(frameworkConfig, getModuleConnector());
+    }
+
     abstract public ConnectFrameworkFactory findFrameworkFactory();
 
     protected final BundleContext getBundleContext()
@@ -657,7 +671,7 @@
         public AtomosLayer addLayer(String name, LoaderType loaderType,
             Path... modulePaths)
         {
-            return AtomosRuntimeBase.this.addLayer(Collections.singletonList(this), name,
+            return AtomosBase.this.addLayer(Collections.singletonList(this), name,
                 -1, loaderType, modulePaths);
         }
 
@@ -1317,7 +1331,7 @@
             @Override
             public Bundle getBundle()
             {
-                return AtomosRuntimeBase.this.getBundle(this);
+                return AtomosBase.this.getBundle(this);
             }
 
             @Override
@@ -1486,13 +1500,13 @@
         }
         catch (IOException e)
         {
-            throw new RuntimeException("Failed to save atomos runtime.", e);
+            throw new RuntimeException("Failed to save atomos.", e);
         }
     });
 
     protected void start(BundleContext bc) throws BundleException
     {
-        debug("Activating Atomos runtime");
+        debug("Activating Atomos");
         this.context.set(bc);
         Runtime.getRuntime().addShutdownHook(saveOnVMExit);
         AtomosFrameworkUtilHelper.addHelper(this);
@@ -1509,11 +1523,11 @@
         bc.registerService(CollisionHook.class, hooks, null);
 
         boolean installBundles = Boolean.parseBoolean(
-            getProperty(bc, AtomosRuntime.ATOMOS_CONTENT_INSTALL, "true"));
+            getProperty(bc, Atomos.ATOMOS_CONTENT_INSTALL, "true"));
         boolean startBundles = Boolean.parseBoolean(
-            getProperty(bc, AtomosRuntime.ATOMOS_CONTENT_START, "true"));
+            getProperty(bc, Atomos.ATOMOS_CONTENT_START, "true"));
         installAtomosContents(getBootLayer(), installBundles, startBundles);
-        atomosRuntimeReg = bc.registerService(AtomosRuntime.class, this, null);
+        atomosReg = bc.registerService(Atomos.class, this, null);
         atomosCommandsReg = new AtomosCommands(this).register(bc);
     }
 
@@ -1564,7 +1578,7 @@
     }
     protected void stop(BundleContext bc) throws BundleException
     {
-        debug("Stopping Atomos runtime");
+        debug("Stopping Atomos");
         this.context.compareAndSet(bc, null);
         try
         {
@@ -1578,7 +1592,7 @@
         }
         catch (IOException e)
         {
-            throw new BundleException("Failed to save atomos runtime.", e);
+            throw new BundleException("Failed to save atomos.", e);
         }
 
         bc.removeBundleListener(this);
@@ -1586,7 +1600,7 @@
 
         AtomosFrameworkUtilHelper.removeHelper(this);
         atomosCommandsReg.unregister();
-        atomosRuntimeReg.unregister();
+        atomosReg.unregister();
     }
 
     private String getProperty(BundleContext bc, String key, String defaultValue)
@@ -1658,7 +1672,7 @@
         if (!storeRoot.compareAndSet(null, storage))
         {
             throw new IllegalStateException(
-                "This AtomosRuntime is already being used by store: " + storeRoot.get());
+                "This Atomos is already being used by store: " + storeRoot.get());
         }
         try
         {
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosRuntimeClassPath.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosClassPath.java
similarity index 89%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosRuntimeClassPath.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosClassPath.java
index 3391596..fdf279c 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosRuntimeClassPath.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosClassPath.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package org.apache.felix.atomos.impl.runtime.base;
+package org.apache.felix.atomos.impl.base;
 
 import java.nio.file.Path;
 import java.util.Collection;
@@ -23,18 +23,18 @@
 import java.util.ServiceLoader;
 import java.util.Set;
 
-import org.apache.felix.atomos.runtime.AtomosContent;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.felix.atomos.AtomosLayer;
+import org.apache.felix.atomos.AtomosLayer.LoaderType;
 import org.osgi.framework.connect.ConnectFrameworkFactory;
 import org.osgi.framework.wiring.BundleCapability;
 
-public class AtomosRuntimeClassPath extends AtomosRuntimeBase
+public class AtomosClassPath extends AtomosBase
 {
 
     private final AtomosLayer bootLayer = createBootLayer();
 
-    public AtomosRuntimeClassPath(Map<String, String> config)
+    public AtomosClassPath(Map<String, String> config)
     {
         super(config);
     }
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosCommands.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosCommands.java
similarity index 94%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosCommands.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosCommands.java
index 7fa52ad..f433e83 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosCommands.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosCommands.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.base;
+package org.apache.felix.atomos.impl.base;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -23,9 +23,9 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.apache.felix.atomos.runtime.AtomosContent;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.felix.atomos.AtomosLayer;
+import org.apache.felix.atomos.AtomosLayer.LoaderType;
 import org.apache.felix.service.command.Descriptor;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -36,9 +36,9 @@
 {
 
     public static String[] functions = new String[] { "list", "install", "uninstall" };
-    private final AtomosRuntimeBase runtime;
+    private final AtomosBase runtime;
 
-    public AtomosCommands(AtomosRuntimeBase runtime)
+    public AtomosCommands(AtomosBase runtime)
     {
         this.runtime = runtime;
     }
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosFrameworkHooks.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosFrameworkHooks.java
similarity index 77%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosFrameworkHooks.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosFrameworkHooks.java
index 8296a16..5f997e7 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosFrameworkHooks.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosFrameworkHooks.java
@@ -11,12 +11,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.base;
+package org.apache.felix.atomos.impl.base;
 
 import java.util.Collection;
 import java.util.Iterator;
 
-import org.apache.felix.atomos.runtime.AtomosContent;
+import org.apache.felix.atomos.AtomosContent;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.hooks.bundle.CollisionHook;
 import org.osgi.framework.hooks.resolver.ResolverHook;
@@ -42,25 +42,25 @@
         public void filterSingletonCollisions(BundleCapability singleton,
             Collection<BundleCapability> collisionCandidates)
         {
-            AtomosContent atomosBundle = atomosRuntime.getByConnectLocation(
+            AtomosContent content = atomos.getByConnectLocation(
                 singleton.getRevision().getBundle().getLocation(), true);
-            atomosRuntime.filterNotVisible(atomosBundle, collisionCandidates);
+            atomos.filterNotVisible(content, collisionCandidates);
         }
 
         @Override
         public void filterMatches(BundleRequirement requirement,
             Collection<BundleCapability> candidates)
         {
-            AtomosContent atomosBundle = atomosRuntime.getByConnectLocation(
+            AtomosContent atomosBundle = atomos.getByConnectLocation(
                 requirement.getRevision().getBundle().getLocation(), true);
             switch (requirement.getNamespace())
             {
                 case PackageNamespace.PACKAGE_NAMESPACE:
                 case BundleNamespace.BUNDLE_NAMESPACE:
-                    atomosRuntime.filterBasedOnReadEdges(atomosBundle, candidates);
+                    atomos.filterBasedOnReadEdges(atomosBundle, candidates);
                     return;
                 default:
-                    atomosRuntime.filterNotVisible(atomosBundle, candidates);
+                    atomos.filterNotVisible(atomosBundle, candidates);
             }
 
         }
@@ -73,11 +73,11 @@
 
     }
 
-    final AtomosRuntimeBase atomosRuntime;
+    final AtomosBase atomos;
 
-    AtomosFrameworkHooks(AtomosRuntimeBase atomosRuntime)
+    AtomosFrameworkHooks(AtomosBase atomos)
     {
-        this.atomosRuntime = atomosRuntime;
+        this.atomos = atomos;
     }
 
     @Override
@@ -90,18 +90,18 @@
     public void filterCollisions(int operationType, Bundle target,
         Collection<Bundle> collisionCandidates)
     {
-        AtomosContent currentlyManaging = atomosRuntime.currentlyManagingConnected();
+        AtomosContent currentlyManaging = atomos.currentlyManagingConnected();
         if (currentlyManaging != null)
         {
             for (Iterator<Bundle> iCands = collisionCandidates.iterator(); iCands.hasNext();)
             {
                 Bundle b = iCands.next();
-                AtomosContent candidate = atomosRuntime.getConnectedContent(
+                AtomosContent candidate = atomos.getConnectedContent(
                     b.getLocation());
                 if (candidate != null)
                 {
                     // Only other atomos connected contents can be filtered out
-                    if (!atomosRuntime.isInLayerHierarchy(
+                    if (!atomos.isInLayerHierarchy(
                         currentlyManaging.getAtomosLayer(), candidate.getAtomosLayer()))
                     {
                         iCands.remove();
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosFrameworkUtilHelper.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosFrameworkUtilHelper.java
similarity index 96%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosFrameworkUtilHelper.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosFrameworkUtilHelper.java
index 0ab8c64..48ba08b 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosFrameworkUtilHelper.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosFrameworkUtilHelper.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package org.apache.felix.atomos.impl.runtime.base;
+package org.apache.felix.atomos.impl.base;
 
 import java.util.Optional;
 import java.util.Set;
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosModuleConnector.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosModuleConnector.java
similarity index 65%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosModuleConnector.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosModuleConnector.java
index 0e2f6ab..aadf90f 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosModuleConnector.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosModuleConnector.java
@@ -12,14 +12,14 @@
  * limitations under the License.
  */
 
-package org.apache.felix.atomos.impl.runtime.base;
+package org.apache.felix.atomos.impl.base;
 
 import java.io.File;
 import java.util.Map;
 import java.util.Optional;
 
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase.AtomosLayerBase.AtomosContentBase;
-import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.apache.felix.atomos.Atomos;
+import org.apache.felix.atomos.impl.base.AtomosBase.AtomosLayerBase.AtomosContentBase;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.connect.ConnectModule;
@@ -27,38 +27,38 @@
 
 public class AtomosModuleConnector implements ModuleConnector
 {
-    final AtomosRuntimeBase atomosRuntime;
+    final AtomosBase atomos;
 
     public AtomosModuleConnector()
     {
         this(null);
     }
 
-    public AtomosModuleConnector(AtomosRuntimeBase atomosRuntime)
+    public AtomosModuleConnector(AtomosBase atomos)
     {
-        if (atomosRuntime == null)
+        if (atomos == null)
         {
-            atomosRuntime = (AtomosRuntimeBase) AtomosRuntime.newAtomosRuntime();
+            atomos = (AtomosBase) Atomos.newAtomos();
         }
-        this.atomosRuntime = atomosRuntime;
+        this.atomos = atomos;
     }
 
     @Override
     public Optional<BundleActivator> newBundleActivator()
     {
-        atomosRuntime.debug("Creating Atomos activator");
+        atomos.debug("Creating Atomos activator");
         return Optional.of(new BundleActivator()
         {
             @Override
             public void start(BundleContext bc) throws Exception
             {
-                atomosRuntime.start(bc);
+                atomos.start(bc);
             }
 
             @Override
             public void stop(BundleContext bc) throws Exception
             {
-                atomosRuntime.stop(bc);
+                atomos.stop(bc);
             }
         });
     }
@@ -66,15 +66,15 @@
     @Override
     public Optional<ConnectModule> connect(String location)
     {
-        atomosRuntime.debug("Framework is attempting to connect location: %s", location);
+        atomos.debug("Framework is attempting to connect location: %s", location);
 
-        final AtomosContentBase atomosBundle = atomosRuntime.getByConnectLocation(
+        final AtomosContentBase atomosBundle = atomos.getByConnectLocation(
             location, false);
         if (atomosBundle == null)
         {
             return Optional.empty();
         }
-        atomosRuntime.addManagingConnected(atomosBundle, location);
+        atomos.addManagingConnected(atomosBundle, location);
         return Optional.of(atomosBundle::getConnectContent);
 
     }
@@ -82,7 +82,7 @@
     @Override
     public void initialize(File storage, Map<String, String> configuration)
     {
-        atomosRuntime.initialize(storage, configuration);
+        atomos.initialize(storage, configuration);
     }
 
 }
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosStorage.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosStorage.java
similarity index 78%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosStorage.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosStorage.java
index a27cd82..1a4233e 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/AtomosStorage.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/AtomosStorage.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.base;
+package org.apache.felix.atomos.impl.base;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -30,31 +30,31 @@
 import java.util.List;
 import java.util.Set;
 
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase.AtomosLayerBase;
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase.AtomosLayerBase.AtomosContentBase;
-import org.apache.felix.atomos.runtime.AtomosContent;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.felix.atomos.AtomosLayer;
+import org.apache.felix.atomos.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.impl.base.AtomosBase.AtomosLayerBase;
+import org.apache.felix.atomos.impl.base.AtomosBase.AtomosLayerBase.AtomosContentBase;
 import org.osgi.framework.Constants;
 
 public class AtomosStorage
 {
     private final static int VERSION = 1;
     private final static String ATOMOS_STORE = "atomosStore.data";
-    private final AtomosRuntimeBase atomosRuntime;
+    private final AtomosBase atomos;
 
-    public AtomosStorage(AtomosRuntimeBase atomosRuntime)
+    public AtomosStorage(AtomosBase atomos)
     {
-        this.atomosRuntime = atomosRuntime;
+        this.atomos = atomos;
     }
 
     void loadLayers(File root) throws IOException
     {
-        atomosRuntime.lockWrite();
+        atomos.lockWrite();
         try (DataInputStream in = new DataInputStream(
             new BufferedInputStream(new FileInputStream(new File(root, ATOMOS_STORE)))))
         {
-            atomosRuntime.debug("Found %s in %s", ATOMOS_STORE, root);
+            atomos.debug("Found %s in %s", ATOMOS_STORE, root);
             int persistentVersion = in.readInt();
             if (persistentVersion > VERSION)
             {
@@ -64,7 +64,7 @@
             }
             long nextLayerId = in.readLong();
             int numLayers = in.readInt();
-            if (numLayers > 1 && !atomosRuntime.getBootLayer().isAddLayerSupported())
+            if (numLayers > 1 && !atomos.getBootLayer().isAddLayerSupported())
             {
                 System.out.println(
                     "Atomos persistent layers are ignored because Atomos is not loaded as a module.");
@@ -74,30 +74,30 @@
             {
                 readLayer(in);
             }
-            atomosRuntime.nextLayerId.set(nextLayerId);
+            atomos.nextLayerId.set(nextLayerId);
         }
         catch (FileNotFoundException e)
         {
             // ignore no file
-            atomosRuntime.debug("No %s found in %s", ATOMOS_STORE, root);
+            atomos.debug("No %s found in %s", ATOMOS_STORE, root);
         }
         finally
         {
-            atomosRuntime.unlockWrite();
+            atomos.unlockWrite();
         }
     }
 
     void saveLayers(File root) throws IOException
     {
         File atomosStore = new File(root, ATOMOS_STORE);
-        atomosRuntime.lockRead();
+        atomos.lockRead();
         try (DataOutputStream out = new DataOutputStream(
             new BufferedOutputStream(new FileOutputStream(atomosStore))))
         {
             out.writeInt(VERSION);
-            out.writeLong(atomosRuntime.nextLayerId.get());
+            out.writeLong(atomos.nextLayerId.get());
             List<AtomosLayerBase> writeOrder = getLayerWriteOrder(
-                atomosRuntime.getBootLayer(), new HashSet<>(),
+                atomos.getBootLayer(), new HashSet<>(),
                 new ArrayList<>());
             out.writeInt(writeOrder.size());
             for (AtomosLayerBase layer : writeOrder)
@@ -107,7 +107,7 @@
         }
         finally
         {
-            atomosRuntime.unlockRead();
+            atomos.unlockRead();
         }
     }
 
@@ -141,7 +141,7 @@
         String name = in.readUTF();
         long id = in.readLong();
         LoaderType loaderType = LoaderType.valueOf(in.readUTF());
-        atomosRuntime.debug("Loading layer %s %s %s", name, id, loaderType);
+        atomos.debug("Loading layer %s %s %s", name, id, loaderType);
 
         int numPaths = in.readInt();
         Path[] paths = new Path[numPaths];
@@ -164,18 +164,18 @@
         for (int i = 0; i < numParents; i++)
         {
             long parentId = in.readLong();
-            AtomosLayerBase parent = atomosRuntime.getById(parentId);
+            AtomosLayerBase parent = atomos.getById(parentId);
             if (parent == null)
             {
                 throw new IllegalArgumentException("Missing parent with id: " + parentId);
             }
             parents.add(parent);
         }
-        if (atomosRuntime.getById(id) == null)
+        if (atomos.getById(id) == null)
         {
             try
             {
-                atomosRuntime.addLayer(parents, name, id, loaderType, paths);
+                atomos.addLayer(parents, name, id, loaderType, paths);
             }
             catch (Exception e)
             {
@@ -188,25 +188,25 @@
         for (int i = 0; i < numBundles; i++)
         {
             String atomosLocation = in.readUTF();
-            atomosRuntime.debug("Found Atomos location %s", atomosLocation);
+            atomos.debug("Found Atomos location %s", atomosLocation);
             if (in.readBoolean())
             {
                 String connectLocation = in.readUTF();
-                atomosRuntime.debug("Found connected location %s", connectLocation);
+                atomos.debug("Found connected location %s", connectLocation);
                 if (Constants.SYSTEM_BUNDLE_LOCATION.equals(connectLocation))
                 {
                     // don't do anything for the system bundle, it is already connected
                     continue;
                 }
-                AtomosContentBase atomosContent = atomosRuntime.getByAtomosLocation(
+                AtomosContentBase atomosContent = atomos.getByAtomosLocation(
                     atomosLocation);
                 if (atomosContent != null)
                 {
-                    atomosRuntime.connectAtomosContent(connectLocation, atomosContent);
+                    atomos.connectAtomosContent(connectLocation, atomosContent);
                 }
                 else
                 {
-                    atomosRuntime.debug("Unable to find atomos content for location %s",
+                    atomos.debug("Unable to find atomos content for location %s",
                         atomosLocation);
                 }
             }
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/JavaServiceNamespace.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/JavaServiceNamespace.java
similarity index 97%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/JavaServiceNamespace.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/JavaServiceNamespace.java
index 4c95e46..776f57c 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/JavaServiceNamespace.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/JavaServiceNamespace.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.base;
+package org.apache.felix.atomos.impl.base;
 
 import java.util.ServiceLoader;
 
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/package-info.java b/atomos/src/main/java/org/apache/felix/atomos/impl/base/package-info.java
similarity index 91%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/package-info.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/base/package-info.java
index 8ae24f0..11654cd 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/base/package-info.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/base/package-info.java
@@ -11,4 +11,4 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.base;
\ No newline at end of file
+package org.apache.felix.atomos.impl.base;
\ No newline at end of file
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentCloseableJar.java b/atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentCloseableJar.java
similarity index 94%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentCloseableJar.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentCloseableJar.java
index 0a13fac..e02bd9c 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentCloseableJar.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentCloseableJar.java
@@ -11,9 +11,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.content;
+package org.apache.felix.atomos.impl.content;
 
-import static org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase.sneakyThrow;
+import static org.apache.felix.atomos.impl.base.AtomosBase.sneakyThrow;
 
 import java.io.File;
 import java.io.IOException;
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentFile.java b/atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentFile.java
similarity index 98%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentFile.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentFile.java
index 920fc41..7069585 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentFile.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentFile.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.content;
+package org.apache.felix.atomos.impl.content;
 
 import java.io.File;
 import java.io.FileInputStream;
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentIndexed.java b/atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentIndexed.java
similarity index 97%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentIndexed.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentIndexed.java
index 039be3b..964957d 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentIndexed.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentIndexed.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.content;
+package org.apache.felix.atomos.impl.content;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentJar.java b/atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentJar.java
similarity index 97%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentJar.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentJar.java
index 1e144bf..1875a1c 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/ConnectContentJar.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/content/ConnectContentJar.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.content;
+package org.apache.felix.atomos.impl.content;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/package-info.java b/atomos/src/main/java/org/apache/felix/atomos/impl/content/package-info.java
similarity index 91%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/package-info.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/content/package-info.java
index e1eb2b8..3c70208 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/content/package-info.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/content/package-info.java
@@ -11,4 +11,4 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.content;
\ No newline at end of file
+package org.apache.felix.atomos.impl.content;
\ No newline at end of file
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/AtomosRuntimeModules.java b/atomos/src/main/java/org/apache/felix/atomos/impl/modules/AtomosModules.java
similarity index 96%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/AtomosRuntimeModules.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/modules/AtomosModules.java
index 3eef765..dc79eb9 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/AtomosRuntimeModules.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/modules/AtomosModules.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.modules;
+package org.apache.felix.atomos.impl.modules;
 
 import java.io.File;
 import java.io.IOException;
@@ -43,11 +43,11 @@
 import java.util.jar.Manifest;
 import java.util.stream.Collectors;
 
-import org.apache.felix.atomos.impl.runtime.base.AtomosRuntimeBase;
-import org.apache.felix.atomos.runtime.AtomosContent;
-import org.apache.felix.atomos.runtime.AtomosLayer;
-import org.apache.felix.atomos.runtime.AtomosLayer.LoaderType;
-import org.apache.felix.atomos.runtime.AtomosRuntime;
+import org.apache.felix.atomos.AtomosContent;
+import org.apache.felix.atomos.AtomosLayer;
+import org.apache.felix.atomos.Atomos;
+import org.apache.felix.atomos.AtomosLayer.LoaderType;
+import org.apache.felix.atomos.impl.base.AtomosBase;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -56,15 +56,15 @@
 import org.osgi.framework.launch.FrameworkFactory;
 import org.osgi.framework.wiring.BundleCapability;
 
-public class AtomosRuntimeModules extends AtomosRuntimeBase
+public class AtomosModules extends AtomosBase
 {
-    private final Module thisModule = AtomosRuntimeModules.class.getModule();
+    private final Module thisModule = AtomosModules.class.getModule();
     private final Configuration thisConfig = thisModule.getLayer() == null ? null
         : thisModule.getLayer().configuration();
     private final Map<Configuration, AtomosLayerBase> byConfig = new HashMap<>();
     private final AtomosLayer bootLayer = createBootLayer();
 
-    public AtomosRuntimeModules(Map<String, String> config)
+    public AtomosModules(Map<String, String> config)
     {
         super(config);
     }
@@ -115,7 +115,7 @@
     public ConnectFrameworkFactory findFrameworkFactory()
     {
         ServiceLoader<ConnectFrameworkFactory> loader;
-        if (AtomosRuntime.class.getModule().getLayer() == null)
+        if (Atomos.class.getModule().getLayer() == null)
         {
             loader = ServiceLoader.load(ConnectFrameworkFactory.class,
                 getClass().getClassLoader());
@@ -413,7 +413,7 @@
                 if (path == null)
                 {
                     ResolvedModule resolved = thisConfig.findModule(
-                        AtomosRuntime.class.getModule().getName()).get();
+                        Atomos.class.getModule().getName()).get();
                     URI location = resolved.reference().location().get();
                     if (location.getScheme().equals("file"))
                     {
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/ConnectContentModule.java b/atomos/src/main/java/org/apache/felix/atomos/impl/modules/ConnectContentModule.java
similarity index 97%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/ConnectContentModule.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/modules/ConnectContentModule.java
index d9bd842..4f16ff7 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/ConnectContentModule.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/modules/ConnectContentModule.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.modules;
+package org.apache.felix.atomos.impl.modules;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -30,8 +30,8 @@
 import java.util.jar.Attributes.Name;
 import java.util.jar.Manifest;
 
-import org.apache.felix.atomos.impl.runtime.base.JavaServiceNamespace;
-import org.apache.felix.atomos.impl.runtime.modules.AtomosRuntimeModules.AtomosLayerModules;
+import org.apache.felix.atomos.impl.base.JavaServiceNamespace;
+import org.apache.felix.atomos.impl.modules.AtomosModules.AtomosLayerModules;
 import org.osgi.framework.Constants;
 import org.osgi.framework.Version;
 import org.osgi.framework.connect.ConnectContent;
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/ModuleConnectLoader.java b/atomos/src/main/java/org/apache/felix/atomos/impl/modules/ModuleConnectLoader.java
similarity index 97%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/ModuleConnectLoader.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/modules/ModuleConnectLoader.java
index 4ba375b..b3718a7 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/ModuleConnectLoader.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/modules/ModuleConnectLoader.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.modules;
+package org.apache.felix.atomos.impl.modules;
 
 import java.io.IOException;
 import java.lang.module.Configuration;
@@ -48,12 +48,12 @@
 
     private final ResolvedModule resolvedModule;
     private final ModuleReader reader;
-    private final AtomosRuntimeModules atomosRuntime;
+    private final AtomosModules atomos;
     private final AtomicReference<Module> module = new AtomicReference<>();
 
     private final HashMap<String, ClassLoader> edges = new HashMap<>();
 
-    public ModuleConnectLoader(ResolvedModule resolvedModule, AtomosRuntimeModules atomosRuntimeModules) throws IOException
+    public ModuleConnectLoader(ResolvedModule resolvedModule, AtomosModules atomosModules) throws IOException
     {
         super("ModuleConnectLoader-" + resolvedModule.name(), null);
 
@@ -61,7 +61,7 @@
         //TODO remove reference and reader? Or Reader needs to be closed?
         ModuleReference reference = resolvedModule.reference();
         this.reader = reference.open();
-        this.atomosRuntime = atomosRuntimeModules;
+        this.atomos = atomosModules;
     }
 
     /** explicit call from AtomosRuntimBundle to allow resources to be freed.
@@ -326,6 +326,6 @@
     @Override
     public Bundle getBundle()
     {
-        return atomosRuntime.getBundle(module.get());
+        return atomos.getBundle(module.get());
     }
 }
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/package-info.java b/atomos/src/main/java/org/apache/felix/atomos/impl/modules/package-info.java
similarity index 91%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/package-info.java
rename to atomos/src/main/java/org/apache/felix/atomos/impl/modules/package-info.java
index f9e4650..530c521 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/impl/runtime/modules/package-info.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/impl/modules/package-info.java
@@ -11,4 +11,4 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.impl.runtime.modules;
\ No newline at end of file
+package org.apache.felix.atomos.impl.modules;
\ No newline at end of file
diff --git a/atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/package-info.java b/atomos/src/main/java/org/apache/felix/atomos/package-info.java
similarity index 94%
rename from atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/package-info.java
rename to atomos/src/main/java/org/apache/felix/atomos/package-info.java
index 281f76c..de58c9a 100644
--- a/atomos.runtime/src/main/java/org/apache/felix/atomos/runtime/package-info.java
+++ b/atomos/src/main/java/org/apache/felix/atomos/package-info.java
@@ -14,4 +14,4 @@
 @org.osgi.annotation.bundle.Export
 @org.osgi.annotation.versioning.Version("1.0.0")
 @org.osgi.annotation.bundle.Requirement(namespace = "osgi.ee", filter = "(&(osgi.ee=JavaSE)(version=1.8))")
-package org.apache.felix.atomos.runtime;
\ No newline at end of file
+package org.apache.felix.atomos;
\ No newline at end of file
diff --git a/atomos.runtime/src/main/resources/META-INF/services/org.osgi.framework.connect.FrameworkUtilHelper b/atomos/src/main/resources/META-INF/services/org.osgi.framework.connect.FrameworkUtilHelper
similarity index 91%
rename from atomos.runtime/src/main/resources/META-INF/services/org.osgi.framework.connect.FrameworkUtilHelper
rename to atomos/src/main/resources/META-INF/services/org.osgi.framework.connect.FrameworkUtilHelper
index 9004a78..121ebe4 100644
--- a/atomos.runtime/src/main/resources/META-INF/services/org.osgi.framework.connect.FrameworkUtilHelper
+++ b/atomos/src/main/resources/META-INF/services/org.osgi.framework.connect.FrameworkUtilHelper
@@ -14,4 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-org.apache.felix.atomos.impl.runtime.base.AtomosFrameworkUtilHelper
+org.apache.felix.atomos.impl.base.AtomosFrameworkUtilHelper
diff --git a/atomos.runtime/src/main/resources/META-INF/services/org.osgi.framework.connect.ModuleConnector b/atomos/src/main/resources/META-INF/services/org.osgi.framework.connect.ModuleConnector
similarity index 92%
rename from atomos.runtime/src/main/resources/META-INF/services/org.osgi.framework.connect.ModuleConnector
rename to atomos/src/main/resources/META-INF/services/org.osgi.framework.connect.ModuleConnector
index 07b6e52..8253f94 100644
--- a/atomos.runtime/src/main/resources/META-INF/services/org.osgi.framework.connect.ModuleConnector
+++ b/atomos/src/main/resources/META-INF/services/org.osgi.framework.connect.ModuleConnector
@@ -14,4 +14,4 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-org.apache.felix.atomos.impl.runtime.base.AtomosModuleConnector
\ No newline at end of file
+org.apache.felix.atomos.impl.base.AtomosModuleConnector
\ No newline at end of file
diff --git a/atomos.runtime/src/test/java/org/apache/felix/atomos/runtime/AtomosRuntimeTest.java b/atomos/src/test/java/org/apache/felix/atomos/AtomosTest.java
similarity index 89%
rename from atomos.runtime/src/test/java/org/apache/felix/atomos/runtime/AtomosRuntimeTest.java
rename to atomos/src/test/java/org/apache/felix/atomos/AtomosTest.java
index 5a82774..cbf9b7d 100644
--- a/atomos.runtime/src/test/java/org/apache/felix/atomos/runtime/AtomosRuntimeTest.java
+++ b/atomos/src/test/java/org/apache/felix/atomos/AtomosTest.java
@@ -11,7 +11,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.runtime;
+package org.apache.felix.atomos;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -29,10 +29,9 @@
 import java.util.ServiceLoader;
 import java.util.function.Supplier;
 
-import org.apache.felix.atomos.impl.runtime.base.AtomosFrameworkUtilHelper;
-import org.apache.felix.atomos.impl.runtime.base.AtomosModuleConnector;
-import org.apache.felix.atomos.impl.runtime.base.JavaServiceNamespace;
-import org.apache.felix.atomos.launch.AtomosLauncher;
+import org.apache.felix.atomos.impl.base.AtomosFrameworkUtilHelper;
+import org.apache.felix.atomos.impl.base.AtomosModuleConnector;
+import org.apache.felix.atomos.impl.base.JavaServiceNamespace;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
@@ -49,7 +48,7 @@
 import org.osgi.resource.Namespace;
 import org.osgi.resource.Requirement;
 
-public class AtomosRuntimeTest
+public class AtomosTest
 {
 
     private Framework testFramework;
@@ -69,10 +68,10 @@
     @Test
     void testRuntime(@TempDir Path storage) throws BundleException
     {
-        AtomosRuntime runtime = AtomosRuntime.newAtomosRuntime();
+        Atomos runtime = Atomos.newAtomos();
         Map<String, String> config = Map.of(Constants.FRAMEWORK_STORAGE,
             storage.toFile().getAbsolutePath());
-        testFramework = AtomosLauncher.newFramework(config, runtime);
+        testFramework = runtime.newFramework(config);
         doTestFramework(testFramework);
     }
 
@@ -80,7 +79,7 @@
     void testFactory(@TempDir Path storage) throws BundleException
     {
         doTestFactory(storage,
-            () -> AtomosRuntime.newAtomosRuntime().getModuleConnector());
+            () -> Atomos.newAtomos().getModuleConnector());
     }
 
     @Test
@@ -151,11 +150,11 @@
     @Test
     void testConnectDisconnect(@TempDir Path storage) throws BundleException
     {
-        AtomosRuntime runtime = AtomosRuntime.newAtomosRuntime();
+        Atomos runtime = Atomos.newAtomos();
         Map<String, String> config = Map.of( //
             Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath(),
-            AtomosRuntime.ATOMOS_CONTENT_INSTALL, "false");
-        testFramework = AtomosLauncher.newFramework(config, runtime);
+            Atomos.ATOMOS_CONTENT_INSTALL, "false");
+        testFramework = runtime.newFramework(config);
         testFramework.start();
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No BundleContext found.");
@@ -194,10 +193,10 @@
 
     @Test
     void testGetConnectContent(@TempDir Path storage) throws BundleException, IOException {
-        AtomosRuntime runtime = AtomosRuntime.newAtomosRuntime();
+        Atomos runtime = Atomos.newAtomos();
         Map<String, String> config = Map.of( //
             Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath());
-        testFramework = AtomosLauncher.newFramework(config, runtime);
+        testFramework = runtime.newFramework(config);
         testFramework.start();
 
         AtomosContent atomosContent;
@@ -215,7 +214,7 @@
     }
 
     private void failConnect(AtomosContent c1, AtomosContent c2, BundleContext bc,
-        AtomosRuntime runtime) throws BundleException
+        Atomos runtime) throws BundleException
     {
         Bundle b1 = c1.getBundle();
         try
@@ -248,7 +247,7 @@
         assertEquals(b1, reinstall, "Wrong bundle.");
     }
 
-    private void connect(AtomosRuntime runtime, AtomosContent content, BundleContext bc)
+    private void connect(Atomos runtime, AtomosContent content, BundleContext bc)
         throws BundleException
     {
         assertNull(content.getConnectLocation(), "Unexpected connect location.");
@@ -266,11 +265,11 @@
     @Test
     void testInstallPrefix(@TempDir Path storage) throws BundleException
     {
-        AtomosRuntime runtime = AtomosRuntime.newAtomosRuntime();
+        Atomos runtime = Atomos.newAtomos();
         Map<String, String> config = Map.of( //
             Constants.FRAMEWORK_STORAGE, storage.toFile().getAbsolutePath(),
-            AtomosRuntime.ATOMOS_CONTENT_INSTALL, "false");
-        testFramework = AtomosLauncher.newFramework(config, runtime);
+            Atomos.ATOMOS_CONTENT_INSTALL, "false");
+        testFramework = runtime.newFramework(config);
         testFramework.start();
         BundleContext bc = testFramework.getBundleContext();
         assertNotNull(bc, "No BundleContext found.");
@@ -288,7 +287,7 @@
         failInstall(javaBase, javaXML, bc, runtime);
     }
 
-    private void install(AtomosRuntime runtime, AtomosContent content, BundleContext bc)
+    private void install(Atomos runtime, AtomosContent content, BundleContext bc)
         throws BundleException
     {
         Bundle b = content.install("test");
@@ -303,7 +302,7 @@
     }
 
     private void failInstall(AtomosContent c1, AtomosContent c2, BundleContext bc,
-        AtomosRuntime runtime) throws BundleException
+        Atomos runtime) throws BundleException
     {
         Bundle b1 = c1.getBundle();
         String b1Location = b1.getLocation();
@@ -351,12 +350,12 @@
     @Test
     void testJavaServiceNamespace(@TempDir Path storage) throws BundleException
     {
-        AtomosRuntime runtime = AtomosRuntime.newAtomosRuntime();
+        Atomos runtime = Atomos.newAtomos();
         Map<String, String> config = Map.of(Constants.FRAMEWORK_STORAGE,
             storage.toFile().getAbsolutePath());
-        testFramework = AtomosLauncher.newFramework(config, runtime);
+        testFramework = runtime.newFramework(config);
         testFramework.init();
-        AtomosContent runtimeContent = runtime.getBootLayer().findAtomosContent("org.apache.felix.atomos.runtime").get();
+        AtomosContent runtimeContent = runtime.getBootLayer().findAtomosContent("org.apache.felix.atomos").get();
         Bundle b = runtimeContent.getBundle();
         assertNotNull(b, "No atomos runtime bundle.");
         BundleRevision rev = b.adapt(BundleRevision.class);
diff --git a/atomos.runtime/src/test/java/org/apache/felix/atomos/runtime/AtomosLauncherTest.java b/atomos/src/test/java/org/apache/felix/atomos/GetConfigurationTest.java
similarity index 74%
rename from atomos.runtime/src/test/java/org/apache/felix/atomos/runtime/AtomosLauncherTest.java
rename to atomos/src/test/java/org/apache/felix/atomos/GetConfigurationTest.java
index f4fa44e..068f604 100644
--- a/atomos.runtime/src/test/java/org/apache/felix/atomos/runtime/AtomosLauncherTest.java
+++ b/atomos/src/test/java/org/apache/felix/atomos/GetConfigurationTest.java
@@ -11,24 +11,24 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.felix.atomos.runtime;
+package org.apache.felix.atomos;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Map;
 
-import org.apache.felix.atomos.launch.AtomosLauncher;
+import org.apache.felix.atomos.Atomos;
 import org.junit.jupiter.api.Test;
 
-public class AtomosLauncherTest
+public class GetConfigurationTest
 {
 
     @Test
     void testRuntimeConfigSimple()
     {
         String[] args = { "a=1", "b=2" };
-        Map<String, String> map = AtomosLauncher.getConfiguration(args);
+        Map<String, String> map = Atomos.getConfiguration(args);
         assertEquals(2, map.size());
         assertEquals("1", map.get("a"));
         assertEquals("2", map.get("b"));
@@ -38,7 +38,7 @@
     void testRuntimeConfig()
     {
         String[] args = { "calc=1+1=2", "separator==" };
-        Map<String, String> map = AtomosLauncher.getConfiguration(args);
+        Map<String, String> map = Atomos.getConfiguration(args);
         assertEquals(2, map.size());
         assertEquals("1+1=2", map.get("calc"));
         assertEquals("=", map.get("separator"));
@@ -48,7 +48,7 @@
     void testRuntimeConfigFilter()
     {
         String[] args = { "nono", "no:no" };
-        Map<String, String> map = AtomosLauncher.getConfiguration(args);
+        Map<String, String> map = Atomos.getConfiguration(args);
         assertEquals(0, map.size());
     }
 
@@ -56,7 +56,7 @@
     void testRuntimeConfigSameKey()
     {
         String[] args = { "a=1", "a=2" };
-        Map<String, String> map = AtomosLauncher.getConfiguration(args);
+        Map<String, String> map = Atomos.getConfiguration(args);
         assertEquals(1, map.size());
         assertEquals("2", map.get("a"));
     }
@@ -65,7 +65,7 @@
     void testRuntimeConfigNoValue()
     {
         String[] args = { "a=" };
-        Map<String, String> map = AtomosLauncher.getConfiguration(args);
+        Map<String, String> map = Atomos.getConfiguration(args);
         assertEquals(1, map.size());
         assertEquals("", map.get("a"));
     }
@@ -74,7 +74,7 @@
     void testRuntimeConfigEmpty()
     {
         String[] args = {};
-        Map<String, String> map = AtomosLauncher.getConfiguration(args);
+        Map<String, String> map = Atomos.getConfiguration(args);
         assertTrue(map.isEmpty());
     }
 
@@ -82,7 +82,7 @@
     void testRuntimeConfigNull()
     {
         String[] args = null;
-        Map<String, String> map = AtomosLauncher.getConfiguration(args);
+        Map<String, String> map = Atomos.getConfiguration(args);
         assertTrue(map.isEmpty());
     }
 }
diff --git a/pom.xml b/pom.xml
index 4ad4d82..5dab168 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
     <modules>
         <module>atomos-parent</module>
         <module>atomos.osgi.core</module>
-        <module>atomos.runtime</module>
+        <module>atomos</module>
         <module>atomos.tests</module>
         <module>atomos.utils</module>
         <module>atomos.maven</module>