A lazydocker-style terminal UI for Kamal-deployed apps. Manage deploy, app, server, accessory, and proxy from one interactive screen—no need to remember every kamal command.
Run from a Kamal project directory to manage that specific app:
lazykamal # In a directory with config/deploy.yml
lazykamal /path/to/kamal-app # Or specify the pathConnect to any server and discover ALL Kamal-deployed apps:
lazykamal --server 100.70.90.101 # Via IP (works with Tailscale)
lazykamal --server user@myserver.com # With username
lazykamal -s deploy@production:2222 # Custom portServer mode SSHs to the server, discovers all Kamal apps from Docker container labels, and groups them with their accessories (postgres, redis, sidekiq, etc.).
- Server mode – Connect to any server and manage ALL Kamal apps at once
- Auto-discovery – Automatically finds and groups apps with their accessories
- Live status – App version and containers for the selected destination refresh every few seconds
- Live logs – Stream app or proxy logs in real time; press Esc to stop
- Animated spinner – Visual feedback with spinning animation while commands run
- Command timing – See exactly how long each command takes to complete
- Timestamped logs – Every log entry shows when it happened
- Confirmation dialogs – Safety prompts before destructive operations (rollback, remove, stop)
- Breadcrumb navigation – Always know where you are in the app
- Color-coded output – Green ✓ for success, red ✗ for errors, yellow ● for running
- Help overlay – Press
?anytime to see all keyboard shortcuts - In-TUI editor – Edit deploy.yml and secrets without leaving the app
- Self-upgrade – Run
lazykamal --upgradeto update to the latest version
- Server-centric management: See ALL apps on a server, not just one project
- Single VPS, many apps: Discover
config/deploy*.ymldestinations and run any Kamal command per app - All Kamal commands: Deploy, redeploy, rollback, app, server, accessory, proxy, and more
- Written in Go (like lazydocker), using gocui
Project Mode:
- Kamal installed and on your
PATH
Server Mode:
- SSH access to the target server
- Docker running on the server
- No Kamal installation required on the server
Building from source:
- Go 1.21+
If the formula is in Homebrew core:
brew install lazykamalOr tap this repo (for a frequently updated formula):
brew tap shuvro/lazykamal https://github.com/shuvro/homebrew-lazykamal
brew install lazykamalOr install from the local formula (after cloning):
brew install --build-from-source ./Formula/lazykamal.rbscoop bucket add lazykamal https://github.com/shuvro/scoop-lazykamal
scoop install lazykamalgo install github.com/shuvro/lazykamal@latestEnsure $GOPATH/bin or $HOME/go/bin is in your PATH.
One-liner that detects your OS/architecture and installs the latest release:
curl -sSL https://raw.githubusercontent.com/shuvro/lazykamal/main/scripts/install.sh | bashCustom install directory:
curl -sSL https://raw.githubusercontent.com/shuvro/lazykamal/main/scripts/install.sh | DIR=/usr/local/bin bashInstall specific version:
curl -sSL https://raw.githubusercontent.com/shuvro/lazykamal/main/scripts/install.sh | VERSION=v0.1.3 bashDownload the latest release for your OS and architecture (e.g. lazykamal_0.1.3_linux_amd64.tar.gz), extract, and put lazykamal in your PATH.
git clone https://github.com/shuvro/lazykamal.git
cd lazykamal
go build -o lazykamal .
./lazykamalRun from a directory that contains Kamal config (e.g. config/deploy.yml or config/deploy.staging.yml):
lazykamalOptional: pass a working directory:
lazykamal /path/to/your/kamal-appConnect to a server and discover all Kamal-deployed apps:
lazykamal --server 100.70.90.101 # IP address
lazykamal --server user@myserver.com # With username
lazykamal -s deploy@production:2222 # Custom SSH portServer mode requires:
- SSH access to the server (uses your existing SSH keys)
- Docker running on the server
lazykamal --help # Show help
lazykamal --version # Show version
lazykamal --upgrade # Upgrade to latest version
lazykamal --check-update # Check if update is available
lazykamal --uninstall # Remove lazykamalGeneral:
| Key | Action |
|---|---|
| ↑ / ↓ | Move selection |
| Enter | Open menu / Run command |
| b / Esc | Back (or stop live logs) |
| j / k | Scroll log panel down/up |
| c | Clear output/log panel |
| ? | Show help overlay |
| q | Quit |
Project Mode:
| Key | Action |
|---|---|
| m | Open main command menu |
| r | Refresh destinations & status |
| J / K | Scroll status panel down/up |
Server Mode - Container Select:
| Key | Action |
|---|---|
| l | View logs for selected container |
| r | Restart selected container |
| s | Stop selected container |
| S | Start selected container |
| x | Remove stopped container |
- Apps – List of deploy destinations (
config/deploy*.yml). Select one and press Enter to open the command menu. - Main menu – Deploy, App, Server, Accessory, Proxy, Other, Config.
- Submenus – Deploy, App (includes Live: App logs), Server, Accessory, Proxy (includes Live: Proxy logs), Other, Config (edit deploy config, edit secrets, redeploy, app restart).
- Live status (top right) – Auto-refreshes every few seconds: app version and containers for the selected destination.
- Output / Live logs (bottom right) – Last command output, or streaming app/proxy logs when you run “Live: App logs” or “Live: Proxy logs”. Press Esc to stop streaming.
When using --server, Lazykamal discovers all Kamal-deployed apps by inspecting Docker container labels. Apps are automatically grouped with their accessories.
Kamal names containers with the pattern {service}-{accessory}. Lazykamal parses these names to group related containers:
| Container Service Name | Grouped As |
|---|---|
myapp |
Main app |
myapp-postgres |
Accessory of myapp |
myapp-redis |
Accessory of myapp |
myapp-sidekiq |
Accessory of myapp |
If your server has these containers:
repoengine
repoengine-postgres
repoengine-redis
sparrow_studio
sparrow_studio-postgres
Lazykamal groups them as:
● repoengine (production)
├─ Web: 1/1 containers
├─ postgres: 1 container(s)
└─ redis: 1 container(s)
● sparrow_studio (production)
├─ Web: 1/1 containers
└─ postgres: 1 container(s)
Lazykamal uses smart detection - it doesn't rely on a hardcoded list of suffixes. Instead:
Rule: If service
myappexists and servicemyapp-anythingexists, thenmyapp-anythingis an accessory ofmyapp.
This means any accessory name works:
| Service Names on Server | Grouped As |
|---|---|
myapp, myapp-postgres |
myapp + postgres accessory |
myapp, myapp-meilisearch |
myapp + meilisearch accessory |
myapp, myapp-custom-worker |
myapp + custom-worker accessory |
myapp, myapp-foo-bar-baz |
myapp + foo-bar-baz accessory |
my-cool-app (alone) |
my-cool-app as main app |
The detection also handles nested hyphens correctly:
myapp-foo-barwithmyappexisting → accessoryfoo-barofmyappmy-app-rediswithmy-appexisting → accessoryredisofmy-app
For each discovered app, you have access to a comprehensive menu:
| Category | Commands |
|---|---|
| Containers | Select and manage individual containers (logs, restart, stop, start) |
| App | Logs (live streaming), Details, Images, Version, Health |
| Actions | Boot/Reboot, Start, Stop, Restart, Remove (stopped containers) |
| Commands | Exec (shell) – shows SSH command to connect |
| Proxy | Logs (live streaming), Details, Restart, Reboot, Stop, Start |
All actions mirror Kamal CLI commands but work directly via SSH + Docker, so you don't need Kamal installed on the server.
From Config in the main menu you can:
- Edit deploy config (current dest) – Opens the selected app’s
config/deploy.yml(orconfig/deploy.<dest>.yml) in an in-TUI editor (nano/vi style). No external editor needed—works on servers too. - Edit secrets (current dest) – Opens
.kamal/secrets(or.kamal/secrets.<dest>) in the same in-TUI editor. Creates.kamaland the secrets file if missing. - Redeploy (after edit) – Runs
kamal redeployfor the selected destination. - App restart (after edit) – Runs
kamal app restartfor the selected destination.
In-TUI editor (nano/vi style): A full-screen modal inside the TUI. Arrow keys move, typing inserts, Enter newline, Backspace delete. ^S (Ctrl+S) save, ^Q or Esc quit (prompts if unsaved). No $EDITOR, nano, or vim required—ideal when Lazykamal runs on a server.
Supports both config/deploy*.yml and config/deploy*.yaml.
Lazykamal exposes all Kamal CLI commands via the TUI:
| Category | Commands |
|---|---|
| Deploy | deploy, deploy (skip push), redeploy, rollback, setup, deploy (no cache), redeploy (no cache), setup (no cache) |
| App | boot, start, stop, restart, logs, containers, details, images, version, stale_containers, exec (whoami), maintenance, live, remove, stale_containers (--stop), exec (--detach whoami) |
| Server | bootstrap, exec (date, uptime) |
| Accessory | boot/start/stop/restart/reboot/remove/details/logs all, upgrade |
| Proxy | boot, start, stop, restart, reboot, reboot (rolling), logs, details, remove, boot_config get/set/reset (deprecated) |
| Build | push, pull, deliver, dev, create, remove, details |
| Prune | all, images, containers |
| Secrets | fetch, extract, print |
| Registry | setup, login, logout, remove |
| Other | config, details, audit, lock (status/acquire/release/release --force), env (push/pull/delete), docs, help, init, upgrade, version |
Build, Prune, Registry, and Secrets are accessible as submenus from the Other menu. Options like --primary, --hosts, --roles, --version are passed via the selected destination (config file and destination name); future versions may expose them in the UI.
Lazykamal is inspired by lazydocker and aims for similar ergonomics, but the domain is different (Kamal vs Docker).
| Aspect | Lazydocker | Lazykamal |
|---|---|---|
| Domain | Docker / Compose (containers, images, volumes, networks) | Kamal (deploy, app, server, accessory, proxy) |
| Tech | Go + gocui | Go + gocui |
| Install | Homebrew, Scoop, Chocolatey, go install, script, AUR, Docker | Homebrew, go install, script, binary (same style) |
| Navigation | Panels + keybindings, mouse support | Panels + keybindings (↑/↓, Enter, m, b, q) |
| Actions | Start/stop/restart/remove, view logs, attach, custom commands | Run any Kamal command from menus; output in right panel |
| Live data | Real-time container logs, CPU/memory stats, list of containers/images | Live status (polled app version + containers); streaming logs (app, proxy) |
| Multi-context | Switch Docker context | Select deploy destination (config/deploy*.yml) per app |
On par with lazydocker: Go + gocui, install options, keyboard-driven TUI, one place to run all relevant commands, live status panel, streaming logs (Esc to stop), animated spinners, command timing, and confirmation dialogs for destructive actions.
# Build
make build # Build binary
make run # Build and run
# Test
make test # Run tests with race detection
make test-short # Run tests quickly
make coverage # Run tests and open coverage report
# Lint
make lint # Run golangci-lint
make lint-fix # Run linter with auto-fix
make fmt # Format code
# CI checks (run before pushing!)
make ci # Run same checks as GitHub Actions
make check # Run fmt, vet, lint, test
make setup-hooks # Install pre-push hook for automatic checks
# Release
make release-snapshot # Test release build (no publish)To automatically run CI checks before every push:
make setup-hooksThis installs a pre-push hook that runs formatting, vet, build, and test checks. If any check fails, the push is aborted so you can fix issues before CI fails.
Or without Make:
go build .– build binarygo run .– run from sourcego test -v ./...– run testsgoreleaser release --snapshot --clean– build archives for all platforms
MIT. Contributions welcome — see CONTRIBUTING.md.




