4/22/2025 at 7:18:18 PM
Hey, so I built this thing, most of it at so far at least. And yeah, right now it isn't doing many things better than Homebrew.Setting of relative paths for bottle installs is still not perfect, well it works for every bottle I have tested except rust. Getting bottles working 100% is very doable though imo.
Build from source formulae is still pretty f*ed + I do not know if it is really feasible given that the json API lacks information there and a full on Ruby -> Rust transpiler is way out of scope. Will probably settle for automatic build system detection based on archive structure there. + Maybe do my own version of the .rb scripts but in a more general machine readable format, not .rs lol
Casks seem to work but I have only tested some .dmg -> .app ones and .pkg installers so far though. As with bottles 100% doable.
Given that almost all formulae are available as bottles for modern ARM mac this could become a fully featured package manager. Actually didn't think so many people would look at it, started building it for myself because Homebrew just isn't cutting it for what I want.
Started working on a declarative package + system manager for mac because I feel ansible is overkill for one machine and not really made for that and nix-darwin worms itself into the system so deep. Wrapping Brew commands was abysmally slow though so I started working on this and by now I am deep enough in I won't stop xD
Anyway I am grateful for every bug report, Issue and well meaning pull request.
by alexykn
4/23/2025 at 2:32:24 AM
This is awesome!Is there uv support?[0]
One of my biggest gripes about brew is how they manage dependencies. The devs have a conflicting philosophy that creates bloat. Package maintainers must define settings, settings should always use the latest Python version. It makes no sense. Maintainers won't update unless things break so you got a bunch of Python versions running around. And it won't use system Python!
Uv seems to provide an elegant solution for this. You can build a venv for each package and rust version will only have the specified deps. Since uv finds all your Python instances (and packages) and soft links them you have way less bloat and venvs become really useful. You can also use run and other tools to handle executables
Plus is also rust so good synergy ;)
by godelski
4/23/2025 at 5:17:34 AM
You should only be using Homebrew for installing software that happens to be written in Python, not dependencies for your own Python projects. If you do that, the Python version does not matter, it's just whatever version is required to make the package work.by Kwpolska
4/23/2025 at 9:28:03 AM
> not dependencies for your own Python projects
I'm not doing that. Honestly I'm not sure how to do that and it sounds like a real pain. > the Python version does not matter
This is incorrect. Go check what versions of Python brew has installed for you. It's definitely not your system version...It's not "what works" it is "what the maintainer specified". And according to the brew devs this is supposed to be /the latest version that works/. Which was my point. People don't update just on a Python change. That's not going to happen without automation. (I even suggested we be allowed to specify the minimum version and I was told it's maintainer's responsibilities). You can trivially find packages that can be used with newer versions of Python than their brew formulas specify.
by godelski
4/23/2025 at 2:00:55 PM
I don't follow the argument here:* One of the main reasons Homebrew doesn't use the "system" Python is because Apple has repeatedly indicated that they want to remove it, and that integrators should not depend on it. This, plus per-package Python version requirements makes using a single system Python a non-starter.
* The "bloat" you're noting in Homebrew around multiple Python interpreters is present in `uv` and `pyenv` as well: `uv` handles multiple interpreters transparently, so you may not even realize how many you have installed. I think this is a good pattern: disk space is cheap relative to the timesink of connecting the right Python version to the right set of packages, which is why every distribution scheme (including both Homebrew and Debian) prefers to distribute multiple Python versions.
by woodruffw
4/23/2025 at 6:15:38 PM
> because Apple has repeatedly indicated that they want to remove it
That's not a reason to not use it. There's absolutely zero reason for me to have two copies of an exact same Python version (e.g 3.11.4). There is rarely reason to have a differing subversions (3.11.3 vs 3.11.4). > is present in `uv`
Are you guessing or do you know? Try it out. Prove me wrong.I said they search for versions on your system and link if found. Seriously, look into it
> disk space is cheap
That's not correct. It's a thing you need to consider when you have to compromise but not an infinite resource. But there's something cheaper than storage: infrequently scanning the system!The problem is when everyone thinks this way then space is no longer cheap (especially with Apple!)
Tragedy of the commons
In fact it's a big reason I live in the terminal. Because even on a modern M2 air that bloat creeps in. My system is fast and snappy. I have plenty of storage. But this isn't true if I didn't. The creep still happens in these programs but their nature lessens the blows and the likelihood that people care about these things increases.
by godelski
4/26/2025 at 12:43:41 AM
Why should brew handle 3.11.3 differently from 3.11.4, just because you have another copy of it on your computer? What if apple patches it or updates the version suddenly?That kind of magical special case behavior is not intuitive and creates more problems than it is worth.
by ycombinatrix
4/23/2025 at 7:07:03 PM
> That's not a reason to not use it.It is, in fact, an excellent reason not to use it. Homebrew runs on tens of millions of machines; we are absolutely not going to rely on things that we're told not to rely on unless absolutely necessary. Python is readily buildable and we already need to build multiple versions for reasons aforementioned, so this condition does not apply.
Also note, it's stronger than what I originally said: 10.15 doesn't ship with Python by default at all anymore. I only have it installed (at 3.9.6) because I also have XCode installed. Homebrew supports being used without XCode or the CLT, so that alone would be a hard blocker for system Python for us.
> Are you guessing or do you know? Try it out. Prove me wrong.
My `uv python list` shows that I have 3 uv-managed versions of Python installed, along with 5 pyenv versions and 2 Homebrew versions. I have more than most people because I test large matrices of Python versions at once, but I imagine a normal Python developer isn't too far off.
You can test this for yourself with the same command. If you're developing more than one Python library or application at a time, I strongly suspect `uv` or `pyenv` is using more space for Python versions than Homebrew is.
by woodruffw
4/23/2025 at 10:50:15 PM
> an excellent reason not to use it
You're really missing my argument here. >> there's something cheaper than storage: infrequently scanning the system!
The solution already exists If required python version does not exist, download.
This is already being done. The missing part is the scanning of the system. I need to make this abundantly clear: You do not need to rely on Apple for this to be a solution. Furthermore, even if Apple completely removes python, making this change would still improve brew and reduce bloat. This is why I didn't care about that comment. Because it is inconsequential to what I'm suggesting. If they remove python you're in the exact same position as not having the right version of python. It is equivalent. I'm not sure why you're harping on this. > My `uv python list` shows
You're again missing the point. It isn't about having different versions, hell I got 3.13, 3.12, 3.11, 3.10, 3.9, and 3.8 on my system. The problem is having redundant copies of the minor (or even patch) versions. When I installed `uv` I uninstalled brew, purged everything, and reinstalled. This is because when I'm creating a new venv it isn't actually `uv` that is installing a new python version, it is linking one that was installed by brew. When I was using Anaconda, conda didn't search for existing versions (and packages), it just installed its own. You might be thinking this isn't a problem with brew and a problem with conda, but that's passing the buck. Brew is making the same error that conda was and thinking brew is better and that the solution should be fixed by others is just idiotic. Its blaming those downstream for a problem that's being created. If a "crime" is a "crime" then it doesn't matter who does it.We're getting off topic now, since this is besides the point. But hey, here's a few things that can help look at the system and what's happening.
On my system, brew installed 3.13, 3.12, and 3.11 (you can guess when I purged). For good measure, try this instead
brew list | xargs -P8 -n1 sh -c 'brew cat "${0}" | grep "depends_on \"python@3." | sed -e "s/.*\(python@3\.[0-9]*\).*/\1/g"' 2> /dev/null | sort -u
This will go through all your brew packages and find the python depends. My output shows 3.11 and 3.12. Interestingly, no python 3.13, though brew installed this. Interesting considering brew and brew-core don't have python code (according to github). Maybe something installed it and then I removed it. I'm unsure. But let's edit our command and check only those python@3.11 instances. brew list | xargs -P8 -n1 sh -c 'brew cat "${0}" | grep "depends_on \"python@3.11" &> /dev/null && echo "${0}"' 2> /dev/null
I checked the formulas on github, none of those even have python 3.11 anymore. These are cryptography, libxml2, numpy, py3parser, py3cairo, python-cryptography, pygobjects3, and python-packaging. With the exception of python-cryptography and python-packaging (no GitHub formula), the brew formula on GitHub depends on both 3.12 and 3.13 for every one of these. There is no dep for 3.11! Did a `brew update` and `brew upgrade` and they're still 3.11. But hey, now the first brew list command reports 3.11, 3.12, and 3.13. Doing `brew info python-cryptography` there's a green checkmark on `python@3.12` and `python@3.13` (`python@3.11` is not shown), while `python-setuptools` has a red x despite the fact that I have setuptools installed in both 3.13 and 3.12 in different uv environments (it also isn't finding rust). So it certainly isn't finding packages and trying to reduce redundancy which is the big problem `uv` tries to solve in the first place.
by godelski
4/23/2025 at 11:38:39 AM
My experience was actually the opposite -- a package I used broke because somebody did an automated "bump the python version this package uses" change without noticing that upstream for the package hadn't yet made a release with the necessary changes to make it work with that python version, so it fell over on startup. (They were quick with reverting it when I reported the problem.)by pm215
4/23/2025 at 5:22:26 PM
That happens too. But that's normal bugs.For the issue I'm talking about you have to look. It's a non breaking bug. So unless you look you likely won't see the problem.
That's two types of bugs: 1) Those that scream at you 2) Those that hide. We're talking about by later
by godelski
4/23/2025 at 7:44:36 AM
https://mise.jdx.dev/ supports uv through its pipx backend, and is a very good package/tool manager in general.by saint_yossarian
4/23/2025 at 9:28:40 AM
Thanks! I'll check it out!by godelski
4/23/2025 at 6:30:29 PM
love uv <3 I will look into integrating that. Have not decided if and how to implement my own packaging / source build dsl though and will probably open a git poll for that the coming daysby alexykn
4/23/2025 at 7:01:01 PM
Awesome! I look forward to see how this progresses! It'll be nice to have a package manager that supports true multithreading and is just overall a lot faster. There's a lot of things that are needed that brew simply just can't do.I haven't played around with this yet (will this weekend!) but I know brew is way too verbose and IO is a big slowdown. Probably doesn't matter because it is written in ruby. But it's an easy thing to miss and is quite common for people to not recognize this. Like when people use `tar xvf` instead of `tar xf`, there's a very noticeable speed difference for many packages lol. (Sorry if I'm preaching to the choir here. It's a pet peeve of mine given how common this is)
by godelski
4/22/2025 at 10:39:22 PM
You mentioned a declarative package manager for Mac. I've really liked using Homebrew Bundle [1] over the last couple years. It's about the level of declarative that I've wanted and has made it really easy to bootstrap new laptop or VM (since it also works on Linux). The format for a Brewfile was pretty easy to figure out.The way I ended up using it was that `brew install` would temporarily install something, without adding it to my Brewfile. And a little `brew add` wrapper would add the package to my Brewfile to keep it on the system permanently. That part with the wrapper could have used some love and would be a nice fit for a new brew-compatible frontend IMO. Maybe you could expand on that for Sapphire, if that also scratches your declarative itch?
by samhclark
4/23/2025 at 9:27:37 AM
That would be fantastic. My bootstrap scripts already use bundle but it’s easy to fall into config drift.by JimDabell
4/22/2025 at 7:20:02 PM
What makes you interested in a rust implementation of brew?I'm guessing it's that you hoping that it is eventually more performant -- are there specific areas of current brew you have identified as performance bottlenecks likely to eventually benefit from a rust implementation?
Or any more info to share about assumptions/hopes that motivated this or any other motivations?
by jrochkind1
4/22/2025 at 7:48:48 PM
Building from source, obviously, will never be really that much more performant as it mainly relies on the underlying build systems and things like ninja, cmake, cargo etc. are usually optimized very very well.Thanks to rust just being (slightly, significantly? no idea about ruby's speed) faster + concurrent downloading & pouring of bottles, most "regular" formula installs feel a good bit faster than brew already. Mainly noticeable when installing multiple formulae at once.
Casks, especially those with pkg installers, seem to profit a bit less here.
Performance was a reason, not the main one though, like I said I wanted and still want, to build a declarative package + system managing solution on top. The idea was to get into rust with that. Imo having the base written in the same language instead of wrapping commands also gives more flexibility there.
Another reason is that I never liked the way brew looks and feels. Right now the ui/ux for Sapphire is far from finished, more like a clusterf*k and only the search command really looks the way I want it. Aiming for something modern, clean and information rich without beeing overly verbose. I really like dnf5 and what AerynOS is doing and will probably take some inspiration there.
Like mentioned, Bottles and Casks should be 100% doable and that would cover most package needs on macOS, I do not see why I should also define a new repo and packaging ecosystem when such a big and popular one exists.
Source build capability will probably stay(for easy integration of source building in the system management part later) but not be focused on brew formulae as the ruby dsl would be a horror to parse.
Well and sh*t I am not trying to compete really. This is the first time building something with rust and I really really had no idea what a giant never ending rabbit hole macOS package management is and how massive and complex Brew is.
This went from should I to can I pretty quick for me xD
by alexykn
4/22/2025 at 8:32:42 PM
I would be interested to see more declarative package managers for macOS, I was looking for something similar just a few days ago.by mudkipdev
4/22/2025 at 7:38:45 PM
I say this from ignorance, but coming from a lineage of linux package managers; brew must be doing something wrong - and upon immediate introspection I doubt that its language specific.The performance of apt/dnf in comparison is surreal; but dnf (or at least yum, its predecessor) is written in Python; which has even worse performance characteristics than Ruby.
Clearly something is wrong, I wonder how different they are architecturally.
by dijit
4/22/2025 at 7:42:20 PM
Have you tried Homebrew in the last year or so? I think a lot of people have an impression of Homebrew's performance from the "bad old days," i.e. back when Homebrew had to evaluate every single local formula file to perform any operations at all.(There's still low handing fruit, but it's not like it was a few years ago where `brew list` took seconds to run. It now runs nearly instantaneously for me locally, like most of the other happy path commands.)
by woodruffw
4/22/2025 at 9:03:55 PM
Yes, I use it on my daily driver, and it's at least two-orders of magnitude slower than apt.However, the speed increase coincided with my upgrade to an M-Series laptop, so it's possible I just presumed there was a significant hardware speedup in the time we're talking about.
by dijit
4/23/2025 at 3:41:33 PM
Yes, I have. It's slow as shit even on an M1. In the time it takes to install one brew package on an M1, a sudo apt update && sudo apt dist-upgrade has finished updating a dozen packages on a ten year old intel system with a SATA SSD.I fucking hate homebrew.
I hate the fact that the project still has the attitude of "sudo is le hard and we are le tired."
The project people are assholes.
The maintainers are often well behind current releases.
It maintains a cache of every installed version for no good reason wasting ~10GB or more of my SSD space.
When it breaks it's impenetrable trying to figure out how it broke, there's nobody to ask for help, the documentation sucks, and the fastest thing is just to wipe the whole fucking directory and start over.
I could go on. I don't know a single person that likes using homebrew - it's just the package manager everyone resigned themselves to use.
by KennyBlanken
4/23/2025 at 4:00:58 PM
> I fucking hate homebrew.> I hate the fact that the project still has the attitude of "sudo is le hard and we are le tired."
> The project people are assholes.
Have you considered that approaching us like this isn't productive and doesn't make anyone remotely interested in helping you?
by woodruffw
4/23/2025 at 9:50:55 PM
I'm not the person you responded to, but I've mostly just accepted that homebrew is another paper cut that you get from using a Mac. If I post publicly about it I'm usually not looking for help.Years ago I worked with someone who strongly disliked brew because it leaned far too heavily on magic. I was okay with it because it seemed to work well. Brew still uses magic but now it just seems like I'm fighting it every single step of the way. I am le tired.
by inferiorhuman
4/23/2025 at 10:39:26 PM
As a serious question, with no leading implied: what are you fighting about Homebrew? I can say with 100% earnestness that we're interested in improving the user experience, and we want to know where the pain points are for our users.Actually hearing about them (instead of just cursing at us) is genuinely helpful, and we genuinely appreciate it.
by woodruffw
4/24/2025 at 7:42:07 AM
> It maintains a cache of every installed version for no good reason wasting ~10GB or more of my SSD space.cmon, `brew cleanup --prune=0` is just part of the muscle memory by now.
by fnord123
4/22/2025 at 11:30:06 PM
Another performance characteristic that used to piss me off when I used brew was that at least for one program, it had to invoke brew to launch. Something about finding a path. So that's an entire ruby interpreter starting and stopping just to (in this case) run a bash script. Horribly slow.by WD-42
4/23/2025 at 2:06:56 AM
That’s been fixed for at least a year! But yes, that used to be very slow, particularly when loading brew also meant loading every formula.by woodruffw
4/22/2025 at 9:32:55 PM
One big difference is that apt and dnf are both binary package management systems, whereas Homebrew is a source-based build system with binary packages (“bottles”) added on top.by amarshall
4/23/2025 at 5:55:05 PM
FWIW, I believe DNF (as of 5?) is now written in C++.But as a long time Linux user who always has to use a Mac at work I've been consistently floored by how painful Homebrew is to use, to the point that for my latest corp-issued MacBook I switched to home-manager and I'm not looking back.
by bobthecowboy
4/24/2025 at 7:39:14 AM
`brew search python` takes 3 seconds from a cold start.by fnord123
4/22/2025 at 11:33:03 PM
Just FYI you are describing a ports system, of which there are many. From macports, to alpine packages, to nixpkgs... Tons of research and automation in this area already. Would encourage looking at Nix and distri in particular. Many Nix packages can be built on/for macOS!by NewJazz
4/23/2025 at 7:31:38 PM
I know nix, did use nix-darwin for a while and actually integrated my own scripts called from the flake into setting up my system xDby alexykn
4/22/2025 at 8:46:14 PM
Cool project, good luck with it!If I may surface one use case: Several years ago I had to manage a bunch of Macs for CI jobs. The build process (Unreal's UAT) didn't support running more than one build process at a time, and Docker was really slow, so I'd hoped to use different user accounts to bypass that and get some parallelization gains. Homebrew made that very difficult with its penchant for system-wide installs. So a feature request: I'd love to see a competitive package manager that limits itself to operating somewhere (overridable) in the user's home directory.
by Scramblejams
4/22/2025 at 9:39:48 PM
IIRC the main reason here is that brew path is hardcoded during the build process of packages, which means that you wouldn't be able to use bottles.I didn't check, but there is a chance that path is also hardcoded in (some) formulae, so even building from the source might not help here.
by watermelon0
4/22/2025 at 10:29:41 PM
You could run the build process with chroot or inside Docker, so that the hardcoded paths actually resolve to a designated subdirectory.by scribu
4/22/2025 at 10:35:28 PM
Incidentally, that’s what is usually done in Nixpkgs in similar situations when there’s no better alternative, see buildFHSEnv et al.by mananaysiempre
4/23/2025 at 1:46:55 AM
In many cases the build output also has hardcoded paths unfortunatelyso doing `brew install` inside a container with the proper volumes it’s not sufficient to fix the issue. Everything would have to run from within the container as well.
by akdev1l
4/22/2025 at 8:49:36 PM
Initial idea for this really came from my dayjob too, we have macs but no way to centrally manage them. The client / server part for the declarative system manager I want to build on top of this is quite far out yet though. At least several monthsby alexykn
4/22/2025 at 9:28:16 PM
Nix effectively has per-user packages, but it’s hard to read into your full use case from your comment.by amarshall
4/22/2025 at 10:39:18 PM
oh, I guess this is why the nix installer creates 32 macOS users called _nixbld$Nby benwaffle
4/22/2025 at 10:50:47 PM
It's explained in the documentation.by homebrewer
4/22/2025 at 8:39:20 PM
One thing that Homebrew does not do easily is to easily allow for creation of universal libraries and binaries - https://github.com/orgs/Homebrew/discussions/4647Maybe that could be a place where sapphire differentiates?
by yincrash
4/22/2025 at 10:29:46 PM
> probably settle for automatic build system detection based on archive structure therePlease add knobs for the end user to manually configure this per package and global default before adding autodetection. As a user to is very frustrating to have to patch the package manager to override some well-intentioned automagic which didn't consider my setup or dig through sources to uncover some undocumented assumption. yarn is a cautionary example.
by 3np
4/22/2025 at 10:50:46 PM
I'll add manual override flags and also let users not only build from source from formulae but any dir on their machine they want, only makes senseby alexykn
4/23/2025 at 5:13:29 PM
> Build from source formulae is still pretty f*ed + I do not know if it is really feasible given that the json API lacks information there and a full on Ruby -> Rust transpiler is way out of scope. Will probably settle for automatic build system detection based on archive structure there. + Maybe do my own version of the .rb scripts but in a more general machine readable format, not .rs lolLast I checked (which was about a year ago), Homebrew had ~7000 formulas (not including casks).
I think it would be feasible to transcribe most of them to your format of choice with AI, run the build in a loop and ask the LLM to fix errors, and reserve manual intervention for the few cases that the LLM can't fix.
by miki123211
4/23/2025 at 6:25:51 PM
Yeah, this would 100% be feasible. Great idea. It's during the week now so I don't have much time besides work.I'll probably open a Poll on git within the next couple days about what to do about a real from source packaging system with it's own dsl, maybe just yaml/toml or something a bit more powerful like lua with mlua. No matter the choice of packaging apporach I would like to keep the generated packages "bottle compliant" -> at least with the json api spec, since this also installs from there.
There seems to be at least some in my project so even though I am very opinionated on a lot of things I don't think I should decide on that completely alone, especially given that this is the first time I play with packaging.
by alexykn
4/23/2025 at 6:26:10 PM
on github xDby alexykn
4/22/2025 at 8:25:34 PM
Perhaps you could embed something like https://github.com/artichoke/artichoke to run the Ruby scripts for compatibility.by nicoburns
4/22/2025 at 8:29:35 PM
Looked at that. I do not really think implementing something like artichoke or rutie would be a good idea. I do not want my project to become overly bloated and to achieve my real goal of a declarative system management thing I think sticking to bottles (that cover almost all formulae thanks to the amazing homebrew community) and casks, getting those to work 100% is the better approach. Thank you for the suggestion though!by alexykn
4/22/2025 at 8:26:10 PM
Please don't.by adamnemecek
4/23/2025 at 3:57:11 PM
Can you just shell out to homebrew for unsupported cases? I don’t imagine the overhead of ruby will be that high compared to compiling the code.by AlphaSite
4/23/2025 at 2:22:14 AM
Does the "casks" and "bottles" language imply that it's intended be compatible with Homebrew? That isn't made explicit in the description.by stevage
4/23/2025 at 12:13:52 PM
Yes, this is only a replacement for the Homebrew CLI. It doesn’t have its own package repository and moreover it doesn’t have the ability to build packages (yet)—it’s just downloading and installing the binaries built by Homebrew.by MatthiasPortzel
4/22/2025 at 11:49:13 PM
Good luck. Homebrew hasn't cut it since they started disallowing custom compile flags, and making the user jump through hoops if they want anything slightly different.by internet2000