| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
New, simpler suspend policy:
AC plugged in -> never auto-suspends (lid close ignored, idle no-op)
On battery only -> lid close suspends, swayidle suspends at 30 min idle
This replaces the SSH/zellij-aware inhibit machinery with a rule that
matches the user's mental model: if you don't want the machine to
sleep, plug it in. Long-running tasks (builds, downloads, SSH
sessions, headless services) just need AC.
Changes:
* etc/systemd/logind.conf.d/20-lid-ac.conf: set
HandleLidSwitchExternalPower=ignore so logind itself handles the AC
case at the source. No userspace daemon, no race, no rate-limit risk.
* dot_local/bin/on-battery-suspend: tiny POSIX wrapper that exits 0
when any /sys/class/power_supply/{AC,ADP}*/online == 1, else execs
`systemctl suspend`.
* dot_config/systemd/user/swayidle.service: add
`timeout 1800 on-battery-suspend`. Idle suspend now exists, but only
when on battery.
* Delete zellij-inhibit-suspend.{path,service} + watcher script and
remove the entry from systemd-units/user.txt. The .path
re-trigger storm bug is moot because the whole mechanism is gone.
Manual suspends (sway XF86Sleep keybind, sway power submode `s`,
`systemctl suspend` over SSH) still always work regardless of AC --
explicit user intent wins.
Also drop /migrate-podman-to-btrfs.sh from .gitignore; the one-off
migration script has been deleted now that the user has switched their
podman storage to the btrfs driver.
On-host steps to apply:
chezmoi apply -v
systemctl --user daemon-reload
systemctl --user reset-failed zellij-inhibit-suspend.service zellij-inhibit-suspend.path || true
systemctl --user stop zellij-inhibit-suspend.path zellij-inhibit-suspend.service || true
systemctl --user disable zellij-inhibit-suspend.path || true
systemctl --user restart swayidle.service
# logind drop-in is reloaded automatically by the etc deploy script.
Verify:
systemctl status systemd-logind | grep -i lid
loginctl show-session $XDG_SESSION_ID | grep -i lid
# Unplug AC -> close lid -> should suspend.
# Plug AC -> close lid -> nothing happens.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The previous watcher exited immediately whenever no SSH-spawned zellij
was present. That caused a start-rate-limit storm:
.path triggers service (zellij dir non-empty)
-> watcher exits because no SSH zellij
-> service stops
-> .path retriggers (zellij dir still non-empty)
-> ... 5 starts in 10s, systemd stops the path unit
-> no inhibitor ever again, even after you SSH in
Restructure so the watcher stays alive for the entire zellij socket
directory lifetime and acquires/releases its own systemd-inhibit lock
dynamically based on SSH-zellij presence:
* Watcher now polls and exits only when the zellij socket dir is empty,
matching the .path's trigger condition so it never re-fires while
zellij is alive.
* systemd-inhibit removed from ExecStart - watcher self-inhibits via a
child 'systemd-inhibit ... sleep infinity' it can terminate on demand.
* StartLimitIntervalSec=0 on the service as belt-and-braces against
any future regression of the cycle.
Recovery from the rate-limit hit:
systemctl --user reset-failed zellij-inhibit-suspend.service zellij-inhibit-suspend.path
systemctl --user daemon-reload
systemctl --user restart zellij-inhibit-suspend.path
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A local zellij session (sway terminal, attended) shouldn't keep the
laptop awake — that's the user actively in front of the machine, and
normal suspend behaviour should apply. Only zellij sessions that were
spawned from an SSH context need the persistent inhibit, so detach +
disconnect leaves the host awake until the session ends.
Use /proc/<pid>/environ to detect SSH-spawned zellij: the daemonised
zellij server is exec'd by the client and Linux preserves the exec-time
environment for the life of the process, so SSH_CONNECTION= survives
the SSH session closing. Walk every running `zellij` pid; hold the
lock as long as at least one of them has SSH_CONNECTION in its environ.
The .path unit still fires on every zellij socket creation, but if no
SSH-spawned zellij exists the watcher exits immediately and the service
stops with no harm done — a couple of cheap process spawns per local
session start, no inhibitor side-effects.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
These three tools are the native (non-flatpak) network parsers in the
install set — every other internet-facing app is already flatpak'd. The
threat model is a RCE in a subtitle/extractor/muxer that walks $HOME
looking for SSH keys, GPG keyring, pass store, cloud tokens, etc.
Approach (defence in depth, not full sandboxing):
- bwrap --bind / / keeps Wayland, PipeWire, DBus, GPU, hwaccel and all
config files working transparently.
- --tmpfs over known-sensitive dirs (.ssh, .gnupg, .password-store,
.config/gh, .config/op, .aws, .local/share/keyrings) blanks them
from the sandbox view; a compromised parser literally cannot see them.
- inner PATH stripped of ~/.local/bin so streamlink's spawn of `mpv`
resolves to /usr/bin/mpv and does not re-enter the sandbox.
- --die-with-parent + --new-session for tidy lifecycle.
- Escape hatch: SANDBOX=0 mpv ... bypasses for one invocation.
- Graceful degradation if bwrap is missing (warns and execs anyway).
bubblewrap added explicitly to meta/base.txt (was implicit via flatpak).
Wrappers in ~/.local/bin shadow /usr/bin via dot_zprofile:15 PATH order.
Not symlinked into the Ubuntu VM (nix/vm.nix does not touch ~/.local/bin),
which is fine: those tools on the headless VM don't need sandboxing.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
User confirms snx-rs's SAML loopback no longer needs chromium routing.
Remove:
- dot_local/bin/snxctl-chromium (PATH-override wrapper)
- dot_local/share/snx-rs/bin/xdg-open (chromium shim)
- snx-rs LibreWolf SAML note in user-overrides.js
The waybar snx-vpn toggle now just runs `snxctl connect` detached,
no wrapper indirection.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
snx-rs.service is a system unit, not --user, so the prior approach of
overriding the daemon's PATH via a systemd drop-in could never apply.
And it wasn't needed anyway: snxctl itself runs opener::open(url)
in-process, so prepending the shim dir to snxctl's PATH is enough.
- Drop dot_config/systemd/user/snx-rs.service.d/10-chromium-saml.conf.
- snxctl-chromium now just sets PATH and exec's snxctl connect.
- xdg-open shim no longer forces --new-window so chromium can reuse a
warm window (faster SAML round-trip).
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
systemd/user/teams-{sii,xsight}.service: autostart both Teams flatpak
profiles on sway-session.target login. KillMode=mixed so SIGTERM hits
only the wrapper process — both instances share the same flatpak app
id, so killing by app id would take down the sibling instance. A 15s
SIGKILL fallback covers the case where Electron tray-hides instead of
quitting. Both units listed in systemd-units/user.txt.
etc/pacman.conf: IgnorePkg = llama-cpp-vulkan. The AUR package rebuilds
on every llama.cpp commit (multi-hour build). Update manually with
`paru -S llama-cpp-vulkan` when intended.
snxctl-chromium wrapper:
- dot_local/share/snx-rs/bin/xdg-open: shim that flatpak-runs
ungoogled-chromium, used only by snx-rs.
- dot_config/systemd/user/snx-rs.service.d/10-chromium-saml.conf:
drop-in prepending that dir to the daemon's PATH so snx-rs's
opener-crate call to xdg-open lands in chromium, without affecting
xdg-open for any other process.
- dot_local/bin/snxctl-chromium: convenience wrapper that
daemon-reloads and restarts snx-rs.service if the drop-in isn't yet
applied, then execs `snxctl connect`.
firefox/user-overrides.js: revert the dom.security.https_only_mode.
upgrade_local and network.lna.local-network-to-localhost.skip-checks
prefs — they didn't actually fix the SAML flow. Replaced with a
comment pointing to the wrapper instead.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Adds two generated 256x256 hicolor PNG icons under
~/.local/share/icons/hicolor/256x256/apps/ and wires them up:
* Icon=teams-{sii,xsight} -> launcher / waybar / sway use them
* --appIcon=<absolute path> -> electron tray icon picks them up
(teams-for-linux respects this flag)
The flatpak override script gains a --filesystem=xdg-data/icons:ro
binding for com.github.IsmaelMartinez.teams_for_linux so the absolute
icon path is reachable from inside the sandbox.
|
| |
|
|
|
|
|
|
|
|
|
| |
Two flatpak-tailored .desktop entries that run separate isolated instances
of teams-for-linux via --class / --user-data-dir / --appTitle. Profile
data lives under $HOME/.var/app/<id>/config/profile-{sii,xsight}/ which
is always sandbox-writable.
The upstream flatpak .desktop is shadowed by an XDG_DATA_HOME entry of
the same basename with NoDisplay=Hidden=true so only the two profile
launchers appear in fuzzel.
|
| |
|
|
|
|
|
| |
Pre-existing whitespace/style drift caught by `just check`. Touch
nothing semantic — pure formatter output (shfmt -i 2 -ci -s, ruff,
prettier, taplo). Excludes dot_config/clangd/config.yaml whose manual
indentation is intentionally preserved.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
doas's one-shot password and absent 'sudo -v' kept wasting hour-long
paru AUR builds. sudo-rs is a memory-safe Rust rewrite (ISRG/Ferrous
Systems), drop-in CLI compatible, and the same one Ubuntu 25.10 ships
as default. We follow the Arch wiki 'Using sudo-rs without the sudo
package' recipe verbatim — no custom shims.
- meta/base.txt: -doas-sudo-shim +sudo-rs
- etc/sudoers-rs (mode 0440): wiki minimal config + NOPASSWD reboot/poweroff
- etc/pam.d/sudo: 4-line copy of upstream sudo's PAM file
- run_onchange_after_deploy-etc.sh.tmpl: use real sudo, deploy sudoers-rs
at 0440, create /etc/pam.d/sudo-i and /usr/local/bin/{sudo,sudoedit,
su,visudo} → sudo-rs symlinks idempotently
- delete etc/doas.conf, dot_local/bin/{doasedit,sudo}
- zshrc: drop sudo=doas/sudoedit=doasedit aliases; rewrite ss/gimme/
pacdiff/ssys to call sudo
- justfile: s/doas/sudo/g (status/diff/restore helpers)
- nvim: rename :DoasWrite → :SudoWrite (uses sudo -S)
- sway config: reboot/poweroff buttons call sudo
- bootstrap.sh: update step-5 comment
- README/KEYBINDS/copilot-instructions: flip the privesc convention
No Defaults overrides: sudo's defaults (passwd_tries=3,
timestamp_timeout=5) already fix the doas pain, and paru SudoLoop
(kept) refreshes the 5-min window via real sudo -v.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The packaged doas-sudo-shim is just 'exec doas "$@"', which means
'sudo -v' (used by paru --sudoloop to keep the auth timestamp fresh
during long AUR builds) hits doas, which doesn't implement -v, and
the loop dies. Then when the build finally finishes and tries the real
install, the cached timestamp has long expired, so we reprompt — and
opendoas only allows one attempt before bailing, so a single mistype
throws an hour of compilation away.
Replace it (per-user, via $HOME/.local/bin precedence) with a shim
that translates:
-v -> doas true (refresh persist timestamp)
-k / -K -> doas -L (clear)
-E -H -i -S etc -> dropped (no doas equivalent)
rest -> doas "$@"
Then enable SudoLoop in paru.conf so the timestamp stays fresh.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Move LibreWolf from native librewolf-bin to Flathub
io.gitlab.librewolf-community. Bubblewrap isolates the browser from
$HOME (\\.ssh, password-store, gnupg, ssh-agent socket) at the cost
of namespace chroot + IPC/network namespace isolation between content
processes (mozilla bug 1756236, P3, considered defense-in-depth).
seccomp-bpf — the dominant sandbox layer — is preserved.
- meta/flatpak.txt: + io.gitlab.librewolf-community
- meta/browser.txt: - librewolf-bin
- run_onchange_after_deploy-firefox.sh.tmpl: profile path moves to
~/.var/app/io.gitlab.librewolf-community/.librewolf
- dot_config/mimeapps.list: librewolf.desktop -> flatpak app id
- dot_local/bin/executable_linkhandler: flatpak run wrapper
- README.md: blurb + new profile path
arkenfox-user.js + chezmoi user-overrides.js deploy keep working
unchanged because the flatpak profile is still on the host fs.
|
| |
|
|
|
|
|
|
|
|
| |
large-v3-turbo-q5_0 ran ~1-2x realtime on the T490's CPU, making
push-to-talk feel sluggish. The base multilingual model is ~142 MB
(vs 547 MB) and runs ~7-10x realtime, dropping perceived latency on
short utterances from a few seconds to near-instant.
Quality on short EN/PT dictation remains usable; bump WHISPER_MODEL
to small or large-v3-turbo if accuracy matters more than latency.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Push-to-talk dictation toggle on Super+i: parecord captures 16 kHz mono
WAV, whisper-cli transcribes (auto language), output is typed via wtype
and copied to the clipboard.
Region OCR on Super+Shift+o: slurp + grim feed tesseract (eng+por),
result lands in the clipboard with a notification preview.
Adds wtype to wayland.txt; tesseract (+eng/por data) and whisper.cpp +
the large-v3-turbo-q5_0 model package to extra.txt.
|
| |
|
|
|
|
|
|
|
| |
Remove aerc, khal, khard, vdirsyncer from meta/mail.txt and delete their
configs (aerc/, vdirsyncer systemd override, aerc .desktop handler).
Point linkhandler mailto at xdg-open until a GUI client is set up.
Add systemd user unit for protonmail-bridge --noninteractive, tied to
graphical-session.target so it starts with the sway session.
|
| |
|
|
|
|
|
| |
Track /etc/kernel/cmdline and enable default_uki/fallback_uki in
linux.preset. Remove create-efi helper (UKI is self-contained; only
needed once at install time). Update bootstrap to print the one-off
efibootmgr command instead of launching create-efi.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Sway's XWayland is lazy — DISPLAY isn't set in sway's env until the
first X client connects, which means systemctl/dbus import-environment
runs too early and nothing downstream sees DISPLAY.
Setting DISPLAY=:0 in zprofile before 'exec sway' ensures sway itself
inherits it, and therefore so do all its child processes (terminals,
scripts, systemd user services via import-environment). XWayland will
spawn on demand when a client actually connects to :0.
Also drop the redundant fallback from rqr now that the session-wide
export covers it.
|
| |
|
|
|
|
|
|
|
|
|
| |
zbarcam needs an X11 display for the live camera preview, which sway
provides via XWayland. Two changes to make that reliable:
- sway/config: add DISPLAY to the systemd/dbus user-environment imports,
so anything launched through those paths (not just direct sway execs)
can reach XWayland.
- rqr: default DISPLAY to :0 (sway's default XWayland socket) when
unset, as a belt-and-suspenders fallback.
|
| |
|
|
|
|
|
| |
zbarcam defaults to opening an X11 preview window, which fails on Sway
without XWayland ("unable to open X display"). --nodisplay runs the
scanner headlessly; we don't need the preview since -1 exits on the
first barcode anyway.
|
| |
|
|
|
|
|
|
|
|
| |
Inline directives for cases where the linter's shell/language dialect
doesn't match reality:
- init.lua: _G.P helper is intentional
- dot_zprofile: zsh tied arrays, $+commands, optional sourcing
- dot_zshrc: zsh brace-group-as-function-body
- ipython_config: 'c' is injected by IPython at load time
- doasedit: /bin/sh on Arch is bash, -O test is supported
|
| | |
|
| |
|
|
|
| |
Aligned with the other personal scripts; chezmoi will deploy it as
~/.local/bin/create-efi (executable, no .sh extension).
|
|
|
Rename home/ contents to chezmoi naming conventions:
- dot_ prefix for dotfiles and dot-dirs
- private_dot_ for .gnupg and .ssh directories
- private_ for 0600 files (nym.pub)
- executable_ for scripts in .local/bin and display-toggle.sh
- symlink_ for mimeapps.list symlink
|