Run Linux desktops and apps on macOS with a native Metal Wayland compositor, Apple Container GUI, Waypipe, Docker/OrbStack, and rootless windows.
Run Linux desktops and apps on macOS with a native Metal Wayland compositor, Apple Container GUI, Waypipe, Docker/OrbStack, and rootless windows.
Cocoa-Way receives the Wayland protocol on macOS and presents Linux applications through a Metal renderer. It can connect to an existing Linux machine with Waypipe or manage local GUI applications through Apple Container, Docker, and OrbStack.
Version 2.0 models the product around three explicit objects:
This keeps classic SSH and local-socket workflows available while making Apple Container a first-class runtime.
| Area | Cocoa-Way 2.0 |
|---|---|
| Rendering | Native Metal renderer with Retina scaling and damage-aware SHM uploads |
| Presentation | Desktop mode for compositors and rootless mode for individual xdg-shell applications |
| Runtimes | Apple Container, Docker-compatible engines, OrbStack, SSH, and local Waypipe sockets |
| Displays | Automatic assignment, named displays, and isolated workers for concurrent applications |
| Transport | Apple Container Transport V2 over --publish-socket, with a compatibility relay fallback |
| Integration | Bidirectional text and PNG clipboard (images up to 64 MiB), low-latency CoreAudio forwarding, keyboard, pointer, and gestures |
| Control plane | Native runtime panels, cocoa-wayctl --json, diagnostics, tasks, logs, and resource warnings |
| Automation | Optional read-only MCP server and onboarding skill; launch, stop, and deletion remain explicit user actions |
Apple Container is a separate Apple runtime and is not bundled with Cocoa-Way. Apple officially supports it on Apple silicon with macOS 26; see its current requirements. Install it before using Cocoa-Way's managed local application workflow:
Apple Container 1.3.1 or newer is strongly recommended. Cocoa-Way retains a compatibility relay for older releases, but 1.3.1 includes important upstream security fixes and satisfies the current Transport V2 baseline. You can verify or update the runtime manually with:
container --version
container system stop
/usr/local/bin/update-container.sh
container system start
container system status
This runtime is optional when Cocoa-Way is used only with SSH, Docker, OrbStack, or an existing local Waypipe socket.
brew tap J-x-Z/tap
brew trust --tap J-x-Z/tap
brew install cocoa-way waypipe-darwin
Download the current .dmg or .zip from GitHub Releases.
brew install libxkbcommon pixman pkg-config
git clone https://github.com/J-x-Z/cocoa-way.git
cd cocoa-way
cargo build --release
waypipe-darwin is required on the Mac for transported applications. The Linux host or GUI-ready container image also needs a compatible Waypipe server.
Start Cocoa-Way:
cocoa-way
Connect to an SSH host with the compatibility script:
./run_waypipe.sh ssh user@linux-host firefox
Waypipe must be installed on both the Mac and the remote Linux host. The script checks the local command and prints this remote requirement before connecting. It also supports local Waypipe/socket workflows and remains independent of Container Mode. The same connection can be created from Connections > Connect to Machine.... Saved entries appear in the Connections menu and are stored in ~/.config/cocoa-way/connections.toml; passwords are never stored.
For a local Apple Container application:
Desktop presentation maps Linux windows into one Cocoa-Way compositor window. Use it for nested compositors such as niri or Hyprland and for workflows that intentionally share one Linux desktop surface.
Rootless presentation maps each xdg-toplevel to a separate native macOS window. Native move, resize, minimize, maximize, fullscreen, title updates, popups, and per-surface input are forwarded to the Linux application.
Use Rootless for ordinary Wayland applications such as Foot or Firefox. A desktop compositor is not a rootless application and should remain in Desktop mode.
runtime = "container" uses Apple's official container CLI. Apple Container itself requires supported Apple silicon and macOS versions; Cocoa-Way reports the installed version and missing capabilities in the Apple Container panel.runtime = "docker" uses the active Docker-compatible context.runtime = "orb" or runtime = "orbstack" uses OrbStack-compatible lifecycle and inventory controls.The runtime panels expose system state, machines or contexts, containers, images, logs, terminal access, CPU/memory statistics, and guarded lifecycle actions. Cocoa-Way does not require Docker or OrbStack for Apple Container sessions.
On Apple Container 1.0 and newer, Cocoa-Way prefers Transport V2. It publishes a host Unix socket into the container, multiplexes Waypipe streams over that channel, and ties the relay lifetime to the application instance. If socket publishing is unavailable or fails during startup, Cocoa-Way can fall back to the older stdio relay.
Clipboard and audio use dedicated local relays. If the Mac uses a loopback HTTP proxy, Cocoa-Way can expose that proxy to the Apple Container subnet without changing global network settings.
The GUI writes profiles to ~/.config/cocoa-way/container-sessions.toml. A representative profile is:
[[session]]
name = "Niri Desktop"
runtime = "container"
image = "localhost/cocoa-way-niri:latest"
profile = "niri"
command = "niri"
presentation = "desktop"
display = "auto"
audio = true
runtime_args = ["--memory", "4G", "--cpus", "4"]
display = "auto" uses the built-in display when it is free and allocates an isolated display when necessary. display = "default" requires the built-in display. Any other stable name selects a dedicated display slot.
While Cocoa-Way is running it exposes a private Unix-socket control API. cocoa-wayctl uses the same validation and event-loop paths as the GUI:
cocoa-wayctl --json status
cocoa-wayctl --json applications
cocoa-wayctl --json displays
cocoa-wayctl diagnostics "Niri Desktop"
cocoa-wayctl launch "Niri Desktop"
cocoa-wayctl stop "Niri Desktop"
cocoa-wayctl display-create "Research Window"
cocoa-wayctl display-close "Research Window"
cocoa-way-mcp is an optional local stdio adapter. Its tools can inspect the environment, suggest trusted image paths, generate reviewable application/connection templates, collect diagnostics, and prepare issue reports. MCP tools are read-only by design; they cannot silently launch applications or delete containers, images, or volumes.
The bundled skills/cocoa-way-onboarding workflow guides new users through image selection and profile creation without replacing explicit GUI confirmation.
graph LR
subgraph macOS
UI[Applications and runtime UI]
API[cocoa-wayctl and MCP]
CW[Cocoa-Way compositor]
Metal[Metal renderer]
Audio[CoreAudio]
end
subgraph Linux
App[Wayland application]
WPServer[Waypipe server]
Helpers[Clipboard and audio relays]
end
UI --> CW
API --> CW
App --> WPServer
WPServer |SSH, Unix socket, or Transport V2| CW
Helpers |local relay sockets| CW
CW --> Metal
CW --> Audio
Dedicated displays run as isolated Cocoa-Way worker processes. A rootless worker may own several native application windows while retaining one runtime/display assignment. Worker telemetry is published back to the control plane without forcing the GUI to redraw continuously.
Some of the compositor, native-surface, transport, and cross-platform work developed in Cocoa-Way has also informed Plyra, a broader project currently being incubated.
Cocoa-Way remains an independent project and has not been abandoned. More information will be shared when Plyra reaches a stage suitable for public release.
0.0 fps - idle; Cocoa-Way renders on demand rather than polling at a fixed frame rate.Use the GUI diagnostics page or:
cocoa-wayctl --json diagnostics "Application Name"
cocoa-wayctl --json logs "Application Name"
For classic SSH socket conflicts, run_waypipe.sh adds StreamLocalBindUnlink=yes. The equivalent manual command is:
waypipe ssh -o StreamLocalBindUnlink=yes user@host application
cargo check --release --all-targets
cargo test --release --all-targets
cargo build --release
The repository vendors the Smithay Universal integration used by Cocoa-Way. waypipe-darwin remains a separately maintained dependency so its Darwin transport fixes can be tested and released independently.
Bug reports should include the application profile, presentation mode, runtime, Cocoa-Way diagnostics, and the relevant launch log. Please discuss large architectural changes in an issue before opening a pull request.
GPL-3.0 - Copyright (c) 2024-2026 J-x-Z
No open issues yet, or sync has not completed.