Install#
pamoja is the whole framework in one package, in every language:
cargo add pamoja # Rust
npm install pamoja # TypeScript and Node
pip install pamoja # Python
dotnet add package Pamoja # C# and .NETThat is the right default. Every capability is also a package of its own, and what you gain by picking them differs between Rust and the bindings, so it is worth knowing which before you choose. This page is about that choice; the reference lists every package in every language, and each domain has a page of its own.
Every crate, package, and binding shares one version and is released together, so any package of a release wraps the same release of every other. The changelog covers all of them in one entry.
What picking packages changes#
In Rust, it changes what gets compiled. A crate you do not name is never built, and its dependencies are never fetched, so a narrow build is genuinely smaller and carries less third-party code.
In the bindings it changes what you import, not what you download. Node, Python, and .NET each load one compiled engine that carries every capability, and every package depends on it. Choosing packages narrows the API you see, the manifest you ship, and the code your dependency scanners have to account for. It does not shrink the engine.
Neither is a workaround. Compiling only what you use is a property of a compiled language, and the deployments that need it (a microcontroller with kilobytes of flash) run Rust and could not host a Python or .NET runtime at all.
The two things called core#
A binding has one package you never name and one you sometimes do, and they are easy to confuse.
The compiled engine is @pamoja/native, pamoja-native, and
Pamoja.Native. It is the built Rust library, the generated contract over it,
and the plumbing every facade needs to call it: the handle type, the error every
failed call raises, and string marshalling. Every package declares it, so it
arrives on its own and you never install it by hand. Rust has no equivalent,
because there you compile the crates.
The engine surface is @pamoja/core, pamoja-core, and Pamoja.Core, the
counterpart of the pamoja-core crate. It is the runtime version and
Transport, the abstraction MQTT, CoAP, and the loopback all implement. It is a
capability like any other, listed first on every reference page, and most packages do
not depend on it: only the transports do, because they are the ones that return a
Transport. Install it when you want to hold a link behind that interface.
By domain#
Six of the ten headings hold more than one capability, and each of those is also one thing to install: a feature in Rust, and a package in every binding that brings in its capabilities and re-exports each under its own name, so a name two of them share stays unambiguous. Pick a language:
cargo add pamoja --no-default-features --features std,field-iocargo add pamoja --no-default-features --features std,sensingcargo add pamoja --no-default-features --features std,radiocargo add pamoja --no-default-features --features std,trustcargo add pamoja --no-default-features --features std,transportscargo add pamoja --no-default-features --features std,profiles@pamoja/field-ionpm install @pamoja/field-io@pamoja/sensingnpm install @pamoja/sensing@pamoja/radionpm install @pamoja/radio@pamoja/trustnpm install @pamoja/trust@pamoja/transportsnpm install @pamoja/transports@pamoja/profilesnpm install @pamoja/profilespamoja.field_iopip install pamoja-field-iopamoja.sensingpip install pamoja-sensingpamoja.radiopip install pamoja-radiopamoja.trustpip install pamoja-trustpamoja.transportspip install pamoja-transportspamoja.profilespip install pamoja-profilesdotnet add package Pamoja.FieldIodotnet add package Pamoja.Sensingdotnet add package Pamoja.Radiodotnet add package Pamoja.Trustdotnet add package Pamoja.Transportsdotnet add package Pamoja.ProfilesEach row opens the section of that language's reference page that lists what the domain brings in, with the install line and the API pages for every capability in it. Every capability, on its own, is on the reference.
Rust#
cargo add pamoja # every capability, behind a feature each
cargo add pamoja-modbus # or one crate on its ownFrom examples/tests/guides/imports.rs:
use pamoja::modbus::Adu; // the same type as pamoja_modbus::Adu
use pamoja_codec::CborCodec;Each module of pamoja is the crate of the same name, so the two ways in share
one API and one set of documentation, and code moves between them unchanged.
Naming features is what makes a build small. Measured from the resolved
dependency graph, for a x86_64-unknown-linux-gnu build:
| Build | What you write | Crates compiled | From this workspace | External |
|---|---|---|---|---|
| Every capability | cargo add pamoja | 124 | 34 | 90 |
| Codecs and identity | cargo add pamoja --no-default-features --features std, | 36 | 4 | 32 |
| Field I/O | cargo add pamoja --no-default-features --features std, | 8 | 7 | 1 |
| One capability | cargo add pamoja --no-default-features --features std, | 5 | 4 | 1 |
Bare metal, no std | cargo add pamoja --no-default-features --features modbus, | 7 | 6 | 1 |
The narrow builds carry one third-party crate, embedded-hal, the trait crate the
bus layer is written against, and otherwise only pamoja, pamoja-core, and the
capability crates. Most capability crates are no_std, so the same code runs on a
gateway and on a microcontroller. The
Rust reference lists every crate.
TypeScript and Node#
npm install pamoja # every capability
npm install @pamoja/modbus @pamoja/codec # or only the packages you useimport { readHoldingRegisters } from '@pamoja/modbus'
import { toCbor, fromCbor } from '@pamoja/codec'Every package depends on @pamoja/native, the compiled engine, prebuilt for
Linux (x64, arm64), macOS (x64, arm64), and Windows (x64); npm picks the right
one, and installs on anything else without a binary to load. Alpine and Windows
on ARM are the two that catch people out. It is one binary carrying every capability whichever packages you install,
so the choice is about the API surface and your dependency manifest, not the
download. Node 16 or later.
Python#
pip install pamoja # every capability
pip install pamoja-modbus pamoja-codec # or only the distributions you usefrom pamoja.modbus import read_holding_registers
from pamoja.codec import to_cbor, from_cborpamoja is a namespace package: each distribution ships one pamoja.<name>
module and they merge on import. Every distribution depends on pamoja-native,
the compiled engine, with wheels for the same platforms as the Node engine and
for Python 3.10 and later; elsewhere pip builds it from the sdist, which needs
a Rust toolchain.
C# and .NET#
dotnet add package Pamoja # every capability
dotnet add package Pamoja.Modbus Pamoja.Codec # or only the packages you useusing Pamoja.Modbus;
using Pamoja.Codec;A domain package there brings in its capabilities and ships no assembly of its own, since C# has no way to re-export a namespace, so a type is named the way it is when its package is referenced directly.
Each package is one namespace of the same name. Every package depends on
Pamoja.Native, which carries the native library for win-x64, linux-x64,
linux-arm64, osx-x64, and osx-arm64, and targets .NET 8. Those five are the
whole list: on any other runtime identifier, win-arm64 and the musl-based
distributions among them, the packages restore and compile and then throw
DllNotFoundException on the first call, because there is no native library to
load and, unlike Python, no source build to fall back on.