Skip to content

feat: Linux support — graceful automation skip on non-macOS (fixes #31)#51

Open
YasienDwieb wants to merge 1 commit into
AlmanacCode:mainfrom
YasienDwieb:linux-support-option-a
Open

feat: Linux support — graceful automation skip on non-macOS (fixes #31)#51
YasienDwieb wants to merge 1 commit into
AlmanacCode:mainfrom
YasienDwieb:linux-support-option-a

Conversation

@YasienDwieb

Copy link
Copy Markdown

Fixes #31.

Problem

codealmanac setup --yes (and config set automation.*) crash on Linux:

codealmanac: launchctl bootstrap failed for com.codealmanac.sync: [Errno 2] No such file or directory: 'launchctl'

create_app unconditionally wires AutomationService with LaunchdSchedulerAdapter, which shells out to macOS launchctl. The crash also left a half-configured global state (config.toml written before the scheduler failed).

Approach — Option A: graceful skip, not a rewrite

Every lifecycle/read command is already platform-neutral; the only macOS blocker is scheduled automation, and SchedulerAdapter is already a port. So:

  • UnsupportedSchedulerAdapter — a no-op implementation of the existing SchedulerAdapter port (no subprocess, no ~/Library/LaunchAgents writes; reports "not installed").
  • core/platform.scheduler_supported() — single platform predicate. create_app selects launchd on macOS, the unsupported adapter elsewhere. Platform detection lives only at the composition root.
  • Render reflects the outcome, not the platform. AutomationTaskApplyResult gains a scheduled field set from the adapter's real result (install().installed). Setup output now says "Scheduled automation unavailable" with a "run sync/garden manually" pointer instead of falsely claiming schedules were installed. Render stays free of sys.platform checks.

Because nothing fails on the unsupported path, the half-configured-state bug is gone as a side effect — setup completes and exits 0.

Real Linux scheduling (systemd user timers) is deliberately left as a follow-up (Option B); this PR unblocks all Linux usage today.

Verification

  • uv run ruff check . clean; 570 tests pass (6 new in tests/test_linux_support.py, platform forced via sys.platform so they're host-independent).
  • Smoke-tested on real Ubuntu: the former crash path (config set automation.sync.enabled true) exits 0, automation status works, no launchd artifacts created.
  • macOS output is unchanged: launchd's install().installed is True, so every existing render branch is taken as before.

A design writeup is in docs/plans/2026-07-24-linux-support-option-a.md.

Select the scheduler adapter at the composition root: launchd on macOS, a
no-op UnsupportedSchedulerAdapter elsewhere. setup/config no longer crash on
launchctl off macOS; render reports scheduling unavailable from the adapter's
actual outcome via a new AutomationTaskApplyResult.scheduled field.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: setup --yes crashes on Linux because scheduled automation is macOS/launchd-only

1 participant