Your shell config is your identity. Every new machine is just a new body.
MOLT is a cross-platform, multi-machine personal shell environment tool. It takes your zsh/bash config, dotfiles, and dev environment setup and makes them portable, reproducible, and bootstrappable from a single command on a fresh machine.
Think of it as what Omarchy does for Linux desktop config, but for shell and dev environments across macOS and Linux.
"Molt" is the biological process of shedding an exoskeleton to grow a new one. The backronym is My Opinionated Local Terminal. Both readings work: you shed the default shell and replace it with yours.
MOLT separates the framework from your personal config:
| Repo | What it contains | Shared? |
|---|---|---|
| molt (this repo) | Framework: CLI, core libs, liberator runner, tests | Yes — the engine |
molt-{user} (eg molt-matts) |
Your config files, dotfiles, manifest, per-instance overrides | No — your soul |
The framework finds your personal repo by searching for molt-$(whoami) in $MOLT_PRJ_DIR, ~/, and ~/.. Your personal repo contains a config/ directory with dotfiles and a molt.toml manifest declaring which liberators to run.
This separation means you can fork the framework independently from your config, and your config never contains framework code.
Set MOLT_PRJ_DIR to the directory where your repos live. There is no default — every machine chooses its own layout:
export MOLT_PRJ_DIR="$HOME/Projects" # or wherever you keep repos# Framework
git clone https://github.com/you/molt "$MOLT_PRJ_DIR/molt"
# Your config (contains molt.toml + config/ directory)
git clone https://github.com/you/molt-you "$MOLT_PRJ_DIR/molt-you"
# Add molt to PATH (or use the bootstrap script)
export PATH="$MOLT_PRJ_DIR/molt/bin:$PATH"
# Preview what would happen
molt resleeve --dry-run
# Bootstrap this machine
molt resleeveMOLT v0.1.0 — My Opinionated Local Terminal
Needlecasting stack to new sleeve...
Zen: Stack found: /home/you/Projects/molt-you
Zen: Loading liberators...
system: ✓ ok
zsh: ✓ installed
git: ✓ installed
...
Zen: Sleeve ready. Welcome back.
"Welcome back" is the key line. You are not setting up a new machine. You are waking up in a new body with all your memories intact.
For a fresh machine where nothing is set up yet:
MOLT_PRJ_DIR=$HOME/Projects bash <(curl -fsSL https://raw.githubusercontent.com/you/molt/main/bin/bootstrap.sh)The bootstrap script clones both repos, links molt into ~/bin, shows a dry-run, and prompts before applying.
In Molt, your config is your cortical stack, your consciousness. Every machine is just a sleeve it gets loaded into.
| Term | What it means |
|---|---|
| stack | Your dotfiles and config bundle. The portable identity. |
| sleeve | A target machine that receives your stack. |
| needlecast | Push your stack to a remote machine. |
| resleeve | Bootstrap a fresh machine from your stack. |
| backup | Snapshot your current stack state. |
| zen | The bootstrap runner on each machine. Executes commands, reports status. |
| liberators | Config modules. Each one frees you from a default. |
| molt.toml | The manifest file. The authoritative source of truth for what your stack contains. |
molt resleeve # Bootstrap the current machine from your stack
molt resleeve --dry-run # Preview what resleeve would do, without changing anything
molt upgrade # Pull latest framework + config, run upgrade hooks, resleeve
molt upgrade --self # Pull framework + config repos only (no hooks, no resleeve)
molt upgrade --dry-run # Preview what upgrade would do
molt upgrade zsh,git # Run upgrade hooks for specific liberators only
molt upgrade --no-resleeve # Upgrade without resleeve
molt maintain # Run system maintenance (brew upgrade, doom upgrade, etc.)
molt maintain --dry-run # Preview maintenance actions
molt maintain brew # Maintain specific liberators only
molt status # Show sleeve state and liberator status
molt list # List liberators with enabled/installed status
molt doctor # System diagnostics and health checks (9 checks)
molt test [liberator] # Run bats test suite (all or one liberator)
molt version # Show version
molt help # Show helpThe only required setting. Tells molt where to find repos. Set it in your shell config (eg .zshenv):
export MOLT_PRJ_DIR="$HOME/Devel/prj"If unset, molt will search ~/molt-{user} and ~/.molt-{user} as fallbacks, but the primary lookup via MOLT_PRJ_DIR is the intended path.
| Variable | Purpose | Default |
|---|---|---|
MOLT_PRJ_DIR |
Where repos live | (none — must be set) |
MOLT_OPT_DIR |
Where opt-style installs live | $(dirname "$MOLT_PRJ_DIR")/opt |
MOLT_LOCAL_BIN |
Where to symlink executables | ~/bin |
UTILZ_HOME |
Override Utilz repo location | $MOLT_PRJ_DIR/Utilz |
INTENT_HOME |
Override Intent repo location | $MOLT_PRJ_DIR/Intent |
A liberator is a config module that frees you from one default. Each liberator implements a lifecycle of functions:
{name}_check— Is this component already installed and configured?{name}_install— Configure it (verify prerequisites, link config, set up).{name}_upgrade— (optional) Config sync hook. Fast, safe, runs duringmolt upgrade.{name}_maintain— (optional) System maintenance hook. Slow, runs duringmolt maintain.{name}_verify— (optional) Final verification.
Liberators never install packages. They check for prerequisites and fail with a hint if something is missing. You install packages yourself; liberators handle configuration.
The framework discovers liberator scripts in liberators/, loads them on demand, and runs them through the lifecycle automatically.
| Liberator | Concern | OS |
|---|---|---|
| system | Verify sudo (linux) or brew (macos) | linux, macos |
| local-bin | ~/bin directory, molt CLI symlink |
linux, macos |
| zsh | Shell default, Starship prompt, config linking | linux, macos |
| git | Git + git-lfs verification, gitconfig linking | linux, macos |
| tmux | Tmux verification, config linking | linux, macos |
| editors | Doom Emacs + LazyVim, config linking, dock pin | linux, macos |
| alacritty | Alacritty config linking, dock pin | linux, macos |
| gnome-terminal | GNOME Terminal profile via dconf | linux |
| iterm2 | iTerm2 dynamic profile linking | macos |
| terminal-app | Terminal.app profile import | macos |
| keys | keyd build from source, key remapping | linux |
| desktop | GNOME settings, GTK config, accessibility | linux |
| tiling | Tactile GNOME extension grid tiling | linux |
| vscode | VS Code settings linking, CLI setup, dock pin | linux, macos |
| dev-tools | CLI tools (bat, rg, fd, fzf) + mise | linux, macos |
| ssh | SSH key detection, config rendering + fragments | linux, macos |
| utilz | Utilz framework, bats-core, ~/bin symlinks |
linux, macos |
| brew | Homebrew maintenance and upgrade | macos |
| intent | Intent framework config and linking | linux, macos |
| pplr | Pplr framework config and linking | linux, macos |
| web | Web browser config and linking | linux, macos |
The manifest lives in your personal config repo. It declares which liberators to run and on which platforms:
[stack]
name = "my-stack"
version = "0.1.0"
user_repo = "molt-matts"
[sleeve]
hostname = "mymachine"
projects_dir = "~/Projects"
[[liberator]]
name = "zsh"
enabled = true
os = ["linux", "macos"]
depends = ["system"]
[[liberator]]
name = "keys"
enabled = false # disabled — toggle when ready
os = ["linux"]Instance-specific manifests can override the repo-level one. MOLT checks instances/{hostname}/molt.toml first, then falls back to the repo root.
molt-{user}/
config/
zsh/zshrc # -> ~/.zshrc
zsh/zshenv # -> ~/.zshenv
git/gitconfig # -> ~/.gitconfig
tmux/tmux.conf # -> ~/.tmux.conf
doom/ # -> ~/.config/doom
alacritty/alacritty.toml # -> ~/.config/alacritty/alacritty.toml
starship/starship.toml # -> ~/.config/starship.toml
ssh/config.tmpl # -> ~/.ssh/config (rendered via envsubst)
instances/
kovacs/ # Per-machine overrides
molt.toml # Instance manifest
vars.sh # Template variables (MOLT_PRJ_DIR, etc)
ssh/config.d/ # Instance-specific SSH config fragments
keyd/default.conf # Machine-specific keyd config
rhadamanth/
molt.toml
vars.sh
Liberators use molt_link to symlink config files from your repo into their expected locations. Existing files are backed up automatically. Template files (.tmpl) are rendered via envsubst using instance-specific variables.
MOLT has opinions and says so. The tone is dry, terse, and functional. Output during a resleeve feels like waking up, not like installing software.
- macOS (Apple Silicon and Intel)
- Linux (Debian/Ubuntu, Fedora/RHEL, Arch)
- WSL2
molt/
bin/
molt # CLI entry point (thin coordinator)
bootstrap.sh # One-liner bootstrap for fresh machines
lib/
constants.sh # All configurable paths and defaults (single source of truth)
molt.sh # Core: logging, platform detection, symlinks, manifest parsing
liberator.sh # Liberator loading, execution, and discovery
liberators/
system.sh # Base system verification
zsh.sh # Shell + Starship prompt
git.sh # Git + git-lfs
tmux.sh # Tmux
editors.sh # Doom Emacs + LazyVim
alacritty.sh # Alacritty
gnome-terminal.sh # GNOME Terminal
iterm2.sh # iTerm2
terminal-app.sh # Terminal.app
keys.sh # keyd
desktop.sh # GNOME settings
tiling.sh # Tactile grid tiling
vscode.sh # VS Code
dev-tools.sh # CLI tools + mise
ssh.sh # SSH
local-bin.sh # ~/bin setup
utilz.sh # Utilz framework
test/
test_helper.bash # Shared test infrastructure (HOME-sandboxed)
molt.bats # CLI tests
constants.bats # Constants tests
liberator.bats # Framework tests
manifest.bats # Manifest parsing tests
templates.bats # Template rendering tests
liberators/
zsh.bats # Exemplar liberator test
MOLT is PATH-based, not package-manager-bound. It depends on standard POSIX tools plus:
- bash 4+ (framework scripts)
- awk (manifest parsing)
- bats (test suite — optional, for
molt test)
Liberators verify their own prerequisites and fail with install hints if anything is missing.
- Getting Started — first-time setup walkthrough
- Writing a Liberator — how to create your own config modules
- Template System — per-instance config rendering with
envsubst - Bootstrap Runbook — detailed manual setup reference
Early development. Three sleeves operational: kovacs (Ubuntu 24.04 ARM64), rhadamanth (macOS M4), and gyges (macOS).
MIT