2026-03-06 14:05:53 +00:00
# Logos Module Developer Guide
A comprehensive guide to creating, building, testing, packaging, and distributing modules for the Logos platform.
## Table of Contents
- [Overview ](#overview )
- [Architecture ](#architecture )
- [Prerequisites ](#prerequisites )
- [Part 1: Creating a Module ](#part-1-creating-a-module )
- [1.1 Scaffold with logos-module-builder ](#11-scaffold-with-logos-module-builder )
- [1.2 Project Structure ](#12-project-structure )
- [1.3 The module.yaml Configuration ](#13-the-moduleyaml-configuration )
- [1.4 Writing Module Code ](#14-writing-module-code )
- [1.5 Building Your Module ](#15-building-your-module )
- [Part 2: Inspecting and Testing Your Module ](#part-2-inspecting-and-testing-your-module )
- [2.1 The lm CLI Tool ](#21-the-lm-cli-tool )
- [2.2 Running with logoscore ](#22-running-with-logoscore )
- [2.3 The logos-module-viewer ](#23-the-logos-module-viewer )
- [Part 3: Packaging Your Module ](#part-3-packaging-your-module )
- [3.1 The LGX Package Format ](#31-the-lgx-package-format )
- [3.2 Creating a Package with lgx ](#32-creating-a-package-with-lgx )
- [3.3 Verifying Packages ](#33-verifying-packages )
- [Part 4: Installing and Managing Modules ](#part-4-installing-and-managing-modules )
- [4.1 The lgpm CLI ](#41-the-lgpm-cli )
- [4.2 Installing from Local Files ](#42-installing-from-local-files )
- [4.3 Installing from a Registry ](#43-installing-from-a-registry )
2026-03-18 14:22:43 +01:00
- [Part 5: Running in logos-basecamp ](#part-5-running-in-logos-basecamp )
- [5.1 Building logos-basecamp ](#51-building-logos-basecamp )
- [5.2 Module Types in logos-basecamp ](#52-module-types-in-logos-basecamp )
2026-03-06 14:05:53 +00:00
- [5.3 Development Mode ](#53-development-mode )
- [Part 6: Inter-Module Communication ](#part-6-inter-module-communication )
- [6.1 The LogosAPI ](#61-the-logosapi )
- [6.2 The C++ SDK Code Generator ](#62-the-c-sdk-code-generator )
- [6.3 LogosResult ](#63-logosresult )
- [6.4 Communication Modes ](#64-communication-modes )
- [Part 7: Advanced Topics ](#part-7-advanced-topics )
- [7.1 Wrapping External Libraries ](#71-wrapping-external-libraries )
- [7.2 UI Modules (C++ Widgets) ](#72-ui-modules-c-widgets )
- [7.3 UI Modules (QML) ](#73-ui-modules-qml )
- [7.4 Module Dependencies ](#74-module-dependencies )
- [Reference: Repository Map ](#reference-repository-map )
- [Reference: CLI Tools Summary ](#reference-cli-tools-summary )
- [Troubleshooting ](#troubleshooting )
---
## Overview
The **Logos platform** is a modular application framework built in C++ on top of Qt 6. Applications are composed of dynamically loaded **modules** (plugins) that communicate via an IPC layer. The platform provides:
- **Process isolation** -- each module runs in its own host process (on desktop), communicating via Qt Remote Objects
- **Cross-platform support** -- macOS (arm64, x86_64) and Linux (arm64, x86_64)
- **A package format** (`.lgx` ) for distributing modules with platform-specific variants
2026-03-18 14:22:43 +01:00
- **A desktop application shell** (`logos-basecamp` ) with a sidebar, tabbed workspace, and plugin management UI
2026-03-06 14:05:53 +00:00
- **A CLI runtime** (`logoscore` ) for running modules headlessly
## Architecture
```
+---------------------------------------------------------------+
| Application Layer |
2026-03-18 14:22:43 +01:00
| logos-basecamp (Desktop GUI) or logoscore (CLI Runtime) |
2026-03-06 14:05:53 +00:00
+---------------------------------------------------------------+
| | |
v v v
+---------------+ +------------------+ +------------------+
| Module A | | Module B | | Package Manager |
| (logos_host) | | (logos_host) | | Module |
+-------+-------+ +--------+---------+ +--------+---------+
| | |
| Qt Remote Objects (IPC) |
+--------------------------------------------+
|
+--------v---------+
| liblogos | (Core Runtime)
| logos-liblogos |
+--------+---------+
|
+--------v---------+
| logos-cpp-sdk | (SDK: LogosAPI,
| | Code Generator,
| | Types, IPC)
+------------------+
```
**Key components:**
| Component | Repository | Role |
|-----------|-----------|------|
| **logos-module-builder** | [logos-co/logos-module-builder ](https://github.com/logos-co/logos-module-builder ) | Scaffolding and build system for new modules |
| **logos-module** | [logos-co/logos-module ](https://github.com/logos-co/logos-module ) | Plugin loading/introspection library + `lm` CLI |
| **logos-cpp-sdk** | [logos-co/logos-cpp-sdk ](https://github.com/logos-co/logos-cpp-sdk ) | C++ SDK, types, IPC layer, code generator |
| **logos-liblogos** | [logos-co/logos-liblogos ](https://github.com/logos-co/logos-liblogos ) | Core runtime (`logoscore` , `logos_host` , `liblogos_core` ) |
| **logos-package** | [logos-co/logos-package ](https://github.com/logos-co/logos-package ) | LGX package format library + `lgx` CLI |
| **logos-package-manager-module** | [logos-co/logos-package-manager-module ](https://github.com/logos-co/logos-package-manager-module ) | Package manager module + `lgpm` CLI |
2026-03-18 14:22:43 +01:00
| **logos-basecamp** | [logos-co/logos-basecamp ](https://github.com/logos-co/logos-basecamp ) | Desktop application shell |
2026-03-06 14:05:53 +00:00
## Prerequisites
### Required
- **Nix** with flakes enabled. This is the primary build tool for the entire ecosystem. Install Nix from [nixos.org ](https://nixos.org/download.html ), then enable flakes:
```bash
# If you need experimental features enabled per-command:
nix --extra-experimental-features "nix-command flakes" <command>
# Or enable globally in ~/.config/nix/nix.conf:
experimental-features = nix-command flakes
` ``
### Recommended Knowledge
- C++ (C++17)
- Qt 6 basics (` QObject`, ` Q_INVOKABLE`, ` Q_PLUGIN_METADATA`, signals/slots)
- Basic CMake
- Basic Nix concepts (flakes, derivations)
---
## Part 1: Creating a Module
### 1.1 Scaffold with logos-module-builder
The fastest way to create a new module is using the **logos-module-builder** template:
` ``bash
# Create a new directory for your module
mkdir logos-my-module && cd logos-my-module
# Scaffold a minimal module (no external dependencies)
nix flake init -t github:logos-co/logos-module-builder
# Or scaffold a module that wraps an external C/C++ library
nix flake init -t github:logos-co/logos-module-builder#with-external-lib
` ``
This generates a ready-to-build project with all the boilerplate handled for you.
### 1.2 Project Structure
After scaffolding, your module directory looks like this:
` ``
logos-my-module/
├── flake.nix # Nix flake (build config, ~15 lines)
├── module.yaml # Declarative module configuration (~30 lines)
├── CMakeLists.txt # CMake build file (~25 lines)
├── metadata.json # Auto-generated at build time from module.yaml
└── src/
├── my_module_interface.h # Qt interface definition
├── my_module_plugin.h # Plugin header
└── my_module_plugin.cpp # Plugin implementation
` ``
The key insight: **logos-module-builder** reduces ~600 lines of configuration across 5+ files down to ~70 lines across 2-3 files.
### 1.3 The module.yaml Configuration
The ` module.yaml` file is the central configuration for your module:
` ``yaml
name: my_module
version: 1.0.0
type: core
category: general
description: "My first Logos module"
dependencies: []
# Nix packages needed at build/runtime (optional)
nix_packages:
build: []
runtime: []
# CMake configuration (optional)
cmake:
find_packages: []
extra_sources: []
extra_include_dirs: []
extra_link_libraries: []
` ``
**Field reference:**
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| ` name` | Yes | -- | Module name (used for filenames and identifiers) |
| ` version` | No | ` 1.0.0` | Semantic version |
| ` type` | No | ` core` | Module type |
| ` category` | No | ` general` | Category (general, network, chat, wallet, integration) |
| ` description` | No | ` "A Logos module"` | Human-readable description |
| ` dependencies` | No | ` []` | Other Logos module names this depends on |
| ` nix_packages.build` | No | ` []` | Nix packages for build time |
| ` nix_packages.runtime` | No | ` []` | Nix packages for runtime |
| ` cmake.find_packages` | No | ` []` | CMake ` find_package()` calls |
| ` cmake.extra_sources` | No | ` []` | Additional source files to compile |
| ` cmake.extra_include_dirs` | No | ` []` | Additional include directories |
| ` cmake.extra_link_libraries` | No | ` []` | Additional libraries to link |
### 1.4 Writing Module Code
A Logos module is a **Qt plugin**. It must:
1. Inherit from ` QObject` and implement the ` PluginInterface`
2. Declare an interface with ` Q_INTERFACES`
3. Embed metadata with ` Q_PLUGIN_METADATA`
4. Mark callable methods with ` Q_INVOKABLE`
#### The Interface Header (` src/my_module_interface.h`)
` ``cpp
#pragma once
#include <QtPlugin>
#include <QString>
#include <interface.h> // From logos-cpp-sdk: provides PluginInterface
class MyModuleInterface : public PluginInterface
{
public:
virtual ~MyModuleInterface() {}
// Declare your module's public methods here
virtual QString doSomething(const QString& input) = 0;
virtual int compute(int a, int b) = 0;
};
#define MyModuleInterface_iid "com.logos.MyModuleInterface"
Q_DECLARE_INTERFACE(MyModuleInterface, MyModuleInterface_iid)
` ``
#### The Plugin Header (` src/my_module_plugin.h`)
` ``cpp
#pragma once
#include <QObject>
#include "my_module_interface.h"
class MyModulePlugin : public QObject, public MyModuleInterface
{
Q_OBJECT
Q_INTERFACES(MyModuleInterface PluginInterface)
Q_PLUGIN_METADATA(IID MyModuleInterface_iid FILE "metadata.json")
public:
explicit MyModulePlugin(QObject* parent = nullptr);
~MyModulePlugin();
// PluginInterface
QString name() const override { return "my_module"; }
QString version() const override { return "1.0.0"; }
// Your methods -- mark with Q_INVOKABLE for remote access
Q_INVOKABLE void initLogos(LogosAPI* logosAPIInstance);
Q_INVOKABLE QString doSomething(const QString& input) override;
Q_INVOKABLE int compute(int a, int b) override;
signals:
// For event forwarding to other modules
void eventResponse(const QString& eventName, const QVariantList& data);
};
` ``
#### The Plugin Implementation (` src/my_module_plugin.cpp`)
` ``cpp
#include "my_module_plugin.h"
#include <QDebug>
MyModulePlugin::MyModulePlugin(QObject* parent) : QObject(parent)
{
qDebug() << "MyModulePlugin: created";
}
MyModulePlugin::~MyModulePlugin()
{
qDebug() << "MyModulePlugin: destroyed";
}
void MyModulePlugin::initLogos(LogosAPI* logosAPIInstance)
{
// Store the API pointer for inter-module communication
logosAPI = logosAPIInstance;
qDebug() << "MyModulePlugin: LogosAPI initialized";
}
QString MyModulePlugin::doSomething(const QString& input)
{
return "Processed: " + input;
}
int MyModulePlugin::compute(int a, int b)
{
return a + b;
}
` ``
**Key rules:**
- Every ` Q_INVOKABLE` method is discoverable and callable by other modules at runtime
- ` initLogos(LogosAPI*)` is called by the host when your module is loaded -- store the pointer for later use
- The ` eventResponse` signal is used for event forwarding between modules
- ` name()` must match the ` name` field in your ` module.yaml` / ` metadata.json`
### 1.5 Building Your Module
` ``bash
# Build everything (library + generated SDK headers)
nix build
# Build just the plugin shared library (.so / .dylib)
nix build .#lib
# Build just the generated SDK headers (for other modules to use)
nix build .#include
# Enter the development shell (provides cmake, ninja, Qt, etc.)
nix develop
# Inside the dev shell, you can also build directly with CMake:
cmake -B build -GNinja
cmake --build build
` ``
**Build outputs:**
` ``
result/
├── lib/
│ └── my_module_plugin.so # (or .dylib on macOS)
├── include/
│ └── ... # Generated SDK headers
└── share/
└── metadata.json # Runtime metadata
` ``
---
## Part 2: Inspecting and Testing Your Module
### 2.1 The ` lm` CLI Tool
The **` lm`** tool (from ` logos-module`) lets you inspect compiled module binaries without loading them into the full runtime. It reads metadata and enumerates methods via Qt's meta-object system.
#### Building lm
` ``bash
nix build 'github:logos-co/logos-module#lm' --out-link ./lm
` ``
#### Viewing Metadata
` ``bash
# Human-readable metadata
./lm/bin/lm metadata ./result/lib/my_module_plugin.so
# JSON output
./lm/bin/lm metadata ./result/lib/my_module_plugin.so --json
` ``
Example JSON output:
` ``json
{
"name": "my_module",
"version": "1.0.0",
"description": "My first Logos module",
"author": "",
"type": "core",
"dependencies": []
}
` ``
#### Viewing Methods
` ``bash
# Human-readable method list
./lm/bin/lm methods ./result/lib/my_module_plugin.so
# JSON output
./lm/bin/lm methods ./result/lib/my_module_plugin.so --json
` ``
Example JSON output:
` ``json
[
{
"name": "initLogos",
"signature": "initLogos(LogosAPI*)",
"returnType": "void",
"isInvokable": true,
"parameters": [
{ "name": "logosAPIInstance", "type": "LogosAPI*" }
]
},
{
"name": "doSomething",
"signature": "doSomething(QString)",
"returnType": "QString",
"isInvokable": true,
"parameters": [
{ "name": "input", "type": "QString" }
]
}
]
` ``
### 2.2 Running with ` logoscore`
The **` logoscore`** CLI (from ` logos-liblogos`) is a headless runtime that can load modules and invoke their methods from the command line.
#### Building logoscore
` ``bash
nix build 'github:logos-co/logos-liblogos' --out-link ./logos
` ``
#### Running a Module
` ``bash
# Load a module from a directory
./logos/bin/logoscore \
-m ./modules \
--load-modules my_module
# Load a module and call a method
./logos/bin/logoscore \
-m ./modules \
--load-modules my_module \
-c "my_module.doSomething(hello)"
# Load a module and call a method with a JSON config file
./logos/bin/logoscore \
-m ./modules \
--load-modules my_module \
-c "my_module.configure(@config.json)"
` ``
**Flags:**
| Flag | Description |
|------|-------------|
| ` -m <dir>` | Directory containing module libraries |
| ` --load-modules <name1,name2>` | Comma-separated list of modules to load |
| ` -c "<module>.<method>(args)"` | Command to execute after loading |
| ` @file .json` | Pass a JSON file as a method argument |
### 2.3 The logos-module-viewer
The **logos-module-viewer** is a graphical tool for inspecting loaded modules.
` ``bash
# Build the viewer
nix build 'github:logos-co/logos-module-viewer#app' --out-link ./logos-viewer
# Run it with your module
./logos-viewer/bin/logos-module-viewer -m ./result/lib/my_module_plugin.so
` ``
This opens a window showing the module's metadata, methods, and allows interactive method invocation.
---
## Part 3: Packaging Your Module
### 3.1 The LGX Package Format
Logos modules are distributed as **` .lgx` packages**. An LGX file is a gzip-compressed tar archive with a specific internal structure:
` ``
manifest.json # Package metadata (required)
manifest.cose # Optional cryptographic signature
variants/ # Platform-specific builds (required)
linux-x86_64/
my_module_plugin.so
darwin-arm64/
my_module_plugin.dylib
docs/ # Optional documentation
licenses/ # Optional license files
` ``
The **manifest.json** declares the package name, version, and maps each variant to its main entry point (the shared library file):
` ``json
{
"name": "my_module",
"version": "1.0.0",
"description": "My first Logos module",
"author": "Developer Name",
"type": "core",
"category": "general",
"manifestVersion": "0.1",
"main": {
"linux-x86_64": "my_module_plugin.so",
"darwin-arm64": "my_module_plugin.dylib"
},
"dependencies": []
}
` ``
### 3.2 Creating a Package with ` lgx`
The **` lgx`** CLI tool (from ` logos-package`) creates and manages LGX packages.
#### Building lgx
` ``bash
nix build 'github:logos-co/logos-package#lgx' --out-link ./lgx
` ``
#### Creating a New Package
` ``bash
# Create an empty package skeleton
./lgx/bin/lgx create my_module.lgx --name my_module
` ``
#### Adding Platform Variants
` ``bash
# Add a single-file variant (the library binary)
./lgx/bin/lgx add-variant my_module.lgx \
--variant linux-x86_64 \
--files ./result/lib/my_module_plugin.so
# Add a macOS variant
./lgx/bin/lgx add-variant my_module.lgx \
--variant darwin-arm64 \
--files ./result-macos/lib/my_module_plugin.dylib
# Add a directory variant (if your module has multiple files)
./lgx/bin/lgx add-variant my_module.lgx \
--variant linux-x86_64 \
--files ./result/lib/ \
--main my_module_plugin.so
` ``
**Variant naming convention:** ` <os>-<arch>` (lowercase). Common variants:
| Variant | Platform |
|---------|----------|
| ` linux-x86_64` | Linux Intel/AMD 64-bit |
| ` linux-arm64` | Linux ARM 64-bit |
| ` darwin-arm64` | macOS Apple Silicon |
| ` darwin-x86_64` | macOS Intel |
#### Removing a Variant
` ``bash
./lgx/bin/lgx remove-variant my_module.lgx --variant linux-x86_64
` ``
#### Listing Package Contents
` ``bash
./lgx/bin/lgx list my_module.lgx
` ``
#### Extracting a Package
` ``bash
# Extract a specific variant
./lgx/bin/lgx extract my_module.lgx --variant linux-x86_64 --output ./extracted/
# Extract all variants
./lgx/bin/lgx extract my_module.lgx --all --output ./extracted/
` ``
### 3.3 Verifying Packages
` ``bash
./lgx/bin/lgx verify my_module.lgx
` ``
This checks:
- Package structure is valid (manifest.json exists, variants/ directory exists)
- Manifest fields are present and valid
- Every variant listed in ` main` has a corresponding directory and file
- Every variant directory has a corresponding ` main` entry
- No forbidden files (symlinks, special files) are present
- All paths are valid (no ` ..` traversal, no absolute paths)
---
## Part 4: Installing and Managing Modules
### 4.1 The ` lgpm` CLI
The **` lgpm`** CLI (Logos Package Manager) installs, searches, and manages module packages.
#### Building lgpm
` ``bash
nix build 'github:logos-co/logos-package-manager-module#cli' --out-link ./package-manager
` ``
#### Commands
` ``bash
# Search for packages
lgpm search waku
# List all available packages
lgpm list
# List only installed packages
lgpm list --installed
# List packages in a category
lgpm list --category networking
# Show package details
lgpm info my_module
# List available categories
lgpm categories
# Install a package (with dependency resolution)
lgpm install my_module
# Install multiple packages
lgpm install my_module another_module
# Install from a local .lgx file
lgpm install --file ./my_module.lgx
` ``
#### Global Options
| Option | Description |
|--------|-------------|
| ` --modules-dir <path>` | Target directory for installed core modules |
| ` --ui-plugins-dir <path>` | Target directory for UI plugins |
| ` --release <tag>` | GitHub release tag to use (default: ` latest`) |
| ` --json` | Output in JSON format |
| ` -h, --help` | Show help |
### 4.2 Installing from Local Files
` ``bash
# Install a locally built .lgx package
./package-manager/bin/lgpm --modules-dir ./modules install --file ./my_module.lgx
` ``
### 4.3 Installing from a Registry
` ``bash
# Install a published package (lgpm fetches from GitHub Releases)
./package-manager/bin/lgpm --modules-dir ./modules install my_module
# Install from a specific release
./package-manager/bin/lgpm --modules-dir ./modules --release v2.0.0 install my_module
` ``
The package manager automatically:
1. Resolves transitive dependencies
2. Downloads the correct platform variant for your OS/architecture
3. Extracts the LGX package
4. Copies the library to the target directory
---
2026-03-18 14:22:43 +01:00
## Part 5: Running in logos-basecamp
2026-03-06 14:05:53 +00:00
2026-03-18 14:22:43 +01:00
### 5.1 Building logos-basecamp
2026-03-06 14:05:53 +00:00
` ``bash
# Build the full application
2026-03-18 14:22:43 +01:00
nix build 'github:logos-co/logos-basecamp#app' --out-link ./logos-basecamp
2026-03-06 14:05:53 +00:00
# Run it
2026-03-18 14:22:43 +01:00
./logos-basecamp/bin/logos-basecamp
2026-03-06 14:05:53 +00:00
# Or build platform-specific distributions:
2026-03-18 14:22:43 +01:00
nix build 'github:logos-co/logos-basecamp#bin-appimage' # Linux AppImage
nix build 'github:logos-co/logos-basecamp#bin-macos-app' # macOS .app bundle
nix build 'github:logos-co/logos-basecamp#bin-macos-dmg' # macOS DMG
2026-03-06 14:05:53 +00:00
` ``
2026-03-18 14:22:43 +01:00
### 5.2 Module Types in logos-basecamp
2026-03-06 14:05:53 +00:00
The application supports three types of modules:
#### Core Modules (Backend)
These are non-UI modules that provide backend functionality. They run in isolated ` logos_host` processes and communicate via Qt Remote Objects.
- Loaded via ` logos_core_load_plugin()`
- Placed in the **modules directory** (` --modules-dir`)
- Have ` "type": "core"` in metadata
#### C++ UI Modules (Native Widgets)
These provide native Qt widget UIs. They implement the ` IComponent` interface:
` ``cpp
class IComponent {
public:
virtual ~IComponent() = default;
virtual QWidget* createWidget(LogosAPI* logosAPI = nullptr) = 0;
virtual void destroyWidget(QWidget* widget) = 0;
};
` ``
- Loaded via ` QPluginLoader`
- Placed in the **plugins directory** (` --ui-plugins-dir`)
- Their widget appears as a tab in the MDI workspace
#### QML UI Modules (Sandboxed)
These provide QML-based UIs in a sandboxed environment:
- Have ` "type": "ui_qml"` in their manifest
- Entry point is ` Main.qml`
- Network access is denied
- Filesystem access is restricted to the module's own directory
- Can call core modules via the ` logos` bridge: ` logos.callModule("module", "method", [args])`
### 5.3 Development Mode
For rapid iteration on QML UI modules, use the development mode launcher:
` ``bash
# Build once
2026-03-18 14:22:43 +01:00
nix build 'github:logos-co/logos-basecamp'
2026-03-06 14:05:53 +00:00
# Run with live QML reloading (edits to .qml files take effect immediately)
./run-dev.sh
` ``
This sets ` QML_UI` to point to the source directory and disables QML caching, so you can edit QML files and see changes without rebuilding.
---
## Part 6: Inter-Module Communication
### 6.1 The LogosAPI
Every module receives a ` LogosAPI*` pointer when ` initLogos()` is called. This is your gateway to communicating with other modules.
` ``cpp
void MyModulePlugin::initLogos(LogosAPI* logosAPIInstance)
{
logosAPI = logosAPIInstance;
// Get a client for calling another module
LogosAPIClient* client = logosAPI->getClient("other_module");
// Call a method on that module
QVariant result = client->invokeRemoteMethod(
"other_module", // target module name
"someMethod", // method name
arg1, arg2 // arguments (up to 5 positional args)
);
}
` ``
### 6.2 The C++ SDK Code Generator
The ` logos-cpp-generator` tool (from ` logos-cpp-sdk`) inspects a compiled module and generates typed C++ wrapper classes, so you get compile-time type safety instead of raw ` invokeRemoteMethod` calls.
#### Generating Wrappers
` ``bash
# Generate wrappers for a single module
logos-cpp-generator /path/to/my_module_plugin.so --output-dir ./generated
# Generate wrappers for all dependencies listed in metadata.json
logos-cpp-generator --metadata metadata.json --module-dir /path/to/modules --output-dir ./generated
# Generate only module files (no umbrella headers)
logos-cpp-generator /path/to/plugin.so --module-only --output-dir ./generated
# Generate only umbrella SDK files (assumes module files exist)
logos-cpp-generator --metadata metadata.json --general-only --output-dir ./generated
` ``
#### Using Generated Wrappers
After generation, you get typed wrapper classes:
` ``cpp
#include "logos_sdk.h" // Umbrella header
// In your module's initLogos():
void MyModulePlugin::initLogos(LogosAPI* api) {
logosAPI = api;
// Create the typed SDK wrapper
LogosModules* logos = new LogosModules(api);
// Call other modules with type safety
QString result = logos->other_module.doSomething("hello");
bool ok = logos->core_manager.loadPlugin("another_module");
}
` ``
The generated ` LogosModules` struct provides a member for each module, with methods matching the module's ` Q_INVOKABLE` methods.
### 6.3 LogosResult
Many module methods return ` LogosResult` for structured success/error handling:
` ``cpp
LogosResult result = logos->my_module.someMethod();
if (result.success) {
// Access the value
QString value = result.getString();
int number = result.getInt();
QVariantMap map = result.getMap();
QVariantList list = result.getList();
// Access nested values
QString name = result.getString("name");
int count = result.getInt("count", 0); // with default
} else {
// Access the error
QString error = result.getError();
}
` ``
To return a ` LogosResult` from your module:
` ``cpp
Q_INVOKABLE LogosResult MyModulePlugin::fetchData(const QString& id) {
if (id.isEmpty()) {
return {false, QVariant(), "ID cannot be empty"};
}
QVariantMap data;
data["id"] = id;
data["name"] = "Example";
data["count"] = 42;
return {true, data};
}
` ``
### 6.4 Communication Modes
The SDK supports two communication modes:
| Mode | Use Case | Mechanism |
|------|----------|-----------|
| **Remote** (default) | Desktop apps | Qt Remote Objects (IPC between processes) |
| **Local** | Mobile apps, single-process | In-process ` PluginRegistry` |
Set the mode before creating any ` LogosAPI` instances:
` ``cpp
// For mobile / embedded (all modules in one process)
LogosModeConfig::setMode(LogosMode::Local);
// For desktop (each module in its own process) -- this is the default
LogosModeConfig::setMode(LogosMode::Remote);
` ``
---
## Part 7: Advanced Topics
### 7.1 Wrapping External Libraries
To create a module that wraps an external C/C++ library, use the external library template:
` ``bash
nix flake init -t github:logos-co/logos-module-builder#with-external-lib
` ``
Then configure the external library in ` module.yaml`:
` ``yaml
name: my_wrapper_module
version: 1.0.0
description: "Wraps libfoo for Logos"
external_libraries:
- name: libfoo
flake_input: "github:example/libfoo"
output_pattern: "lib/libfoo.*"
# Or for a vendored library:
external_libraries:
- name: libfoo
vendor_path: "vendor/libfoo"
build_command: "make"
output_pattern: "build/lib/libfoo.*"
# Or for a Go library:
external_libraries:
- name: libfoo
vendor_path: "vendor/libfoo"
go_build: true
output_pattern: "libfoo.*"
` ``
The builder handles downloading, building, and linking the external library into your module.
### 7.2 UI Modules (C++ Widgets)
To create a module with a native Qt widget UI:
1. Implement the ` IComponent` interface
2. Set ` "type": "ui"` in your metadata
3. Return a ` QWidget*` from ` createWidget()`
2026-03-19 19:42:15 +01:00
` IComponent.h` is not part of the SDK — each UI module vendors its own copy in ` interfaces/IComponent.h`:
` ``cpp
// interfaces/IComponent.h (copy verbatim into your module)
#pragma once
#include <QObject>
#include <QWidget>
#include <QtPlugin>
class LogosAPI;
class IComponent {
public:
virtual ~IComponent() = default;
virtual QWidget* createWidget(LogosAPI* logosAPI = nullptr) = 0;
virtual void destroyWidget(QWidget* widget) = 0;
};
#define IComponent_iid "com.logos.component.IComponent"
Q_DECLARE_INTERFACE(IComponent, IComponent_iid)
` ``
Expose it via ` INCLUDE_DIRS` in your ` CMakeLists.txt`:
` ``cmake
logos_module(
NAME my_ui_module
SOURCES src/my_ui_plugin.h src/my_ui_plugin.cpp
INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/interfaces
)
` ``
Then implement the plugin:
2026-03-06 14:05:53 +00:00
` ``cpp
#include <IComponent.h>
class MyUIPlugin : public QObject, public IComponent
{
Q_OBJECT
Q_INTERFACES(IComponent)
Q_PLUGIN_METADATA(IID IComponent_iid FILE "metadata.json")
public:
Q_INVOKABLE QWidget* createWidget(LogosAPI* logosAPI = nullptr) override {
auto* widget = new QWidget();
// Build your UI here
return widget;
}
void destroyWidget(QWidget* widget) override {
delete widget;
}
};
` ``
### 7.3 UI Modules (QML)
For a QML-based UI module, create a directory with:
` ``
my_qml_module/
├── manifest.json
├── metadata.json
└── Main.qml
` ``
**manifest.json:**
` ``json
{
"type": "ui_qml",
"main": "Main.qml",
"name": "my_qml_module",
"version": "1.0.0"
}
` ``
**Main.qml:**
` ``qml
import QtQuick 2.15
import QtQuick.Controls 2.15
Item {
width: 400
height: 300
Button {
text: "Call Core Module"
onClicked: {
// logos bridge is injected by the host
var result = logos.callModule("my_module", "doSomething", ["hello"])
console.log("Result:", result)
}
}
}
` ``
QML modules are sandboxed: no network access, no filesystem access outside the module directory.
### 7.4 Module Dependencies
Declare dependencies in your ` module.yaml`:
` ``yaml
name: my_module
dependencies:
- package_manager
- waku_module
` ``
Or in ` metadata.json`:
` ``json
{
"name": "my_module",
"dependencies": ["package_manager", "waku_module"]
}
` ``
2026-03-18 14:22:43 +01:00
When your module is installed via ` lgpm`, its dependencies are automatically resolved and installed first. When loaded via ` logos-basecamp`, core module dependencies are loaded before your module.
2026-03-06 14:05:53 +00:00
---
## Reference: Repository Map
| Repository | What It Provides | Key Outputs |
|------------|-----------------|-------------|
| [logos-module-builder](https://github.com/logos-co/logos-module-builder) | Build system / scaffolding | ` mkLogosModule` Nix function, ` LogosModule.cmake`, templates |
| [logos-module](https://github.com/logos-co/logos-module) | Plugin introspection | ` liblogos_module.a` (static lib), ` lm` (CLI) |
| [logos-cpp-sdk](https://github.com/logos-co/logos-cpp-sdk) | SDK + code generator | ` LogosAPI`, ` LogosResult`, ` logos-cpp-generator`, ` PluginInterface` |
| [logos-liblogos](https://github.com/logos-co/logos-liblogos) | Core runtime | ` logoscore` (CLI), ` logos_host`, ` liblogos_core` |
| [logos-package](https://github.com/logos-co/logos-package) | Package format | ` lgx` (CLI), ` liblgx` (library) |
| [logos-package-manager-module](https://github.com/logos-co/logos-package-manager-module) | Package management | ` lgpm` (CLI), ` package_manager_plugin` |
2026-03-18 14:22:43 +01:00
| [logos-basecamp](https://github.com/logos-co/logos-basecamp) | Desktop app shell | ` LogosApp` (GUI), MDI workspace, plugin loader |
2026-03-06 14:05:53 +00:00
## Reference: CLI Tools Summary
### ` lm` -- Module Inspector
` ``bash
lm metadata <plugin-file> [--json] # View module metadata
lm methods <plugin-file> [--json] # List Q_INVOKABLE methods
` ``
### ` logoscore` -- Headless Runtime
` ``bash
logoscore -m <modules-dir> --load-modules <name> [-c "<module>.<method>(args)"]
` ``
### ` lgx` -- Package Tool
` ``bash
lgx create <output.lgx> --name <name> # Create empty package
lgx add-variant <pkg.lgx> --variant <name> --files <path> [--main <file>]
lgx remove-variant <pkg.lgx> --variant <name>
lgx list <pkg.lgx> # List contents
lgx verify <pkg.lgx> # Validate structure
lgx extract <pkg.lgx> --variant <name> --output <dir> # Extract
` ``
### ` lgpm` -- Package Manager
` ``bash
lgpm search <query> # Search packages
lgpm list [--category <cat>] [--installed] # List packages
lgpm install <pkg> [pkgs...] # Install with dependency resolution
lgpm install --file <path.lgx> # Install local file
lgpm info <pkg> # Package details
lgpm categories # List categories
` ``
### ` logos-cpp-generator` -- SDK Code Generator
` ``bash
logos-cpp-generator <plugin-file> [--output-dir <dir>] [--module-only]
logos-cpp-generator --metadata <metadata.json> --module-dir <dir> [--output-dir <dir>]
logos-cpp-generator --metadata <metadata.json> --general-only [--output-dir <dir>]
` ``
---
## Troubleshooting
### "experimental features" error with Nix
If you see errors about experimental features, either pass the flag:
` ``bash
nix --extra-experimental-features "nix-command flakes" build
` ``
Or add to ` ~/.config/nix/nix.conf`:
` ``
experimental-features = nix-command flakes
` ``
### Module loads but LogosAPI is not available
2026-03-18 14:22:43 +01:00
This happens when running a module outside the full Logos runtime (e.g., in the module viewer). The ` LogosAPI` is only available when the module is loaded by ` logoscore` or ` logos-basecamp`.
2026-03-06 14:05:53 +00:00
### Build fails finding Qt
Ensure you're building inside the Nix environment:
` ``bash
nix develop # Enter dev shell with all dependencies
cmake -B build -GNinja && cmake --build build
` ``
2026-03-18 14:22:43 +01:00
### Module not discovered by logos-basecamp
2026-03-06 14:05:53 +00:00
Check that:
1. The module binary is in the correct directory (modules dir for core, plugins dir for UI)
2. The ` metadata.json` file is present alongside the binary
3. The ` name` field in metadata matches the binary name (e.g., ` my_module_plugin.so` for module named ` my_module`)
### lgpm install fails
- Check your internet connection (lgpm fetches from GitHub Releases)
- Try specifying a release: ` lgpm --release v1.0.0 install my_module`
- For local files: ` lgpm install --file ./my_module.lgx`
- Check the target directory is writable: ` lgpm --modules-dir ./modules install my_module`
### Cross-platform builds
Build on each target platform separately, then add each binary as a variant to the same ` .lgx` package:
` ``bash
# On Linux x86_64:
nix build .#lib
lgx add-variant my_module.lgx --variant linux-x86_64 --files ./result/lib/my_module_plugin.so
# On macOS arm64:
nix build .#lib
lgx add-variant my_module.lgx --variant darwin-arm64 --files ./result/lib/my_module_plugin.dylib
` ``