| Age | Commit message (Collapse) | Author | Files | Lines |
|
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.
|
|
read_mode() failed on a missing mode file with a shell redirection
error, 'statusctl: line 56: .../status.dnd: No such file or directory',
printed to stderr on every get/toggle before the file existed and
polluting waybar's exec stderr.
The '2>/dev/null' sat on the 'tr' command, but the error is the parent
shell's input redirection failure, which that redirect cannot suppress.
Guard on '[[ -e "$file" ]]' before reading; a missing file still
reads as 0, which was always the contract.
Mirror the fix into the plan so plan and script agree.
|
|
Two corrections to the plan, both found by running it rather than reading
it.
The test script the plan specifies makes nine assertions; the prose around
it claimed eight, in both the task step and the final check. An implementer
running it would see a passing suite that disagrees with its own expected
output, which reads as a failure of either the test or the plan. My
arithmetic.
The plan's statusctl also swallowed a failed rename and read the mode file
through cat piped into tr, so a write that did not land still reported
success and an unreadable file fell back to off by accident of pipeline
semantics rather than by intent. Review of the implemented script caught
both. The plan now carries the same fixes, so a future run of it does not
reintroduce them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7ThHHh5iTYbVfp3rNAkw2
|
|
Review of the first task caught that the commit message credited
atomicWrites while the code never set it. The property is already the
documented default in 0.3.1, so the behaviour was right, but statusctl
watches close_write,moved_to specifically because an atomic write arrives
as a rename, and leaning on a default for something the CLI depends on is
weaker than declaring it.
Both ModeFile blocks in the plan now set it, so task four does not
reintroduce the gap when it adds the second mode.
Worth recording: the review asserted atomicWrites defaults to false in
0.3.1 and concluded the shipped writes were not atomic. The v0.3.1 and
v0.3.0 documentation both read "If true (default)", so that conclusion was
wrong, though the underlying observation about the unset property was
right.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7ThHHh5iTYbVfp3rNAkw2
|
|
Eight tasks against the registry spec: the singleton with the dnd mode,
the statusctl CLI and its check, naming the keepalive window, presentation
mode and its three effects, the module and tile, the page and registration,
installing the CLI and swapping the waybar module, then the README and
traps.
The plan carries the facts probed while designing so the implementer does
not re-probe them: the runtime directory is tmpfs, elogind runs here with
the pam caveat that stops it guaranteeing logout cleanup, the compositor
advertises zwp_idle_inhibit_manager_v1, inotifywait is present, and
Inconsolata Nerd Font lives under ~/.fonts rather than either share
directory. That last one cost a failed cmap search that read as a missing
glyph when it was a bad search path.
Two claims stay marked unverified because they come from documentation and
have not been observed running: that a FileView fires its own fileChanged
on setText, and that IdleInhibitor does nothing without a non-null window.
The plan handles both and tells the implementer to confirm them and record
what actually happens.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7ThHHh5iTYbVfp3rNAkw2
|
|
Absorbs the kdeconnect-indicator into the drawer: status, battery,
pairing, ping, clipboard send, file share, refresh and mount. State is
polled from a qdbus6 helper script while the drawer is open, since
quickshell 0.3.1 has no generic D-Bus module.
The spec notes the phone-to-PC clipboard is the daemon's plugin, not the
indicator's, so removing the indicator does not touch it.
|
|
The Connections block needs a typed property on a QtObject, the bluetooth
README lines belong to Task 6 so every commit stays self-consistent, and
Pairing has no status property. Each was found by a task review and fixed
in the plan as well as the code.
|
|
Eight tasks, each leaving the tree working: network wired page, wifi
section, README, bluetooth module and page, pairing, README, then the
waybar removal and the trap notes.
The spec's failure section is corrected in the same commit: it claimed
forget and disconnect failures would surface inline, but neither backend
exposes a failure signal for them, so that is a ceiling rather than a
feature.
Verified by probe before writing any task: the singletons start empty for
about two seconds, the device lists are ObjectModels, signalStrength is
0..1, scanner and discovering are writable, and NMSettings is not in QML
scope, which drops the hidden-network join the spec had left conditional.
|
|
Quickshell 0.3.1 IPC requires every declared argument, so the plan's
`ipc call drawer open` with no page fails; the page-less grid entry is
the zero-argument `toggle`. Also records that `... | head` races
timeout and kills the shell early, so verification uses a file redirect.
|
|
The plan claimed a pragma Singleton outside the config root is invisible
until a qmldir names it, and had Task 1 create one plus Tasks 6, 7 and 8
append a line each. That premise was wrong.
Tested: a pragma Singleton in modules/sub/, reached by a plain
import "modules/sub", resolves with no qmldir anywhere. The control was a
reference to a genuinely undefined type, which warns "ReferenceError:
<name> is not defined"; the singleton case produced no such warning and
the binding evaluated. This matches what AGENTS.md already documented
about Theme.qml, which the code review pointed out.
Four registration steps removed and the remaining steps renumbered. The
AGENTS.md note Task 9 adds now records the tested behaviour rather than
the invented one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01We9zcHEH8ZWHPcQwMaJRNv
|
|
The paths are written with a tilde because this file is committed and the
repo forbids home paths in committed files. But neither Hyprland's
exec_cmd nor waybar's exec goes through a shell, so a tilde there never
expands and fails silently, which reads as a broken keybind rather than a
bad path. The two rules genuinely conflict here, so the plan now says
which form goes where instead of shipping lines that would not run.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01We9zcHEH8ZWHPcQwMaJRNv
|
|
Ten tasks: skeleton, contract, chrome, drawer, then the four modules in
increasing order of risk, then documentation, then the six config edits
outside this repo.
Appearance goes first among the modules despite being last in the grid,
because it is nine lines of substance and puts something in the grid
before the three migrations start. Sound, mail and vm follow in that
order: sound splits one 302-line file into three, mail is the gentlest
move and carries the only automated oracle in the project, and vm is the
largest and the one whose polling behaviour actually changes.
Each task leaves the repo working, because several delete a component and
a half-finished deletion is painful to unpick.
Paths in the config task are written with a tilde: the gitleaks hook
rejected the absolute form, correctly, since this file is committed and
the live Hyprland config it describes is not.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01We9zcHEH8ZWHPcQwMaJRNv
|
|
Six tasks, TDD against one bash check rather than a framework: the
script is sourced as a library so the pure functions, the ones that
only move text around, are asserted without notmuch, dunstify or
inotify in the picture.
The two parsing traps that already cost this component a debugging
session each get a fixture apiece: a key containing dots, and a
folder value containing a bracket.
Verification does not wait for mail. Backdating the stored revision
by 2000 replays a real window on demand, and the seed run before it
proves the anti-storm rule with 101 unread messages on disk.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ZwWrCEbdKzmisfg9bb1nS
|
|
Implementing the model found it. The property reads undefined, so the
planned sort compared NaN and silently did nothing, leaving the list in
arbitrary tracker order while looking entirely plausible. It is on
lastIpcObject instead.
Carried into the plan's later tasks so the grid does not reintroduce the
bare property, and into the notes that Task 6 puts in AGENTS.md, since a
sort that quietly does nothing is the kind of wrong answer this repo's
notes exist to prevent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
|
|
The screen was found by a name written inline, falling back to null. The
other three panels all take a monitor property and fall back to
screens[0], so this now does too: a machine without a DP-1 gets its first
monitor rather than a null screen, and the name is in one place if it
ever needs changing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
|
|
Six tasks, each ending in a commit: the skeleton and the keyboard grab,
the window model, one card, the grid and empty state, the Hyprland
wiring, and the docs.
Two things were checked against the running system while writing it
rather than left for the implementation to discover. The keyboard grab
works: Keys.onEscapePressed on a focused Item inside the layer surface
fires, so the AGENTS.md workaround holds and keyboard navigation is safe
to build on. And the dispatcher for sending a key is send_shortcut with
the underscore; sendshortcut does not exist, and a test written against
that name would have failed in a way that looks exactly like the key
never arriving.
No qmldir is added. There is none anywhere in this repo and Theme
resolves without one, since quickshell scans the config directory itself;
the AGENTS.md note about needing one is about singletons outside it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
|
|
The user works at this machine and runs the shell themselves. An agent
executing this plan writes code and runs non-GUI checks, then hands over the
command and the numbers to compare against; the four steps that need a running
qs are now marked as the user's.
Also warns against a bare pkill -x qs, which would take down the three
components the user already has running.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWL8JYHu7yhAdtx5pU9PMU
|
|
The previous commit, the spec and the plan all said notmuch exits 0 on a
malformed query while printing something that is not a count, and that
validating the output as an integer therefore catches it. Measured properly,
that is wrong in a way worth recording, because the truth is worse.
notmuch fails two different ways. A rejected query prints nothing and exits 1:
`notmuch count 'tag:unread and ('`. A query Xapian merely misparses returns a
plausible wrong number and exits 0: `notmuch count 'tag:unread and (('` gives
41, and `'tag:unread and tag:'` gives 3. The second is undetectable by any
check on the output, which is why the original claim was not just imprecise
but inverted: the case it described as caught is the case nothing can catch.
The integer validation still earns its place, on the first failure mode, where
empty output would otherwise render as an empty inbox. The real defence
against the second is that QUERY is a fixed string and is never built from
anything, which the comment now says.
The earlier measurement that produced the wrong claim read 40 as mangled
output when it was a successful parse answering a different question.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWL8JYHu7yhAdtx5pU9PMU
|
|
Seven tasks, ordered so the thing most likely to be wrong is checked first.
The watcher script comes before any QML because it is the only piece with a
real runnable check and needs no compositor. The component skeleton gets its
own commit because the failure it guards against is invisible: a config whose
only window is hidden exits straight after logging Configuration Loaded and
reports no error.
Two decisions changed while reading the existing components. The drawer is a
fullscreen overlay with content anchored top right, which is the idiom both
other panels use and what gives click-outside and Escape for free, rather
than a small anchored window. And its exclusionMode is Normal rather than the
Ignore those two use, so waybar's exclusive zone places it below the bar
without this component carrying the bar's 42px height as a constant to drift.
Also records a trap measured this session: notmuch exits 0 even for a
malformed query, printing something that is not a count, so every count is
validated as an integer rather than trusting the exit status. A failure that
rendered as 0 would look exactly like an empty inbox.
The live-config task needs real absolute paths, because waybar's exec and
Hyprland's Lua strings do not expand a tilde. They are written as <repo> and
<home> placeholders with a note to substitute, since the gitleaks hook blocks
committed home paths and was right to reject the first attempt.
The spec was updated to match both changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWL8JYHu7yhAdtx5pU9PMU
|