Is split-mode / remote-development the only way to make plugins work with dev containers?

I started adapting our plugin to split mode because our users want to use it with Dev Containers. Could you advise whether supporting split mode is the only viable approach for our plugin to work in that environment?

Some core functionality of our plugin:

  • Downloading and managing versions of a CLI binary. When the user is working inside a Dev Container, we need to download the Linux version of the binary in to the Dec Container file system.

  • Executing multiple commands through the CLI tool. These commands need to run inside the Dev Container.

  • Receiving additional environment variables from the CLI tool and injecting them into the run configuration for the application process being debugged.

  • One of these environment variables is LD_PRELOAD, which points to a shared library used to hook into the user’s application process. The library file must exist inside the Dev Container.

Link to our plugin’s GitHub repo: GitHub - metalbear-co/mirrord-intellij: Connect your local process and your cloud environment, and run local code in cloud conditions. · GitHub

Could you please clarify, do you primarily need local DevContainers in Docker or truly remote ones as well?

We only need our plugin to work with local dev container for now.

Hi Yuan,

For IntelliJ IDEA specifically, IDEA can open a Dev Container project natively since 2025.3, and in 2026.1 this is on by default — the IDE keeps running locally and only a small agent is provisioned inside the container, so Split Mode is no longer required there. The native mode is not enabled across every IDE in the family yet, so where it isn’t available Split Mode remains the only option for now. Internally we are steadily migrating platform features and bundled plugins to the native mode, with the goal of having this coverage broadly in place by 2026.3, and we plan to publicly announce the underlying API as part of the next release.

Under the hood, native Dev Container support is built on a new platform API, EelApi, which abstracts the execution environment — local, WSL, Docker (including Dev Containers). Through a single EelApi instance you get:

  • a file-system view of the environment (NIO Path operations are transparently routed there, plus helpers for transferring local content into it),
  • process execution inside the environment,
  • TCP tunnels into and out of it,
  • platform/OS detection for the environment.

The API is currently marked @ApiStatus.Experimental. We expect to stabilize it in the next release, alongside technical blog posts and platform documentation, and it will go through API review before that. Some surface changes are expected, but we expect them to be limited: the same API has been used in production for several releases to power WSL support and Dev Containers in IntelliJ-based IDEs, so the shape is well-exercised. We think it is well worth trying out today, and feedback is very welcome.

The entry point for a plugin is the Project.getEelDescriptor() extension — given a Project (local, WSL, or in a Dev Container), it returns an EelDescriptor that you convert to an EelApi. It lives in com.intellij.platform.eel.provider.EelProviderProjectUtilKt.

Sketched against your three concrete needs:

1. Place a Linux CLI binary into the container’s filesystem

import com.intellij.platform.eel.fs.createTemporaryDirectory
import com.intellij.platform.eel.getOrThrow
import com.intellij.platform.eel.provider.asNioPath
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.eel.provider.toEelApi
import java.nio.file.Files

val eel = project.getEelDescriptor().toEelApi()
// remoteDir is a NIO Path that points *inside* the container; standard NIO
// operations (Files.copy, Files.write, ...) are transparently routed through EEL.
val remoteDir = eel.fs.createTemporaryDirectory()
    .prefix("mirrord-")
    .deleteOnExit(true)
    .getOrThrow()
    .asNioPath()
val remoteBinary = Files.copy(localBinary, remoteDir.resolve(localBinary.fileName))

(There is also a one-liner helper EelPathUtils.transferLocalContentToRemote(source, EelPathUtils.TransferTarget.Temporary(descriptor)) that does essentially this for you. It is currently @ApiStatus.Internal; an equivalent will land on the public surface alongside the EEL stabilization.)

2. Run the CLI inside the container

import com.intellij.platform.eel.provider.asEelPath
import com.intellij.platform.eel.provider.getEelDescriptor
import com.intellij.platform.eel.provider.toEelApi
import com.intellij.platform.eel.provider.utils.readAllBytes
import com.intellij.platform.eel.spawnProcess

val eel = project.getEelDescriptor().toEelApi()
val process = eel.exec.spawnProcess(remoteBinary.asEelPath().toString())
    .args("--version")
    .eelIt()

val exitCode = process.exitCode.await()
val stdout = process.stdout.readAllBytes().toString(Charsets.UTF_8)

3. Get a container-side path string for LD_PRELOAD (or any other env var on a run configuration)

import com.intellij.platform.eel.provider.asEelPath

// Convert a NIO Path that refers to the file inside the container into the absolute
// path string the container itself sees (e.g. /tmp/mirrord-xyz/libmirrord_layer.so).
val containerSidePath: String = sharedLibrary.asEelPath().toString()
runConfiguration.environmentVariables += "LD_PRELOAD" to containerSidePath

And if you need to talk to a TCP port inside the container from the IDE side, eel.tunnels.withConnectionToRemotePort(...) opens that connection for you (with a matching API for listening on the container side).

If you give this a try and run into rough edges or missing capabilities, please do file them — that feedback is what we need to make the API solid.

Best,
Alexander