macpack is a universal macOS package manager CLI. It syncs one manifest across Homebrew, Mac App Store apps, npm/Volta tools, pnpm tools, bun tools, uv Python tools, and git repositories.
It is designed for personal machine bootstrap and repeatable workstation setup.
- One line-oriented manifest for
tap,brew,cask,mas,npm,pnpm,bun,uv, andrepo. - Default manifest lookup:
./packages.macpackfirst, then~/.config/macpack/packages.macpack. addandremovecommands for editing manifest entries.upgradecommand with interactive package selection or--all.- Interactive
setupcommand built with@clack/prompts. - macOS-only guard for mutating commands.
- Homebrew tap trust prompts before installing from non-official taps.
- Manifest-scoped apply behavior: macpack installs entries named in the file instead of running broad global upgrades.
- Cleanup mode removes installed global packages/tools that are no longer in the manifest.
- Collapsed apply logs: successful command output is hidden, warnings stay
visible, and failures print full command output. Use
--verboseto stream all output. - Build output is a normal Node executable with a
binentry for future npm and Homebrew distribution.
git clone https://github.com/sk2andy/macpack.git
cd macpack
npm install
npm run build
node dist/index.js --helpbrew tap sk2andy/tap
brew install macpackOr install directly:
brew install sk2andy/tap/macpackThe Homebrew formula installs the v0.2 macOS Apple Silicon executable from
the GitHub release.
For local development:
npm run dev -- --help
npm run dev -- check --file examples/packages.macpackOn macOS Apple Silicon with Node.js 26:
npm run build:executable
./build/release/macpack --helpThe executable is built with Node's Single Executable Application support. It is
written to build/release/macpack; build/ and dist/ are ignored and not
committed.
macpack uses a small, shell-like DSL. It is parsed by macpack and not executed as a shell script.
tap "azure/functions"
brew "uv"
cask "postman"
mas "Keynote" "409183694"
npm "tsx"
pnpm "serve"
bun "@johnlindquist/worktree"
uv "3.14" "serena-agent"
repo "https://github.com/sk2andy/macpack.git" "~/workspace/macpack"Comments are supported:
# Homebrew CLI tools
brew "gh"
brew "fzf"Versioned specs are passed through to the underlying manager where that manager supports them:
npm "typescript@5.9.3"
pnpm "serve@14"
bun "prettier@3.7.4"
uv "3.14" "ruff==0.14.8"Every command that accepts --file can run without it. macpack resolves the
manifest in this order:
./packages.macpackin the current directory, if it exists.~/.config/macpack/packages.macpack.
macpack setup asks whether it should create the config default when it is
missing. It then always asks whether to scan currently installed packages and
whether to scan home-folder git repositories for the global manifest. Commands
can force the global config manifest with --global. macpack add --global
creates that file if it does not exist. Without --file or --global, add
uses the default lookup and creates ./packages.macpack with a log message if
neither default exists.
Common shortcuts:
-f, --file <path>-g, --global-n, --dry-run-v, --verbose-y, --yes-a, --allforupgrade-p, --python <version>foradd uv-i, --id <app-id>foradd mas--deleteforremove repo
Interactive bootstrap for a new Mac:
macpack setupThe setup flow:
- Checks that macpack runs on macOS.
- Installs Homebrew if missing.
- If Node.js is missing, asks for one of:
- Volta (recommended)
- Homebrew Node
- nvm
- skip
- Asks whether bun should be installed and from which source:
- official bun installer
- Homebrew
- skip
- If Python 3 is missing, asks for a default version and install source:
- uv-managed Python (recommended, default
3.14) - pyenv
- Homebrew Python
- skip
- uv-managed Python (recommended, default
- Installs uv if missing.
- Asks whether
~/.config/macpack/packages.macpackshould be created if missing. - Asks whether currently installed packages should be scanned.
- Asks whether the home folder should be scanned for git repositories.
Package scans collect:
- Homebrew taps, formula leaves, and casks
- Mac App Store apps from
mas list - npm globals and Volta packages
- pnpm globals
- bun globals from
~/.bun/install/global/package.json - uv tools from
uv tool list - git repositories under the home folder when enabled, skipping
worktree-directories,worktrees, git worktree roots, and common cache/media folders
uv tool list does not expose the Python version used for each tool, so setup
asks for a Python version and writes that value for discovered uv tools.
Scan results are merged into the global manifest and deduped, preserving
existing manual entries.
Install or update packages in the manifest:
macpack apply --file examples/packages.macpack
macpack applyRepository entries are cloned when their target directory is missing. Existing repositories are left in place; if the target exists with a different origin, apply fails instead of overwriting it.
Remove packages that are installed but no longer listed:
macpack apply --file examples/packages.macpack --cleanupPreview commands without making changes:
macpack apply -f examples/packages.macpack -nStream full command output instead of collapsed step logs:
macpack apply -vAdd entries to a manifest:
macpack add brew gh
macpack add cask postman
macpack add npm typescript@5.9.3 tsx
macpack add pnpm serve
macpack add bun @johnlindquist/worktree
macpack add uv -p 3.14 serena-agent
macpack add mas -i 409183694 Keynote
macpack add repo https://github.com/sk2andy/macpack.git ~/workspace/macpackUse --file <path> to edit a specific manifest. Without --file, macpack uses
the default manifest lookup. If neither default exists, add creates
./packages.macpack and logs that path.
Use --global to edit ~/.config/macpack/packages.macpack directly:
macpack add -g brew ghRemove entries from a manifest:
macpack remove brew gh
macpack remove npm tsx
macpack remove uv serena-agent
macpack remove mas 409183694
macpack remove repo ~/workspace/macpack
macpack remove repo ~/workspace/macpack --deleteThis edits the file only. Run macpack apply --cleanup or macpack cleanup to
remove installed packages no longer listed. Repositories are never removed by
apply --cleanup or cleanup; only remove repo --delete deletes a repo
folder.
Print manifest entries:
macpack list
macpack ls -g
macpack list --only-brewlist supports the same default lookup, -f/--file, -g/--global, and
--only-* filters as export.
Open the manifest in your editor:
macpack edit
macpack edit -g
macpack edit -f examples/packages.macpackedit uses $VISUAL, then $EDITOR, then macOS open -t. If no manifest
exists, it creates ./packages.macpack; with -g, it creates the global config
manifest.
Find newer versions for entries in the manifest and select what to install:
macpack upgrade
macpack upgrade brew
macpack upgrade npm
macpack upgrade uvUpgrade/install everything in the selected scope without prompts:
macpack upgrade -a
macpack upgrade bun -aWith --all, macpack applies the matching manifest section directly, so missing
entries are installed and installed entries are refreshed to the newest version
allowed by their manifest spec.
Use --verbose to stream package-manager output instead of collapsing
successful steps.
Only remove extras not present in the manifest:
macpack cleanup --file examples/packages.macpack
macpack cleanupUse --verbose to stream cleanup command output.
Export the manifest, or selected managers, into another format:
macpack export --file examples/packages.macpack
macpack export
macpack export --file examples/packages.macpack --only-brew --brewfile
macpack export --file examples/packages.macpack --package-json
macpack export --file examples/packages.macpack --only-uv --requirements-txtFilters:
--only-brew--only-npm--only-pnpm--only-bun--only-uv--only-repos
Formats:
- default macpack manifest
--brewfile--package-json--requirements-txt
Parse the manifest and print counts:
macpack check --file examples/packages.macpack
macpack checkShow platform and package-manager availability:
macpack doctornpm install
npm run typecheck
npm test
npm run build
npm run build:executable
npm audit --audit-level=high
npm pack --dry-runReleases are built by GitHub Actions. Run the Release workflow manually and
provide a tag/version such as v0.2.
The workflow runs on GitHub's macos-26 arm64 runner, builds a darwin-arm64
executable, creates a source archive, creates checksums, and publishes a GitHub
Release with those assets.
src/
cli/ command definitions
config/ manifest parser, formatter, defaults, and mutations
core/ process execution, prompts, platform checks, shared types
installers/ one installer per package ecosystem
setup/ interactive bootstrap flow
upgrades/ outdated detection and upgrade selection
docs/ architecture, command, and feature notes
examples/ example macpack manifest
The npm package exposes:
{
"bin": {
"macpack": "./dist/index.js"
}
}prepack runs the build before packaging, so dist/index.js is included in the
published tarball.
MIT