I love my Apple silicon computer, but having to manually switch to Rosetta-enabled shells for my Intel-only projects was a bummer.

Fish offers a feature to define functions that get called when a variable has changed and Direnv offers a way to set variables when you enter a directory – let’s combine them to automatically switch to Rosetta!

Add the following function to your ~/.config/fish/config.fish1:

function __switch-to-rosetta --on-variable SWITCH_TO_ROSETTA
    if test -n "$SWITCH_TO_ROSETTA"
        set --erase SWITCH_TO_ROSETTA
        exec arch -x86_64 /usr/local/bin/fish -l

Then add the following to the top of the .envrc in the project directory:

if [[ $(sysctl -n sysctl.proc_translated) = 0 ]]; then
    export SWITCH_TO_ROSETTA=1
    exit 0

The “exit 0” ensures that my .envrc doesn’t run setup code like “eval $(pdm venv activate)” on the wrong architecture.

You’re done! Whenever you enter this directory, and Fish is running on ARM, it will replace itself with an Intel version.

Note that since we use exec to start the new shell, the ARM shell process is literally replaced by the Rosetta version. That means that you can’t get out of Rosetta mode again; exiting the shell ends the sessions and running “arch -arm64 /opt/homebrew/bin/fish” does not put you back on ARM.

Bonus Tip: Add a Rosetta Indicator to Your Prompt!

If you’re using starship (which you should, regardless of your shell) you can add the following into your ~/.config/starship.toml:

variable = 'STARSHIP_CPU'
format = 'on $env_value '

And the following into your ~/.config/fish/config.fish:

if test (sysctl -n sysctl.proc_translated) = 1
    set -x STARSHIP_CPU "🦕🦖"

  1. Defining it using funced did not work for me. The name of the function doesn’t matter, it’s never called by hand. ↩︎