Yojam: a macOS default-browser shim that routes URLs through a rule engine

63 points by fluffypony 18 hours ago on lobsters | 32 comments

dmytrish | 16 hours ago

Oh, finally plumber (9) on Mac!

This functionality does feel like a gap in the OS itself.

[OP] fluffypony | 16 hours ago

Ha, yes - plumber is exactly the mental model, and it's wild that nothing in macOS itself fills that gap. LaunchServices gives you one default handler per scheme and that's it; no routing, no context, no source-app awareness. Everything interesting has to live in a shim that registers as the default browser and then dispatches from there.

The nice side-effect of building it that way is that every ingress path (clicks, Finder, Handoff, AirDrop, Share, Services, extensions, yojam://) funnels through the same pipeline, so rules and tracker scrubbing apply uniformly. The less-nice side is that private-window support for Safari and Orion has to go through AppleScript because there is no CLI flag for it, which is about as plumber-esque as it gets.

theblacklounge | 7 hours ago

What is the number between brackets?

[OP] fluffypony | 7 hours ago

Unix / Linux / BSD manual section number. Man pages are grouped into numbered sections by category, and you cite a page as name(section) to disambiguate - so plumber(9) means "the plumber page in section 9". Run man 9 plumber to read it (on a Plan 9 system, macOS doesn't ship it so there is no man entry for plumber).

Classic Unix sections are 1 (user commands), 2 (syscalls), 3 (library functions), 5 (file formats), 7 (miscellaneous/conventions), 8 (sysadmin). Plan 9 reshuffled the numbering a bit, which is why plumber lives at 9 there and why the plumb rules file the other commenter linked is plumb(7).

It reminded me of plumb (see the example): https://9fans.github.io/plan9port/man/man7/plumb.html

[OP] fluffypony | 16 hours ago

Yup, plumb(7) really is the canonical reference for this pattern. The rules file syntax (match on source, type, data; apply actions) maps almost one-to-one onto what Yojam ended up doing, just with a GUI bolted on and macOS ingress paths instead of Plan 9 ones. Source-app matching in particular is basically the src field wearing a different hat.

If I had been braver I would have shipped a plaintext rules file as the source of truth and treated the UI as a view over it. Maybe in a future version; the App Group storage is JSON under the hood, so it is not a huge leap.

thesadsre | 14 hours ago

Neat. Very similar to choosy.app

A basic version can also be created with hammerspoon.

[OP] fluffypony | 14 hours ago

Indeed! Choosy is the closest neighbour and it is a solid app - I used it for a bit (although Bumpr was my go-to more recently). All of these are similar in that they intercept the default-browser role and route based on rules.

Where Yojam goes further are a few things, eg. browser profiles as first-class rule targets (not just bundle IDs), source-app matching with synthetic sentinels for Handoff/AirDrop/Share/Services/each extension, tracker parameter scrubbing before the target browser ever sees the URL, global regex URL rewrites, custom CLI args with a $URL placeholder for non-browser targets (or if you want to use Lynx / Links etc), and a yojam:// scheme for Shortcuts/Raycast/Alfred automation. The URL tester on the Pipeline tab is also something I missed in Choosy - paste a URL and watch exactly which rewrites fire, what gets stripped, and which rule wins.

thesadsre | 3 hours ago

That's really cool!

rsalmond | 13 hours ago

If any finicky users are able to offer a comparison I'd be interested to hear your thoughts.

https://github.com/johnste/finicky

danlamanna | 9 hours ago

Rules can target specific browser profiles, not just bundle IDs.

I'm curious, can it target Firefox container tabs? If not directly I think https://addons.mozilla.org/en-US/firefox/addon/open-url-in-container/ might be able to do the trick.

[OP] fluffypony | 9 hours ago

I'm not sure if it can intrinsically (will research), but Yojam has a FF addon (rough and a bit untested atm) for opening a link in FF via Yojam - I could extend the addon to handle that similarly to that addon. Would you mind opening a GitHub issue for this so I can keep track?

Exagone313 | 17 hours ago

I've been thinking about my need of something like this on Android.

Happy to see this explored.

[OP] fluffypony | 16 hours ago

I had a request for a windows version on X - I’ll do a little digging and see how feasible it is on Android too!

creature | 5 hours ago

One thing I'd like – though it may not be possible – is to be able to assign domains to specific displays.

I'm working somewhere that uses Google Meet, so all my meetings are in-browser. I do most of my browsing on Display 2 (my big external monitor), but meetings should be on Display 1 (the built-in Macbook screen) so it looks like I'm paying attention to everyone. I wish I could have a rule like "If there's already browser window on Display 1, open a new tab; if not, open a new window on that display".

jak2k | 16 hours ago

Someone tried to hide their AGENTS.MD here… (See .gitignore)

Using LLMs is unethical and trying to hide LLM usage even more so. If you use them, please at least be transparent about it so I can avoid your software.

[OP] fluffypony | 16 hours ago

I absolutely do use AI coding assistants to a greater or lesser degree, but there is no AGENTS.md in the source tree and I’m not trying to hide anything

The reason I’ve started putting that in there is because I’ve had to deal with a great many PRs that include the submitter’s AGENTS.md - it’s beyond frustrating. I have no problem with AI assisted PRs, I just don’t see why I also need to read the garbage analysis your agent wrote about the source code or your personal preferences.

I encourage everyone to start doing the same.

jak2k | 16 hours ago

It's right there in the commit history: https://github.com/fluffypony/yojam/blob/709d6ba1c3a8d957d52f04335ab953c422561e8d/AGENTS.md

I'd like to especially highlight this line:

Always invoke the humanizer skill for every piece of user-facing text.

[OP] fluffypony | 16 hours ago

You’re misunderstanding what I said. The very first line in my reply was “I absolutely do use AI coding assistants to a greater or lesser degree”. I nuked the AGENTS.md AND added it to gitignore not because I don’t use AI coding tools, but because (1) they keep getting included in PRs on various projects I work on; (2) where I do use AI coding agents my workflow uses mcp-code-indexer and not AGENTS.md. My previous reply stands - I’m sorry if you misunderstood it to mean I don’t use AI or something along those lines.

WilhelmVonWeiner | 10 hours ago

The "humanizer" skill is not very good, more aggravating than anything.

[OP] fluffypony | 10 hours ago

Sure but writing docs (even a reasme) is the bane of my existence. If it was just something for me to use I wouldn’t bother, but I want others to benefit from this, which necessitates some UI/UX focus. I don’t use the stock skill, I have a modified version (happy to share) and then I still go through the textual changes and manually tweak bits (eg. it still sometimes shoves emdashes in even when I explicitly tell it not to)

olegkovalov | 17 hours ago

1.7k followers on Github profile but dozens of stars on repos, wut?

[OP] fluffypony | 17 hours ago

Most of my followers are because I was the lead maintainer on Monero from the outset till 2019 when I stepped back. I remained a member of the Monero Core Team for a long time after that.

I have posted about some of my newer tools on X but I'm not sure AI tools and a URL click handler appeal much to my GitHub followers:-P

interesting idea. I may just borrow that concept for my particular system.

[OP] fluffypony | 14 hours ago

Would love to make a version for *nix, and happy to target your district as a first class citizen if it’s useful!

an unreleased Linux distro that I am working on, so there are some opportunities to do things different. This concept seems interesting to build into the OS itself. Still early days though, so I wont bother you with this, for now at least :-)

grahams | 9 hours ago

I've been using Choosy for a long time but will give Yojam a try! I daily drive Safari, but Choosy isn't able to target profiles which I use to keep a vague separation between church and state.

In the OP you mention that you support profiles in Safari/Orian via AppleScript, but I didn't see anything in the UI for Safari, nor is there any mention of Safari profiles on the homepage. Is this upcoming functionality or something I can get from a prerelease build or build from source?

[OP] fluffypony | 9 hours ago

Sorry that's bad writing on my part - the AppleScript path for Safari and Orion is for private/incognito windows, not profile targeting - I shouldn't have clumped that all together and missed noting that. Safari profiles don't expose any scripting or CLI surface for "open this URL in profile X" - AppleScript can't do it, open -a Safari --args can't do it, and there's no URL scheme variant for it. As far as I can tell Apple simply hasn't shipped the hook.

So it isn't upcoming in a prerelease or hiding behind a build flag; it's blocked on Apple. The moment they ship a scripting dictionary entry or a CLI flag for profile selection, I'll wire it up the same day - the rule model already supports profile targets, it's purely an ingress problem on Safari's side.

afaik Orion does support profiles, but I only switched to it as my daily a couple of weeks ago so haven't had a chance to even try that and properly bake it in. For anything weird like that, you can always add it as a custom app, and set the launch args with $URL for the url.

If you find a trick I've missed, please shout - I would genuinely love to be wrong about this!

grahams | 8 hours ago

That makes sense, I tried to work around the Safari limitations you mentioned and always came up short. Right now on my work Mac I'm using Safari for work and Orion for personal as a workaround.

[OP] fluffypony | 8 hours ago

Elsewhere on this thread we're discussing using the Firefox addon to create a custom URL scheme that lets Yojam handle opening in a specific container...I'll do a little research and see if there is a way I can do it via a Safari extension. Knowing my luck, I'll come up with some insane hacky thing that works, and then Apple will ship a CLI arg for it in macOS 26.5 or something:-P

WilhelmVonWeiner | 13 hours ago

Comment removed by author

I had implemented something similar to use on my work laptop to keep personal and work related browsing segregated across browsers.

Currently using Better Touch Tool as a replacement with more keyboard shortcuts.

https://github.com/mechanicker/chromer

[OP] fluffypony | 9 hours ago

I had a similar driving force - personal gmail logged in in Safari, and work G Workspace in Chrome (plus all the oauth stuff that stems from that).