Every plugin gets a fully isolated environment — FastAPI router, static file server, sidebar nav entry, in-memory log stream, and lifecycle management — without touching a single line of core code. Ship a plugin in an afternoon. Reach every MeshDash deployment through the verified store.
Available to install from your dashboard
Every plugin reviewed before store publication
One click in the Plugin Manager
Plugins never modify core MeshDash files
These are the real, live plugins currently in the MeshDash plugin store — scanned directly from the plugin repository. Install any of them from the Plugin Manager in your dashboard with one click.
All plugins in the store are available directly from the Plugin Manager inside your running MeshDash instance. Open the Plugins view, click INSTALL PLUGIN, choose the URL tab, and paste the plugin's .zip URL. The server fetches, extracts, and registers the plugin automatically. Then click APPLY & RESTART.
meshdash.local:8000 → Plugins → INSTALL PLUGIN → FROM URL → paste .zip URL → APPLY & RESTART
The complete developer guide lives in the MeshDash documentation. Everything below is a practical overview. Start from Hello Mesh — it's already running on your instance.
plugins/
└── my_plugin/
├── manifest.json ← required
├── main.py ← entry point
├── requirements.txt ← pip deps
├── static/ ← served at /static/plugins/my_plugin/
│ └── index.html
└── README.md ← required for store submission
{
"id": "my_plugin",
"name": "My Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "What this plugin does.",
"entry_point": "main.py",
"router_prefix": "/api/plugins/my_plugin",
"static_prefix": "/static/plugins/my_plugin",
"watchdog": false,
"nav_menu": [{
"label": "My Plugin",
"icon": "fa-puzzle-piece",
"href": "/plugin/my_plugin/index.html"
}]
}
from fastapi import APIRouter
plugin_router = APIRouter()
_ctx = {}
def init_plugin(context: dict):
global _ctx
_ctx = context
_ctx['logger'].info("my_plugin loaded")
@plugin_router.get("/hello")
async def hello():
node = _ctx['meshtastic_data'].local_node_id
return {"node": node, "status": "ok"}
@plugin_router.post("/announce")
async def announce(text: str):
conn = _ctx['connection_manager']
await conn.sendText(text, destinationId="^all",
channelIndex=0)
return {"sent": True}
import time, threading
from fastapi import APIRouter
plugin_router = APIRouter()
_running = False
@plugin_router.get("/status")
async def status():
return {"running": _running}
def _loop(ctx):
global _running
pid = ctx["plugin_id"]
logger = ctx["logger"]
watchdog = ctx["plugin_watchdog"]
conn = ctx["connection_manager"]
_running = True
logger.info("Background task started")
while _running:
try:
# ── Do your work here ──────────────
logger.debug("poll cycle")
# MUST heartbeat if watchdog=true
watchdog[pid] = time.time()
except Exception as e:
logger.error(f"Poll error: {e}")
time.sleep(30)
def init_plugin(context: dict):
t = threading.Thread(
target=_loop, args=(context,), daemon=True)
t.start()
context["logger"].info("Plugin init complete")
Set "watchdog": true in manifest.json. Your background task must write watchdog[pid] = time.time() at least once per minute. If the heartbeat stops, MeshDash marks the plugin as hung, routes return 503, and the APPLY & RESTART button appears.
All plugin routes automatically get a state-check dependency injected by the PluginManager. If the plugin status is not running or the watchdog has fired, the dependency raises 503 Service Unavailable. You never need to implement this yourself.
touch /opt/meshdash/plugins/my_plugin/.disabled
This is what the STOP button does internally. The plugin stops loading at startup without being deleted. Remove the file (or click START) to re-enable.
Your MeshDash account — created during the Setup Wizard — is your developer account. No separate registration, no fee, no gatekeeping on development. Only store publication is reviewed.
Visit meshdash.co.uk/c2_setup.php to set up MeshDash. The account you create is automatically a developer account.
Clone Hello Mesh from your running instance's Plugin Manager. It's already fully documented with live endpoints you can test.
Log in at meshdash.co.uk/plugin-development.php. Upload your plugin .zip, fill in the submission form, and link a test instance.
Code review, manifest validation, functional testing, and documentation check. Two-way feedback via the developer portal. Most reviews complete within 5 business days.
Your plugin appears in every MeshDash Plugin Manager worldwide. You keep full ownership and can push revisions through the portal at any time.
Push revisions at any stage — pre-review, during review, or after going live. Security-affecting changes trigger a targeted re-review only.
See how many instances have your plugin installed, which versions are active, and aggregate error rates from watchdog reports.
Two-way conversation with the MeshDash review team — request clarification, respond to notes, track approval status.
Maintain stable, beta, and deprecated releases. Instances on older versions are notified of updates in their Plugin Manager.
Your name on every plugin card in every Plugin Manager worldwide. Attribution is tied to your account, not just the release.
Private channel to coordinate responsible disclosure updates directly with the MeshDash security team.
MeshDash plugins run inside the server process with access to the database, connected radios, and the network. That's significant trust. The review exists to keep users safe — not to slow down development.
No injection risks, no unsafe subprocess, no credential exfiltration, no calls outside the plugin API.
Required fields, valid semver, safe nav labels, no conflicting route prefixes with core or other plugins.
Installed on a clean instance. Start/stop/restart lifecycle exercised. Routes tested. Watchdog verified.
README must explain functionality, config options, external dependencies, and known limitations.
Start from Hello Mesh — running on your instance right now. Read the developer docs. Set up via the Setup Wizard to get your developer account. The first working plugin usually takes under an afternoon.
Setup wizard account = developer account. No fee. No separate registration.
Development is unrestricted — only store publication goes through review.