Building “arbitrary machines” with Rust

I would like to give a progress report on the project I have been working on for the past 10 years.

It starts from “arbitrary automations” for IoT and evolves into “machines for Internet of Everything.”

The idea is that any data exchange for a process (configuration time and runtime) must have all data schemas published beforehand.

Configuration schema

The configuration schema defines the process’s entry function arguments. For example, a sprinkler controller may require the following data from the user.

  • The water valve device of a “zone.”
  • The plant type (e.g., lawn, trees, flowers, etc.)
  • The soil type (e.g., Loam, clay, etc.)
  • The sprinkler head (e.g., pop spray, surface drip, etc.)
  • Etc.

Guaranteed UI

With a schema, we can automatically generate UI for end users. The UI below shows how to automatically extract a schema from the source code and generate a UI for the user, using the sprinkler above.

In the example, the data must be from the end user for the process to run. We can’t run things with zero user data. The Guaranteed UI certainly makes more sense than “Text UI” or a simple talking conversation.

Runtime schema

If the sprinkler algorithm is really smart. It shall calculate the optimal time to water your plants. End-users want to know that information. They also want to have control of the schedule by adding “hold off periods.” For example, we have a party in the backyard tomorrow afternoon. Do not water the lawn then.

That information is run-time data. We define a universal protocol interaction:

  • Request and response
  • Data subscription and report

Union Type as protocol schema

All protocol payloads must be defined in an enum (union) type.

100% coverage of AI interaction

A Libertas process can automatically be exposed as

  • A tool call or a skill
  • An MCP or CLI
  • An AI agent

End users have 100% control over the visibility.

Arbitrary machines with or without AI

The interfaces can be exposed to AI. They can be used directly by end users with the Libertas Guaranteed UI or connected to other Libertas processes.

Below is the runtime data view and modification of our sprinkler example.

Mandatory documentation for human and AI

The schema from the source code can't be reduced. But more data shall be added for a better user experience.

Machine templates, and run everywhere

Just like we use machines as parts to build bigger machines, linking multiple configuration schemas, with matching runtime schemas (client/server) and node binding. A “bigger machine” requires much less data from the user than all the parts require. We can guarantee it requires the “minimum necessary data” from the user.

The example below shows a template with two schemas.

Since there are arrays in the schema, the result is interesting. A user configuration will result in three processes running on three devices, one actuator, and two sensors.

Rust runtime for Libertas OS

It’s a clean design with minimum dependencies, with only about 7 API, with only two external dependencies.

The design can run arbitrary App code on MCUs with dozens of KB of free RAM, for example, inside your light switch.

Interoperate with TypeScript, more will come later

We also have a TypeScript API and will add support for other modern languages.

1 Like

Here is how it works:

You write one or more public functions with any arguments as a library.
Your library depends on the Libertas crate and uses the Libertas API to exchange runtime data.
Make sure the library compiles successfully.

You run Libertas Hub on a Raspberry Pi. Drop the Rust project folder into the Hub's web interface.

The folder will be uploaded to the Hub. It will be recompiled with a thin "stub" and ready to be used, for all platforms, including a dozen MCUs.

You may also choose to publish it as an App.

I am still working on the beta release, and it has not been released yet. I am open to suggestions on how the community could benefit from my work.