No description
  • Python 46.6%
  • JavaScript 41.8%
  • TypeScript 11.4%
Find a file
Matt Johnson 8359451eaa fix(seismic): v0.5.7-seismic -- USGS quake NATS pattern + severity=5 great-quake clamp + categories audit
Fourth family of the v0.5.7 NATS-and-categories campaign. Seismic = USGS quake adapter (the USGS water/hydro side stays under toggle="seismic" per the v0.5.2 geohazards migration but lives in the water phase that follows).

The Central v0.10.0 consumer integration guide (docs/CONSUMER-INTEGRATION.md on the v0.10.0-itd-511 branch) was treated as source of truth -- ground-truthing the prompt against the guide caught two prompt errors before they shipped (mirrors the FIRMS situation in v0.5.7-fire). Documented below.

FIX 1 -- USGS quake NATS pattern. Pre-v0.5.7-seismic `_subjects_for("usgs_quake","us.id")` returned `["central.quake.event.>.us.id"]`. That subject is BOTH invalid NATS (`>` is only legal at the tail token) AND wouldn't have matched anything Central publishes.

Per Central v0.10.0 guide §usgs_quake the actual published subject is `central.quake.event.<tier>` -- 4 tokens, no region. `<tier>` is one of {minor, light, moderate, strong, major, great} (USGS magnitude bands; bands live in the SUBJECT, not in the severity integer).

Note on prompt vs. guide discrepancy: the v0.5.7-seismic prompt described a "regional v0.9.20+ shape" `central.quake.event.<severity>.us.<state>` with 6 tokens and `us.<state>` at the tail. That's neither what Central v0.10.0 publishes nor what its guide documents. We follow the guide. Subscribing to the prompt's shape would silently match zero messages in production. State filtering for quakes happens client-side via data.latitude/longitude (same situation as FIRMS).

New subscription: `central.quake.event.>` -- tail-only `>`, NATS-legal, matches all <tier> values.

FIX 2 -- severity=5 great-quake clamp (no actual bug; regression-guard pin). The prompt described a "severity=5 IndexError or silent drop" failure mode. Investigation found NO such bug exists in the current code:

  - consumer.map_severity already clamps `sev >= 3` to "immediate". A
    severity=5 (or 99, or any 3+) maps safely to "immediate" with no
    exception path.
  - NotificationToggle.severity_channels is dict-keyed by severity STRING
    ({"routine","priority","immediate"}), not an int-indexed list, so
    IndexError is structurally impossible from this boundary regardless
    of upstream value.
  - Per Central v0.10.0 guide §5b the documented severity vocabulary is
    `0-4 or None`. Severity=5 is not in the published contract; the
    clamp is defensive padding against future contract drift.

Three things were tightened anyway: (a) the map_severity docstring now explicitly documents the high-side clamp behavior and calls out the string-keyed dict guarantee; (b) parametrized test pins map_severity for the full 0..99 range including out-of-contract values; (c) an end-to-end synthetic-envelope test injects a severity=5 quake through _handle and asserts the resulting Event has severity="immediate" / category="earthquake_event" / source="usgs_quake" with no exception. These tests function as regression guards if a future refactor introduces the IndexError vector the prompt was guarding against.

FIX 3 -- ALERT_CATEGORIES seismic-family audit. The registry was MISSING `earthquake_event` entirely. Both native (`usgs_quake.py` emits `category="earthquake_event"`) and central (consumer._CATEGORY_MAP maps `quake.* -> earthquake_event`) paths produce that category, but get_category("earthquake_event") fell through to the mesh_health default -- so the Advanced Rules editor couldn't target quakes at all. The get_toggle() prefix fallback DID route it to "seismic" via the `("earthquake", "seismic")` rule, so events were filtered correctly; the gap was UI-selectability only.

Added the entry under toggle="seismic" with a representative example_message. composer.py already had matching emoji/label mappings (line 78-79, 107-108) from earlier work, no composer change needed.

The two hydro entries (`stream_flood_warning`, `stream_high_water`) also live under toggle="seismic" via the v0.5.2 USGS-water migration (Geohazards family in the GUI). They are OUT OF SCOPE for v0.5.7-seismic -- they belong to the water phase that follows. Verified-unchanged here so the next phase has a clean baseline.

Audit table after v0.5.7-seismic:
  Native emit:   usgs_quake.py -> earthquake_event
  Central path:  all 6 tiers (minor/light/moderate/strong/major/great) -> earthquake_event
  Registry:      {earthquake_event, stream_flood_warning, stream_high_water}
  Quake side:    parity (registry has earthquake_event; native + central emit it)
  Hydro side:    verified-unchanged (deferred to water phase)

Tests
-----
PYTHONPATH=. pytest -q: 400 passed (was 380; +20 net).
  - tests/test_seismic_v057.py (new): quake subject tail-only `>`; no mid-subject `>`; bare-form backward compat; parametrized map_severity full range 0..99 + None / nonsense / negative; synthetic severity=5 envelope routes through _handle to severity="immediate" cleanly; NotificationToggle.severity_channels shape pinned to dict (no IndexError vector); earthquake_event present under toggle="seismic"; hydro entries still toggle="seismic" (regression guard); native + central-path quake emit set equals {earthquake_event}; required-fields check.
  - tests/test_central_region_routing.py: updated `test_subjects_for_usgs_quake_us_id` -> `test_subjects_for_usgs_quake_us_id_uses_tail_only_wildcard` reflecting the guide-correct shape.

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:33:31 +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(seismic): v0.5.7-seismic -- USGS quake NATS pattern + severity=5 great-quake clamp + categories audit 2026-06-04 06:33:31 +00:00
tests fix(seismic): v0.5.7-seismic -- USGS quake NATS pattern + severity=5 great-quake clamp + categories audit 2026-06-04 06:33:31 +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