Add Muse Code as a default coding agent (#9915)

* Add Muse Code as a default coding agent

Meta ships Muse Code only as a binary, so it installs from the AUR
(muse-code-bin) instead of mise, and a fresh install runs the muse login
browser flow in the install terminal before the agent opens.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0148qKzr366p2Ubu2igCLvPg

* Refine Muse Code menu and prompt forwarding

* Install Muse Code from OPR

* Install Muse Code through mise's HTTP backend

* Preinstall the Muse mise stub

* Use the shared Muse installation flow

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: David Heinemeier Hansson <david@hey.com>
This commit is contained in:
authored and GitHub committed 2026-09-06 22:29:16 +02:00
1 parent f4a462ef20
commit 0d223fe820
9 files changed
+167 -6

No files matched your search

+5
View File
@@ -110,6 +110,11 @@ hermes)
command=(hermes --yolo)
fi
;;
muse)
# --approval-mode never skips the tool prompts but keeps Muse's own sandbox.
command=(muse --approval-mode never)
[[ -n ${prompt:-} ]] && command+=(-- "$prompt")
;;
omp)
command=(omp --auto-approve)
[[ -n ${prompt:-} ]] && command+=(-- "$prompt")
+7 -2
View File
@@ -1,7 +1,7 @@
#!/bin/bash
# omarchy:summary=Set and launch the default coding agent
# omarchy:args=[pi|omp|opencode|ori|claude|codex|grok|openclaw|agy|hermes|copilot|crush|cursor-agent]
# omarchy:args=[pi|omp|opencode|ori|claude|codex|grok|openclaw|agy|hermes|copilot|crush|cursor-agent|muse]
# omarchy:examples=omarchy default agent | omarchy default agent codex | omarchy default agent claude
installing=false
@@ -36,9 +36,14 @@ openclaw) agent="openclaw"; name="OpenClaw"; agent_installer="omarchy-install-op
agy | antigravity | antigravity-cli | gemini | gemini-cli) agent="agy"; name="Antigravity"; agent_package="antigravity-cli" ;;
hermes) agent="hermes"; name="Hermes"; agent_installer="omarchy-install-hermes-cli" ;;
copilot | github-copilot) agent="copilot"; name="GitHub Copilot" ;;
muse | muse-code | musecode)
agent="muse"; name="Muse Code"
# Meta's launcher verifies and updates the native binary for this platform.
agent_package="http:muse[url=https://api.meta.ai/muse-launcher.sh,bin=muse,version_list_url=https://api.meta.ai/muse-code/channels/muse-stable,version_json_path=.version]"
;;
cursor | cursor-agent) agent="cursor-agent"; name="Cursor CLI" ;;
*)
echo "Usage: omarchy-default-agent <pi|omp|opencode|ori|claude|codex|grok|openclaw|agy|hermes|copilot|crush|cursor-agent>"
echo "Usage: omarchy-default-agent <pi|omp|opencode|ori|claude|codex|grok|openclaw|agy|hermes|copilot|crush|cursor-agent|muse>"
exit 1
;;
esac
+6
View File
@@ -24,6 +24,12 @@ if gum confirm "Are you sure you want to remove all preinstalled web apps, TUI w
rm -f ~/.local/bin/cursor-agent
fi
# Preserve a user-managed Muse launcher at the same path.
if [[ -f ~/.local/bin/muse && ! -L ~/.local/bin/muse ]] &&
grep -Eq '^mise use -g .*"http:muse\[' ~/.local/bin/muse; then
rm -f ~/.local/bin/muse
fi
# Only the wrapper omarchy-install-hermes-cli wrote is a preinstall. Hermes
# Desktop's command, an official install, or anything else at that path is
# the user's, so it is the installer that decides whether the wrapper is its
+1
View File
@@ -143,6 +143,7 @@
"setup.default.agent.cursor-agent": {"icon":"","iconFont":"omarchy","label":"Cursor CLI","checked":"[[ \"$(omarchy-default-agent)\" == \"cursor-agent\" ]]","action":"omarchy-default-agent cursor-agent"},
"setup.default.agent.grok": {"icon":"","iconFont":"omarchy","label":"Grok","checked":"[[ \"$(omarchy-default-agent)\" == \"grok\" ]]","action":"omarchy-default-agent grok"},
"setup.default.agent.hermes": {"icon":"","iconFont":"omarchy","label":"Hermes","checked":"[[ \"$(omarchy-default-agent)\" == \"hermes\" ]]","action":"omarchy-default-agent hermes"},
"setup.default.agent.muse": {"icon":"󰛤","label":"Muse Code","checked":"[[ \"$(omarchy-default-agent)\" == \"muse\" ]]","action":"omarchy-default-agent muse"},
"setup.default.agent.omp": {"icon":"","iconFont":"omarchy","label":"omp","checked":"[[ \"$(omarchy-default-agent)\" == \"omp\" ]]","action":"omarchy-default-agent omp"},
"setup.default.agent.openclaw": {"icon":"","iconFont":"omarchy","label":"OpenClaw","checked":"[[ \"$(omarchy-default-agent)\" == \"openclaw\" ]]","action":"omarchy-default-agent openclaw"},
"setup.default.agent.opencode": {"icon":"","iconFont":"omarchy","label":"OpenCode","checked":"[[ \"$(omarchy-default-agent)\" == \"opencode\" ]]","action":"omarchy-default-agent opencode"},
+3
View File
@@ -21,3 +21,6 @@ omarchy-mise-install github:OpenRouterLabs/ori-releases ori
# omarchy-provision-user -- the default browser, the mailto handler and the
# finalize-user marker all come after it.
omarchy-install-hermes-cli || true
if omarchy-cmd-missing muse; then
omarchy-mise-install "http:muse[url=https://api.meta.ai/muse-launcher.sh,bin=muse,version_list_url=https://api.meta.ai/muse-code/channels/muse-stable,version_json_path=.version]" muse
fi
+3
View File
@@ -15,6 +15,7 @@ Omarchy treats AI coding agents as first-class citizens, but it doesn't pick a f
| `omp` | [Oh My Pi](https://github.com/can1357/oh-my-pi) |
| `ori` | [Ori](https://openrouter.ai/docs/guides/ori/harness), OpenRouter's harness |
| `hermes` | [Hermes](https://hermes-agent.nousresearch.com/), Nous Research's agent |
| `muse` | [Muse Code](https://dev.meta.ai), Meta's coding agent |
| `cursor-agent` | [Cursor CLI](https://cursor.com/cli) |
`ori` is the odd one out: it runs the other harnesses against OpenRouter's whole model catalog, so `ori claude`, `ori codex`, or `ori opencode` start those agents on whichever model you point them at, and `ori code` is Ori's own agent.
@@ -25,6 +26,8 @@ To wrap an additional CLI the same way, run `omarchy-mise-install <package> [com
Pick your default agent with `omarchy default agent <name>` or under _Setup > Defaults > Agent_ in the Omarchy Menu (`Super + Space`). If the agent isn't installed yet, picking it installs it first. A fresh Omarchy will invite you to make this choice with a one-time notification.
[Muse Code](https://dev.meta.ai) — Meta's `muse` — uses a preinstalled mise stub like the other agents. Picking it as the default installs Meta's official launcher through mise's HTTP backend. The launcher verifies and updates the native binary for your machine.
Once you've chosen, `Super + Shift + Ctrl + A` launches the default agent in a dedicated terminal window (or brings up the picker if you haven't chosen yet). You can also launch it straight into a task with `omarchy agent prompt "Review this project"`. Agents launched this way run unattended in their respective don't-stop-to-ask modes, so be ready for them to actually do things! And since agents refuse to remember trust for your home directory, launches from `$HOME` start in `~/Work` instead.
There are terminal shortcuts too: `a` runs the default agent inline in the current terminal, while `c`, `cx`, and `cy` start OpenCode, Claude Code, and Codex directly (again in their auto-approving modes). Theme changes sync to the agents as well: Claude Code, Pi, OpenCode, and Hermes (once Hermes Desktop is installed) all follow along when you switch the Omarchy theme.
+5
View File
@@ -0,0 +1,5 @@
echo "Install Muse Code via mise wrapper"
if omarchy-cmd-missing muse && [[ ! -f $HOME/.local/state/omarchy/preinstalls-removed ]]; then
omarchy-mise-install "http:muse[url=https://api.meta.ai/muse-launcher.sh,bin=muse,version_list_url=https://api.meta.ai/muse-code/channels/muse-stable,version_json_path=.version]" muse
fi
+133 -2
View File
@@ -19,6 +19,7 @@ mise_history="$test_tmp/mise-history"
stub_log="$test_tmp/stubs"
terminal_log="$test_tmp/terminal"
menu_log="$test_tmp/menu"
muse_login_log="$test_tmp/muse-login"
mkdir -p "$mock_bin" "$test_home"
cat >"$mock_bin/omarchy-notification-send" <<'SH'
@@ -69,6 +70,22 @@ cat >"$mock_bin/omarchy-menu" <<'SH'
printf '%s\0' "$@" >"$OMARCHY_TEST_AGENT_MENU_LOG"
SH
cat >"$mock_bin/omarchy-pkg-add" <<'SH'
#!/bin/bash
echo "Muse must install through mise" >&2
exit 1
SH
ln -s omarchy-pkg-add "$mock_bin/omarchy-pkg-aur-add"
cat >"$mock_bin/muse" <<'SH'
#!/bin/bash
if [[ ${1:-} == "login" ]]; then
printf 'muse %s\n' "$*" >>"$OMARCHY_TEST_MUSE_LOGIN_LOG"
else
printf '%s\0' muse "$@" >"$OMARCHY_TEST_AGENT_INLINE_LOG"
fi
SH
cat >"$mock_bin/omarchy-test-noop" <<'SH'
#!/bin/bash
exit 0
@@ -91,6 +108,7 @@ export OMARCHY_TEST_MISE_HISTORY="$mise_history"
export OMARCHY_TEST_STUB_LOG="$stub_log"
export OMARCHY_TEST_AGENT_TERMINAL_LOG="$terminal_log"
export OMARCHY_TEST_AGENT_MENU_LOG="$menu_log"
export OMARCHY_TEST_MUSE_LOGIN_LOG="$muse_login_log"
export OMARCHY_PATH="$ROOT"
grok_package="npm:@xai-official/grok"
@@ -99,6 +117,7 @@ crush_package="crush"
agy_package="antigravity-cli"
ori_package="github:OpenRouterLabs/ori-releases"
cursor_agent_package="cursor-agent"
muse_package="http:muse[url=https://api.meta.ai/muse-launcher.sh,bin=muse,version_list_url=https://api.meta.ai/muse-code/channels/muse-stable,version_json_path=.version]"
assert_lazy_stub() {
local package=$1
@@ -118,6 +137,7 @@ assert_lazy_stub "$omp_package" omp
assert_lazy_stub "$crush_package" crush
assert_lazy_stub "$ori_package" ori
assert_lazy_stub "$cursor_agent_package" cursor-agent
assert_lazy_stub "$muse_package" muse
pass "custom agent lazy stubs preserve their mise packages"
OMARCHY_TEST_MISSING_COMMAND=cursor-agent source "$ROOT/install/user/mise.sh"
@@ -127,12 +147,29 @@ grep -Fx "$cursor_agent_package" "$stub_log" >/dev/null || fail "user setup crea
grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "user setup creates the Oh My Pi lazy stub"
grep -Fx "$crush_package" "$stub_log" >/dev/null || fail "user setup creates the Crush lazy stub"
grep -Fx "$ori_package ori" "$stub_log" >/dev/null || fail "user setup creates the Ori lazy stub"
OMARCHY_TEST_MISSING_COMMAND=muse source "$ROOT/install/user/mise.sh"
grep -Fx "$muse_package muse" "$stub_log" >/dev/null || fail "user setup creates the Muse lazy stub"
pass "user setup creates the custom agent lazy stubs"
: >"$stub_log"
source "$ROOT/install/user/mise.sh"
grep -Fx "$cursor_agent_package" "$stub_log" >/dev/null && fail "user setup replaces an existing cursor-agent command"
pass "user setup keeps an existing Cursor CLI install"
grep -Fx "$muse_package muse" "$stub_log" >/dev/null && fail "user setup replaces an existing Muse command"
: >"$stub_log"
OMARCHY_TEST_MISSING_COMMAND=muse source "$ROOT/migrations/1788724825.sh" >/dev/null
grep -Fx "$muse_package muse" "$stub_log" >/dev/null || fail "Muse migration creates its lazy stub"
: >"$stub_log"
source "$ROOT/migrations/1788724825.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "Muse migration replaces an existing command"
mkdir -p "$test_home/.local/state/omarchy"
touch "$test_home/.local/state/omarchy/preinstalls-removed"
OMARCHY_TEST_MISSING_COMMAND=muse source "$ROOT/migrations/1788724825.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "Muse migration ignores the preinstall opt-out"
rm "$test_home/.local/state/omarchy/preinstalls-removed"
pass "Muse migration preserves existing installs and the preinstall opt-out"
: >"$stub_log"
source "$ROOT/migrations/1785617047.sh" >/dev/null
@@ -260,9 +297,10 @@ rm "$test_home/.local/state/omarchy/preinstalls-removed"
rm -f "$agent_file"
pass "agent migrations install working wrappers without overriding the preinstall opt-out"
"$ROOT/bin/omarchy-mise-install" "$muse_package" muse
touch "$test_home/.local/bin/agy" "$test_home/.local/bin/ori"
omarchy-remove-preinstalls >/dev/null
for command in agy omp ori grok crush cursor-agent; do
for command in agy omp ori grok crush cursor-agent muse; do
[[ ! -e $test_home/.local/bin/$command ]] || fail "Remove Preinstalls deletes the $command lazy stub"
done
pass "Remove Preinstalls deletes every optional agent lazy stub"
@@ -275,6 +313,13 @@ omarchy-remove-preinstalls >/dev/null
[[ -L $test_home/.local/bin/cursor-agent ]] || fail "Remove Preinstalls keeps an official Cursor CLI install"
rm -f "$test_home/.local/bin/cursor-agent" "$test_home/.local/bin/cursor-agent.official"
pass "Remove Preinstalls keeps an official Cursor CLI install"
printf '#!/bin/bash\necho user-muse\n' >"$test_home/.local/bin/muse"
chmod +x "$test_home/.local/bin/muse"
omarchy-remove-preinstalls >/dev/null
[[ $("$test_home/.local/bin/muse") == "user-muse" ]] || fail "Remove Preinstalls deletes a user-managed Muse"
rm "$test_home/.local/bin/muse"
pass "Remove Preinstalls keeps a user-managed Muse install"
[[ -z $(omarchy-default-agent) ]] || fail "default agent is unset until one is chosen"
pass "default agent is unset until one is chosen"
@@ -338,6 +383,9 @@ declare -A expected_agents=(
[github-copilot]="copilot"
[cursor]="cursor-agent"
[cursor-agent]="cursor-agent"
[muse]="muse"
[muse-code]="muse"
[musecode]="muse"
)
declare -A expected_packages=(
@@ -352,6 +400,7 @@ declare -A expected_packages=(
[agy]="$agy_package"
[copilot]="copilot"
[cursor-agent]="$cursor_agent_package"
[muse]="$muse_package"
)
for selection in "${!expected_agents[@]}"; do
@@ -361,8 +410,12 @@ for selection in "${!expected_agents[@]}"; do
[[ $(omarchy-default-agent) == $expected ]] || fail "default agent canonicalizes $selection"
mapfile -d '' -t mise_args <"$mise_log"
[[ ${mise_args[0]} == "use" && ${mise_args[1]} == "-g" && ${mise_args[2]} == ${expected_packages[$expected]} ]] ||
[[ ${mise_args[0]} == "use" && ${mise_args[1]} == "-g" ]] ||
fail "default agent installs $selection globally through mise"
case ${mise_args[2]} in
"${expected_packages[$expected]}") ;;
*) fail "default agent preserves $selection backend options" ;;
esac
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 1 && ${agent_open_args[0]} == "omarchy-agent" ]] ||
@@ -475,6 +528,76 @@ grep -F "Could not set Codex as the default coding agent" "$test_tmp/setup-failu
[[ ! -s $agent_open_log ]] || fail "failed activation does not open an agent"
pass "default agent reports mise failures without notifications"
# Muse follows the shared mise installation and launch path.
: >"$notification_history"
: >"$agent_open_log"
: >"$terminal_log"
omarchy-default-agent muse
mapfile -d '' -t terminal_args <"$terminal_log"
[[ ${terminal_args[0]} == "omarchy-default-agent" && ${terminal_args[1]} == "--install" && ${terminal_args[2]} == "muse" ]] ||
fail "missing Muse installation opens in a terminal"
[[ ! -s $notification_history ]] || fail "missing Muse installation skips notifications"
[[ ! -s $agent_open_log ]] || fail "missing Muse installation waits to open the agent"
[[ $(omarchy-default-agent) == "copilot" ]] || fail "missing Muse installation waits to change the selection"
if OMARCHY_TEST_MISE_FAIL=true omarchy-default-agent --install muse >"$test_tmp/muse-install-failure-output" 2>&1; then
fail "missing Muse rejects a failed mise installation"
fi
[[ $(omarchy-default-agent) == "copilot" ]] || fail "failed Muse installation preserves the current default"
[[ ! -s $muse_login_log && ! -s $agent_open_log ]] || fail "failed Muse installation skips login and launch"
grep -F "Could not install Muse Code with mise" "$test_tmp/muse-install-failure-output" >/dev/null ||
fail "failed Muse installation identifies mise"
pass "failed Muse mise installation preserves the selection and skips login"
: >"$mise_history"
: >"$stub_log"
omarchy-default-agent --install muse >"$test_tmp/muse-install-output"
grep -Fx "use -g $muse_package" "$mise_history" >/dev/null || fail "visible Muse installation uses the HTTP backend"
[[ ! -s $stub_log ]] || fail "Muse selection recreates its preinstalled wrapper"
[[ ! -s $muse_login_log ]] || fail "Muse selection runs a separate login flow"
[[ $(omarchy-default-agent) == "muse" ]] || fail "visible Muse installation changes the selection"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 2 && ${agent_open_args[0]} == "omarchy-agent" && ${agent_open_args[1]} == "--inline" ]] ||
fail "newly installed Muse opens in the installation terminal"
pass "Muse installs visibly through mise and opens directly"
: >"$terminal_log"
: >"$muse_login_log"
: >"$agent_open_log"
OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent muse-code
[[ ! -s $terminal_log ]] || fail "installed Muse selection skips the terminal"
[[ ! -s $muse_login_log ]] || fail "installed Muse selection skips the login"
[[ $(omarchy-default-agent) == "muse" ]] || fail "default agent canonicalizes muse-code"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 1 && ${agent_open_args[0]} == "omarchy-agent" ]] ||
fail "installed Muse opens in a new terminal after selection"
pass "installed Muse selects and opens directly"
OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent pi
: >"$agent_open_log"
if OMARCHY_TEST_AGENT_INSTALLED=true OMARCHY_TEST_MISE_FAIL=true omarchy-default-agent musecode >"$test_tmp/muse-failure-output" 2>&1; then
fail "default agent rejects a failed Muse activation"
fi
[[ $(omarchy-default-agent) == "pi" ]] || fail "failed Muse activation preserves the current default agent"
grep -F "Could not set Muse Code as the default coding agent" "$test_tmp/muse-failure-output" >/dev/null ||
fail "default agent reports a failed Muse activation"
[[ ! -s $agent_open_log ]] || fail "failed Muse activation does not open an agent"
pass "default agent reports Muse mise failures without changing the selection"
# A manually installed launcher belongs to the user; selecting it must not
# install a second copy or replace it with the Omarchy wrapper.
printf '#!/bin/bash\necho user-muse\n' >"$test_home/.local/bin/muse"
chmod +x "$test_home/.local/bin/muse"
: >"$mise_history"
: >"$stub_log"
: >"$terminal_log"
omarchy-default-agent muse
[[ $(omarchy-default-agent) == "muse" ]] || fail "a user-installed Muse can be selected"
[[ ! -s $mise_history && ! -s $stub_log && ! -s $terminal_log ]] || fail "a user-installed Muse skips installation and wrapper creation"
[[ $("$test_home/.local/bin/muse") == "user-muse" ]] || fail "a user-installed Muse is preserved"
rm "$test_home/.local/bin/muse"
pass "selecting a user-installed Muse preserves its launcher"
rm "$mock_bin/omarchy-agent"
hash -r
@@ -523,6 +646,7 @@ assert_launch opencode opencode --auto --prompt "Review this project"
assert_launch ori ori code --interactive --prompt "Review this project"
assert_launch claude claude --permission-mode auto -- "Review this project"
assert_launch codex codex --approve-for-me -- "Review this project"
assert_launch muse muse --approval-mode never -- "Review this project"
assert_launch crush crush run "Review this project"
assert_launch grok grok --permission-mode bypassPermissions -- "Review this project"
assert_launch cursor-agent cursor-agent --yolo --trust agent -- "Review this project"
@@ -531,6 +655,12 @@ assert_launch agy agy --dangerously-skip-permissions --prompt-interactive "Revie
assert_launch copilot copilot --allow-all --interactive "Review this project"
pass "agent launcher adapts initial prompts for every supported agent"
literal_muse_prompt=$'--disable-sandbox !Crash {$(touch must-not-run)}\ntrailing\\ '
printf '%s\n' "muse" >"$agent_file"
omarchy-agent-prompt "$literal_muse_prompt"
assert_launched muse "separates prompt text from options" muse --approval-mode never -- "$literal_muse_prompt"
pass "Muse receives option-like prompts as one literal argument"
literal_hermes_prompt=$' --help !Crash /quit {$(touch must-not-run)}\ntrailing\\ '
printf '%s\n' "hermes" >"$agent_file"
omarchy-agent-prompt "$literal_hermes_prompt"
@@ -544,6 +674,7 @@ assert_bypass opencode opencode --auto
assert_bypass ori ori code
assert_bypass claude claude --permission-mode auto
assert_bypass codex codex --approve-for-me
assert_bypass muse muse --approval-mode never
assert_bypass crush crush --yolo
assert_bypass grok grok --permission-mode bypassPermissions
assert_bypass cursor-agent cursor-agent --yolo --trust
+4 -2
View File
@@ -228,7 +228,9 @@ const expectedAgents = {
openclaw: { icon: '\ue90c', iconFont: 'omarchy', label: 'OpenClaw' },
copilot: { icon: '', label: 'Copilot' },
crush: { icon: '󰋑', label: 'Crush' },
muse: { icon: '󰛤', label: 'Muse Code' },
'cursor-agent': { icon: '\ue90d', iconFont: 'omarchy', label: 'Cursor CLI' },
}
assert(
Object.entries(expectedAgents).every(([agent, expected]) => {
@@ -241,13 +243,13 @@ assert(
&& !entry.when
&& entry.checked.includes(`== \"${agent}\"`)
}),
'menu exposes every mise-installable coding agent with its own glyph under Defaults > Agent'
'menu exposes every supported coding agent with its own glyph under Defaults > Agent'
)
assertDeepEqual(
defaultItems
.filter(item => item.parent === 'setup.default.agent')
.map(item => item.label),
['Antigravity', 'Claude', 'Codex', 'Copilot', 'Crush', 'Cursor CLI', 'Grok', 'Hermes', 'omp', 'OpenClaw', 'OpenCode', 'Ori', 'Pi'],
['Antigravity', 'Claude', 'Codex', 'Copilot', 'Crush', 'Cursor CLI', 'Grok', 'Hermes', 'Muse Code', 'omp', 'OpenClaw', 'OpenCode', 'Ori', 'Pi'],
'menu sorts coding agents alphabetically'
)
const expectedDefaults = {