feat(linux): add systemd --user backend to 4 scheduler installers - #1704
Open
takanorinishida wants to merge 1 commit into
Open
feat(linux): add systemd --user backend to 4 scheduler installers#1704takanorinishida wants to merge 1 commit into
takanorinishida wants to merge 1 commit into
Conversation
DerivedSync/CommitmentSweep/UsageAggregator/CodexUpdate are Linux-clean at runtime (no macOS dependency in the service bodies) but their installers only knew how to write a launchd plist, so none of the 4 could be scheduled on Linux. DerivedSync in particular has real user-visible impact — it's what keeps PRINCIPAL_TELOS.md (CLAUDE.md @-import) and LIFEOS_STATE.json (statusline rings) in sync with hand-edited TELOS files; without it those two files silently go stale. Follows the process.platform dispatch pattern InstallWorkSweep.ts established (PR danielmiessler#1692, ported-awaiting-release): darwin path unchanged, linux path materializes a systemd --user unit pair instead of a plist. - derivedsync: WatchPaths (7 dirs) + RunAtLoad → .path unit (PathModified x7) + .service (oneshot), service started once at install to match RunAtLoad - commitmentsweep: StartCalendarInterval 07:00 → .timer (OnCalendar, Persistent=true) + .service - usage-aggregator: StartCalendarInterval 03:30 + RunAtLoad → .timer (OnCalendar + OnBootSec=2min) + .service - codexupdate: StartCalendarInterval 04:00, no RunAtLoad → .timer (OnCalendar only) + .service ThrottleInterval becomes StartLimitIntervalSec/StartLimitBurst on the .service (not on derivedsync's .path — TriggerLimitIntervalSec needs systemd 255+, unavailable on e.g. Debian 12's 252). InstallCommitmentSweep.ts's darwin plist hardcodes /opt/homebrew/bin/bun (no detectBun()) — left untouched; only the new linux path calls the newly-added detectBun() to resolve {{BUN}} in the systemd templates. Every deletion in this diff is either a const moved a few lines (LABEL, STATE_DIR, COMMAND_TIMEOUT_MS — same value, same file) or a dispatch line that now ternaries into the same original function (renamed *Darwin, content byte-for-byte unchanged). Verified on this host (Ubuntu 24.04, systemd 255): - `systemd-analyze --user verify` passes clean on all 8 new units - DerivedSync: install → .path unit active → touching TELOS.md fired a targeted re-run (only the changed file's actions, confirmed via the tool's own derived-sync.jsonl log) → PRINCIPAL_TELOS.md regenerated; re-run is idempotent; --uninstall removes both units cleanly - UsageAggregator: install → boot-equivalent run fired immediately, exited 0, wrote usage-daily.jsonl; timer correctly queued for next 03:30 - CommitmentSweep: install → timer correctly queued for next 07:00, service not run (matches RunAtLoad false) - CodexUpdate: timer registered for 04:00; service deliberately left un-started (has global-install side effects) — `systemctl --user is-active` confirms `inactive` Also fixes BackgroundServices.md's now-inaccurate "macOS-only" claim in the Fresh Install section. Unrelated pre-existing issue found during verification, not fixed here (out of scope — a DerivedSync.ts bug, not a scheduling/installer one): DeriveDenyHashes.ts fails with ENOENT because ~/.claude/skills/_LIFEOS/ doesn't exist on this host; would fail identically under launchd.
This was referenced Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's broken
DerivedSync.ts/CommitmentSweep.ts/UsageAggregator.ts/CodexUpdate.tshave no macOS dependency in their service bodies (they're plain bun scripts), but their installers only know how to write a launchd plist — so none of the 4 can be scheduled on Linux.DerivedSyncin particular has real user-visible impact: it's what keepsPRINCIPAL_TELOS.md(imported byCLAUDE.md) andLIFEOS_STATE.json(read by the statusline rings) in sync with hand-edited TELOS files. Without it, those two files silently go stale after every TELOS edit.Fix
Follows the
process.platformdispatch patternInstallWorkSweep.tsestablished (#1692, closed/ported): darwin path untouched, linux path materializes a systemd--userunit pair instead of a plist.WatchPaths(7 dirs) +RunAtLoad→.pathunit (PathModifiedx7) +.service(oneshot); the service is started once at install time to matchRunAtLoad's "fire once when loaded" behaviorStartCalendarInterval07:00 →.timer(OnCalendar,Persistent=true) +.serviceStartCalendarInterval03:30 +RunAtLoad→.timer(OnCalendar+OnBootSec=2min) +.serviceStartCalendarInterval04:00, noRunAtLoad→.timer(OnCalendaronly) +.serviceThrottleIntervalbecomesStartLimitIntervalSec/StartLimitBurston the.service(not on derivedsync's.path—TriggerLimitIntervalSecneeds systemd 255+, unavailable on e.g. Debian 12's 252).InstallCommitmentSweep.ts's darwin plist hardcodes/opt/homebrew/bin/bun(nodetectBun()) — left untouched. Only the new linux path calls a newly-addeddetectBun()to resolve{{BUN}}in the systemd templates.Also fixes
BackgroundServices.md's now-inaccurate "macOS-only" claim in the Fresh Install section.Why this doesn't change macOS behavior
Every deletion in this diff is either a
constmoved a few lines up (LABEL,STATE_DIR,COMMAND_TIMEOUT_MS— same value, same file, just relocated next to the other platform-specific paths) or a dispatch line that now ternaries into the same original function, renamed*Darwinwith its body byte-for-byte unchanged. No darwin behavior is touched.Verification
Tested end-to-end on Ubuntu 24.04 / systemd 255:
systemd-analyze --user verifypasses clean on all 8 new units.pathunit active → touchingTELOS.mdfired a targeted re-run (confirmed via the tool's ownderived-sync.jsonllog — only the actions tied to the changed file ran) →PRINCIPAL_TELOS.mdregenerated. Re-running install is idempotent.--uninstallremoves both units cleanly.usage-daily.jsonl. Timer correctly queued for the next 03:30.RunAtLoad false).systemctl --user is-activeconfirmsinactive.Unrelated pre-existing bug found during verification, not fixed here (out of scope — it's in
DerivedSync.ts's own logic, not the installer/scheduler):DeriveDenyHashes.tsfails withENOENTbecause~/.claude/skills/_LIFEOS/doesn't exist on this host. Would fail identically under launchd.Related: #1692 (WorkSweep systemd backend, same pattern, ported).
🤖 Generated with Claude Code