{"id":50559037,"url":"https://github.com/cwklurks/dockpose","last_synced_at":"2026-06-04T10:04:30.014Z","repository":{"id":352991347,"uuid":"1216437212","full_name":"cwklurks/dockpose","owner":"cwklurks","description":"A keyboard-driven TUI for managing Docker Compose stacks","archived":false,"fork":false,"pushed_at":"2026-04-22T02:11:54.000Z","size":562,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-22T03:13:01.779Z","etag":null,"topics":["bubbletea","devops","docker","docker-compose","go","homelab","selfhosted","terminal","tui"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cwklurks.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-20T22:52:14.000Z","updated_at":"2026-04-22T02:10:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cwklurks/dockpose","commit_stats":null,"previous_names":["cwklurks/dockpose"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/cwklurks/dockpose","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwklurks%2Fdockpose","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwklurks%2Fdockpose/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwklurks%2Fdockpose/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwklurks%2Fdockpose/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cwklurks","download_url":"https://codeload.github.com/cwklurks/dockpose/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cwklurks%2Fdockpose/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33899805,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bubbletea","devops","docker","docker-compose","go","homelab","selfhosted","terminal","tui"],"created_at":"2026-06-04T10:04:29.171Z","updated_at":"2026-06-04T10:04:30.008Z","avatar_url":"https://github.com/cwklurks.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003ch1\u003edockpose\u003c/h1\u003e\n\n\u003cp\u003e\n  \u003ca href=\"https://go.dev/\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Go-1.25-00ADD8?style=for-the-badge\u0026logo=go\u0026logoColor=white\" alt=\"Go 1.25\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/charmbracelet/bubbletea\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Bubble_Tea-TUI-FF7AC0?style=for-the-badge\" alt=\"Bubble Tea TUI\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://docs.docker.com/compose/\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Docker_Compose-2496ed?style=for-the-badge\u0026logo=docker\u0026logoColor=white\" alt=\"Docker Compose\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge\" alt=\"MIT License\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/cwklurks/dockpose/releases/latest\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/release/cwklurks/dockpose?style=for-the-badge\u0026color=10b981\" alt=\"Latest release\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n\u003cimg src=\"docs/media/demo.gif\" alt=\"dockpose demo: stack list with status dots, dependency DAG, and live filter\" width=\"100%\"\u003e\n\n\u003cstrong\u003eA keyboard-driven command center for Docker Compose fleets.\u003c/strong\u003e\n\u003cbr\u003e\nFor people running many Compose stacks across a laptop, NAS, or VPS:\u003cbr\u003eone terminal view for stack discovery, status, dependencies, logs, and actions.\n\n\u003cp\u003e\n  \u003ca href=\"#try-it-in-30-seconds\"\u003eTry It\u003c/a\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003ca href=\"#who-its-for\"\u003eWho It's For\u003c/a\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003ca href=\"#why-not-lazydocker-dockge-or-portainer\"\u003eCompared To\u003c/a\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003ca href=\"#features\"\u003eFeatures\u003c/a\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003ca href=\"#how-it-works\"\u003eHow It Works\u003c/a\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003ca href=\"#keybinds\"\u003eKeybinds\u003c/a\u003e\u0026nbsp;\u0026nbsp;·\u0026nbsp;\u0026nbsp;\u003ca href=\"#install\"\u003eInstall\u003c/a\u003e\n\u003c/p\u003e\n\n\u003c/div\u003e\n\n## What is this?\n\nIf you run a homelab, a VPS, or a handful of services at work with Docker Compose, you probably do not have one stack. You have a sprawl: media, monitoring, auth, reverse proxy, a few dev stacks, maybe a second host over SSH. And with that sprawl comes a lot of:\n\n```sh\ncd ~/docker/media \u0026\u0026 docker compose pull \u0026\u0026 docker compose up -d\ncd ~/docker/monitoring \u0026\u0026 docker compose restart grafana\ncd ~/docker/traefik \u0026\u0026 docker compose logs -f --tail 200\n```\n\ndockpose replaces that dance with a stack-first terminal UI. Point it at the directories that matter, and it gives you one place to see every Compose stack, drill into dependencies, tail logs, edit `.env`, and run common actions without `cd`-ing around or opening a web panel.\n\nThe core idea is simple: **a stack is the unit you care about**, not an individual container. If lazydocker is a broad Docker cockpit, dockpose is the tool for people whose real problem is managing a fleet of Compose projects.\n\n\u003e [!NOTE]\n\u003e v0.2.0 is live on GitHub Releases and Homebrew — see [Install](#install). AUR and Scoop are on the roadmap.\n\n## Who It's For\n\n- **Homelabbers** managing 5-50 Compose stacks across one or more machines\n- **Developers** juggling several dev stacks locally (database + api + worker + web)\n- **Solo operators \u0026 small teams** running a VPS or two without Kubernetes\n- **Anyone on SSH** who wants a real UI for their remote Docker host without installing a web panel\n\nIf you have one Compose file and run it twice a month, you probably don't need this. If you have a `~/docker` folder with ten subdirectories, dockpose is for you.\n\n## Why Not lazydocker, Dockge, or Portainer?\n\nThey are good tools. dockpose exists because the Compose-heavy workflow still has a gap.\n\n| Tool | Best at | Where dockpose differs |\n| --- | --- | --- |\n| **lazydocker** | Broad Docker/container workflows in a terminal UI | dockpose is more opinionated about **Compose stacks as the primary object**, especially when you have many projects spread across directories or hosts |\n| **Dockge** | Browser-based Compose management | dockpose stays **keyboard-first and SSH-native** with no web UI or agent to keep running |\n| **Portainer** | Full web control plane for Docker and beyond | dockpose is intentionally smaller: **single binary, terminal-native, stack-focused**, and fast to jump into over SSH |\n\nIf your main pain is containers in general, `lazydocker` is a strong fit. If your pain is \"I have too many Compose stacks scattered across my machines,\" that's the problem dockpose is built around.\n\n## Try It in 30 Seconds\n\nNo Docker required — demo mode ships a fake homelab so you can kick the tires first:\n\n```sh\nbrew tap cwklurks/tap\nbrew install dockpose\ndockpose --demo\n```\n\nYou'll drop into a synthetic fleet (media, monitoring, traefik, dev-api, authentik) with live-rotating statuses. Every destructive keybind is a safe no-op, so mash away — `?` shows help, `q` quits.\n\nReal-world usage looks like this:\n\n```sh\ndockpose ~/docker ~/homelab ~/projects\n```\n\nThat turns dockpose into a single terminal view over the stack roots you actually care about.\n\nNot on Homebrew? See [Install](#install) for `curl`, `.deb`, `.rpm`, and Windows zip.\n\n## Features\n\n\u003cdetails open\u003e\n\u003csummary\u003e\u003cstrong\u003eStacks are first-class\u003c/strong\u003e — not containers\u003c/summary\u003e\n\n\u003cbr\u003e\n\nThe main view is a list of **stacks**, not containers. Hitting `u` runs `docker compose up -d` for the whole stack; `d` brings it down; `r` restarts; `p` pulls new images. If the stack defines Compose profiles, dockpose prompts you to pick one. Individual services live one level deeper, where they belong.\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\n\u003csummary\u003e\u003cstrong\u003eMulti-root discovery\u003c/strong\u003e — point it at your stack directories\u003c/summary\u003e\n\n\u003cbr\u003e\n\nGive dockpose one or more roots and it walks them for `compose.yml` / `compose.yaml` files. That lets you manage a real homelab or dev fleet from one place instead of hopping directory to directory.\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\n\u003csummary\u003e\u003cstrong\u003eDependency graph\u003c/strong\u003e — see what depends on what, at a glance\u003c/summary\u003e\n\n\u003cbr\u003e\n\nEach stack's detail view draws a layered ASCII dependency graph from its `depends_on` declarations. Colored status dots (● healthy / ◐ starting / ○ stopped) sit next to each service so \"why isn't the API up?\" becomes a visual question: oh, Postgres is red.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eWorks over SSH\u003c/strong\u003e — remote Docker hosts are first-class\u003c/summary\u003e\n\n\u003cbr\u003e\n\nUse dockpose against whatever Docker daemon your current context targets — local socket, `ssh://you@homelab`, `tcp://...`, whatever. No agent to install on the remote host; it rides on Docker's built-in transport.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eStreaming logs\u003c/strong\u003e — follow, filter, timestamps, wrap\u003c/summary\u003e\n\n\u003cbr\u003e\n\nTail any single service or every service in the stack at once. Toggles for follow (`f`), timestamps (`t`), line wrap (`w`), and a buffer filter (`/`). Multi-service tails get per-service prefixes so you can actually tell who said what.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e.env editor\u003c/strong\u003e — with secret masking\u003c/summary\u003e\n\n\u003cbr\u003e\n\nEdit a stack's `.env` inline without ever pasting secrets into your shell history. Values that look like tokens or keys are masked by default; reveal one with `r` when you need to.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eDemo mode\u003c/strong\u003e — try it without Docker\u003c/summary\u003e\n\n\u003cbr\u003e\n\n`--demo` swaps the real Docker backend for a synthetic one with five pre-built stacks and rotating statuses. Perfect for evaluating the tool, recording a screenshot, or showing a teammate what you're talking about. Destructive actions no-op with a friendly toast.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eSingle static binary\u003c/strong\u003e — no runtime, no dependencies\u003c/summary\u003e\n\n\u003cbr\u003e\n\nOne Go binary, cross-compiled for macOS, Linux, and Windows on amd64 and arm64. Install via Homebrew, `.deb`, `.rpm`, or a raw tarball — see [Install](#install). AUR and Scoop coming next.\n\n\u003c/details\u003e\n\n## How It Works\n\n### The 30-second version\n\n1. On launch, dockpose walks the roots you pass it, looking for `compose.yml` / `compose.yaml` files.\n2. It parses each one with the **same library Docker Compose itself uses**, so there's no \"dockpose dialect\" — if `docker compose` accepts it, dockpose does too.\n3. It talks to the Docker daemon over its normal socket (or SSH, for remote hosts), and polls container state every 2 seconds to keep the UI honest.\n4. When you press a key, it shells out to `docker compose` under the hood. dockpose is a UI layer, not a reimplementation — your stacks stay yours.\n\n### Architecture\n\ndockpose is built on [Bubble Tea](https://github.com/charmbracelet/bubbletea) (Elm-style TUI) and [Lip Gloss](https://github.com/charmbracelet/lipgloss) for styling, with the official [Docker SDK for Go](https://github.com/docker/docker) for daemon communication. Compose parsing uses [`compose-spec/compose-go`](https://github.com/compose-spec/compose-go) — the same library Compose itself uses, so v2 manifests parse identically to `docker compose`.\n\n```\ninternal/\n├── docker/      # Source interface; ClientSource (live) + container queries\n├── stack/       # Compose parsing, dependency graph, registry, action shims\n├── discover/    # Filesystem walker for compose.y*ml\n├── demo/        # Synthetic Source: fixture stacks + rotating statuses\n├── ui/          # Bubble Tea root + screens (stacklist, detail, logs, modals)\n└── config/      # XDG config + cache I/O\n```\n\n### The Source abstraction\n\nThe TUI talks to a single `docker.Source` interface — implemented by `ClientSource` (real Docker) and `demo.Source` (synthetic). This means demo mode and production mode share every line of UI code, so bugs in either path surface in both. It's also how you could, in theory, add a Podman or k8s-compose backend later.\n\n### Stack-aware polling\n\nA 2-second tick refreshes container states for every known stack using the same query the detail view uses, so the status dots on the list and the per-service table never disagree. The detail view's refresh is debounced to the same tick to avoid hammering remote daemons over slow SSH links.\n\n## Keybinds\n\n\u003cdetails open\u003e\n\u003csummary\u003e\u003cstrong\u003eStack list\u003c/strong\u003e\u003c/summary\u003e\n\n\u003cbr\u003e\n\n| Key | Action |\n| --- | --- |\n| `↑/k` `↓/j` | navigate |\n| `g` / `G` | jump to top / bottom |\n| `enter` | open stack detail |\n| `u` | up (prompts for profile if multiple defined) |\n| `d` | down |\n| `r` | restart |\n| `p` | pull |\n| `e` | edit `.env` |\n| `c` | switch Docker context |\n| `/` | filter |\n| `?` | help overlay |\n| `q` | quit |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eStack detail\u003c/strong\u003e\u003c/summary\u003e\n\n\u003cbr\u003e\n\n| Key | Action |\n| --- | --- |\n| `l` | tail logs for the selected service |\n| `s` | open shell in container |\n| `x` | stop service |\n| `R` | restart service |\n| `i` | inspect container (JSON) |\n| `esc` | back to stack list |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eLogs\u003c/strong\u003e\u003c/summary\u003e\n\n\u003cbr\u003e\n\n| Key | Action |\n| --- | --- |\n| `f` | toggle follow |\n| `t` | toggle timestamps |\n| `w` | toggle line wrap |\n| `c` | clear buffer |\n| `g` / `G` | top / bottom |\n| `/` | filter buffer |\n\n\u003c/details\u003e\n\n## Install\n\n### Homebrew (macOS + Linux)\n\n```sh\nbrew tap cwklurks/tap\nbrew install dockpose\n```\n\nOnce tapped, `brew upgrade dockpose` keeps you current on every release. Or as a single command:\n\n```sh\nbrew install cwklurks/tap/dockpose\n```\n\n### Linux (binary)\n\n```sh\ntag=$(curl -fsSL -o /dev/null -w '%{url_effective}' https://github.com/cwklurks/dockpose/releases/latest)\ntag=${tag##*/}\nversion=${tag#v}\nos=$(uname -s)\narch=$(uname -m)\ncase \"$arch\" in\n  x86_64|amd64) arch=x86_64 ;;\n  arm64|aarch64) arch=arm64 ;;\nesac\ncurl -fsSL \"https://github.com/cwklurks/dockpose/releases/download/${tag}/dockpose_${version}_${os}_${arch}.tar.gz\" \\\n  | sudo tar -xz -C /usr/local/bin dockpose\ndockpose --version\n```\n\nIf auto-detection does not match your platform, grab the matching archive from the [latest release](https://github.com/cwklurks/dockpose/releases/latest).\n\n### Debian / Ubuntu\n\nGrab the `.deb` from the [latest release](https://github.com/cwklurks/dockpose/releases/latest) and:\n\n```sh\nsudo dpkg -i dockpose_*_amd64.deb   # or _arm64.deb\n```\n\n### Fedora / RHEL\n\n```sh\nsudo rpm -i dockpose-*.x86_64.rpm   # or .aarch64.rpm\n```\n\n### Windows\n\nDownload the zip from the [latest release](https://github.com/cwklurks/dockpose/releases/latest), extract, and put `dockpose.exe` on your `PATH`.\n\n### Build from source\n\n```sh\ngit clone https://github.com/cwklurks/dockpose.git\ncd dockpose\ngo build -o dockpose ./cmd/dockpose\n./dockpose --version\n\n# or, with the full lint + test suite:\nmake check\n```\n\n**Requirements:** Go 1.25+ and Docker. `make check` additionally needs `make` and `golangci-lint`.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eRegenerating the demo recording\u003c/strong\u003e\u003c/summary\u003e\n\n\u003cbr\u003e\n\nThree paths, depending on what you have installed:\n\n```sh\n# 1. Cast file (zero system deps): records frames programmatically.\ngo run ./cmd/dockpose-record \u003e docs/media/demo.cast\n\n# 2. GIF from cast (requires `agg` from asciinema/agg releases):\nagg --theme github-dark --font-size 13 --speed 1.2 \\\n    docs/media/demo.cast docs/media/demo.gif\n\n# 3. Or, with vhs + ttyd installed, drive the real binary:\ngo build -o ./dockpose ./cmd/dockpose\nvhs docs/media/demo.tape\n```\n\n\u003c/details\u003e\n\n## Roadmap\n\nNear-term, in rough priority order:\n\n- **AUR + Scoop** — Arch and Windows packaging. Homebrew + deb/rpm shipped already.\n- **Persistent stack registry** — honor the `~/.config/dockpose/stacks.toml` cache and refresh it lazily instead of rescanning every launch.\n- **Filter persistence** — remember active filter and cursor position across sessions.\n- **Pull progress** — live `docker compose pull` progress in the status bar instead of a single \"done\" toast.\n- **Smarter multi-root defaults** — make \"point me at my homelab/dev stack roots\" easier on first run.\n- **Container events stream** — replace the 2s poll with Docker's events API for sub-second updates.\n- **Theming** — more than the current GitHub Dark palette.\n\nFurther out: Podman backend, Compose file editor, secrets integration. [Open an issue](https://github.com/cwklurks/dockpose/issues) if there's something you want sooner.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and feature ideas welcome via [Issues](https://github.com/cwklurks/dockpose/issues).\n\n## License\n\n[MIT](LICENSE).\n\n## Disclaimer\n\ndockpose is an independent open-source project and is not affiliated with, endorsed by, or sponsored by Docker, Inc.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcwklurks%2Fdockpose","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcwklurks%2Fdockpose","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcwklurks%2Fdockpose/lists"}