Tools: Migrating to zsh Broke Obsidian Git. (2026)

Tools: Migrating to zsh Broke Obsidian Git. (2026)

Introduction

The Structure of the Problem

Why Did It Work Before?

Attempting gcr-ssh-agent Unification (and Failing)

Signing hangs

Keys resurrect after ssh-add -D

Cleaning up via Seahorse was risky

What Remained Unexplained

Pinning OpenSSH ssh-agent as a systemd User Service

Updating ~/.ssh/config

Normalizing the socket in bash and zsh

Dealing with Flatpak

The Obsidian Git wrapper

Automating Key Loading After Reboot

The .desktop Launcher Trap

The fix: SSH_ASKPASS for a GUI dialog

Overriding the .desktop file

The Final Architecture

Separation of Concerns

Lessons Learned In the previous post, I quit .bashrc and gave bash and zsh separate responsibilities. The terminal environment was clean. The next day, I opened Obsidian and Git sync had stopped. It looked like "switching to zsh broke Obsidian." But the shell wasn't the real culprit.

The ssh-agent's scope simply wasn't reaching GUI applications. This is the record of how I tracked down that cause and fought my way through the Flatpak sandbox to fix it. Checking from the terminal, the SSH keys were visible. Yet Obsidian Git plugin kept asking for a passphrase every single time. The problem broke down like this: In other words, this wasn't a shell configuration problem — it was a login session design problem. A question immediately surfaced: when everything was crammed into .bashrc, Obsidian Git worked fine. Why? The answer turned out to involve GNOME Keyring (gcr). gcr-ssh-agent integrates with the GNOME login session and automatically exposes SSH keys when the login keyring is unlocked. That meant Obsidian had always been talking to gcr directly, without going through the shell at all. It wasn't that passphrases were unnecessary — it was that GNOME Keyring had been silently providing the previously-saved passphrase all along. My first plan was to leverage this mechanism and route everything through gcr. I exposed the gcr socket to the Flatpak Obsidian sandbox. It worked — temporarily. GitHub authentication went through. Then I rebooted. The problem came back. The verbose log showed GitHub was accepting the key. The signing request sent to gcr-ssh-agent was never coming back. gcr was auto-publishing keys from its keyring storage. And that auto-restored state was broken for signing. When I tried to delete SSH key entries in Seahorse (GNOME's keyring manager), I realized it looked like it would delete the actual private key files (~/.ssh/id_ed25519_personal) along with them. That was the end of the gcr unification attempt. I never found the root cause of gcr-ssh-agent's signing hang. Here's what I was able to rule out: This isn't a verdict that gcr-ssh-agent is broken. This problem happened in this environment. Given that, I chose to prioritize determinism and switch to OpenSSH ssh-agent. I decided to manage a plain OpenSSH ssh-agent with a fixed socket path under systemd user. The socket is now pinned at /run/user/1000/ssh-agent.socket. I added explicit IdentityAgent directives so SSH connections don't depend on the current value of SSH_AUTH_SOCK. Added to both .bashrc and .zshrc: Flatpak's Obsidian runs inside its own sandbox. The host socket needs to be explicitly exposed. Since the Obsidian Git plugin uses /app/bin/git inside the Flatpak, I wrapped it. BatchMode=yes is the critical part — it prevents the automated commit/sync process from silently hanging while waiting for a passphrase prompt that can never appear. In the Obsidian Git plugin settings, set Custom Git binary path to /home/rbcn2000/.local/bin/obsidian-git. Unlike gcr, OpenSSH ssh-agent does not restore keys automatically. After a reboot, the agent starts empty. I considered bringing keychain back, but decided against it — it risks creating duplicate agents. Instead, I wrote a minimal script whose only job is loading the keys. Call it from .zshrc and .bashrc on interactive shell startup: Now, the first time a terminal opens after reboot, you enter the passphrase once — and that's it. I thought it was solved. There was one more problem. After a reboot, launching Obsidian first meant Git didn't work. The culprit was the TTY check inside ssh-load-github: When Obsidian launches from a .desktop file, there is no TTY. So ssh-load-github exits immediately, keys never get loaded, and Obsidian starts up with an empty agent. OpenSSH has a built-in mechanism for exactly this situation: SSH_ASKPASS. I wrote a dedicated launcher that uses it: The system-side Flatpak .desktop file can't be edited directly — Flatpak updates would overwrite it. Instead, copy it to the user applications directory and redirect the Exec line. Now, launching Obsidian from the app launcher shows a GTK passphrase dialog first, then starts Obsidian. After a reboot, behavior is now fully symmetric: In the end, the responsibilities around ssh-agent sorted themselves into a clear table: Tools like keychain that handle everything in one shot are convenient, but they make it easy to accidentally create duplicate agents or fail to reach GUI applications. Separating the responsibilities made it clear exactly what was happening at every step. An environment variable is not a "setting" — it is the result of process inheritance. Even if SSH_AUTH_SOCK is correctly set somewhere, it only reaches a child process if that child is spawned from a process that has it. Configuration written in .zshrc simply does not reach GUI applications. That was the root of everything. And an additional lesson: Sometimes a fixed socket with a simple agent is more deterministic than a polished GUI integration. gcr-ssh-agent's desktop integration is elegant. But in this environment, its auto-restore mechanism turned out to be unstable at signing time. A plain OpenSSH ssh-agent on a fixed socket was far more predictable. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to ? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ -weight: 500;">git@github.com: Permission denied (publickey). fatal: Could not read from remote repository. -weight: 500;">git@github.com: Permission denied (publickey). fatal: Could not read from remote repository. -weight: 500;">git@github.com: Permission denied (publickey). fatal: Could not read from remote repository. echo "$SSH_AUTH_SOCK" # /run/user/1000/gcr/ssh ssh-add -l # work-github / personal-github echo "$SSH_AUTH_SOCK" # /run/user/1000/gcr/ssh ssh-add -l # work-github / personal-github echo "$SSH_AUTH_SOCK" # /run/user/1000/gcr/ssh ssh-add -l # work-github / personal-github Terminal (zsh) → OK Obsidian (GUI) → NG Terminal (zsh) → OK Obsidian (GUI) → NG Terminal (zsh) → OK Obsidian (GUI) → NG ssh-agent launched from a shell → only valid within that shell's process tree Obsidian launched by the GUI → never reads .zshrc → never reaches the ssh-agent ssh-agent launched from a shell → only valid within that shell's process tree Obsidian launched by the GUI → never reads .zshrc → never reaches the ssh-agent ssh-agent launched from a shell → only valid within that shell's process tree Obsidian launched by the GUI → never reads .zshrc → never reaches the ssh-agent gcr-ssh-agent → /run/user/1000/gcr/ssh → shared by Terminal / Editor / Obsidian / Flatpak gcr-ssh-agent → /run/user/1000/gcr/ssh → shared by Terminal / Editor / Obsidian / Flatpak gcr-ssh-agent → /run/user/1000/gcr/ssh → shared by Terminal / Editor / Obsidian / Flatpak flatpak override --user \ --filesystem=xdg-run/gcr \ --env=SSH_AUTH_SOCK=/run/user/1000/gcr/ssh \ md.obsidian.Obsidian flatpak override --user \ --filesystem=xdg-run/gcr \ --env=SSH_AUTH_SOCK=/run/user/1000/gcr/ssh \ md.obsidian.Obsidian flatpak override --user \ --filesystem=xdg-run/gcr \ --env=SSH_AUTH_SOCK=/run/user/1000/gcr/ssh \ md.obsidian.Obsidian ssh-add -l # personal-github / work-github → visible ssh -T github-personal # → hangs (no response) ssh-add -l # personal-github / work-github → visible ssh -T github-personal # → hangs (no response) ssh-add -l # personal-github / work-github → visible ssh -T github-personal # → hangs (no response) Offering public key: id_ed25519_personal Server accepts key: id_ed25519_personal signing using ssh-ed25519 ← hangs here Offering public key: id_ed25519_personal Server accepts key: id_ed25519_personal signing using ssh-ed25519 ← hangs here Offering public key: id_ed25519_personal Server accepts key: id_ed25519_personal signing using ssh-ed25519 ← hangs here ssh-add -D # All identities removed. ssh-add -l # personal-github / work-github ← instantly back ssh-add -D # All identities removed. ssh-add -l # personal-github / work-github ← instantly back ssh-add -D # All identities removed. ssh-add -l # personal-github / work-github ← instantly back ~/.ssh/id_ed25519_personal The key files were not corrupted The public keys on GitHub were registered correctly Exposing the Flatpak socket was not the sole cause ~/.ssh/config Host aliases were not misconfigured → gcr-ssh-agent's auto-restored state was unstable at signing time → Root cause: unknown The key files were not corrupted The public keys on GitHub were registered correctly Exposing the Flatpak socket was not the sole cause ~/.ssh/config Host aliases were not misconfigured → gcr-ssh-agent's auto-restored state was unstable at signing time → Root cause: unknown The key files were not corrupted The public keys on GitHub were registered correctly Exposing the Flatpak socket was not the sole cause ~/.ssh/config Host aliases were not misconfigured → gcr-ssh-agent's auto-restored state was unstable at signing time → Root cause: unknown mkdir -p ~/.config/systemd/user cat > ~/.config/systemd/user/ssh-agent.-weight: 500;">service <<'EOF' [Unit] Description=OpenSSH key agent [Service] Type=simple Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket ExecStart=/usr/bin/ssh-agent -D -a %t/ssh-agent.socket [Install] WantedBy=default.target EOF -weight: 500;">systemctl --user daemon-reload -weight: 500;">systemctl --user -weight: 500;">enable --now ssh-agent.-weight: 500;">service mkdir -p ~/.config/systemd/user cat > ~/.config/systemd/user/ssh-agent.-weight: 500;">service <<'EOF' [Unit] Description=OpenSSH key agent [Service] Type=simple Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket ExecStart=/usr/bin/ssh-agent -D -a %t/ssh-agent.socket [Install] WantedBy=default.target EOF -weight: 500;">systemctl --user daemon-reload -weight: 500;">systemctl --user -weight: 500;">enable --now ssh-agent.-weight: 500;">service mkdir -p ~/.config/systemd/user cat > ~/.config/systemd/user/ssh-agent.-weight: 500;">service <<'EOF' [Unit] Description=OpenSSH key agent [Service] Type=simple Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket ExecStart=/usr/bin/ssh-agent -D -a %t/ssh-agent.socket [Install] WantedBy=default.target EOF -weight: 500;">systemctl --user daemon-reload -weight: 500;">systemctl --user -weight: 500;">enable --now ssh-agent.-weight: 500;">service /run/user/1000/ssh-agent.socket ~/.ssh/config IdentityAgent SSH_AUTH_SOCK Host github-personal HostName github.com User -weight: 500;">git IdentityFile ~/.ssh/id_ed25519_personal IdentitiesOnly yes AddKeysToAgent yes IdentityAgent /run/user/1000/ssh-agent.socket Host github-work HostName github.com User -weight: 500;">git IdentityFile ~/.ssh/id_ed25519_work IdentitiesOnly yes AddKeysToAgent yes IdentityAgent /run/user/1000/ssh-agent.socket Host github-personal HostName github.com User -weight: 500;">git IdentityFile ~/.ssh/id_ed25519_personal IdentitiesOnly yes AddKeysToAgent yes IdentityAgent /run/user/1000/ssh-agent.socket Host github-work HostName github.com User -weight: 500;">git IdentityFile ~/.ssh/id_ed25519_work IdentitiesOnly yes AddKeysToAgent yes IdentityAgent /run/user/1000/ssh-agent.socket Host github-personal HostName github.com User -weight: 500;">git IdentityFile ~/.ssh/id_ed25519_personal IdentitiesOnly yes AddKeysToAgent yes IdentityAgent /run/user/1000/ssh-agent.socket Host github-work HostName github.com User -weight: 500;">git IdentityFile ~/.ssh/id_ed25519_work IdentitiesOnly yes AddKeysToAgent yes IdentityAgent /run/user/1000/ssh-agent.socket # OpenSSH ssh-agent (shared between .bashrc and .zshrc) if [ -S "$XDG_RUNTIME_DIR/ssh-agent.socket" ]; then export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket" fi # OpenSSH ssh-agent (shared between .bashrc and .zshrc) if [ -S "$XDG_RUNTIME_DIR/ssh-agent.socket" ]; then export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket" fi # OpenSSH ssh-agent (shared between .bashrc and .zshrc) if [ -S "$XDG_RUNTIME_DIR/ssh-agent.socket" ]; then export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket" fi flatpak override --user \ --filesystem=xdg-run/ssh-agent.socket \ --env=SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket \ md.obsidian.Obsidian # Remove gcr access flatpak override --user \ --nofilesystem=xdg-run/gcr \ md.obsidian.Obsidian flatpak override --user \ --filesystem=xdg-run/ssh-agent.socket \ --env=SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket \ md.obsidian.Obsidian # Remove gcr access flatpak override --user \ --nofilesystem=xdg-run/gcr \ md.obsidian.Obsidian flatpak override --user \ --filesystem=xdg-run/ssh-agent.socket \ --env=SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket \ md.obsidian.Obsidian # Remove gcr access flatpak override --user \ --nofilesystem=xdg-run/gcr \ md.obsidian.Obsidian /app/bin/-weight: 500;">git cat > ~/.local/bin/obsidian--weight: 500;">git <<'EOF' #!/usr/bin/env bash SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" export GIT_SSH_COMMAND="ssh \ -F /home/rbcn2000/.ssh/config \ -o IdentityAgent=$SOCK \ -o BatchMode=yes \ -o ConnectTimeout=10 \ -o ServerAliveInterval=5 \ -o ServerAliveCountMax=1" exec /app/bin/-weight: 500;">git "$@" EOF chmod +x ~/.local/bin/obsidian--weight: 500;">git cat > ~/.local/bin/obsidian--weight: 500;">git <<'EOF' #!/usr/bin/env bash SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" export GIT_SSH_COMMAND="ssh \ -F /home/rbcn2000/.ssh/config \ -o IdentityAgent=$SOCK \ -o BatchMode=yes \ -o ConnectTimeout=10 \ -o ServerAliveInterval=5 \ -o ServerAliveCountMax=1" exec /app/bin/-weight: 500;">git "$@" EOF chmod +x ~/.local/bin/obsidian--weight: 500;">git cat > ~/.local/bin/obsidian--weight: 500;">git <<'EOF' #!/usr/bin/env bash SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" export GIT_SSH_COMMAND="ssh \ -F /home/rbcn2000/.ssh/config \ -o IdentityAgent=$SOCK \ -o BatchMode=yes \ -o ConnectTimeout=10 \ -o ServerAliveInterval=5 \ -o ServerAliveCountMax=1" exec /app/bin/-weight: 500;">git "$@" EOF chmod +x ~/.local/bin/obsidian--weight: 500;">git BatchMode=yes Custom Git binary path /home/rbcn2000/.local/bin/obsidian--weight: 500;">git cat > ~/.local/bin/ssh-load-github <<'EOF' #!/usr/bin/env bash set -u SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" if [ ! -S "$SOCK" ]; then -weight: 500;">systemctl --user -weight: 500;">start ssh-agent.-weight: 500;">service 2>/dev/null || true fi if [ ! -S "$SOCK" ]; then echo "ssh-agent socket not found: $SOCK" >&2 exit 1 fi # Don't wait for passphrase input in non-interactive environments if [ ! -t 0 ]; then exit 0 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'personal-github'; then ssh-add "$HOME/.ssh/id_ed25519_personal" || exit 1 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'work-github'; then ssh-add "$HOME/.ssh/id_ed25519_work" || exit 1 fi EOF chmod +x ~/.local/bin/ssh-load-github cat > ~/.local/bin/ssh-load-github <<'EOF' #!/usr/bin/env bash set -u SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" if [ ! -S "$SOCK" ]; then -weight: 500;">systemctl --user -weight: 500;">start ssh-agent.-weight: 500;">service 2>/dev/null || true fi if [ ! -S "$SOCK" ]; then echo "ssh-agent socket not found: $SOCK" >&2 exit 1 fi # Don't wait for passphrase input in non-interactive environments if [ ! -t 0 ]; then exit 0 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'personal-github'; then ssh-add "$HOME/.ssh/id_ed25519_personal" || exit 1 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'work-github'; then ssh-add "$HOME/.ssh/id_ed25519_work" || exit 1 fi EOF chmod +x ~/.local/bin/ssh-load-github cat > ~/.local/bin/ssh-load-github <<'EOF' #!/usr/bin/env bash set -u SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" if [ ! -S "$SOCK" ]; then -weight: 500;">systemctl --user -weight: 500;">start ssh-agent.-weight: 500;">service 2>/dev/null || true fi if [ ! -S "$SOCK" ]; then echo "ssh-agent socket not found: $SOCK" >&2 exit 1 fi # Don't wait for passphrase input in non-interactive environments if [ ! -t 0 ]; then exit 0 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'personal-github'; then ssh-add "$HOME/.ssh/id_ed25519_personal" || exit 1 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'work-github'; then ssh-add "$HOME/.ssh/id_ed25519_work" || exit 1 fi EOF chmod +x ~/.local/bin/ssh-load-github if [[ $- == *i* ]] && [ -t 0 ] && [ "${SSH_LOAD_GITHUB_ON_SHELL:-1}" = "1" ]; then "$HOME/.local/bin/ssh-load-github" 2>/dev/null || true fi if [[ $- == *i* ]] && [ -t 0 ] && [ "${SSH_LOAD_GITHUB_ON_SHELL:-1}" = "1" ]; then "$HOME/.local/bin/ssh-load-github" 2>/dev/null || true fi if [[ $- == *i* ]] && [ -t 0 ] && [ "${SSH_LOAD_GITHUB_ON_SHELL:-1}" = "1" ]; then "$HOME/.local/bin/ssh-load-github" 2>/dev/null || true fi ssh-load-github if [ ! -t 0 ]; then exit 0 # No TTY → do nothing fi if [ ! -t 0 ]; then exit 0 # No TTY → do nothing fi if [ ! -t 0 ]; then exit 0 # No TTY → do nothing fi ssh-load-github SSH_ASKPASS -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install ssh-askpass-gnome -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install ssh-askpass-gnome -weight: 600;">sudo -weight: 500;">apt -weight: 500;">install ssh-askpass-gnome cat > ~/.local/bin/open-obsidian <<'EOF' #!/usr/bin/env bash SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" if [ ! -S "$SOCK" ]; then -weight: 500;">systemctl --user -weight: 500;">start ssh-agent.-weight: 500;">service 2>/dev/null || true fi if [ ! -S "$SOCK" ]; then echo "ssh-agent socket not found: $SOCK" >&2 exit 1 fi # Accept passphrase input via GTK dialog even without a TTY export SSH_ASKPASS="/usr/lib/openssh/gnome-ssh-askpass" export SSH_ASKPASS_REQUIRE=force CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'personal-github'; then ssh-add "$HOME/.ssh/id_ed25519_personal" || exit 1 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'work-github'; then ssh-add "$HOME/.ssh/id_ed25519_work" || exit 1 fi exec flatpak run md.obsidian.Obsidian "$@" EOF chmod +x ~/.local/bin/open-obsidian cat > ~/.local/bin/open-obsidian <<'EOF' #!/usr/bin/env bash SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" if [ ! -S "$SOCK" ]; then -weight: 500;">systemctl --user -weight: 500;">start ssh-agent.-weight: 500;">service 2>/dev/null || true fi if [ ! -S "$SOCK" ]; then echo "ssh-agent socket not found: $SOCK" >&2 exit 1 fi # Accept passphrase input via GTK dialog even without a TTY export SSH_ASKPASS="/usr/lib/openssh/gnome-ssh-askpass" export SSH_ASKPASS_REQUIRE=force CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'personal-github'; then ssh-add "$HOME/.ssh/id_ed25519_personal" || exit 1 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'work-github'; then ssh-add "$HOME/.ssh/id_ed25519_work" || exit 1 fi exec flatpak run md.obsidian.Obsidian "$@" EOF chmod +x ~/.local/bin/open-obsidian cat > ~/.local/bin/open-obsidian <<'EOF' #!/usr/bin/env bash SOCK="/run/user/1000/ssh-agent.socket" export SSH_AUTH_SOCK="$SOCK" if [ ! -S "$SOCK" ]; then -weight: 500;">systemctl --user -weight: 500;">start ssh-agent.-weight: 500;">service 2>/dev/null || true fi if [ ! -S "$SOCK" ]; then echo "ssh-agent socket not found: $SOCK" >&2 exit 1 fi # Accept passphrase input via GTK dialog even without a TTY export SSH_ASKPASS="/usr/lib/openssh/gnome-ssh-askpass" export SSH_ASKPASS_REQUIRE=force CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'personal-github'; then ssh-add "$HOME/.ssh/id_ed25519_personal" || exit 1 fi CURRENT_KEYS="$(ssh-add -l 2>/dev/null || true)" if ! printf '%s\n' "$CURRENT_KEYS" | grep -q 'work-github'; then ssh-add "$HOME/.ssh/id_ed25519_work" || exit 1 fi exec flatpak run md.obsidian.Obsidian "$@" EOF chmod +x ~/.local/bin/open-obsidian cp /var/lib/flatpak/exports/share/applications/md.obsidian.Obsidian.desktop \ ~/.local/share/applications/md.obsidian.Obsidian.desktop sed -i 's|^Exec=.*|Exec=/home/rbcn2000/.local/bin/open-obsidian %U|' \ ~/.local/share/applications/md.obsidian.Obsidian.desktop -weight: 500;">update-desktop-database ~/.local/share/applications/ cp /var/lib/flatpak/exports/share/applications/md.obsidian.Obsidian.desktop \ ~/.local/share/applications/md.obsidian.Obsidian.desktop sed -i 's|^Exec=.*|Exec=/home/rbcn2000/.local/bin/open-obsidian %U|' \ ~/.local/share/applications/md.obsidian.Obsidian.desktop -weight: 500;">update-desktop-database ~/.local/share/applications/ cp /var/lib/flatpak/exports/share/applications/md.obsidian.Obsidian.desktop \ ~/.local/share/applications/md.obsidian.Obsidian.desktop sed -i 's|^Exec=.*|Exec=/home/rbcn2000/.local/bin/open-obsidian %U|' \ ~/.local/share/applications/md.obsidian.Obsidian.desktop -weight: 500;">update-desktop-database ~/.local/share/applications/ systemd user ↓ OpenSSH ssh-agent.-weight: 500;">service ↓ /run/user/1000/ssh-agent.socket ├─ bash / zsh (ssh-load-github on shell startup) ├─ ~/.ssh/config (IdentityAgent explicit) └─ ~/.local/bin/open-obsidian ← launched from .desktop └─ SSH_ASKPASS=gnome-ssh-askpass (GTK dialog) ↓ Flatpak Obsidian ↓ ~/.local/bin/obsidian--weight: 500;">git (BatchMode=yes) ↓ /app/bin/-weight: 500;">git systemd user ↓ OpenSSH ssh-agent.-weight: 500;">service ↓ /run/user/1000/ssh-agent.socket ├─ bash / zsh (ssh-load-github on shell startup) ├─ ~/.ssh/config (IdentityAgent explicit) └─ ~/.local/bin/open-obsidian ← launched from .desktop └─ SSH_ASKPASS=gnome-ssh-askpass (GTK dialog) ↓ Flatpak Obsidian ↓ ~/.local/bin/obsidian--weight: 500;">git (BatchMode=yes) ↓ /app/bin/-weight: 500;">git systemd user ↓ OpenSSH ssh-agent.-weight: 500;">service ↓ /run/user/1000/ssh-agent.socket ├─ bash / zsh (ssh-load-github on shell startup) ├─ ~/.ssh/config (IdentityAgent explicit) └─ ~/.local/bin/open-obsidian ← launched from .desktop └─ SSH_ASKPASS=gnome-ssh-askpass (GTK dialog) ↓ Flatpak Obsidian ↓ ~/.local/bin/obsidian--weight: 500;">git (BatchMode=yes) ↓ /app/bin/-weight: 500;">git Opening a terminal first: → ssh-load-github runs → passphrase entered once → shared across bash / zsh / Obsidian for the rest of the session Opening Obsidian first: → open-obsidian runs → GTK dialog prompts for passphrase → shared across bash / zsh / Obsidian for the rest of the session Opening a terminal first: → ssh-load-github runs → passphrase entered once → shared across bash / zsh / Obsidian for the rest of the session Opening Obsidian first: → open-obsidian runs → GTK dialog prompts for passphrase → shared across bash / zsh / Obsidian for the rest of the session Opening a terminal first: → ssh-load-github runs → passphrase entered once → shared across bash / zsh / Obsidian for the rest of the session Opening Obsidian first: → open-obsidian runs → GTK dialog prompts for passphrase → shared across bash / zsh / Obsidian for the rest of the session ssh-agent.-weight: 500;">service SSH_AUTH_SOCK IdentityAgent ssh-load-github open-obsidian SSH_ASKPASS BatchMode=yes SSH_AUTH_SOCK