OpenCode plugin for WSL devcontainer integration - run commands inside devcontainers from WSL.
When using VSCode Dev Containers from WSL, you need to reinstall OpenCode in every new container. This plugin lets you run OpenCode from WSL and route commands to the container automatically.
- Auto-detect running devcontainers via
devcontainer.local_folderlabel - Container selection by number, ID, or name when multiple containers running
- Visual indicator
[🐳 container-name]prefix in bash output - WSL path conversion automatically converts Linux paths to Windows format
- Direct execution use
!prefix for instant execution without LLM - Security hardened with input validation and command injection prevention
- Container health checks ensures containers are running before command execution
- Dependency checking validates required CLIs are installed
- Operating System: Windows 10/11 with WSL (Windows Subsystem for Linux)
- WSL Distribution: Ubuntu (default) or other distributions (configurable)
- Docker: Docker Desktop with WSL 2 backend
- Node.js: Version 18.0.0 or higher
- WSL 2: Installation guide
- Docker Desktop: Download
- Enable WSL 2 integration in Docker Desktop settings
- devcontainer CLI: Install globally
npm install -g @devcontainers/cli
- jq (required for
scripts/toggle.sh)sudo apt-get update && sudo apt-get install -y jq - OpenCode CLI: Install from opencode.ai
Verify your setup:
# Check WSL
wsl --list --verbose
# Check Docker
docker --version
docker ps
# Check devcontainer CLI
devcontainer --version
# Check Node.js
node --versionnpm install -g @isupervillain/opencode-container-execAdd to your ~/.config/opencode/opencode.json or project opencode.json:
{
"plugin": ["@isupervillain/opencode-container-exec"]
}- Clone this repository
- Copy the
plugindirectory to~/.config/opencode/plugins/or.opencode/plugins/ - Copy
scripts/toggle.shto a location in your PATH
Note: The /container slash command is automatically installed when the plugin loads (global OpenCode config). No manual setup required.
If you don't see /container immediately, restart OpenCode once so the command file can be discovered.
If auto-install fails in your environment, you can still manually copy plugin/command/container.md to ~/.config/opencode/commands/container.md.
For OpenCode runtime loading, keep plugin/index.js limited to plugin export(s) only (for this project: ContainerExecPlugin and default export).
Move helper/utility exports to plugin/internal.js.
# Enable container mode (auto-detect)
!path/to/scripts/toggle.sh on
# Disable container mode
!path/to/scripts/toggle.sh off
# Show current status
!path/to/scripts/toggle.sh status
# List all running devcontainers
!path/to/scripts/toggle.sh list
# Select container by number
!path/to/scripts/toggle.sh on 1
# Select container by ID
!path/to/scripts/toggle.sh on fa6c0c798c6c
# Select container by name
!path/to/scripts/toggle.sh on flamboyant_robinson/container on
/container off
/container status
/container list
/container on 1When container mode is ON, bash commands show:
[🐳 flamboyant_robinson] /home/vscode
[🐳 flamboyant_robinson] Python 3.12.11
When container mode is OFF:
/home/your-user/projects/your-repo
Python 3.12.11
Execute shell commands. Routes to devcontainer when container mode is enabled.
Description:
- When container mode is ON:
Execute shell commands in devcontainer [🐳 container-name] - When container mode is OFF:
Execute shell commands locally on WSL
Arguments:
command(string, required): Shell command to executetimeout(number, optional): Timeout in milliseconds
Returns: Command output with container indicator prefix when applicable.
Toggle devcontainer mode on/off for running commands inside a container.
Description: Toggle devcontainer mode on/off for running commands inside a container
Arguments:
action(enum, required): Action to performon: Enable container modeoff: Disable container modestatus: Show current statuslist: List all running devcontainers
selection(string, optional): Container selection (number, ID, or name)
Returns: Status message and container information.
The toggle.sh script provides the same functionality via command line:
toggle.sh [action] [container]Actions:
on [container]: Enable container mode (auto-detect or specify container)off: Disable container modestatus: Show current state and available containerslist: List all running devcontainers
Container Selection:
- Number: Select by position in list (e.g.,
1) - Container ID: Select by Docker container ID (e.g.,
fa6c0c798c6c) - Container name: Select by Docker container name (e.g.,
flamboyant_robinson)
- The plugin detects running devcontainers by checking the
devcontainer.local_folderDocker label - It converts WSL paths to Windows format (prefers
wslpath -w, falls back to\\wsl.localhost\<distro>\...) - When enabled, bash commands are routed through
devcontainer exec --container-id - State is persisted in
~/.config/opencode/container-mode.json
| Variable | Description | Default | Required |
|---|---|---|---|
WSL_DISTRO_NAME |
WSL distribution name | Ubuntu |
No |
WSL_DISTRO |
Alternate WSL distribution variable (fallback) | unset | No |
HOME |
User home directory | ~ |
No |
NODE_ENV |
Node environment | production |
No |
The plugin stores state in ~/.config/opencode/container-mode.json:
{
"enabled": true,
"containerId": "fa6c0c798c6c",
"containerName": "flamboyant_robinson",
"containerImage": "mcr.microsoft.com/devcontainers/python:2-3.12-bullseye",
"directory": "/home/your-user/projects/your-repo"
}Security: State file is created with restrictive permissions (0o600).
Currently, the plugin uses automatic configuration. Future versions will support:
- Timeout configuration
- Container selection preferences
- Path conversion options
- Security settings
Symptoms: "No running devcontainers found" error
Solutions:
- Ensure VSCode has opened a directory in a devcontainer
- Check if container is running:
docker ps - Verify container has
devcontainer.local_folderlabel:docker inspect --format '{{json .Config.Labels}}' <container_id> | grep devcontainer.local_folder
Symptoms: Commands execute locally instead of in container
Solutions:
- Check container mode status:
!path/to/scripts/toggle.sh status - Verify container is still running:
docker ps | grep <container_name>
- Re-enable container mode:
!path/to/scripts/toggle.sh on
Symptoms: Container not found for current directory
Solutions:
- Check if using correct WSL distribution:
echo $WSL_DISTRO_NAME
- Set distribution name if not Ubuntu (dot/hyphen names are supported, e.g.
Ubuntu-24.04):export WSL_DISTRO_NAME="Ubuntu-24.04"
- Verify path conversion:
wslpath -w "$(pwd)"
Symptoms: "Permission denied" or state file errors
Solutions:
- Check state file permissions:
ls -la ~/.config/opencode/container-mode.json - Fix permissions if needed:
chmod 600 ~/.config/opencode/container-mode.json - Check config directory permissions:
ls -ld ~/.config/opencode chmod 700 ~/.config/opencode
Symptoms: "Cannot connect to Docker daemon" error
Solutions:
- Ensure Docker Desktop is running
- Check WSL integration in Docker Desktop settings
- Verify Docker socket permissions:
ls -la /var/run/docker.sock
- Restart Docker Desktop
Symptoms: "devcontainer: command not found" error
Solutions:
- Install devcontainer CLI:
npm install -g @devcontainers/cli
- Verify installation:
devcontainer --version
- Check PATH includes npm global bin:
echo $PATH | grep "$(npm config get prefix)/bin"
Symptoms: OpenCode fails to load the plugin with a TypeError mentioning plugin.auth.
Cause: plugin/index.js exports non-plugin helper symbols, so runtime plugin detection receives unexpected exports.
Resolution:
- Ensure
plugin/index.jsexports only plugin function entrypoints. - Move helper utilities to
plugin/internal.js. - Upgrade to a release that includes this entrypoint/internal split.
Enable debug logging for troubleshooting:
export NODE_ENV=developmentThis will output security events and debugging information to stderr.
The plugin logs security events in development mode. For production issues:
- Check system logs:
journalctl -u docker - Check Docker logs:
docker logs <container_id> - Check OpenCode logs:
~/.config/opencode/logs/
- Input validation: All inputs validated against strict patterns
- Command injection prevention: Proper escaping of shell arguments
- Secure file permissions: State files created with 0o600 permissions
- Atomic file operations: Prevents state file corruption
- Container health checks: Verifies containers are running before execution
- Dependency validation: Checks required CLIs are installed
- Security logging: Logs suspicious activities in development mode
- Keep dependencies updated: Regularly update Docker, devcontainer CLI, and Node.js
- Use strong container names: Avoid special characters in container names
- Monitor logs: Check security logs for suspicious activities
- Validate inputs: Don't trust user inputs; validate all container selections
- Use restrictive permissions: Ensure config directory has 0o700 permissions
If you discover a security vulnerability, please report it responsibly by opening a private GitHub Security Advisory.
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
# Clone repository
git clone https://github.com/isupervillain/opencode-container-exec.git
cd opencode-container-exec
# Install dependencies
npm install
# Run tests
npm test
# Run tests in watch mode
npm run test:watch# Run all tests
npm test
# Run specific test file
node --test test/unit/state.test.js
# Run tests with watch mode
npm run test:watchSee CHANGELOG.md for version history.
MIT © isupervillain
- Documentation: README.md
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Security: Report via GitHub Security Advisory