Run one docker compose command across every compose project in a directory tree.
mdc discovers compose.yaml, compose.yml, docker-compose.yaml, and docker-compose.yml, picks one canonical file per directory, and runs the same docker compose command for each target.
# Homebrew
brew install aaronflorey/tap/mdc
# Go
go install github.com/aaronflorey/mdc@latestPrebuilt binaries are also published on the GitHub releases page.
mdc ps
mdc up -d
mdc --depth 2 pull
mdc --jobs 4 logs --tail 50
mdc --ansi never psmdc [mdc flags] <docker compose args...>--depth: scan depth (0= current directory only, default1)--jobs: max concurrentdocker composeprocesses (0= all targets)--quiet-targets: suppress per-target section headers; merged tables, live prefixes, and completion labels retain attribution
git clone https://github.com/aaronflorey/mdc.git
cd mdc
mise install
task setup
task ci- Discovery starts in the current directory and walks child directories up to
--depth. - If a directory has multiple compose files, this precedence is used:
compose.yamlcompose.ymldocker-compose.yamldocker-compose.yml
mdcpreserves the target directory basename as the Compose project name when it is unique, and switches to a deterministic unique name only when duplicate basenames would collide.- Most non-
pscommands print grouped output per project in sorted directory order. - Top-level multi-target detached
mdc up -dkeeps one live status line per target on TTYs so concurrent Docker progress stays stable; non-TTY output falls back to grouped summaries, and failed targets still print grouped details. Attached multi-targetmdc upkeeps live target-prefixed output. - Top-level multi-target
mdc logswithout follow mode (-f/--follow) uses grouped output for easier historical scanning, while explicit follow mode keeps live interleaved prefixed lines for per-target attribution. - Top-level multi-target
mdc build(parallel mode) suppresses noisy successful BuildKit logs and prints concise[target] build completesummaries; failed targets still print detailed stdout/stderr plus the standard failure summary. - Top-level
mdc eventsis serial-only for multi-target runs; if multiple targets are discovered, rerun with--jobs 1. mdc pstriesdocker compose ps --format json, merges results into one table, and falls back to stitched text when JSON is unavailable.- Top-level multi-target
mdc imagesemits one merged table when all targets share a conservatively parseable table shape; otherwise it falls back to a deterministic stitched view that keeps one header and preserves all rows in sorted target order. - Exit code is non-zero if any compose target fails.
- Ctrl-C cancels the shared run context so in-flight
docker composeprocesses stop together. mdconly parses its own flags (--depth,--jobs,--quiet-targets) and passes everything else through todocker compose.
Development is driven by mise for tool versions and Task for commands. mise install provisions Go, GoReleaser, hk, golangci-lint, and staticcheck pinned to the versions in mise.toml.
mise install # install pinned tools
task setup # tidy modules and install git hooks
task test
task test:integration
task lint
task build
task ciGit hooks are managed by hk. task setup runs hk install --mise so pre-commit lint/format and commit-msg conventional-commit checks are wired against the mise-managed tools.
task run -- ps forwards arguments to go run ..
task test:integration requires a working local Docker Engine with docker compose available.
Releases use release-please for versioning and changelog management. Merged Conventional Commits are collected into a release PR, and merging that PR creates a vX.Y.Z tag, publishes release archives with GoReleaser, and updates the aaronflorey/homebrew-tap formula.