[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-92447":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":15,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":17,"rankGlobal":9,"rankLanguage":9,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":9,"pushedAt":9,"updatedAt":23,"readmeContent":24,"aiSummary":25,"trendingCount":15,"starSnapshotCount":15,"syncStatus":26,"lastSyncTime":27,"discoverSource":28},92447,"davit","wouterdebie\u002Fdavit","wouterdebie","A native macOS UI for Apple's platform",null,"Swift",814,12,1,7,0,322,57.34,"MIT License",false,"main",true,[],"2026-07-22 04:02:06","# Davit\n\n**A native macOS UI for Apple's [container](https:\u002F\u002Fgithub.com\u002Fapple\u002Fcontainer) platform** — think OrbStack\u002FDocker Desktop, but for the Linux-containers-as-lightweight-VMs stack Apple ships for Apple silicon.\n\n> A *davit* is the shipboard crane that hoists cargo and small craft over the side — which is more or less what this app does with your containers.\n\nBuilt entirely in SwiftUI (no Electron, no web views). Davit links Apple's own\n**`ContainerAPIClient`** library and talks to `container-apiserver` **directly over XPC** —\nthe same wire path the `container` CLI uses. The CLI binary is never invoked: lists,\nlifecycle, live stats, log streaming, image pulls, volume\u002Fnetwork management, the\nin-terminal shell (`davit exec`), and even launchd service bootstrap all go through the API.\n\n## Features\n\n- **Dashboard** — service status with one-click start\u002Fstop, resource counts, disk usage with reclaimable-space cleanup menu, live aggregate CPU chart across running containers.\n- **Containers** — list with live CPU\u002Fmemory\u002FIP per row, start\u002Fstop\u002Fkill\u002Frestart\u002Fdelete, prune, search, and **Edit & Recreate** (containers are immutable on this platform, so \"editing\" opens the Run sheet prefilled with the container's ports\u002Fenv\u002Fmounts\u002Fresources\u002Fnetwork — with the image's entrypoint\u002FCMD\u002Fenv subtracted so only *your* customizations show — and replaces it on confirm). Detail view with:\n  - *Overview*: image, command, platform, resources, network (IP\u002FMAC\u002Fgateway\u002Fhostname), published ports with \"Open in Browser\", mounts, environment, labels.\n  - *Logs*: streaming `-f` follow mode, boot-log toggle, tail selector, copy.\n  - *Stats*: live CPU %, memory, and disk-I\u002FO charts (Swift Charts); tiles for CPU, memory, disk space used, network, and process count.\n  - *Inspect*: pretty-printed raw JSON.\n  - *Terminal*: opens an interactive shell in Terminal\u002FiTerm (`davit exec` over XPC).\n  - *Files*: browse the container filesystem — navigate, download, upload, delete (over `exec` + copy in\u002Fout).\n- **Images** — pull with streaming progress, **Pull Latest** to refresh any image's tag to the newest digest (context menu or image detail), run-from-image, tag, delete, prune; per-image platform variants, size, digest, \"used by\" containers.\n- **Volumes** — create (with size), delete, prune, reveal backing image in Finder, in-use badges.\n- **Networks** — create (subnet \u002F internal), delete, prune, attached-container counts.\n- **Machines** — Apple's container machines (lightweight general-purpose VMs with your home directory mounted and a stable `.machine` DNS name): create from any image with CPU\u002Fmemory sizing, boot\u002Fstop, set the default, delete; detail view with configuration overview, streamed logs, live stats and inspect JSON; one-click **Terminal** into the machine's login shell; edit CPUs\u002Fmemory\u002Fhome-mount (applies on next boot). `Davit machine list|create|boot|stop|delete|exec|set` headless.\n- **Run Container sheet** — image picker, name, command, ports, env vars, volume\u002Fbind mounts, CPU\u002Fmemory limits, network selection.\n- **Build images** — Images → Build Image: pick a context folder and Dockerfile, set tag\u002Fbuild-args, and Davit drives the platform's BuildKit builder (starting it if needed), then loads and tags the result into the image store. `Davit build -t \u003Ctag> \u003Ccontext-dir>` headless.\n- **Compose import** — Containers → ⋯ → Import Compose File: parses a compose file, previews exactly what will be created (services in `depends_on` order, named volumes, networks, the equivalent `container run` command per service, and warnings for anything unsupported), then creates and starts the stack — honoring `healthcheck`s, `profiles`, `depends_on` conditions (`service_healthy`, `service_completed_successfully`), `env_file:`\u002F`entrypoint:`, and `${VAR}` interpolation from the file's sibling `.env` merged under the process environment. Headless: the full lifecycle — `Davit compose plan | up [-d] | down [-v] | ps | logs [-f\\|--follow] [--tail \u003Cn>] | stop | start | restart | pull | exec \u003Cservice> \u003Ccommand…>`, each taking `[-f \u003Cfile>] [--env-file \u003Cpath>] [--profile \u003Cp>]… [service…]` — autodiscovers the file like docker (`compose.yaml`, `compose.yml`, `docker-compose.yml`, `docker-compose.yaml`, walking up parent directories; `COMPOSE_FILE` wins). Naming services scopes the command: `plan`\u002F`up` add the dependency closure, while `stop`\u002F`start`\u002F`restart`\u002F`pull`\u002F`ps` and `down` apply to exactly the named services (docker behavior). Service discovery: the platform's DNS cannot resolve compose service names, so `up`\u002F`start`\u002F`restart` write managed `\u002Fetc\u002Fhosts` entries (suffixed `# davit-compose`) into every running container of the project, mapping each service and container name to its current IP — refreshed on every run, so a recreated service's new IP reaches the containers that kept running. Caveat: containers recreated outside compose keep stale entries until the next `up` or `start`; images without `\u002Fbin\u002Fsh` can't be patched (warning).\n- **Registries** — sign in to Docker Hub \u002F ghcr.io \u002F any registry to pull private images (Settings → Registries); credentials are verified against the registry and stored in the login keychain, shared with the `container` CLI. **Docker credential helpers** are honored too: if `~\u002F.docker\u002Fconfig.json` has a `credHelpers`\u002F`credsStore` entry for a registry (Google Artifact Registry via `gcloud`, ECR, etc.), Davit invokes the helper right before each pull and stages the short-lived token for the platform, so hourly-expiring credentials always work.\n- **Menu bar extra** — service status, per-container quick actions from anywhere.\n- **Auto-start containers** — mark any container \"Start when Davit Opens\" (context menu); on launch Davit brings the platform services up if needed and starts them. Combined with *Open at login*, your containers are running when you sit down.\n- **Open at login** — optional launch-to-menu-bar at login (Settings → General), via `SMAppService`.\n- **In-app updates** — checks GitHub Releases daily (or on demand from About); one click downloads the new version, verifies its Developer ID signature (team must match), swaps the bundle atomically with rollback, and relaunches. `Davit update check|install` headless.\n- **Settings** — platform install-root override and refresh interval (General), plus a full **platform configuration editor** (Platform tab): default container CPUs\u002Fmemory, registry, local DNS domain, builder resources\u002FRosetta, and advanced knobs (kernel, init image, machine). Only values differing from install defaults are written to `~\u002F.config\u002Fcontainer\u002Fconfig.toml`, `[plugin.*]` sections are preserved, every save is validated through the platform's own config loader before commit, and the result is published to the app root immediately — container defaults\u002Fregistry\u002FDNS apply to new operations right away, daemon-side settings after a service restart (button provided).\n\n## Requirements\n\n- Apple silicon Mac, macOS 15+ (macOS 26 recommended — matches `container` 1.1)\n- [apple\u002Fcontainer](https:\u002F\u002Fgithub.com\u002Fapple\u002Fcontainer\u002Freleases) installed (or vendored, see below)\n\n## Releases\n\nTagging `v*` triggers a GitHub Actions workflow that builds the app on a macOS\nrunner and attaches `Davit-\u003Cversion>.zip` (+ sha256) to a GitHub Release.\n\nWith these repository secrets set, releases are Developer ID signed (hardened\nruntime) and notarized, so they open like any other app:\n\n| Secret | Value |\n|---|---|\n| `MACOS_CERT_P12` | base64 of the exported \"Developer ID Application\" cert (`base64 -i cert.p12`) |\n| `MACOS_CERT_PASSWORD` | the .p12 export password |\n| `APPLE_ID` | your Apple ID email |\n| `APPLE_TEAM_ID` | 10-char team id (developer.apple.com → Membership) |\n| `APPLE_APP_SPECIFIC_PASSWORD` | app-specific password from appleid.apple.com |\n\nWithout the secrets, builds fall back to ad-hoc signing and the release notes\ninclude the `xattr -dr com.apple.quarantine` workaround.\n\n## Install\n\n```sh\nbrew install wouterdebie\u002Ftap\u002Fdavit\n```\n\n(Homebrew 6 asks you to trust third-party taps on first use: `brew trust wouterdebie\u002Ftap`.)\nOr download the signed zip from [Releases](https:\u002F\u002Fgithub.com\u002Fwouterdebie\u002Fdavit\u002Freleases\u002Flatest) \u002F [davit.app](https:\u002F\u002Fdavit.app).\n\n## Getting started\n\nFrom a fresh install to something running in your browser:\n\n1. **Open Davit.** On first launch, if Apple's container platform isn't installed, Davit downloads and installs it for you — no admin password needed.\n2. **Pull a demo image** — Images → Pull Image → `nginxdemos\u002Fhello` (small, and it serves a visible page).\n3. **Run it with a port** — Run the image, map host `8088` → container `80`.\n4. **Open it** — the container's Ports row has *Open in Browser*, or visit `localhost:8088`. You'll see a page served from inside the container, showing its own hostname and IP.\n5. **Explore** — live CPU\u002Fmemory\u002Fdisk, streaming logs, a one-click terminal, and Edit & Recreate to change ports\u002Fenv\u002Fresources.\n\n## Build & run\n\n```sh\nscripts\u002Fbundle.sh        # builds release binary + assembles dist\u002FDavit.app\nopen dist\u002FDavit.app\n```\n\nPlain `swift build` \u002F `swift run` also works for development (no bundle, so no icon\u002Fmenu-bar niceties).\n\n## What must still be installed\n\nThe API removes the CLI dependency, **not** the platform dependency: `container-apiserver`\nand its runtime\u002Fnetwork plugin binaries are host launchd services that the library only\ntalks to. Davit resolves the platform install root in this order:\n\n1. custom install root from Settings\n2. a Davit-managed install at `~\u002FLibrary\u002FApplication Support\u002Fdev.wouter.davit\u002Fplatform\u002F\u003Cversion>`\n3. `\u002Fusr\u002Flocal` (the official installer)\n4. vendored inside the app at `Davit.app\u002FContents\u002FResources\u002Fvendor`\n\n**In-app install:** when no platform is found, the onboarding screen offers one-click\ninstall — Davit downloads Apple's signed installer pkg (with a live progress bar),\nverifies the code signature, extracts the payload into the managed root (no\nadministrator rights needed, unlike the official installer), and bootstraps the\nservices from there. Settings → General can then also install a `container` shell\ncommand: a wrapper in `\u002Fusr\u002Flocal\u002Fbin` that pins `CONTAINER_INSTALL_ROOT` to the\nmanaged root before exec'ing the real CLI (one admin prompt; a bare symlink would be\nwrong, since the CLI derives its install root from the unresolved executable path). The managed copy sits\nabove `\u002Fusr\u002Flocal` in the resolution order on purpose: it always matches the client\nversion the app links, so a newer system daemon can't break XPC compatibility.\nAlso available headless: `Davit platform install|remove`.\n\nTo ship a fully self-contained app that works without the system installer:\n\n```sh\nscripts\u002Fvendor.sh 1.0.0        # downloads the official signed .pkg, extracts payload into Vendor\u002Fcontainer\nscripts\u002Fbundle.sh --vendor     # bundles it into the app\n```\n\nService start\u002Fstop is implemented in-process (LaunchPlist + ServiceManager from\n`ContainerPlugin` — the same code `container system start` runs), pointed at whichever\ninstall root was resolved. Kernel and init-image installation are handled\nnon-interactively on first start. App data lives in the standard\n`~\u002FLibrary\u002FApplication Support\u002Fcom.apple.container\u002F`, so Davit and the CLI (if\ninstalled) always see the same containers.\n\n**Version pinning:** the SPM dependency on apple\u002Fcontainer is pinned `exact: \"1.0.0\"` to\nmatch the daemon; client and apiserver ship in lockstep and the XPC protocol is not a\nstable public API. When the installed platform updates, bump the pin and rebuild.\n\nTrade-offs of vendoring, for the record: the bundle grows by ~150 MB, you own the\nupdate cadence of the toolchain, and the launchd services are registered from inside\nthe app bundle (so moving\u002Fdeleting the app orphans them until `container system stop`).\nThe default remains \"use the system install\" because the official pkg keeps services\nunder `\u002Fusr\u002Flocal` and updates independently.\n\n## Binary modes\n\nThe app binary doubles as a small tool:\n\n```sh\nDavit exec \u003Ccontainer-id> [command…]   # interactive TTY shell — or a one-off command — in a container (used by \"Open Terminal\")\nDavit selftest                   # end-to-end test of the XPC service layer against the live daemon\nDavit system start|stop          # bootstrap \u002F tear down the container launchd services\nDavit platform install|remove    # download + verify Apple's signed pkg into an app-managed install root\nDavit registry login|list|logout # registry credentials (login reads the password from stdin)\nDavit compose \u003Csubcommand> [-f \u003Cfile>] [--env-file \u003Cpath>] [--profile \u003Cp>]… [service…]\n    # subcommands: plan | up [-d|--detach] | down [-v|--volumes] | ps | logs [-f|--follow] [--tail \u003Cn>]\n    #              stop | start | restart | pull | exec \u003Cservice> \u003Ccommand…>\n    # file autodiscovered like docker; .env + ${VAR} interpolation; naming services scopes the\n    # command (plan\u002Fup add the dependency closure; stop\u002Fstart\u002Frestart\u002Fpull\u002Fps\u002Fdown take exactly\n    # the named services). In-container service names resolve via managed \u002Fetc\u002Fhosts entries,\n    # re-synced on every up\u002Fstart\u002Frestart — recreates outside compose need another up\u002Fstart.\nDavit build -t \u003Ctag> \u003Cdir>       # build an image from \u003Cdir>\u002FDockerfile via the BuildKit shim\nDavit machine list|create|boot|stop|delete   # container machines (micro VMs)\nDavit --snapshot \u002Ftmp\u002Fshots      # render every screen to PNGs via ImageRenderer (no screen-recording permission)\n```\n\n## Architecture\n\n```\nSources\u002FContainerStack\u002F\n  Main.swift            entry point + exec\u002Fselftest\u002Fsystem binary modes\n  Backend.swift         XPC service layer on ContainerAPIClient: ContainerService facade,\n                        SystemController (launchd bootstrap), LogStreamer (FileHandle tail\u002Ffollow),\n                        PullProgressModel, TerminalLauncher, platform install resolution\n  Models.swift          view models mapped from ContainerResource types (views stay decoupled\n                        from the unstable library API)\n  AppState.swift        @MainActor store: polling (4s data \u002F 2s stats), CPU% derivation, actions\n  SnapshotDriver.swift  --snapshot harness\n  App.swift             SwiftUI scenes, menu bar extra\n  Views\u002F                Shell (sidebar), Dashboard, Containers, ContainerDetail, Images,\n                        VolumesNetworks, Sheets (run\u002Fpull\u002Fcreate), Settings, Components\n```\n\nStats note: the daemon reports cumulative `cpuUsageUsec`; Davit derives CPU% from deltas\nbetween polls, normalized to wall-clock time (100% = one full core).\n","Davit 是一款专为 Apple Silicon Mac 设计的原生 macOS 容器管理工具，用于可视化操作 Apple 官方 container 平台（Linux 容器作为轻量级 VM 的运行时）。它基于 SwiftUI 开发，直接通过 XPC 调用系统级 ContainerAPIClient，不依赖 CLI 或 Web 技术栈，支持容器\u002F镜像\u002F卷\u002F网络\u002F机器全生命周期管理、实时资源监控、日志流式查看、文件浏览上传下载及终端交互。适用于在 Apple Silicon Mac 上进行本地开发、测试和调试容器化应用的开发者与运维人员，尤其适合需要深度集成 macOS 系统能力的轻量级虚拟化场景。",2,"2026-07-09 02:30:02","CREATED_QUERY"]