Self-contained macOS menu bar control plane for Docker runtimes, compose stacks, shared env state and project-local dev workflows.
DevStackMenu is a self-contained macOS menu bar app for managing remote Docker access, compose stacks, shared developer variables and stable developer endpoints from one native AppKit UI.
It provides a native AppKit UI for:
- inspecting status, active profiles, Docker context and compact runtime metrics
- creating managed runtime targets for local Docker contexts and SSH-backed remote hosts
- switching profiles and Docker contexts without relying on an external helper CLI
- starting or stopping tunnel and compose actions
- managing shared env variables and profile-scoped secrets
- importing
docker-compose.ymlfiles into DevStack profiles
The project is functional, but still intentionally small and local-first. The repository now follows a conventional OSS layout so it is easier to build, test, review and contribute to.
Repository: Mesteriis/dev-stack
The current menu structure is grouped around the workflows that matter during day-to-day dev work: status, the active profile, runtimes, and variables.
The status panel stays compact but still shows the active profile, runtime, git context, tunnel state, compose health and forwarded services.
Profile actions stay close to the active profile itself: compose lifecycle, logs, secrets, env files, project folders and profile editing are all in one submenu.
- macOS 13 or newer
- Swift 6
- Docker or OrbStack CLI available in
PATH
Clone the repository:
git clone git@github.com:Mesteriis/dev-stack.git
cd dev-stackmake build
make test
make app
make checkThis produces local app bundles in dist/:
dist/DevStackMenu.appdist/Import Compose To DX.app
To install them into ~/Applications, run:
make install-localFor a release-style install, build and install the package artifact:
make package
make install-packageFor a real root-install smoke-check (installer + pkgutil + post-install checks), run one command:
./Scripts/release-smoke-install.sh dist/DevStackMenu-*.pkgFor signed artifacts:
./Scripts/release-smoke-install.sh --signed dist/DevStackMenu-*.pkgIf you download a release .pkg from GitHub instead of building locally, note the current distribution status:
- local
dist/exists only in your working copy or CI workspace aftermake package - GitHub Release assets are separate downloaded files and do not appear in your local
dist/ - unsigned / non-notarized downloaded packages can be blocked by Gatekeeper on macOS
The smoke script verifies:
- package path resolution and signature policy
- required payload entries (
./Applications/DevStackMenu.app,./Applications/Import Compose To DX.app,./usr/local/bin/dx) - package installation through
sudo installer - presence of installed artifacts in
/Applicationsand/usr/local/bin - CLI entrypoint execution (
dx status)
The installer places:
DevStackMenu.appandImport Compose To DX.appinto/Applicationsdxinto/usr/local/bin
If an existing DevStack installation is found, the installer will ask whether to remove it before installing:
removeexisting files and continue installationkeepkeep the current installation unchanged and complete without replacing itabortinstall
For non-interactive installs in CI or scripts, set:
export DEVSTACK_INSTALL_EXISTING_POLICY=removeto replace existing files automatically. Set it to keep to preserve the current installation without replacing it.
If installation succeeds, dx is available at /usr/local/bin/dx and should run immediately in a new shell.
If an existing shell still does not resolve dx (rare zsh command cache case), reopen the shell or run:
rehashThis .pkg is the primary release artifact built by CI.
If macOS blocks an already-downloaded release package with "Apple could not verify it", the package is not notarized yet.
If you trust the release and want to install it manually, remove the quarantine attribute and open it again:
PKG="$(find "$HOME/Downloads" -maxdepth 1 -type f -name 'DevStackMenu-*.pkg' -exec stat -f '%m %N' {} \; | sort -nr | head -n 1 | cut -d' ' -f2-)"
[ -n "$PKG" ] && [ -f "$PKG" ] || { echo "DevStackMenu pkg not found in ~/Downloads" >&2; exit 1; }
xattr -d com.apple.quarantine "$PKG" 2>/dev/null || xattr -c "$PKG"
open "$PKG"Or install directly without Finder:
PKG="$(find "$HOME/Downloads" -maxdepth 1 -type f -name 'DevStackMenu-*.pkg' -exec stat -f '%m %N' {} \; | sort -nr | head -n 1 | cut -d' ' -f2-)"
[ -n "$PKG" ] && [ -f "$PKG" ] || { echo "DevStackMenu pkg not found in ~/Downloads" >&2; exit 1; }
xattr -d com.apple.quarantine "$PKG" 2>/dev/null || xattr -c "$PKG"
sudo installer -pkg "$PKG" -target /If you want Gatekeeper-friendly installs without removing quarantine manually, the release must be signed with Developer ID Installer and notarized. The repository already contains the pipeline hooks for that in Scripts/sign-notarize-package.sh and .github/workflows/release.yml; it only needs the Apple signing/notarization secrets configured.
- shows the current active profile, managed runtime, tunnel state, Docker context and compact metrics in the macOS menu bar
- stores reusable runtime target definitions in
~/Library/Application Support/DevStackMenu/runtimes - stores imported profile metadata in
~/Library/Application Support/DevStackMenu/profiles - stores managed shared env variables in
~/Library/Application Support/DevStackMenu/managed-vars.json - uses a runtime lock file at
~/Library/Application Support/DevStackMenu/app.lockto keep only one app instance alive - provides a
New Runtime…wizard that verifies SSH access, creates the Docker context and can bootstrap Docker on apt-based remote hosts - switches profiles and Docker contexts without leaving the desktop
- can keep multiple profiles active across different projects while switching safely inside the same project
- prevents duplicate menu bar instances and re-focuses the already running app instead
- opens and edits profile JSON files stored in
~/Library/Application Support/DevStackMenu/profiles - plans compose changes through
docker compose config --format jsonand falls back to a lightweight parser only for degraded import cases - syncs project-relative bind mounts to remote servers before
docker compose upand refuses host paths outside the project tree - imports compose services into DevStack profiles and opens the result in the profile editor
- supports multi-file compose profiles with a primary file plus additional overlays passed in
docker compose -f ...order - includes a global variable manager for non-secret env values, with per-variable profile assignments and
.envimport - includes a profile-scoped Keychain-backed secret manager for
${VAR}compose references - reads IDE state from PyCharm and VS Code on startup and can offer to activate a matching profile automatically
- copies shell exports for the active profile to the clipboard
- provides fast status, runtime and profile switching for compose-driven local and remote workflows
- keeps menu actions focused on lifecycle, inspection, profile operations, variables, and secrets
- manages SSH tunnel launch agents itself instead of delegating orchestration to an external helper CLI
- can preview compose changes, open logs, metrics, volume and remote-file reports in the standard macOS viewer
- can delete a profile together with its compose stack, named volumes, project-scoped managed data and synced remote data
- automatically removes imported profiles whose source compose file no longer exists
Typical flow for a remote build host:
- install the app with
make install-local - open
DevStackMenu - choose
New Runtime… - enter the SSH host, user and desired Docker context name
- let the wizard verify or bootstrap Docker and save the runtime target
- create a profile that targets that saved runtime
Current functional priorities:
- making compose import more tolerant of real-world compose files
- keeping the built-in runtime predictable when switching active profiles
- evolving runtime setup UX around remote Docker preparation and local container modes
Current limitations:
- compose planning/import uses
docker compose config --format jsonwhen Docker is available and falls back to a lightweight parser only as a degraded path - remote compose sync supports project-relative bind mounts only; absolute host paths outside the project directory are treated as unsupported for remote runs
- managed variables are plain stored config intended for shared dev env values and are applied before project
.envfiles; sensitive data should still live in the Keychain-backed secrets flow - automatic remote Docker bootstrap is currently implemented for apt-based Linux hosts; other distributions still need manual setup
- distribution artifacts are currently unsigned
- UI automation is not in place yet; verification is build + smoke-check oriented
DevStackMenu keeps utilities inside the workflows that already exist instead of adding a separate toolbox.
Current V1 utilities:
Compose Environmentinside the profile editor detects${VAR}references from the compose config, shows which values are missing, empty, external, managed or already satisfied by Keychain, and lets you fix them in place.- Missing or empty compose variables can generate values directly from the editor using:
- secure random strings (
32or64) UUID v4UUID v7
- secure random strings (
- While the profile editor is open, DevStack watches the clipboard for Unix timestamps, JSON and base64, then shows a quiet inline preview you can reuse while filling compose env values.
Small examples:
JWT_SECRET is missing
-> Generate…
-> Secure Random (64)
-> Save in Keychain
SESSION_ID is missing
-> Generate…
-> UUID v7
-> Save to .env.devstack
Copied: 1716000000
-> editor shows Clipboard: Unix timestamp -> 2024-05-18T...
-> Use Result
DevStackMenu remains the native control plane. The dx executable is a thin terminal entrypoint into the same profiles, runtimes, compose parsing and env validation rules that the app already uses.
Build it with the rest of the package:
swift build
.build/debug/dx statusIf dx is not on your PATH yet, you can run the same commands through SwiftPM as swift run dx <command>.
Primary V1 flow from a project directory:
cd /path/to/project
dx add profile -f docker-compose.ymlThat wizard reuses the app import flow and asks only for:
- profile name
- runtime target
- optional compose overlays
- how to resolve missing
${VAR}references
Other supported commands:
dx add server
dx use profile state-corp-backend
dx status
dx env check --profile state-corp-backend
dx up
dx downSmall examples:
$ dx status
Profile: state-corp-backend
Runtime: remote-192-168-1-33
Docker context: srv-remote-192-168-1-33
Tunnel: loaded
Compose: state-corp-backend (3 running)
$ dx env check --profile state-corp-backend
Profile: state-corp-backend
Working directory: /Users/avm/projects/Work/ecos/state-corp-backend
Compose refs: 8
Unresolved: 1
Environment:
- JWT_SECRET -> Unresolved
- POSTGRES_DB -> .env
- REDIS_URL -> Variable Manager
If you run an interactive command in a non-interactive shell, dx fails clearly and asks you to rerun it in a TTY.
The current top-level menu is intentionally operational:
Status- current profile name or
Select Profile RuntimesVariables
Profile-specific actions stay under the current-profile item so switching, runtime control, compose actions, secrets and deletion live in one place. Raw Docker contexts are now grouped inside Runtimes, not split into a separate top-level menu.
Useful commands:
make build
make test
make app
make check
make package
make install-package
make cleanmake test runs the repository smoke checks through a small executable target so the project stays verifiable even in command-line macOS environments where the standard test modules are not available.
make check runs the full local verification path used in CI: build, smoke checks and app bundle packaging.
Repository layout:
.
├── Sources/
│ ├── DevStackCore/ # AppKit UI + profile/runtime logic
│ ├── dx/ # thin CLI entrypoint
│ └── DevStackMenu/ # executable entry point
├── Sources/DevStackSmokeTests/ # parser and normalization smoke checks
├── Resources/ # Info.plist and AppleScript helper
├── Scripts/ # app bundle build/install scripts
├── docs/ # architecture and maintainer docs
└── .github/workflows/ # CI
- docs/ARCHITECTURE.md
- RELEASING.md
- SUPPORT.md
- docs/index.md as the documentation hub
- GitHub Docs workflow in
.github/workflows/docs.yml
Start with CONTRIBUTING.md. For behavior changes, include a short rationale and keep user-facing workflows in mind; this app is primarily a developer tool, so regressions in profile handling or compose import matter more than cosmetic changes.
If you want to work on functionality first, the most valuable areas are compose import compatibility, profile safety, and clearer feedback around shell-command failures.
Security reporting instructions are in SECURITY.md.
Released under the MIT License. See LICENSE.



