VE6SLP / Projects

MeshCore shared-radio firmware · In development

One radio.
Several useful mesh services.

Run a repeater, room server, companion and programmable bot through one LoRa radio. Each role keeps its own identity and state. Put the roles on a Seeed XIAO ESP32-S3 with PSRAM and Wio SX1262, or run them on a Go host connected to the shared modem.

One frequency, one radio profile, one airtime budget. Independent identities do not turn a single radio into several RF channels.

Start with the node you want to build

The primary platform is the Seeed XIAO ESP32-S3 with PSRAM + Wio SX1262. Use the combined firmware for a standalone node, or keep applications on a host where they are easier to extend. The XIAO nRF52840 has a smaller native repeater-and-bot option. SX1261 is outside the current hardware targets.

Run these commands from a source checkout. Use the setup guide for your hardware before uploading an image.

Standalone ESP32

Leave the computer at home

Run selected roles and Lua commands on the ESP32. WiFi provides companion TCP, the dashboard and browser administration; local RF roles continue through WiFi loss.

make onchip-config
$EDITOR firmware/platformio.onchip.ini
make onchip-firmware

These commands build the base combined image. Choose the management/Lua or HTTPS profile below for an editable command bot.

Standalone build and flashing guide →

Shared modem + Go host

Run your services on a host

Flash the WiFi KISS modem, then select repeater, room, companion, observer and bot services in the host configuration. The native Lua worker uses the same runtime as the ESP32.

make firmware-config
$EDITOR firmware/platformio.local.ini
make firmware

make host-config
$EDITOR meshcore-host.json
make host-run
Modem, upload and host setup →

XIAO nRF52840 + Wio SX1262

A smaller native node

Run a native repeater and separately addressed command bot, with persistent private notes and optional PIN-protected BLE. This target runs native commands rather than the Lua runtime.

make -C firmware/nrfmast build

The default nrfmast_rx build disables physical transmission. Choose ENV=nrfmast for the RF-capable image after configuring the node.

nRF hardware and provisioning guide →

Before flashing: set a legal local radio profile, WiFi settings and separate administrator/room credentials. Select the exact device and follow its flashing guide. ESP32 filesystem provisioning erases SPIFFS role and bot data; it is a separate step from an application update. Keep identity material and scoped backups private.

After setup, the WiFi modem serves KISS on 8001. A companion application connects to the configured companion endpoint on 5000, not the KISS port. The management-enabled ESP32 serves its dashboard at / and authenticated controls at /admin. The Go host exposes status at http://127.0.0.1:9080/status.

What this adds to MeshCore 1.17+

MeshCore already supplies repeater, room and companion behaviour, encrypted messaging, routing, telemetry and native protocols. This project builds on that foundation: several independent roles and application runtimes share one physical radio, with a common scheduler and operator controls.

MeshCore foundations and the shared-radio additions
MeshCore foundationWhat changes here
Repeater, room and companion rolesCo-locate selected roles on an ESP32 or Go host. Give each role a durable identity, settings and application state rather than switching the whole radio between roles.
LoRa reception and transmissionOne modem owns tuning and arbitrates queued transmissions from multiple roles and KISS clients. It distributes received packets and accounts for the shared airtime.
Native messages, encryption and routingReuse ordinary MeshCore packet behaviour so other radios can exchange adverts, DMs, room traffic and routes. Management and package transfers travel through normal repeaters.
Companion applicationsOffer companion-v13 TCP sessions and independent bot endpoints while retaining one base identity for clients attached to the same companion.
Role administrationAdd shared-node role selection, identity lifecycle, saved/applied settings, radio policy and an authenticated browser/RF management backend.
Application extensionsAdd bounded Lua programs and an optional Wasm interpreter, scoped persistent data, asynchronous mesh/network operations, resumable package installation and recovery. Lua and Wasm can share one bot identity and its native permissions.

Where the project stands

This is evolving development firmware. Shared-radio operation, the principal roles and the Lua runtime are operational. Browser administration, configured HTTPS/host TLS, file-backed scheduler storage, WiFi recovery and local Lua development are implemented in main. Host bots support owner-controlled grants and clock-aware durable scheduling; nRF nodes retain private notes in external flash. ESP32 repeater/room password recovery is available through encrypted RF management. The official Android app can administer configured ESP32 and host repeater/room roles.

The optional Wasm interpreter, C/Rust SDK and independent Lua/Wasm package lifecycle are implemented in main for ESP32 and native host builds. Linux native-host Wasm commands operate over RF alongside Lua, with source selections and private notes retained across restart. ESP32 Wasm execution/deployment, TLS binary-fetch checks and guest timing/instruction measurements remain in progress. A lab check with a private test TCP-to-BLE bridge covered the nRF bot's identity display, contact sync and acknowledged DMs over RF; direct phone BLE connection, including scanning and PIN entry, remains to be checked.

  • Implemented Available in main for the listed platform/profile; some capabilities require configuration or an operator grant.
  • In progress Active implementation or a named integration step that is still unfinished.
  • Planned A future capability, not available in the supported main builds.

Feature snapshot: . “Host” below means the Go host; its native worker retains the configuration name native_lua with or without Wasm compiled in. “nRF” means the XIAO nRF52840/Wio SX1262 native variant. A listed platform does not imply the feature is present on the other platforms.

Choose the firmware profile

Implemented setups and public build/profile names
SetupBuild or serviceWhat runs there
ESP32 WiFi modemXiao_S3_WIO_kiss_wifiShared SX1262, KISS clients and radio dashboard. Roles and applications run on the connected host.
ESP32 combined rolesXiao_S3_WIO_onchipRepeater, room, companion and optional read-only observer beside the shared modem.
ESP32 Lua and managementXiao_S3_WIO_onchip_bot
Xiao_S3_WIO_onchip_beta
The bot profile adds Lua with RAM-only custom activation; it returns to bundled handlers after restart. Choose beta or HTTPS for authenticated RF/web management, durable source installation and rollback.
ESP32 configured HTTPSXiao_S3_WIO_onchip_httpsManaged Lua node with an outbound TLS connection reserved for approved services and package fetch.
Go host + shared modemGo role services; optional native_lua workerIndependent roles and bot connections over KISS. Native Lua/HTTPS uses a Linux C/C++ worker with OpenSSL and the documented native dependencies. The Linux x86-64 worker build can also include Wasm under the same bot identity.
nRF native nodenrfmast_rx
nrfmast
Native repeater and bot, notes and optional BLE. The first profile is receive-only; the second is RF-capable. No production Lua or Wasm runtime.
Role on a separate boardPHY-less ESP32 TCP / nRF UART variantsAttach a role to a separate shared modem over WiFi TCP or wired UART. These boards use the modem's radio rather than adding a channel.

External KISS socket capacity is profile-dependent: commonly eight for radio-only, four for the combined mast, and three for the HTTPS mast. The host queries capacity; plan extra role and bot connections against the selected build.

Choose the runtime at build time: bot-enabled ESP32 and native-worker Make builds default to ONCHIP_BOT_WASM=1. Set ONCHIP_BOT_WASM=0 for Lua without the Wasm dependency, symbols or runtime pool. Check source api runtimes on the installed node before uploading. The build-selection guide covers matching profiles and preparation.

ESP32 flash and memory

Use an ESP32-S3 with 8 MiB flash and PSRAM for the combined node. The shared partition layout provides 3,342,336 bytes per application slot; the inactive OTA slot is reserved for updates, not extra space for the running image.

Measured build baseline: , source 45f6f4f, public profiles. Application BIN sizes exclude the separate bootloader and filesystem contents.

ESP32 application flash by build profile (bytes)
ProfileApplication BINFree in app slot
WiFi KISS modem1,148,9442,193,392
Native roles, no command bot1,236,7682,105,568
Lua bot, Wasm off1,495,9361,846,400
Lua + Wasm bot1,600,0481,742,288
Admin + Lua, Wasm off1,648,1601,694,176
HTTPS/admin + Lua, Wasm off1,821,6801,520,656
HTTPS/admin + Lua + Wasm1,915,0241,427,312

On the matched Xiao_S3_WIO_onchip_https profile, enabling Wasm adds 93,344 bytes to the application BIN. Choose ONCHIP_BOT_WASM=0 when that interpreter is unnecessary. Runtime role masks change which roles start, not which code occupies flash. The native no-command-bot image omits Lua; a Wasm-only, Lua-free bot build is not supported.

Runtime memory is a separate budget

WAMR allocates its 1 MiB PSRAM pool lazily when a Wasm load reaches interpreter initialization. After successful runtime initialization, that pool stays reserved through module removal and worker stop until device restart. Each Wasm instance also needs a separate 64 KiB linear-memory allocation outside the pool.

Lua's 96 KiB per-state allocator limit is a cap, not a preallocated reservation. Active and recovery states have separate caps; native session metadata is additional, and source validation can temporarily add more states. Task stacks, radio and WiFi/TLS allocations also use internal RAM. Check internal RAM, PSRAM and stack usage under your intended workload rather than treating free flash as runtime headroom. The resource-budget guide details allocation lifetimes and the measured profiles.

Feature matrix

These groups cover the radio, roles, applications, storage and management additions. Each row names the applicable platform and the behaviour an operator or application author can use.

On narrow screens, scroll each table horizontally. Table regions can also receive keyboard focus for scrolling.

Shared radio and connections

One physical modem, multiple sources
FeatureStatus / platformBehaviour and practical limits
Shared PHY authorityImplemented
ESP32 + host
The modem applies one frequency, bandwidth, spreading factor, coding rate and transmit power. On a managed node, authenticated management owns changes; ordinary roles cannot silently retune it.
Queued transmission and airtime controlImplemented
ESP32 + host
Sources share a bounded TX queue, physical scheduling, aggregate airtime and source limits. Queue admission is separate from confirmed physical transmission.
Receive fan-out and local reflectionImplemented
ESP32 + host
RF receptions reach subscribed clients. Local sends reach the other local roles, excluding the sender, and are tagged as local reflection rather than measured RF reception.
TX outcomes and reconnect fencingImplemented
ESP32 + host
Report success, failure and unknown transmission outcomes. Reconnection or a changed radio generation does not automatically replay an uncertain packet. A successful TX is not a delivery ACK.
Ordinary KISS and negotiated MKISSImplemented
ESP32 + host
Multiple ordinary KISS clients can coexist. MKISS carries four logical ports, including the controller, over one TCP connection. Extra roles use direct sockets; fallback to separate links must fit reported capacity.
Host PHY following and role overlap reportingImplemented
Host + ESP32 modem
The host can follow modem-owned settings or require a fixed profile. It reports overlapping roles/identities; running two repeaters still needs an operator decision about duplicate forwarding and airtime.
Ordinary path hashes and native TRACEImplemented
ESP32 + host; native nRF paths
Configurable three-byte ordinary originated hashes with legacy incoming paths accepted. TRACE uses its separate native 1/2/4/8-byte width format; there is no three-byte TRACE mode.
WiFi association/IP recoveryImplemented
ESP32
Retry AP association and DHCP, retire old TCP sessions, and restore listeners, HTTP availability and mDNS. RF roles, identities, saved PHY and companion replay history remain. Clients reconnect rather than replaying writes.

Roles, identities and native applications

Independent application state on a shared node
FeatureStatus / platformBehaviour and practical limits
Selectable co-located rolesImplemented
ESP32 + host
Repeater, room, companion/base, read-only MQTT observer and bot connections can share the modem. The combined ESP32 runs at most one of each built-in role. Disabling optional roles leaves the shared radio and management available.
Independent durable identitiesImplemented
ESP32 + host; nRF native roles
Roles retain separate keys, names and applicable preferences/messages. Multiple companion clients on one endpoint share that endpoint's base identity, not a new identity per phone.
Native repeater, room and companion behaviourImplemented
ESP32 + host
Reuse MeshCore routing, encrypted messages, room authentication/membership/history, path discovery and telemetry. The addition is co-location and separate management/state, not a new over-air messaging protocol.
Companion-v13 TCP sessionsImplemented
ESP32 + host
Connect ordinary companion clients, including multiple sessions on one base. Official Android 1.50.0 supports TCP connection, bot DMs, telemetry, discovery and app reconnection.
Official-app role administrationImplemented
Android + ESP32 / host
With configured role credentials, the official app opens repeater/room administrator screens, reads native status and settings, and sends room messages over RF. The Go companion accepts a corrected login to the same role immediately, without waiting for the earlier unanswered login to expire. Management and room guest credentials remain separate.
Independent bot endpointsImplemented
Host
Use a separate bot companion endpoint, a KISS bot proxy, or the shared native Lua worker. An independent Python bot can coexist without taking the base identity.
Runtime names, rekey and identity importImplemented
Managed ESP32 + host
Change durable names and use authorized identity controls without rebuilding. The host's protected owner Unix socket coordinates native-bot rekey without restarting other roles. Original scoped data remains tied to the old full key.
Saved versus applied configurationImplemented
Managed ESP32 + host
Inspect saved selections, running state, policies and grants. The host bot's protected owner Unix socket manages home, shared, reminders and events, with help/status readback. Saved grants survive worker restart. Owner cancel stops running jobs, not personal reminders. A setting may require explicit apply/reboot; role-local permissions do not implicitly authorize shared-radio administration.

Lua runtime and application APIs

ESP32 and the production host worker run actual Lua 5.5.1 with the same command, storage and mesh API. A custom command can be as small as this; native code validates the caller and arguments before invoking it:

function hello(name)
  reply("Hello " .. name)
end

After installing it, send !hello Alex to the bot. Try the supplied template locally first, then follow the runtime API guide for signatures, permissions and limits.

Implemented in ESP32 Lua profiles and the host native_lua worker
FeatureStatus / platformBehaviour and practical limits
Source compilation and named commandsImplemented
ESP32 + host Lua
Compile source locally; exported named functions become commands. Optional command(...) declarations add typed schemas, help, examples, permissions and aliases. The editable source/package envelope is 4,096 bytes.
Retained environment and local modulesImplemented
ESP32 + host Lua
Cooperating functions share a retained environment and declared package-local modules. Globals reset on restart or source replacement; explicitly durable data remains. The installer replaces one custom command/module set, not arbitrary independent packages.
Cooperative asynchronous jobsImplemented
ESP32 + host Lua
Yield while waiting for storage, a timer, mesh traffic or HTTPS. Other accepted commands continue locally. Bounded job slots and native mailboxes prevent unbounded work.
Execution limits and recoveryImplemented
ESP32 + host Lua
Instruction, active-time, parser, heap and native-operation budgets constrain programs. Source generations and grants cancel stale jobs/results; recovery diagnostics remain available after custom-code failure. Functions within the custom set share a VM, not separate sandboxes.
Context, replies and native draftsImplemented
ESP32 + host Lua
ctx, reply, mesh.compose and mesh.send provide caller-bound DM, verified-channel and native TRACE operations. Native code owns keys, timestamps and packet encoding; scripts do not inject arbitrary radio bytes.
Mesh waits and route diagnosticsImplemented
ESP32 + host Lua
mesh.wait, mesh.trace and mesh.multitrace provide bounded TX/ACK/text/TRACE continuations and filtered follow-ups. A received ACK, physical TX completion and application reply are distinct outcomes.
Granted destinations and forwardingImplemented
ESP32 + host Lua
Owner-granted full-key DM destinations and mesh.forward support bounded pair-DM forwarding with attribution, expiry and loop checks. This re-originates an authorized message; it is separate from native repeater transit forwarding.
Events, timers and utilitiesImplemented
ESP32 + host Lua
events.on registers startup, connectivity, message and node-status handlers under grants/capacity. timer.set/get/cancel/wait, reminder.after/list/cancel, utility.calc/convert/roll/choose and node.report cover bounded scheduling and diagnostics.

Optional Wasm alongside Lua

Compile small C or Rust programs into portable Wasm modules for the ESP32-S3 with PSRAM or the Linux x86-64 native host worker. One Lua package and one Wasm package share the bot's identity, permissions, durable scopes and physical radio source. On the native host, C/Rust arithmetic, private notes and built-in home echo respond to authenticated RF requests alongside Lua. Manage host packages through the protected owner Unix socket; ESP32 execution and remaining network/resource checks are in progress.

Implemented in Wasm-enabled ESP32 and native host builds
FeatureStatus / platformBehaviour and practical limits
Optional WAMR interpreterImplemented
ESP32 with PSRAM + native host
WAMR 2.4.1 executes modules in an interpreter, without JIT, AOT, WASI or guest threads. The compile-time flag includes or omits the runtime. Compiling it out preserves stored Wasm packages; re-enabling it restores that runtime's last selection.
Portable C/Rust SDK and ABI v1Implemented
ESP32 + native host Wasm
The versioned meshcore_v1 ABI provides command registration, event subscription, copied context/results, replies and asynchronous native operations. C/Rust examples cover arithmetic, private notes and configured RPC. Use the same module on host and device; each complete package, including metadata, is limited to 4,096 bytes.
Independent Lua/Wasm package lifecycleImplemented
Managed ESP32 + native host Wasm
Keep one whole package per runtime, with eight Wasm commands alongside eight custom Lua commands. Install, update, read back, roll back, remove or retry each runtime separately; conflicting command names are rejected. Host Lua/Wasm source selections and scoped notes survive restart. Updating either runtime cancels pending jobs in both to fence shared I/O, while preserving the other VM and durable data. An arbitrary multi-package registry and Wasm module linking are outside this model.
Shared native APIs, grants and eventsImplemented
ESP32 + native host Wasm
Use scoped KV/CAS/transactions, timers/reminders, mesh send/wait/TRACE/forwarding, utilities, approved HTTP/JSON/RPC and event delivery through the same native grants and quotas as Lua. Both runtimes receive subscribed events. Applications cannot obtain credentials or use owner APIs to set passwords, import private keys or upload bulk source/data.
Execution limits and fault isolationImplemented
ESP32 + native host Wasm
Bound each invocation to 10,000 instructions, 20 ms active execution, 64 native calls and eight yielded operations across resumptions. Guest memory is one 64 KiB page. Both runtimes share four job slots, including one reserved for native diagnostics. Runaway Wasm traps leave Lua and native management available. ESP32 uses PSRAM for Wasm allocations; its 1 MiB shared interpreter pool is allocated on first load and retained until restart.
Binary package installationImplemented
Managed ESP32 + native host Wasm
Manage native-host packages through the protected owner Unix socket: install, read back, resume interrupted uploads, update, roll back, remove and reinstall. Approved HTTPS fetch requires the expected SHA-256 and normal package/interpreter validation. The web page selects a binary file without replacing the Lua editor's draft. Lifecycle CLI operations use --runtime wasm; omitting it selects Lua. ESP32 RF/web installation and running-host/ESP32 TLS binary-fetch checks remain in progress.

Useful commands without writing a program

Send the bot !ping, then !help. Use !help remember for a note command's arguments and example. Help lists commands available to your current context; missing, extra or invalid arguments name the affected command and point to its help. Long help has numbered continuation pages.

Bundled command families on ESP32 and host Lua bots
CommandsStatus / platformWhat a user can do
!ping, !help, !testImplemented
ESP32 + host Lua
Get a reply, discover commands and inspect the received connection/path/signal. Local reflection is explicitly identified rather than given an invented RSSI.
!calc, !convert, !roll, !chooseImplemented
ESP32 + host Lua
Evaluate bounded calculations, convert units and make random selections. Stateless utilities can also run in opted-in channels.
!about, !version, !uptime, !status, !signal, !airImplemented
ESP32 + host Lua
Read identity/build, uptime, readiness, measured signal and shared airtime/queue diagnostics. Missing sensors and unavailable readings are reported directly.
!path, !trace, !mtImplemented
ESP32 + host Lua
Inspect received ordinary paths, request a native direct TRACE, or collect observed copies with !mt. Native TRACE widths and bounded collection windows still apply.
!remember, !recall, !forget, !notes, !list-memoriesImplemented
ESP32 + host Lua
Keep persistent personal notes through authenticated private DMs. Full sender and bot keys select the private scope; a display name does not.
!remind, !reminders, !cancelImplemented
ESP32 + host Lua
Schedule private-DM reminders that survive reboot. Sending requires an owner grant, trusted time and a refreshed direct route, and is allowed only from the deadline through 60 seconds afterward. Later reminders are durably marked overdue and not sent. A durable claim permits one send attempt; transmission is not confirmed delivery.
!boardImplemented
ESP32 + host Lua
Share durable state in an operator-enabled, verified channel. Every holder of the channel secret may write; a nickname or DM cannot select somebody else's channel board.
!weather, !service health|echo|weatherImplemented
ESP32 HTTPS + host Lua
Call an approved reference service from an authenticated private DM. Network access needs configuration and a grant; local commands remain available while the service request waits.
Zero ordinary command cooldownImplemented
ESP32 + host + nRF
No fixed pause between ordinary commands. Available job/packet slots, one-inflight constraints, queue limits and radio airtime still govern admission. HTTPS request limits and nRF persistent-note write budgets are separate.

Persistent data and memory

State survives deliberately, within explicit quotas
FeatureStatus / platformBehaviour and practical limits
Scoped durable key/value dataImplemented
ESP32 + host Lua
kv.get/put/delete/list provides bot, authenticated caller, conversation and verified-channel scopes. Full bot/principal identities keep private data separate through name changes, source updates and restart.
Atomic updates and compatible migrationsImplemented
ESP32 + host Lua
Compare-and-swap and kv.transaction support cooperating handlers and bounded schema migrations. Explicit schema/rollback compatibility preserves the previous representation rather than silently converting it destructively.
File-backed KV and scheduler stateImplemented
ESP32 + host Lua
Checked KV file groups and double-buffered timer/reminder files hold larger payloads, with compact commit records and caches. Host private notes, pending timer deadlines/revisions and personal reminders survive worker restart. Pending reminders resume with trusted time and a fresh direct route only when no more than 60 seconds past their deadline. Later pending timers/reminders are durably marked overdue, without a timer claim or reminder transmission. Downtime, disabled reminders and lost trusted time do not extend this window. Consumed claims remain consumed. Linux scheduling requires kernel-synchronized time within a two-second uncertainty bound; clock steps or lost trust pause dispatch. HTTPS has a separate clock-acceptance check.
Scoped export and restoreImplemented
ESP32 + host Lua
Export or restore KV, timers and reminders by scope. Scheduler restores require no-rearm semantics: restoring an older pending snapshot leaves already-sent reminders sent and cancelled timers cancelled. Families restore separately; inspect readback after an uncertain outcome.
ESP32 memory tiers and contactsImplemented
ESP32 with PSRAM
Keep radio/TLS-critical allocations in internal memory, use PSRAM for VMs/caches/larger role state, and verified SPIFFS files for durable payloads. The PSRAM companion supports 256 contacts.
Host native private filesystemImplemented
Host native Lua
A bounded private state directory provides the native storage adapter: 128 KiB aggregate, 32 files and 32 KiB per file. These larger record limits do not increase the 4 KiB Lua source limit or grant scripts arbitrary filesystem access.

Configured HTTPS, JSON and host services

Approved services, with credentials outside Lua
FeatureStatus / platformBehaviour and practical limits
HTTP GET/POST and named RPCImplemented
ESP32 HTTPS + host Lua
http.get, http.post and rpc.call address operator-configured aliases/operations. Four endpoint aliases and eight RPC mappings are available. Plugins cannot choose arbitrary URLs, headers or redirects.
Bounded JSON utilitiesImplemented
ESP32 + host Lua
json.encode, json.decode, json.null and json.array preserve typed data with size/depth checks. Network requests allow 1 KiB JSON and responses 2 KiB.
Verified TLS and protected credentialsImplemented
ESP32 HTTPS + host Lua
Verify CA, hostname and certificate dates against trusted time; pin the approved destination address. Bearer credentials stay outside Lua. Provision secrets through encrypted authenticated RF or the protected host Unix socket, not plaintext HTTP.
Async network admission and outcomesImplemented
ESP32 HTTPS + host Lua
One HTTPS connection serves bounded asynchronous mailboxes. A 15-second deadline includes queue time. The network grant is private-DM-only, capped at two requests/caller and four globally per minute. Post-send failures may be unknown and are not automatically replayed.
Reference services and optional computeImplemented
Host service + approved bot clients
Run health, echo and weather services. Optional sum/digest operations are fixed, opt-in computations, rather than arbitrary remote code execution. Native host transport uses OpenSSL.
Expected-hash package fetchImplemented
ESP32 HTTPS + host Lua
Fetch source from a fixed approved package endpoint with an expected SHA-256. Normal metadata, compile/init, journal and activation checks follow. The host retains the activated source across worker restart. A bad hash or rejected update leaves current source and data intact.

Start with the network API setup and reference service guide. Configure only the endpoints and operations the node needs.

Program installation and node administration

Owner controls share the native management backend
FeatureStatus / platformBehaviour and practical limits
Authenticated resumable RF source uploadImplemented
Managed ESP32 + owner tooling
Upload through normal MeshCore repeaters, including multi-hop routes. Resume interrupted/rebooted transfers and read the source back exactly. Installation uses provisioned management trust and the 4 KiB source envelope.
Package metadata and staged activationImplemented
ESP32 + host Lua tooling
Check manifests, runtime/API capabilities and schema compatibility; compile and initialize a candidate before activating it. Package tooling supports optional signing checks. Rejected candidates leave running source/data intact.
Rollback, recovery and lifecycle fencingImplemented
ESP32 + host Lua
Restore the previous compatible custom set, return to bundled commands, retry a durable selection or quarantine failed code. Source/grant generations discard obsolete work without resetting unrelated role identities.
Authenticated browser administrationImplemented
Managed ESP32
/admin provides role/radio controls, Lua editing/upload/resume/install, separate Wasm binary controls when compiled in, rollback/recovery, scoped backups, diagnostics and grants. Sessions expire; controls distinguish pending, applied and unknown outcomes.
Safe handling of interrupted admin requestsImplemented
Managed ESP32 web UI
Retain the editor draft within the open page and do not automatically replay writes after reconnect. Read status before repeating an uncertain install/restore. Download drafts before closing the tab.
RF administration and runtime credentialsImplemented
Managed ESP32; host owner socket
RF management has separately provisioned trust and works without WiFi. An authorized ESP32 Management owner can replace an active repeater or room administrator password through authenticated encrypted RF, using the CLI's private credential-file input. Web, local bot-owner sockets and application runtimes cannot perform role-password recovery. It preserves identities, routing, guest access and existing administrator ACLs/sessions; changing the password does not revoke those sessions. Management-password and service-secret controls remain separate.
Persistent and timed temporary tuningImplemented
Managed ESP32; native nRF admin
Authorized radio changes affect every co-located role. Timed temporary settings return to the durable profile. Retuning can interrupt RF management, so retain a recovery route.

Keep device administration on a trusted LAN. The ESP32 dashboard/admin listener uses HTTP, not device-served HTTPS; passwords, sessions and downloaded backups need a protected network or authenticated TLS tunnel. Do not expose it directly to the Internet. Outbound verified HTTPS for bot services is a separate capability. The MeshCore mobile app remains the ordinary chat, repeater and room interface.

The smaller nRF native node

XIAO nRF52840 / Wio SX1262, also known as the Pine variant
FeatureStatus / platformBehaviour and practical limits
Native repeater + command botImplemented
nRF
Two identities share one radio without WiFi, a host process or scripting. Native routing and encrypted administration remain available alongside !ping, !help, !signal and !path.
Persistent authenticated personal notesImplemented
nRF
!remember, !recall, !list and !forget: four notes/user, sixteen/device, 96-byte values and eight durable full-key principal scopes. A 512 KiB external-QSPI rotating journal keeps notes private to their full-key scopes across restart, including retained replay timestamps after deletion. Write-attempt bursts are 32/device and eight/principal; each budget refills one credit per 15 seconds of device uptime. Failed commit attempts also spend credit; reads do not. Busy/budget rejection precedes mutation. Notes remain plaintext in flash.
Secured companion-v13 BLEImplemented
nRF
Nordic UART BLE reuses the bot identity. It stays off until a six-digit PIN is provisioned. Bidirectional DMs, reconnecting with the same bond and repeater forwarding work together. Bonds clear at boot so saved PIN changes take effect; pair again after restart. Physical phone UI integration remains in progress.
Bounded BLE contacts and messagingImplemented
nRF
Eight RAM contacts, four incoming messages and one normal outgoing DM awaiting ACK. Native remote login/status and clock/name operations are supported within permissions. Contacts and inbox need rebuilding after restart.
Restricted BLE authorityImplemented
nRF
BLE cannot change shared PHY settings, import/export private keys or factory-reset the node. Pairing does not grant repeater administration. No production Lua or Wasm runtime is supplied on this platform.

In a lab check, the official MeshCore 1.50.0 Android app in an emulator showed the nRF bot's identity, synchronized contacts and exchanged acknowledged DMs in both directions with an independent companion over RF. The connection used a private test TCP-to-BLE bridge. Direct phone BLE connection, including scanning and PIN entry, remains in progress.

Provisioning an occupied external volume: the USB owner must explicitly retire the old external filesystem before initializing the note region. Retired files may be lost and that filesystem must no longer be used. Provisioning preserves current InternalFS identities/configuration and imports checked notes and principal replay timestamps. Follow the nRF provisioning guide; an interrupted operation leaves notes disabled until owner recovery.

Monitoring and developer tools

Inspect the node, then extend it
FeatureStatus / platformWhat it provides
Serial/TCP KISS monitorImplemented
Host tool + KISS modem
The project's original tool configures the modem and decodes frames to stdout. Use it independently of the full role stack.
Radio dashboard, status and readinessImplemented
ESP32 + host
Read role state, physical connectivity, RF counters, heap, queue and airtime diagnostics. Host status/readiness exposes the selected services.
Read-only MQTT observation and metricsImplemented
ESP32 + host; ESP32 metrics publisher
Observe packet events without creating a transmit bus. Optional configured ESP32 metrics publishing uses native HTTPS; it remains separate from Lua service requests.
Package CLI, examples and native replayImplemented
Developer host
make bot-local runs source and JSON scenario assertions in the native Lua runtime. Supplied examples cover permissions, scoped state, async work and failure outcomes. Owner replay uses real MastAdmin trust and full-key request admission. Package tools handle validation, installation, fetch and rollback.

Run a Lua command before uploading

From the repository root, run the supplied template's success and argument-error checks:

make -s -C firmware/onchip bot-local \
  SOURCE=firmware/onchip/plugins/template.lua \
  SCENARIO=firmware/onchip/plugins/examples/hello.scenario.json

Expect PASS 4 native replay assertions on stderr, JSONL records on stdout and a zero exit status. An unexpected reply or failed assertion makes the command fail. The first build fetches the pinned dependencies; replay itself uses an in-memory radio and socket-free network fixture, so it neither transmits RF nor calls a live service.

The local @restart directive recreates the fixture and restores its source through the actual source journal. NVS/filesystem state stays in memory within the runner process; disk persistence and physical power-loss checks are separate. Follow the local Lua development guide for build dependencies, your own scenarios and the package/install workflow.

Build a portable C/Rust command

Use Clang 21.1.8 with wasm-ld 21 and Rust 1.96.0 with the wasm32-unknown-unknown target. From the repository root, build the supplied examples and run their native integration checks:

make -C firmware/onchip bot-wasm-examples
make -C firmware/onchip bot-wasm-integration-test

The Wasm package workflow covers the SDK, compiler setup, packaging and authenticated installation. These local commands do not flash or transmit. Examples include !wadd 40 2 and !radd 40 2, which reply 42 after installation; RPC examples additionally need the configured service and network grant.

In progress and planned

Native-host Wasm RF commands, owner-socket package management and Lua coexistence are operational. Remaining Wasm work covers network and execution measurements on the host, plus ESP32 execution and deployment. Choose a build with the required runtime and inspect the installed node's capabilities before transferring a package.

Remaining work and future options, separate from implemented features
Feature / next outcomeStatus / targetWhat remains
Remaining Wasm network and device checksIn progress
ESP32 + native host
Complete successful approved TLS binary package fetch, in-flight cancellation, offline service behaviour and guest execution timing/instruction-count measurements on host and ESP32. ESP32 also needs physical Wasm execution/fault checks, RF/web binary installation and interrupted-transfer recovery, internal-memory/PSRAM/radio-timing measurements, and image checks with Wasm enabled or compiled out.
WiFi recovery under physical network lossIn progress
ESP32 integration
Exercise AP/IP loss and recovery with active radio and client workloads. Automatic recovery itself is implemented in main.
Physical-phone BLE scanning and PIN UIIn progress
Android device + nRF
Complete the phone's own BLE discovery, pairing/PIN entry and resulting connection flow. A lab check through a private test TCP-to-BLE bridge covered the official app's bot identity display, contact sync and bidirectional acknowledged DMs over RF. Same-bond BLE reconnect and concurrent repeater forwarding remain available.
ESP32 package and scheduler restart integrationIn progress
ESP32
Finish on-device expected-hash package fetch, source reactivation and nonempty timer/reminder state across restart, alongside other roles. General HTTPS GET/POST and named RPC work; host durable scheduling and package restart are operational.
Adaptive airtime throttlingPlanned
Shared-radio bot scheduling
Adjust per-user admission to network load and airtime. Current queue/capacity/airtime limits work independently of this future adaptive policy.
Companion-assisted bulk transferPlanned
Companion + shared modem
Coordinate a temporary faster radio mode with the other endpoint for larger transfers. Existing timed temporary tuning still moves the single radio off its normal profile.
Additional administration clientsPlanned
Companion / mobile tools
More convenient companion-assisted or iOS administration, including carrying owner requests through a BLE-connected companion radio. The ESP32 browser admin is already implemented.
Multiple instances of one on-device rolePlanned
Possible ESP32 follow-on
Consider more than one room, repeater or companion instance if demand and measured resources justify it. Current combined builds select at most one of each.
Scripting on nRFPlanned
Possible follow-on / feasibility
Evaluate whether a useful bounded Lua runtime fits beside native roles. A resource probe exists, not a production scripting environment; no nRF Wasm target is promised.

Build, run or extend a node

Start with the setup guide for your platform, then use the focused references for wiring, protocol details and operating limits. When reporting a problem, include the build/profile, role selection and a description of the observed result; remove credentials, private keys and private endpoint details.