AI-assisted project. This codebase was created with Claude (Anthropic), directed and reviewed by a human author. The Rust backend compiles and the panel UI has been exercised via its mock backend; the full tray app has not yet been run end-to-end against a live server on the target machine.
A menu-bar tray launcher shell for the local web-server apps in this fleet (srt-router, flock, RFutils, …). It gives any of them a small panel to pick a network interface and port, Start/Stop the server, Open the web UI, and live in the system tray — without each app building its own.
The panel is an original card design that themes itself to each app's own web
UI (palette carried in launcher.toml), built with
Tauri v2 (Rust + a tiny HTML/CSS/JS panel) — a small native
app, not a bundled browser.
![]() srt-router · running |
![]() flock · running |
![]() RFutils · stopped |
The same shell, themed per app from launcher.toml. Rendered from the exact
panel HTML/CSS via scripts/screenshot.sh (headless Chrome).
v0.2.0 — prebuilt for macOS, Windows and Linux. Pick your platform:
macOS — Apple Silicon, Intel
| Build | Download | Size |
|---|---|---|
| Apple Silicon · .dmg disk image | av-launcher-0.2.0-macos-aarch64.dmg |
3.7 MB |
| Intel · .dmg disk image | av-launcher-0.2.0-macos-x86_64.dmg |
4.0 MB |
| Apple Silicon · .pkg installer | av-launcher-0.2.0-macos-aarch64.pkg |
3.7 MB |
| Intel · .pkg installer | av-launcher-0.2.0-macos-x86_64.pkg |
4.0 MB |
Windows — x64
| Build | Download | Size |
|---|---|---|
| x64 · .exe installer | AV.Launcher_0.2.0_x64-setup.exe |
2.5 MB |
| x64 · .msi installer | AV.Launcher_0.2.0_x64_en-US.msi |
3.9 MB |
Linux — x64
| Build | Download | Size |
|---|---|---|
| x64 · .deb package (Debian/Ubuntu) | AV.Launcher_0.2.0_amd64.deb |
5.1 MB |
| x64 · AppImage | AV.Launcher_0.2.0_amd64.AppImage |
83 MB |
All builds, checksums and release notes: github.com/stoatworks-labs/av-launcher/releases.
macOS builds are signed and notarised and open normally. The Windows builds are unsigned, so SmartScreen warns once — see Unsigned builds — Gatekeeper, SmartScreen & Defender Firewall for the one-time click-through.
Each fleet app ships this shell as its own desktop app, with the server embedded so the download is one self-contained thing (no linking, nothing to install). Built and released from each repo:
| app | source | download | server embedding |
|---|---|---|---|
| srt-router | launcher/ |
v0.1.0 | native binary bundled |
| flock | launcher/ |
v0.1.0 | native binary bundled |
| RFutils | launcher/ |
v0.1.0 | Node runtime + app embedded |
This repo remains the canonical template/shell. A shipped .app finds its
baked-in config, theme, and server (a native binary, or an embedded Node runtime
- ESM bundle) via bundled resources — the
{resource}placeholder inlauncher.tomlpoints at them. Seescripts/screenshot.shfor how the README panel images are rendered.
The launcher itself is app-agnostic. It supervises a child process and
knows nothing about any particular server. Each app it can launch is described
by a single src-tauri/launcher.toml, which says how
to start the binary and — the important part — how to inject the chosen
host:port. Three modes cover the whole fleet:
| mode | what it does | fleet example |
|---|---|---|
configfile |
patches a dotted key in the app's own TOML, then passes the rendered copy as the config arg | srt-router (nested web.bind, --config), flock (top-level bind, positional arg) |
env |
sets environment variables | RFutils (RFUTILS_SERVER_PORT / RFUTILS_HOST) |
args |
{host}/{port} placeholders already in [app].args |
WebLinked (--bind / --port, plus --headless) |
Ready-made configs for each app live in launchers/. To point the
launcher at one you only pick a config and swap the icon — no Rust changes.
(A future version can ship one bundled app per fleet member, each with its own
baked-in launcher.toml + icon.)
See docs/adding-an-app.md for the full schema and a new-app checklist.
- GUI Interface dropdown — every bindable IPv4 interface, plus an
"All interfaces (0.0.0.0)" entry. Choosing a specific interface binds to that
IP and shows it in the URL; "All" binds
0.0.0.0and shows your primary LAN IP. - Port — persisted per app.
- Start / Stop — spawns/kills the server child process and supervises it (detects if it exits on its own).
- Launch GUI — opens the resolved URL in your default browser.
- Hide — hides to the tray; Quit — stops the server and exits.
- Interface/port are locked while the server is running.
Settings persist to the OS app-config dir
(~/Library/Application Support/com.allansargeant.av-launcher/ on macOS), along
with the rendered config the launcher hands to the server.
cd ~/Projects/av-launcher
npm install # first time only (fetches @tauri-apps/cli)
npm run tauri dev # launches the panel + traylauncher.toml is read from the working directory (src-tauri/ under
tauri dev), or from $AV_LAUNCHER_CONFIG, or next to the built executable.
The bundled launcher.toml targets srt-router and expects its debug binary at
~/Projects/srt-router/target/debug/srtrouter — build it once with
cargo build in that repo (or edit command/cwd to taste).
To target another fleet app, point at its config in launchers/:
AV_LAUNCHER_CONFIG=launchers/flock.toml npm run tauri dev # flock
AV_LAUNCHER_CONFIG=launchers/rfutils.toml npm run tauri dev # RFutilsnpm run tauri build # produces a .app / .dmg (macOS), etc.By default the .app/.dmg/.exe this produces is not code-signed or
notarized, so macOS and Windows will each warn once — see
Unsigned builds
below, and docs/UNSIGNED.md for the full walkthrough.
Signing it yourself: Tauri signs + notarizes automatically when you set the
Apple credentials as env vars / GitHub Actions secrets — APPLE_CERTIFICATE,
APPLE_CERTIFICATE_PASSWORD, APPLE_SIGNING_IDENTITY, APPLE_ID,
APPLE_PASSWORD, APPLE_TEAM_ID. RFutils' desktop app (which is built on this
shell) documents the full flow in
its launcher/SIGNING.md.
For an ad-hoc local-only signature: codesign --force --deep --sign - "<App>.app".
On Windows, clearing SmartScreen needs an Authenticode code-signing certificate.
cd src-tauri && cargo test # covers host:port injection for all three modes,
# incl. flock (top-level bind) vs srt-router (web.bind)| Doc | Contents |
|---|---|
| docs/USER-GUIDE.md | Using the panel, interface/port choices, and the Gatekeeper trap |
| docs/API.md | The launcher contract and the Tauri command surface |
| docs/DEVELOPING.md | Why changes ripple across three apps, and the behaviours to preserve |
| docs/adding-an-app.md | The config schema, the three injection modes, host resolution |
- Copy the closest config from
launchers/(or the activesrc-tauri/launcher.toml). - Set
[app].name,command,args,default_port,cwd, and the[inject]block. Full guide: docs/adding-an-app.md. - Replace
src-tauri/icons/with the app's icon (npm run tauri icon path/to/icon.pngregenerates all sizes). - Rewrite the string in
src-tauri/Info.plistto name the app and say what it does on the network. Without that key a double-clicked macOS app is denied local network traffic silently — the file explains why no test catches it.
src/ panel UI (index.html, styles.css, main.js)
launchers/ ready-made per-app configs (srt-router, flock, rfutils)
docs/adding-an-app.md schema + injection modes + new-app checklist
src-tauri/
launcher.toml the ACTIVE per-app config (this build → srt-router)
Info.plist macOS local-network declaration (edit the string per app)
src/config.rs config parsing, interface enumeration, host:port injection (+ tests)
src/lib.rs Tauri commands, process supervision, system tray
The release binaries are not code-signed or notarized — that needs paid Apple and Microsoft developer certificates this project doesn't carry. The downloads are fine; the OS just can't identify the publisher, so it warns you the first time.
- macOS — "cannot be opened because the developer cannot be verified".
Right-click the app → Open → Open, or clear the flag:
xattr -dr com.apple.quarantine "/Applications/AV Launcher.app" - Windows — SmartScreen shows "Windows protected your PC" → More info → Run anyway.
- Windows Defender Firewall — first launch pops "Allow AV Launcher to communicate on these networks". Tick Private (and Domain on a managed network) — AV Launcher needs it to bind the wrapped app's web server to the interface you chose in the panel. Deny it and the app will start but be reachable only from the machine it runs on.
- Linux — no signing gate.
Per-artifact steps, self-signing, checksum verification and the Defender Firewall reset procedure: docs/UNSIGNED.md.
This project is built on other people's work — see ATTRIBUTIONS.md.


