Migrating from Homebrew Bundle to Jarvy¶
If your team has a Brewfile and you're already happy with it, the question is: do you have any non-macOS contributors? If yes, Jarvy gets you the same ergonomics on Linux and Windows from the same config file. If no, the migration is mostly about the extras Jarvy adds — drift detection, hooks, roles.
This guide assumes you have a working Brewfile. By the end you'll have a jarvy.toml that does everything your Brewfile did, plus.
At a glance¶
| Brewfile concept | jarvy.toml equivalent |
|---|---|
brew "node" |
node = "20" (or "latest") under [provisioner] |
brew "node@20" |
node = "20" |
cask "docker" |
docker = "latest" (Jarvy picks cask automatically when needed) |
tap "homebrew/cask-fonts" |
Not needed — Jarvy resolves the right install path. Custom taps still work via custom_install. |
mas "Xcode", id: 497799835 |
Not currently supported — keep mas separately. |
brew "..." link: false |
Use [provisioner] detail form with platform-specific overrides. |
Step 1: list what's in your Brewfile¶
Categorize:
- CLI tools →
[provisioner] - GUI apps (casks) →
[provisioner](Jarvy auto-detects) - Mac App Store (
mas) → keep inBrewfile, run separately - Custom taps → check if the tool is already in Jarvy's registry; most popular formulae are.
Step 2: write the equivalent jarvy.toml¶
A typical Brewfile:
brew "git"
brew "node@20"
brew "[email protected]"
brew "docker"
cask "visual-studio-code"
cask "iterm2"
Becomes:
[provisioner]
git = "latest"
node = "20"
python = "3.12"
docker = "latest"
vscode = "latest"
iterm2 = "latest"
Run jarvy validate to catch any tools the registry doesn't know about. For unknown ones, you have three options:
- Check
jarvy search <name>for the right canonical name - Open a PR adding it — see Adding tools
- Use a
pre_setuphook to shell out tobrew install ...for that single tool
Step 3: replicate side effects with hooks¶
Brewfile's brew "..." is install-only. If your team also runs brew bundle dump --force or has a wrapper script that does post-install setup, move that logic into hooks:
Step 4: cross-platform check (the payoff)¶
Have a Linux teammate (Ubuntu, Fedora, Arch) or Windows teammate clone the repo and run jarvy setup. Tools that are macOS-only in your Brewfile (some casks) will fail validation early — drop them or guard with platform-conditional roles.
Then on macOS: jarvy setup --role macos-extras. On Linux/Windows, default to base.
Step 5: commit a baseline¶
jarvy setup
jarvy drift accept
git add jarvy.toml .jarvy/state.json
git commit -m "chore: migrate from Brewfile to jarvy.toml"
You can keep the Brewfile around during the transition, or delete it once the team is on Jarvy.
What you gain¶
- Cross-platform — same config works on macOS, Linux (apt/dnf/pacman/apk), Windows (winget/Chocolatey)
- Version requirements —
^,~,>=operators instead ofnode@20only - Drift detection — know when a teammate's brew is on a different version
- Hooks — post-install configuration declared in the same file
- Roles — split the toolchain by job
- Templates — start a new project from 14 examples
- AI agents — Jarvy ships an MCP server; Brewfile doesn't
What you give up¶
- Mac App Store apps via
mas— keep that separate, or skip it - Brewfile's tight coupling to Homebrew internals — Jarvy abstracts the package manager, which is usually a feature but occasionally not
- Your existing muscle memory of
brew bundle— you'll be runningjarvy setupinstead
Migrate with AI¶
Paste this into Claude, ChatGPT, Cursor, or any LLM. Drop your Brewfile between the <<< and >>> markers.
You are a config translator. Convert the Homebrew Bundle Brewfile below into
a valid jarvy.toml file.
# Schema (jarvy.toml)
- Required: [provisioner] — table of registered tool names mapped to versions.
- Versions: "latest", "20", "^3.10", "~3.12", "=20.11.0".
- Detailed: tool = { version = "20", version_manager = true }
- Optional: [npm] [pip] [cargo] [hooks] [env.vars] [env.secrets]
[git] [network] [drift] [services] [telemetry] [commands]
# Tool-name canonicalization (CRITICAL — Brewfile names often differ)
- node@20 → node = "20"
- node@18 → node = "18"
- [email protected] → python = "3.12"
- [email protected] → python = "3.11"
- aws-cli → awscli
- azure-cli → azure_cli
- postgresql / postgresql@15 → psql = "latest" (Jarvy registers psql, not server)
- visual-studio-code → vscode
- iterm2 → iterm2 (cask, but registered)
- nodejs → node, python3 → python, golang → go
# What does NOT translate
- tap "user/repo" → not needed; if a tool isn't registered, flag with a comment
- mas "..." (Mac App Store) → not supported by Jarvy; keep mas separately
- brew "x" link: false / args: [...] → translate to [provisioner] detailed form
with comments noting the dropped flags
# Per-source rules
- brew "X" or brew "X@Y" → X = "latest" or X = "Y" under [provisioner]
- cask "X" → X = "latest" under [provisioner] (Jarvy auto-detects cask vs formula)
- If a brew name isn't in the canonicalization list and you're unsure whether
it's registered, use the brew name verbatim and add a TOML comment:
# TODO: verify "<name>" is registered (jarvy search <name>)
# Output contract
- Output ONLY the jarvy.toml content. No prose, no fence.
# INPUT
<<<
[paste your Brewfile here]
>>>
After the model responds, run jarvy validate (it will tell you which tool names need correction).
See also¶
- vs Homebrew Bundle — feature comparison table
- Configuration reference
- Tutorial: onboard a team