<feed xmlns='http://www.w3.org/2005/Atom'>
<title>dotfiles/dot_config/zsh, branch master</title>
<subtitle>My linux config and rc files</subtitle>
<id>https://git.sommerfeld.dev/dotfiles/atom/dot_config/zsh?h=master</id>
<link rel='self' href='https://git.sommerfeld.dev/dotfiles/atom/dot_config/zsh?h=master'/>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/'/>
<updated>2026-06-05T10:06:04Z</updated>
<entry>
<title>Limit git switch completion to local branches</title>
<updated>2026-06-05T10:06:04Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-06-05T10:06:04Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=929f8bea128361822b054db36402b5e19234319f'/>
<id>urn:sha1:929f8bea128361822b054db36402b5e19234319f</id>
<content type='text'>
</content>
</entry>
<entry>
<title>refactor(suspend): drop SSH session inhibit; AC rule handles it</title>
<updated>2026-05-29T10:18:15Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:15Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=45ce3902227fdfe4380d7b956ed89274e04b6ba5'/>
<id>urn:sha1:45ce3902227fdfe4380d7b956ed89274e04b6ba5</id>
<content type='text'>
Same rationale as the previous commit: the new policy is "if you don't
want the machine to sleep, plug it in." An SSH-only inhibit in zprofile
is redundant on AC (logind already ignores the lid) and inconsistent on
battery (it would hold the lock for an SSH-attached idle session,
defeating the schedule).

Also removes a stale doc reference to zellij-inhibit-suspend.path which
no longer exists.
</content>
</entry>
<entry>
<title>feat(suspend): hold inhibit lock while any zellij session exists</title>
<updated>2026-05-29T10:18:13Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:13Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=01df321e907b6c8568bb8622eb44a5c1486a0631'/>
<id>urn:sha1:01df321e907b6c8568bb8622eb44a5c1486a0631</id>
<content type='text'>
The SSH-shell inhibitor in dot_zprofile is bound to the lifetime of the
login shell, so it disappears the moment the user detaches a zellij
session and disconnects — defeating the whole point of using zellij for
persistent remote work.

Add a user-scope path+service+watcher trio that ties the inhibit lock
to the existence of zellij sessions instead:

  - dot_local/bin/executable_zellij-inhibit-watcher
      Polls `zellij list-sessions --short` every 15s, exits when none
      remain. Override poll interval via $ZELLIJ_INHIBIT_POLL.

  - dot_config/systemd/user/zellij-inhibit-suspend.service
      Wraps the watcher in `systemd-inhibit --what=sleep:idle:handle-lid-switch
      --mode=block`. When the watcher exits, the service stops and the
      lock is released.

  - dot_config/systemd/user/zellij-inhibit-suspend.path
      Activates the service whenever $XDG_RUNTIME_DIR/zellij becomes
      non-empty (i.e. zellij creates its first session socket). Re-fires
      on every empty→non-empty transition.

Enable via systemd-units/user.txt (the .path unit; the service is
on-demand).

The existing SSH-shell inhibitor is kept as a backstop for non-zellij
remote sessions and is now documented as such.

VM (nix/vm.nix) deliberately not updated: the Ubuntu remote-dev VM
never suspends, so the inhibit machinery would be inert there.
</content>
</entry>
<entry>
<title>feat(zsh): inhibit suspend while an SSH session is active</title>
<updated>2026-05-29T10:18:13Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-29T10:18:13Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=263f39704ae5e8f44a79d64dce2be048009b4df6'/>
<id>urn:sha1:263f39704ae5e8f44a79d64dce2be048009b4df6</id>
<content type='text'>
A remote session is useless if the laptop suspends mid-command, but
logind doesn't suppress lid-close or idle-suspend for SSH sessions on
its own — you have to hold an explicit inhibitor lock.

When $SSH_CONNECTION is set, re-exec the login shell under
`systemd-inhibit --what=sleep:idle:handle-lid-switch --mode=block`
so the lock is bound to the shell's lifetime: it covers swayidle,
logind's HandleLidSwitch, and any other consumer that respects
inhibit locks, and it's released the moment the SSH session ends.

A guard env var prevents recursion if the user nests a login shell
inside the wrapped one (e.g. `exec zsh -l`).
</content>
</entry>
<entry>
<title>fix(ssh): make agent.sock symlink concurrent-connection-safe</title>
<updated>2026-05-22T09:41:24Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-22T09:41:24Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=982d180f9b9a2f8a90d454816474dce8d4b4b8e2'/>
<id>urn:sha1:982d180f9b9a2f8a90d454816474dce8d4b4b8e2</id>
<content type='text'>
Previously every new login retargeted ~/.ssh/agent.sock to its own
per-connection forwarded socket. That broke a multi-connection setup
when the most-recent connection (which 'won' the symlink) dropped:
all surviving connections' panes would point at a dead socket until a
fresh login from a surviving connection re-ran zprofile.

zprofile: only retarget when the existing symlink target is dead
(sshd unlinks the per-connection socket on disconnect, so [[ -S ]] on
the resolved path is a reliable liveness probe). First connection
seeds the symlink, subsequent logins keep using it.

ssh-agent-refresh: scan /tmp/ssh-*/agent.* for any live forwarded
socket and retarget to the first that responds to ssh-add. Lets the
surviving connection recover without waiting for a new login shell.
</content>
</entry>
<entry>
<title>feat(zsh): recover Arch site-functions + HELPDIR after removing system zsh</title>
<updated>2026-05-22T09:41:24Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-22T09:41:24Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=6b7e057bd4fc2cbdffe5fc8b3095810db1ccf9e3'/>
<id>urn:sha1:6b7e057bd4fc2cbdffe5fc8b3095810db1ccf9e3</id>
<content type='text'>
Switching to nix's zsh on the Arch host left two functional gaps the
Arch zsh package used to fill:

1. /usr/share/zsh/site-functions in fpath: pacman, paru, systemctl,
   journalctl, flatpak, docker, kubectl, makepkg etc. drop their
   completions there. nix zsh's compiled-in fpath doesn't include
   /usr/share so we lose all of them silently. Added that path (and
   vendor-completions for the VM's apt-installed completions) to the
   existing fpath loop, guarded by [[ -d ]].

2. HELPDIR for the run-help / help-alias machinery: needed so 'help cd'
   etc. find the per-builtin help docs. Pick the first existing version
   dir, preferring nix-profile so it matches the running zsh version.
</content>
</entry>
<entry>
<title>fix(nix,zsh): tuicr flake schema + restore XDG_DATA_DIRS</title>
<updated>2026-05-22T09:41:23Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-22T09:41:23Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=a97634f5062088f8d4e6d3c06fdf82a87c157167'/>
<id>urn:sha1:a97634f5062088f8d4e6d3c06fdf82a87c157167</id>
<content type='text'>
tuicr's upstream flake uses the legacy 'defaultPackage.&lt;system&gt;' output
schema, not 'packages.&lt;system&gt;.default' — fixes the home-manager switch
error 'attribute packages missing' at nix/flake.nix:28.

zsh: removing the system zsh package took /etc/zsh/zprofile with it,
which used to 'source /etc/profile' and pull in /etc/profile.d/*.sh
(flatpak.sh, nix.sh, etc.). Reconstruct XDG_DATA_DIRS in dot_zprofile
defensively, including per-user + system flatpak exports + nix-profile
share, so 'flatpak update' stops warning and desktop entries from
flatpak/nix-installed apps work in launchers (fuzzel).
</content>
</entry>
<entry>
<title>fix(ssh): stabilise forwarded ssh-agent socket across reconnects</title>
<updated>2026-05-22T09:41:23Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-22T09:41:23Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=159d69ddd122cfdb55d087d754d7472d42fa73ae'/>
<id>urn:sha1:159d69ddd122cfdb55d087d754d7472d42fa73ae</id>
<content type='text'>
Forwarded SSH_AUTH_SOCK lives at /tmp/ssh-XXX/agent.NNN — a
per-connection path that disappears on disconnect, leaving every
long-running zellij pane (and its children: claude-code, nvim, …)
pointing at a dead socket. Reattaching after reconnect doesn't help:
the env was captured when zellij first started.

Fix: maintain ~/.ssh/agent.sock as a symlink, re-aimed at the live
forwarded socket on every login (zprofile). Export the stable path so
processes inherit a value that survives reconnects — git fetch /
commit signing keep working in re-attached zellij panes with zero
per-pane re-export.

Adds 'ssh-agent-refresh' helper for transitional panes still holding
the dead per-connection path: re-exports SSH_AUTH_SOCK to the stable
symlink and validates with ssh-add -l. Already-running children
(claude-code) must still be restarted since env is inherited, not
observed.
</content>
</entry>
<entry>
<title>feat(zsh): enrich pacopt with reverse-optdep info</title>
<updated>2026-05-22T09:41:21Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-22T09:41:21Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=7212ed8f2e355856b456b0c83e8a1ebe5a62d71d'/>
<id>urn:sha1:7212ed8f2e355856b456b0c83e8a1ebe5a62d71d</id>
<content type='text'>
Promote pacopt from a plain alias to a function. In addition to listing
packages that remain installed solely as someone's optional dependency,
each package is now annotated with its parent(s) and the upstream
reason text from the parent's Optional Deps field.

Implementation is pacman-only (no expac): one awk pass over 'pacman -Qi'
builds a reverse index of every (parent, optdep, reason) edge in the
local DB, then per leaf package the index is filtered for matching deps.
</content>
</entry>
<entry>
<title>refactor(zsh): drop FIRECRAWL_API_KEY export</title>
<updated>2026-05-20T13:01:04Z</updated>
<author>
<name>sommerfeld</name>
<email>sommerfeld@sommerfeld.dev</email>
</author>
<published>2026-05-20T13:01:04Z</published>
<link rel='alternate' type='text/html' href='https://git.sommerfeld.dev/dotfiles/commit/?id=5f5abfb453191c2bd3d1fb6de3a7aa7cc3ad6109'/>
<id>urn:sha1:5f5abfb453191c2bd3d1fb6de3a7aa7cc3ad6109</id>
<content type='text'>
Unused; the pass entry doesn't exist on most machines, so login emitted
'Error: copilot/firecrawl-api-key is not in the password store' on every
shell start. Easier to drop than to gate.
</content>
</entry>
</feed>
