Daemon
The APX daemon (apx-daemon) is the host layer of the system — a long-running local HTTP server
on 127.0.0.1:7430 that owns everything that needs to persist across commands: project state,
plugin lifecycle, the scheduler, conversation files, and the super-agent endpoint.
Every surface — apx CLI, TUI, the web admin panel, the MCP bridge, the Desktop window — talks to
the daemon over HTTP. See Architecture for the full picture.
$ apx daemon status ✓ daemon running pid 48213 port 7430 http://127.0.0.1:7430 version 1.38.0 uptime 2h 14m pid file ~/.apx/daemon.pid plugins ● telegram running 1 channel polling ● desktop running 0 clients • 3 projects loaded
Auto-start
Section titled “Auto-start”You never need to start the daemon manually. The first apx call that needs it spawns it in the
background and waits a moment for it to become healthy. Subsequent calls reuse the running process.
The daemon is a singleton: a PID file at ~/.apx/daemon.pid prevents double starts. If the file
exists but the process is dead, the next start cleans it up automatically.
Managing the daemon
Section titled “Managing the daemon”apx daemon start # boot the daemon explicitlyapx daemon stop # send SIGTERM and waitapx daemon reload # re-read ~/.apx/config.json only — does NOT restart the processapx daemon status # print health: port, pid, uptime, plugins, projectsapx daemon logs # legacy stdout log tailapx daemon logs --tail 200apx daemon reload is the lightweight option: it picks up config changes (Telegram channels,
model keys, permission mode) without dropping in-flight requests. Use apx daemon restart (a
stop + start) when you change source code or prompts.
APX writes to two places:
| Path | What | Command |
|---|---|---|
~/.apx/daemon.log | Legacy stdout redirect (daemon process output) | apx daemon logs --tail N |
~/.apx/logs/apx.log | Unified structured log — every module writes here | apx log |
apx log is the recommended way to follow the system:
apx log # print the last 200 linesapx log -f # follow (tail -f style)apx log --tail 500apx log --errors # only ERROR-level lines$ apx log -f [2026-06-14 09:31:58.004] [INFO ] [daemon ] apx-daemon 1.38.0 listening on http://127.0.0.1:7430 [2026-06-14 09:31:58.061] [INFO ] [telegram] plugin telegram initialized [2026-06-14 09:31:58.088] [INFO ] [telegram] polling channel "default" (chat 123456789) [2026-06-14 09:32:14.220] [INFO ] [scheduler] routine "morning-standup" due → exec_agent [2026-06-14 09:32:16.733] [INFO ] [super-agent] roby routed 1 task to sofia [2026-06-14 09:32:19.510] [WARN ] [engine ] anthropic 429 — backing off 2s, retry 1/3 [2026-06-14 09:32:21.998] [INFO ] [engine ] anthropic ok — 612 tok in / 248 out
The unified log format is:
[2026-05-30 14:22:01.123] [INFO ] [telegram] plugin telegram initialized[2026-05-30 14:22:01.456] [INFO ] [daemon ] apx-daemon 1.22.2 listening on http://127.0.0.1:7430Secret masking
Section titled “Secret masking”Secrets are scrubbed from every log line before it hits disk, in two layers:
- By key — structured metadata fields whose name looks secret (
token,api_key,authorization,bot_token, …) are replaced with[redacted]. - By value — at boot (and again whenever the config changes) the daemon registers every
known secret value: engine API keys, TTS/transcription/embeddings keys, Telegram bot
tokens, and MCP env/header tokens. Any of those values appearing anywhere in a log
line — a provider error that echoes your key, tool output, a stack trace — is replaced
with a
***…XXXXmarker (last 4 characters kept so you can tell which secret it was).
Both layers apply to ~/.apx/logs/apx.log and to the error traces in
~/.apx/logs/errors.jsonl. Masking is always on — there is no config key to disable it —
and it never fails a log write: if masking itself errors, the line is written as-is rather
than dropped.
Plugin lifecycle
Section titled “Plugin lifecycle”On boot the daemon discovers two built-in plugins:
| Plugin | What it does |
|---|---|
telegram | Long-poll Telegram bot gateway, inbound routing, contact roster |
desktop | WebSocket bridge for the Electron floating window |
The PluginManager calls each plugin’s init() once, then start() after the HTTP server is
listening. On SIGTERM / SIGINT it calls stop() on each plugin before closing the server.
Plugins can also install their own Express routes (routes(app) hook). The daemon registers these
immediately after the core API routes, so plugin paths are available at the same base URL.
You can inspect plugin state at any time:
apx plugins list # all loaded plugins + running/stoppedapx plugins status telegram # detailed status for one pluginScheduler ticks
Section titled “Scheduler ticks”The daemon runs a RoutineScheduler that ticks every 5 seconds and checks which routines are due.
When a routine fires, the scheduler:
- Reads the routine definition from
.apc/routines.json. - Resolves the kind handler (
heartbeat,exec_agent,super_agent,telegram,shell). - Runs any configured
pre_commands, evaluates theskip_prompt_oncondition, runs the main action, then runspost_commands. - Writes the updated
last_run/next_runtimestamps back to the routine store.
See Routines for the full spec and apx routine add flags.
Conversation files
Section titled “Conversation files”Every agent conversation thread is stored as a Markdown file on disk — no database required for the core data, only for the regenerable index. The layout:
Directory~/.apx/
- config.json
- identity.json
- daemon.pid
- daemon.token
- daemon.log
Directorylogs/
- apx.log
- errors.jsonl
Directorymessages/
Directorytelegram/
- YYYY-MM-DD.jsonl
Directoryprojects/
Directory<project-id>/
Directorymessages/
- …
Directoryagents/
Directory<slug>/
Directorysessions/ ← one .md per runtime invocation
- …
Directoryconversations/ ← LLM conversation threads
- …
Directorydefault/
Directorysessions/
- …
Configuration
Section titled “Configuration”The daemon reads ~/.apx/config.json on start. Key fields:
{ "port": 7430, "host": "127.0.0.1", "log_level": "info", "super_agent": { "enabled": true, "model": "claude-3-5-sonnet", "permission_mode": "automatico" }, "telegram": { "enabled": true, "channels": [] }, "engines": { "anthropic": { "api_key": "sk-ant-..." } }}After editing config, run apx daemon reload (for config-only changes) or apx daemon restart
(for code/prompt changes). The apx config set and apx model key commands write this file and
call the reload endpoint automatically.