Developer's Guide
Guide for building and contributing to Propeller
Getting Propeller
Propeller source can be found in the official Propeller GitHub repository. You should fork this repository in order to make changes to the project. The forked version of the repository should be cloned using the following:
git clone https://github.com/your-github-username/propeller.git $SOMEPATH/propeller
cd $SOMEPATH/propeller
git remote add upstream https://github.com/absmach/propeller.gitBuilding Propeller
Prerequisites
To build Propeller, you will need the following:
Building
Use the GNU Make tool to build all Propeller services:
make allThis will build Propeller for your platforms.
To build Propeller for other platforms, use the following:
| OS | Architecture | Command |
|---|---|---|
| Linux | amd64 | GOOS=linux GOARCH=amd64 make all |
| Linux | arm64 | GOOS=linux GOARCH=arm64 make all |
| Windows | amd64 | GOOS=windows GOARCH=amd64 make all |
| Darwin | amd64 | GOOS=darwin GOARCH=amd64 make all |
Building an individual service
You can build individual services using the following:
make <service>For example, to build the manager service, use the following:
make managerThe built binaries will be located in the build directory.
Building examples
You can build examples using the following:
make <example>For example, to build the addition example, use the following:
make additionThis compiles the addition example to wasm and can be located in the build directory.
To test the addition example, use the following:
wasmtime --invoke add ./build/addition.wasm 1 2This will output something like:
warning: using `--invoke` with a function that takes arguments is experimental and may break in the future
warning: using `--invoke` with a function that returns values is experimental and may break in the future
3Installing
Once you have built Propeller, you can install it using the following:
make installThis will install Propeller to the GOBIN directory.
export GOBIN=~/go/bin
export PATH=$GOBIN:$PATH
make installLinter
Propeller uses golangci-lint to lint the code. You can run the linter using the following:
make lintSuperMQ
Starting SuperMQ
To start SuperMQ, use the following:
make start-supermqThis will in the background run docker compose -f docker/compose.yaml up -d which will start the SuperMQ services.
You can override the configuration or add some extra parameters to the docker compose configuration.
After this is done, you will need to provision propeller using the following command
propeller-cli provisionAfter this is done, config.toml file will be created for easier setup, we can copy it to the docker folder and uncomment config.toml configuration for manager, proplet and proxy.
cp config.toml dockerThe changes on the docker compose file looks like this
diff --git a/docker/compose.yaml b/docker/compose.yaml
index 46302ea..e872f29 100644
--- a/docker/compose.yaml
+++ b/docker/compose.yaml
@@ -1607,8 +1607,8 @@ services:
- supermq-base-net
# To use a custom config.toml, uncomment the following line and ensure ./config.toml exists.
# If you are using environment variables for configuration, leave this commented out.
- # volumes:
- # - ./config.toml:/config.toml
+ volumes:
+ - ./config.toml:/config.toml
proplet:
image: ghcr.io/absmach/propeller/proplet:${PROP_RELEASE_TAG}
@@ -1642,8 +1642,8 @@ services:
- supermq-base-net
# To use a custom config.toml, uncomment the following line and ensure ./config.toml exists.
# If you are using environment variables for configuration, leave this commented out.
- # volumes:
- # - ./config.toml:/home/proplet/config.toml
+ volumes:
+ - ./config.toml:/home/proplet/config.toml
proxy:
image: ghcr.io/absmach/propeller/proxy:${PROP_RELEASE_TAG}
@@ -1671,5 +1671,5 @@ services:
- supermq-base-net
# To use a custom config.toml, uncomment the following line and ensure ./config.toml exists.
# If you are using environment variables for configuration, leave this commented out.
- # volumes:
- # - ./config.toml:/config.toml
+ volumes:
+ - ./config.toml:/config.tomlThen run make start-supermq again to start SuperMQ.
The logs from then manager should look like this:
{"time":"2026-02-11T16:57:43.822945669Z","level":"INFO","msg":"MQTT connection lost"}
{"time":"2026-02-11T16:57:43.883167345Z","level":"INFO","msg":"Subscribe to MQTT topic completed successfully","duration":"60.157736ms"}
{"time":"2026-02-11T16:57:43.883519119Z","level":"INFO","msg":"manager service http server listening at manager:7070 without TLS"}The logs from the proplet should look like this:
2026-02-11T17:34:32.841840Z INFO Starting Proplet (Rust) - Instance ID: f34cddff-2855-4e3f-9b55-9d83b982b315
2026-02-11T17:34:32.841888Z INFO MQTT client created (TLS: false)
2026-02-11T17:34:32.841931Z INFO Using external Wasm runtime: wasmtime
2026-02-11T17:34:32.842001Z INFO Starting MQTT event loop
2026-02-11T17:34:32.846168Z DEBUG Received MQTT packet: ConnAck(ConnAck { session_present: false, code: Success })
2026-02-11T17:34:32.877390Z INFO Starting PropletService
2026-02-11T17:34:32.877439Z DEBUG Published to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/proplet/create
2026-02-11T17:34:32.877443Z INFO Published discovery message
2026-02-11T17:34:32.877463Z INFO Subscribed to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/manager/start
2026-02-11T17:34:32.877467Z INFO Subscribed to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/manager/stop
2026-02-11T17:34:32.877472Z INFO Subscribed to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/registry/server
2026-02-11T17:34:32.878594Z DEBUG Published to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/proplet/alive
2026-02-11T17:34:32.878615Z DEBUG Published liveliness update
2026-02-11T17:34:32.879956Z DEBUG Published to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/proplet/metrics
2026-02-11T17:34:32.880019Z DEBUG Published proplet metrics
2026-02-11T17:34:32.882250Z DEBUG Received MQTT packet: PubAck(PubAck { pkid: 1 })
2026-02-11T17:34:32.897028Z DEBUG Received MQTT packet: SubAck(SubAck { pkid: 2, return_codes: [Success(AtLeastOnce)] })
2026-02-11T17:34:32.902466Z DEBUG Received MQTT packet: SubAck(SubAck { pkid: 3, return_codes: [Success(AtLeastOnce)] })
2026-02-11T17:34:32.908233Z DEBUG Received MQTT packet: SubAck(SubAck { pkid: 4, return_codes: [Success(AtLeastOnce)] })
2026-02-11T17:34:32.909485Z DEBUG Received MQTT packet: PubAck(PubAck { pkid: 5 })
2026-02-11T17:34:32.909510Z DEBUG Received MQTT packet: PubAck(PubAck { pkid: 6 })
2026-02-11T17:34:42.878374Z DEBUG Published to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/proplet/alive
2026-02-11T17:34:42.878387Z DEBUG Published liveliness update
2026-02-11T17:34:42.879526Z DEBUG Published to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/proplet/metrics
2026-02-11T17:34:42.879540Z DEBUG Published proplet metrics
2026-02-11T17:34:42.881430Z DEBUG Received MQTT packet: PubAck(PubAck { pkid: 7 })
2026-02-11T17:34:42.883416Z DEBUG Received MQTT packet: PubAck(PubAck { pkid: 8 })
2026-02-11T17:34:52.878418Z DEBUG Published to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/proplet/alive
2026-02-11T17:34:52.878441Z DEBUG Published liveliness update
2026-02-11T17:34:52.880337Z DEBUG Published to topic: m/fcf50e58-a080-4179-a260-e91cdf8fc1c2/c/8259a673-ab09-4b97-8c09-e1f9e60c7c2c/control/proplet/metrics
2026-02-11T17:34:52.880366Z DEBUG Published proplet metricsStopping SuperMQ
SuperMQ can be stopped using the following:
make stop-supermq