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 )
2026-03-24 18:36:10 +01:00
- [1.3 The metadata.json Configuration ](#13-the-metadatajson-configuration )
2026-03-06 14:05:53 +00:00
- [1.4 Writing Module Code ](#14-writing-module-code )
- [1.5 Building Your Module ](#15-building-your-module )
2026-03-25 10:37:15 +01:00
- [Part 2: Inspecting Your Module ](#part-2-inspecting-your-module )
2026-03-06 14:05:53 +00:00
- [2.1 The lm CLI Tool ](#21-the-lm-cli-tool )
2026-03-25 10:37:15 +01:00
- [2.2 The logos-module-viewer ](#22-the-logos-module-viewer )
2026-03-06 14:05:53 +00:00
- [Part 3: Packaging Your Module ](#part-3-packaging-your-module )
- [3.1 The LGX Package Format ](#31-the-lgx-package-format )
2026-03-26 11:48:27 +01:00
- [3.2 Building LGX Packages ](#32-building-lgx-packages )
- [Built-in Nix Derivation (Preferred) ](#built-in-nix-derivation-preferred )
- [Using nix bundle (Alternative) ](#using-nix-bundle-alternative )
2026-03-06 14:05:53 +00:00
- [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-25 10:37:15 +01:00
- [Part 5: Running Your Module ](#part-5-running-your-module )
- [5.1 Running with logoscore ](#51-running-with-logoscore )
- [Part 6: Running in logos-basecamp ](#part-6-running-in-logos-basecamp )
- [6.1 Building logos-basecamp ](#61-building-logos-basecamp )
- [6.2 Module Types in logos-basecamp ](#62-module-types-in-logos-basecamp )
- [Part 7: Inter-Module Communication ](#part-7-inter-module-communication )
- [7.1 The LogosAPI ](#71-the-logosapi )
- [7.2 The C++ SDK Code Generator ](#72-the-c-sdk-code-generator )
- [7.3 LogosResult ](#73-logosresult )
- [7.4 Communication Modes ](#74-communication-modes )
- [Part 8: Advanced Topics ](#part-8-advanced-topics )
- [8.1 Tutorials ](#81-tutorials )
- [8.2 Module Dependencies ](#82-module-dependencies )
2026-03-06 14:05:53 +00:00
- [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 |
2026-03-24 13:53:18 -04:00
| **logos-liblogos** | [logos-co/logos-liblogos ](https://github.com/logos-co/logos-liblogos ) | Core library (`logos_host` , `liblogos_core` ) |
| **logos-logoscore-cli** | [logos-co/logos-logoscore-cli ](https://github.com/logos-co/logos-logoscore-cli ) | Headless CLI runtime (`logoscore` ) |
2026-03-06 14:05:53 +00:00
| **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-25 10:37:15 +01:00
| **logos-standalone-app** | [logos-co/logos-standalone-app ](https://github.com/logos-co/logos-standalone-app ) | Minimal shell for running/testing UI modules in isolation |
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
2026-03-25 10:37:15 +01:00
# Scaffold a minimal core module (no external dependencies)
2026-03-06 14:05:53 +00:00
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
2026-03-25 10:37:15 +01:00
# For UI modules (C++ Qt widget with logos-standalone-app runner)
nix flake init -t github:logos-co/logos-module-builder#ui-module
# For QML UI modules (with logos-standalone-app runner)
nix flake init -t github:logos-co/logos-module-builder#ui-qml-module
2026-03-06 14:05:53 +00:00
` ``
2026-03-25 10:37:15 +01:00
**Available templates:**
| Template | Use Case |
|----------|----------|
| ` default` | Minimal core module (C++ backend, no UI) |
| ` with-external-lib` | Core module wrapping an external C/C++ library |
| ` ui-module` | C++ Qt widget UI module with ` logos-standalone-app` runner |
| ` ui-qml-module` | QML-based UI module with ` logos-standalone-app` runner |
The ` ui-module` and ` ui-qml-module` templates include ` logos-standalone-app` as an input, enabling ` nix run` to launch and test your UI plugin in isolation without the full logos-basecamp shell.
2026-03-06 14:05:53 +00:00
This generates a ready-to-build project with all the boilerplate handled for you.
### 1.2 Project Structure
2026-03-25 10:37:15 +01:00
> We will use the ` default` template here (minimal core module).
2026-03-06 14:05:53 +00:00
After scaffolding, your module directory looks like this:
` ``
logos-my-module/
├── flake.nix # Nix flake (build config, ~15 lines)
2026-03-24 18:36:10 +01:00
├── metadata.json # Single source of truth: module metadata + build config (~30 lines)
2026-03-06 14:05:53 +00:00
├── CMakeLists.txt # CMake build file (~25 lines)
└── src/
├── my_module_interface.h # Qt interface definition
├── my_module_plugin.h # Plugin header
└── my_module_plugin.cpp # Plugin implementation
` ``
2026-03-24 18:36:10 +01:00
The key insight: **logos-module-builder** reduces ~600 lines of configuration across 5+ files down to ~70 lines across 2-3 files. ` metadata.json` serves as the single source of truth — it contains both the runtime metadata (embedded into the plugin binary by Qt) and the build configuration (read by the builder via the ` nix` section).
2026-03-06 14:05:53 +00:00
2026-03-26 13:45:12 +01:00
The ` CMakeLists.txt` is minimal -- it includes ` LogosModule.cmake` (provided by the builder) and calls the ` logos_module()` macro, which sets up the Qt plugin target, links the SDK, configures include paths, and handles code generation. You just list your source files. See the generated [` CMakeLists.txt`](https://github.com/logos-co/logos-module-builder/blob/master/templates/minimal-module/CMakeLists.txt) in the template.
2026-03-25 10:37:15 +01:00
2026-03-24 18:36:10 +01:00
### 1.3 The metadata.json Configuration
2026-03-06 14:05:53 +00:00
2026-03-26 13:45:12 +01:00
The ` metadata.json` file is the single source of truth for your module. It is embedded into the plugin binary by Qt's ` Q_PLUGIN_METADATA` macro (for runtime metadata), read by ` logos-module-builder` to configure the Nix build, used by CMake to resolve external dependencies and link libraries (via the ` nix` section), and used by ` nix-bundle-lgx` to generate the LGX manifest. See the scaffolded [` metadata.json`](https://github.com/logos-co/logos-module-builder/blob/master/templates/minimal-module/metadata.json) in the template.
The full set of available fields:
2026-03-06 14:05:53 +00:00
2026-03-24 18:36:10 +01:00
` ``json
{
"name": "my_module",
"version": "1.0.0",
"type": "core",
"category": "general",
"description": "My first Logos module",
2026-03-26 13:45:12 +01:00
"icon": null,
2026-03-24 18:36:10 +01:00
"main": "my_module_plugin",
"dependencies": [],
2026-03-26 13:45:12 +01:00
"include": [],
2026-03-06 14:05:53 +00:00
2026-03-24 18:36:10 +01:00
"nix": {
"packages": {
"build": [],
"runtime": []
},
"external_libraries": [],
"cmake": {
"find_packages": [],
"extra_sources": [],
"extra_include_dirs": [],
"extra_link_libraries": []
}
}
}
2026-03-06 14:05:53 +00:00
` ``
**Field reference:**
| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| ` name` | Yes | -- | Module name (used for filenames and identifiers) |
| ` version` | No | ` 1.0.0` | Semantic version |
2026-03-24 18:36:10 +01:00
| ` type` | No | ` core` | Module type (` core`, ` ui`, ` ui_qml`) |
2026-03-06 14:05:53 +00:00
| ` category` | No | ` general` | Category (general, network, chat, wallet, integration) |
| ` description` | No | ` "A Logos module"` | Human-readable description |
2026-03-26 13:45:12 +01:00
| ` icon` | No | ` null` | Relative path to the module icon (used by UI modules). The build system includes it in the standalone app plugin directory. |
2026-03-24 18:36:10 +01:00
| ` main` | Yes | -- | Plugin entry point (plugin name for core/ui, ` Main.qml` for QML) |
2026-03-25 10:37:15 +01:00
| ` dependencies` | No | ` []` | Other Logos module names this depends on. Each entry must match the ` name` field in that dependency's ` metadata.json`. |
2026-03-26 13:45:12 +01:00
| ` include` | No | ` []` | Additional files (e.g. shared libraries like ` libwaku.so`, ` libwaku.dylib`) to bundle alongside the plugin in the output. |
2026-03-24 18:36:10 +01:00
| ` nix.packages.build` | No | ` []` | Nix packages for build time |
| ` nix.packages.runtime` | No | ` []` | Nix packages for runtime |
2026-03-26 13:45:12 +01:00
| ` nix.external_libraries` | No | ` []` | External C/C++ libraries to wrap. Each entry is an object — see [configuration reference](https://github.com/logos-co/logos-module-builder/blob/master/docs/configuration.md#nixexternal_libraries) for fields (` name`, ` vendor_path`, ` build_command`, etc.). |
2026-03-24 18:36:10 +01:00
| ` nix.cmake.find_packages` | No | ` []` | CMake ` find_package()` calls |
| ` nix.cmake.extra_sources` | No | ` []` | Additional source files to compile |
| ` nix.cmake.extra_include_dirs` | No | ` []` | Additional include directories |
| ` nix.cmake.extra_link_libraries` | No | ` []` | Additional libraries to link |
2026-03-06 14:05:53 +00:00
2026-03-26 13:45:12 +01:00
### 1.4 Understanding the Module Code
2026-03-06 14:05:53 +00:00
2026-03-26 13:45:12 +01:00
The scaffolded source files form a standard **Qt plugin**. Browse the full source in the template:
[` src/`](https://github.com/logos-co/logos-module-builder/tree/master/templates/minimal-module/src) --
[` minimal_interface.h`](https://github.com/logos-co/logos-module-builder/blob/master/templates/minimal-module/src/minimal_interface.h) |
[` minimal_plugin.h`](https://github.com/logos-co/logos-module-builder/blob/master/templates/minimal-module/src/minimal_plugin.h) |
[` minimal_plugin.cpp`](https://github.com/logos-co/logos-module-builder/blob/master/templates/minimal-module/src/minimal_plugin.cpp)
2026-03-06 14:05:53 +00:00
2026-03-26 13:45:12 +01:00
Every Logos module must:
2026-03-06 14:05:53 +00:00
2026-03-26 13:45:12 +01:00
1. **Inherit from ` QObject` and implement ` PluginInterface`** -- the interface header declares pure-virtual methods; the plugin class implements them.
2. **Declare ` Q_INTERFACES` and ` Q_PLUGIN_METADATA`** -- this is how Qt discovers the plugin and embeds ` metadata.json`.
3. **Mark callable methods with ` Q_INVOKABLE`** -- any ` Q_INVOKABLE` method is automatically discoverable by ` lm`, callable by ` logoscore -c`, and accessible from other modules via ` LogosAPI`.
2026-03-06 14:05:53 +00:00
**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
2026-03-24 18:36:10 +01:00
- ` name()` must match the ` name` field in your ` metadata.json`
2026-03-06 14:05:53 +00:00
### 1.5 Building Your Module
` ``bash
2026-03-25 10:37:15 +01:00
# Nix requires all source files to be tracked by git
git init && git add -A
2026-03-06 14:05:53 +00:00
# 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
2026-03-26 13:45:12 +01:00
# Enter the dev shell for manual CMake builds (see: https://nix.dev/tutorials/first-steps/dev-environment)
# The shell provides cmake, ninja, Qt, the Logos SDK, and all build dependencies.
2026-03-06 14:05:53 +00:00
nix develop
2026-03-26 13:45:12 +01:00
cmake -B build -GNinja && cmake --build build
2026-03-06 14:05:53 +00:00
` ``
**Build outputs:**
` ``
result/
├── lib/
2026-03-26 11:48:27 +01:00
│ └── my_module_plugin.so # (or .dylib on macOS)
2026-03-25 10:37:15 +01:00
└── include/
├── my_module_api.h # Generated type-safe wrapper header
└── my_module_api.cpp # Generated wrapper implementation
2026-03-06 14:05:53 +00:00
` ``
---
2026-03-25 10:37:15 +01:00
## Part 2: Inspecting Your Module
2026-03-06 14:05:53 +00:00
### 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" }
]
}
]
` ``
2026-03-25 10:37:15 +01:00
### 2.2 The logos-module-viewer
2026-03-06 14:05:53 +00:00
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
2026-03-25 10:37:15 +01:00
Before you can run your module with ` logoscore` or install it into ` logos-basecamp`, you need to package the build output into an ` .lgx` package and install it into a ` modules/` directory.
2026-03-06 14:05:53 +00:00
### 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:
` ``
2026-03-25 10:37:15 +01:00
mymodule.lgx (tar.gz)
├── manifest.json # Package metadata
├── variants/
│ ├── linux-amd64/
│ │ └── my_module_plugin.so
│ ├── darwin-arm64/
│ │ └── my_module_plugin.dylib
│ └── darwin-arm64-dev/
│ └── my_module_plugin.dylib
├── docs/ # Optional
└── licenses/ # Optional
2026-03-06 14:05:53 +00:00
` ``
2026-03-25 10:37:15 +01:00
The **manifest.json** is auto-generated from your module's ` metadata.json` by the bundler. It maps each variant to its main entry point.
2026-03-06 14:05:53 +00:00
2026-03-26 11:48:27 +01:00
### 3.2 Building LGX Packages
2026-03-06 14:05:53 +00:00
2026-03-26 11:48:27 +01:00
There are two ways to create ` .lgx` packages. The preferred approach uses the built-in Nix derivation that comes with ` logos-module-builder`. Alternatively, you can use the ` nix bundle` command directly.
#### Built-in Nix Derivation (Preferred)
When your module's ` flake.nix` includes ` nix-bundle-lgx` as an input (which all ` logos-module-builder` templates do by default), LGX package outputs are automatically available as part of your flake:
2026-03-06 14:05:53 +00:00
` ``bash
2026-03-25 10:37:15 +01:00
# Dev variant (uses /nix/store references, for local development)
2026-03-26 11:48:27 +01:00
nix build .#lgx
2026-03-25 10:37:15 +01:00
# Portable variant (self-contained, all dependencies bundled)
2026-03-26 11:48:27 +01:00
nix build .#lgx-portable
# Dual variant (both dev and portable in one .lgx file)
nix build .#lgx-dual
` ``
This produces a ` my_module-<version>.lgx` file in the ` result/` directory.
This works because ` logos-module-builder.lib.mkLogosModule` detects the ` nix-bundle-lgx` input in your ` flakeInputs` and automatically creates the ` lgx`, ` lgx-portable`, and ` lgx-dual` package outputs. No extra configuration is needed — it is part of the standard module template:
` ``nix
{
inputs = {
logos-module-builder.url = "github:logos-co/logos-module-builder";
nix-bundle-lgx.url = "github:logos-co/nix-bundle-lgx";
};
outputs = inputs@{ logos-module-builder, ... }:
logos-module-builder.lib.mkLogosModule {
src = ./.;
configFile = ./metadata.json;
flakeInputs = inputs;
};
}
` ``
#### Using ` nix bundle` (Alternative)
You can also create ` .lgx` packages using the ` nix bundle` command directly. This is useful if your module does not use ` logos-module-builder` or if you need the ` dual` bundling mode (both dev and portable in a single ` .lgx` file):
` ``bash
# Dev variant
nix bundle --bundler github:logos-co/nix-bundle-lgx .#lib
# Portable variant
2026-03-25 10:37:15 +01:00
nix bundle --bundler github:logos-co/nix-bundle-lgx#portable .#lib
# Dual variant (both dev and portable in one .lgx file)
nix bundle --bundler github:logos-co/nix-bundle-lgx#dual .#lib
2026-03-06 14:05:53 +00:00
` ``
2026-03-25 10:37:15 +01:00
This produces a ` my_module-<version>.lgx` file in the current directory.
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
**Bundling modes:**
2026-03-06 14:05:53 +00:00
2026-03-26 11:48:27 +01:00
| Mode | Built-in Command | ` nix bundle` Command | Variant Created | Use Case |
|------|-----------------|---------------------|----------------|----------|
| **Dev** | ` nix build .#lgx ` | ` nix bundle --bundler ...#default .#lib ` | ` darwin-arm64-dev` | Local development (requires Nix store) |
| **Portable** | ` nix build .#lgx -portable` | ` nix bundle --bundler ...#portable .#lib ` | ` darwin-arm64` | Distribution (self-contained, no Nix needed) |
| **Dual** | ` nix build .#lgx -dual` | ` nix bundle --bundler ...#dual .#lib ` | Both dev and portable | One package for both environments |
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
**Variant naming:**
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
| Nix System | Dev Variant | Portable Variant |
|-----------|------------|-----------------|
| ` aarch64-darwin` | ` darwin-arm64-dev` | ` darwin-arm64` |
| ` x86_64-darwin` | ` darwin-amd64-dev` | ` darwin-amd64` |
| ` aarch64-linux` | ` linux-arm64-dev` | ` linux-arm64` |
| ` x86_64-linux` | ` linux-amd64-dev` | ` linux-amd64` |
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
> **Important:** The variant type matters when installing into ` logos-basecamp`. A dev build of basecamp expects dev variants, and a portable build expects portable variants. Use the ` dual` bundler to produce packages that work with both.
2026-03-06 14:05:53 +00:00
---
## Part 4: Installing and Managing Modules
### 4.1 The ` lgpm` CLI
2026-03-25 10:37:15 +01:00
The **` lgpm`** CLI (Logos Package Manager) installs, searches, and manages module packages. Installing a package extracts it into a ` modules/` directory that ` logoscore` and ` logos-basecamp` can load from.
2026-03-06 14:05:53 +00:00
#### Building lgpm
` ``bash
nix build 'github:logos-co/logos-package-manager-module#cli' --out-link ./package-manager
` ``
#### Commands
` ``bash
# Search for packages
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm search waku
2026-03-06 14:05:53 +00:00
# List all available packages
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm list
2026-03-06 14:05:53 +00:00
# List only installed packages
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm list --installed
2026-03-06 14:05:53 +00:00
# List packages in a category
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm list --category networking
2026-03-06 14:05:53 +00:00
# Show package details
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm info my_module
2026-03-06 14:05:53 +00:00
# List available categories
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm categories
2026-03-06 14:05:53 +00:00
# Install a package (with dependency resolution)
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm --modules-dir ./modules install my_module
2026-03-06 14:05:53 +00:00
# Install multiple packages
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm --modules-dir ./modules install my_module another_module
2026-03-06 14:05:53 +00:00
# Install from a local .lgx file
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm --modules-dir ./modules install --file ./my_module.lgx
2026-03-06 14:05:53 +00:00
` ``
#### 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
2026-03-25 10:37:15 +01:00
# Install a locally built .lgx package into a modules/ directory
./package-manager/bin/lgpm --modules-dir ./modules install --file ./my_module-1.0.0.lgx
` ``
After installation, the ` modules/` directory contains your extracted module:
` ``
modules/
└── my_module/
├── manifest.json
├── my_module_plugin.dylib # (or .so on Linux)
└── variant
2026-03-06 14:05:53 +00:00
` ``
### 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-25 10:37:15 +01:00
## Part 5: Running Your Module
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
Once your module is packaged and installed into a ` modules/` directory (see Parts 3 and 4), you can run it with ` logoscore`.
### 5.1 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
2026-03-06 14:05:53 +00:00
` ``bash
2026-03-25 10:37:15 +01:00
nix build 'github:logos-co/logos-logoscore-cli' --out-link ./logos
2026-03-06 14:05:53 +00:00
` ``
2026-03-25 10:37:15 +01:00
#### Daemon Mode
` logoscore` runs as a daemon that stays alive to host modules. Start it with ` -D`:
` ``bash
# Start the daemon with a modules directory
./logos/bin/logoscore -D -m ./modules
` ``
Once the daemon is running, use commands from another terminal:
` ``bash
# Load a module
./logos/bin/logoscore load-module my_module
# Call a method on a loaded module
./logos/bin/logoscore call my_module doSomething hello
# List loaded modules
./logos/bin/logoscore list-modules --loaded
# Show module details
./logos/bin/logoscore module-info my_module
# Watch events from a module
./logos/bin/logoscore watch my_module
# Show daemon and module health
./logos/bin/logoscore status
# Stop the daemon
./logos/bin/logoscore stop
` ``
#### Inline Mode (Legacy)
For one-shot execution (load, call, exit), use the legacy inline flags:
` ``bash
# Load a module and call a method
./logos/bin/logoscore \
-m ./modules \
--load-modules my_module \
-c "my_module.doSomething(hello)"
# Multiple sequential calls
./logos/bin/logoscore \
-m ./modules \
-l my_module \
-c "my_module.init(@config.json)" \
-c "my_module.start()"
# Exit immediately after calls complete
./logos/bin/logoscore \
-m ./modules -l my_module \
-c "my_module.doSomething(hello)" \
--quit-on-finish
` ``
> **Note:** Without ` -c` or ` --quit-on-finish`, logoscore enters the Qt event loop and stays running (daemon behavior). Always use ` -c` for one-shot execution.
**Inline mode flags:**
| Flag | Description |
|------|-------------|
| ` -m, --modules-dir <dir>` | Directory containing module libraries (repeatable) |
| ` -l, --load-modules <name1,name2>` | Comma-separated list of modules to load |
| ` -c "<module>.<method>(args)"` | Call a method after loading (repeatable, sequential) |
| ` --quit-on-finish` | Exit after all ` -c` calls complete |
| ` @file .json` | Pass a file's contents as a method argument |
**Daemon commands:**
| Command | Description |
|---------|-------------|
| ` status` | Show daemon and module health |
| ` load-module <name>` | Load a module into the daemon |
| ` unload-module <name>` | Unload a module |
| ` reload-module <name>` | Reload (unload + load) a module |
| ` list-modules [--loaded]` | List available or loaded modules |
| ` module-info <name>` | Show detailed module information |
| ` call <module> <method> [args]` | Call a method on a loaded module |
| ` watch <module> [--event]` | Watch events from a module |
| ` stats` | Show module resource usage |
| ` stop` | Stop the daemon |
---
## Part 6: Running in logos-basecamp
### 6.1 Building logos-basecamp
logos-basecamp produces two binary variants:
- **` logos-basecamp`** -- development build (shell wrapper that sets Qt environment variables, depends on ` /nix/store`)
- **` LogosBasecamp`** -- portable binary (self-contained, used in distributed builds and ` .app` bundles)
` ``bash
# Build the development version
nix build 'github:logos-co/logos-basecamp#app' --out-link ./logos-basecamp
# Run the dev binary
./logos-basecamp/bin/logos-basecamp
# Build the portable/distributed version
nix build 'github:logos-co/logos-basecamp#portable' --out-link ./logos-basecamp-portable
# Or build platform-specific distributions:
nix build 'github:logos-co/logos-basecamp#bin-bundle-dir' # Flat directory bundle
nix build 'github:logos-co/logos-basecamp#bin-appimage' # Linux AppImage
nix build 'github:logos-co/logos-basecamp#bin-macos-app' # macOS .app bundle
` ``
> **Note:** When installing modules into logos-basecamp, the LGX variant type must match the build type. Dev builds of basecamp expect **dev** LGX variants (e.g., ` darwin-arm64-dev`), while portable builds expect **portable** variants (e.g., ` darwin-arm64`). Use the ` dual` bundler (see [3.2](#32-bundling-with-nix-bundle-lgx)) to produce packages that work with both.
### 6.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])`
---
2026-03-25 10:37:15 +01:00
## Part 7: Inter-Module Communication
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
### 7.1 The LogosAPI
2026-03-06 14:05:53 +00:00
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");
2026-03-25 10:37:15 +01:00
// Synchronous call (blocks until result is returned)
2026-03-06 14:05:53 +00:00
QVariant result = client->invokeRemoteMethod(
"other_module", // target module name
"someMethod", // method name
arg1, arg2 // arguments (up to 5 positional args)
);
2026-03-25 10:37:15 +01:00
// Async call (preferred -- non-blocking, result delivered via callback)
client->invokeRemoteMethodAsync(
"other_module",
"someMethod",
[](QVariant result) {
// Handle result (called on the main thread)
if (result.isValid()) {
qDebug() << "Got result:" << result;
}
},
arg1, arg2
);
2026-03-06 14:05:53 +00:00
}
` ``
2026-03-25 10:37:15 +01:00
> **Prefer async calls.** Synchronous ` invokeRemoteMethod` blocks the caller's thread until the remote module responds. Use ` invokeRemoteMethodAsync` to avoid blocking, especially in UI modules.
### 7.2 The C++ SDK Code Generator
2026-03-06 14:05:53 +00:00
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.
2026-03-25 10:37:15 +01:00
#### Getting logos-cpp-generator
The generator is bundled with ` logos-cpp-sdk`. It is automatically available:
- **In ` nix develop`** -- the module dev shell includes the SDK on PATH
- **Build it directly:**
` ``bash
nix build 'github:logos-co/logos-cpp-sdk#cpp-generator' --out-link ./cpp-gen
./cpp-gen/bin/logos-cpp-generator --help
` ``
2026-03-06 14:05:53 +00:00
#### 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
2026-03-25 10:37:15 +01:00
After generation, you get typed wrapper classes with both synchronous and asynchronous methods:
2026-03-06 14:05:53 +00:00
` ``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);
2026-03-25 10:37:15 +01:00
// Synchronous call (blocks until result)
2026-03-06 14:05:53 +00:00
QString result = logos->other_module.doSomething("hello");
2026-03-25 10:37:15 +01:00
// Async call (preferred -- non-blocking)
logos->other_module.doSomethingAsync("hello", [](QVariant result) {
qDebug() << "Got:" << result;
});
2026-03-06 14:05:53 +00:00
}
` ``
2026-03-25 10:37:15 +01:00
The generated ` LogosModules` struct provides a member for each module, with methods matching the module's ` Q_INVOKABLE` methods. For every method ` foo()`, an async variant ` fooAsync()` is also generated that takes a callback parameter.
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
> **Prefer async wrappers.** Use ` doSomethingAsync(...)` instead of ` doSomething(...)` to avoid blocking the caller's thread. Synchronous calls can cause hangs if the target module is slow to respond.
### 7.3 LogosResult
2026-03-06 14:05:53 +00:00
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();
2026-03-25 10:37:15 +01:00
bool flag = result.getBool();
2026-03-06 14:05:53 +00:00
QVariantMap map = result.getMap();
QVariantList list = result.getList();
2026-03-25 10:37:15 +01:00
// Access nested values by key (for map results)
2026-03-06 14:05:53 +00:00
QString name = result.getString("name");
int count = result.getInt("count", 0); // with default
2026-03-25 10:37:15 +01:00
// Generic typed access
auto custom = result.getValue<MyType>();
2026-03-06 14:05:53 +00:00
} 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};
}
` ``
2026-03-25 10:37:15 +01:00
### 7.4 Communication Modes
2026-03-06 14:05:53 +00:00
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);
` ``
---
2026-03-25 10:37:15 +01:00
## Part 8: Advanced Topics
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
### 8.1 Tutorials
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
For hands-on walkthroughs of module development patterns, see the dedicated tutorials:
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
- **[Wrapping a C Library](tutorial-wrapping-c-library.md)** — create ` calc_module` wrapping a vendored C library. Covers external library configuration in ` metadata.json`.
- **[Building a QML UI App](tutorial-qml-ui-app.md)** — create ` calc_ui`, a QML-only UI plugin that calls a core module via the ` logos.callModule()` bridge.
- **[Building a C++ UI Module](tutorial-cpp-ui-app.md)** — create ` calc_ui_cpp`, a native C++ Qt widget plugin using ` LogosAPI*` and the generated SDK.
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
### 8.2 Module Dependencies
2026-03-06 14:05:53 +00:00
2026-03-24 18:36:10 +01:00
Declare dependencies in your ` metadata.json`:
2026-03-06 14:05:53 +00:00
` ``json
{
"name": "my_module",
"dependencies": ["package_manager", "waku_module"]
}
` ``
2026-03-24 18:36:10 +01:00
Each entry in ` dependencies` must match the ` name` field in that module's own ` metadata.json`. When adding a dependency as a flake input, the **input attribute name** must also match the dependency name — e.g., ` waku_module.url = "github:logos-co/logos-waku-module"`. The URL can point to any repo, but the attribute name is how the builder resolves dependencies.
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` |
2026-03-24 13:53:18 -04:00
| [logos-liblogos](https://github.com/logos-co/logos-liblogos) | Core library | ` logos_host`, ` liblogos_core` |
| [logos-logoscore-cli](https://github.com/logos-co/logos-logoscore-cli) | Headless CLI runtime | ` logoscore` (CLI) |
2026-03-06 14:05:53 +00:00
| [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-25 10:37:15 +01:00
| [logos-standalone-app](https://github.com/logos-co/logos-standalone-app) | Minimal UI module runner | ` logos-standalone-app` (loads a single UI plugin for testing) |
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
2026-03-25 10:37:15 +01:00
lm <plugin-file> # Show metadata + methods
lm metadata <plugin-file> [--json] # View module metadata
lm methods <plugin-file> [--json] # List Q_INVOKABLE methods
2026-03-06 14:05:53 +00:00
` ``
### ` logoscore` -- Headless Runtime
` ``bash
2026-03-25 10:37:15 +01:00
# Daemon mode
logoscore -D -m <modules-dir> # Start daemon
logoscore load-module <name> # Load a module
logoscore call <module> <method> [args] # Call a method
logoscore list-modules [--loaded] # List modules
logoscore module-info <name> # Show module details
logoscore status # Daemon health
logoscore stop # Stop daemon
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
# Inline mode (legacy)
logoscore -m <dir> -l <name> -c "<module>.<method>(args)" [--quit-on-finish]
2026-03-06 14:05:53 +00:00
` ``
### ` lgpm` -- Package Manager
` ``bash
2026-03-25 10:37:15 +01:00
./package-manager/bin/lgpm search <query> # Search packages
./package-manager/bin/lgpm list [--category <cat>] [--installed] # List packages
./package-manager/bin/lgpm install <pkg> [pkgs...] # Install with dependency resolution
./package-manager/bin/lgpm install --file <path.lgx> # Install local file
./package-manager/bin/lgpm info <pkg> # Package details
./package-manager/bin/lgpm categories # List categories
2026-03-06 14:05:53 +00:00
` ``
### ` 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>]
` ``
2026-03-25 10:37:15 +01:00
### ` nix-bundle-lgx` -- LGX Bundler
` ``bash
2026-03-26 11:48:27 +01:00
# Preferred: built-in derivation (when using logos-module-builder with nix-bundle-lgx input)
nix build .#lgx # Dev variant
nix build .#lgx-portable # Portable variant
nix build .#lgx-dual # Both variants
# Alternative: nix bundle command
2026-03-25 10:37:15 +01:00
nix bundle --bundler github:logos-co/nix-bundle-lgx .#lib # Dev variant
nix bundle --bundler github:logos-co/nix-bundle-lgx#portable .#lib # Portable variant
nix bundle --bundler github:logos-co/nix-bundle-lgx#dual .#lib # Both variants
` ``
2026-03-06 14:05:53 +00:00
---
## 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
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)
2026-03-25 10:37:15 +01:00
- Try specifying a release: ` ./package-manager/bin/lgpm --release v1.0.0 install my_module`
- For local files: ` ./package-manager/bin/lgpm install --file ./my_module.lgx`
- Check the target directory is writable: ` ./package-manager/bin/lgpm --modules-dir ./modules install my_module`
### Checking if a module loaded successfully
Use ` logoscore` to verify your module loads and its methods are callable:
` ``bash
# Start daemon and load the module
./logos/bin/logoscore -D -m ./modules &
# Check if the module is listed as loaded
./logos/bin/logoscore list-modules --loaded
# Inspect the module
./logos/bin/logoscore module-info my_module
# Or use inline mode for a quick check
./logos/bin/logoscore -m ./modules -l my_module -c "my_module.greet(test)" --quit-on-finish
` ``
If the module doesn't appear, check:
1. The ` modules/` directory contains a subdirectory for your module with ` manifest.json` and the plugin binary
2. The variant in the manifest matches your platform (e.g., ` darwin-arm64-dev` for dev builds on Apple Silicon)
3. Use ` lm` to verify the plugin binary is a valid Qt plugin: ` ./lm/bin/lm ./modules/my_module/my_module_plugin.dylib`
### Capability module not found
logos-basecamp requires the ` capability` module to be installed. It is bundled as a preinstall ` .lgx` package and installed on first launch. If you see errors about it:
1. Check that the preinstall directory exists: ` ls ./logos-basecamp/preinstall/`
2. Check that the capability module was extracted to the modules directory
3. Verify the LGX variant type matches your basecamp build (dev variant for dev build, portable for portable build)
### LGX variant mismatch
If a module installs but fails to load, the variant type may not match:
- **Dev build** of logos-basecamp needs **dev** LGX variants (` darwin-arm64-dev`)
- **Portable build** needs **portable** variants (` darwin-arm64`)
2026-03-26 11:48:27 +01:00
- Use ` nix build .#lgx ` and ` nix build .#lgx -portable` to produce each variant separately, ` nix build .#lgx -dual` for a single package with both, or ` nix bundle --bundler github:logos-co/nix-bundle-lgx#dual .#lib ` via the standalone bundler
2026-03-06 14:05:53 +00:00
### Cross-platform builds
2026-03-26 11:48:27 +01:00
Build on each target platform separately to create ` .lgx` packages:
2026-03-06 14:05:53 +00:00
` ``bash
2026-03-26 11:48:27 +01:00
# On each platform, the built-in derivation produces the correct variant automatically:
nix build .#lgx-portable
# Or using nix bundle for dual variant:
2026-03-25 10:37:15 +01:00
nix bundle --bundler github:logos-co/nix-bundle-lgx#dual .#lib
2026-03-06 14:05:53 +00:00
2026-03-25 10:37:15 +01:00
# Then merge platform-specific .lgx files into one:
./lgx/bin/lgx merge my_module-linux.lgx my_module-macos.lgx -o my_module.lgx
2026-03-06 14:05:53 +00:00
` ``