MeshCore Network Operations Center
Anchor. Bridge. Monitor.
Development Blog | Report Issues | Contribute | Sister Project: MeshForge
MeshAnchor is a MeshCore-primary Network Operations Center — the sister project to MeshForge.
Where MeshForge treats Meshtastic as the "home" radio, MeshAnchor flips the architecture: MeshCore is primary, Meshtastic and RNS are optional gateways. Same TUI framework. Same gateway bridge pattern. Same RF tools. Different home radio.
ALPHA SOFTWARE — Field-deployed and accumulating mileage. More testers wanted.
MeshAnchor has 5,168 tests passing against mocks. The canonical NOC (
meshanchor-server, Pi 4B + RAK Heltec V3 in Serial Companion mode) has been running as a continuous deployment since 2026-05-02 and is currently the source of truth for field validation. As of 2026-05-13 it carries: bidirectional MeshCore channel messaging, MeshCore↔RNS LXMF broadcast bridge (same-host + cross-federation fan-out validated 2026-05-09), LXMF subscriber reliability tier engine with Prometheus metrics, a fleet observability stack (collector + watchdog + 24h clean-soak passed 2026-05-11), MeshCore map population frommap.meshcore.devplus operator pin placement, and ameshcore-cliTUI passthrough with daemon hand-off. Coverage maps with live GPS position data and full 3-way (MeshCore ↔ Meshtastic ↔ RNS) concurrent traffic remain unvalidated. If you have a MeshCore companion radio (RAK4631, Heltec V3, T-Deck, T-Echo), your independent field testing on different hardware is the single most valuable contribution right now. See Contributing.
Plug in a MeshCore companion radio, run the installer, and you get:
- MeshCore integration — direct companion radio management via meshcore_py, pre-flight device validation, persistent udev naming, in-TUI radio config (LoRa params, channels, TX power) with region-aware validation
- MeshCore CLI passthrough — TUI surface that drops the operator into meshcore-cli (common verbs, send DM/channel, remote-admin
cmdbridge to docs.meshcore.io/cli_commands/, interactive REPL) with the daemon's radio ownership handed off cleanly so the bridge resumes when the CLI exits - Gateway bridge — bidirectional MeshCore to Meshtastic/RNS message routing via CanonicalMessage
- RF engineering tools — link budget, Fresnel zone, FSPL, coverage maps, space weather (NOAA)
- TUI interface — 85 handler files, MeshCore-primary menu with Optional Gateways submenu, raspi-config style (whiptail/dialog), SSH-friendly
- Live NOC maps — Leaflet.js browser view with WebSocket updates
- meshforge-maps integration — discovery, browser launch, configurable endpoint, bidirectional data fusion, and double-confirmed lifecycle control for the sister-project mapping service on
:8808 - MQTT monitoring — nodeless mesh observation, protobuf decode, traffic inspector
- AI diagnostics — offline knowledge base + optional Claude PRO mode
- Prometheus/Grafana — 50+ metrics, 5 pre-built dashboards
Optional add-ons (install from TUI when you need them):
- NomadNet — terminal-based LXMF client (Reticulum users)
MeshCore brings capabilities that Meshtastic can't — 64-hop routing (vs 7), flood-free mesh topology, and a protocol designed from the ground up for resilient long-range communication. But MeshCore lacks the operational tooling that network operators need: maps, monitoring, diagnostics, gateway bridging.
MeshAnchor fills that gap.
One interface to manage your MeshCore network. One gateway to bridge messages to Meshtastic and Reticulum nodes. One toolkit for RF planning, diagnostics, and field operations. All running on a Raspberry Pi that you can SSH into from anywhere.
This is the first open-source NOC that treats MeshCore as the primary radio, with Meshtastic and RNS as optional gateways rather than the other way around. No cloud dependencies. No subscriptions. Just a box that makes mesh networks work together.
sudo python3 src/launcher_tui/main.pyBuilt for: MeshCore developers, RF engineers, network operators, amateur radio operators, and emergency comms planners who want professional-grade network visibility.
Using Meshtastic as your primary radio? Use MeshForge instead.
# One-liner (Pi / Debian / Ubuntu)
curl -sSL https://raw.githubusercontent.com/Nursedude/meshanchor/main/install.sh | sudo bash
# Or manually
git clone https://github.com/Nursedude/meshanchor.git /opt/meshanchor
cd /opt/meshanchor
sudo bash scripts/install_noc.sh # Full NOC stack installThe NOC installer auto-detects your radio hardware (SPI HAT or USB), optionally installs meshtasticd + Reticulum, and sets up systemd services. It will prompt you to select your HAT if SPI is detected.
One-liner options (environment variables):
# Install with automatic system upgrade
curl -sSL https://raw.githubusercontent.com/Nursedude/meshanchor/main/install.sh | sudo UPGRADE_SYSTEM=yes bash
# Install without upgrade prompt
curl -sSL https://raw.githubusercontent.com/Nursedude/meshanchor/main/install.sh | sudo SKIP_UPGRADE=yes bash
# Use system pip instead of venv
curl -sSL https://raw.githubusercontent.com/Nursedude/meshanchor/main/install.sh | sudo BREAK_SYSTEM_PACKAGES=yes bashNOC installer options (scripts/install_noc.sh):
sudo bash scripts/install_noc.sh --skip-meshtasticd # Don't install meshtasticd
sudo bash scripts/install_noc.sh --skip-rns # Don't install Reticulum
sudo bash scripts/install_noc.sh --client-only # MeshAnchor only (no daemons)
sudo bash scripts/install_noc.sh --force-native # Force SPI mode (native meshtasticd)
sudo bash scripts/install_noc.sh --force-python # Force USB mode (Python CLI)MeshAnchor supports 5 deployment profiles. Install only the dependencies you need. Order below matches the in-TUI picker (MeshCore-first per the v0.1.0-alpha charter).
| Profile | Primary Use | MeshCore | Meshtastic | RNS | MQTT | Maps | Tactical |
|---|---|---|---|---|---|---|---|
meshcore (default) |
MeshCore companion radio | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
radio_maps |
MeshCore + coverage mapping | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ |
monitor |
MQTT packet analysis (no radio) | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ |
gateway |
MeshCore + Meshtastic/RNS bridge | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
full |
Everything | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
# Select profile at launch
python3 src/launcher.py --profile gateway
# Auto-detect (default): scans running services and installed packages
python3 src/launcher.py
# Profile is saved to ~/.config/meshanchor/deployment.jsonFor the full feature-flag matrix, per-profile install commands, decision tree, and
the rationale behind each default, see
.claude/foundations/deployment_profiles.md.
sudo python3 src/launcher_tui/main.pypython3 src/standalone.py # Interactive menu
python3 src/standalone.py rf # RF calculator
python3 src/standalone.py sim # Network simulator
python3 src/standalone.py --check # Check dependenciesThe TUI uses a raspi-config style interface (whiptail/dialog) designed for SSH and headless operation. Navigation is keyboard-driven with max 10 items per menu level:
Main Menu (MeshAnchor NOC)
├── 1. Dashboard Service status, health, alerts, data path check
├── 2. MeshCore Primary radio + Optional Gateways
│ ├── MeshCore submenu Status, detect, config, radio (LoRa/TX/channels),
│ │ nodes, stats, chat, daemon control
│ ├── MeshCore CLI meshcore-cli passthrough — common verbs, DM/channel,
│ │ remote-admin cmd, interactive REPL (auto daemon handoff)
│ └── Optional Gateways → Meshtastic, RNS, AREDN, MQTT, Gateway Bridge
├── 3. RF & SDR Link budget, site planner, frequency slots, SDR
├── 4. Maps & Viz Live NOC map, coverage, topology, traffic inspector,
│ meshforge-maps :8808 integration
├── 5. Configuration Radio, channels, RNS config, services, backup
├── 6. System Hardware detect, logs, network tools, shell, reboot
├── q. Quick Actions Common shortcuts (2-tap access)
├── e. Emergency Mode Field ops, weather/EAS alerts, SOS beacon
├── t. Tactical Ops SITREP, zones, QR, ATAK (visible under FULL profile)
├── a. About Version, web client, help
└── x. Exit
# Quick update (code + service files)
cd /opt/meshanchor && sudo bash scripts/update.sh
# Quick update to specific branch
sudo bash scripts/update.sh --branch main
# Clean reinstall (recommended for major version bumps)
sudo bash /opt/meshanchor/scripts/reinstall.sh
# Clean reinstall without confirmation prompt
sudo bash scripts/reinstall.sh --no-confirm
# Complete removal
sudo bash scripts/reinstall.sh --remove-only
# Manual git pull (developers)
cd /opt/meshanchor && sudo git pull origin mainWhat is preserved during reinstall (never touched):
| Preserved | Path | Why |
|---|---|---|
| meshtasticd | apt package + /etc/meshtasticd/config.yaml |
Separate package, your radio config |
| Radio hardware configs | /etc/meshtasticd/config.d/ |
Backed up and restored |
| Reticulum identity | ~/.reticulum/ |
Your RNS address + keys |
| MeshAnchor user settings | ~/.config/meshanchor/ |
Backed up and restored |
| MQTT broker | mosquitto service + config | Separate service |
| System packages | pip, apt installs | Not managed by MeshAnchor |
No need to re-image your Pi. Your radio stays configured.
# Automated check
sudo python3 src/launcher.py --verify-install
# Manual checks
python3 -c "from src.__version__ import __version__; print(__version__)"
python3 -m pytest tests/ -v --tb=short
sudo python3 src/launcher_tui/main.py| Issue | Solution |
|---|---|
| Python import errors | sudo bash scripts/reinstall.sh (clean reinstall) |
Local changes would be overwritten |
git stash before pull, or use clean reinstall |
| Service won't start | journalctl -u meshanchor -n 50 |
meshcore module not found |
pip install meshcore (or --break-system-packages on Bookworm+) |
meshcore-cli not found in TUI CLI menu |
/opt/meshanchor/venv/bin/pip install meshcore-cli (or use TUI's MeshCore CLI → Install / Locate) |
| USB device path changes on reboot | Install udev rules: sudo cp scripts/99-meshcore.rules /etc/udev/rules.d/ && sudo udevadm control --reload-rules |
| Permission denied on serial port | Add user to dialout group: sudo usermod -aG dialout $USER then log out/in |
meshtastic module not found |
pip install meshtastic --break-system-packages --ignore-installed |
| Config file conflicts | Restore from ~/meshanchor-backup-* or regenerate via TUI |
Stale .pyc files |
Clean reinstall handles this automatically |
| Status | Meaning |
|---|---|
| Mock-Tested | Passes unit tests against mocks. No field validation with real hardware. |
| Inherited | Carried from MeshForge where it was field-tested. Untested in MeshAnchor context. |
| Code-Ready | Implemented and compiles. Needs real hardware/services to validate. |
| Feature | Tests | Notes |
|---|---|---|
| Companion radio detection | -- | Serial USB scan + udev persistent naming (/dev/ttyMeshCore) |
| Pre-flight device validation | -- | Serial probe before connection, permission + existence checks |
| meshcore_py connection | 58 | Async event loop, reconnect, message handling. Field-validated with RAK Heltec V3 in Serial Companion mode (2026-05-02). |
| CanonicalMessage bridging | 46 | Protocol-agnostic message format, N-protocol routing |
| 3-way routing classifier | 32 | MeshCore + Meshtastic + RNS tri-bridge tests (mock-only) |
| MeshCore TUI menu | -- | Status, detect, config, nodes, stats, chat, daemon control |
Chat HTTP API (/chat/* on :8081) |
19 | Daemon-side ring buffer + send/receive endpoints. Bidirectional Public + private-channel messaging field-validated 2026-05-02. |
| Daemon control in TUI | 5 | start / stop / restart / journal / live tail through service_check SSOT |
| Feature | Tests | Notes |
|---|---|---|
| Meshtastic MQTT bridge | 250 | Zero-interference gateway (v0.5.4 architecture) |
| RNS/LXMF gateway | 97 | rnsd shared instance client |
| LXMF broadcast bridge plug-in | -- | Field-validated 2026-05-09: same-host + cross-federation subscribe/fan-out. Fleet floor: RNS ≥ 1.1.9. |
| LXMF subscriber reliability | 187 | Field-live 2026-05-12: state machine, tier engine, auto-transitions, tier-aware backoff, Stale Subscribers TUI prune, Prometheus metrics on /metrics, structured JSON state-transition logs, /health digest, Stack Health probe |
| Message queue (SQLite) | 104 | Persistent queue, retry policy, circuit breaker |
| Reconnect engine | 45 | Exponential backoff (1s -> 30s max), jitter, slow start |
| MQTT robustness | 68 | Reconnection, message loss recovery, broker failover |
| Feature | Tests | Notes |
|---|---|---|
| Fleet collector + watchdog | -- | Local cron-style systemd units writing heartbeat / blackout state. 24h clean-soak passed 2026-05-11 (NRestarts=0, history matches expected events). |
| Blackout kinds | -- | no_data, http_dead, frozen, daemon_dead — 4-kind silence detection with 2-cycle hysteresis. End-to-end smoke: 43s detect, 13s recover. |
/fleet/slo + /fleet/federation + /fleet/activity |
-- | Daemon HTTP endpoints; required/optional service split (1+ required up = degraded, all required down = error, optional doesn't gate). |
Cross-fleet web view (/fleet) |
-- | web/fleet.html BIARC demo surface with sparklines, decoupled polling, active/stale federation styling. |
| Prometheus exposition | -- | /metrics + /healthz on daemon and map processes. Map's /fleet/* polls auto-instrumented as meshanchor_map_http_requests_total. |
| Feature | Tests | Notes |
|---|---|---|
| Link budget calculator | 107 | FSPL, Fresnel zone, earth bulge, signal classification |
| Coverage maps (Folium) | -- | Static HTML, SNR-based link coloring, offline tiles |
| Live NOC map (Leaflet) | -- | Force-clustering across all networks (>1k features), gzipped JSON+HTML (28MB→3.4MB on meshanchor-server), reticulum→rns alias |
map.meshcore.dev fetcher |
-- | Direct fetch of ~42k positioned MeshCore nodes (MessagePack) into the live NOC map |
| Operator pin placement (TUI) | -- | "MeshCore Map Pins" handler for local pubkeys; daemon PUT /radio/coords writes radio identity |
| Space weather (NOAA) | -- | Solar flux, K-index, band conditions |
| Site planner | -- | Range estimation with terrain |
| Cython fast path | -- | Optional 5-10x RF calculation speedup |
| Feature | Tests | Notes |
|---|---|---|
| Handler registry | 70 | 85 handler files, Protocol + BaseHandler pattern |
| whiptail/dialog backend | -- | raspi-config style, SSH-friendly |
| Deployment profile selector | 76 | 5 profiles, MeshCore-first ordering, auto-detect, full matrix pinned |
| Startup health checks | 38 | Profile-aware classification (required / optional / not_applicable) |
| Fleet monitor panel | -- | TUI handler reads daemon /fleet/slo with required-only semantics ("ready · 2/2 required") |
| Identity & Position submenu | -- | set_radio_name / set_radio_coords / send advert; pushes to daemon HTTP /radio/{name,coords,advert} |
meshcore-cli passthrough |
-- | TUI surface drops operator into meshcore-cli with daemon hand-off; bridge resumes on exit |
| Feature | Tests | Notes |
|---|---|---|
| MQTT subscriber | 68 | Nodeless node tracking, protobuf decode |
| Traffic inspector | -- | Packet capture, protocol tree, display filters |
| RNS packet sniffer | -- | Wireshark-grade capture, announce tracking |
| Prometheus exporter | -- | 50+ metric families, Grafana-compatible |
| Node tracker | 68 | Unified node inventory, 15m offline threshold, 24h stale purge |
| Feature | Limitation | Workaround / Status |
|---|---|---|
| Fleet Monitor (multi-host) | Handler-thread pile-up on Pi-class hardware under sustained dashboard polling. Single-tab steady-state works; multiple dashboard tabs / sustained over-polling can briefly trigger 429 (server_busy) responses. | In-flight semaphore caps concurrent /fleet/* handlers (#128) + dashboard auto-retries on 429 honoring Retry-After. Daily meshanchor-map-restart.timer is in place as a workaround belt-and-suspenders until the supporting fixes (#126, #127) land. Single-box deployment is the most reliable mode today. Full failure-mode log in #131. |
non_self_peers filter |
Filters by peer name only, so a fleet.json self entry under a non-matching name slips through and the rollup HTTP-polls its own listener every cycle. |
#130 tracks the fix; until then, don't include a self entry in ~/.config/meshanchor/fleet.json (or name it exactly your hostname). |
| Cascade detector | Not yet ported from MeshForge — pre-failure shapes (rnsd RPC wedge, stale tracer fires) won't alarm before the cross-fleet rollup shows their downstream effects. | #129 tracks the port. |
MeshAnchor has 5,168 automated tests across 165 test files. However, automated tests validate code paths with mocks — they do not replace field testing. Every feature listed above needs validation with real radios and real mesh traffic before it can be considered reliable.
What has been validated with real hardware on meshanchor-server (Pi 4B + RAK Heltec V3, continuous deployment since 2026-05-02):
- MeshCore companion radio connection (Serial Companion firmware via USB)
- Bidirectional channel messaging on Public (slot 0) and private channels (
meshanchoron slot 1/2) — RX from a paired BLE Companion + iOS, TX from the daemon's chat API through the TUI, both directions confirmed - MeshCore↔RNS LXMF broadcast bridge (2026-05-09) — same-host subscribe + fan-out,
then cross-host fan-out across the MeshForge Hawaii federation; "Got to test Claude"
message round-tripped from a federation peer to
meshanchor-serverand broadcast to subscribers - LXMF subscriber reliability stack (2026-05-12) — state machine, tier engine,
Prometheus metrics on daemon
/metrics(4 metric families),/healthdigest, Stack Health probe; live sample shows 3 healthy/external subscribers - Fleet observability (2026-05-11) — collector + watchdog ran a 24-hour clean
soak with
NRestarts=0on both units, exactly the expected closed blackout history, and all required services available - MeshCore map population (2026-05-07) — first appearance of MeshCore data on the
meshanchor-server live map (
map.meshcore.devfetcher + operator pin placement) meshcore-cliTUI passthrough (2026-05-07) — daemon hand-off + restart wrapper validated against meshcore-cli v1.5.7 on meshanchor-server- Daemon stability under restart cycles (no watchdog churn, NRestarts=0 over the most recent 24h window)
- Chat HTTP API + TUI Chat menu (since-id polling, channel + DM send paths)
- TUI daemon control (status / start / stop / restart / journal / live tail)
- RNS announce reception (gateway sees external MeshForge gateway announces)
What has not yet been tested with real hardware in MeshAnchor:
- Coverage maps with real GPS position data
- 3-way routing (MeshCore ↔ Meshtastic ↔ RNS) with concurrent traffic on a single host
- Independent confirmation on hardware other than
meshanchor-server(this is the gap external testers can close — see Contributing)
Reliability ratio — single-box vs fleet monitor:
The fleet rollup / federation monitoring path has the least field time in
the project and the most documented recurrence patterns (#34, #128, #130, #131).
Single-box install (one host, one TUI, the local map at :5000) is
significantly more reliable than the multi-host fleet monitor view. Operators
who need steady-state observability should start with single-box, confirm the
core flows, then layer in the cross-host dashboard once they've understood the
restart cadence + known limitations above.
What was field-tested in MeshForge (inherited, likely works): TUI, meshtasticd config, RF tools, RNS/rnsd integration, NomadNet, service management, standalone tools.
graph TB
subgraph User Interfaces
TUI[Terminal UI<br>SSH-friendly, raspi-config style]
BROWSER[Browser Maps<br>Live Leaflet.js NOC view]
CLI[Standalone CLI<br>Zero-dependency RF tools]
end
subgraph MeshAnchor Core
MESHCORE[MeshCore Handler<br>meshcore_py companion radio]
CANONICAL[CanonicalMessage<br>Protocol-agnostic bridge]
GATEWAY[Gateway Bridge<br>MQTT transport + SQLite queue]
MONITOR[MQTT Subscriber<br>Nodeless node tracking]
RF[RF Engine<br>Link budget, Fresnel, path loss]
DIAG[Diagnostics<br>Rule engine + knowledge base]
AI[AI Assistant<br>Standalone + PRO modes]
end
subgraph Optional Gateways
MESHTASTICD[meshtasticd<br>LoRa radio daemon]
RNSD[rnsd<br>Reticulum transport]
MQTT[MQTT Broker<br>Node telemetry]
end
subgraph Hardware
MESHCORE_RADIO[MeshCore Radio<br>RAK4631, Heltec V3, T-Deck]
SPI[SPI HAT<br>Meshtoad, MeshAdv]
USB[USB Radio<br>Heltec, T-Beam, RAK]
end
TUI --> MESHCORE
TUI --> BROWSER
CLI --> RF
MESHCORE --> MESHCORE_RADIO
MESHCORE --> CANONICAL
CANONICAL --> GATEWAY
GATEWAY --> MQTT
GATEWAY --> RNSD
MONITOR --> MQTT
MQTT --> MESHTASTICD
RF --> TUI
DIAG --> AI
MESHTASTICD --> SPI
MESHTASTICD --> USB
style MESHCORE fill:#1a5c1a,color:#fff
style CANONICAL fill:#1a3a5c,color:#fff
style TUI fill:#2d5016,color:#fff
style BROWSER fill:#2d5016,color:#fff
style CLI fill:#2d5016,color:#fff
style GATEWAY fill:#1a3a5c,color:#fff
style AI fill:#5c1a3a,color:#fff
style MESHCORE_RADIO fill:#5c4a1a,color:#fff
sequenceDiagram
participant MC as MeshCore Radio
participant MH as MeshCore Handler
participant CM as CanonicalMessage
participant MR as Message Router
participant MT as Meshtastic (MQTT)
participant RN as RNS (LXMF)
MC->>MH: meshcore_py event
MH->>CM: Convert to CanonicalMessage
CM->>MR: Classify + route
MR->>MT: meshtastic CLI (transient)
MR->>RN: LXMF via rnsd
RN->>MR: RNS reply
MR->>CM: Convert to CanonicalMessage
CM->>MH: Route to MeshCore
MH->>MC: meshcore_py send
| MeshAnchor | MeshForge | |
|---|---|---|
| Primary radio | MeshCore | Meshtastic |
| Default profile | meshcore |
radio_maps |
| Bridge direction | MeshCore -> Meshtastic/RNS | Meshtastic -> MeshCore/RNS |
| meshtasticd required? | No (optional gateway) | Yes (primary) |
| meshcore package | Primary dependency | Optional |
| Python version | 3.10+ | 3.9+ |
| Field-tested | Continuous deployment on meshanchor-server since 2026-05-02; 24h clean fleet soak 2026-05-11; LXMF bridge cross-federation 2026-05-09 |
Yes (beta) |
- TUI is a dispatcher — selects what to run, not how to run it
- Services run independently — MeshAnchor connects, never embeds
- Standard Linux tools —
systemctl,journalctl,meshtastic,rnstatus - Config overlays — writes to
config.d/, never overwrites defaults - Graceful degradation — missing dependencies disable features, don't crash
- Defense-in-depth — handler registry dispatches with exception isolation per handler
MeshAnchor includes two tiers of AI-powered network diagnostics:
- 20+ topic knowledge base covering mesh networking fundamentals
- Rule-based diagnostic engine with pattern matching
- Structured troubleshooting guides for common issues
- Confidence scoring on diagnoses
- Works completely offline — ideal for field deployment
- Natural language troubleshooting ("Why is my MeshCore node offline?")
- Log file analysis with suggested actions
- Context-aware responses (knows your network topology)
- Predictive issue detection
- Falls back to Standalone when API unavailable
Minimum: Raspberry Pi 3B+ + MeshCore companion radio Recommended: Raspberry Pi 4/5 + MeshCore radio (~$35-90)
| Component | Options |
|---|---|
| Computer | Raspberry Pi 4/5 (recommended), Pi 3B+, Pi Zero 2W, x86_64 Linux |
| OS | Raspberry Pi OS Bookworm 64-bit, Debian 12+, Ubuntu 22.04+ |
| MeshCore Radio | See companion radios table below |
| Optional | Meshtastic radio (gateway), RTL-SDR (spectrum), GPS module |
MeshCore companion radios connect via USB serial and are managed by the meshcore_py library. MeshAnchor auto-detects connected devices.
| Device | Connection | Notes |
|---|---|---|
| RAK4631 (nRF52840) | USB Serial | Ultra-low power, GPS, UF2 flashing |
| Heltec V3 (ESP32-S3) | USB Serial / WiFi TCP | Common, affordable, gateway capable |
| Heltec V4 (ESP32-S3) | USB Serial | 28dBm TX power |
| T-Deck | USB Serial | Built-in keyboard + display |
| T-Echo | USB Serial | E-ink display, GPS |
| Station G2 | USB Serial | Gateway capable, PoE option |
For the gateway or full deployment profile, you also need a Meshtastic radio.
MeshAnchor supports all radios that MeshForge supports — see the
MeshForge hardware tables for
SPI HATs (MeshAdv, Waveshare, Ebyte, RAK) and USB radios (Heltec, T-Beam, MeshToad).
Pre-built gateway profiles are available in src/gateway/profiles/:
| Profile | Radio | Use Case |
|---|---|---|
heltec_v3_gateway.yaml |
Heltec V3 | Standard USB gateway |
heltec_v4_gateway.yaml |
Heltec V4 | High-power USB gateway |
rak4631_gateway.yaml |
RAK4631 | Low-power gateway |
station_g2_gateway.yaml |
Station G2 | Infrastructure gateway |
rnode_gateway.yaml |
RNode | Dedicated RNS radio |
MeshAnchor shares 2,848 commits of history with MeshForge. Here's how we got here:
The project started as "Meshtasticd Interactive UI" — a simple interactive installer and manager for meshtasticd on Raspberry Pi. Initial commit: 2025-12-27.
The installer rapidly evolved into a full Network Operations Center:
| Version | Date | Milestone |
|---|---|---|
| v0.4.0-beta | 2026-01-10 | Initial public release — GTK4 desktop + Meshtastic-RNS gateway |
| v0.4.1-beta | 2026-01-12 | TUI interface added (raspi-config style) |
| v0.4.2-beta | 2026-01-13 | RF tools — FSPL, Fresnel zone, link budget |
| v0.4.6-beta | 2026-01-17 | AI diagnostics, coverage maps, CI/CD |
| v0.4.7-beta | 2026-01-17 | Regression prevention system, predictive analytics |
| v0.5.0-beta | 2026-02-01 | Beta milestone — TUI stable across 6+ fresh installs |
| v0.5.1-beta | 2026-02-06 | Telemetry pipeline, RNS sniffer, Path.home() security fixes |
| v0.5.3-beta | 2026-02-08 | 350+ unit tests for core gateway bridge |
| v0.5.4-beta | 2026-02-11 | MQTT bridge architecture (zero interference with web client) |
| v0.5.5-beta | 2026-03-09 | MeshChat removed, mesh alert engine, focus narrowed |
During this period, MeshCore support was explored on an alpha branch with a 796-line
meshcore_handler.py, a CanonicalMessage protocol format for N-protocol bridging,
and 1,839 tests for tri-bridge routing.
MeshAnchor was extracted from MeshForge main at commit 7e4fa02. The extraction:
- Rebranded 580+ references from MeshForge to MeshAnchor
- Renamed all service/config files (
meshforge.service->meshanchor.service) - Created
RadioModeabstraction (src/core/radio_mode.py) - Inverted the architecture: MeshCore enabled by default, Meshtastic optional
- Inverted deployment profiles:
meshcoreis the default (wasradio_maps) - Removed 16 Meshtastic-specific source files and 8 Meshtastic-specific test files
- Gated remaining Meshtastic imports as optional gateway support
- Updated CI for Python 3.10+, meshcore package
- Version reset to 0.1.0-alpha
Two sister projects with the same DNA, different home radios:
MeshForge (v0.6.2-beta) MeshAnchor (v0.1.0-alpha)
Primary: Meshtastic Primary: MeshCore
Gateway to: MeshCore/RNS Gateway to: Meshtastic/RNS
Field-tested: Yes Field-tested: One box — needs YOU
MeshAnchor is part of a 5-repository ecosystem:
| Repository | Purpose | Version |
|---|---|---|
| meshanchor (this repo) | MeshCore-primary NOC — gateway, TUI, RF tools, diagnostics | 0.1.0-alpha |
| meshforge | Meshtastic-primary NOC — same architecture, different home radio | 0.6.2-beta |
| meshanchor-maps | Visualization plugin — Leaflet/D3.js topology, health scoring | 0.7.0 |
| meshing_around_meshanchor | Bot alerting — 12 alert types, complements meshing-around bot | 0.5.0 |
| RNS-Management-Tool | Cross-platform RNS ecosystem installer | 0.3.2 |
Both MeshForge and MeshAnchor share these core components. Changes to the shared contract must stay compatible across both projects:
- CanonicalMessage (
src/gateway/canonical_message.py) — the protocol-agnostic message format that bridges all three radio protocols - TUI handler architecture — Protocol + BaseHandler + HandlerRegistry dispatch
- RF tools (
src/utils/rf.py) — link budget, Fresnel, FSPL, coverage maps - Gateway bridge pattern — adapter -> CanonicalMessage -> message router
- RNS substrate (
src/utils/rns_init.py+ therequirements/rns.txtfork pin) — RNS and LXMF are installed from MeshForge-owned hard forks (Nursedude/reticulum, Nursedude/lxmf), pinned by tag + SHA (MF-FORK-PINlines). MeshForge is the lead repo for this substrate; itsscripts/parity_check.pykeeps the shared files byte-identical across both projects
- MeshForge — if Meshtastic is your primary radio
- MeshAnchor — if MeshCore is your primary radio
- Both — if you operate both radio types on separate Pis
src/
├── launcher_tui/ # PRIMARY INTERFACE (TUI)
│ ├── main.py # NOC launcher + handler registration
│ ├── handler_protocol.py # CommandHandler Protocol + TUIContext + BaseHandler
│ ├── handler_registry.py # register/lookup/dispatch
│ ├── backend.py # whiptail/dialog abstraction
│ ├── startup_checks.py # Environment checks + conflict resolution
│ ├── status_bar.py # Service status bar
│ └── handlers/ # 85 registered command handlers
├── daemon.py # MeshCore radio daemon (chat API + /radio endpoints on :8081)
├── gateway/ # Multi-protocol bridge engine
│ ├── meshcore_handler.py # MeshCore companion radio (meshcore_py) — PRIMARY
│ ├── rns_bridge.py # RNS/LXMF gateway (optional)
│ ├── mqtt_bridge_handler.py # Meshtastic MQTT bridge (optional)
│ ├── canonical_message.py # Protocol-agnostic message format
│ ├── message_routing.py # 3-way routing classifier
│ ├── message_queue.py # SQLite persistent queue
│ ├── circuit_breaker.py # Fault tolerance
│ └── profiles/ # 5 gateway radio profiles (Heltec, RAK, RNode, Station G2)
├── monitoring/ # Network monitoring
│ ├── mqtt_subscriber.py # Nodeless MQTT node tracking
│ ├── traffic_inspector.py # Packet capture + protocol analysis
│ ├── rns_sniffer.py # RNS packet capture + announce tracking
│ └── path_visualizer.py # Multi-hop path tracing
├── commands/ # Command modules (propagation, hamclock, service mgmt)
├── utils/ # Core utilities
│ ├── rf.py # RF calculations (haversine, FSPL, Fresnel, link budget)
│ ├── coverage_map.py # Folium map generator + offline tile cache
│ ├── service_check.py # Service management (single source of truth)
│ ├── diagnostic_engine.py # Rule-based diagnostics
│ ├── claude_assistant.py # AI assistant (Standalone + PRO)
│ ├── prometheus_exporter.py # Metrics pipeline
│ ├── active_health_probe.py # Health probes (RNS wedge, delivery stall, drift checks)
│ ├── rns_init.py # Guarded RNS chokepoint (shared with MeshForge, fork-pinned)
│ └── paths.py # Sudo-safe path resolution
├── tactical/ # Tactical operations, QR transport, compliance
├── core/ # RadioMode, orchestrator, plugin system
├── standalone.py # Zero-dependency RF tools
└── __version__.py # Version: 0.1.0-alpha
scripts/
├── install_noc.sh # Full NOC stack installer
├── update.sh # In-place code update
├── reinstall.sh # Clean reinstall (preserves config)
├── lint.py # Security linter (17 rules: MF001-MF014, MF016, MA017, MF019-MF020)
├── meshanchor-launcher.sh # Shell wrapper
└── verify_post_install.sh # Post-install health check
dashboards/ # 5 Grafana monitoring dashboards
├── meshanchor-overview.json # Health, services, queues
├── meshanchor-nodes.json # Per-node RF metrics
├── meshanchor-gateway.json # Gateway bridge status
├── meshanchor-infinity.json # Long-term trends
└── meshanchor-influxdb.json # InfluxDB integration
templates/ # Config templates (meshtasticd, reticulum, MQTT, systemd)
config_templates/ # RNS gateway configuration templates
tests/ # 165 test files, 5,168 tests
docs/ # REST API, metrics, usage guide, visual guide
examples/ # Example configurations
web/ # Node map, LOS visualization (browser)
MeshAnchor writes hardware config overlays (never overwrites defaults):
/etc/meshtasticd/
├── config.yaml # Package default (DO NOT EDIT)
└── config.d/
├── lora-*.yaml # Hardware config (SPI pins, module)
└── meshanchor-overrides.yaml # Custom overrides
LoRa modem presets and frequency slots are applied via the meshtastic
CLI (--set lora.modem_preset, --set lora.channel_num), not config.d.
Auto-deploys a working config from templates/reticulum.conf:
- AutoInterface (LAN discovery)
- Meshtastic Interface on
127.0.0.1:4403(if gateway profile) - RNode LoRa (optional, for dedicated RNS radio)
Gateway-specific templates in config_templates/:
rns_meshtastic_gateway.conf— full gateway with Meshtastic interfacerns_minimal.conf— minimal config for MeshCore-only operation
| Port | Service | Owner | Notes |
|---|---|---|---|
| 4403 | meshtasticd TCP API | meshtasticd | Optional (gateway only), single client limit |
| 9443 | meshtasticd Web UI | meshtasticd | Optional (gateway only) |
| 1883 | MQTT broker | mosquitto | Optional, multi-consumer |
| 5000 | Map Server | MeshAnchor | Live NOC map + REST API |
| 5001 | WebSocket | MeshAnchor | Real-time message broadcast |
| 8081 | Config API | MeshAnchor | RESTful config management |
| 9090 | Prometheus metrics | MeshAnchor | Grafana-compatible JSON API |
5,168 tests across 165 test files. Top suites by depth:
| Test File | Tests | Covers |
|---|---|---|
test_all_handlers_protocol.py |
449 | Protocol conformance across all 85 TUI handlers |
test_rns_bridge.py |
250 | Core bridge: routing, circuit breaker, callbacks |
test_rf.py |
107 | RF calculations: haversine, FSPL, Fresnel, link budget |
test_message_queue.py |
104 | SQLite queue, retry policy, dead letter |
test_rns_transport.py |
97 | Packet fragmentation, reassembly, transport stats |
test_lxmf_broadcast_bridge.py |
88 | LXMF broadcast bridge: subscribe, fan-out, dedup |
test_gateway_config.py |
80 | Gateway config + validators |
test_status_bar.py |
70 | TUI status bar rendering |
test_fleet_aggregator.py |
69 | Fleet observability aggregation |
test_node_tracker.py |
68 | Unified node tracking |
test_mqtt_robustness.py |
68 | MQTT reconnection, broker failover |
test_service_check.py |
67 | Service management single source of truth |
test_phase4b_radio_writes.py |
63 | MeshCore radio writes, region-aware validation |
test_rns_status_parser.py |
62 | rnstatus parsing (incl. timed_out wedge detection) |
test_commands.py |
61 | CLI command handlers |
test_meshcore_handler.py |
58 | MeshCore connection, messaging, node tracking |
All tests use mocked external services. Field validation with real hardware is a separate track — and the one that needs your help.
python3 -m pytest tests/ -v # Run all tests
python3 -m pytest tests/ -v -x # Stop on first failure
python3 -m pytest tests/test_meshcore_handler.py -v # MeshCore tests onlySecurity linter (scripts/lint.py) enforces 17 rules:
| Rule | Description |
|---|---|
| MF001 | Path.home() -> use get_real_user_home() for sudo safety |
| MF002 | No shell=True in subprocess calls |
| MF003 | No bare except: — specify exception types |
| MF004 | All subprocess calls need timeout parameter |
| MF006 | No safe_import for first-party modules — use direct imports |
| MF007 | No direct TCPInterface() — use connection manager |
| MF008 | No raw systemctl for service state — use service_check |
| MF009 | RNS.Reticulum() must include configdir= parameter |
| MF010 | No time.sleep() in daemon loops — use _stop_event.wait() |
| MF011 | RNS repair logic must live in _rns_repair.py / diagnostics |
| MF012 | Context-loaded docs (e.g. persistent_issues.md) must stay under 40k chars |
| MF013 | Bare sqlite3.connect() outside db_helpers.py — use connect_tuned() |
| MF014 | No operator-specific values (hostnames, personal emails, /home/<user>/ paths) |
| MF016 | @patch('src.utils.paths.…') in tests no-ops — production imports via utils.paths |
| MA017 | Hardened systemd units: ReadWritePaths= must cover the MeshAnchor write buckets |
| MF019 | RNS.Reticulum() only via the open_reticulum() chokepoint in utils/rns_init.py |
| MF020 | apply_config_and_restart() (bool, msg) result must not be discarded in TUI handlers |
python3 scripts/lint.py --all # Run all lint rules
git config core.hooksPath .githooks # Enable pre-commit hooks- Circuit breaker — fault isolation on gateway connections
- Exponential backoff — reconnect (1s -> 2s -> 4s -> ... -> 30s max) with jitter
- Graceful degradation —
safe_importfor optional dependencies, features disable not crash - Handler isolation — registry dispatch with per-handler exception boundaries
- Persistent queue — SQLite message queue survives restarts
- Shared connection manager — prevents TCP:4403 client contention
- Pre-flight validation — device probes before connection, service checks before operations
- Stale node purge — 24h TTL on offline nodes, prevents ghost entries in node tracker
- Localhost-only control — all mutating HTTP endpoints restricted to loopback
- Permission hardening — narrow Bash subcommand patterns with explicit deny list (CVE-2026-21852)
The #1 way to help right now: test MeshAnchor with a real MeshCore radio and report what happens.
-
Test with real MeshCore hardware — connect a companion radio, try the TUI, attempt gateway bridging, report results. This is the single most impactful contribution you can make.
-
Report issues — field test results (even "it worked!" is valuable), bugs, unexpected behavior, missing documentation. Use GitHub Issues.
-
Code contributions — feature branches use
claude/prefix, merged via PR to main.
python3 -m pytest tests/ -v # Run tests
python3 scripts/lint.py --all # Security linter
git config core.hooksPath .githooks # Enable pre-commit hooksCode rules: No shell=True, no bare except:, use get_real_user_home() not
Path.home(), use _stop_event.wait() not time.sleep() in daemon loops,
use connect_tuned() not bare sqlite3.connect(), split files over 1,500 lines.
Commit style: feat:, fix:, docs:, refactor:, test:, security:
See CLAUDE.md for the complete development guide.
| Branch | Version | Focus |
|---|---|---|
main |
0.1.0-alpha |
MeshCore-primary NOC, alpha testing |
Sister project: MeshForge is the Meshtastic-primary NOC — extracted from the same codebase on 2026-04-01.
Feature branches use claude/ prefix, merged via PR to main. Dependabot
dependency PRs auto-merge once CI is green.
Shared contract: CanonicalMessage in src/gateway/canonical_message.py must
stay compatible with MeshForge's version. Changes to the message format should be
coordinated across both projects.
MeshAnchor development is backed by 22+ technical research documents covering protocol analysis, integration architecture, and RF engineering. These inform every major design decision in the codebase.
- MeshCore <> Meshtastic dual-protocol bridge architecture (3-way routing design)
- MeshCore reliability patterns: canonical packet format, MQTT origin filtering, lenient parsing
- Gateway scenario analysis: multi-protocol deployment topologies and trade-offs
- LoRa PHY deep-dive: CSS modulation, spreading factors, SNR limits, link budget calculations
- Official Semtech LoRa reference data for engineering-grade RF planning
- Complete Reticulum/RNS protocol documentation, configuration guides, and integration patterns
- AREDN mesh network integration research
- XTOC/XCOM integration: X1 compact packet protocol, structured message templates
- ATAK ecosystem research: CoT XML, PLI, GeoChat, KML/CoT export
- MQTT zero-interference bridging design (foundation of the gateway architecture)
- NGINX reliability patterns applied to mesh networking APIs
Full research library: .claude/research/
| Resource | Link | Relation |
|---|---|---|
| MeshCore | meshcore.co | Primary radio protocol |
| Meshtastic | meshtastic.org/docs | Optional gateway radio |
| Reticulum | reticulum.network | Optional gateway (encrypted transport) |
| MeshForge | github.com/Nursedude/meshforge | Sister project (Meshtastic-primary) |
| Development Blog | nursedude.substack.com | Project updates |
GPL-3.0 — See LICENSE
MeshAnchor
Made with aloha for the mesh community
WH6GXZ | Hawaii