Skip to content

Reference ​

Lookup tables for everything the package installs and everything the two binaries accept. For what any of it means, see the chapter it links to.

Package ​

ItemValue
Debian packagemuxen-synapse
Architectureany, Multi-Arch: foreign
Hard dependenciesmuxen-systemd, muxen-sextant (>= 2.2.0), muxen-sensors (>= 5.0.0)
Recommendedmuxen-boat (>= 9.4.0), muxen-energy, muxen-nmea2000 (>= 3.5.0)
Debian triggersactivate muxen-restart-target; activate-noawait nginx-reload — a running nginx reloads at the end of the transaction, so a changed muxen-ws-synapse.conf is served at once
Lua runtimeLua 5.5, vendored and statically linked — no system Lua needed
Sourcehttps://code.muxen.fr/muxen/brain/synapse

Installed files ​

PathContent
/usr/bin/muxen-synapsedThe daemon
/usr/bin/muxen-synapse-ctlThe operator CLI
/usr/share/muxen-synapse/*.luaTemplate library, read-only
/usr/share/muxen-synapse/fsm.luaThe state-machine module, loaded by the engine at runtime
/usr/share/muxen-synapse/index.jsonGenerated template manifest (metadata + config schemas)
/usr/lib/systemd/system/muxen-synapse.servicesystemd unit
/etc/nginx/snippets/muxen-synapse-templates.confServes the template library over HTTP
/etc/nginx/snippets/muxen-ws-synapse.confMQTT-over-WebSocket proxy at /ws/synapse
/usr/share/bash-completion/completions/muxen-synapsedCompletion for muxen-synapsed
/usr/share/bash-completion/completions/muxen-synapse-ctlCompletion for the CLI

Runtime paths ​

PathAccessContent
/etc/muxen/deploy.jsonread-onlyThe synapse section — the instance list. Owned by the config daemon
/var/lib/muxen-synapse/state.jsonread-writeEnable overrides, snoozes, script state, FSM positions. The only writable path
/usr/share/muxen-synapse/read-onlyTemplate library

systemd unit ​

DirectiveValue
Unit namemuxen-synapse.service
DescriptionMuxen Synapse — Lua automation engine
PartOfmuxen.target
Aftermosquitto.service
WantedBymuxen.target
ExecStart/usr/bin/muxen-synapsed
User / Groupmuxen / muxen (created by muxen-systemd)
StateDirectorymuxen-synapse, mode 0750
Restart / RestartSecalways / 30
TimeoutStopSec20 (above the 10 s onStop budget)

Hardening: NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelModules, ProtectKernelTunables, ProtectControlGroups, ProtectClock, ProtectKernelLogs, ProtectHostname, ProtectProc=invisible, ProcSubset=pid, RestrictRealtime, RestrictSUIDSGID, RestrictNamespaces, LockPersonality, MemoryDenyWriteExecute, DevicePolicy=closed, empty CapabilityBoundingSet and AmbientCapabilities, SystemCallArchitectures=native, SystemCallFilter=@system-service minus @privileged @debug @module @mount @reboot @swap @raw-io @clock @resources, SystemCallErrorNumber=EPERM.

Address families are limited to AF_UNIX AF_INET AF_INET6 and network interfaces to lo — the daemon can only reach a loopback broker when run under the unit.

muxen-synapsed — daemon CLI ​

usage: muxen-synapsed [OPTION]
FlagDefaultMeaning
-h, --helpPrint usage and exit
-v, --verboseoffIncrease verbosity. Repeatable: -v debug, -vv trace. Clamped at trace
-V, --versionPrint the git describe version and exit
--deploy=PATH/etc/muxen/deploy.jsonDeployed-config path
--state=PATH/var/lib/muxen-synapse/state.jsonState file path
--templates=DIR/usr/share/muxen-synapseTemplate library directory
--host=HOST127.0.0.1MQTT broker host
--port=PORT1883MQTT broker port (1–65535)
--prefer-mqtt-timeautoAlways take wall-clock from the boat's system/time
--prefer-local-timeautoAlways use the local system clock

--prefer-mqtt-time and --prefer-local-time are mutually exclusive. The default is automatic: a loopback --host (127.0.0.1, localhost, ::1, unset) uses the local clock, any other host tracks boat time. The resolved source is printed in the startup banner.

Verbosity levels ​

LevelFlagWhat it logs
Normal(none)Errors only — daemon errors and per-script last_error
Debug-vLifecycle, enable/disable, FSM transitions, popups, watchdog aborts
Trace-vvEverything above plus per-message dispatch, timer firings, FSM detail, full Lua tracebacks

Errors always go to stdout, so they appear both at a console and in journald under systemd. Verbosity changes stdout only — it never changes what is published on synapse/….

Signals ​

SignalEffect
SIGTERM, SIGINTGraceful shutdown: persist state.json first, then run onStop for each running instance within the 10 s budget, then exit 0. A second signal is ignored
SIGUSR1Print a one-line-per-instance audit to stdout: run state, effective enabled, consecutive fault count, Lua heap usage, pending popup or last error. Repeatable, no side effects

Exit status ​

CodeMeaning
0Normal shutdown; also -h, -V, and a CLI usage error (usage is printed to stdout and the process exits 0)
1Engine initialisation failed

Environment overrides ​

Read from the process environment. The unit ships every default as an Environment= line mirroring src/daemon/context.h; override them with a drop-in (systemctl edit muxen-synapse). Applied before the command line, so an explicit flag always wins.

SYNAPSE_MQTT_HOST is only useful for another local address: the unit sets RestrictNetworkInterfaces=lo, which silently drops traffic to a remote broker.

VariableOverridesNotes
SYNAPSE_DEPLOY_PATH--deploy
SYNAPSE_STATE_PATH--state
SYNAPSE_TEMPLATE_DIR--templates
SYNAPSE_MQTT_HOST--hostFalls back to MQTT_HOST
SYNAPSE_MQTT_PORT--portFalls back to MQTT_PORT. Ignored unless 1–65535
SYNAPSE_LUA_MEM_MAXper-automation Lua heap ceiling, in bytes0 disables the cap. No equivalent CLI flag

max_runtime_ms is deliberately not overridable from the environment — it is the locked engine-wide cap.

muxen-synapse-ctl — operator CLI ​

muxen-synapse-ctl [--host H] [--port P] [--json] <command> [args]
CommandArguments
list—
debug <id>--what a,b,… (sections: fsm, variables, config, state, wiring, commands)
config <id>—
start <id>—
stop <id>—
restart <id>—
journal <id>-f/--follow, -n N/--lines N (default 50)

Global flags: --host, --port, --json, -h/--help, -V/--version.

Broker resolution: --host/--port → $SYNAPSE_MQTT_HOST / $SYNAPSE_MQTT_PORT → $MQTT_HOST / $MQTT_PORT → 127.0.0.1:1883.

Exit codeMeaning
0Success
1Request timed out (unknown id or daemon down); or start/restart did not reach running; or stop left it running
2Usage error
127journal could not execute journalctl

Timeouts: 2 s to connect, 500 ms to settle retained statuses for list, 3 s for a debug reply, 4 s for a start/stop to be reflected in the status.

Runtime limits ​

Engine-wide, not per-script. These are the locked v1 values.

SettingValueMeaning
max_runtime_ms50Hard cap on one Lua callback's CPU time. Not overridable by a script or the environment
watchdog_check_instructions1000How often the watchdog samples the CPU clock, in Lua VM instructions
status_period30 sHeartbeat interval for republishing every instance's retained status
expireAfterSec60 sFreshness window advertised in each status metadata — twice the heartbeat
default_expire_sec30 sFallback freshness window for a cached device/<fc>/<inst>/{io,state} payload that carries no metadata.expireAfterSec of its own. synapse.variable.get no longer consults it: an app/sensor/<name> payload without metadata.rxTimestamp and expireAfterSec is permanently stale
sextant expireAfterSec3600 sFreshness window for the cached sextant/* topics
fault_threshold5Consecutive callback faults before an instance is auto-disabled. A success resets the count
shutdown_grace10 sAggregate budget for running all onStop hooks on SIGTERM. Kept below the unit's 20 s TimeoutStopSec
lua_mem_max_bytes16 MBPer-automation Lua heap ceiling. Overridable via SYNAPSE_LUA_MEM_MAX; 0 disables
inline script soft cap64 KBA larger inline script warns but still runs
popup timeout300 sDefault when a prompt sets no timeout of its own
MQTT client idmuxen-synapse
MQTT keepalive5 s

deploy.json instance fields ​

Under the synapse object, keyed by instance id.

FieldTypeMeaning
keystring [a-zA-Z0-9-]+Instance id. Unique. Becomes synapse/<id>
templatestringTemplate name (filename without .lua). Mutually exclusive with script
scriptstringInline Lua source. Mutually exclusive with template
configobjectPer-instance tuning, validated against the script's schema
enabledbooleanDeployed default, defaults to true. false is a hard force-off
namestringDisplay name (English), overriding the script's own
name.<LANG>stringLocalised display names, e.g. name.FR, name.ES

state.json structure ​

KeyMeaning
automations.<id>.enabledRuntime enable override; outranks the deploy default but not a force-off
automations.<id>.snoozes.<key>.untilSnooze expiry, ISO-8601, keyed by prompt key
automations.<id>.stateThe script's synapse.state key/value store
automations.<id>.fsm.<name>Current state of each named state machine
automations.<id>.fsmVersionScript version the FSM positions were written under; a change resets them

Config schema field types ​

Declared in synapse.meta{ config = { … } }. Each entry takes key (required) and type, plus optional default, label, description, min, max, options (for enum) and required.

typeValue shapeEngine validation
numbernumberClamped to min/max; coerced from a numeric string
integerintegerAs number, truncated to an integer
booleanbooleanCoerced where unambiguous
enumone of optionsFalls back to the default when not in options
outputIOChannelMust be { deviceId, index }; stored strictly
outputsarray of IOChannelEvery element must be valid; empty array allowed; any bad element falls back to the default
buttonIOChannelAs output — the type is a frontend picker hint
torIOChannelDigital input, read with readTOR
analogIOChannelAnalog input, read with readAnalog
anything elsestringUnrecognised type names are treated as string

An IOChannel is { deviceId, index }, both integers, with deviceId = functionCode × 64 + instance (0–4095) and index the 0-based channel (≥ 0). Extra keys are dropped.

MQTT topics at a glance ​

Full payload shapes in MQTT interface.

TopicDirectionRetained
synapse/<id>engine → allyes
synapse/<id>/commandfrontend → engineno
synapse/<id>/feedbackfrontend → engineno
synapse/<id>/debugrequester → engineno
synapse/<id>/debug/dumpengine → requesterno
synapse/debugrequester → engineno
synapse/debug/dumpengine → requesterno
synapse/validaterequester → engineno
synapse/validate/resultengine → requesterno
app/synapse/infoengine → allyes

Topics synapse reads: app/sensor/<name> (cached), sextant/* (cached), device/<fc>/<inst>/{io,state} (cached), system/time, and anything a script subscribes to. Topics synapse writes: device/<fc>/<inst>/command, plus anything a script publishes.

HTTP endpoints ​

Served by nginx from /etc/nginx/snippets/muxen-synapse-templates.conf.

URLContent
/synapse/templates/JSON directory listing of the library
/synapse/templates/index.jsonTemplate manifest: name, title, description, version, config schema
/synapse/templates/<name>.luaTemplate source, served as text/plain
/ws/synapseMQTT-over-WebSocket proxy to 127.0.0.1:1884

nginx only ever serves this directory; it never writes. Creating an instance from a template goes through the config daemon, which owns deploy.json.

The WebSocket snippet requires map $http_upgrade $connection_upgrade { default upgrade; '' close; } in the surrounding http block, as for /ws/boat.

Both the site that includes these two snippets and that map block are shipped by the boat's UI interface package (muxen-interface-*), one site file per boat. There the two includes carry a trailing *, which makes them optional: a Brain whose interface expects synapse but does not have muxen-synapse installed still passes nginx -t and starts, and /synapse/templates/ and /ws/synapse simply do not exist. So the URLs above are live only on a boat whose interface site includes them and where this package is installed.

Logging ​

Every line the daemon or a script emits carries a tag and an sd-daemon priority prefix, so journald records it at the right level without a libsystemd dependency:

<6>[synapse:<id>] message

Engine-scope lines use the tag [synapse] with no id. synapse.log.debug lines are suppressed unless -v or higher is in effect; every other level is always emitted. In the sandbox, print is redirected to synapse.log.info.

muxen-synapse-ctl journal <id> is journalctl -u muxen-synapse --grep '\[synapse:<id>\]' with -o short-iso --no-hostname.

const.FunctionCode ​

The Lua constants table, generated at build time from libstdmuxen's MUXEN_FUNCTION_* defines in stdmuxen/functions.h. Names match the canonical @muxen/device-id TypeScript enum; the mapping from numeric code to name lives in tools/gen-function-codes.

ConstantCodeConstantCode
Button0CurrentLimiter19
Bloc81WaterMaker20
Hydrogenerator2AirConditioning21
Interconnexion3SFSPReceptor22
PowerGenerator4SFSPSwitch23
Battery5MagicTrim24
PowerConverter6BatterySwitch25
Motor7CGS26
Lighting8Alternator27
Display9ThermalEngine28
SolarPanel10KeelMotor29
WindTurbine11BatteryConcentrator30
NavigationInstruments12BusExtender31
ImocaKeelTeam16BowThruster32
GenericIO17
BlinkKeypad18

Codes 13–15 are reserved (internal IMOCA keel) and are never emitted. A constant appears only when libstdmuxen's header actually defines that code, so the installed table is the intersection of this mapping and the header.

The table and const itself are read-only proxies: every assignment raises (const.FunctionCode is read-only), existing names included; an unknown name reads as nil; pairs() yields every constant. See Lua API reference.

SFSPRecepter (22) is a deprecated alias of SFSPReceptor, kept in the table so scripts written before @muxen/device-id 9.5.1 renamed the member keep working. Use SFSPReceptor in new scripts. Deprecated aliases are listed in k_deprecated_aliases in tools/gen-function-codes.

Integration of multiplexed solutions
MUXEN and the MUXEN logo are trademarks of MUXEN SAS.