All your ops tools. One terminal.
Open-source · Self-hosted · Runs locally
Docker, Kubernetes, Git, SSH, Redis, Postgres, Argo CD, and more — one keyboard-driven TUI, backed by a local KeePass vault and out-of-process plugins.
Website · Why omo · Install · Quick start · Screenshots · Plugins · Architecture · Development · Contributing
Plugin rail on the left. Active tool on the right. Keyboard shortcuts always visible.
Ops work is fragmented. You bounce between the AWS console, kubectl, Redis Insight, Docker Desktop, Argo CD, GitHub, SSH sessions, and a password manager — each with its own UI, auth, and muscle memory.
omo is a local TUI host. No SaaS. No telemetry. Secrets stay in KeePass under ~/.omo/. Plugins talk over RPC so a crash in one tool never takes down the cockpit.
| Pain today | With omo |
|---|---|
| Ten browser tabs + CLIs | One binary, one keyboard model |
Credentials scattered in .env, shells, and vaults |
One KeePass DB under ~/.omo/secrets/ |
| Plugins break when the host Go version changes | Out-of-process RPC plugins (hashicorp/go-plugin) |
| New tools mean new UIs to learn | Shared navigation: views, actions, filter, help |
Built for SREs, platform engineers, and indie operators who live in the terminal.
- 15 official plugins — Docker, Redis, Kafka, RabbitMQ, Postgres, SSH, Argo CD, Kubernetes users, Kubernetes port-forward, Bunny DNS, AWS Costs, S3, Git, GitHub, system processes
- KeePass-backed secrets — auto-created on first launch; open with KeePassXC or
omo secrets - Package Manager — sync the plugin index from GitHub and install/update plugins in-app
- Multi-target —
Ctrl+tswitches instances (e.g.redis/production/cache↔redis/staging/cache) - Keyboard-first — Tab focus, filter (
/), refresh (R), help (?); Tab stays inside open modals - Safe by design — credentials stay local; plugins receive config via
Configure, not nested secret RPC - Cross-platform host — Linux / macOS / Windows; plugins ship as standalone executables
curl -fsSL https://raw.githubusercontent.com/hatembentayeb/omo/main/install.sh | bashInstalls the latest release into /usr/local/bin (override with OMO_INSTALL_DIR) and creates ~/.omo/.
Download the archive for your OS/arch from the Releases page, extract omo, and put it on your PATH.
git clone https://github.com/hatembentayeb/omo.git
cd omo
make all # builds host + all plugins into ~/.omo/pluginsRequires Go 1.25+.
omoOn first run, omo:
- Generates
~/.omo/keys/omo.key - Creates
~/.omo/secrets/omo.kdbx(unlocked by that key file)
Back up
~/.omo/keys/omo.key. Without it you cannot open the secrets database.
Inside omo:
- Focus the plugins list (left sidebar) and press
p
— or Tab to the host actions list and select Package Manager - Press
Sto sync the plugin index - Press
Ato install all plugins (or install selectively) - Press
Qto return
Every connection is a KeePass entry:
<plugin>/<environment>/<instance>
Examples: redis/production/cache-01, docker/development/local, k8sportforward/development/playground.
Option A — CLI (scriptable):
omo secrets put redis/development/local \
--url localhost \
--password mypass \
--attr port=6379 \
--attr database=0
omo secrets list redis
omo secrets get redis/development/localOption B — KeePassXC:
- Open
~/.omo/secrets/omo.kdbx - Authenticate with Key File →
~/.omo/keys/omo.key - Create groups
redis→development, entrylocal - Set URL / username / password and custom attributes (
port, …)
Select the plugin in the sidebar. Use Ctrl+t to pick the target, ? for plugin help, R to refresh.
No mockups — these are the same screens you run every day.
Dashboard — plugin rail on the left, cover in the center. Pick a tool or open the Package Manager with p.
Package Manager — sync the index, install, and update plugins without leaving the TUI.
Docker — containers, images, networks, volumes, and compose — keyboard-first.
Logs — shared in-place logs view — wrap, find, marks, and copy from any plugin.
Kubernetes — workloads, services, pods, and port-forwards against your cluster context.
Postgres — users, databases, tables, and schemas in one keyboard-driven manager.
More on the site: oh-myops.com.
| Plugin | What you manage | KeePass path |
|---|---|---|
| docker | Containers, images, networks, volumes, Compose | docker/<env>/<host> |
| redis | Keys, memory, clients, slowlog, pub/sub | redis/<env>/<instance> |
| kafka | Brokers, topics, partitions, consumer groups | kafka/<env>/<cluster> |
| rabbitmq | Queues, exchanges, bindings, connections | rabbitmq/<env>/<instance> |
| postgres | Databases, users, queries, replication | postgres/<env>/<instance> |
| ssh | Remote shell, processes, disk, services | ssh/<env>/<server> |
| argocd | Apps, projects, accounts, RBAC | argocd/<env>/<instance> |
| k8suser | Cert-based users & roles | k8suser/<env>/<cluster> |
| k8sportforward | Deployments / StatefulSets / Services / Pods port-forward | k8sportforward/<env>/<cluster> |
| bunnydns | Bunny.net DNS zones, records, DNSSEC, stats, certificates | bunnydns/<env>/<account> |
| dnscheck | Dig-style DNS, SSL expiry, mail auth, HTTP, WHOIS | dnscheck/<env>/<domain> or press L |
| awsCosts | Cost explorer, budgets, forecasts | awsCosts/<env>/<profile> |
| s3 | Buckets, objects, ACL, lifecycle, multipart | s3/<env>/<profile> |
| git | Status, commits, branches, stash | git/<env>/<repo> |
| github | PRs, Actions, secrets, variables, releases | github/<env>/<account> |
| sysprocess | Local processes, CPU, memory, disk, ports | (no KeePass entry) |
Plugin metadata lives in plugins.meta.yaml; the published index is index.yaml.
| Field | Typical use |
|---|---|
| Title | Instance display name |
| URL | Host / endpoint / socket |
| UserName | Username |
| Password | Password / token / secret key |
| Notes | Free-form description |
| Custom attributes | port, database, region, ssl_mode, kubeconfig, … |
Empty fields are ignored — only set what the plugin needs.
Example entries
Redis — redis/production/cache-main
| Field | Value |
|---|---|
| URL | redis.example.com |
| Password | … |
port |
6379 |
database |
0 |
Postgres — postgres/production/app-db
| Field | Value |
|---|---|
| URL | db.example.com |
| UserName | admin |
| Password | … |
port |
5432 |
database |
myapp |
ssl_mode |
require |
Docker — docker/development/local
| Field | Value |
|---|---|
| URL | unix:///var/run/docker.sock |
Kubernetes port-forward — k8sportforward/development/playground
| Field | Value |
|---|---|
kubeconfig |
~/.kube/config |
context |
kind-omo-playground (optional) |
namespace |
demo (optional default filter) |
Bunny DNS — bunnydns/production/main
| Field | Value |
|---|---|
| Password | Bunny account AccessKey |
| URL | https://api.bunny.net (optional) |
SSH — ssh/production/web-01
| Field | Value |
|---|---|
| URL | 10.0.1.50 |
| UserName | deploy |
port |
22 |
auth_method |
key |
private_key_path |
~/.ssh/id_ed25519 |
Manage the vault without a GUI (CI-friendly):
omo secrets list [prefix]
omo secrets get <plugin/env/name>
omo secrets put <plugin/env/name> [--username U] [--password P] [--url U] [--notes N] [--attr k=v]
omo secrets delete <plugin/env/name>
omo secrets reset --yes # deletes omo.kdbx; key file is keptRun omo secrets with no args for full help.
| Key | Action |
|---|---|
| Tab / Shift+Tab | Cycle focus (plugins ↔ main ↔ actions); inside a modal, move between its fields/buttons only |
| ↑ / ↓ | Move selection |
| Enter | Activate |
| r | Refresh plugins (plugins list focused) |
| p | Open Package Manager (plugins list focused) |
| i | Open Settings / Info (plugins list focused) |
| Key | Action |
|---|---|
| Ctrl+t | Switch target / connection |
| R | Refresh view |
| / | Filter rows |
| ? | Help (plugin + global bindings) |
| Esc | Back / home / dismiss modal |
Plugin-specific actions are listed in ? and in the actions column.
┌─────────────────────────────────────────────────────────┐
│ KeePass ~/.omo/secrets/omo.kdbx + ~/.omo/keys/omo.key│
│ redis/prod/cache · docker/dev/local · s3/prod/main … │
└──────────────────────────┬──────────────────────────────┘
│ host resolves secrets
┌──────────────────────────▼──────────────────────────────┐
│ omo host (cmd/omo) │
│ · TUI (tview/tcell) │
│ · Package Manager + plugin launcher │
│ · Configure → GetView / DoAction over RPC │
└──────────────────────────┬──────────────────────────────┘
│ hashicorp/go-plugin (exec)
┌─────────────────┼─────────────────┐
▼ ▼ ▼
plugin-redis plugin-docker plugin-s3 …
(ViewData) (ViewData) (ViewData)
Why RPC plugins? Native Go plugins (.so) break across Go versions. omo plugins are separate binaries spoken to over RPC, so the host and plugins can be released independently and cross-compiled cleanly.
~/.omo/
├── secrets/omo.kdbx # credentials (KeePass KDBX4)
├── keys/omo.key # master key file — back this up
├── index.yaml # remote plugin catalog (synced)
├── installed.yaml # what you have installed
├── logs/ # omo.log + per-plugin logs
└── plugins/
├── redis/redis
├── docker/docker
└── …
cmd/omo/ # host binary + secrets CLI
internal/host/ # TUI host, RPC renderer, package manager wiring
pkg/
pluginrpc/ # RPC contract (ViewData, DoAction, …)
pluginapi/ # shared metadata / logging helpers
secrets/ # KeePass integration
ui/ # reusable TUI widgets
plugins/<name>/ # one directory per official plugin
cmd/<name>/ # plugin main (Serve)
dev/ # local stacks + KeePass seed scripts
- Go 1.25+
- Docker (optional, for
make dev-setupstacks) - KeePassXC (optional, for inspecting the vault)
make all # build host + install all plugins to ~/.omo/plugins
make plugin-redis # rebuild a single plugin quickly
make clean # remove local ./omo binary (keeps ~/.omo)
make purge # remove ~/.omo entirely (destructive)
make dev-setup # start/seed local Redis/Kafka (and friends) via dev/
make dev-seed # seed KeePass for plugins that don't need DockerAfter make all, run omo from your Go bin or ./omo.
go mod tidy
go vet ./...
go build ./cmd/omo
# CI also builds every plugin under plugins/*/cmd/*CI workflow: .github/workflows/ci.yml.
-
Implement
pluginrpc.Plugin:GetMetadata() (pluginapi.PluginMetadata, error) Configure(pluginrpc.ConfigureRequest) error GetView(pluginrpc.ViewRequest) (pluginrpc.ViewData, error) DoAction(pluginrpc.ActionRequest) (pluginrpc.ActionResult, error) Stop() error
-
Return tables as
ViewData(Headers,Rows, key bindings). The host owns rendering. -
Put an entrypoint at
plugins/<name>/cmd/<name>that callsplugin.Servewithpluginrpc.ServePluginMap(impl). -
Register the plugin in
plugins.meta.yaml. -
Add a
dev/<name>/setup.sh(and KeePass seed) so reviewers can try it locally.
Study a full example: plugins/redis/.
The host loads KeePass settings and calls Configure with a map[string]string (host, port, password, …). Plugins must not open nested RPC back to secrets during GetView — that deadlocks net/rpc on the shared mux.
- Host:
~/.omo/logs/omo.log,rpc-host.log - Plugins:
~/.omo/logs/<plugin>.log
- Credentials never leave your machine unless you point a plugin at a remote service.
- Prefer the key file model; treat
~/.omo/keys/omo.keylike a private key. - Use
omo secretsin automation instead of committing passwords. - Review plugin source before installing third-party plugins (same as any ops tool).
-
omo secretsCLI - RPC plugins (no Go
.soversion skew) - Kubernetes port-forward plugin
- Bunny DNS plugin
- Richer plugin SDK / lifecycle docs
- Prometheus / Grafana plugin
- Theme / color customization
- Community plugin registry guidelines
Ideas and bugs: GitHub Issues.
Contributions are welcome — bug fixes, plugins, docs, and DX improvements.
- Fork and create a branch (
feat/…,fix/…) - Keep changes focused; match existing style
- Ensure
go vet ./...and builds succeed (make allor CI-equivalent) - For plugins: include
dev/setup + a KeePass seed path so maintainers can test - Open a PR against
mainwith a clear summary and test notes
Please be respectful in issues and PRs. This is a community project.
| OS | Arch | Host | Plugins |
|---|---|---|---|
| Linux | amd64 / arm64 | ✅ | ✅ |
| macOS | amd64 / arm64 | ✅ | ✅ |
| Windows | amd64 | ✅ | ✅ |
Release automation: .github/workflows/release.yml.
Apache License 2.0 — see LICENSE.
Built for people who operate systems from a shell.
oh-myops.com ·
GitHub





