From 45e32c8c2d000ffee5488e16fb7601100a2c0511 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 15 Sep 2026 08:10:58 -0400 Subject: [PATCH 1/3] Set up browser integration when choosing Claude --- bin/omarchy-agent | 2 +- bin/omarchy-default-agent | 5 +++ bin/omarchy-install-chromium-claude | 43 +++++++++++++++++++ manual/17-ai.md | 2 + test/shell.d/chromium-claude-test.sh | 50 +++++++++++++++++++++++ test/shell.d/default-agent-test.sh | 22 +++++++++- test/shell.d/unowned-system-paths-test.sh | 7 +++- 7 files changed, 126 insertions(+), 5 deletions(-) create mode 100755 bin/omarchy-install-chromium-claude create mode 100644 test/shell.d/chromium-claude-test.sh diff --git a/bin/omarchy-agent b/bin/omarchy-agent index e35bcf04..23d0e2f3 100755 --- a/bin/omarchy-agent +++ b/bin/omarchy-agent @@ -75,7 +75,7 @@ crush) fi ;; claude) - command=(claude --permission-mode auto) + command=(claude --permission-mode auto --chrome) [[ -n ${prompt:-} ]] && command+=(-- "$prompt") ;; grok) diff --git a/bin/omarchy-default-agent b/bin/omarchy-default-agent index af93d863..8c14a4f2 100755 --- a/bin/omarchy-default-agent +++ b/bin/omarchy-default-agent @@ -86,6 +86,11 @@ if ! agent_install; then exit 1 fi +if [[ $agent == "claude" ]] && ! omarchy-install-chromium-claude; then + echo "Could not install the Claude browser extension" >&2 + exit 1 +fi + mkdir -p "$(dirname "$agent_file")" printf '%s\n' "$agent" >"$agent_file" diff --git a/bin/omarchy-install-chromium-claude b/bin/omarchy-install-chromium-claude new file mode 100755 index 00000000..df338271 --- /dev/null +++ b/bin/omarchy-install-chromium-claude @@ -0,0 +1,43 @@ +#!/bin/bash + +# omarchy:summary=Install the Claude extension for Chromium-based browsers +# omarchy:requires-sudo=true + +set -euo pipefail + +if (( EUID == 0 )); then + export PATH=/usr/bin:/bin +fi + +EXTENSION_ID="fcoeoabgfenejglbffodgkkbkcdhcgfn" +EXTENSION_JSON='{ "external_update_url": "https://clients2.google.com/service/update2/crx" }' +PACKAGED_PATH=/usr/bin/omarchy-install-chromium-claude + +# Brave and Brave Origin share Chromium's external extension directory. +# Seed all supported browsers, including those installed after choosing Claude. +EXTENSION_DIRS=( + /usr/share/chromium/extensions + /usr/share/google-chrome/extensions + /usr/share/microsoft-edge/extensions +) + +installed=true +for dir in "${EXTENSION_DIRS[@]}"; do + if [[ ! -f $dir/$EXTENSION_ID.json ]] || [[ $(cat "$dir/$EXTENSION_ID.json") != "$EXTENSION_JSON" ]]; then + installed=false + fi +done + +if [[ $installed == "true" ]]; then + exit 0 +fi + +if (( EUID == 0 )); then + for dir in "${EXTENSION_DIRS[@]}"; do + printf '%s\n' "$EXTENSION_JSON" | install -D -m 0644 /dev/stdin "$dir/$EXTENSION_ID.json" + done +elif [[ -t 0 ]]; then + exec sudo "$PACKAGED_PATH" +else + exec pkexec "$PACKAGED_PATH" +fi diff --git a/manual/17-ai.md b/manual/17-ai.md index 8c3d48b0..7f76d481 100644 --- a/manual/17-ai.md +++ b/manual/17-ai.md @@ -26,6 +26,8 @@ To wrap an additional CLI the same way, run `omarchy-mise-install [com Pick your default agent with `omarchy default agent ` 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. +Choosing Claude also sets up its browser extension for Chromium, Chrome, Brave, Brave Origin, and Edge, and enables browser integration when launched through `omarchy agent`. The extension setup applies to all users and may ask for your system password; cancelling leaves your previous default agent selected. Restart your browser, enable the extension if prompted, and sign in to Claude to finish connecting it. Run `/chrome` in Claude to check the connection. Firefox and Zen do not support this extension. If Claude was already your default before this setup was added, select it again to install the extension. + [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. diff --git a/test/shell.d/chromium-claude-test.sh b/test/shell.d/chromium-claude-test.sh new file mode 100644 index 00000000..5d8c61ef --- /dev/null +++ b/test/shell.d/chromium-claude-test.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +# Exercise the privileged installer without writing to the host's /usr/share. +if ! command -v bwrap >/dev/null || ! bwrap --ro-bind / / --unshare-user --uid 0 --gid 0 true 2>/dev/null; then + pass "user namespaces unavailable; skipping isolated Claude extension installation" + exit 0 +fi + +test_tmp=$(mktemp -d) +trap 'rm -rf "$test_tmp"' EXIT +mkdir -p "$test_tmp/share" "$test_tmp/bin" +installer="$ROOT/bin/omarchy-install-chromium-claude" +extension_id=fcoeoabgfenejglbffodgkkbkcdhcgfn +sandbox=(bwrap --ro-bind / / --bind "$test_tmp" "$test_tmp" --dev /dev --proc /proc --unshare-user) + +"${sandbox[@]}" --uid 0 --gid 0 --bind "$test_tmp/share" /usr/share bash "$installer" +for browser in chromium google-chrome microsoft-edge; do + file="$test_tmp/share/$browser/extensions/$extension_id.json" + jq -e '.external_update_url == "https://clients2.google.com/service/update2/crx"' "$file" >/dev/null || + fail "$browser registers the official Claude Web Store extension" + [[ $(stat -c '%a' "$file") == "644" ]] || fail "$browser extension registration is readable" +done +pass "Claude extension installer registers all supported browser families" + +cat >"$test_tmp/bin/pkexec" <<'SH' +#!/bin/bash +printf '%s\n' "$@" >"$AUTH_LOG" +exit 42 +SH +chmod +x "$test_tmp/bin/pkexec" +export AUTH_LOG="$test_tmp/auth-log" +export PATH="$test_tmp/bin:$PATH" + +# A read-only /usr/share and a failing auth stub prove that a repeated run +# neither rewrites the files nor requests authentication. +"${sandbox[@]}" --uid 1000 --gid 1000 --ro-bind "$test_tmp/share" /usr/share bash "$installer" "$mock_bin/omarchy-install-chromium-claude" <<'SH' +#!/bin/bash +echo claude-extension >>"$OMARCHY_TEST_STUB_LOG" +[[ ${OMARCHY_TEST_EXTENSION_FAIL:-false} != "true" ]] +SH + cat >"$mock_bin/omarchy-notification-send" <<'SH' #!/bin/bash printf '%s\0' "$@" >>"$OMARCHY_TEST_NOTIFICATION_HISTORY" @@ -406,9 +412,16 @@ declare -A expected_packages=( for selection in "${!expected_agents[@]}"; do expected=${expected_agents[$selection]} : >"$agent_open_log" + : >"$stub_log" OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent "$selection" [[ $(omarchy-default-agent) == $expected ]] || fail "default agent canonicalizes $selection" + if [[ $expected == "claude" ]]; then + grep -qx claude-extension "$stub_log" || fail "Claude selection installs the browser extension" + else + [[ ! -s $stub_log ]] || fail "other agents do not install the Claude extension" + fi + mapfile -d '' -t mise_args <"$mise_log" [[ ${mise_args[0]} == "use" && ${mise_args[1]} == "-g" ]] || fail "default agent installs $selection globally through mise" @@ -427,6 +440,11 @@ pass "default agent selects and opens every supported provider and alias" pass "default agent stores its selection in Omarchy user config" OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent pi +if OMARCHY_TEST_AGENT_INSTALLED=true OMARCHY_TEST_EXTENSION_FAIL=true omarchy-default-agent claude >"$test_tmp/extension-failure" 2>&1; then + fail "Claude selection fails when browser extension installation fails" +fi +[[ $(omarchy-default-agent) == "pi" ]] || fail "extension installation failure preserves the default agent" +pass "extension installation failure preserves the default agent" : >"$notification_history" : >"$agent_open_log" : >"$terminal_log" @@ -644,7 +662,7 @@ assert_launch pi pi "Review this project" assert_launch omp omp --auto-approve -- "Review this project" 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 claude claude --permission-mode auto --chrome -- "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" @@ -672,7 +690,7 @@ assert_bypass pi pi assert_bypass omp omp --auto-approve assert_bypass opencode opencode --auto assert_bypass ori ori code -assert_bypass claude claude --permission-mode auto +assert_bypass claude claude --permission-mode auto --chrome assert_bypass codex codex --approve-for-me assert_bypass muse muse --approval-mode never assert_bypass crush crush --yolo diff --git a/test/shell.d/unowned-system-paths-test.sh b/test/shell.d/unowned-system-paths-test.sh index e2450619..efe940b4 100755 --- a/test/shell.d/unowned-system-paths-test.sh +++ b/test/shell.d/unowned-system-paths-test.sh @@ -31,10 +31,13 @@ allowed = { # them so the hook does not exist where it does not apply. "/usr/lib/systemd/system-sleep", # Written through a variable, so the scan below cannot see them at the point - # they are written. Both drop configuration into another project's tree rather - # than Omarchy's, which is why neither is a candidate for omarchy-settings. + # they are written. These drop configuration into another project's tree + # rather than Omarchy's and are not candidates for omarchy-settings. "/usr/share/chromium/extensions", "/usr/lib/firefox/distribution", + # Claude's extension is registered only when the user selects Claude. + "/usr/share/google-chrome/extensions", + "/usr/share/microsoft-edge/extensions", # Static content that belongs in omarchy-settings. It cannot move there in the # same release that first ships omarchy-update-system-pkgs-when-conflicted: the # upgrade carrying the handler is the one that would hit the conflict, and the From 8fa9f4d03e02411f62772f2defc2b6139e86d222 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 15 Sep 2026 12:38:00 -0400 Subject: [PATCH 2/3] Leave Claude browser integration settings unchanged --- bin/omarchy-agent | 2 +- manual/17-ai.md | 2 +- test/shell.d/default-agent-test.sh | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/omarchy-agent b/bin/omarchy-agent index 23d0e2f3..e35bcf04 100755 --- a/bin/omarchy-agent +++ b/bin/omarchy-agent @@ -75,7 +75,7 @@ crush) fi ;; claude) - command=(claude --permission-mode auto --chrome) + command=(claude --permission-mode auto) [[ -n ${prompt:-} ]] && command+=(-- "$prompt") ;; grok) diff --git a/manual/17-ai.md b/manual/17-ai.md index 7f76d481..24ade4f4 100644 --- a/manual/17-ai.md +++ b/manual/17-ai.md @@ -26,7 +26,7 @@ To wrap an additional CLI the same way, run `omarchy-mise-install [com Pick your default agent with `omarchy default agent ` 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. -Choosing Claude also sets up its browser extension for Chromium, Chrome, Brave, Brave Origin, and Edge, and enables browser integration when launched through `omarchy agent`. The extension setup applies to all users and may ask for your system password; cancelling leaves your previous default agent selected. Restart your browser, enable the extension if prompted, and sign in to Claude to finish connecting it. Run `/chrome` in Claude to check the connection. Firefox and Zen do not support this extension. If Claude was already your default before this setup was added, select it again to install the extension. +Choosing Claude also sets up its browser extension for Chromium, Chrome, Brave, Brave Origin, and Edge. The extension setup applies to all users and may ask for your system password; cancelling leaves your previous default agent selected. Restart your browser, enable the extension if prompted, and sign in to Claude to finish connecting it. Run `/chrome` in Claude to check the connection. Firefox and Zen do not support this extension. If Claude was already your default before this setup was added, select it again to install the extension. [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. diff --git a/test/shell.d/default-agent-test.sh b/test/shell.d/default-agent-test.sh index 1ce05582..7fd06093 100644 --- a/test/shell.d/default-agent-test.sh +++ b/test/shell.d/default-agent-test.sh @@ -662,7 +662,7 @@ assert_launch pi pi "Review this project" assert_launch omp omp --auto-approve -- "Review this project" 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 --chrome -- "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" @@ -690,7 +690,7 @@ assert_bypass pi pi assert_bypass omp omp --auto-approve assert_bypass opencode opencode --auto assert_bypass ori ori code -assert_bypass claude claude --permission-mode auto --chrome +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 From 677e69d4f13e90ee83251d75e7839f76532f97bc Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 15 Sep 2026 12:40:25 -0400 Subject: [PATCH 3/3] Make Claude browser extension installation best effort --- bin/omarchy-default-agent | 5 ++--- manual/17-ai.md | 2 +- test/shell.d/default-agent-test.sh | 18 ++++++++++++------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/bin/omarchy-default-agent b/bin/omarchy-default-agent index 8c14a4f2..eb2ef7fb 100755 --- a/bin/omarchy-default-agent +++ b/bin/omarchy-default-agent @@ -86,9 +86,8 @@ if ! agent_install; then exit 1 fi -if [[ $agent == "claude" ]] && ! omarchy-install-chromium-claude; then - echo "Could not install the Claude browser extension" >&2 - exit 1 +if [[ $agent == "claude" ]]; then + omarchy-install-chromium-claude 2>/dev/null || true fi mkdir -p "$(dirname "$agent_file")" diff --git a/manual/17-ai.md b/manual/17-ai.md index 24ade4f4..0d62622d 100644 --- a/manual/17-ai.md +++ b/manual/17-ai.md @@ -26,7 +26,7 @@ To wrap an additional CLI the same way, run `omarchy-mise-install [com Pick your default agent with `omarchy default agent ` 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. -Choosing Claude also sets up its browser extension for Chromium, Chrome, Brave, Brave Origin, and Edge. The extension setup applies to all users and may ask for your system password; cancelling leaves your previous default agent selected. Restart your browser, enable the extension if prompted, and sign in to Claude to finish connecting it. Run `/chrome` in Claude to check the connection. Firefox and Zen do not support this extension. If Claude was already your default before this setup was added, select it again to install the extension. +Choosing Claude also attempts to set up its browser extension for Chromium, Chrome, Brave, Brave Origin, and Edge. The extension setup applies to all users and may ask for your system password; cancelling or a failed extension install still selects and launches Claude. Restart your browser, enable the extension if prompted, and sign in to Claude to finish connecting it. Run `/chrome` in Claude to check the connection. Firefox and Zen do not support this extension. If Claude was already your default before this setup was added, select it again to install the extension. [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. diff --git a/test/shell.d/default-agent-test.sh b/test/shell.d/default-agent-test.sh index 7fd06093..60e630d3 100644 --- a/test/shell.d/default-agent-test.sh +++ b/test/shell.d/default-agent-test.sh @@ -25,7 +25,10 @@ mkdir -p "$mock_bin" "$test_home" cat >"$mock_bin/omarchy-install-chromium-claude" <<'SH' #!/bin/bash echo claude-extension >>"$OMARCHY_TEST_STUB_LOG" -[[ ${OMARCHY_TEST_EXTENSION_FAIL:-false} != "true" ]] +if [[ ${OMARCHY_TEST_EXTENSION_FAIL:-false} == "true" ]]; then + echo "Extension installation failed" >&2 + exit 1 +fi SH cat >"$mock_bin/omarchy-notification-send" <<'SH' @@ -440,11 +443,14 @@ pass "default agent selects and opens every supported provider and alias" pass "default agent stores its selection in Omarchy user config" OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent pi -if OMARCHY_TEST_AGENT_INSTALLED=true OMARCHY_TEST_EXTENSION_FAIL=true omarchy-default-agent claude >"$test_tmp/extension-failure" 2>&1; then - fail "Claude selection fails when browser extension installation fails" -fi -[[ $(omarchy-default-agent) == "pi" ]] || fail "extension installation failure preserves the default agent" -pass "extension installation failure preserves the default agent" +: >"$agent_open_log" +OMARCHY_TEST_AGENT_INSTALLED=true OMARCHY_TEST_EXTENSION_FAIL=true omarchy-default-agent claude >"$test_tmp/extension-failure" 2>&1 +[[ $(omarchy-default-agent) == "claude" ]] || fail "extension installation failure still selects Claude" +mapfile -d '' -t agent_open_args <"$agent_open_log" +[[ ${agent_open_args[*]} == "omarchy-agent" ]] || fail "extension installation failure still launches Claude" +[[ ! -s $test_tmp/extension-failure ]] || fail "extension installation failure is silent" +pass "extension installation failure silently continues selecting and launching Claude" +OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent pi : >"$notification_history" : >"$agent_open_log" : >"$terminal_log"