aboutsummaryrefslogtreecommitdiffstats
path: root/AGENTS.md
AgeCommit message (Collapse)AuthorFilesLines
6 dayssettings: qtmaildir's config, in four Mail pagesDanilo M.1-1/+1
qtmaildir is configured through qtmaildir.conf alone, which it reads at startup and never writes. Four settings pages under a new Mail group edit it: Mail ([general], [sync], [completion]), Compose, Accounts (a card per account, add and remove) and Tags & shortcuts ([tagcolors] and [keys]). Fields save on Enter and unset when emptied, with qtmaildir's defaults as placeholders and numbers range-checked; the pages say when qtmaildir is running and a change waits for its restart. Ini.js edits the file line by line so its comments survive. Headers are only whole [name] lines: a section is never cut at the next "[", since values such as [Gmail]/Bozze hold brackets, the trap AGENTS.md records. The shortcut actions are copied from qtmaildir's KeyMap::knownActions() rather than exported by it, since a CLI flag there would have meant translations and a changelog entry; the field also takes free text, and the copy is marked as a ponytail ceiling. The settings sidebar now clips, which a list long enough to scroll showed it did not: entries drew over the search box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 daysassistant: pick the preferred model, loaded on demandDanilo M.1-0/+6
The daemon answers with whichever model llama-server has loaded and never asks for one, so it never evicts a model another client is using. The Assistant settings page now lists the router's models with their state. Load saves one as the preferred model, in Prefs, and asks the router to load it now, polling /v1/models until it reports loaded; Prefer marks the loaded model as preferred without swapping. The swap happens only on that click, so the daemon's rule holds. AGENTS.md records the router's load endpoint and its two refusals, both measured: it lives on the server root, not under /v1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 dayssettings: the assistant's daemon config, tools, and Ask presetsDanilo M.1-1/+2
Two settings pages for desktop-assistant. Assistant edits the daemon's config.toml: server, temperature, tool rounds, thinking, the system prompt, and the [env] values its tools read; a switch per tool renames tools/<name>.toml to .toml.off, which the daemon's glob skips. The daemon reads all of it at startup only, so the page says when a change is pending and Restart runs assistant.sh restart, showing its status when the daemon does not come back. The file is edited line by line, like autostart.lua, so the comments the example ships with survive: unset keys stay commented out in place. Every write parses the whole new file with tomllib first and replaces the old one atomically, so no edit can leave a config the daemon will not start with. Defaults are read from assistant.py --defaults rather than copied into QML. Ask presets edits the canvas's canned questions, which Prefs already stored for exactly this page: label, question, and the kinds each is offered for. They apply live. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 daysappearance moves into the settings windowDanilo M.1-3/+3
The appearance shell existed because a wallpaper picker needed more room than the 600px drawer, so it ran as its own process with a full-screen overlay. The settings window now gives it that room, and its five tabs become five settings pages in the desktop process: Wallpaper, Theme, Icons & cursor, Sunset and Idle. appearance/ is gone, and with it a process, a keepalive window and a layer blur rule. The files move to desktop/modules/appearance/ unchanged in what they do. Each tab gets a small *Module.qml; the window's refresh-on-open calls the singletons' refresh(), which the panel's show() used to. The two tabs that were inline Components in AppearancePanel become ThemeTab and WallpaperTab, owning the notices the panel printed. Sunset, Idle and Icons drop their own Flickable so the page scrolls them and search can reveal a row; the wallpaper list virtualises its rows and scrolls itself, so it takes the page's new viewHeight instead. Search finds a colour scheme and an icon or cursor theme by name. The appearance IPC target moves to desktop/shell.qml with the same verbs, so udt-steps and any keybind change only the path. Git now follows the appearance pages and autostart in the sidebar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 daysdesktop: settings search finds rows, and a hit reveals its rowDanilo M.1-5/+12
Search used to stop at the page: clicking a result opened it at the top and left the setting to be found by eye. Now each settings module keeps its rows as searchItems, {text, key}, reread on every window open since the page itself is not loaded until shown: git runs gitcfg list, and autostart watches its file. A row hit opens the page, and Page.reveal() finds the row whose objectName is the key, waiting up to 3s for the page's own data, scrolls to it and flashes it in the accent. The reveal lives in Page, so a page only names its rows. Git's long keyword list was a stand-in for exactly this and is cut to "gitconfig". The autostart page takes its path from the module now that both read the file. Also corrects the AGENTS note on missed hot reloads: it blamed sed -i replacing the file, but the Edit tool writes a new inode too and usually reloads. The cause is unknown; the note now says how to detect it and that a process that stops watching needs a restart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 daysdocs: sed -i breaks hot reloadDanilo M.1-0/+6
sed -i renames a new file over the old one, and quickshell's watch on the old file dies with it. The autostart glyph fix went in that way and the running shell never reloaded: the log showed no reload after the edit, and a content change to shell.qml brought the glyph up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 daysdesktop: a settings window, and autostart as its first pageDanilo M.1-1/+2
The drawer's tiles were turning into a full settings app. The drawer stays the quick area, live state and things toggled often; pages set once and left alone go to a settings window, a normal Hyprland toplevel listing them down the left. A module joins with settings: true, which also drops its tile. A gear tile and ipc call settings open|toggle reach it. Autostart edits hypr-theme's autostart.lua directly, line by line: an hl.exec_cmd line is an entry, behind -- it is disabled, everything else passes through. Edits refuse when their line moved since the parse, and writes are atomic because Hyprland reloads on every change. A wrong entry only shows at the next login, so adding is guided rather than a free text field: pick an installed app or type a command whose program must resolve on PATH before Add enables, then a workspace and silent, composed into a [workspace X silent] rule. Try runs the line through hyprctl dispatch so the rule applies as at login. Existing rows get no Try: they ran at login, and a second start stacks an instance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7 daysdocs: FileView.setText writes nothing for empty text on an unloaded pathDanilo M.1-5/+15
Found from use: a note saved with an empty body got an index entry and no file, because setText with an empty string on a path the view has not loaded creates nothing and reports no error, with or without atomicWrites. While confirming that, the neighbouring note turned out to be wrong too: blockLoading does not make reload() synchronous. Measured on a regular file and on /proc/stat, reload() then text() returned the contents from before the reload, and only waitForJob() between them returned the new ones. The FileView docs say the same. Perf.qml reloads and reads without waitForJob, so a sample reads the previous interval; not changed here.
7 dayschore(assistant): retire the voice overlayDanilo M.1-5/+5
desktop-assistant is a text daemon now (its voice version is the tag voice-v1), and the canvas in desktop/assistant/ is its front end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7 daysdocs(git): the git config page, and replace-all appending on no matchDanilo M.1-0/+5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7 daysfeat(shared): one faded glow for hovers across the shellsDanilo M.1-1/+4
Hover and attention effects were solid: a flat accent ring round the user page's avatar, a flat quarter-disc in the hot corner, and thick accent or white borders on window cards, keycaps and knobs. Glow.qml is a RectangularShadow in the accent, fading out from the shape's edge and in over 140ms, linked into desktop, window-switcher and keybinds like Theme.qml, and all five places use it. Selection borders in the appearance tabs stay: they mark state, not hover. The avatar also gains the hover cue in the first place: the hand cursor never showed under a hyprcursor-only theme, so without it the picture gave no sign it could be clicked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7 daysdocs(user): the module's README and the busctl escaping noteDanilo M.1-2/+6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7 daysfeat(perf): the performance page moves to the drawer, with ~/.cacheDanilo M.1-1/+1
The island's performance icon and panel are gone: the drawer page covers them. With only one host left, the panel drops its three-column grid for one card per row at a larger size, since the page scrolls; temperatures get a card of their own as tiles. The files move from island/perf to modules/perf. A cache card ports conky's: ~/.cache and its five largest children, measured with du each time the page opens (28ms over 2 GiB here) rather than read from conky's 15-minute sampler file. The largest is yellow, red past half the total, as conky had it. The warning dot now shows only on the drawer tile. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 daysdocs: PwNode.isSink reads true for a playback streamDanilo M.1-0/+4
Recorded because the inverted filter looked correct, linted clean and returned an empty list with no error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 daysfeat(desktop): the mouse back button steps out of the drawerDanilo M.1-0/+5
The side button (BTN_SIDE, Qt.BackButton) does what Escape does: closes the history, then leaves a page for the tiles, then closes the drawer. Both go through one back(). The first attempt let the press fall through to the full-surface click catcher under the panel, since nothing above it accepts that button; it never arrived while a page was open. A MouseArea on top with z: 1, taking only the back button, works, and left clicks still pass through it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 daysdocs(updates): the module's READMEDanilo M.1-1/+1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 daysrefactor(island): the controls panel goesDanilo M.1-5/+6
Each of its seven tiles opened a drawer page that already existed, and it went unused. SUPER alone will open the drawer instead. Removed with it: the status pill's controls icon, Island.toggleControls, the island IPC target, Controls.js and its test, and the controls list in Prefs. Prefs now holds only the pinned IP; a controls key left in desktop.json is still kept on write, because writes merge into the parsed document. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 daysdocs: the expose and its hot cornerDanilo M.1-1/+2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
10 daysdocs: the performance panelDanilo M.1-1/+10
What the panel shows, the dot's thresholds and their lack of hysteresis, why the public IP is pinned, and what is sampled always versus only while open. AGENTS.md gains two gotchas found building it: FileView reads /proc on reload(), and a hot reload does not resize an existing layer surface, which left the panel cut off after the height was raised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
10 daysdocs: the calendar panel and calctlDanilo M.1-1/+19
The island README gains the panel. AGENTS.md records why calctl reads the vdir itself, the local-time recurrence rule, the system Python it needs, and two traps the build hit: a QML method named escape fails to load, and a pill expanding for any panel grew beside the calendar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
10 daysdocs: the controls panel, its preferences file and bindDanilo M.1-1/+11
The island README gains the panel. AGENTS.md records that a bare SUPER release bind is cancelled by drag and scroll on Hyprland 0.56.2, which was the open risk in the spec, and that FileView creates parent directories while Quickshell.stateDir is per-shell. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07docs(agents): a branch switch can drop a component until restartDanilo M.1-0/+7
Seen merging the island: the shell reloaded while desktop/island/ did not exist, and stayed without it after the fast-forward restored the files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07docs: the island, and waybar goneDanilo M.1-12/+45
AGENTS.md describes the hybrid model (desktop/ hosts drawer and island) and gains the gotchas found while building the island: UseQApplication for tray menus, WheelHandler vs MouseArea, accent colliding with green, xkb layout switching, and the tray popup un-hovering the island. The Blur waybar measurement becomes history. READMEs drop their present-tense waybar references. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07docs(agents): point at the Modesty reference cloneDanilo M.1-0/+9
The island work borrows Modesty's ideas. A local clone makes it reachable from later sessions, and the note carries the licence constraint with it: Modesty is GPLv3, this repo GPLv2-only, so it is read and never copied. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05docs(agents): llama-server /slots autoloads the modelDanilo M.1-0/+6
A slot query for an unloaded model loads it into VRAM, so any status probe against the router needs autoload=false. Found when a probe during the ai module's design reloaded Gemma. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29docs(agents): hot reload does not follow symlinksDanilo M.1-0/+7
An edit to shared/Notify.qml was never picked up by the running shells, while an edit in the same pass to a component's own file did reload, so the shell looked current and ran the old sanitize. Record that shared/ edits need a forced reload of each linking component. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26fix(assistant): retry the event socket with a fresh SocketDanilo M.1-0/+7
Quickshell 0.3.1 keeps the QLocalSocket of a failed connect, so setting connected = true again never retries: an overlay started before the assistant (at login, or by a restart) stayed dark for good. The Socket now lives in a LazyLoader that the retry timer turns off and on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26feat(assistant): overlay for the voice assistantDanilo M.1-0/+1
Reads desktop-assistant's event socket, JSON lines on a Unix socket the assistant owns: state, context use, the running tool and audio levels. A circle shows the name and used/total context, a wrench and the tool name while one runs, and pulsing dots while it transcribes or thinks. Around it three sine ripples follow the loudness, the user's voice and the reply in two palette colours from Theme, so a udt change recolours them live. It fades out a configurable delay after the reply. The ripple is driven by FrameAnimation, not a Timer: a 16 ms Timer drifted against the display refresh and visibly stuttered. Standalone like the other components; it reconnects every 2 s while the assistant is down, and the assistant runs the same without it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25feat(keybinds): live keybind reminder overlayDanilo M.1-0/+1
Modelled on window-switcher: a Scope with a 1x1 keepalive PanelWindow plus a LazyLoader'd overlay, opened via IpcHandler (SUPER+k is bound in a different repo). hyprctl binds -j is asked fresh on every opening so the list matches whatever Hyprland has loaded, with Binds.group() from task 1 turning it into the grid's {name, rows} groups. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25feat: reload.sh restarts quickshell componentsDanilo M.1-0/+8
The volume OSD drew only its "Output 72%" label, with the icon, bar and device line clipped below the panel edge. The code and the theme were not at fault: a hot reload fixed it, and a debug line logged just after showed the volume row laid out correctly at the top of the panel. The stuck state lived in the running process, so the fix is a restart. quickshell has no reload subcommand and no IPC target for it, and a hot reload needs a real content change to a file. reload.sh kills and restarts each named component, or every directory holding a shell.qml, and prints the qs count afterwards, since the process is qs and not quickshell. It must run from the user's terminal. A detached qs started from an agent's tool call dies with the call, which would leave the desktop without its shells; AGENTS.md now says so under Reloading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-16docs: the old waybar notification module is archived, not just deadDanilo M.1-3/+3
The note pointed at waybar/scripts/notifications.py and its module by path. Both moved to ~/bin/archive/ with the rest of the stock waybar theme, whose scripts had no caller left once this shell took over notifications. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16refactor(theme): read the palette from ~/.cache/udtDanilo M.1-1/+1
unified-desktop-theme moved its generated files out of ~/.cache/wal, which pywal used to own and nothing writes any more. The palette udt-accent generates is now at ~/.cache/udt/udt-palette.qml. shared/Theme.qml is the only code change; every component reaches it through a symlink. The module READMEs cite the path, so they move with it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15fix(notifications): apply final review fixesDanilo M.1-1/+1
Mirror the balloon's right-click close-all on the drawer row: the spec says the gestures are identical in both forms, and a right-click on a row previously did nothing. The right-button branch precedes the live guard so it behaves the same on history rows. Stop importing the Status singleton into the notification shell. Referencing it instantiated it, and its onPresentationChanged writes status.dnd and runs breaktimer.sh, so a read-only consumer was writing state and shelling out on every presentation toggle, and doubled the dndBeforePresentation race. Notify now reads "/run/user/<uid>/status.dnd" directly through a FileView, the same convention as the notifyd files; a missing file means off. AGENTS.md named Drawer.qml as the drawer's reserved space; it is desktop/NotificationList.qml.
2026-09-15docs(notifications): document the renderers and record the trapsDanilo M.1-0/+15
The daemon is a separate process and the files are the interface; suppression lives in the balloon shell so the drawer can list what DND held back; and the drawer flag is what stops a notification appearing as both a balloon and a row.
2026-09-15docs(status): document the module and record its trapsDanilo M.1-0/+17
A FileView fires its own fileChanged on setText, so a handler that writes in response to a change loops unless it compares first. IdleInhibitor has no window of its own and does nothing without one, so the singleton is handed the keepalive window by shell.qml. Both were read from the documentation while designing and confirmed while implementing.
2026-09-15docs: record the scan, logind and idle-inhibit trapsDanilo M.1-0/+31
Four findings from designing the status registry, all runtime-verified. The scan one shipped as a fix in f43f31a: neither BluetoothAdapter.discovering nor WifiDevice.scannerEnabled self-terminates, and closing the drawer destroys the page without stopping them, so a forgotten scan held the radio for the session. The logind one corrects an assumption that reached a committed spec before it was caught. elogind does run here, with pam_elogind in the PAM stack and a tracked session on seat0. The narrower true caveat is that pam_elogind no-ops when the system was not booted with elogind as init, so its documented removal of XDG_RUNTIME_DIR at last logout is not guaranteed on Slackware; a reboot clears it anyway because /run/user/1000 is tmpfs. The two idle-inhibit entries record that the compositor advertises zwp_idle_inhibit_manager_v1 and hypridle honours it, so an inhibitor goes over Wayland rather than D-Bus, and that waybar's built-in idle_inhibitor owns its own inhibitor object and therefore cannot be demoted to an indicator for a mode owned elsewhere. Held back deliberately: FileView firing its own onFileChanged on setText, and IdleInhibitor requiring a non-null window. Both are read from the documentation and neither has been observed running, so they wait for the registry implementation to confirm them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A7ThHHh5iTYbVfp3rNAkw2
2026-09-14fix(desktop): name the kdeconnect injected property kc, not modDanilo M.1-0/+7
The tile, page and row each took a required property named mod while the module object's id is also mod. In a Component scope the id resolves to the property's own unset self, so every page.mod read was undefined and the device list never rendered. Only a runtime TypeError showed it; the smoke check was clean because the drawer was closed. kc matches the net and bt convention and cannot collide with the id.
2026-09-14docs: record the KDE Connect trapsDanilo M.1-0/+15
No D-Bus module means shell-outs and no push; the daemon and the indicator are separate; the battery plugin is not on every device; and qdbus reads properties and methods through one call shape.
2026-09-14docs: hot reload does not pick up a new component fileDanilo M.1-0/+10
Adding desktop/Switch.qml while only editing files under modules/ left it out of the running shell's generated qmldir, so the two pages that use Switch could not resolve it and their tiles dropped from the grid. The code was correct; a fresh process rendered it. The directory's qmldir is regenerated only when a file that imports the directory reloads.
2026-09-14docs: glyphs render with Theme.iconFamily, pinned to InconsolataDanilo M.1-0/+9
Fontconfig falls back per codepoint, so the same codepoint can be a different glyph in a different Nerd Font: the ethernet codepoint rendered as a gamepad. The theme now pins the family and the note says to check the font cmap for a new glyph.
2026-09-14fix(desktop): wire tile active state and clear connect errorsDanilo M.1-2/+2
2026-09-14docs: record the network and bluetooth trapsDanilo M.1-0/+15
The native backends start empty for about two seconds, device lists are ObjectModels, NMSettings is not in QML scope, and quickshell has no BlueZ agent. Each one cost a probe to learn; writing them down is cheaper than re-learning them.
2026-09-14docs: the desktop shell and what the merge changedDanilo M.1-9/+16
Five components become three, and the Theme symlink count with them. Two new notes: a pragma Singleton in a subdirectory resolves through a plain directory import with no qmldir, and Virsh.sampling gates only the stats poll, not the lifecycle stream that keeps the tile correct while the page is closed.
2026-09-13feat(vm-manager): offer to discard a saved state that will not restoreDanilo M.1-0/+9
A VM saved rather than shut down restores its memory image on the next start. When that image cannot be restored the start fails every time with "unable to execute QEMU command 'migrate-incoming'", and the panel showed an ordinary "shut off" with a Start button that could never work. Detection is virsh dominfo grepped for "Managed save: yes", polled per VM on every list refresh the way the agent rows are. domstats does not report it: the shut-off reason reads "failed", from the failed start, not from the save. virsh list --all --managed-save does print "saved" in the state column, but not together with --name, which is the form the panel lists with. The button appears only when a saved image exists, since managedsave-remove fails without one and would be noise on every other VM. It takes a confirmation click but not a typed name: it deletes the memory image and leaves the disk alone, so the cost of a misclick is a cold boot. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Lo1FG4qTr1inavmhqhfobe
2026-09-12docs(window-switcher): write down what the build cost to learnDanilo M.1-6/+35
The component is finished and on the user's ALT+TAB, so what is left is the part that would otherwise have to be rediscovered. Most of the time this build took went to three things that report success and then do nothing: Hyprland 0.56.2 evaluating dispatch arguments as Lua, so the documented-looking `focuswindow address:0x...` is a silent syntax error; a focus dispatched while the overlay still holds an exclusive keyboard grab being accepted and ignored; and a sort on a `focusHistoryID` property that does not exist, comparing NaN and leaving an arbitrary order that looks plausible. None of them logs anything. Those six, plus the missing `0x` prefix, the empty `toplevels` before `refreshToplevels()` and `ScreencopyView` reporting (-1, -1) rather than (0, 0), generalise past this component, so they go in AGENTS.md next to the other notes that exist because a commit message explained itself once. The card geometry and the blank icon square are specific to the grid and stay in the component README. Also corrects the counts that four components made true and five do not: the component lists, "the other three use ExclusionMode.Ignore", and the Theme symlink note. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12refactor: one Theme.qml in shared/, symlinked from each componentDanilo M.1-1/+11
The four copies had already drifted, which is the argument for doing this now rather than when a palette change has to be made four times and lands in three of them. vm-manager was missing surfaceAlt; volume-osd was missing green, yellow and surfaceAlt. The shared file is the superset, so the two thin ones gain properties they never had and nothing loses one. A symlink rather than a shared import path: a singleton outside the config directory needs a qmldir beside it, the same friction that already keeps the generated palette parsed rather than imported. Quickshell follows the link and resolves the singleton with no qmldir, so no consumer changes and no component stops running standalone under qs -p. All four load clean with Configuration Loaded and no QML resolution error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TvHeJEXJzdfAaCCYqURAWp
2026-09-12docs: add mail-overview to the inventory and its traps to the notesDanilo M.1-3/+32
Four of the notes generalise beyond this component. Two were measured while building it: notmuch fails two different ways and only the rejected-query case is detectable, the misparsed-query case returning a plausible wrong number with exit 0; and notmuch deduplicates by message id, so one message with two file paths is counted twice by a path glob and per-account counts then sum above the total. Two more were bugs found only by running the thing. Xapian replaces files on commit, so a watch on a filename dies with it and the watch belongs on the directory. And an INI section body is not everything up to the next bracket, because values can contain brackets themselves: folders named [Gmail]/Bozze ended a section before its label and three of five accounts quietly displayed their raw key instead. The Blur section gains the exclusion-zone note with its measured geometry, since mail-overview is the first panel here that sits below waybar rather than over it. The "Both" phrasing that assumed two components is now plural. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WWL8JYHu7yhAdtx5pU9PMU
2026-09-11docs: the process is qs, not quickshellDanilo M.1-2/+10
Both binaries ship and qs is the one that runs, so pkill -x quickshell matches nothing and exits successfully. Every restart during development therefore left the old instance running, and 47 accumulated before the user noticed. The same mistake produced pgrep readings of zero that were twice taken for the shell having exited, and sent one debugging session after a bug that did not exist. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G7NRsGyF9jGfPYS4zPqpN7
2026-09-11feat(appearance): wallpaper picker and scheme switcherDanilo M.1-0/+6
One drawer for how the desktop looks, on SUPER+Return, replacing the qarma file dialog that key used to open. wallp is untouched and still does the work: the panel calls it with H= and V= and it still runs from a terminal. Clicking a thumbnail stages it rather than setting it, so both screens can be composed before anything changes and Apply is a single wallp call. The mock screens show the result: the staged pick where there is one, what is set where there is not, and the hovered thumbnail on the targeted screen. They are drawn at the real proportions from hyprctl monitors, DP-3 upright because it has transform=1, centred against each other as Hyprland has them. The scheme tab reads the palette pair unified-desktop-theme keeps for each scheme, so the swatches are that scheme's real colours and the list needs no edit when a scheme is added. Applying writes roles.conf and runs install.sh, and reloads nothing, because install.sh reloads nothing: the panel says what is still showing the old scheme rather than pretending the switch is done. Two QML traps are documented in AGENTS.md because neither announces itself: there is no String.matchAll, which threw inside a try and left every swatch empty, and assigning running = true to an already-running Process does nothing, which stopped the scheme loader after the first file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G7NRsGyF9jGfPYS4zPqpN7
2026-09-11docs: add AGENTS.md and a thin CLAUDE.mdDanilo M.1-0/+118
Records what cost time rather than what the code already says: the no-visible-window exit that broke both components, the two measurement traps that made it look like a code bug, and the per-component findings that generalise to a third one. CLAUDE.md points at it, matching unified-desktop-theme, so there is one source of truth per repo rather than one per agent tool. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G7NRsGyF9jGfPYS4zPqpN7