Run Bestie in the background
Use Bestie background runtimes when you want Telegram, Zalo, or cron schedules to keep running after the current terminal command exits. Bestie supports two local options:
bestie daemon ...starts and tracks independent detached processes from the CLI.bestie service ...installs the user-level startup integration for your platform.
Use bestie daemon ... for manual control, local debugging, and targeted start/stop of one runtime target. Use bestie service ... when you want Bestie to start at login or be managed by the host OS.
Best for debugging, non-Linux systems, and targeted start/stop of one runtime target.
Best for long-running local installs that should come back after login or restart.
Telegram, Zalo, cron, and the local UI can run through platform startup integration.
Run only one background mode for the same target to avoid duplicate polling or duplicate cron runs.
Bestie can manage three runtime targets:
telegramrunsbestie channels telegram.zalorunsbestie channels zalo.cronrunsbestie cron run.
Daemon commands use --channel telegram|zalo|cron|all. If you do not pass --channel, daemon commands target Telegram.
Before you start
Section titled “Before you start”Complete the setup for each channel you want to run:
- Telegram needs
channels.telegram.enabled, an owner id or username, and the Telegram bot token env value. - Zalo needs
channels.zalo.enabled, an owner id, and the Zalo bot token env value. - Cron needs at least one configured schedule if you expect work to run.
Run Doctor before starting long-lived processes:
bestie doctorbestie channels doctorIf a channel is not configured correctly, the daemon can still start, but the channel process will write the failure to its daemon log.
Choose one background mode for normal operation. Running both a manual daemon and a user service for the same target can start duplicate polling or duplicate cron execution.
Start daemons
Section titled “Start daemons”Start one channel:
bestie daemon start --channel telegrambestie daemon start --channel zalobestie daemon start --channel cronStart all supported daemon channels:
bestie daemon start --channel allOn start, Bestie records daemon state under the runtime app directory and prints the process id and log path. Each target writes to its own state file and log file, such as daemon-telegram.json and daemon-telegram.log, daemon-zalo.json and daemon-zalo.log, or daemon-cron.json and daemon-cron.log.
Starting a daemon that is already running does not create a second copy. Bestie reports the existing process id instead.
Check status
Section titled “Check status”Check the default Telegram daemon:
bestie daemon statusCheck all daemon channels:
bestie daemon status --channel allStatus can report:
runningwhen the recorded process id is still active.stalewhen Bestie has a daemon state file but the process is no longer running.stoppedwhen no daemon state is recorded for that channel.
If status is stale, restart the daemon to remove the old state and create a fresh background process.
For older Telegram daemon state, Bestie still recognizes the legacy daemon.json file so status, stop, and restart can clean it up through the current command.
Restart after config changes
Section titled “Restart after config changes”Restart a channel after changing config, tokens, voice settings, or cron schedules:
bestie daemon restart --channel telegrambestie daemon restart --channel zalobestie daemon restart --channel cronRestart every daemon channel:
bestie daemon restart --channel allRestart sends SIGTERM to the recorded process, waits for it to exit, removes the old state file, then starts a new process. If the recorded process id has been reused by another command, Bestie removes the stale state instead of killing the unrelated process.
Stop daemons
Section titled “Stop daemons”Stop one channel:
bestie daemon stop --channel telegramStop every daemon channel:
bestie daemon stop --channel allBestie waits up to 30 seconds for the process to stop. Before stopping a recorded process, Bestie checks the process command line when the platform exposes it. If the recorded pid now belongs to something else, Bestie removes stale daemon state instead of killing that process. If the Bestie process does not exit in time, the command reports a timeout and leaves the state visible for follow-up troubleshooting.
Install the user service
Section titled “Install the user service”Bestie can create user-level startup integration. This belongs to the bestie service command, not the installer and not bestie daemon:
bestie service installOn Linux, this writes bestie.service under the user systemd config directory, removes older per-channel service files when they exist, and runs:
systemctl --user daemon-reloadsystemctl --user enable --now bestie.serviceThe Linux service unit runs bestie service run in the foreground with Restart=on-failure, RestartSec=5, and TimeoutStopSec=45. At startup, Bestie chooses installable targets from local config:
cronis included by default.telegramis included only when the Telegram channel is enabled and the configured bot token env value is available.zalois included only when the Zalo channel is enabled and the configured bot token env value is available.
Check the service command’s status hint:
bestie service statusOn macOS, bestie service install writes launchd LaunchAgents for the service runtime and local UI. On Windows, it writes Bestie.lnk and Bestie.ico into the user’s Startup folder; the shortcut starts bestie daemon start --channel all, which also starts the Web UI companion daemon.
Restart the user service after changing channel, token, voice, cron, or UI configuration:
bestie service restartTo remove the service:
bestie service uninstallOn Linux, uninstall disables and stops bestie.service, removes the service file, then reloads the user systemd daemon. It also removes older per-channel service files named bestie-telegram.service, bestie-zalo.service, and bestie-cron.service when they exist. Missing service units are ignored during uninstall. On macOS, uninstall unloads and removes the Bestie LaunchAgents. On Windows, it removes the Startup shortcut and icon.
Do not run bestie service run yourself for normal use. It is the hidden foreground command used by platform service integration.
Read logs
Section titled “Read logs”The daemon command prints the log path when a process starts or when status finds a running or stale state. Use that path when debugging channel startup failures.
For user services, use the status hint printed by Bestie. On Linux, inspect the systemd journal for bestie.service; on macOS, inspect launchd logs; on Windows, inspect the Startup shortcut and Bestie daemon logs.
You can also inspect recent redacted Bestie logs through the tools command:
bestie tools logs --lines 20Do not paste bot tokens, provider keys, .bestie/.env, or raw daemon logs into public issue trackers. Logs may include operational context even when secrets are intended to stay in env files.
Common fixes
Section titled “Common fixes”The daemon starts but the channel does not respond
Section titled “The daemon starts but the channel does not respond”Run the channel directly once so the error is visible in the terminal:
bestie channels telegram --oncebestie channels zalo --onceThen check channel diagnostics:
bestie channels doctor --channel telegram --connectbestie channels doctor --channel zalo --connectStatus says stale
Section titled “Status says stale”Restart the affected channel:
bestie daemon restart --channel telegramBestie removes stale state during restart and writes a new state file for the replacement process.
bestie daemon install is rejected
Section titled “bestie daemon install is rejected”Startup integration moved to the service command. Use:
bestie service installbestie service statusManual daemon lifecycle commands are limited to:
bestie daemon start --channel allbestie daemon stop --channel allbestie daemon restart --channel allbestie daemon status --channel allThe service starts but only cron or UI runs
Section titled “The service starts but only cron or UI runs”Bestie always includes the cron service target in the service runtime. Telegram and Zalo service targets are skipped unless the channel is enabled and the configured bot token env value is available. On macOS and Windows, the local UI can also be started by the platform integration.
Check channel setup and env values, then restart the service:
bestie channels doctor --channel telegram --connectbestie channels doctor --channel zalo --connectbestie service restartStop times out
Section titled “Stop times out”If stop reports that a daemon pid did not stop within the timeout, inspect the log path from status, then stop the process manually only after confirming the pid still belongs to Bestie.
bestie daemon status --channel telegram