diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8ab105a892f39a38343b71583a1747e06ea07ffb..58bc800e578ee0541a6d06d5ebbebcf4e378dba2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -46,7 +46,18 @@ test:
       junit: "ragconnect.tests/build/test-results/**/TEST-*.xml"
     expire_in: 1 week
 
-publish:
+publish-dev:
+  image: openjdk:11
+  stage: publish
+  needs:
+    - test
+  script:
+    - "./gradlew setDevVersionForCI"
+    - "./gradlew publish"
+  except:
+    - master
+
+publish-master:
   image: openjdk:11
   stage: publish
   needs:
@@ -54,7 +65,6 @@ publish:
   script:
     - "./gradlew publish"
   only:
-    - dev
     - master
 
 ragdoc_build:
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..716e4573edac6a32f4fe667ce5fa8140e2ee8858
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,6 @@
+plugins {
+    id 'com.github.ben-manes.versions' version '0.42.0'
+    id 'java'
+}
+
+java.toolchain.languageVersion.set(JavaLanguageVersion.of(11))
diff --git a/gradle.properties b/gradle.properties
index 036899c6241c9aefbd7613611ceb35349d9d6624..10f87a12d6325a7c2aecf6e7c23f1c6dcae731f8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,2 +1,3 @@
 log4j_version = 2.14.0
-mustache_java_version = 0.9.7
+mustache_java_version = 0.9.10
+preprocessor_version = 0.1.0-41
diff --git a/libs/jastadd2.jar b/libs/jastadd2.jar
deleted file mode 100644
index 3c952d30318ddc23d38d7ccb277ee8431fe6b000..0000000000000000000000000000000000000000
Binary files a/libs/jastadd2.jar and /dev/null differ
diff --git a/libs/relast.jar b/libs/relast.jar
deleted file mode 100644
index b1a7542048dd1611db7f479307b0285efd8bb1f6..0000000000000000000000000000000000000000
Binary files a/libs/relast.jar and /dev/null differ
diff --git a/ragconnect.base/build.gradle b/ragconnect.base/build.gradle
index 7275d3ba1afc3347e047f840ad3188e3b6048c6c..21b7e3c276c390735e1fddcd68a80bc18eb87fe1 100644
--- a/ragconnect.base/build.gradle
+++ b/ragconnect.base/build.gradle
@@ -1,3 +1,4 @@
+// --- Buildscripts (must be at the top) ---
 buildscript {
     repositories.mavenCentral()
     dependencies {
@@ -5,21 +6,18 @@ buildscript {
     }
 }
 
+// --- Plugin definitions ---
 plugins {
+    id 'com.github.ben-manes.versions'
     id 'java'
-    id 'java-library'
     id 'idea'
-    id 'com.github.ben-manes.versions' version '0.36.0'
-    id 'maven-publish'
+    id 'org.jastadd'
     id 'application'
+    id 'java-library'
+    id 'maven-publish'
 }
 
-apply plugin: 'jastadd'
-
-group = 'de.tudresden.inf.st'
-
-mainClassName = 'org.jastadd.ragconnect.compiler.Compiler'
-
+// --- Dependencies ---
 repositories {
     mavenCentral()
     maven {
@@ -27,76 +25,60 @@ repositories {
         url "https://git-st.inf.tu-dresden.de/api/v4/groups/jastadd/-/packages/maven"
     }
 }
-tasks.compileJava {
-    options.release.set(11)
+
+configurations {
+    relast
 }
 
 dependencies {
-    implementation project(':relast-preprocessor')
+    relast group: 'org.jastadd', name: 'relast', version: "0.3.0-137"
+    implementation group: 'org.jastadd', name: 'relast-preprocessor', version: "${preprocessor_version}"
     implementation group: 'com.github.spullara.mustache.java', name: 'compiler', version: "${mustache_java_version}"
     runtimeOnly group: 'org.jastadd', name: 'jastadd2', version: '2.3.5-dresden'
-//    runtimeOnly fileTree(include: ['jastadd2.jar'], dir: '../libs')
     api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
 }
 
-java {
-    toolchain {
-        languageVersion.set(JavaLanguageVersion.of(11))
-    }
+// --- Preprocessors ---
+ext {
+    extractLocation = "src/gen/jastadd-sources/relast.preprocessor"
 }
-
-def versionFile = 'src/main/resources/ragConnectVersion.properties'
-def props = new Properties()
-
-try {
-    file(versionFile).withInputStream { stream -> props.load(stream) }
-    version = props['version']
-} catch (e) {
-    // this happens, if either the properties file is not present, or cannot be read from
-    throw new GradleException("File ${versionFile} not found or unreadable. Aborting.", e)
-}
-
-task printVersion() {
-    doLast {
-        println(version)
-    }
-}
-
-task newVersion() {
-    doFirst {
-        def newProps = new Properties()
-        newProps['version'] = value
-        newProps.store(file(versionFile).newWriter(), null)
-    }
-}
-
 File genSrc = file("src/gen/java")
 sourceSets.main.java.srcDir genSrc
 idea.module.generatedSourceDirs += genSrc
 
-jar {
-    manifest {
-        attributes "Main-Class": 'org.jastadd.ragconnect.compiler.Compiler'
-    }
-
-    from {
-        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
+task extractJastAddSources(type: Sync) {
+    dependsOn configurations.runtimeClasspath
+    configurations.runtimeClasspath.asFileTree.filter { it.toString().endsWith("relast-preprocessor-${preprocessor_version}.jar") }.collect {
+        from(zipTree(it)) {
+            include "**/*.jrag"
+            include "**/*.jadd"
+            include "**/*.ast"
+            include "**/*.relast"
+            include "**/*.flex"
+            include "**/*.parser"
+        }
     }
-    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
-
-    archiveBaseName = 'ragconnect'
+    includeEmptyDirs false
+    into file("${extractLocation}")
 }
 
 File preprocessorGrammar = file('../relast-preprocessor/src/main/jastadd/RelAst.relast')
 File ragConnectGrammar = file('./src/main/jastadd/RagConnect.relast')
 File intermediateGrammar = file('./src/main/jastadd/Intermediate.relast')
 File mustacheGrammar = file('../relast-preprocessor/src/main/jastadd/mustache/Mustache.relast')
+
 task relast(type: JavaExec) {
     group = 'Build'
-    main = "-jar"
+    classpath = configurations.relast
+    mainClass = 'org.jastadd.relast.compiler.Compiler'
+
+    dependsOn extractJastAddSources
+
+    doFirst {
+        mkdir "src/gen/jastadd/"
+    }
 
     args = [
-            "../libs/relast.jar",
             preprocessorGrammar,
             ragConnectGrammar,
             intermediateGrammar,
@@ -128,52 +110,45 @@ clean {
     delete "src/gen/jastadd/RagConnectResolverStubs.jrag"
 }
 
+// --- JastAdd ---
 jastadd {
     configureModuleBuild()
     modules {
         //noinspection GroovyAssignabilityCheck
         module("RagConnect") {
 
-            java {
-                basedir ".."
-                include "relast-preprocessor/main/**/*.java"
-                include "relast-preprocessor/gen/**/*.java"
-                include "ragconnect.base/src/main/**/*.java"
-                include "ragconnect.base/src/gen/**/*.java"
-            }
-
             jastadd {
-                basedir ".."
-                include "relast-preprocessor/src/main/jastadd/**/*.ast"
-                include "relast-preprocessor/src/main/jastadd/**/*.jadd"
-                include "relast-preprocessor/src/main/jastadd/**/*.jrag"
-                include "ragconnect.base/src/main/jastadd/**/*.ast"
-                include "ragconnect.base/src/main/jastadd/**/*.jadd"
-                include "ragconnect.base/src/main/jastadd/**/*.jrag"
-                include "ragconnect.base/src/gen/jastadd/**/*.ast"
-                include "ragconnect.base/src/gen/jastadd/**/*.jadd"
-                include "ragconnect.base/src/gen/jastadd/**/*.jrag"
+                basedir "."
+                include "src/gen/jastadd-sources/relast.preprocessor/**/*.ast"
+                include "src/gen/jastadd-sources/relast.preprocessor/**/*.jadd"
+                include "src/gen/jastadd-sources/relast.preprocessor/**/*.jrag"
+                include "src/main/jastadd/**/*.ast"
+                include "src/main/jastadd/**/*.jadd"
+                include "src/main/jastadd/**/*.jrag"
+                include "src/gen/jastadd/**/*.ast"
+                include "src/gen/jastadd/**/*.jadd"
+                include "src/gen/jastadd/**/*.jrag"
             }
 
             scanner {
-                basedir ".."
-                include "ragconnect.base/src/main/jastadd/scanner/Header.flex",             [-5]
-                include "relast-preprocessor/src/main/jastadd/scanner/Preamble.flex",       [-4]
-                include "relast-preprocessor/src/main/jastadd/scanner/Macros.flex",         [-3]
-                include "ragconnect.base/src/main/jastadd/scanner/Macros.flex",             [-3]
-                include "relast-preprocessor/src/main/jastadd/scanner/RulesPreamble.flex",  [-2]
-                include "ragconnect.base/src/main/jastadd/scanner/MappingContent.flex",     [-1]
-                include "ragconnect.base/src/main/jastadd/scanner/Keywords.flex"
-                include "relast-preprocessor/src/main/jastadd/scanner/Keywords.flex"
-                include "relast-preprocessor/src/main/jastadd/scanner/Symbols.flex",        [1]
-                include "relast-preprocessor/src/main/jastadd/scanner/RulesPostamble.flex", [2]
+                basedir "."
+                include "src/main/jastadd/scanner/Header.flex",                                    [-5]
+                include "src/gen/jastadd-sources/relast.preprocessor/scanner/Preamble.flex",       [-4]
+                include "src/gen/jastadd-sources/relast.preprocessor/scanner/Macros.flex",         [-3]
+                include "src/main/jastadd/scanner/Macros.flex",                                    [-3]
+                include "src/gen/jastadd-sources/relast.preprocessor/scanner/RulesPreamble.flex",  [-2]
+                include "src/main/jastadd/scanner/MappingContent.flex",                            [-1]
+                include "src/main/jastadd/scanner/Keywords.flex"
+                include "src/gen/jastadd-sources/relast.preprocessor/scanner/Keywords.flex"
+                include "src/gen/jastadd-sources/relast.preprocessor/scanner/Symbols.flex",        [ 1]
+                include "src/gen/jastadd-sources/relast.preprocessor/scanner/RulesPostamble.flex", [ 2]
             }
 
             parser {
-                basedir ".."
-                include "ragconnect.base/src/main/jastadd/parser/Preamble.parser"
-                include "ragconnect.base/src/main/jastadd/parser/RagConnect.parser"
-                include "relast-preprocessor/src/main/jastadd/parser/RelAst.parser"
+                basedir "."
+                include "src/main/jastadd/parser/Preamble.parser"
+                include "src/main/jastadd/parser/RagConnect.parser"
+                include "src/gen/jastadd-sources/relast.preprocessor/parser/RelAst.parser"
             }
         }
     }
@@ -184,9 +159,7 @@ jastadd {
     }
 
     preprocessParser.doFirst {
-
         args += ["--no-beaver-symbol"]
-
     }
 
     module = "RagConnect"
@@ -205,28 +178,73 @@ jastadd {
     jastaddOptions = ["--lineColumnNumbers", "--List=JastAddList", "--safeLazy", "--visitCheck=true", "--rewrite=cnta", "--cache=all"]
 }
 
-generateAst.dependsOn relast
+// --- Versioning and Publishing ---
+group = 'de.tudresden.inf.st'
+
+ext {
+    mainClassName = 'org.jastadd.ragconnect.compiler.Compiler'
+}
+application.mainClassName = "${mainClassName}"
+
+jar {
+    manifest.attributes "Main-Class": "${mainClassName}"
+}
+
+task fatJar(type: Jar) {
+    dependsOn jar
+    group = "build"
+    archiveAppendix = "fatjar"
+    from sourceSets.main.output
+    from {
+        configurations.runtimeClasspath.collect {it.isDirectory() ? it : zipTree(it) }
+    }
+
+    manifest.attributes "Main-Class": "${mainClassName}"
+}
+
+def versionFile = "src/main/resources/ragconnectVersion.properties"
+
+try {
+    def props = new Properties()
+    file(versionFile).withInputStream { stream -> props.load(stream) }
+    version = props['version']
+} catch (e) {
+    // this happens, if either the properties file is not present, or cannot be read from
+    throw new GradleException("File ${versionFile} not found or unreadable. Aborting.", e)
+}
+
+task printVersion() {
+    doLast {
+        println(version)
+    }
+}
+
+task newVersion() {
+    doFirst {
+        def newProps = new Properties()
+        newProps['version'] = value
+        newProps.store(file(versionFile).newWriter(), null)
+    }
+}
+
+task setDevVersionForCI() {
+    doFirst {
+        def props = new Properties()
+        props['version'] = version + "-$System.env.CI_PIPELINE_IID"
+        props.store(file(versionFile).newWriter(), null)
+    }
+}
 
-//708
 publishing {
     publications {
         maven(MavenPublication) {
             artifactId = 'ragconnect'
-            // Comment rs: components.java does not include relast.preprocessor
-            // from components.java
-            artifact("build/libs/ragconnect-${version}.jar") {
-                extension 'jar'
-            }
+            from components.java
         }
     }
     repositories {
         maven {
-            url "https://git-st.inf.tu-dresden.de/api/v4/projects/708/packages/maven"
-            // Uncomment the following lines to publish manually (and comment out the other credentials section)
-//            credentials(HttpHeaderCredentials) {
-//                name = "Private-Token"
-//                value = gitLabPrivateToken // the variable resides in ~/.gradle/gradle.properties
-//            }
+            url "https://git-st.inf.tu-dresden.de/api/v4/projects/$System.env.CI_PROJECT_ID/packages/maven"
             credentials(HttpHeaderCredentials) {
                 name = 'Job-Token'
                 value = System.getenv("CI_JOB_TOKEN")
@@ -239,5 +257,6 @@ publishing {
     }
 }
 
+// --- Task order ---
+generateAst.dependsOn relast
 publish.dependsOn jar
-jar.dependsOn ":relast-preprocessor:jar"
diff --git a/ragconnect.base/src/main/resources/ragConnectVersion.properties b/ragconnect.base/src/main/resources/ragconnectVersion.properties
similarity index 100%
rename from ragconnect.base/src/main/resources/ragConnectVersion.properties
rename to ragconnect.base/src/main/resources/ragconnectVersion.properties
diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle
index 821617bef166830e8c3710b81034a6e962073ee1..207c4b53ed5a5a8fde27ff57085d8ff565ff6467 100644
--- a/ragconnect.tests/build.gradle
+++ b/ragconnect.tests/build.gradle
@@ -1,7 +1,7 @@
+// --- Buildscripts (must be at the top) ---
 buildscript {
     repositories {
         mavenCentral()
-//        mavenLocal()
         maven {
             name "gitlab-maven"
             url "https://git-st.inf.tu-dresden.de/api/v4/groups/jastadd/-/packages/maven"
@@ -9,26 +9,26 @@ buildscript {
     }
     dependencies {
         classpath 'org.jastadd:jastaddgradle:1.13.3'
-        classpath 'org.jastadd.preprocessor:testing:0.2.12'
+        classpath 'org.jastadd.preprocessor:testing:0.2.13-27'
     }
 }
 
+// --- Plugin definitions ---
 import org.jastadd.preprocessor.testing.plugin.PreprocessorPlugin
 import org.jastadd.preprocessor.testing.plugin.RagConnectTest
 
 plugins {
+    id 'com.github.ben-manes.versions'
     id 'java'
-    id 'java-library'
     id 'idea'
-    id 'com.github.ben-manes.versions' version '0.36.0'
+    id 'org.jastadd'
+    id 'java-library'
     id 'com.google.protobuf' version "0.8.14"
 }
 
-apply plugin: 'jastadd'
 apply plugin: PreprocessorPlugin
 
-group = 'de.tudresden.inf.st'
-
+// --- Dependencies ---
 repositories {
     mavenCentral()
     maven {
@@ -36,15 +36,12 @@ repositories {
         url "https://git-st.inf.tu-dresden.de/api/v4/groups/jastadd/-/packages/maven"
     }
 }
-tasks.compileTestJava {
-    options.release.set(11)
-}
 
 dependencies {
     implementation project(':ragconnect.base')
 
-//    runtimeOnly group: 'org.jastadd', name: 'jastadd', version: '2.3.5-dresden'
-    runtimeOnly fileTree(include: ['jastadd2.jar'], dir: '../libs')
+    implementation group: 'org.jastadd', name: 'jastadd2', version: '2.3.5-dresden-5'
+    implementation group: 'org.jastadd', name: 'relast', version: "0.3.0-137"
 
     testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.4.0'
     testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.4.0'
@@ -69,19 +66,12 @@ dependencies {
     api group: 'com.google.protobuf', name: 'protobuf-java', version: '3.0.0'
 }
 
-java {
-    toolchain {
-        languageVersion.set(JavaLanguageVersion.of(11))
-    }
-}
-
-//task helper {
-//    doLast {
-//        println(defaultOnlyRead.inputs.files.files)
-//        println(defaultOnlyRead.outputs.files.files)
-//    }
-//}
+// --- Preprocessors ---
+File genSrc = file("src/test/java-gen")
+sourceSets.test.java.srcDir genSrc
+idea.module.generatedSourceDirs += genSrc
 
+// --- Tests ---
 test {
     useJUnitPlatform {
         excludeTags 'mqtt'
@@ -90,13 +80,6 @@ test {
     maxHeapSize = '1G'
 }
 
-protobuf {
-    protoc {
-        // The artifact spec for the Protobuf Compiler
-        artifact = 'com.google.protobuf:protoc:3.0.0'
-    }
-}
-
 task allTests(type: Test, dependsOn: testClasses) {
     description = 'Run every test'
     group = 'verification'
@@ -126,16 +109,6 @@ task newTests(type: Test, dependsOn: testClasses) {
     }
 }
 
-preprocessorTesting {
-    //noinspection GroovyAssignabilityCheck
-    relastCompilerLocation = '../libs/relast.jar'
-//    ragconnectCompilerLocation = '../libs/ragconnect.jar'
-}
-
-File genSrc = file("src/test/java-gen")
-sourceSets.test.java.srcDir genSrc
-idea.module.generatedSourceDirs += genSrc
-
 clean {
     delete fileTree(dir: 'src/test/02-after-ragconnect/', exclude: '.gitignore')
     delete fileTree(dir: 'src/test/03-after-relast/', exclude: '.gitignore')
@@ -151,8 +124,6 @@ def JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL = JASTADD_INCREMENTAL_OPTIONS.clone
 JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL.set(0, '--tracing=all')
 JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL.set(1, '--incremental=param,debug')
 
-classes.dependsOn(':ragconnect.base:jar')
-
 // --- Test: Example ---
 task compileExampleTest(type: RagConnectTest) {
     ragconnect {
@@ -172,6 +143,7 @@ task compileExampleTest(type: RagConnectTest) {
         inputFiles = [file('src/test/01-input/example/Test.jadd')]
     }
 }
+compileExampleTest.outputs.upToDateWhen { false }
 
 // --- Test: default-only-read ---
 task compileDefaultOnlyRead(type: RagConnectTest) {
@@ -355,7 +327,7 @@ task compileMapping(type: RagConnectTest) {
 }
 
 // --- Test: tree-manual ---
-task compileTreeManual(type: RagConnectTest, dependsOn: ':ragconnect.base:compileJava') {
+task compileTreeManual(type: RagConnectTest) {
     ragconnect {
         outputDir = file('src/test/02-after-ragconnect/tree')
         inputFiles = [file('src/test/01-input/tree/Test.relast'),
@@ -668,6 +640,7 @@ task compileRelationIncremental(type: RagConnectTest) {
                       file('src/test/01-input/relation/Test.connect')]
         rootNode = 'Root'
         logWrites = true
+        logIncremental = true
         extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329'])
     }
     relast {
@@ -682,11 +655,23 @@ task compileRelationIncremental(type: RagConnectTest) {
         extraOptions = JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL
     }
 }
+
+// --- Task order ---
+classes.dependsOn(':ragconnect.base:jar')
+//compileAttributeIncremental.outputs.upToDateWhen { false }
 compileRelationIncremental.outputs.upToDateWhen { false }
 
+// --- Misc ---
 static ArrayList<String> defaultRagConnectOptionsAnd(ArrayList<String> options = []) {
     if (!options.contains('--logTarget=slf4j')) {
         options.add('--logTarget=slf4j')
     }
     return options
 }
+
+protobuf {
+    protoc {
+        // The artifact spec for the Protobuf Compiler
+        artifact = 'com.google.protobuf:protoc:3.0.0'
+    }
+}