CLI reference
deeplo commands, grouped by function.
deeplo is a single binary with two roles:
deeplo daemon— the long-running daemon: webhook listener, poller, deploy runner. In a native install this is run by systemd; in Docker it is the container's default command.deeplo <cmd>— operator CLI for inspecting state, managing the install, and triggering runtime actions.
Commands are grouped by function:
| Group | Commands | Daemon required? |
|---|---|---|
| State | status, runs, logs, health, version | No (reads local files on native installs) |
| Control | daemon, reload, refresh | Yes |
| Local | check, doctor, config | No |
| System | service, env, update, remove | No (native only) |
For daemon environment variables, see Bootstrap config.
deeplo daemon
Starts the deployment daemon. Configured exclusively via DEEPLO_* environment variables.
deeplo daemonIn a native install, systemd manages this. In Docker, it is the container's default command. You do not normally need to run it directly.
deeplo status
Shows the latest recorded deployment state for each (project, host) pair.
On native installs, reads local state files directly — no daemon required. On Docker installs, queries the running daemon.
deeplo statusIf no deployments have been recorded yet:
No deployments recorded yet.
Trigger one by pushing to a tracked branch, or wait for the poller.Example:
$ deeplo status
PROJECT HOST STATUS COMMIT TRIGGER STARTED
------- ---- ------ ------ ------- -------
api web-1 success a3f2bc9 webhook 2026-04-14T15:30:00Z
api web-2 success a3f2bc9 poll 2026-04-14T15:30:01Z
worker web-1 failed 8892eb0 webhook 2026-04-14T14:00:00Zdeeplo runs
Lists recent deploy runs, most recent first.
On native installs, reads local state files directly — no daemon required. On Docker installs, queries the running daemon.
deeplo runs [--limit N] [--project NAME]Flags:
| Flag | Default | Description |
|---|---|---|
--limit | 20 | Maximum number of runs to show |
--project | — | Filter by project name |
If no runs have been recorded yet:
No runs recorded yet.Example:
$ deeplo runs --limit 5
ID PROJECT HOST STATUS COMMIT TRIGGER STARTED
-- ------- ---- ------ ------ ------- -------
1744660003-a3f2bc91 api web-1 success a3f2bc9 webhook 2026-04-14T15:30:00Z
1744659801-9d3e4f22 worker web-1 failed 8892eb0 webhook 2026-04-14T14:00:00ZUse the run ID with deeplo logs to see the full deploy log.
deeplo logs
Prints the full log for a specific deploy run.
On native installs, reads the log file directly — no daemon required. On Docker installs, fetches the log from the running daemon.
deeplo logs <run-id>Example:
$ deeplo logs 1744660003-a3f2bc91
=== Deploy Run 1744660003-a3f2bc91 ===
Project: api
Host: web-1 (10.0.0.10)
Commit: a3f2bc9...
...
[15:30:00Z] Fetching repository git@github.com:org/api.git
[15:30:02Z] Commit a3f2bc9 is available
[15:30:02Z] Connecting to web-1 (deploy@10.0.0.10:22)
[15:30:03Z] Running docker compose up in /srv/apps/api
[15:30:07Z] Deploy succeeded in 7.2sdeeplo health
Shows service health. On native installs, checks the systemd service state — never fails with a raw socket error. On Docker installs, pings the admin socket directly.
deeplo healthExit code: 0 = service running (native) or daemon reachable (Docker); non-zero otherwise.
Example — native install, service running:
$ deeplo health
Service: running
Enabled: yes
Socket: present
Daemon: reachable
Version: v0.2.0
Uptime: 4h32m15sExample — native install, service stopped:
$ deeplo health
Service: stopped
Enabled: yes
Socket: missing
Daemon: not checked (socket missing)
Service is not running. To start:
sudo systemctl start deeploExample — Docker, daemon reachable:
$ docker exec deeplo deeplo health
Daemon: reachable
Version: v0.2.0
Uptime: 4h32m15sdeeplo version
Prints the CLI version and, if the daemon is reachable, its version too.
deeplo versionExample — daemon running:
$ deeplo version
deeplo: v0.2.0
daemon: v0.2.0Example — daemon not running:
$ deeplo version
deeplo: v0.2.0
daemon: not reachabledeeplo reload
Asks the daemon to re-read its managed config immediately. Requires the daemon to be running.
deeplo reload- In local mode: re-reads the config file from disk.
- In git mode: fetches the latest commit from the config repo.
If the config is unchanged, the daemon does nothing (not an error). If the config is invalid, the daemon rejects it and keeps the current config; the error is returned to the CLI.
deeplo refresh
Asks the daemon to SSH into all configured hosts and run docker compose ps for each project, returning the live container state. Requires the daemon to be running.
deeplo refreshIf no hosts are configured:
No hosts configured.Example:
$ deeplo refresh
PROJECT HOST SERVICE STATE STATUS
------- ---- ------- ----- ------
api web-1 api running Up 3 hours
api web-1 redis running Up 3 hours
worker web-1 worker exited Exited (1) 2 hours agodeeplo check
Validates the config file offline. Does not require the daemon to be running.
deeplo check [--config FILE] [--probe-hosts]Flags:
| Flag | Default | Description |
|---|---|---|
--config | /etc/deeplo/config.yml | Path to the config file |
--probe-hosts | false | Dial each host over SSH and verify connectivity |
SSH settings for --probe-hosts are read from bootstrap environment variables (DEEPLO_SSH_KEY_FILE, DEEPLO_SSH_PORT, etc.).
Exit codes: 0 = success, non-zero = load, validation, or probe failure
Example — valid config:
$ deeplo check --config /etc/deeplo/config.yml
Config OK: /etc/deeplo/config.yml (version 1, 2 host(s), 1 repo(s), 3 project(s))Example — errors:
$ deeplo check --config config.yml
ERROR repos[0].url url is required
ERROR projects[0].targets[0] target "missing-host" does not reference a known host
Config INVALID: 2 error(s), 0 warning(s) in config.ymlExample — probe hosts:
$ deeplo check --config config.yml --probe-hosts
Config OK: config.yml (version 1, 2 host(s), 1 repo(s), 2 project(s))
PROBE OK web-1 10.0.0.10
PROBE FAIL web-2 dial tcp 10.0.0.11:22: connection refused
1 host(s) unreachabledeeplo doctor
Runs a local diagnostic and reports pass/fail for key conditions. Does not modify files or restart services. Works in both native and Docker environments.
deeplo doctorChecks performed:
| Check | Notes |
|---|---|
| config file | exists and is readable |
| daemon | admin socket reachable |
| env file | native installs only |
| unit file | native installs only |
| service enabled | native installs only |
| service running | native installs only |
| SSH key configured | DEEPLO_SSH_KEY_FILE is set |
| SSH key file exists | the referenced file is present |
Systemd-specific checks are skipped automatically when running in Docker or any non-systemd environment.
Exit code is non-zero if any check fails.
deeplo config
Commands for working with the managed config file. The config file path is read from DEEPLO_CONFIG_FILE (default: /etc/deeplo/config.yml). Available on all install types.
deeplo config path Print the path to the config file
deeplo config edit Open the config file in an editordeeplo config edit selects the editor automatically:
- If the file is writable by the current user, opens it with
$VISUAL>$EDITOR>vi. - If the file is not writable (e.g. root-owned on a native install), uses
sudoedit— you are never left with a read-only buffer.
After the editor exits successfully, the command prints the file path and next steps. The daemon is not automatically reloaded.
Example output (root-owned file):
Opening /etc/deeplo/config.yml with sudoedit...
[editor opens]
Edited /etc/deeplo/config.yml
Next steps:
deeplo check validate your changes
deeplo reload apply changes without restarting the daemon
deeplo service restart or restart the service if neededdeeplo service (native installs only)
Convenience wrappers around systemctl for the deeplo systemd unit. Only available on native systemd installs.
deeplo service status Show the deeplo service status
deeplo service start Start the service
deeplo service stop Stop the service
deeplo service restart Restart the service
deeplo service enable Enable the service to start on boot
deeplo service disable Disable the service from starting on boot
deeplo service logs Show service logs (via journalctl)Privilege model: status and logs run as the current user. Mutating commands (start, stop, restart, enable, disable) require root; when not running as root they prepend sudo automatically.
deeplo service logs flags:
| Flag | Default | Description |
|---|---|---|
--follow / -f | false | Stream live log output |
--lines / -n | 50 | Number of recent lines to show (0 = all) |
deeplo env (native installs only)
Commands for working with the deeplo env file (/etc/deeplo/deeplo.env). Not available in Docker deployments.
deeplo env path Print the path to the env file
deeplo env edit Open the env file via sudoeditdeeplo env edit always uses sudoedit (the env file is root-owned). After a successful edit it prints the file path and a reminder to restart the service for env changes to take effect.
deeplo update (native installs only)
Downloads and installs the latest deeplo release. Restarts the daemon if it was running before the update.
deeplo update [--version TAG]Flags:
| Flag | Default | Description |
|---|---|---|
--version | — | Version to install (default: latest release) |
Example — update to latest:
$ deeplo update
Fetching latest version...
Updating deeplo to v0.3.0...
Downloading deeplo v0.3.0 (linux/amd64)...
✓ Installed binary to /usr/local/bin/deeplo
Restarting deeplo service...
✓ Restarted deeplo
deeplo updated to v0.3.0Example — install a specific version:
deeplo update --version v0.2.1Fails clearly with an error on Docker or non-systemd hosts.
deeplo remove (native installs only)
Removes the deeplo binary and systemd service from this host. Config and data are preserved by default.
deeplo remove [--purge] [--yes]Flags:
| Flag | Default | Description |
|---|---|---|
--purge | false | Also remove /etc/deeplo, /var/lib/deeplo, and the deeplo system user |
--yes | false | Skip the confirmation prompt |
Example — standard remove:
$ deeplo remove
This will stop and remove the deeplo service and binary.
Continue? [y/N] y
Removing deeplo...
✓ Stopped deeplo
✓ Removed /etc/systemd/system/deeplo.service
✓ Removed /usr/local/bin/deeplo
deeplo removeed. Config and data preserved.
Config: /etc/deeplo
Data: /var/lib/deeplo
To also remove config and data: deeplo remove --purgeExample — full purge:
deeplo remove --purge --yesFails clearly with an error on Docker or non-systemd hosts.
Shell completion
deeplo completion bash
deeplo completion zsh
deeplo completion fish
deeplo completion powershellInstall bash completion (system-wide):
deeplo completion bash | sudo tee /etc/bash_completion.d/deeplo > /dev/nullInstall zsh completion:
deeplo completion zsh > "${fpath[1]}/_deeplo"Install fish completion:
deeplo completion fish > ~/.config/fish/completions/deeplo.fishCommon workflows
Validate config before restarting:
deeplo checkCheck SSH connectivity:
deeplo check --probe-hostsShow service health:
deeplo healthRun full local diagnostic:
deeplo doctorView what's deployed:
deeplo statusInspect live runtime state:
deeplo refreshApply a config change without restarting:
deeplo config edit
deeplo check
deeplo reloadDebug a failed deploy:
deeplo runs --limit 10
deeplo logs <run-id>Tail daemon logs (systemd):
deeplo service logs --followTail daemon logs (Docker):
docker compose logs -fAdvanced: admin socket
Some commands communicate with the running daemon over a Unix socket at /run/deeplo/deeplo.sock. This is an internal transport detail. State inspection commands (status, runs, logs) read local files directly on native installs and only use the socket as a fallback.
If you need to override the socket path (e.g. for testing or non-standard installs), pass --socket <path> to any command that contacts the daemon. This flag is intentionally omitted from normal help output.