cherry pick directory structure from ic branch, refactor and document model.
diff --git a/kotlin/builder/integrationtests/KotlinBuilderActionTests.java b/kotlin/builder/integrationtests/KotlinBuilderActionTests.java
index 59b1fdb..a26c1a1 100644
--- a/kotlin/builder/integrationtests/KotlinBuilderActionTests.java
+++ b/kotlin/builder/integrationtests/KotlinBuilderActionTests.java
@@ -9,6 +9,6 @@
     addSource("AClass.kt", "package something;" + "class AClass{}");
     instance(KotlinCompiler.class).compile(builderCommand());
     assertFileExists(DirectoryType.CLASSES, "something/AClass.class");
-    assertFileDoesNotExist(outputs().getOutput());
+    assertFileDoesNotExist(outputs().getJar());
   }
 }
diff --git a/kotlin/builder/integrationtests/KotlinBuilderTestCase.java b/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
index 01ed512..f1cc005 100644
--- a/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
+++ b/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
@@ -38,12 +38,16 @@
     return builder.getOutputs();
   }
 
+  protected KotlinModel.BuilderCommand.Directories directories() {
+    return builder.getDirectories();
+  }
+
   protected String label() {
     return Preconditions.checkNotNull(label);
   }
 
   private Path classDir() {
-    return Paths.get(outputs().getClassDirectory());
+    return Paths.get(directories().getClasses());
   }
 
   protected KotlinModel.BuilderCommand builderCommand() {
@@ -55,7 +59,8 @@
   }
 
   protected void addSource(String filename, String... lines) {
-    Path file = Preconditions.checkNotNull(inputSourceDir, "initialize test context").resolve(filename);
+    Path file =
+        Preconditions.checkNotNull(inputSourceDir, "initialize test context").resolve(filename);
     try (BufferedWriter writer = com.google.common.io.Files.newWriter(file.toFile(), UTF_8)) {
       writer.write(Joiner.on("\n").join(lines));
       String f = file.toString();
@@ -74,10 +79,13 @@
 
   protected void resetTestContext(String label) {
     this.label = label;
+    Path prefixPath = Paths.get(label);
+
+    createTestOuputDirectory(prefixPath);
+    inputSourceDir = Paths.get(createTestOuputDirectory(prefixPath.resolve("input_sources")));
+
     builder.clear();
-    KotlinModel.BuilderCommand.Outputs.Builder testOuputs = setupTestOutputs(label);
-    builder.setInfo(
-        KotlinModel.BuilderCommand.Info.newBuilder()
+    builder.getInfoBuilder()
             .setLabel("//some/bogus:" + label)
             .setKotlinModuleName("some_bogus_module")
             .setRuleKind("kt_jvm_library")
@@ -88,8 +96,17 @@
                             .setApiVersion("1.2")
                             .setCoroutines("enabled")
                             .setLanguageVersion("1.2"))
-                    .setJvm(KotlinModel.KotlinToolchainInfo.Jvm.newBuilder().setJvmTarget("1.8"))));
-    builder.setOutputs(testOuputs);
+                    .setJvm(KotlinModel.KotlinToolchainInfo.Jvm.newBuilder().setJvmTarget("1.8")));
+    builder
+        .getDirectoriesBuilder()
+        .setClasses(prefixPath.resolve("classes").toAbsolutePath().toString())
+        .setGeneratedSources(prefixPath.resolve("sources").toAbsolutePath().toString())
+        .setTemp(prefixPath.resolve("temp").toAbsolutePath().toString())
+        .setGeneratedClasses(prefixPath.resolve("generated_classes").toAbsolutePath().toString());
+    builder
+        .getOutputsBuilder()
+        .setJar(prefixPath.resolve("jar_file.jar").toAbsolutePath().toString())
+        .setJdeps(prefixPath.resolve("jdeps_files.jdeps").toAbsolutePath().toString());
   }
 
   private static String createTestOuputDirectory(Path path) {
@@ -108,21 +125,10 @@
     }
   }
 
-  private KotlinModel.BuilderCommand.Outputs.Builder setupTestOutputs(String label) {
-    Path prefixPath = Paths.get(label);
-    createTestOuputDirectory(prefixPath);
-    inputSourceDir = Paths.get(createTestOuputDirectory(prefixPath.resolve("input_sources")));
-    return KotlinModel.BuilderCommand.Outputs.newBuilder()
-        .setClassDirectory(prefixPath.resolve("classes").toAbsolutePath().toString())
-        .setSourceGenDir(prefixPath.resolve("sources").toAbsolutePath().toString())
-        .setTempDirectory(prefixPath.resolve("temp").toAbsolutePath().toString())
-        .setOutputJdeps(prefixPath.resolve("jdeps_files.jdeps").toAbsolutePath().toString())
-        .setOutput(prefixPath.resolve("jar_file.jar").toAbsolutePath().toString());
-  }
-
   protected enum DirectoryType {
     ROOT,
     CLASSES,
+    GENERATED_CLASSES,
     TEMP,
     SOURCE_GEN;
 
@@ -130,13 +136,16 @@
       Path ret;
       switch (type) {
         case CLASSES:
-          ret = Paths.get(command.getOutputs().getClassDirectory());
+          ret = Paths.get(command.getDirectories().getClasses());
+          break;
+        case GENERATED_CLASSES:
+          ret = Paths.get(command.getDirectories().getGeneratedClasses());
           break;
         case TEMP:
-          ret = Paths.get(command.getOutputs().getTempDirectory());
+          ret = Paths.get(command.getDirectories().getTemp());
           break;
         case SOURCE_GEN:
-          ret = Paths.get(command.getOutputs().getSourceGenDir());
+          ret = Paths.get(command.getDirectories().getGeneratedSources());
           break;
         default:
           throw new RuntimeException("unhandled type: " + type);
diff --git a/kotlin/builder/integrationtests/KotlinBuilderTests.java b/kotlin/builder/integrationtests/KotlinBuilderTests.java
index 0d515e9..cb5aa62 100644
--- a/kotlin/builder/integrationtests/KotlinBuilderTests.java
+++ b/kotlin/builder/integrationtests/KotlinBuilderTests.java
@@ -3,11 +3,13 @@
 import com.google.common.truth.Truth;
 import com.google.devtools.build.lib.view.proto.Deps;
 import io.bazel.kotlin.builder.mode.jvm.KotlinJvmCompilationExecutor;
+import io.bazel.kotlin.model.KotlinModel;
 import org.junit.Test;
 
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -28,23 +30,33 @@
     runCompileTask();
     assertFileExists(DirectoryType.CLASSES, "something/AClass.class");
     assertFileExists(DirectoryType.CLASSES, "something/AnotherClass.class");
-    assertFileExists(outputs().getOutput());
+    assertFileExists(outputs().getJar());
   }
 
   private void runCompileTask() {
+    KotlinModel.BuilderCommand command = builderCommand();
+    for (DirectoryType directoryType : DirectoryType.values()) {
+      try {
+        if (directoryType != DirectoryType.ROOT) {
+          Files.createDirectories(DirectoryType.select(directoryType, command));
+        }
+      } catch (IOException e) {
+        throw new UncheckedIOException(e);
+      }
+    }
     int timeoutSeconds = 10;
     KotlinJvmCompilationExecutor executor = instance(KotlinJvmCompilationExecutor.class);
     try {
-      CompletableFuture.runAsync(() -> executor.compile(builderCommand()))
+      CompletableFuture.runAsync(() -> executor.compile(command))
           .get(timeoutSeconds, TimeUnit.SECONDS);
     } catch (TimeoutException e) {
       throw new AssertionError("did not complete in: " + timeoutSeconds);
     } catch (Exception e) {
       throw new RuntimeException(e);
     }
-    assertFileExists(outputs().getOutput());
-    assertFileExists(outputs().getOutputJdeps());
-    try (FileInputStream fs = new FileInputStream(Paths.get(outputs().getOutputJdeps()).toFile())) {
+    assertFileExists(outputs().getJar());
+    assertFileExists(outputs().getJdeps());
+    try (FileInputStream fs = new FileInputStream(Paths.get(outputs().getJdeps()).toFile())) {
       Deps.Dependencies dependencies = Deps.Dependencies.parseFrom(fs);
       Truth.assertThat(dependencies.getRuleLabel()).endsWith(label());
     } catch (IOException e) {
diff --git a/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar b/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar
index d44630c..943c343 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 8d27cd0..d1e4ced 100644
--- a/kotlin/builder/proto/kotlin_model.proto
+++ b/kotlin/builder/proto/kotlin_model.proto
@@ -17,32 +17,45 @@
 
 option java_package = "io.bazel.kotlin.model";
 
+// An abstract definition of an annotation processor. This is encoded into a format understood by kapt3.
+// +stable
 message AnnotationProcessor {
-    // the annotation processor class
+    // The annotation processor class.
     string processor_class = 1;
-    // bazel `java_plugin` generates_api setting.
+    // The Bazel `java_plugin` `generates_api` attribute.
     bool generates_api = 2;
-    // the classpath
+    // The full transitive classpath required for annotation processing.
     repeated string classpath = 3;
-
+    // The label of the plugin.
     string label = 4;
 }
 
+// A container for all of the types of compiler plugins needed by the kotlin compilers.
+// +stable
 message CompilerPlugins {
+    // Regular java annotation_processor descriptors.
     repeated AnnotationProcessor annotation_processors = 1;
 }
 
+// Toolchain info this contains info to be used to configure the compile tasks as well as configuring certain features
+// in IDE plugins.
+// +stable
 message KotlinToolchainInfo {
+    // Common properties that should be common to all platforms.
     message Common {
         // mandatory
         string language_version = 1;
-        //mandatory
+        // mandatory
         string api_version = 2;
+        // mandatory
         // oneof "enable", "warn" or "error"
         string coroutines = 3;
     }
 
+    // Properties specific to the JVM.
     message Jvm {
+        // The property is additionally to configure the source and target bytecode levels in kapt3, javac and kotlin.
+        // mandatory
         // oneof "1.6", or "1.8"
         string jvm_target = 1;
     }
@@ -51,6 +64,7 @@
     Jvm jvm = 2;
 }
 
+// Mested messages not marked with stable could be refactored.
 message BuilderCommand {
     message Info {
         string label = 1;
@@ -67,44 +81,65 @@
 
         CompilerPlugins plugins = 8;
 
-        // derived from plugins
-        repeated string encoded_plugin_descriptors=9;
+        // All of the plugin descriptors in the format kotlinc understands.
+        // +derived
+        repeated string encoded_plugin_descriptors = 9;
 
-        // friend jars -- kotlin compiler allows internal visibility access to these jars. Used for tests.
+        // Jars that the kotlin compiler will allow package private access to.
         repeated string friend_paths = 10;
     }
 
-    message Outputs {
-        string class_directory = 1;
-        string temp_directory = 2;
-        string source_gen_dir = 3;
+    // Directories used by the builder.
+    // +stable
+    message Directories {
+        // The directory the compiler should use for class files.
+        string classes = 1;
+        // The directory to use by annotation processors to produce classes.
+        string generated_classes = 2;
+        // The directory used by annotation processors. The generated sources are currently only java.
+        string generated_sources = 3;
+        // A temp directory that the compiler may use. The source_jars are expanding into here.
+        string temp = 4;
+    }
 
-        string output = 4;
-        string output_jdeps = 5;
+    // Outputs produced by the builder.
+    // +stable
+    message Outputs {
+        // The path to the primary output jar.
+        string jar = 1;
+        // The path to the jdeps file.
+        string jdeps = 2;
     }
 
     message Inputs {
+        // The full classpath
         repeated string classpath = 1;
-        // derived from command line classpath
+        // The full joined classpath
+        // +derived
         string joined_classpath = 2;
-
+        // Direct dependencies of the target.
         map<string, string> direct_dependencies = 3;
+        // Indirect dependencies of the target.
         map<string, string> indirect_dependencies = 4;
 
-        // partitioned from builder flags
+        // Partitioned from the builder flags and by expanding the source_jars.
+        // +derived
         repeated string kotlin_sources = 5;
-        // partitioned from builder flags
+        // Partitioned from the builder flags and by expanding the source_jars.
+        // +derived
         repeated string java_sources = 6;
-
-        // created during compilation
+        // Created during annotation processing and partitioned from the generated_sources directory.
+        // +dervived
         repeated string generated_kotlin_sources = 7;
-        // created during compilation
+        // Created during annotation processing and partitioned from the generated_sources directory.
+        // +derived
         repeated string generated_java_sources = 8;
-
+        // Jars containing additional sources.
         repeated string source_jars = 9;
     }
 
     Info info = 1;
-    Outputs outputs = 2;
-    Inputs inputs = 3;
+    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/BuildCommandBuilder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/BuildCommandBuilder.kt
index 9e69452..54302c1 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/BuildCommandBuilder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/BuildCommandBuilder.kt
@@ -87,11 +87,15 @@
     override fun fromInput(argMap: ArgMap): BuilderCommand =
         BuilderCommand.newBuilder().let { root ->
             with(root.outputsBuilder) {
-                classDirectory = argMap.mandatorySingle(JavaBuilderFlags.CLASSDIR.flag)
-                tempDirectory = argMap.mandatorySingle(JavaBuilderFlags.TEMPDIR.flag)
-                sourceGenDir = argMap.mandatorySingle(JavaBuilderFlags.SOURCEGEN_DIR.flag)
-                output = argMap.mandatorySingle(JavaBuilderFlags.OUTPUT.flag)
-                outputJdeps = argMap.mandatorySingle("--output_jdeps")
+                jar = argMap.mandatorySingle(JavaBuilderFlags.OUTPUT.flag)
+                jdeps = argMap.mandatorySingle("--output_jdeps")
+            }
+
+            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)
             }
 
             with(root.inputsBuilder) {
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilder.kt
index a5cda42..61431ba 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilder.kt
@@ -21,8 +21,8 @@
 import io.bazel.kotlin.builder.mode.jvm.KotlinJvmCompilationExecutor
 import io.bazel.kotlin.builder.utils.ArgMap
 import io.bazel.kotlin.builder.utils.ArgMaps
+import io.bazel.kotlin.builder.utils.ensureDirectories
 import io.bazel.kotlin.model.KotlinModel
-import java.nio.file.Files
 import java.nio.file.Paths
 
 @Singleton
@@ -39,7 +39,12 @@
         commandBuilder.fromInput(args).let { execute(it) }
 
     fun execute(command: KotlinModel.BuilderCommand): Int {
-        ensureOutputDirectories(command)
+        ensureDirectories(
+            command.directories.classes,
+            command.directories.temp,
+            command.directories.generatedSources,
+            command.directories.generatedClasses
+        )
         val updatedCommand = expandWithSourceJarSources(command)
         return try {
             compilationExector.compile(updatedCommand)
@@ -49,12 +54,6 @@
         }
     }
 
-    private fun ensureOutputDirectories(command: KotlinModel.BuilderCommand) {
-        Files.createDirectories(Paths.get(command.outputs.classDirectory))
-        Files.createDirectories(Paths.get(command.outputs.tempDirectory))
-        Files.createDirectories(Paths.get(command.outputs.sourceGenDir))
-    }
-
     /**
      * If any sourcejars were provided expand the jars sources and create a new [KotlinModel.BuilderCommand] with the
      * Java and Kotlin sources merged in.
@@ -64,7 +63,7 @@
             command
         } else {
             val sourceUnpackDirectory =
-                Paths.get(command.outputs.tempDirectory).let {
+                Paths.get(command.directories.temp).let {
                     it.resolve("_srcjars").toFile().let {
                         try {
                             it.mkdirs(); it
@@ -75,7 +74,8 @@
                 }
             for (sourceJar in command.inputs.sourceJarsList) {
                 jarToolInvoker.invoke(
-                    listOf("xf", Paths.get(sourceJar).toAbsolutePath().toString()), sourceUnpackDirectory)
+                    listOf("xf", Paths.get(sourceJar).toAbsolutePath().toString()), sourceUnpackDirectory
+                )
             }
 
             commandBuilder.withSources(
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/KotlinJvmCompilationExecutor.kt b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/KotlinJvmCompilationExecutor.kt
index 6ce5a15..db1b42d 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/KotlinJvmCompilationExecutor.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/KotlinJvmCompilationExecutor.kt
@@ -21,7 +21,6 @@
 import com.google.inject.Singleton
 import io.bazel.kotlin.builder.BuildCommandBuilder
 import io.bazel.kotlin.builder.CompilationStatusException
-import io.bazel.kotlin.builder.ToolException
 import io.bazel.kotlin.builder.mode.jvm.KotlinJvmCompilationExecutor.Result
 import io.bazel.kotlin.builder.mode.jvm.actions.JDepsGenerator
 import io.bazel.kotlin.builder.mode.jvm.actions.JavaCompiler
@@ -67,7 +66,7 @@
         try {
             if (command.info.plugins.annotationProcessorsList.isNotEmpty()) {
                 kotlinCompiler.runAnnotationProcessor(command)
-                File(command.outputs.sourceGenDir).walkTopDown()
+                File(command.directories.generatedSources).walkTopDown()
                     .filter { it.isFile }
                     .map { it.path }
                     .iterator()
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JDepsGenerator.kt b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JDepsGenerator.kt
index 4c167a2..0bcc45f 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JDepsGenerator.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JDepsGenerator.kt
@@ -55,7 +55,7 @@
                         val res = invoker.run(
                             arrayOf(
                                 "-cp", command.inputs.joinedClasspath,
-                                command.outputs.output),
+                                command.outputs.jdeps),
                             writer)
                         out.toByteArray().inputStream().bufferedReader().readLines().let {
                             if (res != 0) {
@@ -64,7 +64,7 @@
                             try {
                                 JdepsParser.parse(
                                     command.info.label,
-                                    command.outputs.output,
+                                    command.outputs.jdeps,
                                     command.inputs.joinedClasspath,
                                     it,
                                     isKotlinImplicit
@@ -76,7 +76,7 @@
                     }
                 }
             }
-        Paths.get(command.outputs.outputJdeps).also {
+        Paths.get(command.outputs.jdeps).also {
             Files.deleteIfExists(it)
             FileOutputStream(Files.createFile(it).toFile()).use {
                 jdepsContent.writeTo(it)
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JavaCompiler.kt b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JavaCompiler.kt
index b88f440..ee5df82 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JavaCompiler.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/JavaCompiler.kt
@@ -31,12 +31,12 @@
     val javacInvoker: KotlinToolchain.JavacInvoker
 ) : JavaCompiler {
     override fun compile(command: BuilderCommand) {
-        val inputs = command.inputs
-        val outputs = command.outputs
-        if (inputs.javaSourcesList.isNotEmpty() || inputs.generatedJavaSourcesList.isNotEmpty()) {
+        val i = command.inputs
+        val d = command.directories
+        if (i.javaSourcesList.isNotEmpty() || i.generatedJavaSourcesList.isNotEmpty()) {
             val args = mutableListOf(
-                "-cp", "${outputs.classDirectory}/:${outputs.tempDirectory}/:${inputs.joinedClasspath}",
-                "-d", outputs.classDirectory
+                "-cp", "${d.classes}/:${d.temp}/:${i.joinedClasspath}",
+                "-d", d.classes
             ).let {
                 it.addAll(
                     // Kotlin takes care of annotation processing.
@@ -46,8 +46,8 @@
                     "-source", command.info.toolchainInfo.jvm.jvmTarget,
                     "-target", command.info.toolchainInfo.jvm.jvmTarget
                 )
-                it.addAll(inputs.javaSourcesList)
-                it.addAll(inputs.generatedJavaSourcesList)
+                it.addAll(i.javaSourcesList)
+                it.addAll(i.generatedJavaSourcesList)
                 it.toTypedArray()
             }
             javacInvoker.compile(args).takeIf { it != 0 }?.also { throw CompilationStatusException("javac failed",it) }
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/KotlinCompiler.kt b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/KotlinCompiler.kt
index dbff055..ffcf837 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/KotlinCompiler.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/KotlinCompiler.kt
@@ -71,7 +71,7 @@
 
         args
             .addAll("-module-name", command.info.kotlinModuleName)
-            .addAll("-d", command.outputs.classDirectory)
+            .addAll("-d", command.directories.classes)
 
         command.info.passthroughFlags?.takeIf { it.isNotBlank() }?.also { args.addAll(it.split(" ")) }
         return args
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/OutputJarCreator.kt b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/OutputJarCreator.kt
index 19aab9f..e46147b 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/OutputJarCreator.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/mode/jvm/actions/OutputJarCreator.kt
@@ -33,9 +33,10 @@
     private fun MutableList<String>.addAllFrom(dir: Path) = addAll(arrayOf("-C", dir.toString(), "."))
     override fun createOutputJar(command: KotlinModel.BuilderCommand) {
         mutableListOf(
-            "cf", command.outputs.output
+            "cf", command.outputs.jar
         ).also { args ->
-            args.addAllFrom(Paths.get(command.outputs.classDirectory))
+            args.addAllFrom(Paths.get(command.directories.classes))
+            args.addAllFrom(Paths.get(command.directories.generatedClasses))
         }.let { toolInvoker.invoke(it) }
     }
 }
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/IOUtils.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/IOUtils.kt
index 0eb34a3..9e9c70b 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/IOUtils.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/IOUtils.kt
@@ -20,6 +20,7 @@
 import java.io.BufferedReader
 import java.io.File
 import java.io.PrintStream
+import java.nio.file.Files
 import java.nio.file.Path
 import java.nio.file.Paths
 import java.util.*
@@ -72,6 +73,11 @@
 
 fun Path.verified(): File = this.toFile().also { check(it.exists()) { "file did not exist: $this" } }
 
+fun ensureDirectories(vararg directories: String) {
+    for (directory in directories) {
+        Files.createDirectories(Paths.get(directory))
+    }
+}
 
 val Throwable.rootCause: Throwable
     get() {
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 716107d..1d29c0a 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
@@ -96,13 +96,13 @@
         val javacArgs = mutableMapOf<String, String>(
             "-target" to command.info.toolchainInfo.jvm.jvmTarget
         )
-
+        val d = command.directories
         return command.info.plugins.takeIf { it.annotationProcessorsList.isNotEmpty() }?.let { plugin ->
             PluginArgs().let { arg ->
-                arg["sources"] = command.outputs.sourceGenDir.toString()
-                arg["classes"] = command.outputs.classDirectory.toString()
-                arg["stubs"] = command.outputs.tempDirectory.toString()
-                arg["incrementalData"] = command.outputs.tempDirectory.toString()
+                arg["sources"] = d.generatedSources.toString()
+                arg["classes"] = d.generatedClasses.toString()
+                arg["stubs"] = d.temp.toString()
+                arg["incrementalData"] = d.temp.toString()
                 arg["javacArguments"] = javacArgs.let(::encodeMap)
                 arg["aptMode"] = "stubsAndApt"
                 arg["correctErrorTypes"] = "true"
diff --git a/kotlin/internal/compile.bzl b/kotlin/internal/compile.bzl
index 9a02835..b444c16 100644
--- a/kotlin/internal/compile.bzl
+++ b/kotlin/internal/compile.bzl
@@ -15,6 +15,9 @@
 load("//kotlin/internal:plugins.bzl", "plugins")
 load("//kotlin/internal:utils.bzl", "utils")
 
+def _declare_output_directory(ctx, aspect, dir_name):
+    return ctx.actions.declare_directory("_kotlinc/%s_%s/%s_%s" % (ctx.label.name, aspect, ctx.label.name, dir_name))
+
 def _kotlin_do_compile_action(ctx, rule_kind, output_jar, compile_jars, module_name, friend_paths, srcs, src_jars):
     """Internal macro that sets up a Kotlin compile action.
 
@@ -27,9 +30,11 @@
         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.
     """
-    classes_directory=ctx.actions.declare_directory(ctx.label.name + "_classes")
-    sourcegen_directory=ctx.actions.declare_directory(ctx.label.name + "_sourcegendir")
-    temp_directory=ctx.actions.declare_directory(ctx.label.name + "_tempdir")
+    classes_directory=_declare_output_directory(ctx, "jvm", "classes")
+    generated_classes_directory=_declare_output_directory(ctx, "jvm", "generated_classes")
+    sourcegen_directory=_declare_output_directory(ctx, "jvm", "sourcegenfiles")
+    temp_directory=_declare_output_directory(ctx, "jvm", "temp")
+
 
     tc=ctx.toolchains[kt.defs.TOOLCHAIN_TYPE]
 
@@ -40,6 +45,7 @@
         "--classdir", classes_directory.path,
         "--sourcegendir", sourcegen_directory.path,
         "--tempdir", temp_directory.path,
+        "--kotlin_generated_classdir", generated_classes_directory.path,
 
         "--output", output_jar.path,
         "--output_jdeps", ctx.outputs.jdeps.path,
@@ -83,7 +89,14 @@
     ctx.action(
         mnemonic = "KotlinCompile",
         inputs = compile_inputs,
-        outputs = [output_jar, ctx.outputs.jdeps, sourcegen_directory, classes_directory, temp_directory],
+        outputs = [
+            output_jar,
+            ctx.outputs.jdeps,
+            sourcegen_directory,
+            classes_directory,
+            temp_directory,
+            generated_classes_directory
+        ],
         executable = ctx.executable._kotlinw,
         execution_requirements = {"supports-workers": "1"},
         arguments = ["@" + args_file.path],