A Cargo workspace of small, annotated Fancy Mumble server
plugins. Each member crate compiles to a self-contained cdylib
that you drop into /etc/mumble/plugins and enable with a single INI
switch — no server recompile, no rebuild, no link edit.
fancy-plugin-example/
├── Cargo.toml # workspace root (lints, shared deps)
├── rust-toolchain.toml # pins the Rust toolchain
└── examples/
├── greeter/ # slash command + button + modal + plugin messages
├── gallery-showcase/ # Container + Section + Thumbnail + MediaGallery
├── info-card/ # Section + Button accessory + Toast follow-up
└── feedback-form/ # multi-field TextInput modal
Each example is intentionally small. When in doubt, add a new example rather than piling features onto an existing one.
| Crate | Slash command | Demonstrates |
|---|---|---|
fancy-greeter |
/greet |
Slash command, button, modal, toast, plugin messages, persistent config |
fancy-gallery-showcase |
/showcase |
TextDisplay, Thumbnail, MediaGallery, Container (visual-only) |
fancy-info-card |
/info |
Section with a Button accessory, #[component] handler, Toast |
fancy-feedback-form |
/feedback |
Multi-field TextInput modal, #[modal] handler |
| Tool | Version |
|---|---|
| Rust | as pinned by rust-toolchain.toml (currently 1.95.0) |
That is the whole list: cargo build fetches the plugin API itself. Nothing
else needs checking out.
The API lives in Starling, the Rust server, and is pulled in over git:
mumble-plugin-api = { git = "https://github.com/Fancy-Mumble/starling.git", branch = "main" }It used to be a path dependency on a sibling checkout of the C++ mumble-server, whose tree still carries a copy. That copy is frozen, so a plugin built against it is built against the past; Starling is where the API is maintained now. Nothing about the ABI changed in the move — the same binary loads in either server — but there is no longer a reason to check out a C++ server to build a Rust plugin.
A plugin must be built against the same API version as the server that will
load it. The host reads the version out of the binary before it does anything
else, and refuses a mismatch with has ABI version N but host expects M rather
than loading it and misbehaving. If you run a server built from a particular
Starling commit, pin the dependency to that commit.
Checking out Starling beside this repo and uncommenting the [patch] block at
the foot of the root Cargo.toml builds every example against that working
tree instead of the branch. That is what you want when changing the API itself.
# Build every example.
cargo build --release
# Or just one.
cargo build --release -p fancy-info-cardEach crate emits the cdylib at target/release/lib<name>.{so,dylib}
(or <name>.dll on Windows).
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspaceThe lint policy is defined once in the root [workspace.lints] block
and inherited by every member via [lints] workspace = true.
The workflow runs the lint/test gate once for the whole workspace,
then fans out to a (example × os) matrix. Every job uploads a
single drop-in archive named
<crate>-<os>-<arch>.{tar.gz|zip} containing:
- the platform-appropriate
cdylib - the matching
plugin.example.ini - the per-crate
README.md
Tagging vX.Y.Z additionally attaches every archive to a GitHub
Release.
Copy whichever example is closest to what you want, rename the crate,
and add it to the workspace members list in the root Cargo.toml.
Update the matrix in .github/workflows/ci.yml to ship a build of
your new plugin.