infra/¶
Runtime infrastructure: process lifecycle, restart/update flow, Docker sandbox, service backends, shared low-level helpers.
Files¶
- process/runtime:
pidlock.py,restart.py,inflight.py,recovery.py,startup_state.py,boot_id.py - watchers:
file_watcher.py - secrets:
env_secrets.py - Docker:
docker.py,docker_extras.py - service:
service.py,service_base.py,service_logs.py,service_linux.py,service_macos.py,service_windows.py - update/version:
install.py,version.py,updater.py - filesystem/atomic I/O:
fs.py,atomic_io.py,json_store.py - shared observer/task helpers:
base_observer.py,base_task_observer.py,task_runner.py - platform/process helpers:
platform.py,process_tree.py
Startup and recovery state¶
State files under ~/.sygen/:
startup_state.jsoninflight_turns.json
Behavior:
- startup kind detection:
first_start,service_restart,system_reboot - in-flight foreground turns are tracked for restart recovery planning
- named-session recovery candidates are merged by
RecoveryPlanner
PID lock and single-instance control¶
acquire_lock(pid_file, kill_existing=True) ensures one active runtime instance.
run_bot() acquires lock at startup and releases it on shutdown.
Restart protocol¶
Restart code: 42 (EXIT_RESTART).
/restartwrites sentinel and stops polling- service/supervisor context: process exits with restart code
- foreground direct context: process re-exec path
Lifecycle stop behavior¶
stop_bot() (implemented in cli_commands/lifecycle.py):
- stop installed service
- kill PID-file instance
- kill remaining sygen processes
- short Windows lock-release wait
- stop Docker container when enabled
Docker manager¶
DockerManager.setup() handles:
- daemon/image/container checks
- container (re)start
- mounts:
~/.sygen -> /sygen- provider homes (
~/.claude,~/.codex,~/.gemini,~/.claude.jsonwhen present) - optional host cache mount
- user-configured
docker.mountsto/mnt/<name>
Docker extras (docker_extras.py):
DockerExtrafrozen dataclass registry of optional AI/ML packages (Whisper, PyTorch, OpenCV, Tesseract, etc.)resolve_extras()resolves transitive dependencies in topological ordergenerate_dockerfile_extras()appendsRUNblocks (apt + pip) to the base Dockerfile- packages with custom
--index-url(e.g. PyTorch CPU) are installed before standard PyPI packages to prevent CUDA variant downloads calculate_build_timeout()adds per-extra timeout to the base build timeout- build output is streamed live via
_exec_stream()to the Rich console
Fallback behavior:
- if Docker setup/recovery fails, runtime falls back to host execution.
Service backends¶
Platform dispatch via infra/service.py:
- Linux: systemd user service
- macOS: launchd
- Windows: Task Scheduler
sygen service logs:
- Linux: journal stream
- macOS/Windows: file tail from
~/.sygen/logs/agent.log(fallback newest*.log)
Deep dive: service_management
Atomic persistence helpers¶
atomic_io.py:atomic_text_save,atomic_bytes_savejson_store.py:atomic_json_save,load_json
These are used across session/task/cron/webhook/config persistence paths.
Environment secrets (env_secrets.py)¶
Centralised loading of user-defined API secrets from ~/.sygen/.env.
- standard dotenv syntax (comments,
exportprefix, single/double quotes) - loaded once per process and cached
- injected at three points:
_build_subprocess_env()inexecutor.py(host CLI execution)docker_wrap()inbase.py(docker exec -eflags)_start_container()indocker.py(docker run -eflags)- existing environment variables are never overridden
- provider-specific
extra_env(e.g.GEMINI_API_KEYfrom config) takes precedence - mtime-based cache invalidation: edits take effect on the next CLI invocation without restart
Shared task observer helpers¶
base_task_observer.py: shared execution-config and execution-log behavior for cron/webhook observerstask_runner.py: shared one-shot task execution helpers used by cron/webhook/background
Update/version flow¶
version.py: current version + PyPI metadata helpersupdater.py:UpdateObserverand upgrade pipeline helpers- upgrade sentinel is consumed on next startup for post-upgrade user message