5b8fef406facfd8ec9952d33bda031dc4002f1c4
13
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2cc3510d2a |
Offer an AI diagnosis when a process crashes (#6746)
* Offer an AI diagnosis when a process crashes systemd-coredump journals every core dump under a known MESSAGE_ID with the crashing program, pid, and signal as structured fields. omarchy-crash-watch follows that stream and raises a "Process crashed: <program>" toast; clicking it opens omarchy-agent-crash, which briefs the default agent on the crash. The toast goes through omarchy-notification-send --exec rather than a libnotify action, because the shell runs clicks from its own omarchy-exec hint and never emits ActionInvoked. It keeps the default "omarchy-action" app name too, the only one shouldBypassDnd() lets through -- a crash being the last notification worth swallowing. It stays quiet until an agent is configured, since a diagnosis is all it offers. The method lives in a diagnose-crash skill rather than the prompt, so it is edited in one place and works with whichever agent is default. It covers investigating the core, and reporting a confirmed Omarchy bug upstream: scoped to bugs Omarchy controls, searched for duplicates first, only with the user's agreement, and signed with the model and harness that produced it. A migration reaches existing installs, whose skill symlinks and unit enablement would otherwise sit behind one-time setup paths. * Let the diagnosis clean up the core it extracted "Do not modify or delete anything" contradicted the symbolization step right above it, which writes a core to a temp file and deletes it on exit. Read literally, the core survives -- and the same section warns it holds passwords and tokens. The prohibition is about the system, not about your own scratch. * Do not spend a crash toast on a dead notification server The shell owns org.freedesktop.Notifications, so its own crash takes the notification server down with it -- and a shell crash is exactly what you want told about. The toast was sent once into that gap and the dedupe window was recorded regardless, so the rest of the crash loop went quiet for a minute and `journalctl -n 0` never replays what was missed. It now waits for the restarted shell to reclaim the bus name, as omarchy-migrate-notify already does, and only a delivered toast starts the dedupe window. |
||
|
|
2cff67fa45 |
Fix sleep lock session environment race (#6493)
Found by @tobi. |
||
|
|
1ea910f662 |
Let systemd-oomd kill a runaway app instead of losing the session (#6445)
Nothing stood between "memory is tight" and "processes die at random": the kernel OOM killer only fires after an allocation has already failed, so a machine under pressure thrashes in reclaim until something breaks somewhere fatal — seen in practice as Hyprland taking SIGBUS mid-memcpy from a client shm pool that memory pressure was tearing down. Enable systemd-oomd, which keys on PSI stall time rather than free pages, and mark app.slice — and only app.slice — as its kill candidate. Hyprland runs in session.slice, so the compositor is structurally ineligible as a victim: oomd takes the app that caused the pressure and the session survives. Thresholds (50% stall over 20s, Fedora's desktop defaults) live in an oomd.conf.d drop-in; candidacy ships as a vendor drop-in under /usr/lib/systemd/user so existing users get it on package upgrade with no per-user seeding. New installs enable the daemon from enable-services.sh; a migration covers existing ones, restarting an already-running oomd so it doesn't keep stale thresholds until reboot. Deliberately not earlyoom: it triggers only when free RAM and free swap are both under threshold, so Omarchy's large, mostly-idle swapfiles keep it asleep through exactly this failure. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6e07fd0e82 |
Supervise fcitx5 so XCompose sequences can't silently die
fcitx5 is what turns the CapsLock compose sequences in ~/.XCompose into text for Wayland clients -- CapsLock m s for an emoji, CapsLock space n for your name. It was launched fire-and-forget from Hyprland's autostart via uwsm-app, so nothing supervised it, nothing restarted it, and it logged nowhere. When it went away, every compose sequence stopped working for the rest of the session with no visible symptom beyond "emoji input is busted", and no record of why. That is not hypothetical: it was found dead on a running machine with no coredump, no OOM kill, and nothing in the journal to explain it. Move it to a systemd user service: - Restart=always, not on-failure. fcitx5 exits 0 when it finds another instance already owning org.fcitx.Fcitx5, and a clean exit still leaves the user with no input method. - After=/PartOf=graphical-session.target. It needs WAYLAND_DISPLAY and DISPLAY, which uwsm imports into the user manager before reaching the target, and its wayland connection dies with the compositor. - ConditionEnvironment=WAYLAND_DISPLAY. After= is ordering only and does not stop the unit from being started while the target is inactive. An update over SSH has a live user manager (pam_systemd) and no graphical session, and a fcitx5 started there comes up blind -- then stays active, so the later target activation won't pull in a working one, because Wants= does not restart what is already running. Skipping the start leaves the unit enabled and healthy for the next graphical login. The migration hands over inside a live session only: it enables without --now, and only when graphical-session.target is active does it drop the autostart-launched process and start the unit. Because that kills a fcitx5 that was working a moment ago, a failed start is reported instead of leaving the session mute with the migration marked complete. omarchy-restart-xcompose now drives the unit. It still clears any fcitx5 running outside it first: that process owns the bus name, so the unit's instance would exit on arrival and the stale one would keep serving the old table -- a restart that reports success and changes nothing. Side benefit: fcitx5 now logs to the journal under its own unit, so the next disappearance leaves a record. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c7e327b05a |
Order the migration notifier after graphical-session.target
omarchy-migrate-notify.service is a Type=oneshot wanted by graphical-session.target, and systemd complements a target's Wants= with an implicit After=, so the target waited for the notifier to exit. The notifier does not exit quickly: it sends the notification through systemd-run --scope, which is synchronous, and omarchy-notification-send -a blocks until the user clicks. The target stayed in activating for as long as the toast was up. wayland-wm-app-daemon.service is After=graphical-session.target and nothing wants it, so uwsm-app starts it on demand. Clicking the notification runs omarchy-launch-floating-terminal-with-presentation, which execs uwsm-app, which blocks on a systemctl --user restart of that daemon -- a job queued behind the very target the clicked notifier was holding open. The terminal never opened; uwsm-app gave up on its own pipe timeout instead. Declaring After= on the wanted unit suppresses the implicit dependency rather than forming a cycle, so the target is reached without waiting and the notifier runs behind it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e57f3b286c |
Send and receive files with Taildrop (#6375)
* Send files to a tailnet machine with Taildrop The panel gets a send button next to the copy one on every machine that Tailscale grades as a Taildrop target, and `s` does the same from the keyboard. Picking runs through the XDG portal chooser, so it looks like the file dialog every other app opens. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TJQJfHXXApUk6En8EZisHg * Save incoming Taildrop files and say so Linux keeps Taildrop files in the daemon's inbox until someone asks for them, so nothing arrived until you ran `tailscale file get` by hand. A user service now stages each delivery next to the downloads directory, hands it over under a free name, and announces it — with a preview when it's an image, and a click to open it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TJQJfHXXApUk6En8EZisHg * Float every portal dialog, not just the titled ones The portal only ever shows dialogs, and the title regex missed any chooser an app names something else — ours included. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TJQJfHXXApUk6En8EZisHg * Re-run the Taildrop enable now that the unit ships The unit was never installed to /usr/lib/systemd/user/, so the enable had nothing to act on and machines that already ran the migration carry a marker for a no-op. Rename it so they get a working pass, and report what systemctl says instead of a bare failure line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Wait for the file chooser on the connection that asked for it The portal answers a request with a Response signal directed at the connection that made it, and dbus-daemon delivers directed signals only to that connection. gdbus monitor registers with AddMatch rather than BecomeMonitor, so it never saw the reply: every pick left omarchy-file-select blocked on a read that could not arrive, taking omarchy-tailscale-send down with it before it reached either its notification or the transfer. Make the call and wait for the signal on one connection, and give up after ten minutes so an unanswered dialog cannot strand the caller. Drop the "Sending to" notification while here, so a send reports once. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Mark Taildrop notifications with the panel's send glyph Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Stop a hung tailscale poll from freezing the panel Each poll is skipped while its own process is still running, so one that never exits leaves the panel showing whatever it last read, for good: the peer list keeps a woken machine missing, and opening the panel cannot help because open runs the same refresh that hits the same guard. Reap anything still running fifteen seconds after a refresh, well inside the thirty second interval, so the next tick starts clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Place a moved widget where an added one lands 'move omarchy.media left' named a section, not a slot, but the section went through as an explicit target, which resolves a missing index by appending. The widget landed on the far end of the row instead of after the section anchor where 'add' puts it. Its test has never run: the assertion covering this went in four hours after an unrelated layout change had already stopped the file, and the runner stops the whole suite at the first failure. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Keep the config test from failing on things it is not about The center layout assertion pinned the whole row, so parking the indicators left of the clock broke a test named for update sitting next to weather. Assert that adjacency instead. The package-defaults check reads PKGBUILDs from the omarchy-pkgs repo and blew up with a traceback wherever that is not a sibling checkout. Skip it when the checkout is absent, honour OMARCHY_PKGS_ROOT when it is somewhere else, and keep failing when it is present and wrong. Between them these stopped the suite eighty files early. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Make the file chooser a Python command rather than a bash host for one The portal work was a heredoc wedged inside a bash script that existed only to parse two flags. Drop the host: argparse covers the flags, and the file says at the top why it is the one command here not written in bash. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Tell a chooser that never opened apart from one that was dismissed Three fixes from review: The poll watchdog rearmed on every refresh, so a refresh interval shorter than its timeout — the setting goes down to five seconds — pushed the deadline ahead of a hung process forever. Arm it on the launch that needs watching and leave it alone. omarchy-file-select exited 1 both for nothing picked and for a chooser that could not run, and omarchy-tailscale-send read it through a process substitution, which drops the status anyway. A session bus that was not there looked exactly like someone changing their mind. Separate the two exits and read them with a command substitution. Delivery picked a free name and then renamed, which overwrites anything that takes the name in between. Link to the name instead: link(2) refuses one that is taken, so the check and the claim are the same step. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
425c3ff84d |
Only check for pending migrations at login
omarchy-update-user-notify.path watched /usr/share/omarchy/migrations, but pacman writes that directory during every update, including the blessed omarchy update, which runs omarchy-migrate a step later. The watcher fired a critical notification for the migrations the update was already applying in the visible terminal. A watcher cannot tell that apart from a bypassed pacman -Syu, so the only trigger that never collides with a running update is a once-per-login check. The service that already ran at graphical-session.target is now the whole mechanism, renamed after the command it runs. That is also all the second-user case needs: markers are per-user, so anyone who did not run the update finds them missing at their next login. Login timing means the toast can be sent before the shell has claimed org.freedesktop.Notifications, so the notifier waits for a live server first. The wait is omarchy-first-run's, lifted into omarchy-notification-wait rather than duplicated. The package keeps omarchy-update-user-notify.service as a symlink onto the new unit. Existing users hold an absolute wants symlink to the old path, and the migration that repoints it only runs for users who run an update, which is the opposite of who the notifier is for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
aa9f0c54c5 |
Add per-laptop speaker tunings, starting with the XPS 14
Laptop speakers ship voiced by the vendor's Windows DSP layer, which Linux does not get. A tuning restores that as a PipeWire filter-chain in front of the internal speaker sink, matched to the machine by DMI string and expected sink. Adding a laptop is a directory under default/audio/tunings with two files and no new code: matching is data. The XPS 14 DA14260 tuning included here was derived by measuring the xps-audio-linux EasyEffects profile (MIT) and fitting a biquad chain to it, so no impulse response or other upstream asset is redistributed. It measures 1.24 dB RMS against that reference, and matches its dynamic range within 0.1 LU -- the reference's multiband compressor turned out to contribute nothing, so a linear chain replaces it. Bass Q is capped deliberately: a closer magnitude fit swung group delay 31 ms across 63-80 Hz, which smears bass transients. The graph runs as its own PipeWire client under its own config name rather than loading into the audio daemon. The daemon only reads its config at startup, so a daemon-loaded tuning could only be switched by restarting PipeWire -- which drops every PulseAudio client's connection, and applications that do not reconnect (Spotify) then have to be restarted by hand. Hosting it separately also contains failure, since a malformed tuning breaks only that service. Three things about the surrounding audio graph needed fixing for this to behave: - Volume must live downstream of the tuning. omarchy-audio-output-sink is now the single definition of which sink an output's volume really uses, shared by the volume keys, the output switcher's OSD and the audio panel, so they cannot disagree. It resolves the current default output, which keeps it correct when headphones are selected while a tuning exists. - The tuning's own output is a movable sink input, so rerouting "all streams" to a newly selected output would drag the processing onto headphones, or into the tuning's own sink, which is a cycle. It is pinned, and stream moves are limited to streams carrying an application.name. - The physical sink a tuning fronts is not independently selectable, since picking it would only bypass the tuning, so it is kept out of the output list. Applying happens at first-run, not finalize-user, because finalize-user also runs in the ISO chroot where there is no audio server and nothing would retry. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
b87de89372 |
Stop the migration notifier from busy-looping the session
omarchy-update-user-notify.path used PathExistsGlob= on the packaged migrations directory. That directive is level-triggered: systemd re-checks it every time the triggered unit deactivates and fires again while the glob still matches. Since applied migrations stay on disk forever (state lives in ~/.local/state/omarchy/migrations), the glob always matches, so the oneshot notifier re-triggered itself in a tight loop (~26-66 starts/sec) — burning about a core and flooding the journal for the whole session. The loop existed since the unit was introduced, but the default start-rate limit killed it after 5 iterations, taking the .path unit down with 'unit-start-limit-hit'. That symptom was reported as #6174 and fixed yesterday by setting StartLimitIntervalSec=0 — which removed the only brake and turned the capped hiccup into an unbounded busy-loop. Fix the actual cause instead: * Drop PathExistsGlob= from the .path unit, keeping the edge-triggered PathModified= watch for updates that land mid-session. * Revert the StartLimitIntervalSec=0 override; with the level trigger gone there is no self-re-fire to trip the limit, and the default limit is a useful backstop again. * Preserve the once-per-login pending check the glob used to provide by giving the service its own WantedBy=graphical-session.target, enabled at first-run alongside the other user units. * Add a migration that daemon-reloads, revives a rate-limit-killed .path, restarts the watcher, and enables the login-time notifier on existing installs. Verified with transient path/service units: the old config runs the service 200 times in 3 seconds; the new config runs it zero times while idle and exactly once when a new migration file lands. Thanks to @HANCORE-Linux for finding and diagnosing the problem. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ef1db32774 |
Prevent migration notifier from rate-limiting itself off (#6174)
omarchy-update-user-notify.path watches /usr/share/omarchy/migrations with PathModified. A single update commonly drops several migration files at once, so the oneshot service is re-triggered in a burst and exceeds the default start-rate limit (StartLimitBurst=5 / 10s): omarchy-update-user-notify.service: Start request repeated too quickly. omarchy-update-user-notify.path: Failed with result 'unit-start-limit-hit'. When the limit trips, the watching .path unit itself fails and stops watching, so migrations that land later in the session are never surfaced until the next login. Set StartLimitIntervalSec=0 on the service. omarchy-migrate-notify is idempotent, so there is no downside to letting it run on every trigger. Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
c582e7133a | Unify Omarchy migrations | ||
|
|
0804962619 | Improve update and migration flow | ||
|
|
babfafa5e9 |
Split user defaults into skel seed, finalize, and resync
Reorganizes Omarchy 4 around three layers for populating $HOME:
Seed: omarchy-settings ships defaults to /etc/skel; useradd -m
copies them on user creation
Finalize: omarchy-finalize-user (renamed from omarchy-setup-user)
handles only the runtime tweaks /etc/skel can't do — skill
symlinks, xdg-user-dirs, default browser/mailto, vconsole→hypr
keyboard sync, and install/user/all.sh
Resync: omarchy-reinstall-configs is the explicit, destructive
resync of /etc/skel into an existing user's $HOME
Package-owned files move out of config/ into default/, where the
omarchy-settings PKGBUILD installs them to real system paths:
config/environment.d/fcitx.conf -> /usr/lib/environment.d/
config/fontconfig/fonts.conf -> /usr/share/fontconfig/conf.avail/
config/mimeapps.list -> /usr/share/applications/
config/omarchy.ttf -> /usr/share/fonts/omarchy/
config/systemd/user/*.service -> /usr/lib/systemd/user/
config/uwsm/default -> /usr/share/omarchy/default/uwsm/
config/uwsm/env -> /usr/share/uwsm/env.d/10-omarchy
config/xdg-terminals.list -> /usr/share/xdg-terminal-exec/
omarchy-upgrade-to-4 grows a 'retire' action (renamed from 'move' to
clarify nothing is copied — the system path is owned by the new package
once the user's hash-matched ~/.config copy is removed). Mismatched
copies are kept as backups so user overrides survive the upgrade.
Other simplifications:
- Single env bootstrap at default/bash/env-bootstrap sourced by
/etc/profile.d/omarchy.sh, /etc/skel/.bashrc,
/usr/share/uwsm/env.d/10-omarchy, and default/bash/envs. PATH
prepend only in dev-link mode (production uses /usr/bin/omarchy-*).
- omarchy-refresh-config reads from /etc/skel/.config so refresh
means 'snap to skel'.
- omarchy-reinstall-configs collapses to 'cp -af /etc/skel/. ~/'
plus limine/plymouth/nvim refresh.
- omarchy-font-set uses awk against our own 30-omarchy.conf instead
of xmlstarlet; xmlstarlet dropped from omarchy-base.packages.
- Defer user systemd enables (bt-agent, sleep-lock,
recover-internal-monitor) to first-run via
install/user/first-run/enable-user-units.sh; delete
omarchy-user-systemctl-enable and the per-hardware install
scripts that called it.
- Wireplumber bluetooth-a2dp-autoconnect.conf moves to config/ so
/etc/skel ships it; install/user/hardware/bluetooth.sh deleted.
- Default terminal switched to foot.desktop.
- docs/file-layout.md documents the three-layer model and the
build-time repo→path map.
|