diff --git a/independent-projects/arc/arquillian/pom.xml b/independent-projects/arc/arquillian/pom.xml
new file mode 100644
index 0000000000000..38043e4e86ad0
--- /dev/null
+++ b/independent-projects/arc/arquillian/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+
+ io.quarkus.arc
+ arc-parent
+ 999-SNAPSHOT
+
+
+ arc-arquillian
+ ArC - Arquillian Container
+
+
+
+
+ org.jboss.arquillian
+ arquillian-bom
+ ${version.arquillian}
+ pom
+ import
+
+
+
+
+
+
+ io.quarkus.arc
+ arc-processor
+
+
+
+ org.jboss.arquillian.container
+ arquillian-container-spi
+
+
+ org.jboss.arquillian.container
+ arquillian-container-test-spi
+
+
+ org.jboss.arquillian.container
+ arquillian-container-test-impl-base
+
+
+
+
diff --git a/independent-projects/arc/arquillian/src/main/java/io/quarkus/arc/arquillian/ArcContainerConfiguration.java b/independent-projects/arc/arquillian/src/main/java/io/quarkus/arc/arquillian/ArcContainerConfiguration.java
new file mode 100644
index 0000000000000..28c3e245147cf
--- /dev/null
+++ b/independent-projects/arc/arquillian/src/main/java/io/quarkus/arc/arquillian/ArcContainerConfiguration.java
@@ -0,0 +1,10 @@
+package io.quarkus.arc.arquillian;
+
+import org.jboss.arquillian.container.spi.ConfigurationException;
+import org.jboss.arquillian.container.spi.client.container.ContainerConfiguration;
+
+public class ArcContainerConfiguration implements ContainerConfiguration {
+ @Override
+ public void validate() throws ConfigurationException {
+ }
+}
diff --git a/independent-projects/arc/arquillian/src/main/java/io/quarkus/arc/arquillian/ArcDeployableContainer.java b/independent-projects/arc/arquillian/src/main/java/io/quarkus/arc/arquillian/ArcDeployableContainer.java
new file mode 100644
index 0000000000000..fef060e773718
--- /dev/null
+++ b/independent-projects/arc/arquillian/src/main/java/io/quarkus/arc/arquillian/ArcDeployableContainer.java
@@ -0,0 +1,171 @@
+package io.quarkus.arc.arquillian;
+
+import java.io.File;
+import java.io.IOException;
+
+import jakarta.enterprise.event.Shutdown;
+import jakarta.enterprise.event.Startup;
+
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.container.spi.client.container.DeploymentException;
+import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
+import org.jboss.arquillian.container.spi.context.annotation.DeploymentScoped;
+import org.jboss.arquillian.core.api.Instance;
+import org.jboss.arquillian.core.api.InstanceProducer;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.arquillian.test.spi.TestClass;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.jboss.shrinkwrap.descriptor.api.Descriptor;
+
+import io.quarkus.arc.Arc;
+import io.quarkus.arc.ArcContainer;
+import io.quarkus.arc.InjectableInstance;
+import io.quarkus.arc.InstanceHandle;
+import io.quarkus.arc.arquillian.utils.ClassLoading;
+import io.quarkus.arc.arquillian.utils.Directories;
+
+public class ArcDeployableContainer implements DeployableContainer {
+ @Inject
+ @DeploymentScoped
+ private InstanceProducer deploymentDir;
+
+ @Inject
+ @DeploymentScoped
+ private InstanceProducer deploymentClassLoader;
+
+ @Inject
+ @DeploymentScoped
+ private InstanceProducer runningArc;
+
+ @Inject
+ private Instance testClass;
+
+ static Object testInstance;
+
+ @Override
+ public Class getConfigurationClass() {
+ return ArcContainerConfiguration.class;
+ }
+
+ @Override
+ public void setup(ArcContainerConfiguration configuration) {
+ }
+
+ @Override
+ public ProtocolDescription getDefaultProtocol() {
+ return new ProtocolDescription("ArC");
+ }
+
+ @Override
+ public ProtocolMetaData deploy(Archive> archive) throws DeploymentException {
+ if (System.getProperty("saveArchive") != null) {
+ File file = new File(archive.getName());
+ archive.as(ZipExporter.class).exportTo(file);
+ System.out.println("Archive for test " + testClass.get().getName() + " saved in: " + file.getAbsolutePath());
+ }
+
+ if (testClass.get() == null) {
+ throw new IllegalStateException("Test class not available");
+ }
+ String testClassName = testClass.get().getName();
+
+ ClassLoader old = Thread.currentThread().getContextClassLoader();
+ try {
+ DeploymentDir deploymentDir = new DeploymentDir();
+ this.deploymentDir.set(deploymentDir);
+
+ DeploymentClassLoader deploymentClassLoader = new Deployer(archive, deploymentDir, testClassName).deploy();
+ this.deploymentClassLoader.set(deploymentClassLoader);
+
+ Thread.currentThread().setContextClassLoader(deploymentClassLoader);
+
+ ArcContainer arcContainer = Arc.initialize();
+ runningArc.set(arcContainer);
+ arcContainer.beanManager().getEvent().fire(new Startup());
+
+ Class> actualTestClass = Class.forName(testClassName, true, deploymentClassLoader);
+ testInstance = findTest(arcContainer, actualTestClass);
+ } catch (Throwable t) {
+ // clone the exception into the correct class loader
+ Throwable nt = ClassLoading.cloneExceptionIntoSystemCL(t);
+ throw new DeploymentException("Unable to start ArC", nt);
+ } finally {
+ Thread.currentThread().setContextClassLoader(old);
+ }
+
+ return new ProtocolMetaData();
+ }
+
+ private Object findTest(ArcContainer arc, Class> testClass) {
+ InjectableInstance> instance = arc.select(testClass);
+ if (instance.isResolvable()) {
+ return instance.get();
+ }
+
+ // fallback for generic test classes, whose set of bean types does not contain a `Class`
+ // but a `ParameterizedType` instead
+ for (InstanceHandle