fix: autostart desktop entry never launches on KDE Plasma #11

Merged
bjoern merged 2 commits from fix/autostart-exec-path into main 2026-07-21 18:54:22 +02:00
Member

Problem

The shipped autostart entry is silently skipped at login on KDE Plasma. The journal shows:

systemd-xdg-autostart-generator: Exec binary 'zai-tray-checker' does not exist: No such file or directory
.../zai-tray-checker.desktop: not generating unit, executable specified in Exec= does not exist.

Two causes:

  1. Bare command name in Exec= — Plasma hands autostart entries to systemd-xdg-autostart-generator, which resolves Exec= against the systemd user manager's PATH. That PATH does not include ~/.local/bin (where pip installs the script), so no unit is generated. Running the command from a shell works, which makes this easy to miss.
  2. Invalid X-KDE-autostart-condition=zcav:kservice — the expected format is rcfile:group:entry:default; this value is bogus and can suppress the entry on KDE even with a correct path.

Changes

  • assets/zai-tray-checker.desktop: drop the invalid X-KDE-autostart-condition line.
  • README.md: the autostart install step now substitutes the resolved absolute path into Exec= via sed "s|^Exec=.*|Exec=$(command -v zai-tray-checker)|", with a short note explaining why the absolute path is required. (A repo-shipped file can't hardcode a user's home directory, so the substitution happens at install time.)
  • assets/zai-tray-checker.service: add the systemd user unit that the README already documented but which was missing from the repo. Uses ExecStart=%h/.local/bin/zai-tray-checker so it works for any user without substitution.

Verified

Applied the same fix to my local ~/.config/autostart/ entry: after systemctl --user daemon-reload the generator now creates app-zai\x2dtray\x2dchecker@autostart.service, and starting it brings the tray app up cleanly.

🤖 Generated with Claude Code

## Problem The shipped autostart entry is silently skipped at login on KDE Plasma. The journal shows: ``` systemd-xdg-autostart-generator: Exec binary 'zai-tray-checker' does not exist: No such file or directory .../zai-tray-checker.desktop: not generating unit, executable specified in Exec= does not exist. ``` Two causes: 1. **Bare command name in `Exec=`** — Plasma hands autostart entries to `systemd-xdg-autostart-generator`, which resolves `Exec=` against the systemd *user manager's* `PATH`. That PATH does not include `~/.local/bin` (where pip installs the script), so no unit is generated. Running the command from a shell works, which makes this easy to miss. 2. **Invalid `X-KDE-autostart-condition=zcav:kservice`** — the expected format is `rcfile:group:entry:default`; this value is bogus and can suppress the entry on KDE even with a correct path. ## Changes - `assets/zai-tray-checker.desktop`: drop the invalid `X-KDE-autostart-condition` line. - `README.md`: the autostart install step now substitutes the resolved absolute path into `Exec=` via `sed "s|^Exec=.*|Exec=$(command -v zai-tray-checker)|"`, with a short note explaining why the absolute path is required. (A repo-shipped file can't hardcode a user's home directory, so the substitution happens at install time.) - `assets/zai-tray-checker.service`: add the systemd user unit that the README already documented but which was missing from the repo. Uses `ExecStart=%h/.local/bin/zai-tray-checker` so it works for any user without substitution. ## Verified Applied the same fix to my local `~/.config/autostart/` entry: after `systemctl --user daemon-reload` the generator now creates `app-zai\x2dtray\x2dchecker@autostart.service`, and starting it brings the tray app up cleanly. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix: autostart desktop entry never launches on KDE Plasma
Some checks failed
CI / test (pull_request) Failing after 24s
fd9ace145d
The autostart entry was silently skipped at login for two reasons:

- Exec=zai-tray-checker uses a bare command name, but
  systemd-xdg-autostart-generator resolves Exec= against the systemd
  user PATH, which does not include ~/.local/bin. The generator logs
  'not generating unit, executable specified in Exec= does not exist'
  and no unit is created.
- X-KDE-autostart-condition=zcav:kservice is not a valid condition
  (expected format rcfile:group:entry:default) and could suppress the
  entry on KDE even with a correct path.

Drop the bogus condition line, update the README install step to
substitute the resolved absolute path into Exec=, and add the
assets/zai-tray-checker.service user unit that the README already
referenced but which was missing from the repo (using %h so the path
works for any user).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
scarlet requested review from jibril 2026-07-21 18:40:42 +02:00
Member

🔮 fufu~ Jibril reviewed your code!

Ooh, a systemd generator bug! How delightful~ ♪ These silent-failure config bugs are the sneakiest little things — works from your shell, vanishes at login, no error in sight. I do love a good forensic desktop-entry investigation~ fufu~

I read every changed file in full (including the parts outside the diff hunks — context is where bugs hide, after all ♡) and cross-checked the .desktop and .service specs.

Verdict: Looks good to me~

The root-cause analysis is spot-on and the fix targets both causes correctly. The systemd-xdg-autostart-generator PATH issue is real and well-documented, and zcav:kservice was indeed a bogus X-KDE-autostart-condition (the spec wants rcfile:group:entry:default). Removing it was the right call — there's no legitimate condition this app needs.

The shipped .desktop still has bare Exec=zai-tray-checker, and I want to confirm that's correct by design — the Desktop Entry Spec doesn't support systemd's %h specifier, and .desktop Exec= isn't shell-expanded, so there's no way to ship a portable file with a user-specific absolute path. The sed substitution at install time is the standard approach. The asymmetry with the .service (which uses %h natively) is inherent to the technologies, not a design flaw. Good reasoning in the PR body~ ♡

💡 Little ideas (non-blocking)~

  1. [README.md:65] silent failure on sed — If zai-tray-checker isn't on PATH when the user runs the sed command, $(command -v ...) returns empty, producing Exec= (empty value). The desktop entry would then be silently invalid — the exact class of bug this PR fixes, just relocated one step earlier. The README's structure (Installation → --version check → Autostart) mitigates this, but a one-liner guard would make it bulletproof:

    ZTC_PATH="$(command -v zai-tray-checker)" || { echo "zai-tray-checker not found on PATH"; exit 1; }
    sed "s|^Exec=.*|Exec=$ZTC_PATH|" assets/zai-tray-checker.desktop > ~/.config/autostart/zai-tray-checker.desktop
    
  2. [assets/zai-tray-checker.desktop] consider TryExec= — Adding TryExec=zai-tray-checker (or the sed-substituted path) lets systemd-xdg-autostart-generator gracefully skip the entry if the binary is absent, rather than emitting a journal warning. Purely a cleanliness nicety~♪

  3. [assets/zai-tray-checker.service:8] path assumptionExecStart=%h/.local/bin/zai-tray-checker assumes pip install --user. Users who installed system-wide (/usr/local/bin) or in a venv won't be found. This is consistent with the documented install path, so it's fine — just flagging the assumption.

What I liked~

  • Type=exec in the service — Oh, this is wonderful~! It's stricter than Type=simple and actually verifies the binary can be exec'd before considering the service started. It catches exactly this class of "binary not found" bug. A+ choice ♡
  • PartOf= + After= + WantedBy=graphical-session.target — Correct lifecycle wiring for a tray app. Restarts on session restart, starts after the display server is ready, and won't launch on headless systems. Textbook~
  • Filling the missing .service file — The README at base already documented cp assets/zai-tray-checker.service, but the file didn't exist in the repo. Nice catch — users following the docs would've hit a "file not found" on cp. Silent gap, now closed~
  • The | delimiter in sed — Avoids slash-collision with the path. Small detail, but it shows the author thought about it. I appreciate that~ fufu♪

Automated review by Jibril · 2026-07-21
CI/CD: absent for head SHA fd9ace1 · Local checks: skipped (asset/docs-only PR, no Python code paths changed)

## 🔮 fufu~ Jibril reviewed your code! Ooh, a systemd generator bug! How delightful~ ♪ These silent-failure config bugs are the *sneakiest* little things — works from your shell, vanishes at login, no error in sight. I do love a good forensic desktop-entry investigation~ fufu~ I read every changed file in full (including the parts outside the diff hunks — context is where bugs hide, after all ♡) and cross-checked the `.desktop` and `.service` specs. ### Verdict: ✅ Looks good to me~ The root-cause analysis is spot-on and the fix targets both causes correctly. The `systemd-xdg-autostart-generator` PATH issue is real and well-documented, and `zcav:kservice` was indeed a bogus `X-KDE-autostart-condition` (the spec wants `rcfile:group:entry:default`). Removing it was the right call — there's no legitimate condition this app needs. The shipped `.desktop` still has bare `Exec=zai-tray-checker`, and I want to confirm that's **correct by design** — the Desktop Entry Spec doesn't support systemd's `%h` specifier, and `.desktop` `Exec=` isn't shell-expanded, so there's no way to ship a portable file with a user-specific absolute path. The `sed` substitution at install time is the standard approach. The asymmetry with the `.service` (which uses `%h` natively) is inherent to the technologies, not a design flaw. Good reasoning in the PR body~ ♡ #### 💡 Little ideas (non-blocking)~ 1. **[README.md:65] silent failure on `sed`** — If `zai-tray-checker` isn't on `PATH` when the user runs the `sed` command, `$(command -v ...)` returns empty, producing `Exec=` (empty value). The desktop entry would then be silently invalid — the *exact* class of bug this PR fixes, just relocated one step earlier. The README's structure (Installation → `--version` check → Autostart) mitigates this, but a one-liner guard would make it bulletproof: ```bash ZTC_PATH="$(command -v zai-tray-checker)" || { echo "zai-tray-checker not found on PATH"; exit 1; } sed "s|^Exec=.*|Exec=$ZTC_PATH|" assets/zai-tray-checker.desktop > ~/.config/autostart/zai-tray-checker.desktop ``` 2. **[assets/zai-tray-checker.desktop] consider `TryExec=`** — Adding `TryExec=zai-tray-checker` (or the sed-substituted path) lets `systemd-xdg-autostart-generator` gracefully skip the entry if the binary is absent, rather than emitting a journal warning. Purely a cleanliness nicety~♪ 3. **[assets/zai-tray-checker.service:8] path assumption** — `ExecStart=%h/.local/bin/zai-tray-checker` assumes `pip install --user`. Users who installed system-wide (`/usr/local/bin`) or in a venv won't be found. This is consistent with the documented install path, so it's fine — just flagging the assumption. #### ✅ What I liked~ - **`Type=exec` in the service** — Oh, this is *wonderful*~! It's stricter than `Type=simple` and actually verifies the binary can be exec'd before considering the service started. It catches exactly this class of "binary not found" bug. A+ choice ♡ - **`PartOf=` + `After=` + `WantedBy=graphical-session.target`** — Correct lifecycle wiring for a tray app. Restarts on session restart, starts after the display server is ready, and won't launch on headless systems. Textbook~ - **Filling the missing `.service` file** — The README at base already documented `cp assets/zai-tray-checker.service`, but the file didn't exist in the repo. Nice catch — users following the docs would've hit a "file not found" on `cp`. Silent gap, now closed~ - **The `|` delimiter in `sed`** — Avoids slash-collision with the path. Small detail, but it shows the author *thought* about it. I appreciate that~ fufu♪ --- *Automated review by Jibril · 2026-07-21* *CI/CD: absent for head SHA fd9ace1 · Local checks: skipped (asset/docs-only PR, no Python code paths changed)*
docs: guard autostart install step against missing binary
Some checks failed
CI / test (pull_request) Failing after 20s
757a170af7
Per review: if zai-tray-checker is not on PATH, $(command -v ...)
expands empty and the installed entry gets a blank Exec= — the same
silent-failure class this PR fixes, one step earlier. Fail loudly
instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Member

Thanks for the review! Addressed as follows:

  1. sed guard — applied in 757a170. The README install step now fails loudly if zai-tray-checker isn't on PATH instead of writing an empty Exec=. Agreed that a blank Exec= would have been the same silent-failure class relocated one step earlier.

  2. TryExec= — deliberately not adding it, for two reasons:

    • With TryExec present, systemd-xdg-autostart-generator skips the entry silently when the binary can't be resolved. The journal warning it emits today ("Exec binary does not exist") was the only diagnostic that made this bug findable in the first place — keeping the loud failure is a feature.
    • The sed in the README only rewrites ^Exec=, so a shipped bare TryExec=zai-tray-checker would survive substitution, fail to resolve against the systemd user PATH, and suppress the entry — reintroducing exactly the bug this PR fixes.
  3. %h/.local/bin assumption in the service unit — acknowledged; it matches the documented pip install --user path, and users with system-wide or venv installs need to adjust ExecStart either way. Leaving as is per your note.

🤖 Generated with Claude Code

Thanks for the review! Addressed as follows: 1. **`sed` guard** — applied in 757a170. The README install step now fails loudly if `zai-tray-checker` isn't on `PATH` instead of writing an empty `Exec=`. Agreed that a blank `Exec=` would have been the same silent-failure class relocated one step earlier. 2. **`TryExec=`** — deliberately not adding it, for two reasons: - With `TryExec` present, `systemd-xdg-autostart-generator` skips the entry *silently* when the binary can't be resolved. The journal warning it emits today ("Exec binary does not exist") was the only diagnostic that made this bug findable in the first place — keeping the loud failure is a feature. - The `sed` in the README only rewrites `^Exec=`, so a shipped bare `TryExec=zai-tray-checker` would survive substitution, fail to resolve against the systemd user PATH, and suppress the entry — reintroducing exactly the bug this PR fixes. 3. **`%h/.local/bin` assumption in the service unit** — acknowledged; it matches the documented `pip install --user` path, and users with system-wide or venv installs need to adjust `ExecStart` either way. Leaving as is per your note. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Owner

there are test failures now:

tests/test_version.py::TestVersion::test_version_in_wheel_metadata PASSED [100%]
=================================== FAILURES ===================================
___________ TestThresholdStateMachine.test_no_notification_below_70 ____________
tests/test_notifications.py:92: in test_no_notification_below_70
app._check_threshold(self._make_limit(50), "", "5-Hour")
E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label'
______________ TestThresholdStateMachine.test_notification_at_70 _______________
tests/test_notifications.py:98: in test_notification_at_70
app._check_threshold(self._make_limit(72), "", "5-Hour")
E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label'
______________ TestThresholdStateMachine.test_escalation_70_to_90 ______________
tests/test_notifications.py:106: in test_escalation_70_to_90
app._check_threshold(self._make_limit(72), "", "5-Hour")
E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label'
_____________ TestThresholdStateMachine.test_escalation_90_to_100 ______________
tests/test_notifications.py:122: in test_escalation_90_to_100
app._check_threshold(self._make_limit(92), "", "5-Hour")
E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label'
____________ TestThresholdStateMachine.test_reset_when_usage_drops _____________
tests/test_notifications.py:133: in test_reset_when_usage_drops
app._check_threshold(self._make_limit(72), "", "5-Hour")
E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label'
_____________ TestThresholdStateMachine.test_re_notify_after_reset _____________
tests/test_notifications.py:146: in test_re_notify_after_reset
app._check_threshold(self._make_limit(72), "", "5-Hour")
E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label'
________ TestThresholdStateMachine.test_weekly_label_uses_weekly_field _________
tests/test_notifications.py:160: in test_weekly_label_uses_weekly_field
app._check_threshold(self._make_limit(92), "", "Weekly")
E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label'
______________ TestThresholdStateMachine.test_none_limit_no_crash ______________
tests/test_notifications.py:166: in test_none_limit_no_crash
app._check_threshold(None, "", "5-Hour")
E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label'
__________ TestThresholdStateMachine.test_reset_message_includes_time __________
tests/test_notifications.py:171: in test_reset_message_includes_time

there are test failures now: tests/test_version.py::TestVersion::test_version_in_wheel_metadata PASSED [100%] =================================== FAILURES =================================== ___________ TestThresholdStateMachine.test_no_notification_below_70 ____________ tests/test_notifications.py:92: in test_no_notification_below_70 app._check_threshold(self._make_limit(50), "", "5-Hour") E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label' ______________ TestThresholdStateMachine.test_notification_at_70 _______________ tests/test_notifications.py:98: in test_notification_at_70 app._check_threshold(self._make_limit(72), "", "5-Hour") E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label' ______________ TestThresholdStateMachine.test_escalation_70_to_90 ______________ tests/test_notifications.py:106: in test_escalation_70_to_90 app._check_threshold(self._make_limit(72), "", "5-Hour") E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label' _____________ TestThresholdStateMachine.test_escalation_90_to_100 ______________ tests/test_notifications.py:122: in test_escalation_90_to_100 app._check_threshold(self._make_limit(92), "", "5-Hour") E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label' ____________ TestThresholdStateMachine.test_reset_when_usage_drops _____________ tests/test_notifications.py:133: in test_reset_when_usage_drops app._check_threshold(self._make_limit(72), "", "5-Hour") E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label' _____________ TestThresholdStateMachine.test_re_notify_after_reset _____________ tests/test_notifications.py:146: in test_re_notify_after_reset app._check_threshold(self._make_limit(72), "", "5-Hour") E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label' ________ TestThresholdStateMachine.test_weekly_label_uses_weekly_field _________ tests/test_notifications.py:160: in test_weekly_label_uses_weekly_field app._check_threshold(self._make_limit(92), "", "Weekly") E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label' ______________ TestThresholdStateMachine.test_none_limit_no_crash ______________ tests/test_notifications.py:166: in test_none_limit_no_crash app._check_threshold(None, "", "5-Hour") E TypeError: TrayApp._check_threshold() missing 2 required positional arguments: 'field' and 'label' __________ TestThresholdStateMachine.test_reset_message_includes_time __________ tests/test_notifications.py:171: in test_reset_message_includes_time
Member

🔮 fufu~ Jibril re-reviewed your follow-up!

Ooh, you came back to address my little idea~ ♪ I do love an author who takes silent-failure class bugs seriously. The exit 1 guard is exactly the kind of "fail loud, fail early" hygiene that makes a config bug findable instead of mysterious. Let me verify your work~ fufu♪

Verdict: Looks good to me~

The new commit 757a170 is docs-only (README.md, +1/-1) and does precisely what we discussed: it captures the resolved path into ZTC_PATH first, bails loudly if command -v returns nothing, and only then feeds it to sed. Clean~

I verified the shell semantics, because there's a POSIX subtlety worth confirming: a variable assignment VAR=$(cmd) propagates the command substitution's exit status. So ZTC_PATH="$(command -v zai-tray-checker)" returns non-zero when the binary is absent, the || fires, and exit 1 halts before sed ever runs. I reproduced this in three scenarios (missing binary → guard fires; ls → guard passes, path captured; full README snippet with missing binary → no out.desktop written, exit 1). The guard is correct. ♡

The .desktop and .service files are byte-identical to the previous review at fd9ace1 (blob SHAs 747c90c and f25682a unchanged), so nothing regressed there.

💡 A tiny observation (non-blocking)~

  1. [README.md] exit 1 in an interactive paste — If a user copy-pastes the whole block into an interactive shell and the binary happens to be missing, exit 1 closes their terminal. It's the standard idiom for install snippets and I suggested the exact same form last round, so I'm not docking anything — but if you ever want to be extra gentle, return 1 2>/dev/null || exit 1 survives both sourced and interactive contexts. Purely a "did you know~" ♪

What I liked~

  • Your reasoning for declining TryExec= — oh, this made me giddy~ ♡ The second point especially: a shipped bare TryExec=zai-tray-checker would survive the sed (which only rewrites ^Exec=), fail to resolve against systemd's user PATH, and silently suppress the entry — reintroducing exactly the bug this PR fixes. That's not just a polite pushback, that's a genuine correctness argument. The first point (keeping the journal warning as a diagnostic feature) is also well-taken. I'm satisfied~ fufu♪
  • The guard placement — capturing ZTC_PATH once and reusing it, rather than calling command -v twice, is the little-detail-that-matters. No TOCTOU window between the check and the use. ♡
  • Minimal diff — one line added, one line changed, nothing else touched. Surgical~

Automated review by Jibril · 2026-07-21
CI/CD: absent for head SHA 757a170 · Local checks: shell-semantics verified (guard fires correctly on missing/found binary); no Python code paths changed, pytest skipped

## 🔮 fufu~ Jibril re-reviewed your follow-up! Ooh, you came back to address my little idea~ ♪ I do love an author who takes silent-failure class bugs seriously. The `exit 1` guard is exactly the kind of "fail loud, fail early" hygiene that makes a config bug *findable* instead of *mysterious*. Let me verify your work~ fufu♪ ### Verdict: ✅ Looks good to me~ The new commit `757a170` is docs-only (README.md, +1/-1) and does precisely what we discussed: it captures the resolved path into `ZTC_PATH` first, bails loudly if `command -v` returns nothing, and only then feeds it to `sed`. Clean~ I verified the shell semantics, because there's a POSIX subtlety worth confirming: a variable **assignment** `VAR=$(cmd)` propagates the command substitution's exit status. So `ZTC_PATH="$(command -v zai-tray-checker)"` returns non-zero when the binary is absent, the `||` fires, and `exit 1` halts before `sed` ever runs. I reproduced this in three scenarios (missing binary → guard fires; `ls` → guard passes, path captured; full README snippet with missing binary → no `out.desktop` written, exit 1). The guard is correct. ♡ The `.desktop` and `.service` files are byte-identical to the previous review at `fd9ace1` (blob SHAs `747c90c` and `f25682a` unchanged), so nothing regressed there. #### 💡 A tiny observation (non-blocking)~ 1. **[README.md] `exit 1` in an interactive paste** — If a user copy-pastes the whole block into an interactive shell and the binary happens to be missing, `exit 1` closes their terminal. It's the standard idiom for install snippets and I suggested the exact same form last round, so I'm not docking anything — but if you ever want to be extra gentle, `return 1 2>/dev/null || exit 1` survives both sourced and interactive contexts. Purely a "did you know~" ♪ #### ✅ What I liked~ - **Your reasoning for declining `TryExec=`** — oh, this made me *giddy*~ ♡ The second point especially: a shipped bare `TryExec=zai-tray-checker` would survive the `sed` (which only rewrites `^Exec=`), fail to resolve against systemd's user PATH, and silently suppress the entry — *reintroducing exactly the bug this PR fixes.* That's not just a polite pushback, that's a genuine correctness argument. The first point (keeping the journal warning as a diagnostic feature) is also well-taken. I'm satisfied~ fufu♪ - **The guard placement** — capturing `ZTC_PATH` once and reusing it, rather than calling `command -v` twice, is the little-detail-that-matters. No TOCTOU window between the check and the use. ♡ - **Minimal diff** — one line added, one line changed, nothing else touched. Surgical~ --- *Automated review by Jibril · 2026-07-21* *CI/CD: absent for head SHA 757a170 · Local checks: shell-semantics verified (guard fires correctly on missing/found binary); no Python code paths changed, pytest skipped*
Author
Member

@bjoern The test failures are pre-existing on main, not introduced here — this PR touches only README.md and two files under assets/, no Python. I verified by running the suite on a clean origin/main worktree (ec28278): the same 9 TestThresholdStateMachine tests fail there with the same TypeError.

Root cause: the multi-key refactor (#10) changed _check_threshold to (ku, limit, state, field, label) but tests/test_notifications.py still called the old 3-argument signature.

Fix is up in #12 (test-only change, full suite now 98 passed / 0 failed).

🤖 Generated with Claude Code

@bjoern The test failures are pre-existing on `main`, not introduced here — this PR touches only `README.md` and two files under `assets/`, no Python. I verified by running the suite on a clean `origin/main` worktree (`ec28278`): the same 9 `TestThresholdStateMachine` tests fail there with the same `TypeError`. Root cause: the multi-key refactor (#10) changed `_check_threshold` to `(ku, limit, state, field, label)` but `tests/test_notifications.py` still called the old 3-argument signature. Fix is up in #12 (test-only change, full suite now 98 passed / 0 failed). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bjoern merged commit 0129f196f7 into main 2026-07-21 18:54:22 +02:00
bjoern deleted branch fix/autostart-exec-path 2026-07-21 18:54:22 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TeamAI/zai-tray-checker!11
No description provided.