Dev Environments, Contained
Isolated, reproducible development sandboxes and a secure package manager that give your whole team identical environments, while keeping AI agents off the laptop.
Documentation · Getting Started · Loadouts · Architecture · Discussions
Minimal is a declarative, content-addressed build system and development-environment manager. It repeatably builds Linux, terminal-based development sandboxes, each populated with exactly the toolsets and agents a project needs, all declared in a single minimal.toml blueprint. A sandbox runs natively on Linux via unprivileged user namespaces and inside a lightweight libkrun microVM on macOS, so the same environment travels across your team's machines. Commit that blueprint to your repository and every teammate gets an identical environment, one that keeps AI agents sealed inside the sandbox and off the host laptop.
The executables inside a sandbox (git, claude-code, compilers, shells, and more) are delivered by Minimal's secure package manager from a curated registry that is refreshed daily. Because packages are addressed by content rather than mutable version tags and builds are hermetic, the same blueprint resolves to the same environment on every machine. Moving the whole team to the freshest tool versions is one min update, which re-pins the blueprint in place. No more stale setup wikis, no more version drift.
Per-developer Loadouts then layer each person's own editors, terminal multiplexers, and configs on top of that shared toolchain, so the environment stays identical for everyone while you keep the muscle memory you have earned.
Full documentation lives at docs.minimal.dev.
Minimal works on:
- macOS on ARM64 (Apple Silicon)
- Ubuntu and Debian Linux on ARM64 and x86_64, with a Linux kernel >= 5.10. Rootless user-namespace creation must be enabled for non-VM usage.
Not on one of these platforms yet? Tell us what you'd like to see supported in Discussions. It helps us prioritize.
To get started, install Minimal with the following shell command:
curl --proto "=https" --tlsv1.2 -fsSL 'https://go.minimal.dev/' | shThis installs the stable channel of Minimal, adds min to your PATH, and sets up shell completions for bash, fish, and zsh.
Minimal can be uninstalled with:
curl --proto "=https" --tlsv1.2 -fsSL 'https://go.minimal.dev/' | sh -s -- --uninstallThe examples below walk through the two most common workflows: starting a brand-new project inside a sandbox, and joining an existing project that already has a minimal.toml.
In this example we'll create a new git repo from within a Minimal sandbox, using tools from the Minimal Public Registry. The workflow keeps the agent credential-free: it uses a fine-grained GitHub personal access token (PAT) stored in the macOS keychain, revealed to the sandbox only after the agent has exited.
First create the new, empty GitHub repo, then create a fine-grained PAT scoped to it at https://github.com/settings/personal-access-tokens. Store the PAT in your keychain with security add-generic-password -s "PAT-foo-repo" -a "my-mac-user-name" -w.
The following shows how to populate that repo from within a sandbox:
mkdir -p ~/projects/foo
cd ~/projects/foo
# create and update a minimal.toml file
min init
min add --session git gh claude-code mermaid-cli kittyview less emacs
# copy the GitHub PAT to your clipboard from your macOS keychain
security find-generic-password -w -s "PAT-foo-repo" -a "my-mac-user-name" | pbcopy
# start and enter a sandbox; the current directory's file tree is copied in
min session activate --attach .
git init
# develop specs, generate code, etc. — skipping permission prompts is
# reasonable here: the agent is sealed in the sandbox with no credentials;
# agents can add build/runtime dependencies from the registry with "min add"
claude --dangerously-skip-permissions
# review the generated code before committing
git add -A
git commit -m "initial commit"
# add the GitHub credential now that the AI agent has exited
read -sp "paste GitHub PAT now: " GH_TOKEN && export GH_TOKEN
# push to github
git remote add origin https://github.com/<your-owner>/<your-repo>.git
git branch -M main
git push -u origin main
exitIn this example we'll work on an existing git repo that already has a minimal.toml, reusing the keychain-stored GitHub PAT from the previous example so Claude can pull the repo and open a PR.
cd ~/projects/foo
# get the latest files on the current branch; we need the minimal.toml
git pull
# copy the GitHub PAT to your clipboard from your macOS keychain
security find-generic-password -w -s "PAT-foo-repo" -a "my-mac-user-name" | pbcopy
# don't copy any files up; we'll git pull inside the sandbox
min session activate --attach --sync none .
# note: the exported GH_TOKEN is visible to Claude in this session
read -sp "paste GitHub PAT now: " GH_TOKEN && export GH_TOKEN
# tell claude to pull https://github.com/<your-owner>/<your-repo>.git
# then add new features, fix bugs, etc.
# then ask claude to create a PR
claude
exitThe project's minimal.toml describes what every contributor's session
needs; a loadout carries what you want on top: your editor, terminal
multiplexer, shell config, and dotfiles. Loadouts are single TOML files under
~/.config/minimal/loadouts/:
# ~/.config/minimal/loadouts/dev.toml
name = "dev"
description = "helix + zellij with my dotfiles"
packages = ["helix", "zellij"]
patches = [
# Helix: single config files plus a themes directory.
{ dest = ".config/helix/config.toml", source = "~/dotfiles/helix/config.toml" },
{ dest = ".config/helix/languages.toml", source = "~/dotfiles/helix/languages.toml" },
{ dest = ".config/helix/themes/", source = "~/dotfiles/helix/themes/**/*.toml" },
# Zellij: single config file plus a layouts directory.
{ dest = ".config/zellij/config.kdl", source = "~/dotfiles/zellij/config.kdl" },
{ dest = ".config/zellij/layouts/", source = "~/dotfiles/zellij/layouts/**/*.kdl" },
]
[vars]
EDITOR = "hx"
VISUAL = "hx"
# Declared to warm helix's tree-sitter grammar cache when the session
# comes up. Best-effort; failures don't tank activation.
[[lifecycle_hooks]]
on_activate = { type = "inline", value = "hx --grammar fetch >/dev/null 2>&1 || true" }Apply one with min session activate --loadout dev --attach ., or list it in
default_loadouts under [loadouts] in ~/.config/minimal/config.toml to have it join every
session automatically. min loadout list shows what's available. The full
schema (file patches, lifecycle hooks, environment-variable inheritance,
composition rules) is in the
loadouts reference.
Sandboxes: a pure Rust client, daemon, and VM manager. The sandbox VM is powered by libkrun, a custom Linux kernel image, and an Alpine Linux rootfs.
Packages: glibc-based packages built frequently on Minimal's build servers from their canonical sources (GNU, GitHub, GitLab, etc.).
- Architecture overview: how the crates fit together
- CLI reference: every
mincommand minimal.tomlreference: the project blueprint format- Linux host setup: kernel and namespace requirements
- More guides live in docs/
Minimal is a Cargo workspace, and the just recipes are the easiest way to
build and test it: they apply the correct per-OS scope for you. That matters
most on macOS, where the full workspace does not build yet (minimald's
sandbox stack is Linux-only), so the recipes scope to what does.
just ci # the full pre-PR gate: fmt, clippy, cargo-deny, tests, doctests
just test # run the test suite
just clippy # lintjust --list shows every recipe (builds, VM bring-up, e2e, and more). On
Linux you can also drive Cargo directly against the whole workspace
(cargo build, cargo test); on macOS prefer the recipes so you never have
to scope crates by hand. Binaries land at
target/debug/{min,mip,minimald,minvmd} (or target/release/). Building the
entire package registry is heavy: 8 cores and at least 16 GB of RAM are
recommended. See AGENTS.md for the platform
matrix.
Sessions run in an unprivileged user namespace, which Ubuntu 24.04 blocks by
default (kernel.apparmor_restrict_unprivileged_userns=1), so every session dies
at uid_map with Operation not permitted. Install the AppArmor profile that
grants minimald the userns permission:
$> sudo scripts/install-apparmor-profile.sh # installed binary
$> sudo scripts/install-apparmor-profile.sh --path "$PWD/target/debug/minimald" # dev buildInstalled via curl … | sh instead of a checkout? The installer ships this
loader and prints a hint when the host needs it; run
sudo bash ~/.local/share/minimal/apparmor/install-apparmor-profile.sh.
See docs/reference/linux-host-setup.md.
We'd love your help, and you don't need to be a Rust expert to pitch in: bug reports, docs fixes, and feature ideas are all valued contributions. Please open an Issue (or start a Discussion if it's large in scope) to outline the improvements you're seeking.
If you want to contribute code, docs, etc., please head over to CONTRIBUTING.md for the development workflow and what we look for in a contribution.
Before we can merge your first pull request, you'll need to accept our Individual Contributor License Agreement (ICLA). This is a one-time, ~30 second step: CLA Assistant will post a link on your PR, you click through, sign in with GitHub, and you're done. You're then covered for all future contributions to this repository.
If you're contributing on your employer's time, or with code your employer might own, your employer will also need a Corporate CLA (CCLA) on file listing you as an authorized contributor. See CONTRIBUTING.md for details, or email security@minimal.dev if you need help getting one set up.
We want everyone to feel welcome here, whatever your background or experience level. This project follows the Contributor Covenant; by participating (contributing code, filing issues, or joining discussions) you agree to uphold it.
If you believe you've found a security vulnerability, please email security@minimal.dev instead of opening a public issue. We appreciate responsible disclosure and will get back to you quickly.
This project is licensed under the Apache License Version 2.0. See the LICENSE file for details.
