Overview

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.

Installation

Platform: macOS only right now. Linux is on the radar, Windows likely via WSL later. Bring Docker Desktop or equivalent.

Prerequisites

Install via Homebrew

brew tap 0xa1bed0/mkenv
brew install mkenv

Verify Installation

mkenv version

Important: Ensure Docker is running before launching containers.

Quickstart

  1. Navigate to your project directory: cd /path/to/your/project
  2. Run: mkenv .
  3. mkenv analyzes your project, builds a Docker image, and drops you into a container shell
  4. You're now inside a sandboxed environment with all detected tools installed

First run: Builds the full image and caches dependencies (slower)

Subsequent runs: Reuse cached layers for fast startup

.mkenv Configuration Files

While mkenv works with zero configuration, you can customize behavior using .mkenv files. These files provide the same options as command-line flags.

Example: Organization-wide Defaults

Create ~/projects/.mkenv to apply settings to all projects in that directory:

{
  "enabled_bricks": ["codex", "nvim", "tmux"]
}

Example: Project-specific Settings

Create .mkenv in your project root:

{
  "enabled_bricks": ["claude-code"],
  "volumes": ["~/datasets:/data"]
}

Example: Install Additional System Packages

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).

How It Works

Available Fields

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.

LLM Support

Run AI coding tools safely inside mkenv containers using the --tools flag.

Example: Install Claude Code

mkenv . --tools claude-code

Available LLM Tools

Usage

# Start container with Claude Code
mkenv . --tools claude-code

# Inside the container, run Claude
claude

Security Isolation

AI tools run inside the container with restricted access:

Combining Tools

Install multiple tools at once:

mkenv . --tools claude-code,nvim,tmux

Other available tools: nvim, tmux, pulumi

Commands

All commands accept -h/--help for usage details.

mkenv / mkenv run

Build (if necessary) and run a dev container for the current project.

mkenv run [PATH] [flags]

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 attach

Open an additional shell in an already-running container for the same project.

mkenv attach [PATH]

mkenv list

List all mkenv containers and their status.

mkenv list [--verbose]

mkenv clean

Remove containers and caches for a project.

mkenv clean [PATH] [--all]

mkenv completion

Generate shell completion scripts.

mkenv completion [bash|zsh|fish]

Add the output to your shell config for tab completion.

mkenv help

Show help for commands.

mkenv help [command]

Configuration & Behavior

Automatic Language Detection

mkenv automatically detects your project's languages and tools by scanning for:

Based on what it finds, mkenv installs the appropriate language runtimes, package managers, and language servers.

Security Defaults

Caching

mkenv caches dependencies using Docker volumes. First run builds everything, subsequent runs are fast. Rebuilds only happen when dependency files change.

Security Warnings

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.

Accessing Your Dev Server

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.

How Port Forwarding Works

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.

Architecture


┌──────────────────┐
│ 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.

How Traffic Flows

Key Points

Policies & Guardrails

mkenv 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.

Security Scanning

Secret Detection:

Restricted Directories:

Policy Configuration

Create 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": []
  }
}

Policy Fields

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)

Policy File Security

Important: Policy files must have 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

Reverse Proxy Security

mkenv allows containers to access host services (like databases) via a reverse proxy. The policy engine strictly controls which ports can be accessed.

Hardcoded Denied Ports (Always Blocked)

The following ports are permanently blocked and cannot be overridden by policy configuration:

Custom Port Policies

{
  "reverse_proxy": {
    "denied_ports": [5432, 3306],
    "allowed_ports": [8000, 8080]
  }
}

Policy Enforcement

Tool Control (Bricks)

Policies can control which tools (called "bricks") are available:

{
  "disabled_bricks": ["claude-code", "codex"],
  "enabled_bricks": ["nvim", "tmux", "pulumi"]
}

Use Cases:

Volume Mount Restrictions

{
  "allowed_mount_paths": [
    "/home/user/projects",
    "/data/shared"
  ]
}

Project Path Restrictions

{
  "allowed_project_path": "/home/user/approved-projects"
}

Example: Enterprise Policy

{
  "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:

Example: Developer-Friendly Policy

{
  "disabled_bricks": [],
  "enabled_bricks": ["claude-code", "nvim", "tmux"],
  "reverse_proxy": {
    "denied_ports": [],
    "allowed_ports": []
  }
}

This policy:

FAQ

Can I use this on Linux or Windows?

Not officially yet. Linux support is near-term; Windows likely rides on WSL once the experience doesn't suck.

Does mkenv replace Docker Desktop?

No, it depends on Docker for virtualization. Think of mkenv as the paranoid orchestrator on top.

Where is the cache stored?

In Docker volumes managed by mkenv. Use mkenv list --verbose to inspect cache details.

What happens if the container dies?

Run mkenv . again. You'll either reattach or get a fresh container using existing caches.

Is this meant for production workloads?

No. It's a dev tool for local workstations, not a deployment platform. If you push it to prod, that's on you.

Can I keep my editor outside the container?

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.

Is there telemetry?

No analytics pings. If something breaks, file an issue rather than letting logs spy on you.

How do I git push?

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.

How do I install packages that need sudo?

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.

What if auto-detection gets my project wrong?

Guide it with CLI options (--langs, --tools), a .mkenv file, or adjust ad-hoc with mkenv sandbox install.

IDE integration?

VS Code and Cursor can connect to mkenv containers using their remote development features. Dedicated plugins coming soon.