| Age | Commit message (Collapse) | Author | Files | Lines |
|
Twice in one session an edit adding an import to desktop/shell.qml
hot-reloaded into "UdtModule is not a type" and then "SunsetModule is
not a type", both existing appearance modules a fresh process resolved.
Recorded so the next one is met with a restart, not a debugging session.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The README records the measurements the code depends on: where typing
and BackSpace come from, why the dodge waits for the pointer, the
IdleMonitor enabled default, and fullscreen 2 against maximised 1.
AGENTS.md gains the QtQuick Sprite trap beside the Controls Button one,
since it took the desktop shell down on restart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The counterpart of /models/load, measured: the same body, answers
{"success":true}, and the next request loads the model again. sd-webui
now calls it before starting sd-server, because a resident Gemma left
Pony 1.1 GB of 12 GB and its first step failed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Same class as matchAll and fromEntries: a TypeError that only reaches the
log. In the docker Update button it threw after the busy flag was set, so
the button read "Updating…" forever with no process behind it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Shows the live scheme, accent and both wallpapers, the scheme and
wallpapers linking to their own pages, then every udt consumer in a
software and a hardware list, each with a Re-apply button running
`install.sh <name>`, and Re-apply all in the header. The list comes from
`install.sh --list`, so a consumer added in unified-desktop-theme shows up
here with no edit. One run at a time, and none during a scheme switch.
QML's JS engine has no Object.fromEntries either: it threw a TypeError
that only reached the log and left the page without its list. Noted in
AGENTS.md beside String.matchAll.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Measured: after shared/Notify.qml changed, a reload triggered by editing
Balloons.qml left the notifications shell on the old singleton, while a
fresh instance read the new config correctly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A bare TextInput defaults activeFocusOnTab to false, unlike the Controls
TextField some pages use, so Tab skipped every field built from one: the
settings search, Field, the qtmaildir, git, autostart, assistant, OBS,
user, VM and network rows, and the calendar editor. Multi-line TextEdits
stay out of the chain.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Hyprland draws no decorations, so the settings window had no way to fill
the monitor and no visible close (only Ctrl+Q and Escape). It now carries
a titlebar row of its own: "Keystone Settings" centred, and maximize and
close at the right. Maximize toggles FloatingWindow.maximized, which
Hyprland honours and undoes.
A corner button floating over the page was tried first and covered the
pages' Save buttons; a row of its own keeps clear of every page header
without each page knowing about it.
The buttons are Rectangles rather than the directory's Button.qml,
because this file imports QtQuick.Controls and that import shadows it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The repository had no name of its own, only the framework's. It is now
Keystone, in the README, AGENTS.md, the settings window, notes commit
messages, calctl's PRODID and the user page's User-Agent.
Its files move off quickshell's name too:
~/.config/quickshell/greetings -> ~/.config/keystone/
~/.config/quickshell/obs-scene-icons.json -> ~/.config/keystone/
$XDG_STATE_HOME/quickshell/desktop.json -> $XDG_STATE_HOME/keystone/
~/.config/quickshell is Quickshell's own default config directory (a
bare qs loads its shell.qml), so sharing it was a collision rather than
a home. There is no fallback to the old paths: the files are moved once.
The layer namespaces become keystone-*, and the Hyprland blur rules in
hypr-theme are renamed to match in the same change. A running shell
keeps its old namespaces until restarted.
Left alone: the retired standalone mail and vm shells' namespaces,
which their READMEs keep as history; Quickshell's own app id, binary
and process name; and the repository directory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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.
|
|
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>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
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>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
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>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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>
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|