Slice 23 - Local Automation
Scope#
Add the first Python automation surface:
codealmanac automation install [sync|garden...]
codealmanac automation status [sync|garden...]
codealmanac automation uninstall [sync|garden...]This slice installs local launchd jobs for foreground sync and garden.
It does not add a background worker, pending sync reconciliation, legacy
capture migration, or scheduled update checks.
Design#
Automation is a service, not a workflow. It decides which local recurring tasks should exist and how their commands should be shaped. It does not decide sync eligibility, Garden behavior, run lifecycle, transcript parsing, or wiki writes.
result = app.automation.install(InstallAutomationRequest(...))
report = app.automation.status(AutomationStatusRequest(...))
removed = app.automation.uninstall(UninstallAutomationRequest(...))The scheduler is a port owned by services/automation/ports.py. The launchd
implementation lives under integrations/automation/scheduler/launchd.py and
translates ScheduledJob models into launchd plist files.
Cosmic Python chapter 13 shaped this slice: app.py is the composition root
that wires AutomationService to the concrete launchd adapter. CLI and tests
call the service boundary, and tests inject a fake scheduler instead of
monkeypatching launchctl behavior.
The adapter uses Python's stdlib plistlib for property-list serialization.
The archived TypeScript code hand-rendered XML; the Python rewrite should use
the structured plist API instead of rebuilding an XML serializer.
Behavior#
Default install selects sync and garden.
sync is machine-global:
python -m codealmanac.cli.main sync --quiet 45mIt has no working directory because sync discovers quiet transcript stores and maps them back to repos.
garden is repo-scoped:
python -m codealmanac.cli.main gardenInstalling Garden resolves the current workspace and writes that repo root as
launchd WorkingDirectory. automation status and automation uninstall do
not require a repo because they only inspect or remove plist state.
Task selection mirrors the old command feel but narrows valid v1 tasks to
sync and garden. update is not schedulable until the Python update
command exists.
Tests#
tests/test_automation_service.pycovers task planning, Garden workspace resolution, sync-only install outside a repo,--garden-off, validation, and launchd plist serialization.tests/test_cli.py::test_cli_automation_install_status_and_uninstallcovers public command parsing and rendering with a fake scheduler.tests/test_architecture.pykeeps services/workflows/CLI from importing integrations.
Deferred#
Background scheduled sync still uses the foreground sync command. Before
introducing pending cursor state, add a durable background owner and a
reconciliation loop over run records.
Scheduled update checks remain blocked on the Python codealmanac update
command and packaging policy.