Packages

libcluster strategies for mesh VPNs (Tailscale, NetBird, LOLIPOP Zero Trust Link, plain WireGuard) that discover peers by polling the local mesh daemon — no cloud API, no API keys, no static host lists

Current section

Files

Jump to
libcluster_mesh CHANGELOG.md
Raw

CHANGELOG.md

# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.1.1] - 2026-08-03
### Fixed
- The install snippets name the package rather than the git repository they
were written against before it was published
## [0.1.0] - 2026-08-03
Four mesh-daemon strategies and their shared discovery pipeline.
### Added
- `Cluster.Strategy.TailscaleLocal` — peer discovery via
`tailscale status --json`, working with Tailscale and with Headscale-based
control servers, and needing no API key
- `Cluster.Strategy.LolipopZTL` — peer discovery via `ztlctl status`
- `Cluster.Strategy.Netbird` — peer discovery via `netbird status --json`
- `Cluster.Strategy.WireGuard` — peer discovery via `wg show <if> dump` for
plain WireGuard meshes, selecting members by IPv4 CIDR and treating peers
with a recent handshake as online
- `cidr` member selection (`LibclusterMesh.CIDR`) alongside hostname prefixes
- `LibclusterMesh.Runner`, a behaviour for running the mesh CLI, with a
timeout-guarded port-based default that reports a missing binary or a hung
daemon rather than raising, and signals a command outliving its timeout so
that a wedged daemon cannot leave one behind on every poll
- Config validated at startup by `LibclusterMesh.Config.new!/3`
### Notes
- Publishing is triggered by pushing a `v*` tag. The workflow refuses a tag
whose version disagrees with `mix.exs`, or one with no section in this file,
because a version on hex cannot be corrected or reused.
- A config key a strategy does not support raises `ArgumentError` at startup
rather than being ignored. This is the failure that is hardest to diagnose
otherwise: a mistyped or misplaced key means no peer ever matches, so the
cluster never forms and nothing says why. `socket` is part of that — only
`Cluster.Strategy.LolipopZTL` takes one.
- A daemon that answers with the right key and the wrong shape is an error,
not an empty peer list. A strategy that keeps polling and finds nobody looks
exactly like a mesh with nothing on it, so each parser guards its "no peers"
clause on the key being absent rather than letting it catch everything —
`%{}` matches every map in Elixir.
[0.1.1]: https://github.com/kentaro/libcluster_mesh/releases/tag/v0.1.1
[0.1.0]: https://github.com/kentaro/libcluster_mesh/releases/tag/v0.1.0