Set up browser integration when choosing Claude

This commit is contained in:
David Heinemeier Hansson committed 2026-09-15 08:10:58 -04:00
1 parent 47de63290f
commit 45e32c8c2d
7 files changed
+126 -5

No files matched your search

+1 -1
View File
@@ -75,7 +75,7 @@ crush)
fi
;;
claude)
command=(claude --permission-mode auto)
command=(claude --permission-mode auto --chrome)
[[ -n ${prompt:-} ]] && command+=(-- "$prompt")
;;
grok)
+5
View File
@@ -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"
+43
View File
@@ -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
+2
View File
@@ -26,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.
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.
+50
View File
@@ -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" </dev/null
[[ ! -e $AUTH_LOG ]] || fail "configured Claude extensions need no authentication"
pass "configured Claude extensions need neither writes nor authentication"
rm "$test_tmp/share/google-chrome/extensions/$extension_id.json"
status=0
"${sandbox[@]}" --uid 1000 --gid 1000 --ro-bind "$test_tmp/share" /usr/share bash "$installer" </dev/null || status=$?
[[ $status == 42 ]] || fail "Claude extension installer propagates authentication failure"
[[ $(cat "$AUTH_LOG") == "/usr/bin/omarchy-install-chromium-claude" ]] ||
fail "menu installation elevates only the packaged installer"
pass "missing registration uses pkexec and propagates authentication failure"
+20 -2
View File
@@ -22,6 +22,12 @@ menu_log="$test_tmp/menu"
muse_login_log="$test_tmp/muse-login"
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" ]]
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
+5 -2
View File
@@ -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