various tidy ups and reorganizations (for a task-model and from the android and js branches)
diff --git a/BUILD b/BUILD
index a0e589f..54f21e0 100644
--- a/BUILD
+++ b/BUILD
@@ -22,7 +22,7 @@
     ]
 )
 
-#  Local tests
+#  Local tests. Tests that shouldn't be run on the CI server.
 test_suite(
     name = "all_local_tests",
     tests = [
diff --git a/WORKSPACE b/WORKSPACE
index 369b328..e68b3c4 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -14,11 +14,11 @@
 workspace(name="io_bazel_rules_kotlin")
 load("//kotlin/internal:bootstrap.bzl",github_archive="github_archive")
 
-#github_archive(
-#    name = "com_google_protobuf",
-#    repo = "google/protobuf",
-#    commit = "106ffc04be1abf3ff3399f54ccf149815b287dd9",
-#)
+github_archive(
+    name = "com_google_protobuf",
+    repo = "google/protobuf",
+    commit = "106ffc04be1abf3ff3399f54ccf149815b287dd9",
+)
 
 github_archive(
     name = "build_bazel_rules_nodejs",
diff --git a/kotlin/builder/integrationtests/KotlinBuilderTestCase.java b/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
index f285a8b..71b69b5 100644
--- a/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
+++ b/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
@@ -3,7 +3,10 @@
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
 import io.bazel.kotlin.builder.toolchain.KotlinToolchain;
-import io.bazel.kotlin.model.KotlinModel;
+import io.bazel.kotlin.model.JvmCompilationTask;
+import io.bazel.kotlin.model.KotlinToolchainInfo;
+import io.bazel.kotlin.model.Platform;
+import io.bazel.kotlin.model.RuleKind;
 import org.junit.Before;
 
 import java.io.BufferedWriter;
@@ -23,8 +26,7 @@
       Paths.get(Preconditions.checkNotNull(System.getenv("TEST_TMPDIR")));
   private static final AtomicInteger counter = new AtomicInteger(0);
 
-  private final KotlinModel.CompilationTask.Builder builder =
-      KotlinModel.CompilationTask.newBuilder();
+  private final JvmCompilationTask.Builder builder = JvmCompilationTask.newBuilder();
   private final KotlinBuilderComponent component =
       DaggerKotlinBuilderComponent.builder()
           .out(System.err)
@@ -39,11 +41,11 @@
     resetTestContext("a_test_" + counter.incrementAndGet());
   }
 
-  protected KotlinModel.CompilationTask.Outputs outputs() {
+  protected JvmCompilationTask.Outputs outputs() {
     return builder.getOutputs();
   }
 
-  protected KotlinModel.CompilationTask.Directories directories() {
+  protected JvmCompilationTask.Directories directories() {
     return builder.getDirectories();
   }
 
@@ -55,7 +57,7 @@
     return Paths.get(directories().getClasses());
   }
 
-  protected KotlinModel.CompilationTask builderCommand() {
+  protected JvmCompilationTask builderCommand() {
     return builder.build();
   }
 
@@ -94,16 +96,16 @@
         .getInfoBuilder()
         .setLabel("//some/bogus:" + label)
         .setModuleName("some_bogus_module")
-        .setPlatform(KotlinModel.CompilationTask.Info.Platform.JVM)
-        .setRuleKind(KotlinModel.CompilationTask.Info.RuleKind.LIBRARY)
+        .setPlatform(Platform.JVM)
+        .setRuleKind(RuleKind.LIBRARY)
         .setToolchainInfo(
-            KotlinModel.KotlinToolchainInfo.newBuilder()
+            KotlinToolchainInfo.newBuilder()
                 .setCommon(
-                    KotlinModel.KotlinToolchainInfo.Common.newBuilder()
+                    KotlinToolchainInfo.Common.newBuilder()
                         .setApiVersion("1.2")
                         .setCoroutines("enabled")
                         .setLanguageVersion("1.2"))
-                .setJvm(KotlinModel.KotlinToolchainInfo.Jvm.newBuilder().setJvmTarget("1.8")));
+                .setJvm(KotlinToolchainInfo.Jvm.newBuilder().setJvmTarget("1.8")));
     builder
         .getDirectoriesBuilder()
         .setClasses(prefixPath.resolve("classes").toAbsolutePath().toString())
@@ -140,7 +142,7 @@
     TEMP,
     SOURCE_GEN;
 
-    protected static Path select(DirectoryType type, KotlinModel.CompilationTask command) {
+    protected static Path select(DirectoryType type, JvmCompilationTask command) {
       Path ret;
       switch (type) {
         case CLASSES:
diff --git a/kotlin/builder/integrationtests/KotlinBuilderTests.java b/kotlin/builder/integrationtests/KotlinBuilderTests.java
index 7c0dd1a..56534f7 100644
--- a/kotlin/builder/integrationtests/KotlinBuilderTests.java
+++ b/kotlin/builder/integrationtests/KotlinBuilderTests.java
@@ -2,7 +2,7 @@
 
 import com.google.common.truth.Truth;
 import com.google.devtools.build.lib.view.proto.Deps;
-import io.bazel.kotlin.model.KotlinModel;
+import io.bazel.kotlin.model.JvmCompilationTask;
 import org.junit.Test;
 
 import java.io.FileInputStream;
@@ -33,7 +33,7 @@
   }
 
   private void runCompileTask() {
-    KotlinModel.CompilationTask command = builderCommand();
+    JvmCompilationTask command = builderCommand();
     for (DirectoryType directoryType : DirectoryType.values()) {
       try {
         if (directoryType != DirectoryType.ROOT) {
@@ -46,7 +46,7 @@
     int timeoutSeconds = 10;
 //    KotlinJvmTaskExecutor executor = instance(KotlinJvmTaskExecutor.class);
     try {
-      CompletableFuture.runAsync(() -> component().jvmTaskExecutor().compile(command))
+      CompletableFuture.runAsync(() -> component().jvmTaskExecutor().execute(command))
           .get(timeoutSeconds, TimeUnit.SECONDS);
     } catch (TimeoutException e) {
       throw new AssertionError("did not complete in: " + timeoutSeconds);
diff --git a/kotlin/builder/proto/BUILD b/kotlin/builder/proto/BUILD
index d8d7109..4eec6f4 100644
--- a/kotlin/builder/proto/BUILD
+++ b/kotlin/builder/proto/BUILD
@@ -12,31 +12,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 package(default_visibility=["//visibility:public"])
-# commented out till 0.16 is released. We aren't  prebuilding the libraries at the moment so it's fine.
-# TODO constrain the visibility when fixing  the comments below as well
-#proto_library(
-#    name = "kotlin_model_proto",
-#    srcs = [":kotlin_model.proto"],
-#    visibility=["//visibility:public"]
-#)
-#
-#java_proto_library(
-#    name = "kotlin_model_java_proto",
-#    deps = [":kotlin_model_proto"]
-#)
-#
-#_PROTO_LIBS=["deps", "worker_protocol"]
-#
-#[proto_library(
-#    name="%s_proto" % lib,
-#    srcs=["%s.proto" % lib]
-#    ) for lib in _PROTO_LIBS]
-#
-#[java_proto_library(
-#    name="%s_java_proto" % lib,
-#    deps=["%s_proto" % lib],
-#    ) for lib in _PROTO_LIBS]
-#
+
+proto_library(
+    name = "kotlin_model_proto",
+    srcs = [":kotlin_model.proto"],
+    visibility=["//visibility:public"]
+)
+
+java_proto_library(
+    name = "kotlin_model_java_proto",
+    deps = [":kotlin_model_proto"]
+)
+
+_PROTO_LIBS=["deps", "worker_protocol"]
+
+[proto_library(
+    name="%s_proto" % lib,
+    srcs=["%s.proto" % lib]
+    ) for lib in _PROTO_LIBS]
+
+[java_proto_library(
+    name="%s_java_proto" % lib,
+    deps=["%s_proto" % lib],
+    ) for lib in _PROTO_LIBS]
+
 
 java_import(
     name = "deps",
diff --git a/kotlin/builder/proto/gen_jars.sh b/kotlin/builder/proto/gen_jars.sh
deleted file mode 100755
index b6241ce..0000000
--- a/kotlin/builder/proto/gen_jars.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-WS_ROOT=$(bazel info workspace)
-PATH_PROTO=kotlin/builder/proto
-function build_lib() {
-bazel build //${PATH_PROTO}:$1_java_proto
-local FILE=lib$1_proto-speed.jar
-cp ${WS_ROOT}/bazel-bin/${PATH_PROTO}/${FILE} ${WS_ROOT}/${PATH_PROTO}/jars/${FILE}
-}
-
-build_lib "deps"
-build_lib "worker_protocol"
-build_lib "kotlin_model"
-
-chmod -R 0754 jars
-
diff --git a/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar b/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar
index 63d0189..2e614f0 100755
--- a/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar
+++ b/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar
Binary files differ
diff --git a/kotlin/builder/proto/kotlin_model.proto b/kotlin/builder/proto/kotlin_model.proto
index ddea9f7..2af674f 100644
--- a/kotlin/builder/proto/kotlin_model.proto
+++ b/kotlin/builder/proto/kotlin_model.proto
@@ -16,6 +16,7 @@
 package bazel.kotlin;
 
 option java_package = "io.bazel.kotlin.model";
+option java_multiple_files = true;
 
 // An abstract definition of an annotation processor. This is encoded into a format understood by kapt3.
 // +stable
@@ -64,40 +65,40 @@
     Jvm jvm = 2;
 }
 
+enum RuleKind {
+    LIBRARY = 0;
+    BINARY = 1;
+    TEST = 2;
+    IMPORT = 3;
+}
+
+enum Platform {
+    JVM = 0;
+    JS = 1;
+}
+
+// Common info about a Kotlin compilation task, this message is shared by all compilation tasks.
+message CompilationTaskInfo {
+    string label = 1;
+    // The Platform type.
+    Platform platform = 2;
+    // The kind of the rule.
+    RuleKind rule_kind = 3;
+    // The name of the module being compiled.
+    string module_name = 4;
+    // Flags to be passed straight through to the compiler.
+    string passthrough_flags = 5;
+    // Toolchain info for this build.
+    KotlinToolchainInfo toolchain_info = 6;
+    // Compiler plugin descriptors.
+    CompilerPlugins plugins = 7;
+    // Paths to Jars that the kotlin compiler will allow package private access to.
+    repeated string friend_paths = 8;
+}
+
 // Mested messages not marked with stable could be refactored.
-message CompilationTask {
-    message Info {
-        enum RuleKind {
-            LIBRARY = 0;
-            BINARY = 1;
-            TEST = 2;
-            IMPORT = 3;
-        }
-
-        enum Platform {
-            JVM = 0;
-            JS = 1;
-        }
-
-        string label = 1;
-        // The Platform type.
-        Platform platform = 2;
-        // The kind of the rule.
-        RuleKind rule_kind = 3;
-        // The name of the module being compiled.
-        string module_name = 4;
-        // Flags to be passed straight through to the compiler.
-        string passthrough_flags = 5;
-        // Toolchain info for this build.
-        KotlinToolchainInfo toolchain_info = 6;
-        // Compiler plugin descriptors.
-        CompilerPlugins plugins = 7;
-        // Paths to Jars that the kotlin compiler will allow package private access to.
-        repeated string friend_paths = 8;
-    }
-
+message JvmCompilationTask {
     // Directories used by the builder.
-    // +stable
     message Directories {
         // The directory the compiler should use for class files.
         string classes = 1;
@@ -110,7 +111,6 @@
     }
 
     // Outputs produced by the builder.
-    // +stable
     message Outputs {
         // The path to the primary output jar.
         string jar = 1;
@@ -122,22 +122,22 @@
     message Inputs {
         // The full classpath
         repeated string classpath = 1;
-
         // Direct dependencies of the target.
         map<string, string> direct_dependencies = 2;
         // Indirect dependencies of the target.
         map<string, string> indirect_dependencies = 3;
-
-        // Partitioned from the builder flags, expanding the source_jars.
+        // Partitioned from the builder flags and could have been augmented with sources discovered by expanding the
+        // source_jars and from annotation processing.
         repeated string kotlin_sources = 4;
-        // Partitioned from the builder flags and by expanding the source_jars.
+        // Partitioned from the builder flags and could have been augmented with sources discovered by expanding the
+        // source_jars and from annotation processing.
         repeated string java_sources = 5;
         // Jars containing additional sources.
         repeated string source_jars = 6;
     }
 
-    Info info = 1;
+    CompilationTaskInfo info = 1;
     Directories directories = 2;
     Outputs outputs = 3;
     Inputs inputs = 4;
-}
\ No newline at end of file
+}
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt
index f90042a..901bfb5 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt
@@ -22,7 +22,7 @@
 import io.bazel.kotlin.builder.utils.ensureDirectories
 import io.bazel.kotlin.builder.utils.expandWithSources
 import io.bazel.kotlin.builder.utils.jars.SourceJarExtractor
-import io.bazel.kotlin.model.KotlinModel
+import io.bazel.kotlin.model.JvmCompilationTask
 import java.nio.charset.StandardCharsets.UTF_8
 import java.nio.file.Files
 import java.nio.file.Paths
@@ -50,16 +50,18 @@
             STANDARD_FLAGFILE_RE.matches(flagFile) -> {
                 Files.readAllLines(flagFilePath, UTF_8).let { loadedFlags ->
                     ArgMaps.from(loadedFlags).let {
-                        taskBuilder.fromInput(it)
+                        val taskInfo = taskBuilder.buildTaskInfo(it)
+                        taskBuilder.buildJvm(taskInfo, it)
                     }
                 }
             }
             else -> throw IllegalStateException("unknown flag file format for $flagFile")
         }
+
         return execute(task)
     }
 
-    fun execute(command: KotlinModel.CompilationTask): Int {
+    fun execute(command: JvmCompilationTask): Int {
         ensureDirectories(
             command.directories.classes,
             command.directories.temp,
@@ -68,7 +70,7 @@
         )
         val updatedCommand = expandWithSourceJarSources(command)
         return try {
-            jvmTaskExecutor.compile(updatedCommand)
+            jvmTaskExecutor.execute(updatedCommand)
             0
         } catch (ex: CompilationStatusException) {
             ex.status
@@ -76,10 +78,10 @@
     }
 
     /**
-     * If any sourcejars were provided expand the jars sources and create a new [KotlinModel.CompilationTask] with the
+     * If any srcjars were provided expand the jars sources and create a new [JvmCompilationTask] with the
      * Java and Kotlin sources merged in.
      */
-    private fun expandWithSourceJarSources(command: KotlinModel.CompilationTask): KotlinModel.CompilationTask =
+    private fun expandWithSourceJarSources(command: JvmCompilationTask): JvmCompilationTask =
         if (command.inputs.sourceJarsList.isEmpty()) {
             command
         } else {
@@ -87,7 +89,7 @@
                 destDir = Paths.get(command.directories.temp).resolve("_srcjars"),
                 fileMatcher = IS_JVM_SOURCE_FILE
             ).also {
-                it.jarFiles.addAll(command.inputs.sourceJarsList.map { Paths.get(it) })
+                it.jarFiles.addAll(command.inputs.sourceJarsList.map { p -> Paths.get(p) })
                 it.execute()
             }.let {
                 command.expandWithSources(it.sourcesList.iterator())
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/TaskBuilder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/TaskBuilder.kt
index 1bc43ba..63e984c 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/TaskBuilder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/TaskBuilder.kt
@@ -16,10 +16,11 @@
 package io.bazel.kotlin.builder.tasks
 
 import com.google.protobuf.util.JsonFormat
-import io.bazel.kotlin.builder.utils.ArgMap
-import io.bazel.kotlin.builder.utils.partitionSources
-import io.bazel.kotlin.model.KotlinModel
-import io.bazel.kotlin.model.KotlinModel.CompilationTask
+import io.bazel.kotlin.builder.tasks.TaskBuilder.JavaBuilderFlags.*
+import io.bazel.kotlin.builder.tasks.TaskBuilder.KotlinBuilderFlags.*
+import io.bazel.kotlin.builder.utils.*
+import io.bazel.kotlin.model.*
+import io.bazel.kotlin.model.KotlinModel.getDescriptor
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -28,8 +29,7 @@
     companion object {
         @JvmStatic
         private val jsonTypeRegistry = JsonFormat.TypeRegistry.newBuilder()
-            .add(KotlinModel.getDescriptor().messageTypes).build()
-
+            .add(getDescriptor().messageTypes).build()
 
         @JvmStatic
         private val jsonFormat: JsonFormat.Parser = JsonFormat.parser().usingTypeRegistry(jsonTypeRegistry)
@@ -38,7 +38,7 @@
     /**
      * Declares the flags used by the java builder.
      */
-    private enum class JavaBuilderFlags(val flag: String) {
+    private enum class JavaBuilderFlags(override val flag: String) : Flag {
         TARGET_LABEL("--target_label"),
         CLASSPATH("--classpath"),
         JAVAC_OPTS("--javacopts"),
@@ -70,65 +70,88 @@
         POST_PROCESSOR("--post_processor"),
         COMPRESS_JAR("--compress_jar"),
         RULE_KIND("--rule_kind"),
-        TEST_ONLY("--testonly")
+        TEST_ONLY("--testonly");
     }
 
-    fun fromInput(argMap: ArgMap): CompilationTask =
-        CompilationTask.newBuilder().let { root ->
+    enum class KotlinBuilderFlags(override val flag: String) : Flag {
+        MODULE_NAME("--kotlin_module_name"),
+        PASSTHROUGH_FLAGS("--kotlin_passthrough_flags"),
+        API_VERSION("--kotlin_api_version"),
+        LANGUAGE_VERSION("--kotlin_language_version"),
+        JVM_TARGET("--kotlin_jvm_target"),
+        OUTPUT_SRCJAR("--kotlin_output_srcjar"),
+        GENERATED_CLASSDIR("--kotlin_generated_classdir"),
+        PLUGINS("--kotlin_plugins"),
+        FRIEND_PATHS("--kotlin_friend_paths"),
+        OUTPUT_JDEPS("--kotlin_output_jdeps"),
+        TASK_ID("--kotlin_task_id");
+    }
+
+    fun buildTaskInfo(argMap: ArgMap): CompilationTaskInfo =
+        with(CompilationTaskInfo.newBuilder()) {
+            label = argMap.mandatorySingle(TARGET_LABEL)
+            argMap.mandatorySingle(RULE_KIND).split("_").also {
+                check(it.size == 3 && it[0] == "kt") { "invalid rule kind $it" }
+                platform = checkNotNull(Platform.valueOf(it[1].toUpperCase())) {
+                    "unrecognized platform ${it[1]}"
+                }
+                ruleKind = checkNotNull(RuleKind.valueOf(it[2].toUpperCase())) {
+                    "unrecognized rule kind ${it[2]}"
+                }
+            }
+            moduleName = argMap.mandatorySingle(MODULE_NAME).also {
+                check(it.isNotBlank()) { "--kotlin_module_name should not be blank" }
+            }
+            passthroughFlags = argMap.optionalSingle(PASSTHROUGH_FLAGS)
+            argMap.optional(FRIEND_PATHS)?.let(::addAllFriendPaths)
+            toolchainInfoBuilder.commonBuilder.apiVersion = argMap.mandatorySingle(API_VERSION)
+            toolchainInfoBuilder.commonBuilder.languageVersion = argMap.mandatorySingle(LANGUAGE_VERSION)
+            build()
+        }
+
+
+    fun buildJvm(info: CompilationTaskInfo, argMap: ArgMap): JvmCompilationTask =
+        JvmCompilationTask.newBuilder().let { root ->
+            root.info = info
+
             with(root.outputsBuilder) {
-                jar = argMap.mandatorySingle(JavaBuilderFlags.OUTPUT.flag)
-                jdeps = argMap.mandatorySingle("--output_jdeps")
-                srcjar = argMap.mandatorySingle("--kotlin_output_srcjar")
+                jar = argMap.mandatorySingle(OUTPUT)
+                jdeps = argMap.mandatorySingle(OUTPUT_JDEPS)
+                srcjar = argMap.mandatorySingle(OUTPUT_SRCJAR)
             }
 
             with(root.directoriesBuilder) {
-                classes = argMap.mandatorySingle(JavaBuilderFlags.CLASSDIR.flag)
-                generatedClasses = argMap.mandatorySingle("--kotlin_generated_classdir")
-                temp = argMap.mandatorySingle(JavaBuilderFlags.TEMPDIR.flag)
-                generatedSources = argMap.mandatorySingle(JavaBuilderFlags.SOURCEGEN_DIR.flag)
+                classes = argMap.mandatorySingle(CLASSDIR)
+                generatedClasses = argMap.mandatorySingle(GENERATED_CLASSDIR)
+                temp = argMap.mandatorySingle(TEMPDIR)
+                generatedSources = argMap.mandatorySingle(SOURCEGEN_DIR)
             }
 
             with(root.inputsBuilder) {
-                addAllClasspath(argMap.mandatory(JavaBuilderFlags.CLASSPATH.flag))
-                putAllIndirectDependencies(argMap.labelDepMap(JavaBuilderFlags.DIRECT_DEPENDENCY.flag))
-                putAllIndirectDependencies(argMap.labelDepMap(JavaBuilderFlags.INDIRECT_DEPENDENCY.flag))
+                addAllClasspath(argMap.mandatory(CLASSPATH))
+                putAllIndirectDependencies(argMap.labelDepMap(DIRECT_DEPENDENCY))
+                putAllIndirectDependencies(argMap.labelDepMap(INDIRECT_DEPENDENCY))
 
-                argMap.optional(JavaBuilderFlags.SOURCES.flag)?.iterator()?.partitionSources(
+                argMap.optional(SOURCES)?.iterator()?.partitionSources(
                     { addKotlinSources(it) },
                     { addJavaSources(it) }
                 )
-                argMap.optional(JavaBuilderFlags.SOURCE_JARS.flag)?.also {
+                argMap.optional(SOURCE_JARS)?.also {
                     addAllSourceJars(it)
                 }
             }
 
             with(root.infoBuilder) {
-                label = argMap.mandatorySingle(JavaBuilderFlags.TARGET_LABEL.flag)
-                argMap.mandatorySingle(JavaBuilderFlags.RULE_KIND.flag).split("_").also {
-                    check(it.size == 3 && it[0] == "kt")
-                    platform = checkNotNull(CompilationTask.Info.Platform.valueOf(it[1].toUpperCase())) {
-                        "unrecognized platform ${it[1]}"
-                    }
-                    ruleKind = checkNotNull(CompilationTask.Info.RuleKind.valueOf(it[2].toUpperCase())) {
-                        "unrecognized rule kind ${it[2]}"
-                    }
-                }
-                moduleName = argMap.mandatorySingle("--kotlin_module_name").also {
-                    check(it.isNotBlank()) { "--kotlin_module_name should not be blank" }
-                }
-                passthroughFlags = argMap.optionalSingle("--kotlin_passthrough_flags")
-                addAllFriendPaths(argMap.mandatory("--kotlin_friend_paths"))
-                toolchainInfoBuilder.commonBuilder.apiVersion = argMap.mandatorySingle("--kotlin_api_version")
-                toolchainInfoBuilder.commonBuilder.languageVersion = argMap.mandatorySingle("--kotlin_language_version")
-                toolchainInfoBuilder.jvmBuilder.jvmTarget = argMap.mandatorySingle("--kotlin_jvm_target")
+                toolchainInfoBuilder.jvmBuilder.jvmTarget = argMap.mandatorySingle(JVM_TARGET)
 
-                argMap.optionalSingle("--kt-plugins")?.let { input ->
-                    plugins = KotlinModel.CompilerPlugins.newBuilder().let {
+                argMap.optionalSingle(PLUGINS)?.let { input ->
+                    plugins = CompilerPlugins.newBuilder().let {
                         jsonFormat.merge(input, it)
                         it.build()
                     }
                 }
             }
+
             root.build()
         }
 }
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/JDepsGenerator.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/JDepsGenerator.kt
index a6197a7..83cc7e8 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/JDepsGenerator.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/JDepsGenerator.kt
@@ -19,10 +19,10 @@
 import io.bazel.kotlin.builder.toolchain.CompilationException
 import io.bazel.kotlin.builder.toolchain.CompilationStatusException
 import io.bazel.kotlin.builder.toolchain.KotlinToolchain
-import io.bazel.kotlin.model.KotlinModel
 import io.bazel.kotlin.builder.utils.joinedClasspath
 import io.bazel.kotlin.builder.utils.resolveVerified
 import io.bazel.kotlin.builder.utils.rootCause
+import io.bazel.kotlin.model.JvmCompilationTask
 import java.io.ByteArrayOutputStream
 import java.io.FileOutputStream
 import java.io.PrintWriter
@@ -32,13 +32,15 @@
 import javax.inject.Singleton
 
 @Singleton
-internal class JDepsGenerator  @Inject constructor(
+internal class JDepsGenerator @Inject constructor(
     toolchain: KotlinToolchain,
     private val invoker: KotlinToolchain.JDepsInvoker
 ) {
     private val isKotlinImplicit = JdepsParser.pathSuffixMatchingPredicate(
-        toolchain.kotlinHome.resolveVerified("lib").toPath(), *toolchain.kotlinStandardLibraries.toTypedArray())
-    fun generateJDeps(command: KotlinModel.CompilationTask) {
+        toolchain.kotlinHome.resolveVerified("lib").toPath(), *toolchain.kotlinStandardLibraries.toTypedArray()
+    )
+
+    fun generateJDeps(command: JvmCompilationTask) {
         val jdepsContent =
             if (command.inputs.classpathList.isEmpty()) {
                 Deps.Dependencies.newBuilder().let {
@@ -52,8 +54,10 @@
                         val res = invoker.run(
                             arrayOf(
                                 "-cp", joinedClasspath,
-                                command.outputs.jdeps),
-                            writer)
+                                command.outputs.jdeps
+                            ),
+                            writer
+                        )
                         out.toByteArray().inputStream().bufferedReader().readLines().let {
                             if (res != 0) {
                                 throw CompilationStatusException("could not run jdeps tool", res, it)
@@ -75,9 +79,7 @@
             }
         Paths.get(command.outputs.jdeps).also {
             Files.deleteIfExists(it)
-            FileOutputStream(Files.createFile(it).toFile()).use {
-                jdepsContent.writeTo(it)
-            }
+            FileOutputStream(Files.createFile(it).toFile()).use(jdepsContent::writeTo)
         }
     }
 }
\ No newline at end of file
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/JavaCompiler.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/JavaCompiler.kt
index d260143..b52a222 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/JavaCompiler.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/JavaCompiler.kt
@@ -17,9 +17,9 @@
 
 import io.bazel.kotlin.builder.toolchain.CompilationStatusException
 import io.bazel.kotlin.builder.toolchain.KotlinToolchain
-import io.bazel.kotlin.model.KotlinModel.CompilationTask
 import io.bazel.kotlin.builder.utils.addAll
 import io.bazel.kotlin.builder.utils.joinedClasspath
+import io.bazel.kotlin.model.JvmCompilationTask
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -27,7 +27,7 @@
 internal class JavaCompiler @Inject constructor(
     private val javacInvoker: KotlinToolchain.JavacInvoker
 ) {
-   fun compile(command: CompilationTask) {
+    fun compile(command: JvmCompilationTask) {
         val i = command.inputs
         val d = command.directories
         if (i.javaSourcesList.isNotEmpty()) {
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt
index d5cf108..a004df3 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt
@@ -16,11 +16,11 @@
 package io.bazel.kotlin.builder.tasks.jvm
 
 import io.bazel.kotlin.builder.toolchain.CompilationStatusException
-import io.bazel.kotlin.builder.utils.KotlinCompilerPluginArgsEncoder
 import io.bazel.kotlin.builder.toolchain.KotlinToolchain
+import io.bazel.kotlin.builder.utils.KotlinCompilerPluginArgsEncoder
 import io.bazel.kotlin.builder.utils.addAll
 import io.bazel.kotlin.builder.utils.joinedClasspath
-import io.bazel.kotlin.model.KotlinModel
+import io.bazel.kotlin.model.JvmCompilationTask
 import java.io.ByteArrayInputStream
 import java.io.ByteArrayOutputStream
 import java.io.File
@@ -40,7 +40,7 @@
     private val compiler: KotlinToolchain.KotlincInvoker,
     private val pluginArgsEncoder: KotlinCompilerPluginArgsEncoder
 ) {
-    fun runAnnotationProcessor(command: KotlinModel.CompilationTask): List<String> {
+    fun runAnnotationProcessor(command: JvmCompilationTask): List<String> {
         check(command.info.plugins.annotationProcessorsList.isNotEmpty()) {
             "method called without annotation processors"
         }
@@ -48,13 +48,13 @@
             it.addAll(pluginArgsEncoder.encode(command))
             it.addAll(command.inputs.kotlinSourcesList)
             it.addAll(command.inputs.javaSourcesList)
-        }.let { invokeCompilePhase(it) }
+        }.let(::invokeCompilePhase)
     }
 
     /**
      * Return a list with the common arguments.
      */
-    private fun getCommonArgs(command: KotlinModel.CompilationTask): MutableList<String> {
+    private fun getCommonArgs(command: JvmCompilationTask): MutableList<String> {
         val args = mutableListOf<String>()
 
         // use -- for flags not meant for the kotlin compiler
@@ -75,7 +75,7 @@
         return args
     }
 
-    fun compile(command: KotlinModel.CompilationTask): List<String> =
+    fun compile(command: JvmCompilationTask): List<String> =
         with(getCommonArgs(command)) {
             addAll(command.inputs.javaSourcesList)
             addAll(command.inputs.kotlinSourcesList)
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt
index 4b249cb..738fd88 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt
@@ -17,9 +17,10 @@
 
 
 import io.bazel.kotlin.builder.toolchain.CompilationStatusException
+import io.bazel.kotlin.builder.toolchain.CompilationTaskExecutor
 import io.bazel.kotlin.builder.utils.expandWithSources
 import io.bazel.kotlin.builder.utils.jars.SourceJarCreator
-import io.bazel.kotlin.model.KotlinModel.CompilationTask
+import io.bazel.kotlin.model.JvmCompilationTask
 import java.io.File
 import java.nio.file.Files
 import java.nio.file.Paths
@@ -33,16 +34,13 @@
     private val javaCompiler: JavaCompiler,
     private val jDepsGenerator: JDepsGenerator,
     private val outputJarCreator: OutputJarCreator
-) {
-    @Suppress("unused")
-    class Result(val timings: List<String>, val command: CompilationTask)
-
-    fun compile(command: CompilationTask): Result {
+) : CompilationTaskExecutor<JvmCompilationTask>() {
+    override fun execute(task: JvmCompilationTask): Result {
         // fix error handling
         try {
             val context = Context()
             val commandWithApSources = context.execute("kapt") {
-                runAnnotationProcessors(command)
+                runAnnotationProcessors(task)
             }
             compileClasses(context, commandWithApSources)
             context.execute("create jar") {
@@ -59,13 +57,14 @@
         }
     }
 
-    private fun produceSourceJar(command: CompilationTask) {
+
+    private fun produceSourceJar(command: JvmCompilationTask) {
         Paths.get(command.outputs.srcjar).also { sourceJarPath ->
             Files.createFile(sourceJarPath)
             SourceJarCreator(
                 sourceJarPath
             ).also { creator ->
-                // This check asserts that source jars were unpacked.
+                // This check asserts that source jars were unpacked if present.
                 check(
                     command.inputs.sourceJarsList.isEmpty() ||
                             Files.exists(Paths.get(command.directories.temp).resolve("_srcjars"))
@@ -75,14 +74,14 @@
                     command.inputs.javaSourcesList.stream(),
                     command.inputs.kotlinSourcesList.stream()
                 ).stream()
-                    .flatMap { it.map { Paths.get(it) } }
+                    .flatMap { it.map { p -> Paths.get(p) } }
                     .also { creator.addSources(it) }
                 creator.execute()
             }
         }
     }
 
-    private fun runAnnotationProcessors(command: CompilationTask): CompilationTask =
+    private fun runAnnotationProcessors(command: JvmCompilationTask): JvmCompilationTask =
         try {
             if (command.info.plugins.annotationProcessorsList.isNotEmpty()) {
                 kotlinCompiler.runAnnotationProcessor(command)
@@ -99,7 +98,7 @@
             throw ex
         }
 
-    private fun compileClasses(context: Context, command: CompilationTask) {
+    private fun compileClasses(context: Context, command: JvmCompilationTask) {
         var kotlinError: CompilationStatusException? = null
         var result: List<String>? = null
         context.execute("kotlinc") {
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/OutputJarCreator.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/OutputJarCreator.kt
index ff6c075..0233dc5 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/OutputJarCreator.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/OutputJarCreator.kt
@@ -15,16 +15,16 @@
  */
 package io.bazel.kotlin.builder.tasks.jvm
 
-import io.bazel.kotlin.model.KotlinModel
 import io.bazel.kotlin.builder.utils.bazelRuleKind
 import io.bazel.kotlin.builder.utils.jars.JarCreator
+import io.bazel.kotlin.model.JvmCompilationTask
 import java.nio.file.Paths
 import javax.inject.Inject
 import javax.inject.Singleton
 
 @Singleton
 internal class OutputJarCreator @Inject constructor() {
-    fun createOutputJar(command: KotlinModel.CompilationTask) {
+    fun createOutputJar(command: JvmCompilationTask) {
         JarCreator(
             path = Paths.get(command.outputs.jar),
             normalize = true,
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/CompilationTaskExecutor.kt b/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/CompilationTaskExecutor.kt
new file mode 100644
index 0000000..bda3300
--- /dev/null
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/CompilationTaskExecutor.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2018 The Bazel Authors. All rights reserved.
+ *
+ * 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 io.bazel.kotlin.builder.toolchain
+
+import com.google.protobuf.MessageOrBuilder
+
+/**
+ * Base Compilation Task Executor class
+ */
+abstract class CompilationTaskExecutor<T: MessageOrBuilder> {
+    @Suppress("unused")
+    inner class Result(val timings: List<String>, val command: T)
+
+    abstract fun execute(task: T): Result
+}
\ No newline at end of file
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt b/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt
index d087b5c..1f39682 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/KotlinToolchain.kt
@@ -21,13 +21,13 @@
 import java.io.File
 import java.io.PrintStream
 import java.io.PrintWriter
+import java.lang.reflect.Method
 import java.nio.file.Path
 import java.nio.file.Paths
 import javax.inject.Inject
 import javax.inject.Singleton
 
 class KotlinToolchain private constructor(
-    internal val javaHome: Path,
     val kotlinHome: Path,
     val classLoader: ClassLoader,
     val kotlinStandardLibraries: List<String> = listOf(
@@ -66,27 +66,11 @@
         @JvmStatic
         fun createToolchain(): KotlinToolchain {
             val kotlinHome = Paths.get("external", "com_github_jetbrains_kotlin")
-            val javaHome = Paths.get(System.getProperty("java.home")).let {
-                it.takeIf { !it.endsWith(Paths.get("jre")) } ?: it.parent
+            val javaHome = Paths.get(System.getProperty("java.home")).let { path ->
+                path.takeIf { !it.endsWith(Paths.get("jre")) } ?: path.parent
             }
-            return KotlinToolchain(
-                javaHome,
-                kotlinHome,
-                createClassLoader(javaHome, kotlinHome)
-            )
+            return KotlinToolchain(kotlinHome, createClassLoader(javaHome, kotlinHome))
         }
-
-//        @JvmStatic
-//        fun createToolchainModule(outputProvider: Provider<PrintStream>): Module {
-//            val toolchain = createToolchain()
-//            return object : AbstractModule() {
-//                override fun configure() {
-//                    bind(PrintStream::class.java).toProvider(outputProvider)
-//                    bind(KotlinToolchain::class.java).toInstance(toolchain)
-//                    install(KotlinToolchainModule)
-//                }
-//            }
-//        }
     }
 
     data class CompilerPlugin(val jarPath: String, val id: String)
@@ -107,20 +91,33 @@
         fun run(args: Array<String>, out: PrintWriter): Int = method.invoke(clazz, args, out) as Int
     }
 
-    @Singleton
-    class KotlincInvoker @Inject constructor(toolchain: KotlinToolchain) {
-        private val compilerClass = toolchain.classLoader.loadClass("io.bazel.kotlin.compiler.BazelK2JVMCompiler")
-        private val exitCodeClass = toolchain.classLoader.loadClass("org.jetbrains.kotlin.cli.common.ExitCode")
+    open class KotlinCliToolInvoker internal constructor(
+        toolchain: KotlinToolchain,
+        clazz: String
+    ) {
+        private val compiler: Any
+        private val execMethod: Method
+        private val getCodeMethod: Method
 
-        private val compiler = compilerClass.getConstructor().newInstance()
-        private val execMethod = compilerClass.getMethod("exec", PrintStream::class.java, Array<String>::class.java)
-        private val getCodeMethod = exitCodeClass.getMethod("getCode")
+        init {
+            val compilerClass = toolchain.classLoader.loadClass(clazz)
+            val exitCodeClass = toolchain.classLoader.loadClass("org.jetbrains.kotlin.cli.common.ExitCode")
+
+            compiler = compilerClass.getConstructor().newInstance()
+            execMethod = compilerClass.getMethod("exec", PrintStream::class.java, Array<String>::class.java)
+            getCodeMethod = exitCodeClass.getMethod("getCode")
+        }
 
         fun compile(args: Array<String>, out: PrintStream): Int {
             val exitCodeInstance = execMethod.invoke(compiler, out, args)
             return getCodeMethod.invoke(exitCodeInstance, *NO_ARGS) as Int
         }
     }
+
+    @Singleton
+    class KotlincInvoker @Inject constructor(
+        toolchain: KotlinToolchain
+    ) : KotlinCliToolInvoker(toolchain, "io.bazel.kotlin.compiler.BazelK2JVMCompiler")
 }
 
 
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/ArgMap.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/ArgMap.kt
index 0256e2d..01988d5 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/ArgMap.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/ArgMap.kt
@@ -40,12 +40,22 @@
     fun optional(key: String): List<String>? = map[key]
 }
 
+interface Flag {
+    val flag: String
+}
+
+fun ArgMap.mandatorySingle(key: Flag) = mandatorySingle(key.flag)
+fun ArgMap.optionalSingle(key: Flag) = optionalSingle(key.flag)
+fun ArgMap.mandatory(key: Flag) = mandatory(key.flag)
+fun ArgMap.optional(key: Flag) = optional(key.flag)
+fun ArgMap.labelDepMap(key: Flag) = labelDepMap(key.flag)
+
 object ArgMaps {
     @JvmStatic
     fun from(args: List<String>): ArgMap =
         mutableMapOf<String, MutableList<String>>()
             .also { argsToMap(args, it) }
-            .let { ArgMap(it) }
+            .let(::ArgMap)
 
     @JvmStatic
     fun from(file: File): ArgMap = from(file.reader().readLines())
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
index 77f2227..3f3f98c 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
@@ -16,7 +16,7 @@
 package io.bazel.kotlin.builder.utils
 
 
-import io.bazel.kotlin.model.KotlinModel
+import io.bazel.kotlin.model.JvmCompilationTask
 import java.io.ByteArrayOutputStream
 import java.io.ObjectOutputStream
 import java.util.*
@@ -86,7 +86,7 @@
     }
 
     fun encode(
-        command: KotlinModel.CompilationTaskOrBuilder
+        command: JvmCompilationTask
     ): List<String> {
         val javacArgs = mutableMapOf<String, String>(
             "-target" to command.info.toolchainInfo.jvm.jvmTarget
@@ -105,7 +105,7 @@
 
                 arg["processors"] = plugin.annotationProcessorsList
                     .filter { it.processorClass.isNotEmpty() }
-                    .onEach { it.classpathList.forEach { arg.bindMulti("apclasspath", it) } }
+                    .onEach { processor -> processor.classpathList.forEach { arg.bindMulti("apclasspath", it) } }
                     .joinToString(",") { it.processorClass }
                 arg.encode()
             }
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/TaskUtils.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/TaskUtils.kt
index 7003979..67c607a 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/TaskUtils.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/TaskUtils.kt
@@ -15,25 +15,26 @@
  */
 package io.bazel.kotlin.builder.utils
 
-import io.bazel.kotlin.model.KotlinModel.CompilationTask
+import io.bazel.kotlin.model.CompilationTaskInfo
+import io.bazel.kotlin.model.JvmCompilationTask
 import java.io.File
 
-fun CompilationTask.expandWithSources(
+fun JvmCompilationTask.expandWithSources(
     sources: Iterator<String>
-): CompilationTask =
+): JvmCompilationTask =
     updateBuilder { builder ->
         sources.partitionSources(
             { builder.inputsBuilder.addKotlinSources(it) },
             { builder.inputsBuilder.addJavaSources(it) })
     }
 
-val CompilationTask.Inputs.joinedClasspath: String get() = this.classpathList.joinToString(File.pathSeparator)
+val JvmCompilationTask.Inputs.joinedClasspath: String get() = this.classpathList.joinToString(File.pathSeparator)
 
-val CompilationTask.Info.bazelRuleKind: String get() = "kt_${platform.name.toLowerCase()}_${ruleKind.name.toLowerCase()}"
+val CompilationTaskInfo.bazelRuleKind: String get() = "kt_${platform.name.toLowerCase()}_${ruleKind.name.toLowerCase()}"
 
-private fun CompilationTask.updateBuilder(
-    init: (CompilationTask.Builder) -> Unit
-): CompilationTask =
+private fun JvmCompilationTask.updateBuilder(
+    init: (JvmCompilationTask.Builder) -> Unit
+): JvmCompilationTask =
     toBuilder().let {
         init(it)
         it.build()
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/jars/SourceJarCreator.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/jars/SourceJarCreator.kt
index b30431b..9d76d31 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/jars/SourceJarCreator.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/jars/SourceJarCreator.kt
@@ -62,7 +62,7 @@
          */
         private val directoryToPackageMap = mutableMapOf<Path, String>()
         /**
-         * Entries for which packages could not be located.
+         * Entries for which packages paths could not be located during processing.
          */
         private val deferredEntries = mutableMapOf<Path, ByteArray>()
 
@@ -74,15 +74,10 @@
          * Files like `package-info.java` could end up getting deferred if they have an annotation embedded on the same
          * line or files that have entries such as `/* weird comment */package lala`
          */
-        fun getFilename(sourceFile: Path, bytes: ByteArray): String? {
-            return directoryToPackageMap[sourceFile.parent].let { existingPackageName ->
-                existingPackageName ?: locatePackageLineInBody(bytes).also {
-                    if (it == null) {
-                        deferredEntries[sourceFile] = bytes
-                    }
-                }?.let { "$it/${sourceFile.fileName}" }
+        fun getFilenameOrDefer(sourceFile: Path, body: ByteArray): String? =
+            directoryToPackageMap[sourceFile.parent] ?: locatePackagePathOrDefer(sourceFile, body)?.let {
+                "$it/${sourceFile.fileName}"
             }
-        }
 
         /**
          * Visit any deferred entries.
@@ -95,16 +90,13 @@
             }
         }
 
-        private fun locatePackageLineInBody(bytes: ByteArray): String? =
-            bytes.inputStream().bufferedReader().use {
-                var res = it.readLine()
-                while (res != null) {
-                    extractPackage(res)?.replace('.', '/')?.also {
-                        return@use it
-                    }
-                    res = it.readLine()
+        private fun locatePackagePathOrDefer(sourceFile: Path, body: ByteArray): String? =
+            body.inputStream().bufferedReader().useLines {
+                it.mapNotNull(::extractPackage).firstOrNull()?.replace('.', '/')
+            }.also {
+                if (it == null) {
+                    deferredEntries[sourceFile] = body
                 }
-                null
             }
     }
 
@@ -151,7 +143,7 @@
      */
     private fun addJavaLikeSourceFile(sourceFile: Path) {
         val bytes = Files.readAllBytes(sourceFile)
-        filenameHelper.getFilename(sourceFile, bytes)?.also {
+        filenameHelper.getFilenameOrDefer(sourceFile, bytes)?.also {
             addEntry(it, sourceFile, bytes)
         }
     }
diff --git a/kotlin/internal/compile.bzl b/kotlin/internal/compile.bzl
index 0444853..9ff4051 100644
--- a/kotlin/internal/compile.bzl
+++ b/kotlin/internal/compile.bzl
@@ -37,16 +37,18 @@
     return args
 
 def _kotlin_do_compile_action(ctx, rule_kind, output_jar, compile_jars, module_name, friend_paths, srcs):
-    """Internal macro that sets up a Kotlin compile action.
-
-    This macro only supports a single Kotlin compile operation for a rule.
+    """This macro performs a compile operation in a single action.
 
     Args:
       rule_kind: The rule kind,
       output_jar: The jar file that this macro will use as the output of the action.
+      module_name: The Kotlin module name, this must be provided and is used by the compiler for symbol mangling in
+         advanced use cases.
       compile_jars: The compile time jars provided on the classpath for the compile operations -- callers are
         responsible for preparing the classpath. The stdlib (and jdk7 + jdk8) should generally be added to the classpath
         by the caller -- kotlin-reflect could be optional.
+      friend_paths: A list of jars paths that this compilation unit should have package private access to.
+      srcs: a struct with the various input sources partitioned.
     """
     classes_directory=_declare_output_directory(ctx, "jvm", "classes")
     generated_classes_directory=_declare_output_directory(ctx, "jvm", "generated_classes")
@@ -62,7 +64,7 @@
     args.add("--kotlin_generated_classdir", generated_classes_directory)
 
     args.add("--output", output_jar)
-    args.add("--output_jdeps", ctx.outputs.jdeps)
+    args.add("--kotlin_output_jdeps", ctx.outputs.jdeps)
     args.add("--kotlin_output_srcjar", ctx.outputs.srcjar)
 
     args.add("--kotlin_friend_paths", "\n".join(friend_paths.to_list()))
@@ -74,7 +76,7 @@
     # Collect and prepare plugin descriptor for the worker.
     plugin_info=plugins.merge_plugin_infos(ctx.attr.plugins + ctx.attr.deps)
     if len(plugin_info.annotation_processors) > 0:
-        args.add("--kt-plugins", plugin_info.to_json())
+        args.add("--kotlin_plugins", plugin_info.to_json())
 
     progress_message = "Compiling Kotlin %s { kt: %d, java: %d, srcjars: %d }" % (
         ctx.label,
@@ -168,26 +170,10 @@
     deps = [
         d[JavaInfo]
         for d in (
-            toolchain.jvm_stdlibs +
             getattr(ctx.attr, "friends", []) +
             ctx.attr.deps
         )
-    ]
-
-    runtime_deps = [
-        d[JavaInfo]
-        for d in (
-            ctx.attr.runtime_deps +
-            [toolchain.jvm_runtime]
-        )
-    ]
-
-    exports = [
-        d[JavaInfo]
-        for d in (
-            getattr(ctx.attr, "exports", [])
-        )
-    ]
+    ] + [toolchain.jvm_stdlibs]
 
     # setup the compile action.
     _kotlin_do_compile_action(
@@ -205,15 +191,14 @@
         utils.actions.fold_jars(ctx, rule_kind, output_jar, output_merge_list)
 
     # create the java provider but the kotlin and default provider cannot be created here.
-
     return JavaInfo(
         output_jar = ctx.outputs.jar,
         compile_jar = ctx.outputs.jar,
         source_jar = ctx.outputs.srcjar,
 #        jdeps = ctx.outputs.jdeps,
         deps = deps,
-        runtime_deps = runtime_deps,
-        exports = exports,
+        runtime_deps = [d[JavaInfo] for d in ctx.attr.runtime_deps],
+        exports = [d[JavaInfo] for d in getattr(ctx.attr, "exports", [])],
         neverlink = getattr(ctx.attr, "neverlink", False)
     )
 
diff --git a/kotlin/kotlin.bzl b/kotlin/kotlin.bzl
index 87decf2..f9920af 100644
--- a/kotlin/kotlin.bzl
+++ b/kotlin/kotlin.bzl
@@ -159,8 +159,13 @@
         default = [],
         allow_files = [".srcjar", ".kt", ".java"],
     ),
-    "deps": attr.label_list(aspects = [_kt_jvm_plugin_aspect], providers=[JavaInfo]),
-    "runtime_deps": attr.label_list(default = []),
+    "deps": attr.label_list(
+        aspects = [_kt_jvm_plugin_aspect],
+        providers=[
+            [JavaInfo],
+        ],
+        allow_files = False),
+    "runtime_deps": attr.label_list(default = [], allow_files=False),
     "resources": attr.label_list(
         default = [],
         allow_files = True,
@@ -228,6 +233,7 @@
     outputs = _common_outputs,
     toolchains = [_kt.defs.TOOLCHAIN_TYPE],
     implementation = _kt_jvm_library_impl,
+    provides = [JavaInfo, _kt.info.KtInfo]
 )
 
 """This rule compiles and links Kotlin and Java sources into a .jar file.
@@ -308,16 +314,20 @@
         "jars": attr.label_list(
             allow_files = True,
             mandatory = True,
+            cfg = "target",
         ),
         "srcjar": attr.label(
             allow_single_file = True,
+            cfg = "target",
         ),
         "runtime_deps": attr.label_list(
             default = [],
             mandatory = False,
+            providers = [JavaInfo]
         )
     },
     implementation = _kt_jvm_import_impl,
+    provides = [JavaInfo, _kt.info.KtInfo]
 )
 
 # The pairing of src and class is used by intellij to attatch sources, this is picked up via the kt provider attribute.
diff --git a/kotlin/toolchains.bzl b/kotlin/toolchains.bzl
index 814cc52..a0b9c5e 100644
--- a/kotlin/toolchains.bzl
+++ b/kotlin/toolchains.bzl
@@ -84,7 +84,8 @@
 _kt_jvm_attrs = dict(_common_attrs.items() + {
     "jvm_runtime": attr.label(
         default = Label("@" + _KT_COMPILER_REPO + "//:kotlin-runtime"),
-        providers = [JavaInfo]
+        providers = [JavaInfo],
+        cfg = "target",
     ),
     "jvm_stdlibs": attr.label_list(
         default = [
@@ -92,7 +93,8 @@
             Label("@" + _KT_COMPILER_REPO + "//:kotlin-stdlib-jdk7"),
             Label("@" + _KT_COMPILER_REPO + "//:kotlin-stdlib-jdk8"),
         ],
-        providers = [JavaInfo]
+        providers = [JavaInfo],
+        cfg = "target",
     ),
     "jvm_target": attr.string(
         default = "1.8",
@@ -104,7 +106,7 @@
 }.items())
 
 def _kotlin_toolchain_impl(ctx):
-    toolchain = platform_common.ToolchainInfo(
+    toolchain = dict(
         label = _utils.restore_label(ctx.label),
         language_version = ctx.attr.language_version,
         api_version = ctx.attr.api_version,
@@ -112,18 +114,23 @@
 
         jvm_target = ctx.attr.jvm_target,
 
-
         kotlinbuilder = ctx.attr.kotlinbuilder,
         kotlin_home = ctx.files.kotlin_home,
 
-        jvm_runtime = ctx.attr.jvm_runtime,
-        jvm_stdlibs = ctx.attr.jvm_stdlibs
+        jvm_stdlibs = java_common.create_provider(
+            compile_time_jars = ctx.files.jvm_stdlibs,
+            runtime_jars = ctx.files.jvm_runtime,
+            use_ijar = False,
+        ),
     )
-    return struct(providers=[toolchain])
+    return [
+        platform_common.ToolchainInfo(**toolchain)
+    ]
 
 kt_toolchain = rule(
     attrs = _kt_jvm_attrs,
     implementation = _kotlin_toolchain_impl,
+    provides = [platform_common.ToolchainInfo],
 )
 
 """The kotlin jvm toolchain
diff --git a/scripts/gen_proto_jars b/scripts/gen_proto_jars
new file mode 100755
index 0000000..f4afc0f
--- /dev/null
+++ b/scripts/gen_proto_jars
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# The script precompiles the ptoto deps. If this isn't used the client workspaces would have a dependency on protoc.
+# If (when) Bazel distributes a host protoc this file can be removed.
+
+WS_ROOT=$(bazel info workspace)
+PROTO_PATH=kotlin/builder/proto
+JAR_DIR=${WS_ROOT}/${PROTO_PATH}/jars
+
+function build_lib() {
+    bazel build //${PROTO_PATH}:$1_java_proto
+    local FILE=lib$1_proto-speed.jar
+    cp ${WS_ROOT}/bazel-bin/${PROTO_PATH}/${FILE} ${JAR_DIR}/${FILE}
+}
+
+build_lib "deps"
+build_lib "worker_protocol"
+build_lib "kotlin_model"
+
+chmod -R 0744 ${PROTO_PATH}/jars
\ No newline at end of file