mkenv is a CLI that builds and runs per-project developer containers using Docker with security-focused defaults, disposable sessions, and caching for language tooling. It exists for developers who would rather delete a container than reimage their laptop.
This documentation covers how to install, run, and configure mkenv. No YAML files required.
$PATH.brew tap 0xa1bed0/mkenv
brew install mkenv
mkenv version
Important: Ensure Docker is running before launching containers.
cd /path/to/your/projectmkenv .First run: Builds the full image and caches dependencies (slower)
Subsequent runs: Reuse cached layers for fast startup
While mkenv works with zero configuration, you can customize behavior using .mkenv files. These files provide the same options as command-line flags.
Create ~/projects/.mkenv to apply settings to all projects in that directory:
{
"enabled_bricks": ["codex", "nvim", "tmux"]
}
Create .mkenv in your project root:
{
"enabled_bricks": ["claude-code"],
"volumes": ["~/datasets:/data"]
}
Create .mkenv in your project root:
{
"extra_pkgs": ["git", "curl", "vim", "htop", "jq"]
}
These packages will be installed via the system's package manager (e.g., apt-get on Debian-based systems).
.mkenv files found are loaded and merged (root → project).mkenv files| Field | Type | Description |
|---|---|---|
enabled_bricks |
array | Tools to install (e.g., ["codex", "claude-code", "nvim", "pulumi"]) |
disabled_bricks |
array | Tools to exclude from auto-detection |
extra_pkgs |
array | Additional system packages to install (e.g., ["git", "curl", "vim"]) |
volumes |
array | Additional directories to mount (e.g., ["~/data:/data"]) |
disable_auto |
boolean | Disable automatic language detection (default: false) |
Use cases: Set organization-wide defaults, team preferences, or project-specific requirements without repeating command flags.
Run AI coding tools safely inside mkenv containers using the --tools flag.
mkenv . --tools claude-code
claude-code — Anthropic's Claude Code CLIcodex — OpenAI's Codex CLI# Start container with Claude Code
mkenv . --tools claude-code
# Inside the container, run Claude
claude
AI tools run inside the container with restricted access:
~/.ssh, ~/.aws, ~/.config, or other credentialsInstall multiple tools at once:
mkenv . --tools claude-code,nvim,tmux
Other available tools: nvim, tmux, pulumi
-h/--help for usage details.mkenv / mkenv runBuild (if necessary) and run a dev container for the current project.
mkenv run [PATH] [flags]
..| Flag | Type | Description | Default |
|---|---|---|---|
--tools |
comma list | Extra tools to preinstall (e.g. codex,claude,nvim,tmux,pulumi). |
none |
--langs |
comma list | Hint runtimes to prioritize (node,go,python,rust). | auto-detect |
--volume |
comma list | Mount additional host directories inside the container. Supports relative paths (e.g. "~/foo:~/foo") | project dir only |
--rebuild |
bool | Ignore cache and rebuild the image from scratch. | false |
--shell |
string | Preferred shell to launch inside the container (bash, zsh, fish). |
zsh |
--entrypoint |
string | Preferred entrypoint (e.g. "tmux") | none |
mkenv attachOpen an additional shell in an already-running container for the same project.
mkenv attach [PATH]
mkenv listList all mkenv containers and their status.
mkenv list [--verbose]
--verbose includes cache and volume detailsmkenv cleanRemove containers and caches for a project.
mkenv clean [PATH] [--all]
--all: removes all mkenv containers and cachesmkenv completionGenerate shell completion scripts.
mkenv completion [bash|zsh|fish]
Add the output to your shell config for tab completion.
mkenv helpShow help for commands.
mkenv help [command]
mkenv automatically detects your project's languages and tools by scanning for:
package.json, pnpm-lock.yaml, yarn.lockrequirements.txt, poetry.lock, Pipfilego.modCargo.tomlGemfileBased on what it finds, mkenv installs the appropriate language runtimes, package managers, and language servers.
mkenv caches dependencies using Docker volumes. First run builds everything, subsequent runs are fast. Rebuilds only happen when dependency files change.
mkenv scans your project directory for sensitive files (SSH keys, tokens, credential files) before starting. If it detects anything suspicious, it will warn you and ask for confirmation.
Best practice: Never mount sensitive credentials into the container. Keep secrets on your host machine only. Remember that the container could be compromised by a supply chain attack.
Run your dev server normally inside the container:
npm run dev
mkenv automatically routes localhost:3000 (or any port) from your host machine to the container. Access it from your browser, Postman, or any other tool as usual.
Unlike vanilla Docker or Devcontainers, you can't dynamically expose ports from inside a Docker environment — you need to think of exposed ports in advance. mkenv solves this with a bidirectional reverse proxy.
┌──────────────────┐
│ Browser │
│ │
│ connects to │
│ localhost:3000 │
└────┬─────────────┘
│
│ ┌──────────────────────┐
│ │ mkenv host process │ ┌──────────┐
└────────────► │ │ Postgres │
│ Binds :3000, :5432 │────► :5432 │
│ on Mac on demand │ └──────────┘
└───────────▲──────────┘
│
│
:45454 (fixed port)
┌─────────────────┼────────────────────┐
│ Docker │ │
│ │ │
│ ┌────────────▼──────────────┐ │
│ │ mkenv Container │ │
│ │ │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ Proxy Daemon │ │ │
│ │ │ :45454 :5432│ │ │
│ │ └─────────┬──────────▲─┘ │ │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ ┌─────────▼──────────┼─┐ │ │
│ │ │ npm run dev :3000 │ │ │ │
│ │ │ │ │ │ │
│ │ │ connects to │ │ │ │
│ │ │ localhost:5432 ───┘ │ │ │
│ │ └──────────────────────┘ │ │
│ └───────────────────────────┘ │
│ │
└──────────────────────────────────────┘
The mkenv host process acts as a bidirectional traffic hub between your host and the container, using a fixed port (:45454) to avoid Docker's dynamic port limitation.
mkenv . and dies when you exitmkenv includes a comprehensive policy engine that enforces security guardrails at multiple levels. Policies can be configured globally or per-project using a policy.json file.
Secret Detection:
Restricted Directories:
~/.ssh, ~/.aws, ~/.config from being mountedCreate a policy.json file in your mkenv config directory (typically ~/.mkenv/policy.json) to enforce organizational policies:
{
"disabled_bricks": ["codex"],
"enabled_bricks": ["nvim", "tmux"],
"allowed_mount_paths": ["/home/user/projects", "/data"],
"allowed_project_path": "/home/user/projects",
"ignore_preferences": false,
"reverse_proxy": {
"denied_ports": [5432, 3306],
"allowed_ports": []
}
}
| Field | Type | Description |
|---|---|---|
disabled_bricks |
array | Block specific tools from being installed (e.g., ["codex", "claude-code"]) |
enabled_bricks |
array | Force-enable specific tools regardless of project detection |
allowed_mount_paths |
array | Whitelist of directories that can be mounted (empty = allow all except blocked) |
allowed_project_path |
string | Restrict where mkenv can run (empty = allow all) |
ignore_preferences |
boolean | Override user preferences with policy settings |
reverse_proxy |
object | Control which host ports containers can access (see Reverse Proxy Security below) |
0444 permissions (read-only). mkenv will refuse to start if the policy file has incorrect permissions. This prevents unauthorized modification of security policies.
chmod 444 ~/.mkenv/policy.json
mkenv allows containers to access host services (like databases) via a reverse proxy. The policy engine strictly controls which ports can be accessed.
The following ports are permanently blocked and cannot be overridden by policy configuration:
{
"reverse_proxy": {
"denied_ports": [5432, 3306],
"allowed_ports": [8000, 8080]
}
}
denied_ports - Additional ports to block beyond hardcoded listallowed_ports - Explicit allowlist (if set, only these ports are accessible, but hardcoded denials still apply)Policies can control which tools (called "bricks") are available:
{
"disabled_bricks": ["claude-code", "codex"],
"enabled_bricks": ["nvim", "tmux", "pulumi"]
}
Use Cases:
{
"allowed_mount_paths": [
"/home/user/projects",
"/data/shared"
]
}
allowed_mount_paths is set, only directories under these paths can be mounted~/.ssh){
"allowed_project_path": "/home/user/approved-projects"
}
{
"disabled_bricks": ["codex"],
"enabled_bricks": ["nvim"],
"allowed_project_path": "/work/projects",
"allowed_mount_paths": ["/work"],
"ignore_preferences": true,
"reverse_proxy": {
"denied_ports": [5432, 3306, 6379, 27017],
"allowed_ports": []
}
}
This policy:
/work/projects directory only/work{
"disabled_bricks": [],
"enabled_bricks": ["claude-code", "nvim", "tmux"],
"reverse_proxy": {
"denied_ports": [],
"allowed_ports": []
}
}
This policy:
Not officially yet. Linux support is near-term; Windows likely rides on WSL once the experience doesn't suck.
No, it depends on Docker for virtualization. Think of mkenv as the paranoid orchestrator on top.
In Docker volumes managed by mkenv. Use mkenv list --verbose to inspect cache details.
Run mkenv . again. You'll either reattach or get a fresh container using existing caches.
No. It's a dev tool for local workstations, not a deployment platform. If you push it to prod, that's on you.
Yes. You can connect VS Code or Cursor to the mkenv container using their remote development features. This keeps the editor UI on your host while running all commands inside the container.
No analytics pings. If something breaks, file an issue rather than letting logs spy on you.
Git operations (push, pull, clone) happen on your host machine where your credentials live. Everything else happens in the sandbox. This separates concerns: work runs isolated with no credentials, git operations run on host with credentials and no bloat.
Use mkenv sandbox install <pkg> from inside the container. This is a controlled, audited way to install system packages. You can also specify packages in your .mkenv file with extra_pkgs.
Guide it with CLI options (--langs, --tools), a .mkenv file, or adjust ad-hoc with mkenv sandbox install.
VS Code and Cursor can connect to mkenv containers using their remote development features. Dedicated plugins coming soon.