Wigly Woo is a LocalSend/AirDrop-style file transfer app, fast, nearby, no shared Wi-Fi network required, no accounts, no cloud storage, built with one constraint that shaped everything else: the protocol logic lives exactly once, in a shared Go core, and the macOS and Android apps are thin shells that only draw UI and pull OS-specific radio levers such as Wi-Fi, hotspot, and notifications. Both shells talk to the same core through a single C ABI, a static library on macOS, a JNI-loaded shared library on Android, so a bug fixed or a feature added in the discovery, transfer, or crypto logic is fixed on both platforms at once, by construction rather than by discipline.
Phase 1, working today: same-LAN peer discovery via a UDP multicast beacon, plus TLS file transfer with trust-on-first-use fingerprints, verified end-to-end through the CLI
One core, two shells: every downcall goes shell to core and every event goes core to shell through one callback, all defined in a single C header that is the sole source of truth for the boundary
Link-strategy fallback chain: same LAN, then phone hotspot, then Wi-Fi Direct, tried in order until one connects; the transfer layer above it does not know or care which one won
Remote companion mode: Android notification mirroring with reply and dismiss, clipboard sync, and Mac-to-Android keyboard input, all over an encrypted Supabase Realtime channel that works across completely unrelated Wi-Fi and mobile networks. Deliberately account-free for now: a generated 64-character pairing secret derives both the channel name and an AES-256-GCM key, so Supabase only ever sees ciphertext, a sender ID, and timestamps
Dockerized Android builds: a container carries Go plus the Android SDK, NDK, and Gradle so the core cross-compiles to a shared library per ABI and the APK assembles on the host, without installing any Android tooling locally
The core design constraint of the whole project was not a feature, it was making the Go core genuinely usable from both a native macOS app and a native Android app without either shell needing to understand Go’s memory model or runtime. On macOS, the build script cross-builds a static archive that gets linked straight into the SwiftUI app via a module map. On Android, the same core cross-compiles to a shared library per ABI, loaded through a hand-written JNI shim. Keeping the C header the single source of truth, rather than letting either platform grow its own bespoke bindings, is what makes fix it once actually true.
macOS and iOS builds only run on Apple hardware, full stop, so there was no point trying to containerize that side. The actual pain point, a local Android SDK, NDK, and Gradle setup, got moved into a Docker image instead, pinned to a specific architecture since the NDK’s host toolchain is x86-only. It runs emulated on Apple Silicon, slower on the first build but correct. Net effect: one script produces a working debug APK with nothing installed locally but Docker itself.
The remote-companion path deliberately ships without user accounts, which means the 64-character pairing secret is the entire trust boundary between two devices talking over Supabase’s public Realtime channel. The mitigation was to make that secret long and non-negotiable, never a short phrase, and derive both the channel name and the encryption key from it, so a public channel only ever carries ciphertext and metadata, with a documented, explicit follow-up to replace this with real authentication, private channels, access control, and an offline queue before this path is anything more than a test mode.
Wigly Woo is really a bet that write the protocol once, in a language with a stable C ABI, and let the platforms be dumb pays for itself the moment there is a second platform, which, here, there already is. The interesting problems so far have been at the edges: which layer owns which radio decision, how far you can push an account-free trust model before it needs to grow up, and how to keep an Apple-only build and a fully containerizable build living in the same repo without either one holding the other hostage.