Skip to content

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.

Manual daemon

Best for debugging, non-Linux systems, and targeted start/stop of one runtime target.

User service

Best for long-running local installs that should come back after login or restart.

Runtime targets

Telegram, Zalo, cron, and the local UI can run through platform startup integration.

Safety check

Run only one background mode for the same target to avoid duplicate polling or duplicate cron runs.

Bestie can manage three runtime targets:

  • telegram runs bestie channels telegram.
  • zalo runs bestie channels zalo.
  • cron runs bestie cron run.

Daemon commands use --channel telegram|zalo|cron|all. If you do not pass --channel, daemon commands target Telegram.

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:

Terminal window
bestie doctor
bestie channels doctor

If 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 one channel:

Terminal window
bestie daemon start --channel telegram
bestie daemon start --channel zalo
bestie daemon start --channel cron

Start all supported daemon channels:

Terminal window
bestie daemon start --channel all

On 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 the default Telegram daemon:

Terminal window
bestie daemon status

Check all daemon channels:

Terminal window
bestie daemon status --channel all

Status can report:

  • running when the recorded process id is still active.
  • stale when Bestie has a daemon state file but the process is no longer running.
  • stopped when 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 a channel after changing config, tokens, voice settings, or cron schedules:

Terminal window
bestie daemon restart --channel telegram
bestie daemon restart --channel zalo
bestie daemon restart --channel cron

Restart every daemon channel:

Terminal window
bestie daemon restart --channel all

Restart 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 one channel:

Terminal window
bestie daemon stop --channel telegram

Stop every daemon channel:

Terminal window
bestie daemon stop --channel all

Bestie 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.

Bestie can create user-level startup integration. This belongs to the bestie service command, not the installer and not bestie daemon:

Terminal window
bestie service install

On Linux, this writes bestie.service under the user systemd config directory, removes older per-channel service files when they exist, and runs:

Terminal window
systemctl --user daemon-reload
systemctl --user enable --now bestie.service

The 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:

  • cron is included by default.
  • telegram is included only when the Telegram channel is enabled and the configured bot token env value is available.
  • zalo is included only when the Zalo channel is enabled and the configured bot token env value is available.

Check the service command’s status hint:

Terminal window
bestie service status

On 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:

Terminal window
bestie service restart

To remove the service:

Terminal window
bestie service uninstall

On 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.

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:

Terminal window
bestie tools logs --lines 20

Do 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.

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:

Terminal window
bestie channels telegram --once
bestie channels zalo --once

Then check channel diagnostics:

Terminal window
bestie channels doctor --channel telegram --connect
bestie channels doctor --channel zalo --connect

Restart the affected channel:

Terminal window
bestie daemon restart --channel telegram

Bestie removes stale state during restart and writes a new state file for the replacement process.

Startup integration moved to the service command. Use:

Terminal window
bestie service install
bestie service status

Manual daemon lifecycle commands are limited to:

Terminal window
bestie daemon start --channel all
bestie daemon stop --channel all
bestie daemon restart --channel all
bestie daemon status --channel all

The 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:

Terminal window
bestie channels doctor --channel telegram --connect
bestie channels doctor --channel zalo --connect
bestie service restart

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.

Terminal window
bestie daemon status --channel telegram