mycelium defaults --tcp-listen-port and --quic-listen-port to 9651 when not provided. If anything else holds 9651 (a previous test instance, a Docker container from the level-1 procedure, another mycelium running on the host), the daemon comes up far enough to serve the loopback API for a few seconds before tearing itself down on the listen failure. Pick three distinct ephemeral ports (api, tcp, quic) per spawn. Trade-off: inbound peers need the actual port number, which we already log; the user can pin via a future SidecarConfig field.
mycellium-ui
Cross-platform desktop GUI for Mycelium — Threefold's end-to-end encrypted IPv6 overlay network.
The app embeds the official mycelium binary as a Tauri sidecar and pilots it through its HTTP API on a loopback ephemeral port. Root privileges (required to create the TUN interface) are obtained via pkexec.
Status
v1, Linux-only. Implements the full docs/api.yaml surface of mycelium v0.6.1: admin, peers (CRUD), routes (selected/fallback/queried), messages (send/receive/reply/status), topics (default + whitelist + sources + forward), pubkey lookup.
Architecture
┌──────────────────────────────────────────────────────────────┐
│ WebView (Vue 3 + TS + Tailwind + radix-vue + Pinia) │
│ Status / Peers / Routes / Messages / Topics / Settings │
└────────────────┬─────────────────────────────────────────────┘
│ invoke() / Tauri events
┌────────────────┴─────────────────────────────────────────────┐
│ Tauri core (Rust, tokio + reqwest) │
│ • sidecar.rs — supervises mycelium via pkexec │
│ • api/* — typed REST client │
│ • poller.rs — emits peers://, stats://, routes://, messages://incoming │
└────────────────┬─────────────────────────────────────────────┘
│ HTTP loopback :ephemeral
┌────────────────┴─────────────────────────────────────────────┐
│ mycelium daemon (sidecar binary, runs as root via pkexec) │
│ TUN0 ◄─► overlay network │
└──────────────────────────────────────────────────────────────┘
There is no Unix socket / named pipe IPC — the daemon's own HTTP API is the integration point.
Prerequisites (Debian / Ubuntu)
sudo apt install -y \
libwebkit2gtk-4.1-dev libjavascriptcoregtk-4.1-dev \
libsoup-3.0-dev libayatana-appindicator3-dev librsvg2-dev \
build-essential curl wget file libssl-dev libgtk-3-dev libxdo-dev \
pkg-config policykit-1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
Then Node 20+ and pnpm 10+.
Setup
# 1. Install JS deps
pnpm install
# 2. Fetch the mycelium sidecar binary for your target triple
bash scripts/fetch-mycelium.sh # uses MYCELIUM_VERSION (default v0.6.1)
# or: MYCELIUM_VERSION=v0.6.1 bash scripts/fetch-mycelium.sh
# 3. Run in dev
pnpm tauri dev
The first start triggers a pkexec dialog asking you to authenticate; the polkit policy installed by the .deb caches the auth for the user session.
Build
pnpm tauri build # → src-tauri/target/release/bundle/{deb,appimage}/
The .deb declares Depends: policykit-1 and ships the polkit policy under /usr/share/polkit-1/actions/tech.threefold.mycellium-ui.policy. The AppImage relies on pkexec being present on the host — on systems without polkit, fall back to running with sudo after disabling the sidecar's pkexec wrapper.
Layout
src/ # Vue 3 frontend
views/ # one file per nav item
components/ # shadcn-style UI primitives + dialogs
stores/ # Pinia: node, peers, routes, messages, topics, config
lib/ # api wrapper, events, base64 + format helpers
src-tauri/
src/
sidecar.rs # spawn + supervise mycelium
elevation.rs # pkexec command builder
poller.rs # 3 background loops (peers, routes, inbox long-poll)
api/ # REST client modules (admin, peers, routes,
# messages, topics, pubkey)
commands.rs # #[tauri::command] handlers, 1:1 with REST
error.rs # AppError + Serialize-as-string for invoke()
binaries/ # gitignored; populated by scripts/fetch-mycelium.sh
packaging/polkit/ # XML policy bundled into the .deb
scripts/fetch-mycelium.sh
.github/workflows/ci.yml # pnpm typecheck + cargo fmt/clippy/test
Verification matrix
| Test | How |
|---|---|
| Sidecar starts under pkexec | pnpm tauri dev, daemon visible in ps, splash disappears in <10 s |
| Peers connect | Add tcp://188.40.132.242:9651 from the Peers page; state turns to alive within ~10 s |
| Routes propagate | Routes/Selected becomes non-empty after ~30 s |
| Live event stream | Sidebar status dot tracks ready/idle, peers table updates without manual refresh |
| Bidirectional messages | Two instances on different VMs, exchange via Compose → Inbox |
| Identity regen | Settings → Regenerate; restart daemon; new IP appears on Status |
.deb install |
Fresh Ubuntu LTS / Debian 12; daemon spawns under polkit on first start |
Known limitations (v1)
- Linux only. Windows is reachable (sidecar via
runas/ Wintun driver) but not implemented. - Auto-start at login isn't wired — the desktop entry installed by the
.debis the manual launcher. - The TOML config editor in Settings only exposes
peers,tunName,noTun. Other keys (metricsApiAddress, etc.) are passed-through if you edit the file directly at~/.local/share/tech.threefold.mycellium-ui/mycelium.tomland restart the daemon. message_statusis forwarded as opaque JSON; the upstream schema isn't pinned in the spec, so we don't strongly type it.