No description
  • Python 46.5%
  • JavaScript 41.8%
  • TypeScript 11.5%
Find a file
Matt Johnson 60e8e62e85 fix(fire): v0.5.7-fire -- FIRMS NATS pattern + WFIGS tombstone dedup + remove fire_proximity + categories audit
Third family of the v0.5.7 NATS-and-categories campaign. Fire is the heaviest of the campaign -- four distinct fixes plus a category audit. Two of the four were broken in production: FIRMS subscribed to a syntactically invalid pattern, and WFIGS tombstones were silently dropped.

FIX 1 -- FIRMS NATS pattern (the canonical bug). Pre-v0.5.7-fire `_subjects_for("firms","us.id")` returned `["central.fire.hotspot.>.us.id"]`, which is INVALID NATS (the `>` multi-level wildcard is only legal at the tail token). It also wouldn't have matched anything Central publishes: per the Central v0.10.0 consumer integration guide §firms, the actual published pattern is `central.fire.hotspot.<satellite>.<confidence>` (5 tokens, no us.<state> suffix). The two slots after "hotspot" are satellite name and confidence band -- NOT tile coordinates or region tokens.

Note on prompt vs. guide discrepancy: the v0.5.7-fire task spec described a tile-coord/state pattern `central.fire.hotspot.*.*.us.id` (7 tokens with us.<state> tail). That's neither what Central v0.10.0 publishes nor what its guide documents. We follow the guide. Subscribing to the prompt's 7-token pattern would silently match zero messages in production (token-count mismatch). State filtering for FIRMS happens client-side via data.latitude / data.longitude against the configured region bbox.

New subscription: `central.fire.hotspot.>` -- tail-only `>`, NATS-legal, matches all <satellite>.<confidence> combinations.

FIX 2 -- WFIGS tombstone subjects. Per guide §wfigs_incidents and §wfigs_perimeters, WFIGS publishes:

    active:    central.fire.incident.<state>.<county>     (Convention A, depth-3 state)
    active:    central.fire.perimeter.<state>.<county>
    tombstone: central.fire.incident.removed.<state>     (5 tokens, "removed" at depth-3)
    tombstone: central.fire.perimeter.removed.<state>

Pre-v0.5.7-fire `_subjects_for("fires","us.id")` subscribed only to the active subjects (`central.fire.incident.id.>` and `central.fire.perimeter.id.>`). The tombstone subjects have "removed" at depth-3 instead of the state token, so the active-subject `>` filters silently dropped EVERY tombstone. Fall-off signals never reached meshai's inhibitor, so old incidents stayed "live" in the pipeline indefinitely.

Added the two tombstone subjects to the subscription list. Both are 5-token literals with no wildcards -- trivially NATS-legal.

FIX 3 -- WFIGS tombstone dedup. Per guide §wfigs_incidents removal semantics, the tombstone env_id has the shape `<IrwinID>:removed:<iso_now>` -- the `:removed:` is sandwiched in the middle, with a timestamp tail. Pre-v0.5.7-fire the consumer.py group_key recovery was `re.sub(r":removed$", "", group_key)` -- a literal trailing `:removed` match -- which DID NOT FIRE on the WFIGS form (the regex required `:removed` at the very end of the string, but the WFIGS form has `:<iso>` after it).

Consequence: WFIGS tombstones' group_key was the full `<IrwinID>:removed:<iso>` string instead of the bare `<IrwinID>`. The pipeline grouper/inhibitor never matched tombstones to their original incidents, so the lapse signal was lost.

Fixed by switching the regex to `re.sub(r":removed(:.*)?$", "", group_key)` -- handles both the WFIGS `<IrwinID>:removed:<iso>` form AND the legacy GDACS `<id>:removed` form. The `is_tombstone` detection also gained an explicit `":removed:" in env_id` check for the WFIGS shape.

Per the guide: "the same incident can have one or more removal tombstones over its lifecycle" (it can re-enter and re-fall-off). To preserve per-tombstone distinctness for downstream lifecycle accounting, the full env_id is stashed on `Event.data["_central_tombstone_id"]` (the group_key collapses to the IrwinID by design, but the original env_id with the :<iso> tail survives on data).

FIX 4 -- ALERT_CATEGORIES fire-family audit + removed parametric entries. Per Matt's direct feedback ("fire near mesh has its own set of parameters that I don't even know what they could be. like how far is near mesh? I don't know I can't set that."), the parametric `fire_proximity` and the duplicate-named `wildfire_proximity` (both labeled "Fire Near Mesh" with parametric radius-based descriptions) were unselectable in the new Advanced Rules UI. Removed both.

Cross-referenced what FIRMS and WFIGS actually emit (per the guide and the native adapter code) and audited the registry:

    Native emit:
      firms.py  -> new_ignition (when adapter flags new_ignition)
                or wildfire_hotspot (otherwise)  [v0.5.7-fire: was wildfire_proximity]
      fires.py  -> wildfire_incident
    Central path emit (via map_category):
      fire.hotspot.*    -> wildfire_hotspot
      fire.incident.*   -> wildfire_incident
      fire.perimeter.*  -> wildfire_incident (perimeters merge to the incident)
      fire.<other>      -> wildfire_incident (catchall)
    Registry after v0.5.7-fire:
      {new_ignition, wildfire_hotspot, wildfire_incident}
    Parity confirmed. No orphans, no missing.

Aligning firms.py to emit `wildfire_hotspot` (matching the central FIRMS map) means native + central FIRMS produce identical categories regardless of which feed path is enabled.

Composer (`_CATEGORY_EMOJI`, `_CATEGORY_LABEL`) and router (three source-attribution tables) updated to drop the removed categories and add the new ones.

Deferred to v0.5.8: distance_max_km field on rules for actual proximity filtering. Replaces the parametric fire_proximity registry entry with a parameterized rule field that the user CAN configure ("alert me about wildfire_incident within 30 km" instead of an opaque "Fire Near Mesh" toggle).

Tests
-----
PYTHONPATH=. pytest -q: 380 passed (was 366; +14 net).
  - tests/test_fire_v057.py (new): FIRMS subject is tail-only `>` with no mid-subject placement; WFIGS subjects cover active + four tombstones; WFIGS tombstone strips `:removed(:.*)?$` for group_key; two same-IrwinID tombstones both propagate through _handle and share group_key, with the original env_id preserved on data["_central_tombstone_id"]; legacy GDACS `:removed` shape still strips cleanly; fire_proximity / wildfire_proximity absent from ALERT_CATEGORIES; no "Fire Near Mesh" name duplicates; fire-family parity (native + central emit == registry); required-fields check on the three fire entries.
  - tests/test_central_region_routing.py: updated FIRMS test (tail-only `>`) and WFIGS test (includes tombstone subjects).
  - tests/test_pipeline_toggle_filter.py, tests/test_adapter_firms.py, tests/test_v052_dispatcher.py, tests/test_pipeline_digest.py: bulk-migrated obsolete category references (wildfire_proximity -> wildfire_hotspot, fire_proximity -> wildfire_incident) so the existing test suites continue to exercise the same routing/digest/dispatch paths with the new category names.

Safe-mode preserved (master off, all family toggles off, all adapters native, central disabled). No live toggle flipped. Not tagging yet -- v0.5.7 tag waits until all families ship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-04 06:25:42 +00:00
.github/workflows Add GHCR publishing workflow and update docker-compose for registry pull 2026-02-23 21:39:23 +00:00
config build: normalize all line endings to LF 2026-05-14 22:43:06 +00:00
dashboard-frontend feat(dashboard): v0.5.6 -- Advanced Rules editor polish (grouped categories, region_scope, name tooltip, smart activity badge) 2026-06-04 03:08:15 +00:00
meshai fix(fire): v0.5.7-fire -- FIRMS NATS pattern + WFIGS tombstone dedup + remove fire_proximity + categories audit 2026-06-04 06:25:42 +00:00
tests fix(fire): v0.5.7-fire -- FIRMS NATS pattern + WFIGS tombstone dedup + remove fire_proximity + categories audit 2026-06-04 06:25:42 +00:00
.dockerignore Initial commit: MeshAI - LLM-powered Meshtastic assistant 2025-12-15 11:53:46 -07:00
.gitattributes build: add .gitattributes to enforce LF line endings 2026-05-14 22:42:14 +00:00
.gitignore chore(meshai): v0.5.5 -- cleanup bundle (gitignore env anchor, ducting health event_count, mesh_sources secret stripping, delete unused SeverityRouter) 2026-06-04 02:50:45 +00:00
config.example.yaml build: normalize all line endings to LF 2026-05-14 22:43:06 +00:00
docker-compose.yml fix(infra): point meshai container DNS at LXC working resolver 2026-05-27 17:15:29 +00:00
docker-entrypoint.sh feat: Hybrid RAG knowledge base, sentence-aware chunking, MeshMonitor HTTP sync 2026-05-04 07:44:12 +00:00
Dockerfile feat(dashboard): embedded FastAPI backend with REST API + WebSocket 2026-05-12 15:47:58 +00:00
LICENSE Add MIT license file 2026-02-23 21:31:59 +00:00
pyproject.toml feat(central): v0.4 C.1 Central connector backend (no-op until adapter source flipped) 2026-05-28 02:28:19 +00:00
README.md docs: comprehensive README with full setup guide 2026-05-12 21:02:17 -06:00
requirements.txt feat: Add MQTT source adapter 2026-05-12 21:57:11 +00:00

MeshAI

LLM-powered mesh intelligence assistant for Meshtastic networks. MeshAI connects to your mesh as a physical node, monitors network health in real-time, and answers questions about your infrastructure over LoRa.

What It Does

MeshAI runs on your Meshtastic node and provides:

  • Mesh Intelligence — 5-pillar health scoring, per-region breakdowns, infrastructure monitoring, coverage gap analysis, and environmental sensing
  • Conversational Queries — ask "how's the mesh?" or "tell me about MHR" and get data-driven answers over LoRa
  • Node Distance — GPS-based distance calculations between any two nodes on the mesh
  • Multi-Source Awareness — aggregates data from multiple Meshview instances and MeshMonitor with staggered polling
  • Feeder Gateway Tracking — identifies which physical MQTT gateways hear each node and signal quality
  • Subscriptions — scheduled daily/weekly health reports and instant alerts delivered via DM
  • LLM Chat — general conversation, knowledge base lookups, and weather queries
  • Multi-Backend — supports Google Gemini, OpenAI, Anthropic Claude, and local LLMs via LiteLLM

Quick Start

# Clone
git clone https://github.com/zvx-echo6/meshai.git
cd meshai

# Install
pip install -e .

# Configure (interactive TUI)
meshai --config

# Run
meshai

Or with Docker:

mkdir -p meshai/data && cd meshai
curl -O https://raw.githubusercontent.com/zvx-echo6/meshai/main/docker-compose.yml
curl -o data/config.yaml https://raw.githubusercontent.com/zvx-echo6/meshai/main/config.example.yaml
# Edit data/config.yaml
docker compose up -d

Commands

Command Description
!health Mesh health overview with colored status dots
!region List all regions with health status
!region [name] Detailed region breakdown
!neighbors [node] Top infrastructure neighbors with signal quality
!sub daily 6pm Subscribe to daily health reports
!sub weekly 8am sun Subscribe to weekly digest
!sub alerts Subscribe to instant alerts on issues
!unsub [type] Remove a subscription
!mysubs List your active subscriptions
!clear Clear conversation history
!help Show available commands
!help [cmd] Detailed help for a command
!quakes Recent earthquakes in monitored area
!fires Active wildfires from NIFC
!hotspots NASA FIRMS satellite fire detections
!hotspots --new Only hotspots not matching known fires
!traffic Traffic incidents from TomTom
!space Space weather conditions (solar/geomagnetic)
!water USGS stream gauge readings
!air Air quality index

Commands can be disabled in config if another service (like MeshMonitor) handles them.

Mesh Intelligence

MeshAI continuously polls mesh data sources and computes a 5-pillar health score:

Pillar Weight What It Measures
Infrastructure 30% Router uptime — how many infra nodes are online
Utilization 25% Channel busyness — RF congestion across the mesh
Coverage 20% Gateway reach — how many monitoring sources see each node
Behavior 15% Traffic patterns — detecting noisy or misconfigured nodes
Power 10% Battery health — infrastructure nodes only

Health Display

!health shows a compact overview with personality:

📡 Mesh 🟢 healthy
🏗️ 15/16 routers up
❌ Down: TVM Tablerock Relay
📶 152 full coverage, 94 on thin ice
🔥 Hayden Peak Router at 21% util
🔋 All infra powered ✅
🌡️ 29-34°C across 2 sensors
Treasure Valley 🟢 | Magic Valley 🟢

Status dots: 🔵 perfect (100) · 🟢 healthy (75+) · 🟠 warning (50+) · 🔴 critical (<50)

Monitoring Rules

Infrastructure nodes (routers, repeaters) are monitored individually with full detail — battery, offline alerts, coverage, neighbors, hardware. Client nodes dying is normal and not tracked. Channel utilization and environmental sensors are monitored for all nodes.

Conversational Queries

Ask questions naturally over LoRa:

  • "how's the mesh?" → health overview with top issues
  • "tell me about MHR" → full node detail with neighbors, coverage, feeders
  • "where do we need more coverage?" → named gaps with specific nodes
  • "how far is MHR from AIDA?" → GPS distance calculation
  • "which nodes only reach one gateway?" → named nodes with their gateway
  • "which gateway has the best signal?" → feeder comparison

Geographic Regions

Regions are configurable with local names, descriptions, aliases, and cities — all manageable through the TUI. No hardcoded geography in the code.

mesh_intelligence:
  regions:
    - name: "South Central ID"
      local_name: "Magic Valley"
      description: "Twin Falls area"
      aliases: ["southern Idaho", "magic valley"]
      cities: ["Twin Falls", "Burley", "Jerome"]
      lat: 42.5
      lon: -114.5
      radius_km: 80

Environmental Feeds

MeshAI integrates real-time environmental data for situational awareness beyond mesh network health.

USGS Earthquake Monitoring

env:
  usgs:
    enabled: true
    min_magnitude: 2.5
    radius_km: 500
    center_lat: 43.6150
    center_lon: -116.2023

No API key required. Data from USGS Earthquake Hazards Program.

NWS Weather Alerts

env:
  nws:
    enabled: true
    zone: IDZ025         # NWS zone ID
    point: "43.6150,-116.2023"

No API key required. Find your zone at NWS Zone Lookup.

NOAA Space Weather

env:
  noaa_space:
    enabled: true

No API key required. Data from NOAA SWPC.

NIFC Wildfire Perimeters

env:
  nifc:
    enabled: true
    radius_km: 200
    center_lat: 43.6150
    center_lon: -116.2023

No API key required. Data from NIFC Open Data.

NASA FIRMS Satellite Fire Detection

env:
  firms:
    enabled: true
    map_key: "your-map-key"    # Required
    radius_km: 200
    center_lat: 43.6150
    center_lon: -116.2023
    source: VIIRS_SNPP         # VIIRS_SNPP, VIIRS_NOAA20, MODIS_NRT
    day_range: 1               # 1, 2, or 10 days

API Key Required: Register at NASA FIRMS. Free MAP_KEY provides access to near real-time satellite fire detections. Hotspots are cross-referenced against NIFC perimeters to identify potential new ignitions.

TomTom Traffic

env:
  tomtom:
    enabled: true
    api_key: "your-api-key"    # Required
    bbox: "-117.5,42.5,-115.0,44.5"  # lon1,lat1,lon2,lat2

API Key Required: Register at TomTom Developer Portal. Free tier includes 2,500 requests/day.

511 Road Conditions

env:
  fiveonone:
    enabled: true
    state: ID                  # State code
    api_key: "your-api-key"    # If required by state
    bbox: [-117.5, 42.5, -115.0, 44.5]

API key requirements vary by state. Check your state's 511 developer portal.

USGS Water Services

env:
  usgs_water:
    enabled: true
    sites: ["13206000", "13202000"]  # USGS site numbers

No API key required. Find sites at USGS Water Services.

AirNow Air Quality

env:
  airnow:
    enabled: true
    api_key: "your-api-key"    # Required
    zipcode: "83702"

API Key Required: Register at AirNow API.

Dashboard Configuration

dashboard:
  enabled: true
  host: 0.0.0.0
  port: 8080

The web dashboard provides real-time visualization of mesh nodes, environmental conditions, and alerts with WebSocket push notifications.


Data Sources

MeshAI aggregates from multiple sources using staggered tick-based polling (one API call per 30-second tick):

Meshview

Unauthenticated REST API. Supports multiple instances.

Endpoint Interval Data
/api/packets 30s Near real-time packet feed
/api/nodes 2 min Node list with metadata
/api/stats 3 min Traffic statistics
/api/edges 3 min Node-to-node connections
/api/traceroutes 5 min Route data
/api/packets_seen 10 min Per-gateway RSSI/SNR (sampled)

MeshMonitor

Authenticated (Bearer token). Single instance.

Endpoint Interval Data
/api/v1/packets 60s Packet feed
/api/v1/nodes 2 min Nodes with battery, utilization, hardware
/api/v1/telemetry 2 min Environmental sensors, device metrics
/api/v1/traceroutes 5 min Route data
/api/v1/channels 5 min Channel configuration
/api/v1/network 5 min Network statistics
/api/v1/solar 10 min Solar estimates

Rate Limiting

Built-in protection for all sources: HTTP 429 backoff with Retry-After, exponential backoff on consecutive errors, slow response warnings, and optional polite mode for shared instances.

Source Configuration

mesh_sources:
  - name: "local-meshview"
    type: meshview
    url: "http://192.168.1.100:8080"
    enabled: true

  - name: "meshmonitor"
    type: meshmonitor
    url: "http://192.168.1.100:3333"
    api_token: "your-bearer-token"
    enabled: true

Knowledge Base (RAG)

MeshAI uses a hybrid knowledge retrieval system with two backends:

Primary: RECON Qdrant Backend

Queries RECON's knowledge extraction pipeline — 2.8M+ vectors covering survival skills, communications, medical, technical documentation, Meshtastic docs, and more. Uses the same embedding infrastructure as RECON:

  • Dense embeddings: TEI service with BAAI/bge-m3 (1024-dim)
  • Sparse embeddings: bge-m3-sparse with IDF modifier
  • Search: Qdrant hybrid with Reciprocal Rank Fusion (dense + sparse)

No data is copied — MeshAI queries RECON's Qdrant and TEI services over the network.

knowledge:
  enabled: true
  backend: auto            # "qdrant", "sqlite", or "auto" (try qdrant, fall back)
  qdrant_host: "192.168.1.150"
  qdrant_port: 6333
  qdrant_collection: "recon_knowledge_hybrid"
  tei_host: "192.168.1.150"
  tei_port: 8090
  sparse_host: "192.168.1.150"
  sparse_port: 8091
  use_sparse: true
  top_k: 5

Fallback: Local SQLite

If the Qdrant backend is unreachable, MeshAI falls back to a local SQLite knowledge base using FTS5 keyword search and bge-small-en-v1.5 vector embeddings (384-dim).

# Build from Meshtastic ZIM file
python scripts/zim_to_knowledge.py meshtastic.zim --output knowledge.db
knowledge:
  enabled: true
  backend: sqlite
  db_path: /data/meshai_knowledge.db
  top_k: 5

Requires sqlite-vec and fastembed for the SQLite backend.

Architecture

┌──────────────────────────────────────────────────────────────────────┐
│                              MeshAI                                  │
├──────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  DATA SOURCES              INTELLIGENCE              DELIVERY        │
│  ┌─────────────┐          ┌──────────────┐         ┌────────────┐   │
│  │ Meshview ×N  │─────┐   │ Health Engine │────────▶│  Reporter  │   │
│  │ (staggered)  │     │   │ 5-pillar     │         │ Tier 1/2   │   │
│  └─────────────┘     ▼   │ scoring      │         └─────┬──────┘   │
│  ┌─────────────┐  ┌──────┴──┐            │               │          │
│  │ MeshMonitor │─▶│  Data   │─┘          │         ┌─────▼──────┐   │
│  │ (staggered) │  │  Store  │            │         │   Router   │   │
│  └─────────────┘  │ SQLite  │            │         │ scope/dist │   │
│                   └─────────┘            │         └─────┬──────┘   │
│                        │                 │               │          │
│                   ┌────▼────┐      ┌─────▼──────┐  ┌────▼────┐    │
│                   │ Feeder  │      │    LLM     │  │ Chunker │    │
│                   │ Sampling│      │  Backend   │  │LoRa-fit │    │
│                   └─────────┘      └────────────┘  └────┬────┘    │
│                                                         │         │
│  KNOWLEDGE             ALERTS             DELIVERY      │         │
│  ┌─────────────┐  ┌─────────────┐  ┌──────────────┐    │         │
│  │ RECON/Qdrant│  │   Alert     │  │ Subscription │    │         │
│  │ 2.8M vectors│  │   Engine    │  │   Manager    │    │         │
│  │ (network)   │  │ 17 triggers │  │ daily/weekly │    │         │
│  ├─────────────┤  │  scaling    │  │   alerts     │    │         │
│  │ SQLite FTS5 │  │  cooldown   │  └──────┬───────┘    │         │
│  │ (fallback)  │  └──────┬──────┘         │            │         │
│  └─────────────┘         │          ┌─────▼────────┐   │         │
│                          └─────────▶│  Responder   │◀──┘         │
│  ┌─────────────┐                    │ ACK-paced DM │             │
│  │ Conversation│                    │ Channel alert│             │
│  │   History   │                    └──────────────┘             │
│  └─────────────┘                                                 │
│                                                                   │
└───────────────────────────────────────────────────────────────────┘
         │                    │
    ┌────▼────┐          ┌────▼────┐
    │  TEI    │          │ Qdrant  │
    │ bge-m3  │          │ hybrid  │
    │ cortex  │          │ cortex  │
    └─────────┘          └─────────┘

Dashboard API Reference

The dashboard exposes a REST API (default port 8080):

Core Endpoints

Endpoint Method Description
/api/health GET System health check
/api/status GET Full system status with health scores
/api/nodes GET Connected mesh nodes
/api/messages GET Recent mesh messages

Environmental Data

Endpoint Method Description
/api/env/earthquakes GET Recent earthquakes
/api/env/weather GET Weather conditions and alerts
/api/env/fires GET Active wildfires from NIFC
/api/env/hotspots GET NASA FIRMS satellite detections
/api/env/traffic GET Traffic incidents
/api/env/water GET Stream gauge readings
/api/env/space GET Space weather data
/api/env/air GET Air quality readings

Alerts

Endpoint Method Description
/api/alerts/active GET Currently active alerts
/api/alerts/history GET Historical alerts (?severity=, ?source=, ?limit=, ?offset=)
/api/alerts/{id}/ack POST Acknowledge an alert
/api/subscriptions GET Alert subscriptions

WebSocket

Connect to /ws for real-time updates:

const ws = new WebSocket('ws://localhost:8080/ws');
ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // data.type: 'message', 'alert', 'node_update', 'health_update'
};

Message Chunking

Long responses are split into mesh-friendly chunks with sentence-aware splitting, configurable limits, and continuation prompts. Command output (like !health) packs multiple lines into 2-3 messages using newlines within each message to minimize airtime usage.

response:
  max_length: 200       # Max chars per message
  max_messages: 3       # Messages before continuation prompt

Alerting

Real-time alerts when mesh conditions change, with scaling cooldowns to prevent spam.

Alert Conditions (17 total, each toggleable)

Pillar Condition Default Threshold
Infrastructure Router goes offline
Infrastructure Router recovery
Infrastructure New router appears
Power Battery warning <50%
Power Battery critical <25%
Power Battery emergency <10%
Power 7-day declining trend >10% drop with rate
Power USB → battery (power outage)
Power Solar not charging during day
Utilization Sustained high utilization >20% for 6h
Utilization Packet flood >500 pkts/24h
Coverage Infra drops to single gateway
Coverage Feeder gateway stops responding
Coverage Region total blackout All infra offline
Scores Mesh health score drop <70/100
Scores Region health score drop <60/100

Scaling Cooldown

Alerts don't spam. When a condition triggers:

  1. Alert 1: fires immediately
  2. Alert 2: 12 hours later (if still in condition)
  3. Alert 3: 24 hours after that
  4. Alert 4: 48 hours after that
  5. Stops until condition resolves

When the condition clears, one recovery notification fires and the tracker resets.

Delivery

Alerts are delivered two ways:

  • Channel broadcast: configurable channel index for mesh-wide visibility
  • DM to subscribers: users who ran !sub alerts receive DMs matching their scope

Critical Nodes

Designate important infrastructure (e.g., MHR, HPR) as critical. When a critical node goes offline, alerts use priority formatting.

mesh_intelligence:
  critical_nodes: ["MHR", "HPR"]
  alert_channel: 0        # Channel for broadcast alerts (-1 = disabled)

All conditions and thresholds are configurable via the TUI under Mesh Intelligence → Alert Rules.

LLM Configuration

llm:
  backend: "google"            # openai, anthropic, google
  api_key: "your-api-key"
  model: "gemini-2.0-flash"

Local LLMs

MeshAI works with any OpenAI-compatible API:

  • LiteLLM: base_url: "http://localhost:4000/v1"
  • Open WebUI: base_url: "http://localhost:3000/api"
  • Ollama: base_url: "http://localhost:11434/v1"

Docker

connection:
  type: "tcp"
  tcp_host: "192.168.1.100"
  tcp_port: 4403

Serial Connection

connection:
  type: "serial"
  serial_port: "/dev/ttyUSB0"

Edit docker-compose.serial.yml to match your device path.

Environment Variables

LLM_API_KEY=your-key-here docker compose up -d

Running Alongside Other Services

advBBS

MeshAI coexists with advBBS on the same node. BBS protocol messages (sync, RAP, mail notifications) are automatically filtered. No configuration needed.

bot:
  filter_bbs_protocols: true

MeshMonitor

MeshAI integrates with MeshMonitor at two levels: it fetches MeshMonitor's auto-responder patterns to avoid duplicate responses, and it uses MeshMonitor's API as a data source for mesh intelligence (battery, telemetry, traceroutes, solar).

meshmonitor:
  enabled: true
  url: "http://192.168.1.100:8080"
  inject_into_prompt: true
  refresh_interval: 300

Running as a Service

# /etc/systemd/system/meshai.service
[Unit]
Description=MeshAI - Meshtastic Mesh Intelligence
After=network.target

[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/meshai
ExecStart=/usr/bin/python3 -m meshai
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable meshai
sudo systemctl start meshai

Acknowledgments

  • Meshtastic — the mesh networking platform
  • MeshMonitor by Yeraze — monitoring integration and data source
  • advBBS — BBS coexistence design
  • sqlite-vec by Alex Garcia — vector search in SQLite
  • fastembed by Qdrant — fast local embeddings

License

MIT License

Author

K7ZVX - matt@echo6.co