Aleph
Concepts

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 start directly and the OS watchdog handles restart on crash.
  • Single-source subcommandaleph-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 state

There is no start subaction: install already 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 with launchctl load -w to arm RunAtLoad and start now
  • Linux: ~/.config/systemd/user/aleph-server.service, systemctl --user enable --now; best-effort loginctl enable-linger $USER so 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 an aleph-server-hidden.vbs shim

Daemon RPC (inside the gateway)

These methods are registered on the gateway WebSocket and callable from clients or aleph-server gateway call …:

MethodDescription
daemon.statusReports uptime, version, platform (running / uptime_secs / version / platform)
daemon.shutdownGraceful shutdown: sends the response, then std::process::exit(0) after a short delay
daemon.logsReads 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 query

Selected flags:

FlagDefaultDescription
-c, --config <path>~/.aleph/config.tomlConfig file
--daemonfalseRun via daemonize()
--pid-file <path>~/.aleph/gateway.pidPID file for daemon mode
--log-file <path>stdout/stderr redirect target
--bind <addr> / --port <n>127.0.0.1 / 18790Listen address and port
--forcefalseTry to start even if the port is busy
--log-levelinfotracing log level
--max-connectionsMax concurrent connections

Logs and Rotation

Aleph has two independent log streams:

  • Structured logs at ~/.aleph/logs/aleph-server.log.YYYY-MM-DD: written by tracing, 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 run

Rotation 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-boot ALEPH-BOOT marker 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.rs calls is_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 path
  • src/bin/aleph-server/daemon.rs — PID file / lock / log rotation / daemonize()
  • src/bin/aleph-server/commands/service/mod.rs — Cross-platform service implementation
  • src/bin/aleph-server/commands/service/descriptors.rs — launchd plist / systemd unit / scheduled-task XML / vbs shim
  • src/bin/aleph-server/commands/start/helpers.rsALEPH-BOOT startup marker
  • src/gateway/handlers/daemon_control.rsdaemon.status / daemon.shutdown / daemon.logs RPC
  • src/tasks/heartbeat/probe.rs — Heartbeat probe and dangerous-tool gate
  • src/approval/guardian_requester.rs — Guardian Judge approval reviewer

On this page