A native macOS Wayland compositor and Linux application control plane.
Demo | Install | Quick start | Container mode | Architecture
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:
- Application profile: saved image, command, runtime, presentation, audio, mounts, and environment settings.
- Application instance: one running profile with its own process, logs, transport, and lifecycle state.
- Display: the default compositor window or an isolated display worker assigned to an instance.
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 clipboard, 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:
- Download and install the latest official Apple Container release.
- Open Cocoa-Way and select Container > Apple Container.
- Use Start System, then confirm that the Compatibility card reports a running service.
Apple Container 1.0 is supported through a compatibility fallback, but version 1.1 or newer is recommended for the non-root published Unix sockets used by Transport V2. You can verify the runtime manually with:
container system start
container system statusThis 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-darwinDownload 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 --releasewaypipe-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-wayConnect to an SSH host with the compatibility script:
./run_waypipe.sh ssh user@linux-host firefoxWaypipe 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:
- Install Apple Container separately, then open Container > Apple Container to start and validate it. If it is missing, Cocoa-Way links to Apple's official release page.
- Open Container > Applications.
- Use Images to pull/import an OCI image or build the bundled GUI-ready example.
- Create an application, choose Desktop or Rootless presentation, and leave Display on Auto unless a stable slot is required.
- Run Check, then Launch.
- Inspect instance status, logs, terminal, files, audio, display assignment, and resource diagnostics in the same panel.
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 officialcontainerCLI. 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"orruntime = "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-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.
- A static display reports
0.0 fps - idle; Cocoa-Way renders on demand rather than polling at a fixed frame rate. - Apple Container does not currently provide guest GPU passthrough to Cocoa-Way. Linux applications may render with Mesa/CPU before their SHM buffers are uploaded to Metal on macOS.
- Rootless mode targets native Wayland xdg-shell clients. X11 applications still require an Xwayland environment inside Linux, and nested desktop compositors should use Desktop mode.
- Registry images are not automatically GUI-ready. They need Waypipe and the requested application; clipboard and audio require the Cocoa-Way helper binaries.
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- Continue refining GUI behavior and improving Cocoa-Way's responsiveness and runtime efficiency.
- Continue closing the remaining integration gaps toward a WSLg-like experience for Linux applications on macOS.
cargo check --release --all-targets
cargo test --release --all-targets
cargo build --releaseThe 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
