Platform-specific background service management for ductor service ....
ductor_bot/infra/service.py is the single dispatcher:
- Linux ->
service_linux.py - macOS ->
service_macos.py - Windows ->
service_windows.py
Every backend exposes the same surface:
is_service_available()is_service_installed()is_service_running()install_service()start_service()stop_service()uninstall_service()print_service_status()print_service_logs()
This keeps cli_commands/service.py platform-agnostic.
- onboarding offers service install whenever the active platform backend is available
stop_bot()stops the installed service before killing the current process tree, so the service manager does not immediately respawn it- restart semantics still come from the process exit code (
42) and the surrounding backend policy - file logs live under
~/.ductor/logs/
Implementation: ductor_bot/infra/service_linux.py
Mechanism:
- systemd user service
- unit file:
~/.config/systemd/user/ductor.service - enable + start via
systemctl --user
Service unit details:
ExecStart=<ductor binary>Restart=on-failureRestartSec=5- sets
PATH,HOME, andDUCTOR_SUPERVISOR=1 WantedBy=default.target
Operational notes:
- installer attempts
sudo loginctl enable-linger <user>when linger is missing - without linger, the user service may stop after logout
ductor service logsfollowsjournalctl --user -u ductor -f --no-hostname
Implementation: ductor_bot/infra/service_macos.py
Mechanism:
- launchd Launch Agent
- plist:
~/Library/LaunchAgents/dev.ductor.plist - loaded via
launchctl load -w
Launch Agent details:
RunAtLoad=trueKeepAlive.SuccessfulExit=falseso restart happens on crash, not clean exitThrottleInterval=10ProcessType=Background- extends
PATHwith common system paths plus discovered NVM bin directories - sets
HOMEandDUCTOR_SUPERVISOR=1 - stdout/stderr go to
~/.ductor/logs/service.logandservice.err
Operational notes:
ductor service logstails file logs from~/.ductor/logs/rather than usinglaunchctl- status uses
launchctl list dev.ductor
Implementation: ductor_bot/infra/service_windows.py
Mechanism:
- Task Scheduler task named
ductor - created through
schtasks.exewith an XML definition
Task details:
- starts 10 seconds after user logon
- restart-on-failure enabled: 3 retries, 1 minute apart
- runs with
InteractiveTokenandLeastPrivilege - prefers
pythonw.exe -m ductor_botfor windowless execution - falls back to the
ductorbinary whenpythonw.exeis unavailable
Operational notes:
- some systems require an elevated terminal for task creation/removal; backend detects common access-denied variants and shows an admin hint panel
ductor service logstails file logs from~/.ductor/logs/- the backend writes a temporary XML file under
~/.ductor/ductor_task.xmlduring install and removes it after task creation
If service behavior looks wrong, the first question is not "is the bot broken?" but "which backend owns this process?"
- Linux issues usually mean systemd user-service state or missing linger
- macOS issues usually mean Launch Agent load state or PATH resolution
- Windows issues usually mean Task Scheduler permissions or
pythonw.exeresolution
For CLI routing see docs/modules/cli_commands.md. For low-level infra context see docs/modules/infra.md.