One native macOS GUI. One CLI that doubles as docker and docker-compose. Zero gRPC. Zero NIO. Zero daemon of its own.
Macker replaces Docker Desktop on macOS by talking directly to Apple's
apple/containerruntime — no Docker daemon, no license, no Electron, no gRPC stack.
Native SwiftUI GUI — Dashboard, Containers, Images, Builds, Volumes, Networks, Compose, Activity Monitor, Settings.
Drop-in CLI — symlink the binary as
dockeranddocker-compose.Custom Compose engine —
${VAR}interpolation,depends_onwithservice_healthy, service-name DNS, config-hash recreation.Hot reload — synthetic inotify bridge over virtiofs so Vite/webpack/nodemon rebuild on host edits.
Menu bar extra — CPU/memory rings and per-container quick actions.
Dashboard — runtime status, resource cards, live CPU/Memory/Block I/O charts, and active containers.
apple/container exposes a private XPC API (container-apiserver). Macker
talks to it through a lightweight XPC client — no gRPC, no NIO, no daemon of
its own. Operations that have no XPC route (image build, pull, push, tag,
prune) fall back to the container CLI.
The single macker binary dispatches on its arguments:
| Invocation | Mode |
|---|---|
macker |
Launches the SwiftUI GUI |
macker <args> |
Runs the headless CLI (ArgumentParser) |
Read the full module map in docs/ARCHITECTURE.md.
| macOS | 15+ (Sequoia or later) |
| CPU | Apple Silicon (arm64) |
| Runtime | apple/container installed and running (container-apiserver) |
| XPC protocol | pinned to 1.6.0 in Package.swift — client and runtime ship in lockstep |
| Runtime upgrade | Settings → Runtime shows the installed, recommended and latest container versions. The upgrade installs the recommended release after checking its SHA-256 |
brew install --cask djpfs/tools/macker
Installs the Macker.app bundle into /Applications (Launchpad/Spotlight
discoverable). The cask lives in the
homebrew-tools tap and points to
the latest stable .pkg from GitHub Releases.
To use the CLI as a drop-in docker replacement, symlink the bundled binary:
ln -s /Applications/Macker.app/Contents/MacOS/macker /usr/local/bin/docker
ln -s /Applications/Macker.app/Contents/MacOS/macker /usr/local/bin/docker-composeThis installs /usr/local/bin/macker. To use it as a drop-in docker
replacement:
ln -s /usr/local/bin/macker /usr/local/bin/docker
ln -s /usr/local/bin/macker /usr/local/bin/docker-compose
The GUI also has a Settings → Install CLI button that does the same thing (with an administrator password prompt).
Build a
.pkg installer and install it into /Applications:
./Scripts/build-pkg.sh 1.0.0
open dist/Macker-1.0.0.pkgOr, from the GUI, use Settings → Install app in /Applications to copy the
app bundle into /Applications.
git clone https://github.com/djpfs/macker.git
cd macker
make build # debug buildmackerThe GUI provides:
Sidebar — Overview, Resources (with item counts), and System sections.
Dashboard — resource cards, daemon status, and CPU/memory/I/O charts with configurable time intervals.
Containers — list with search, All / Running / Stopped filter, sort, published-port badges, and memory use for running containers. The detail pane has Info / Stats / Logs / Terminal / Files / Settings tabs.
Images — list, pull, and delete (with confirmation).
Builds — build history, build an image from a context, retry failed builds, copy the build command, and prune the build cache.
Volumes / Networks — create, inspect, and delete.
Compose — load compose files (including drag & drop), up/down, logs, and per-project actions.
Activity Monitor — per-container resource usage.
Settings — appearance (System / Light / Dark), the container runtime section (installed, recommended and latest versions, with a one-click upgrade to the tested release), menu bar customization, storage cleanup, install CLI/app, launch at login, and more.
docker version
docker selftest
docker system status
docker ps
docker compose up -dSome commands with the 1.6.0 runtime:
docker commit web myimage:1 # container commit (needs REPOSITORY[:TAG])
docker run -d --network-alias api nginx # DNS alias on the default network
docker network connect --alias api mynet web # DNS alias on an existing networkdocker commit does not support -a, -c or -m; they are refused with an error.
Because the binary is meant to be symlinked as docker, unknown top-level
subcommands are transparently routed to the docker shim. So these are
equivalent:
docker ps
macker psecho "$TOKEN" | docker login ghcr.io -u myuser --password-stdin # password never in argv
docker login registry.local:5000 --scheme http -u ci --password-stdin
docker logout ghcr.io
docker build -t app:1 --target prod --platform linux/arm64 --label team=web \
--secret id=token,src=$HOME/.npmrc --pull -f Dockerfile.dev .
docker build -t app:1 --no-cache .
docker tag app:1 registry.example.com/team/app:1
docker push registry.example.com/team/app:1docker login reads the password from --password-stdin or a hidden prompt.
Build caching is controlled with --no-cache and --pull. The 1.6.0 CLI has no
cache-from/cache-to options, so cache import and export are not available yet.
docker context ls
docker context create colima --docker host=unix://$HOME/.colima/default/docker.sock
docker context use colima # later commands go to Colima through its docker CLI
docker --context default ps # one call on the local runtime
docker context rm colimaThe default context is Macker's own runtime. Any other context sends the
command, unchanged, to the docker CLI installed with that runtime (Docker
Desktop, Colima and OrbStack ship one). Macker never uses itself for that.
macker migrate --from colima --dry-run # list images (and volumes with --volumes)
macker migrate --from colima # copy every image
macker migrate --from orbstack --volumes # also copy named volumes, with contents
macker migrate --from docker-desktop --volumes --helper-image alpine:latestImages are saved with the source's docker CLI and loaded with container image load. Named volumes are read and written with tar in a helper container
(default alpine:latest, which must contain tar). Containers, compose
projects, bind mounts and anonymous volumes are not moved; recreate them with
docker compose up once the images and volumes are in place.
docker compose -f compose.yaml -f compose.prod.yaml up -d # files are merged in order
COMPOSE_FILE=compose.yaml:compose.dev.yaml docker compose up -d
docker compose --profile debug up -d # or COMPOSE_PROFILES=debug
docker compose up -d --scale web=3 # replicas: web-1, web-2, web-3
docker compose stop web # acts on every replica- Without
-f, Macker usescompose.yaml(ordocker-compose.yml) and its.overridefile when present. - Services with
profiles:run only when a matching profile is active. deploy.replicassets the replica count whenscale:and--scaleare unset.configs:andsecrets:with afile:source are mounted read-only at theirtarget:(default/<name>for configs,/run/secrets/<name>for secrets).healthcheck: { disable: true }(ortest: [NONE]) turns a healthcheck off.
Not yet supported in Compose: inline content: configs, environment-backed
secrets, external configs and secrets, healthcheck status in ps, and the
per-check timeout.
Full command reference — see docs/COMMANDS.md.
| Layers, modules, and how they fit together | |
Full docker and docker compose reference |
|
How docker compose up works and the virtiofs inotify bridge |
|
| Menu bar and storage & cleanup | |
| Security policy and notes | |
| Development setup, code style, testing, releasing | |
| Known limitations and planned improvements |
- Privilege escalation: the Settings "Install CLI" and "Install app in
/Applications" actions run
osascriptwith administrator privileges. These are user-initiated and only copy the app's own binary into standard locations. See SECURITY.md. - No secrets: the project contains no hardcoded credentials, API keys, or
tokens. Do not commit
.envfiles orfirebase-adminsdk-*.json. - Keychain-backed secrets: runtime secrets can be managed with
docker secret ...and referenced askeychain://SECRET_NAMEinKEY=VALUEenvironment entries. - Shell safety: subprocesses are launched with argument arrays (not shell string interpolation), so command arguments are not shell-injected.
Contributions are welcome — bug reports, feature requests, docs, and pull requests.
make build # debug build
make test # unit tests (needs full Xcode)
make release # release build
make lint # swift-format (if installed)
make guest-agent # cross-compile the hot-reload agent
make clean # remove build artifactsTests run in CI on macOS with full Xcode (XCTest is not shipped with
CommandLineTools). The XPC protocol is not a stable public API — client and
container-apiserver ship in lockstep. When updating the runtime, bump both
containerVersion in Package.swift and RuntimeVersion.recommended in
Sources/ContainerBackend/RuntimeVersion.swift.
Full guide — see docs/CONTRIBUTING.md.













