{"id":50687147,"url":"https://github.com/getgantry/gantry","last_synced_at":"2026-06-17T17:01:15.771Z","repository":{"id":362486433,"uuid":"1259254831","full_name":"getgantry/gantry","owner":"getgantry","description":"Native macOS app for managing and monitoring Docker — local and over SSH. Agent-ready: built-in MCP server and App Intents. Free and open source.","archived":false,"fork":false,"pushed_at":"2026-06-13T22:50:16.000Z","size":5956,"stargazers_count":40,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-13T23:23:53.555Z","etag":null,"topics":["ai-agents","containers","developer-tools","docker","macos","mcp","mcp-server","ssh","swift","swiftui"],"latest_commit_sha":null,"homepage":"https://getgantry.github.io/","language":"Swift","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/getgantry.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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-06-04T10:27:32.000Z","updated_at":"2026-06-13T22:50:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/getgantry/gantry","commit_stats":null,"previous_names":["andrewkomkov/gantry","getgantry/gantry"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/getgantry/gantry","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getgantry%2Fgantry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getgantry%2Fgantry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getgantry%2Fgantry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getgantry%2Fgantry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getgantry","download_url":"https://codeload.github.com/getgantry/gantry/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getgantry%2Fgantry/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34457743,"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-17T02:00:05.408Z","response_time":127,"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":["ai-agents","containers","developer-tools","docker","macos","mcp","mcp-server","ssh","swift","swiftui"],"created_at":"2026-06-09T00:00:27.015Z","updated_at":"2026-06-17T17:01:15.758Z","avatar_url":"https://github.com/getgantry.png","language":"Swift","funding_links":[],"categories":["開発ツール","Development"],"sub_categories":["仮想化","Web Development"],"readme":"# Gantry\n\n**Native Docker management for your Mac. Local and over SSH. Agent-ready with a built-in MCP server. Free, open source, no limits.**\n\n[![CI](https://github.com/getgantry/gantry/actions/workflows/ci.yml/badge.svg)](https://github.com/getgantry/gantry/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/getgantry/gantry)](https://github.com/getgantry/gantry/releases/latest)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![macOS 26+](https://img.shields.io/badge/macOS-26%2B-black)](https://github.com/getgantry/gantry/releases/latest)\n[![MCP](https://img.shields.io/badge/MCP-server%20included-8A2BE2)](#agent-friendly)\n\nGantry is a fully native macOS app (SwiftUI, Swift 6) for managing and monitoring\nDocker — the local daemon and any number of remote hosts over SSH — plus\n[apple/container](https://github.com/apple/container) hosts on your Mac. No\nElectron, no subscription, no artificial limits. It is built to be driven by AI agents\ntoo: a bundled [MCP server](#agent-friendly) and App Intents expose your Docker\nhosts to Claude, Shortcuts, Siri and scripts.\n\nWebsite: **https://getgantry.github.io/**\n\n![Fleet dashboard](assets/dashboard.png)\n\n## Features\n\n### Core\n- **Containers** — list, inspect, start/stop/restart/kill/pause, rename, remove,\n  create and run with ports/env/volumes/restart-policy, commit to image,\n  export filesystem, view processes (`top`), update restart policy\n- **Images** — list, **build from a Dockerfile** (drag-and-drop, live build log),\n  history, tag, pull with per-layer progress, remove, prune\n- **Private registries** — pulls resolve credentials from your\n  `~/.docker/config.json` (inline `auth`, credential helpers, macOS Keychain),\n  the same `docker login` you already ran — so create-and-run, Quick Run and\n  Compose pull private images, not just the manual Pull sheet\n- **Volumes / Networks** — list, inspect, create, remove, prune,\n  connect/disconnect containers\n- **Docker Compose** — containers grouped by compose project with collapsible\n  sections and group start/stop/restart; **run a compose file on any host**\n  (local Docker, SSH or apple/container — the runner adapts per engine) with an\n  inline **YAML editor**, and open **merged stack logs** for a whole project\n- **System** — disk usage (`docker system df`), prune build cache\n- **Smart Cleanup** — a *Reclaim Space* panel that shows dangling images,\n  stopped containers, unused volumes and build cache with their sizes and prunes\n  each, or all at once, reporting how much was freed\n\n### Live\n- **Logs** — streamed in real time with follow mode, **regex** or literal\n  Cmd+F search with match highlighting and next/previous navigation, a\n  **minimum-level filter** (Error/Warn/Info/Debug/Trace), **ANSI color**\n  rendering, and a 50k-line virtualized buffer\n- **Stats** — CPU, memory, network and disk I/O charts (Swift Charts), 1s sampling\n- **Events-driven UI** — lists update live from the Docker events stream,\n  with polling fallback\n\n### Notifications\n- **Failure alerts** — a native macOS notification the moment a container\n  crashes (non-zero exit), runs out of memory, or fails its health check, on\n  any host (local, SSH, apple/container). Derived from the live events stream\n- **Click through** — opening a notification activates Gantry and jumps\n  straight to the offending container's detail view\n- **No false alarms** — stops, restarts, kills and removes you trigger from\n  Gantry are never reported as crashes, and an unhealthy container alerts once\n  per episode, not on every health re-check. Toggle the whole thing in\n  Settings ▸ General\n\n![Live stats](assets/stats.png)\n\n### Fleet \u0026 hosts\n- **Fleet dashboard** — every connected host on one screen: live CPU/memory\n  sparklines (10-minute rolling window), container state breakdown, host facts;\n  opens at launch\n- **Health column** — failed connections and unhealthy / restarting / dead\n  containers across all hosts, each row jumping straight to the culprit\n- **Host overview** — CPU/memory gauges, Docker disk usage, daemon facts\n- **Host terminal \u0026 files (SSH hosts)** — a shell on the host itself and an\n  SFTP file browser, alongside the per-container ones\n- **Auto-reconnect** — dropped tunnels and transient connect failures retry\n  with backoff; stale data stays on screen instead of blanking out\n\n### Terminal \u0026 Files\n- **Exec terminal** — full terminal emulation (SwiftTerm) into any running\n  container, local or remote\n- **File browser** — browse the container filesystem, download and upload files,\n  **drag \u0026 drop** between Finder and the container (tar-packed transparently)\n- **Drop any folder into a container** — upload whole folder trees from the\n  picker or by dropping them from Finder. Works on every engine, including\n  apple/container (where there is no archive endpoint, it streams a tar through\n  `tar -x` over exec)\n\n### Ports \u0026 networking\n- **Open in browser** — one click on a published port opens it in your browser:\n  directly for local Docker and apple/container, through an automatic forward\n  for SSH hosts\n- **Local port forwarding (SSH)** — forward a remote container port to\n  `localhost` (an `ssh -L`-style tunnel over a dedicated connection). If the\n  local port is taken, Gantry picks a free one — and you can edit it. Active\n  forwards are listed with open/copy-URL/stop controls\n\n### Remote hosts over SSH\n- Connects exactly like `docker -H ssh://user@host`: an SSH exec channel runs\n  `docker system dial-stdio` and Gantry speaks HTTP/1.1 to the remote daemon\n  over it — nothing to install on the server beyond Docker itself\n- Reads `~/.ssh/config` (aliases, HostName, User, Port, IdentityFile,\n  **ProxyJump** — bastion chains with per-hop auth and host key checks);\n  the Add Host sheet offers one-click import of your config hosts and of\n  `ssh://` **Docker contexts** (`docker context ls`)\n- ed25519 and RSA keys (openssh-key-v1, optional passphrase), password auth;\n  RSA signs with **rsa-sha2-256** so it works against modern OpenSSH servers\n- Host key verification with trust-on-first-use prompts (SHA256 fingerprints),\n  honoring `~/.ssh/known_hosts`; secrets live in the macOS **Keychain**\n\n### apple/container hosts\n- Add an **Apple Container** host to manage Linux containers run by\n  [apple/container](https://github.com/apple/container) side by side with your\n  Docker hosts\n- **Zero-setup onboarding** — on first launch (and after Gantry updates) it\n  checks for the `container` CLI and offers to install or upgrade a supported\n  version through Homebrew for you, so the runtime is ready before you add a host\n- Driven through the `container` CLI and translated to the same engine\n  interface, so lifecycle, live logs, exec terminal, stats, create-container,\n  images (pull/tag/delete/prune), volumes, networks and disk usage all work\n  from the same UI — and through the MCP server and App Intents\n- Connecting the host starts the `container` services if they are down\n- **Service control** — start/stop the `container` background services from the\n  menu bar and Settings ▸ Apple, with live running/stopped status\n- **Open by IP \u0026 hostname** — every apple/container gets a routable IP on your\n  Mac; the container's Overview surfaces that address (and, when it was launched\n  on a local domain, its `name.domain` hostname) with one-click open-in-browser\n  per port\n- **Local DNS domains** — create/list/delete apple/container DNS domains from\n  Settings ▸ Apple (admin-approved), and **star a default**: Gantry writes it\n  into apple/container's `config.toml` and restarts the services for you, so the\n  whole flow works without touching the CLI\n- **Automatic DNS names** (OrbStack-style) — new containers are assigned the\n  default domain automatically with a unique, image-derived name, so each one\n  resolves as `name.domain` across your Mac; the resolver cache is flushed so it\n  works immediately. A DNS domain can also be chosen in **New Container** and\n  **Quick Run**\n- **Assign / Change DNS Name** — set or change a container's domain after\n  creation from its Address section. apple/container fixes the domain at create\n  time, so Gantry recreates the container, preserving its image, command,\n  environment, published ports, volume binds, restart policy and labels (named\n  volumes are kept)\n- **Quick Run** — an OrbStack-style quick-launch sheet: pick a local image, name\n  it, share a macOS folder, map ports and pick a DNS domain, then run — and the\n  container's address opens straight in the browser\n- **Run docker-compose files from Finder** — right-click a `docker-compose.yml`\n  and choose *Open With ▸ Gantry* or *Quick Actions ▸ Compose Up in\n  apple/container* (or File ▸ Open Compose File…). Gantry parses the file,\n  builds any `build:` services, creates the project's network and named\n  volumes, and starts every service in `depends_on` order with the standard\n  `com.docker.compose.*` labels — so the project groups in the sidebar just\n  like Compose on Docker. apple/container has no native `compose`; Gantry does\n  the orchestration itself over the `container` CLI\n- Features the platform does not offer (pause, rename, commit, restart\n  policies, network attach, image history, file *download*) are hidden\n  for these hosts instead of erroring\n\n![Host overview](assets/overview.png)\n\n### Mac-native\n- Three-column split view, Liquid Glass materials, dark/light/system appearance\n- Collapsible host sections in the sidebar; reorder hosts via Move Up/Down\n- Menu bar panel listing running containers per host — open one in your browser,\n  copy its `dns`/`ip:port`, stop/restart inline, or click through to its details\n- Keyboard shortcuts (Cmd+R refresh, Cmd+N new container, Cmd+F log search)\n- **Terminal themes** (System, Solarized Dark, Dracula, Nord) for the embedded shell\n- Optional **Touch ID** confirmation before removing a container or deleting a host\n- Auto-updates via **Sparkle** (EdDSA-signed appcast)\n\n### Agent-friendly\n- **App Intents** — list/start/stop/restart containers and fetch logs from\n  Shortcuts, Siri, Spotlight, or scripts (`shortcuts run`); works even when\n  the app is closed\n- **MCP server** — a bundled `gantry-mcp` binary exposes hosts, containers,\n  images, volumes, networks, logs, stats, exec and disk usage as\n  [Model Context Protocol](https://modelcontextprotocol.io) tools over stdio,\n  so AI agents can manage your Docker hosts (including SSH ones):\n\n  ```sh\n  claude mcp add gantry -- /Applications/Gantry.app/Contents/Resources/gantry-mcp\n  ```\n\n  Headless SSH connections only use hosts whose keys you already trusted in the app.\n- **Copy as Prompt** — every container (list, detail view with ⌥⌘P, menu bar,\n  dashboard issues) can be copied as a paste-ready debugging prompt for an AI\n  coding agent. The prompt carries the host and how to reach it (the exact\n  `ssh` command or the local socket), the Gantry MCP `host_id` and tool names,\n  the container's identity and state — image, health, exit code, restarts,\n  ports, compose project — and a task matched to the symptom: unhealthy asks\n  to debug the failing health check, crash-looping to find the crash, healthy\n  leaves room for your own question. Paste into Claude Code and let it dig in.\n\n## Install\n\n### Homebrew\n\n```sh\nbrew install --cask getgantry/tap/gantry\nxattr -dr com.apple.quarantine /Applications/Gantry.app\n```\n\nThe `xattr` step clears the quarantine flag — the app is not notarized and\nmacOS refuses to open it otherwise.\n\n**Updating:** because the app is ad-hoc signed (not notarized), in-app\nSparkle auto-updates can't launch their installer under Gatekeeper, so updates\ngo through Homebrew:\n\n```sh\nbrew upgrade --cask gantry        # or: brew reinstall --cask gantry\nxattr -dr com.apple.quarantine /Applications/Gantry.app\n```\n\n### Manual\n\n1. Download the latest zip from [Releases](https://github.com/getgantry/gantry/releases/latest)\n2. Unzip and drag **Gantry.app** to Applications\n3. First launch: right-click the app and choose **Open** (the app is not\n   notarized), or clear quarantine:\n\n   ```sh\n   xattr -dr com.apple.quarantine /Applications/Gantry.app\n   ```\n\nRequires **macOS 26 (Tahoe)** or later. Works with Docker Desktop, OrbStack,\nColima, or a plain remote `dockerd` — the socket is auto-discovered\n(`$DOCKER_HOST`, `~/.docker/run`, `~/.orbstack/run`, `~/.colima`, `/var/run`).\n\nUpdates arrive automatically via Sparkle once installed.\n\n## Building from source\n\n```sh\ngit clone https://github.com/getgantry/gantry.git\ncd gantry\nopen Gantry.xcodeproj   # Xcode 26+, build the \"Gantry\" scheme\n```\n\nNo setup steps. The project is a thin hand-written `.xcodeproj` whose code\nlives in local Swift packages.\n\n### Repository layout\n\n```\nApp/                  SwiftUI app target (views, intents, app shell)\nPackages/\n  DockerKit/          Docker Engine API client\n    Transport/          unix socket (async-http-client), SSH dial-stdio glue,\n                        raw-NIO hijack for exec, hand-rolled HTTP/1.1 codec\n    Endpoints/          containers, images, volumes, networks, exec, archive,\n                        system, streaming (logs/stats/events)\n    Streams/            multiplexed log demuxer, JSON-lines decoder,\n                        stats model with the docker CLI CPU/memory formulas,\n                        tar reader/writer\n  SSHKit/             SSH layer on Citadel: key loading, ssh_config parser,\n                      known_hosts + TOFU, SSHDialStdioTransport, local port\n                      forwarding (SSHPortForward)\n  AppCore/            @Observable stores, hosts persistence, Keychain,\n                      headless connections for Intents/MCP\n  GantryMCP/          stdio MCP server executable (bundled into the app)\nscripts/release.sh    release build + Sparkle appcast\nTools/                app icon generator\n```\n\n### How the SSH transport works\n\n`docker -H ssh://` does not forward the remote unix socket. It runs\n`docker system dial-stdio` on the server, which bridges the SSH channel's\nstdin/stdout to the daemon socket. Gantry does the same with\n[Citadel](https://github.com/orlandos-nl/Citadel): one persistent exec channel\ncarries serialized HTTP/1.1 requests (FIFO, keep-alive), and every streaming\nendpoint (logs, stats, events, exec) gets a dedicated channel so nothing blocks.\nA `101 Upgraded` response switches the parser into raw passthrough — that is\nhow the interactive terminal rides the same machinery.\n\n### About the forks\n\nGantry currently builds against two small forks, both intended for upstreaming:\n\n- [andrewkomkov/swift-nio-ssh](https://github.com/andrewkomkov/swift-nio-ssh)\n  (`gantry-fixes`) — fixes a process-killing `preconditionFailure` when a\n  pending read delivers a window adjust on a locally closed channel, and lets\n  a key type declare a distinct userauth algorithm name\n- [andrewkomkov/Citadel](https://github.com/andrewkomkov/Citadel) (`gantry`) —\n  RSA signing with rsa-sha2-256 (RFC 8332) instead of legacy ssh-rsa, which\n  modern OpenSSH servers reject\n\n### Tests\n\n```sh\nswift test --package-path Packages/DockerKit   # parsers, codecs, tar, exec\nswift test --package-path Packages/SSHKit      # ssh_config, known_hosts, keys\n```\n\nLive integration tests are **gated**: they run automatically only when a local\nDocker socket exists (lists, streaming, exec, pull, prune, archive) or when the\nSSH test host is reachable (dial-stdio, exec, stream-cancellation stress, RSA\nauth). On CI they skip cleanly.\n\n### Releasing\n\n```sh\nscripts/release.sh 0.6.0\ngh release create v0.6.0 dist/Gantry-0.6.0.zip --title \"Gantry 0.6.0\"\ngit add appcast.xml CHANGELOG.md \u0026\u0026 git commit -m \"Release 0.6.0\" \u0026\u0026 git push\n```\n\nThe script builds the app, embeds `gantry-mcp`, zips, signs the Sparkle appcast\nentry (EdDSA key in the login Keychain), and stamps the `## [Unreleased]`\nsection of [`CHANGELOG.md`](CHANGELOG.md) with the version and date — so the\nonly manual changelog work is adding bullets under **Unreleased** as you go.\n\n## Known limitations\n\n- Not notarized (no Apple Developer ID) — first launch needs right-click Open\n- ECDSA private keys in OpenSSH format are not supported (ed25519/RSA are)\n- Remote hosts need `docker` on `PATH` for `dial-stdio` (any recent version)\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetgantry%2Fgantry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetgantry%2Fgantry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetgantry%2Fgantry/lists"}