2026-01-23 08:50:17 -05:00
|
|
|
# Quick Reference
|
|
|
|
|
|
|
|
|
|
Cheat sheet for common logos-module-builder tasks.
|
|
|
|
|
|
|
|
|
|
## Create a New Module
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# 1. Create directory
|
|
|
|
|
mkdir logos-my-module && cd logos-my-module
|
|
|
|
|
|
2026-03-24 17:21:59 +01:00
|
|
|
# 2. Create metadata.json
|
2026-01-23 08:50:17 -05:00
|
|
|
cat > metadata.json << 'EOF'
|
|
|
|
|
{
|
|
|
|
|
"name": "my_module",
|
2026-06-19 14:27:28 +02:00
|
|
|
"display_name": "My Module",
|
2026-01-23 08:50:17 -05:00
|
|
|
"version": "1.0.0",
|
|
|
|
|
"type": "core",
|
2026-06-13 09:15:05 -03:00
|
|
|
"interface": "universal",
|
2026-01-23 08:50:17 -05:00
|
|
|
"category": "general",
|
2026-03-24 17:21:59 +01:00
|
|
|
"description": "My module",
|
2026-01-23 08:50:17 -05:00
|
|
|
"main": "my_module_plugin",
|
2026-03-24 17:21:59 +01:00
|
|
|
"dependencies": [],
|
|
|
|
|
"nix": {
|
|
|
|
|
"packages": { "build": [], "runtime": [] },
|
|
|
|
|
"external_libraries": [],
|
|
|
|
|
"cmake": { "find_packages": [], "extra_sources": [] }
|
|
|
|
|
}
|
2026-01-23 08:50:17 -05:00
|
|
|
}
|
|
|
|
|
EOF
|
|
|
|
|
|
2026-03-24 17:21:59 +01:00
|
|
|
# 3. Create flake.nix
|
|
|
|
|
cat > flake.nix << 'EOF'
|
|
|
|
|
{
|
2026-03-26 11:27:34 +01:00
|
|
|
inputs = {
|
|
|
|
|
logos-module-builder.url = "github:logos-co/logos-module-builder";
|
|
|
|
|
};
|
2026-03-24 17:21:59 +01:00
|
|
|
outputs = inputs@{ logos-module-builder, ... }:
|
|
|
|
|
logos-module-builder.lib.mkLogosModule {
|
|
|
|
|
src = ./.;
|
|
|
|
|
configFile = ./metadata.json;
|
|
|
|
|
flakeInputs = inputs;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
EOF
|
|
|
|
|
|
|
|
|
|
# 4. Create CMakeLists.txt
|
2026-01-23 08:50:17 -05:00
|
|
|
cat > CMakeLists.txt << 'EOF'
|
|
|
|
|
cmake_minimum_required(VERSION 3.14)
|
|
|
|
|
project(MyModulePlugin LANGUAGES CXX)
|
|
|
|
|
include($ENV{LOGOS_MODULE_BUILDER_ROOT}/cmake/LogosModule.cmake)
|
2026-06-13 09:15:05 -03:00
|
|
|
logos_module(NAME my_module SOURCES src/my_module_impl.h src/my_module_impl.cpp)
|
2026-01-23 08:50:17 -05:00
|
|
|
EOF
|
|
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
# 5. Create source files in src/ directory (universal model: impl class only)
|
2026-01-23 09:08:16 -05:00
|
|
|
mkdir -p src
|
|
|
|
|
# (see templates for source file content)
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-03-24 17:21:59 +01:00
|
|
|
# 6. Track files and build
|
|
|
|
|
git init && git add -A
|
2026-01-23 08:50:17 -05:00
|
|
|
nix build
|
|
|
|
|
```
|
|
|
|
|
|
2026-03-24 17:21:59 +01:00
|
|
|
## metadata.json Quick Reference
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-03-24 17:21:59 +01:00
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"name": "module_name",
|
|
|
|
|
"version": "1.0.0",
|
|
|
|
|
"type": "core",
|
2026-06-13 09:15:05 -03:00
|
|
|
"interface": "universal",
|
2026-03-24 17:21:59 +01:00
|
|
|
"category": "general",
|
|
|
|
|
"description": "A Logos module",
|
|
|
|
|
"main": "module_name_plugin",
|
|
|
|
|
"dependencies": ["waku_module", "other_module"],
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-03-24 17:21:59 +01:00
|
|
|
"nix": {
|
|
|
|
|
"packages": {
|
|
|
|
|
"build": ["protobuf", "abseil-cpp"],
|
|
|
|
|
"runtime": ["zstd"]
|
|
|
|
|
},
|
|
|
|
|
"external_libraries": [
|
|
|
|
|
{ "name": "mylib", "vendor_path": "lib" }
|
|
|
|
|
],
|
|
|
|
|
"cmake": {
|
|
|
|
|
"find_packages": ["Protobuf", "Threads"],
|
|
|
|
|
"extra_sources": ["src/helper.cpp"],
|
|
|
|
|
"extra_include_dirs": ["include"],
|
|
|
|
|
"extra_link_libraries": ["pthread"]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-01-23 08:50:17 -05:00
|
|
|
```
|
|
|
|
|
|
2026-08-21 16:46:22 -03:00
|
|
|
### Platform-specific values
|
|
|
|
|
|
|
|
|
|
`include` and everything under `nix` may be overridden per target by an ordered
|
|
|
|
|
list of overlays. Every matching entry applies, in declaration order; **lists
|
|
|
|
|
concatenate**, **scalars overwrite**, and **objects recurse** (merged key by
|
|
|
|
|
key, base-only keys survive).
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
"include": [],
|
|
|
|
|
"platforms": [
|
|
|
|
|
{ "when": { "os": "linux" }, "include": ["libcore.so"] },
|
|
|
|
|
{ "when": { "os": "darwin" }, "include": ["libcore.dylib"] },
|
|
|
|
|
{ "when": { "os": "windows" }, "include": ["libcore.dll"] }
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
"nix": {
|
|
|
|
|
"packages": { "runtime": ["nlohmann_json"] },
|
|
|
|
|
"platforms": [
|
|
|
|
|
{ "when": { "os": "linux" }, "packages": { "runtime": ["krb5"] } }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The **empty base** for `include` is the pattern to copy, not a stylistic choice.
|
|
|
|
|
Lists concatenate, so leaving `libcore.so` in the base would resolve darwin to
|
|
|
|
|
`["libcore.so","libcore.dylib"]` — a cross-platform superset, which is exactly
|
|
|
|
|
what the overlays exist to eliminate. The `.so` is the Linux value; it goes in
|
|
|
|
|
the Linux overlay. `nix.packages.runtime` above shows the other case:
|
|
|
|
|
`nlohmann_json` is genuinely correct everywhere, so it stays in the base.
|
|
|
|
|
|
|
|
|
|
`main` and `dependencies` may **not** be platform-keyed. Not on principle — the
|
|
|
|
|
shipped `metadata.json` is the source file copied verbatim, so a per-target
|
|
|
|
|
value would be resolved for the build and not for the artifact. A `platforms`
|
|
|
|
|
key anywhere but the top level or `nix` (e.g. `nix.packages.platforms`) is a
|
|
|
|
|
hard error, not a silently skipped overlay.
|
|
|
|
|
|
|
|
|
|
`os` ∈ `linux | darwin | windows`, `architecture` ∈ `x86_64 | aarch64`,
|
|
|
|
|
`abi` ∈ `gnu | unknown` — each independently optional, an empty `when` is an
|
|
|
|
|
error, and an unrecognised value is an error rather than a non-match. Note the
|
|
|
|
|
Windows target is mingw, so its `abi` is `gnu` (and `{"abi":"gnu"}` on its own
|
|
|
|
|
therefore also matches Linux). See `docs/configuration.md` for the full rules.
|
|
|
|
|
|
2026-08-27 12:21:46 +02:00
|
|
|
### App-to-app intents (`ui_qml` only)
|
|
|
|
|
|
|
|
|
|
A capability another app can ask for by name, without knowing you exist. Add to
|
|
|
|
|
`metadata.json`:
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
"provides": [ { "intent": "wallet.send",
|
|
|
|
|
"params": [ { "name": "to", "type": "string", "required": true } ] } ],
|
|
|
|
|
"uses": [ { "intent": "packages.show" } ]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- `provides` — what you can service. `params` is optional, and **enforced**: a
|
|
|
|
|
missing required field or wrong type is refused before your handler runs.
|
|
|
|
|
- `uses` — what you may request. Undeclared requests fail `not_declared`.
|
|
|
|
|
- Entries are **objects**; `["wallet.send"]` parses and declares nothing.
|
|
|
|
|
- `core` modules cannot use either — they call each other directly through
|
|
|
|
|
`LogosAPI`, with no user decision to mediate.
|
|
|
|
|
|
|
|
|
|
Declaring is not implementing — handle `logos.intentRequested` in QML or the
|
|
|
|
|
request times out. Full reference: [Configuration](configuration.md#provides).
|
|
|
|
|
|
2026-01-23 08:50:17 -05:00
|
|
|
## CMakeLists.txt Quick Reference
|
|
|
|
|
|
|
|
|
|
```cmake
|
|
|
|
|
cmake_minimum_required(VERSION 3.14)
|
|
|
|
|
project(MyModulePlugin LANGUAGES CXX)
|
|
|
|
|
|
|
|
|
|
include($ENV{LOGOS_MODULE_BUILDER_ROOT}/cmake/LogosModule.cmake)
|
|
|
|
|
|
|
|
|
|
logos_module(
|
|
|
|
|
NAME my_module
|
2026-03-24 17:21:59 +01:00
|
|
|
SOURCES
|
2026-06-13 09:15:05 -03:00
|
|
|
src/my_module_impl.h
|
|
|
|
|
src/my_module_impl.cpp
|
2026-01-23 08:50:17 -05:00
|
|
|
src/helper.cpp
|
|
|
|
|
EXTERNAL_LIBS
|
|
|
|
|
mylib
|
|
|
|
|
FIND_PACKAGES
|
|
|
|
|
Protobuf
|
|
|
|
|
LINK_LIBRARIES
|
|
|
|
|
pthread
|
|
|
|
|
)
|
|
|
|
|
```
|
|
|
|
|
|
2026-08-20 00:31:52 -03:00
|
|
|
> `PROTO_FILES` used to be accepted here and is not parsed any more — compile
|
|
|
|
|
> `.proto` files yourself and add the results via `nix.cmake.extra_sources`.
|
|
|
|
|
|
2026-01-23 08:50:17 -05:00
|
|
|
## flake.nix Quick Reference
|
|
|
|
|
|
|
|
|
|
### Basic Module
|
|
|
|
|
```nix
|
|
|
|
|
{
|
2026-03-26 11:27:34 +01:00
|
|
|
inputs = {
|
|
|
|
|
logos-module-builder.url = "github:logos-co/logos-module-builder";
|
|
|
|
|
};
|
2026-03-24 17:21:59 +01:00
|
|
|
|
|
|
|
|
outputs = inputs@{ logos-module-builder, ... }:
|
2026-01-23 08:50:17 -05:00
|
|
|
logos-module-builder.lib.mkLogosModule {
|
|
|
|
|
src = ./.;
|
2026-03-24 17:21:59 +01:00
|
|
|
configFile = ./metadata.json;
|
|
|
|
|
flakeInputs = inputs;
|
2026-01-23 08:50:17 -05:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### With Module Dependencies
|
|
|
|
|
```nix
|
|
|
|
|
{
|
|
|
|
|
inputs = {
|
|
|
|
|
logos-module-builder.url = "github:logos-co/logos-module-builder";
|
2026-03-24 17:21:59 +01:00
|
|
|
waku_module.url = "github:logos-co/logos-waku-module"; # input name must match dependency name
|
2026-01-23 08:50:17 -05:00
|
|
|
};
|
2026-03-24 17:21:59 +01:00
|
|
|
|
|
|
|
|
outputs = inputs@{ logos-module-builder, ... }:
|
2026-01-23 08:50:17 -05:00
|
|
|
logos-module-builder.lib.mkLogosModule {
|
|
|
|
|
src = ./.;
|
2026-03-24 17:21:59 +01:00
|
|
|
configFile = ./metadata.json;
|
|
|
|
|
flakeInputs = inputs; # waku_module resolved automatically from dependencies[]
|
2026-01-23 08:50:17 -05:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-03-24 17:21:59 +01:00
|
|
|
### With External Library (flake input, built from source)
|
2026-01-23 08:50:17 -05:00
|
|
|
```nix
|
|
|
|
|
{
|
|
|
|
|
inputs = {
|
|
|
|
|
logos-module-builder.url = "github:logos-co/logos-module-builder";
|
|
|
|
|
mylib = { url = "github:org/mylib"; flake = false; };
|
|
|
|
|
};
|
2026-03-24 17:21:59 +01:00
|
|
|
|
|
|
|
|
outputs = inputs@{ logos-module-builder, ... }:
|
2026-01-23 08:50:17 -05:00
|
|
|
logos-module-builder.lib.mkLogosModule {
|
|
|
|
|
src = ./.;
|
2026-03-24 17:21:59 +01:00
|
|
|
configFile = ./metadata.json;
|
|
|
|
|
flakeInputs = inputs;
|
2026-01-23 08:50:17 -05:00
|
|
|
externalLibInputs = {
|
2026-03-24 17:21:59 +01:00
|
|
|
mylib = inputs.mylib;
|
2026-01-23 08:50:17 -05:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-04-02 13:23:45 +02:00
|
|
|
### ui_qml Module (QML view + optional C++ backend)
|
2026-03-24 17:21:59 +01:00
|
|
|
```nix
|
|
|
|
|
{
|
|
|
|
|
inputs = {
|
|
|
|
|
logos-module-builder.url = "github:logos-co/logos-module-builder";
|
2026-04-02 13:23:45 +02:00
|
|
|
# Add backend module dependencies as inputs if needed
|
2026-03-24 17:21:59 +01:00
|
|
|
};
|
|
|
|
|
|
2026-03-27 14:35:39 +01:00
|
|
|
outputs = inputs@{ logos-module-builder, ... }:
|
2026-03-24 17:21:59 +01:00
|
|
|
logos-module-builder.lib.mkLogosQmlModule {
|
|
|
|
|
src = ./.;
|
|
|
|
|
configFile = ./metadata.json;
|
|
|
|
|
flakeInputs = inputs;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
## Source File Templates (universal model)
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-08-20 00:31:52 -03:00
|
|
|
You write only the impl class. Everything else is generated from
|
|
|
|
|
`src/my_module_impl.h` into `generated_code/`: `my_module.lidl` (the contract),
|
|
|
|
|
`my_module_cdylib_glue.{h,cpp}` (the Qt plugin, `Q_PLUGIN_METADATA` + `onInit`)
|
|
|
|
|
and `my_module_module_impl.cpp` / `my_module_types.h` (the Qt-free C ABI).
|
|
|
|
|
The old `*_interface.h` / `*_plugin.{h,cpp}` names are no longer emitted.
|
2026-06-13 09:15:05 -03:00
|
|
|
Module code is Qt-free — use `std::string`.
|
|
|
|
|
|
|
|
|
|
### Impl Header (`src/my_module_impl.h`)
|
2026-01-23 08:50:17 -05:00
|
|
|
```cpp
|
2026-06-13 09:15:05 -03:00
|
|
|
#pragma once
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
#include <string>
|
|
|
|
|
#include "logos_module_context.h"
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
class MyModuleImpl : public LogosModuleContext
|
2026-01-23 08:50:17 -05:00
|
|
|
{
|
|
|
|
|
public:
|
2026-06-13 09:15:05 -03:00
|
|
|
/// Returns a processed string. Public methods are the module API.
|
|
|
|
|
std::string myMethod(const std::string& input);
|
|
|
|
|
|
|
|
|
|
logos_events:
|
|
|
|
|
/// Typed event; subscribers use `modules().my_module.onProcessed(...)`.
|
|
|
|
|
void processed(const std::string& result);
|
2026-01-23 08:50:17 -05:00
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
### Impl Implementation (`src/my_module_impl.cpp`)
|
2026-01-23 08:50:17 -05:00
|
|
|
```cpp
|
2026-06-13 09:15:05 -03:00
|
|
|
#include "my_module_impl.h"
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
std::string MyModuleImpl::myMethod(const std::string& input) {
|
|
|
|
|
std::string result = "Result: " + input;
|
|
|
|
|
processed(result); // generated event body fans out to subscribers
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
```
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
`LogosModuleContext` gives you `modules().<dep>.method(...)` for typed calls into
|
|
|
|
|
dependencies, typed event subscriptions, and an `onContextReady()` hook (override
|
|
|
|
|
it to arm subscriptions once the module is wired).
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
### UI C++ backend (universal `ui_qml`)
|
2026-01-23 08:50:17 -05:00
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
For a C++ UI module (`"type": "ui_qml"` + `"interface": "universal"`) you write a
|
|
|
|
|
`.rep` view contract plus a `*Backend` class deriving the generated
|
2026-06-15 11:22:57 -03:00
|
|
|
`<RepClass>SimpleSource` and `LogosUiPluginContext`. Point `codegen.rep` at the
|
2026-06-13 09:15:05 -03:00
|
|
|
`.rep` and use `REP_FILE` in `CMakeLists.txt`:
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
// src/my_ui.rep — the QtRO view contract
|
|
|
|
|
class MyUi {
|
|
|
|
|
SLOT(int add(int a, int b))
|
|
|
|
|
PROP(QString status="Ready" READONLY)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```cpp
|
|
|
|
|
// src/my_ui_backend.h
|
|
|
|
|
#pragma once
|
|
|
|
|
#include "rep_my_ui_source.h"
|
2026-06-15 11:22:57 -03:00
|
|
|
#include "logos_ui_plugin_context.h"
|
2026-06-13 09:15:05 -03:00
|
|
|
|
2026-06-15 11:22:57 -03:00
|
|
|
class MyUiBackend : public MyUiSimpleSource, public LogosUiPluginContext {
|
2026-01-23 08:50:17 -05:00
|
|
|
public:
|
2026-06-13 09:15:05 -03:00
|
|
|
int add(int a, int b) override; // feed PROPs via setStatus(...)
|
2026-01-23 08:50:17 -05:00
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
|
2026-06-13 09:15:05 -03:00
|
|
|
```cmake
|
|
|
|
|
logos_module(
|
|
|
|
|
NAME my_ui
|
|
|
|
|
REP_FILE src/my_ui.rep
|
|
|
|
|
SOURCES
|
|
|
|
|
src/my_ui_backend.h
|
|
|
|
|
src/my_ui_backend.cpp
|
|
|
|
|
INCLUDE_DIRS
|
|
|
|
|
src
|
|
|
|
|
)
|
2026-01-23 08:50:17 -05:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Common Commands
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-01-23 09:08:16 -05:00
|
|
|
# Build module (combined lib + include)
|
2026-01-23 08:50:17 -05:00
|
|
|
nix build
|
|
|
|
|
|
2026-01-23 09:08:16 -05:00
|
|
|
# Build just the library
|
|
|
|
|
nix build .#lib
|
|
|
|
|
|
|
|
|
|
# Build just the generated headers
|
|
|
|
|
nix build .#include
|
|
|
|
|
|
2026-03-27 11:02:41 +01:00
|
|
|
# Build .lgx packages
|
2026-03-26 11:27:34 +01:00
|
|
|
nix build .#lgx
|
|
|
|
|
nix build .#lgx-portable
|
|
|
|
|
|
2026-03-24 17:21:59 +01:00
|
|
|
# Run UI module in logos-standalone-app
|
|
|
|
|
nix run .
|
|
|
|
|
|
2026-01-23 08:50:17 -05:00
|
|
|
# Enter dev shell
|
|
|
|
|
nix develop
|
|
|
|
|
|
2026-01-23 09:08:16 -05:00
|
|
|
# Build specific output (alternative syntax)
|
2026-01-23 08:50:17 -05:00
|
|
|
nix build .#my_module-lib
|
|
|
|
|
nix build .#my_module-include
|
|
|
|
|
|
|
|
|
|
# Check flake
|
|
|
|
|
nix flake check
|
|
|
|
|
|
|
|
|
|
# Update flake inputs
|
|
|
|
|
nix flake update
|
|
|
|
|
```
|