Daemon
System service management, lifecycle, and log rotation for `aleph-server`.
The aleph-server binary is itself both the foreground gateway and the daemon. It registers itself into the platform's native boot supervisor — macOS launchd LaunchAgent, Linux systemd --user, Windows Task Scheduler — through the aleph-server service … subcommand, instead of forking a second process.
Design Philosophy
- Native supervisor — no second fork; the service descriptor invokes
aleph-server startdirectly and the OS watchdog handles restart on crash. - Single-source subcommand —
aleph-server service {install|uninstall|enable|disable|status}is the only entry point for all start-on-boot / undo logic. - Per-user registration — no root-level units; each user installs into their own LaunchAgent / systemd-user unit / Scheduled Task.
Architecture
┌──────────────────────────────────────────┐
│ aleph-server │
├──────────────────────────────────────────┤
│ │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ start cmd │ │ service subcmd │ │
│ │ (foreground / │ │ install / │ │
│ │ --daemon) │ │ uninstall / │ │
│ └────────────────┘ │ enable / │ │
│ │ disable / │ │
│ │ status │ │
│ └────────────────┘ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Gateway WebSocket (JSON-RPC 2.0)│ │
│ │ daemon.status / daemon.shutdown │ │
│ │ daemon.logs │ │
│ └────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Logs: │ │
│ │ ~/.aleph/logs/aleph-server.log │ │
│ │ .YYYY-MM-DD (daily + 7d retain) │ │
│ │ + raw stdout/stderr redirect │ │
│ └────────────────────────────────────┘ │
└──────────────────────────────────────────┘service Subcommand
aleph-server exposes a service subcommand that wraps every "start on boot" install/uninstall/toggle action. The installer calls service install once after placing the binary (ALEPH_AUTOSTART=0 opts out).
aleph-server service install # write descriptor + enable + start now (launchd LaunchAgent / systemd --user unit / Scheduled Task)
aleph-server service uninstall # stop + remove descriptor
aleph-server service enable # arm boot/login autostart (does not touch the running process)
aleph-server service disable # disarm boot/login autostart (does not touch the running process)
aleph-server service status # report whether the descriptor is installed and the current run stateThere is no
startsubaction:installalready starts the service immediately. Day-to-day start/stop is delegated to the native supervisor (launchctl load/unload,systemctl --user start/stop,schtasks /Run).
The implementation lives in src/bin/aleph-server/commands/service/mod.rs and branches per platform:
- macOS:
~/Library/LaunchAgents/ai.aleph.server.plist, loaded withlaunchctl load -wto arm RunAtLoad and start now - Linux:
~/.config/systemd/user/aleph-server.service,systemctl --user enable --now; best-effortloginctl enable-linger $USERso the service starts at boot without a login session (warns but does not fail if it requires polkit/root) - Windows: scheduled task
Aleph\aleph-server, logon trigger, hidden-window launch via analeph-server-hidden.vbsshim
Daemon RPC (inside the gateway)
These methods are registered on the gateway WebSocket and callable from clients or aleph-server gateway call …:
| Method | Description |
|---|---|
daemon.status | Reports uptime, version, platform (running / uptime_secs / version / platform) |
daemon.shutdown | Graceful shutdown: sends the response, then std::process::exit(0) after a short delay |
daemon.logs | Reads the most recent aleph-*.log under ~/.aleph/logs/, optionally filtered by level, returns the last lines entries |
There is no separate Unix-socket IPC — every call goes through the gateway WebSocket + JSON-RPC 2.0.
Start and Foreground Run
aleph-server start # foreground (default subcommand)
aleph-server start --daemon # fork into daemon mode
aleph-server start --log-file ~/.aleph/server.log
aleph-server stop # stop a running daemon
aleph-server status [--json] # status querySelected flags:
| Flag | Default | Description |
|---|---|---|
-c, --config <path> | ~/.aleph/config.toml | Config file |
--daemon | false | Run via daemonize() |
--pid-file <path> | ~/.aleph/gateway.pid | PID file for daemon mode |
--log-file <path> | — | stdout/stderr redirect target |
--bind <addr> / --port <n> | 127.0.0.1 / 18790 | Listen address and port |
--force | false | Try to start even if the port is busy |
--log-level | info | tracing log level |
--max-connections | — | Max concurrent connections |
Logs and Rotation
Aleph has two independent log streams:
- Structured logs at
~/.aleph/logs/aleph-server.log.YYYY-MM-DD: written bytracing, rotated daily with 7-day retention, every line timestamped. Grep here first. - Raw stdout/stderr stream (
--log-file, or a shell redirect of the foreground process): only banner / warnings / panics / child-process output; the tracing console layer is dropped when stdout is not a TTY.
Every startup prints one grep-friendly boot marker to stdout, so operators can locate the current boot inside the raw stream (which appends across restarts):
ALEPH-BOOT ts=<RFC3339> pid=<pid> version=<ver>
grep ALEPH-BOOT ~/.aleph/server.log | tail -1 # the lines after this = this runRotation of the raw stream depends on how it was opened:
- Daemon mode (
--daemon --log-file <path>): rotates on startup — if the file was last written on an earlier calendar day, or exceeds ~5 MB, it is archived as<name>.YYYY-MM-DD(the file's own last-write day) and aged out after 7 days. Same-day restarts keep appending; the per-bootALEPH-BOOTmarker separates runs. No in-flight rotation: while the daemon holds the fd open it is never rotated mid-run. - Foreground / shell redirect: the fd belongs to the shell, so Aleph cannot rotate it. Use system logrotate. The repo ships
scripts/aleph-server.logrotate(copytruncate+ daily + 7-day retention); copy it to/etc/logrotate.d/after editing the absolute paths.
Sleep inhibitor:
inhibit_sleep("Aleph agent loop")is held by the harness for the duration of each Think→Act turn and is silent on stderr; it is not part of the daemon log stream.
Heartbeat Probe
aleph-server start initializes HeartbeatService from [heartbeat] config:
- Refuses dangerous / confirmation-gated tools:
tasks/heartbeat/probe.rscallsis_denied_on_gateway_surface(tool_name)before invoking any probe tool and rejects on a hit; there is no LLM in the loop and no approval transport. - Guardian Judge scope: Guardian Judge is the LLM risk assessor in the approval flow (
src/approval/guardian_requester.rs); it is not part of the heartbeat probe — probes are pure L1 trigger evaluation. - Payload masking: the Guardian Judge prompt payload masks secrets — they are no longer serialized into logs or read by the auditor.
Code Locations
src/bin/aleph-server/cli.rs— CLI definitions (Start/Stop/Status/Doctor/PromptSize/Service/Hooks/Secret/Identity/Plugin(s)/Gateway/BootstrapRuntime/Pair/BootstrapToken/Update)src/bin/aleph-server/main.rs— Command dispatch and boot pathsrc/bin/aleph-server/daemon.rs— PID file / lock / log rotation /daemonize()src/bin/aleph-server/commands/service/mod.rs— Cross-platformserviceimplementationsrc/bin/aleph-server/commands/service/descriptors.rs— launchd plist / systemd unit / scheduled-task XML / vbs shimsrc/bin/aleph-server/commands/start/helpers.rs—ALEPH-BOOTstartup markersrc/gateway/handlers/daemon_control.rs—daemon.status/daemon.shutdown/daemon.logsRPCsrc/tasks/heartbeat/probe.rs— Heartbeat probe and dangerous-tool gatesrc/approval/guardian_requester.rs— Guardian Judge approval reviewer
Related Pages
- Deployment — Actual install flow (autostart enabled by default)
- Workspaces —
~/.aleph/directory layout and log paths - Process Management — Process-level details (locks, logs, rotation)
- Heartbeat Automation —
heartbeat.*RPC and probe configuration