sys-mumu

Crates.iosys-mumu
lib.rssys-mumu
version0.2.0-rc.5
created_at2025-08-16 06:45:58.957611+00
updated_at2025-10-07 11:29:19.104612+00
descriptionSystem calls and tools plugin for the Mumu ecosystem
homepagehttps://lava.nu11.uk
repositoryhttps://gitlab.com/tofo/mumu-sys
max_upload_size
id1798062
size89,117
(justifiedmumu)

documentation

README

sys-mumu — System tools plugin for the Lava/MuMu language

Version: 0.2.0-rc.3 Repository: https://gitlab.com/tofo/mumu-sys
License: MIT OR Apache-2.0

sys-mumu is a native (no external binaries) system plugin for the Lava/MuMu runtime. It exposes timestamps, hardware inventory, sensors (temperatures, fans, voltages), fan control, CPU inventory & frequencies, thermal zones, and a streaming watch API that plays nicely with your flow-style code. The public API is stable and namespaced under sys:* with sub-namespaces like sys:hw:* and sys:cpu:*.

This document covers everything in the repository: what it exposes to users, how the data is shaped, the internals that make it work, platform notes, and the legacy/demo assets that remain in the tree.


Table of contents


Feature summary

  • Native, no shell: does not invoke bash, sensors, or any other external program in the plugin’s runtime paths.
  • Linux-first: implements /proc and /sys readers for:
    • hwmon (temperatures/fans/voltages)
    • cpufreq (per-core frequencies)
    • /proc/cpuinfo (per-logical-CPU inventory)
    • /sys/class/thermal (thermal zones)
  • Fan control: PWM duty writes (0..100%) when permitted.
  • Streaming: sys:hw:watch(interval_ms [, filter]) yields an Iterator of sensor rows at a cadence — ergonomic with flow transforms.
  • Stable MuMu shapes: all functions return KeyedArray or arrays (MixedArray) of KeyedArray rows; row shapes are documented below.
  • Extensible: backend registry is pluggable; additional OS backends (macOS/Windows) can register later without changing the user API.

Public API (MuMu functions)

All functions are registered by exact name. Multi-segment names (e.g. sys:hw:info) are supported by the runtime.

Timestamps

  • sys:timestamp_ms() -> long
    Milliseconds since UNIX epoch.

  • sys:timestamp_micro() -> long
    Microseconds since UNIX epoch.

Hardware: info & capabilities

  • sys:hw:info() -> keyed

    {
      vendor:   string,           // e.g., "AuthenticAMD", "GenuineIntel" (best-effort)
      model:    string,           // model name (best-effort)
      family:   string,           // CPU family (best-effort)
      features: [string],         // CPU flags when available
      backend:  "linux-hwmon" | "null"
    }
    
  • sys:hw:caps() -> keyed

    { temps:bool, fans:bool, voltages:bool, clocks:bool, thermal:bool }
    

Hardware: sensors (snapshot)

  • sys:hw:sensors([filter]) -> [keyed]
    Returns a snapshot list of sensor rows. Accepts an optional filter string:

    • kinds: "temp" | "fan" | "volt" | "clock" | "thermal"
    • or a backend name: "linux-hwmon", "linux-thermal", etc.

    Row shape:

    {
      kind:    "temp" | "fan" | "volt" | "clock" | "thermal",
      id:      string,    // e.g., "k10temp:temp1", "nct6798:fan3"
      label:   string,    // human-friendly label when available, else fallback
      value:   float|int, // temps: °C, fans: rpm, voltages: V, clocks: MHz
      unit:    "C" | "rpm" | "V" | "MHz",
      path:    string,    // sysfs path when applicable
      backend: string     // e.g., "linux-hwmon", "linux-thermal"
    }
    

Hardware: fan control

  • sys:hw:fan_list() -> [keyed]
    Lists controllable PWM devices:

    { id:"<chip>:pwmN", label:string, min:int(0), max:int(100), path:string, backend:"linux-hwmon" }
    
  • sys:hw:fan_set(id, percent) -> bool | keyed(error)
    Set PWM duty to percent (0..100). Accepts <chip>:pwmN or an absolute pwmN sysfs path.
    On success: true. On failure (e.g., permission denied):

    { type:"runtime", message:string, id:string, percent:int }
    

Permissions: writes usually require root or suitable udev rules. Reads do not.

Hardware: streaming watch (flow-friendly)

  • sys:hw:watch(interval_ms [, filter]) -> Iterator
    Produces an Iterator that yields the same row shapes as sys:hw:sensors() at a cadence. Between batches, the iterator yields "NO_MORE_DATA" so host poll loops remain responsive. Designed to plug into flow transforms and slog in the REPL.

CPU

  • sys:cpu:info() -> [keyed]
    One row per logical CPU parsed from /proc/cpuinfo. Keys reflect kernel field names; values are auto-typed when possible.

  • sys:cpu:frequency() -> [keyed]
    Per-CPU current frequency (MHz) from cpufreq if present:

    { cpu:int, cur_freq_mhz:float, path:string, backend:"linux-cpufreq" }
    

Thermal zones

  • sys:thermal:list() -> [keyed]
    Thermal zones from /sys/class/thermal:

    { kind:"temp", id:"thermal_zoneN", label:string, value:float(C), unit:"C", path:string, backend:"linux-thermal" }
    

Data shapes & error conventions

  • KeyedArray (implemented with indexmap) is used for all rows and single-object returns (inventory, caps, error objects). Ordering is stable for displays and tests.

  • Errors are returned as standard keyed objects with at least:

    { type:"runtime", message:string, ... }
    

    This crate pins core-mumu 0.8.1-rc.5, which does not define a dedicated KeyedError value, so we use KeyedArray consistently.

  • Streaming semantics: iterators return one item per next_value() when available; otherwise they return "NO_MORE_DATA". This integrates with the REPL/host poller without blocking.


Filters & backends

The optional filter parameter in sys:hw:sensors and sys:hw:watch:

  • If a kind (e.g., "temp"), only rows of that kind are returned.
  • If a backend name (e.g., "linux-hwmon"), only rows from that backend are returned.

Backends included today:

  • Linux hwmon (linux-hwmon) — temperatures, fans, voltages under /sys/class/hwmon/*.
  • Linux thermal (linux-thermal) — OS thermal zones under /sys/class/thermal/*.
  • Linux cpufreq (linux-cpufreq) — per-CPU scaling current frequency.
  • Null backend (null) — present on non-Linux builds; reports empty snapshots.

Permissions & security

  • Read-only APIs (*info, *caps, *sensors, cpu:info, cpu:frequency, thermal:list) typically read world-readable files under /proc and /sys. Missing nodes simply result in missing rows.
  • Fan writes (sys:hw:fan_set) require privileges to write pwm* sysfs nodes. If the write fails (e.g., EPERM), the function returns a keyed error with a helpful message. Typical solutions:
    • run with sufficient privileges
    • add udev rules to grant group write access and run under that group

No public API in this plugin invokes external programs or shells.


Internals & layout

src/lib.rs — registration conduit

  • Exposes Cargo_lock (entrypoint for Lava/MuMu loader).
  • Re-exports modules:
    • pub mod share; — internals, not user-callable
    • pub mod register; — bridges that register the MuMu functions
  • Registers all sys:* functions during Cargo_lock.

src/register/** — user-callable bridges

Each file registers one or more public functions with the interpreter. Bridges validate arguments, call the appropriate helpers under share/**, and return MuMu Value objects.

Bridges in this crate:

  • timestamp.rssys:timestamp_ms, sys:timestamp_micro
  • hw_info.rssys:hw:info
  • hw_caps.rssys:hw:caps
  • hw_sensors.rssys:hw:sensors([filter])
  • hw_fan_list.rssys:hw:fan_list
  • hw_fan_set.rssys:hw:fan_set(id, percent)
  • hw_watch.rssys:hw:watch(interval_ms [, filter])
  • cpuinfo.rssys:cpu:info
  • cpufreq.rssys:cpu:frequency
  • thermal.rssys:thermal:list

All bridges use register::bind_dyn_only to (1) register a dynamic function by name and (2) bind a variable of the same name so calls like sys:hw:info() resolve naturally.

src/share/** — reusable internals

  • watch_iter.rs
    A small engine for periodic producers: spawns a thread that calls a closure at a cadence and pushes produced Values into a channel. A PluginIterator pulls from that channel, returning "NO_MORE_DATA" when empty.

  • hw/backend.rs
    Minimal backend trait and a registry that merges multiple backends (ORs capability booleans, concatenates rows) with a Null fallback.

  • hw/mod.rs
    Owns the global backend registry. On Linux, it installs the linux-hwmon backend at startup and re-exports Linux helpers so bridges can reuse them (e.g., linux_cpuinfo, linux_cpufreq, linux_thermal).

Linux backends

  • linux_hwmon.rs
    Reads /sys/class/hwmon/*:

    • temperatures (temp*_input) — millidegrees converted to °C
    • fans (fan*_input) — rpm
    • voltages (in*_input) — millivolts converted to V
      Discovers PWM (pwmN, pwmN_enable) and exposes fan list/control.
  • linux_cpuinfo.rs
    Parses /proc/cpuinfo into one KeyedArray per logical CPU (auto-typing values). Also provides summarize_cpuinfo() used by hw:info.

  • linux_cpufreq.rs
    Reads cpufreq/scaling_cur_freq per CPU and returns MHz rows.

  • linux_thermal.rs
    Reads /sys/class/thermal/thermal_zone* to provide OS thermal sensors.

Streaming iterator

sys:hw:watch uses share/watch_iter.rs to:

  • spawn a producer thread that samples sensors at interval_ms
  • enqueue rows as Value::KeyedArray
  • expose a PluginIterator that yields one item per call and returns "NO_MORE_DATA" when the queue is empty

This design makes it safe in the REPL and in interpreted runs and integrates with the host’s poll loop (and your flow transforms).


Repository assets (examples & tests)

  • examples/sys-command.mu
    A legacy/demo example showing a shell-based sys:command pattern. The current plugin does not register sys:command (to keep runtime strictly native). This file is kept for historical reference.

  • tests/sys_command_test.mu
    A legacy test that exercises sys:command. Not run by default with this native build; keep it or adapt it behind a feature if you want to exercise shell execution locally.

All other code paths (timestamps, sensors, frequency, thermal, watch) are fully native and ready to use.


Compatibility notes

  • MuMu core: this crate targets core-mumu = "0.8.1-rc.5". That version:

    • exposes KeyedArray but not a special KeyedError; errors here are returned as keyed objects with type:"runtime".
    • does not expose a namespace-reservation API; the plugin simply registers dynamic names and binds matching variables.
  • OS support:

    • Linux: full functionality.
    • Non-Linux: APIs load and return empty arrays ([]) when the platform backends are not available.

Contributing

Bug reports and merge requests are welcome at the GitLab repository. To help us reproduce issues quickly, please include:

  • OS/distro and kernel version (e.g., uname -a)
  • Output of relevant /proc and /sys nodes (paths are reported in every row)
  • The exact sys:* function and arguments used, including any filter
  • Whether the behavior is on snapshot (sys:hw:sensors) or streaming (sys:hw:watch)

We welcome backends for additional platforms (macOS SMC/IOKit, Windows WMI/PDH). The backend trait is intentionally small; feel free to propose extensions.


Acknowledgements

  • Tom Fotheringham (@tofo) — author & maintainer of the MuMu/Lava ecosystem and this plugin.
  • All MuMu/Lava contributors for the interpreter, REPL, and flow tooling that make these bridges a joy to use.

License

Licensed under MIT OR Apache-2.0 (dual). See LICENSE for the full text of each license.


Commit count: 3

cargo fmt