> For the complete documentation index, see [llms.txt](https://docs.logos.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.logos.co/build-an-app/build-modules/build-and-run-a-logos-core-module.md).

# Build and run a Logos core module

#### Scaffold, build, package, and test a core module on Logos.

{% hint style="info" %}

* **Permissions**: No special permissions required.
* **Product**: Logos Basecamp
  {% endhint %}

Logos is a modular application framework built on Qt 6. Applications are composed of dynamically loaded modules (Qt plugins) that provide features and functionality.

Logos core modules are non-UI modules that provide backend functionality. Core modules run in isolated `logos_host` processes and communicate via Qt Remote Objects.

{% hint style="info" %}
For other module types, check out [Wrap a C Library as a Logos core module](/build-an-app/build-modules/wrap-a-c-library-as-a-logos-core-module.md), [Build a QML UI for your logos module](https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/build-a-qml-ui-for-your-logos-module.md) and [Build a Logos C++ UI module](/build-an-app/build-modules/build-a-logos-cpp-ui-module.md). These guides — along with the [LGX package format and bundling reference](https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/lgx-package-format-and-bundling-reference.md) and the [Logos CLI Reference](https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/logos-cli-reference.md) — are still being written; the linked pages are placeholders for now.
{% endhint %}

Before you start, make sure you have the following:

* Linux (x86\_64 or aarch64) or macOS (arm64 or x86\_64)
* At least 10 GB of disk space
* [Nix](https://nixos.org/download.html) with flakes enabled
* Git
* Basic familiarity with C++ (C++17), Qt 6 (`QObject`, `Q_INVOKABLE`, signals/slots), CMake, and Nix concepts

## What to expect

* You can scaffold, configure, and build a Logos core module using the templates provided by `logos-module-builder`.
* You can inspect the compiled module's metadata and methods using the `lm` CLI tool or the `logos-module-viewer` graphical tool.
* You can package, install, and call your module's methods through `logoscore` or load it into `logos-basecamp`.

## Step 1: Scaffold the module project

The `logos-module-builder` provides four scaffolding templates for different module types. To create a Logos core module, choose the `default` template that produces a minimal core module with a C++ backend and no UI.

1. Create a new directory using your module's name and initialise it from the module builder template. Replace `<module-name>` with your module's name, for example, `my_module`.

   ```bash
   mkdir <module-name> && cd <module-name>
   nix flake init -t github:logos-co/logos-module-builder/tutorial-v1
   ```
2. Review the project directory. The generated project structure looks like this:

   ```
   <module-name>/
   ├── flake.nix
   ├── metadata.json
   ├── CMakeLists.txt
   └── src/
       ├── minimal_interface.h
       ├── minimal_plugin.h
       └── minimal_plugin.cpp
   ```

   The template uses `minimal` as a placeholder in the source filenames, class names, and identifiers. You replace these placeholders with your module's name in Step 2.

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p>The <code>metadata.json</code> file is the single source of truth for your module. Read <a href="https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/lgx-package-format-and-bundling-reference.md">LGX package format and bundling reference</a> for more details.</p></div>

## Step 2: Adapt the template for your module

The template generates files with placeholder names like `minimal`/`Minimal` and `doSomething`. Replace these in every generated file to match your module's name and methods.

1. Edit `metadata.json` and set `name`, `version`, `description`, and `main` to match your module.
   * `name` must be a valid C identifier; it is used in filenames, method calls, and module loading.
   * `main` must match the plugin filename without the extension (for example, `my_module_plugin` resolves to `my_module_plugin.so` or `.dylib`).
   * Leave the other fields (`type`, `category`, `dependencies`, and the `nix` block with `packages`, `external_libraries`, `cmake.find_packages`) in place. The bundler relies on the `nix` block to build the LGX package.
2. Edit `CMakeLists.txt` and update the `project()` name and the `NAME` and `SOURCES` values inside the `logos_module()` call.
   * The `CMakeLists.txt` uses the `logos_module()` macro to handle Qt plugin setup.
   * `NAME` must match the `name` field in `metadata.json`. A mismatch causes the build to succeed but the install phase to fail.
3. Edit `flake.nix` and update the `description` field.
   * The generated `flake.nix` uses an unpinned `logos-module-builder` URL. For reproducible builds, pin it to `tutorial-v1`.
4. Rename the source files in `src/` to match your module name.

   ```bash
   mv src/minimal_interface.h    src/<module-name>_interface.h
   mv src/minimal_plugin.h       src/<module-name>_plugin.h
   mv src/minimal_plugin.cpp     src/<module-name>_plugin.cpp
   ```
5. Edit the interface header (`src/<module-name>_interface.h`) and replace the class name, include guard, and interface ID string.
   * Declare each method your module exposes as `Q_INVOKABLE virtual` and pure-virtual.
   * The interface ID (for example, `"org.logos.MyModuleInterface"`) must be unique across all modules.
6. Edit the plugin header (`src/<module-name>_plugin.h`) and replace the class name, include guard, and interface references.
   * `Q_PLUGIN_METADATA(IID ... FILE "metadata.json")` embeds the metadata into the binary.
   * `Q_INTERFACES` must list both your interface and `PluginInterface`.
   * `name()` must return the same string as the `name` field in `metadata.json`.
   * Declare `initLogos(LogosAPI* api)` as `Q_INVOKABLE` but not `override`.
7. Edit the plugin implementation (`src/<module-name>_plugin.cpp`) and replace the placeholder method bodies with your logic.
   * In `initLogos`, assign the `LogosAPI*` pointer to the global `logosAPI` variable, not to a class member.

{% hint style="success" %}
Run `grep -ri "minimal" .` after editing to catch any remaining placeholder references (`minimal`, `Minimal`, `MINIMAL_*`, `MinimalInterface_iid`) before building.
{% endhint %}

## Step 3: Build the module

1. Initialise a Git repository.

   ```bash
   git init && git add -A
   ```
2. Build the full module output (library and generated SDK headers).

   ```bash
   nix build
   ```

   * Use `nix build '.#lib'` to build only the plugin shared library.
   * Use `nix build '.#include'` to build only the generated SDK headers.
3. Verify the build output contains the plugin binary and generated headers:

   ```
   result/
   ├── lib/
   │   └── <module-name>_plugin.so   # (or .dylib on macOS)
   └── include/
       ├── <module-name>_api.h       # Generated type-safe wrapper header
       └── <module-name>_api.cpp     # Generated wrapper implementation
   ```

## Step 4: Inspect your module

You can inspect the compiled module binary to verify the embedded metadata and exposed methods using the `lm` CLI tool or the `logos-module-viewer` graphical tool.

### Inspect with the 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.

1. Build the `lm` tool from the `logos-module` repository.

   ```bash
   nix build 'github:logos-co/logos-module/tutorial-v1#lm' --out-link ./lm
   ```
2. View the module metadata and confirm the information is correct.

   ```bash
   ./lm/bin/lm metadata result/lib/<module-name>_plugin.so
   ```

   * Append `--json` for JSON output.

   The JSON output looks like this:

   ```json
   {
      "name": "my_module",
      "version": "1.0.0",
      "description": "My first Logos module",
      "author": "",
      "type": "core",
      "dependencies": []
   }
   ```
3. View the module methods.

   ```bash
   ./lm/bin/lm methods result/lib/<module-name>_plugin.so
   ```

   * Append `--json` for JSON output.

   The JSON output looks like this:

   ```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" }
         ]
      }
   ]
   ```

   The output also includes any Qt signals declared in the module (for example, `eventResponse`) with `isInvokable: false`.

### Inspect with the graphical tool

The `logos-module-viewer` is a graphical tool for inspecting loaded modules. It displays the module's metadata and methods in a graphical interface and lets you call methods interactively.

1. Build the viewer.

   ```bash
   nix build 'github:logos-co/logos-module-viewer/tutorial-v1#app' --out-link ./logos-viewer
   ```
2. Launch the viewer with the module binary.

   ```bash
   ./logos-viewer/bin/logos-module-viewer -m ./result/lib/<module-name>_plugin.so
   ```

## Step 5: Package the module

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. Check out the [LGX package format and bundling reference](https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/lgx-package-format-and-bundling-reference.md) for more details on the format and bundling options.

{% hint style="info" %}
The `manifest.json` is auto-generated from your module's `metadata.json` by the bundler. It maps each variant to its main entry point.
{% endhint %}

There are two ways to create `.lgx` packages:

* Use the built-in Nix derivation that comes with `logos-module-builder` (preferred).
* Use the `nix bundle` command directly.

### Use the Nix derivation

When your module uses `logos-module-builder`, LGX package outputs are automatically available as part of your flake (the builder includes `nix-bundle-lgx` internally).

1. Bundle the module into an LGX package that uses `/nix/store` references for local development.

   ```bash
   nix build .#lgx
   ```

   * Use `#lgx-portable` for a self-contained, all dependencies bundled package: `nix build .#lgx-portable`.
2. Check the `result/` directory and confirm the `logos-<module-name>-module-lib.lgx` file is present.

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><code>.#lgx</code> produces a single variant (for example, <code>linux-amd64</code>) and <code>.#lgx-portable</code> produces a single portable variant. Neither produces the <code>-dev</code> variant that <code>logos-basecamp</code> dev builds expect. If you need the dev variant for use with <code>logos-basecamp</code>, use the <code>#dual</code> bundler described in the next section.</p></div>

### Use the `nix bundle` command

The `nix bundle` command 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) which is only available via the `nix bundle` command.

1. Bundle the module into an LGX package using the `nix bundle` command.

   ```bash
   nix bundle --bundler github:logos-co/nix-bundle-lgx/tutorial-v1 .#lib
   ```

   * Use `#portable` for a self-contained package with no `/nix/store` references: `nix bundle --bundler github:logos-co/nix-bundle-lgx/tutorial-v1#portable .#lib`.
   * Use `#dual` to produce both `-dev` and portable variants in a single `.lgx` file: `nix bundle --bundler github:logos-co/nix-bundle-lgx/tutorial-v1#dual .#lib`. Use this mode when you need to install the module into a dev build of `logos-basecamp`.
2. Check the current directory for the bundle output. `nix bundle` creates a symlink directory in the current directory named `./logos-<module-name>-module-lib-lgx-<version>/`, and the `.lgx` file is inside it at `./logos-<module-name>-module-lib-lgx-<version>/logos-<module-name>-module-lib.lgx`.

{% hint style="success" %}
Check out [LGX package format and bundling reference](https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/lgx-package-format-and-bundling-reference.md) for more details on the format and bundling options.
{% endhint %}

## Step 6: Install the module

Before you can run your module with `logoscore` or `logos-basecamp`, install the LGX package into a `modules/` directory that the runtime can load from.

There are two ways to install `.lgx` packages:

* Install a locally built `.lgx` package
* Download and install a `.lgx` file from a registry

### Install a locally built `.lgx` package

1. Build the Logos Package Manager (`lgpm`) CLI.

   ```bash
   nix build 'github:logos-co/logos-package-manager/tutorial-v1#cli' --out-link ./package-manager
   ```
2. Create the `modules/` directory and install the `.lgx` package.

   ```bash
   ./package-manager/bin/lgpm --modules-dir ./modules install --file result/logos-<module-name>-module-lib.lgx
   ```

   * Use `--dir` instead of `--file` to install all LGX packages in a directory at once: `./package-manager/bin/lgpm --modules-dir ./modules install --dir ./packages/`
   * If you bundled with `nix bundle`, the path is `./logos-<module-name>-module-lib-lgx-<version>/logos-<module-name>-module-lib.lgx` instead of `result/...`.
3. Verify the installed module directory. The directory contains `manifest.json`, the plugin binary (`.so` or `.dylib`), and a `variant` file.

### Download and install a `.lgx` file from a registry

The Logos module catalogue is hosted on GitHub Releases in the [logos-modules](https://github.com/logos-co/logos-modules) repository. Use `lgpd` to search and download packages, then `lgpm` to install them locally.

{% hint style="warning" %}
Registry packages currently ship portable variants only (for example, `linux-amd64`, `darwin-arm64`). They cannot be installed into a dev build of `logos-basecamp`, which expects `-dev` variants. To use a registry module with a dev build, you must build the module from source and bundle it with `#dual`. They install cleanly into `logoscore` and into portable builds of `logos-basecamp`.
{% endhint %}

1. Build the Logos Package Manager (`lgpm`) CLI.

   ```bash
   nix build 'github:logos-co/logos-package-manager/tutorial-v1#cli' --out-link ./package-manager
   ```
2. Build the Logos Package Downloader (`lgpd`) CLI.

   ```bash
   nix build 'github:logos-co/logos-package-downloader/tutorial-v1#cli' --out-link ./downloader
   ```
3. Search the catalogue for the module you want to install. Replace `<registry-name>` with the registry name of the module you want to find (for example, `logos-chat-module`).

   ```bash
   ./downloader/bin/lgpd search <registry-name>
   ```

   <div data-gb-custom-block data-tag="hint" data-style="success" class="hint hint-success"><p>Use <code>./downloader/bin/lgpd list</code> to browse all available packages.</p></div>
4. Download the LGX package to a local directory.

   ```bash
   ./downloader/bin/lgpd download <registry-name> -o ./packages/
   ```

   * Use `--release <tag>` to download from a specific release version. For example: `./downloader/bin/lgpd --release v2.0.0 download <registry-name> -o ./packages/`
   * The downloaded file is named after the module's internal `name` field, not the registry name. For example, `lgpd download logos-chat-module` writes `./packages/chat_module.lgx`.
5. Create the `modules/` directory and install the downloaded package. Replace `<downloaded-name>` with the actual filename written by `lgpd` (for example, `chat_module.lgx`).

   ```bash
   ./package-manager/bin/lgpm --modules-dir ./modules install --file ./packages/<downloaded-name>.lgx
   ```

   * Use `--ui-plugins-dir` instead of `--modules-dir` when installing UI modules.

## Step 7: Run the module

There are two Logos runtimes, `logoscore` and `logos-basecamp`, that can load and run your module. However, to interact with your module directly through the `logos-basecamp` interface, you need to [provide a UI module](https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/build-a-qml-ui-for-your-logos-module.md).

### Run with `logoscore`

The `logoscore` CLI (from `logos-liblogos`) is a headless runtime that can load modules and invoke their methods from the command line. It runs as a daemon that stays alive to host modules.

1. Build `logoscore` from the `logos-logoscore-cli` repository.

   ```bash
   nix build 'github:logos-co/logos-logoscore-cli/tutorial-v1' --out-link ./logos
   ```
2. Start the `logoscore` daemon with the `modules/` directory.

   ```bash
   ./logos/bin/logoscore -D -m ./modules
   ```
3. From another terminal, load the module and call a method. Replace `<method>` and `<args>` with the method name and arguments you want to call.

   ```bash
   ./logos/bin/logoscore load-module <module-name>
   ./logos/bin/logoscore call <module-name> <method> <args>
   ```
4. Stop the daemon when finished.

   ```bash
   ./logos/bin/logoscore stop
   ```

{% hint style="success" %}
Check out [Logos CLI Reference](https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/logos-cli-reference.md) for more details on available commands and options.
{% endhint %}

### Run with `logos-basecamp`

Logos Basecamp is a desktop shell that provides a graphical interface for managing and running modules. Core modules run as background services in `logos-basecamp`. Other UI modules can call them through `LogosAPI` or the `logos.callModule()` bridge once they are installed.

{% hint style="warning" %}
The LGX variant type must match the basecamp build type. Dev builds of basecamp expect dev LGX variants (for example, `darwin-arm64-dev`), and portable builds expect portable variants (for example, `darwin-arm64`). Check out the [LGX package format and bundling reference](https://github.com/logos-co/logos-docs/blob/main/docs/core/build-modules/lgx-package-format-and-bundling-reference.md) for more details.
{% endhint %}

1. Build the development version of `logos-basecamp`.

   ```bash
   nix build 'github:logos-co/logos-basecamp/tutorial-v1#app' --out-link ./logos-basecamp
   ```
2. Launch `logos-basecamp` once to create its data directory and preinstall bundled modules, then close it.

   ```bash
    ./logos-basecamp/bin/logos-basecamp
   ```

   * Look for the directory containing `modules/` and `plugins/` subdirectories at `~/Library/Application Support/Logos/LogosBasecamp/` (macOS) or `~/.config/Logos/LogosBasecamp/` (Linux).
3. Set the `BASECAMP_DIR` variable to your platform's path.

   ```bash
   # macOS
   BASECAMP_DIR="$HOME/Library/Application Support/Logos/LogosBasecamp"

   # Linux
   BASECAMP_DIR="$HOME/.config/Logos/LogosBasecamp"
   ```
4. Install the module's dev LGX package into basecamp's modules directory. The package must contain a `-dev` variant for your platform; build it with `nix bundle --bundler github:logos-co/nix-bundle-lgx/tutorial-v1#dual .#lib` as described in Step 5.

   ```bash
   ./package-manager/bin/lgpm --modules-dir "$BASECAMP_DIR/modules" install --file ./logos-<module-name>-module-lib-lgx-<version>/logos-<module-name>-module-lib.lgx
   ```

## Troubleshooting

### Known constraints

A single `logoscore` instance supports only one instance of a module, so all dependent apps share that state. To run multiple independent instances, start separate `logos-basecamp` instances with their own user directories, and each `logos-basecamp` instance runs its own `logoscore` and module instances in isolation.

### Nix reports an "experimental features" error

If you see errors about experimental features, either pass the flag:

```bash
nix --extra-experimental-features "nix-command flakes" build
```

Or add the following to `~/.config/nix/nix.conf`:

```conf
experimental-features = nix-command flakes
```

### Module not discovered by `logos-basecamp`

Confirm the module is in a subdirectory of the `modules/` directory (for example, `modules/my_module/`) and that the subdirectory contains the module binary and `manifest.json`. The `name` field in `manifest.json` must match the binary name (for example, `my_module` for `my_module_plugin.so`).

### Module not discovered by `logoscore`

Confirm the module is in a subdirectory of the `modules/` directory (for example, `modules/my_module/`) and that the subdirectory contains a `manifest.json` with a `main` object matching your OS and architecture.

### `lgpm` fails to install a module

Verify the target directory exists and is writable. If installing from a local `.lgx` file, confirm the file path is correct (the bundler writes `logos-<module-name>-module-lib.lgx`, not `<module-name>.lgx`). If installing from the registry, check your internet connection — `lgpd` fetches packages from GitHub Releases. To pin a specific release version, pass `--release <tag>` to `lgpd` (not `lgpm`) when downloading.

### LGX variant mismatch

If `lgpm install` fails with `Package does not contain variant for platform: <platform>-dev`, the LGX file does not include a `-dev` variant for your platform.

* `nix build .#lgx` produces a single variant (for example, `linux-amd64`) suitable for `logoscore` but not for a dev build of `logos-basecamp`.
* `nix build .#lgx-portable` produces a single portable variant suitable for portable builds of `logos-basecamp`.
* `nix bundle --bundler github:logos-co/nix-bundle-lgx/tutorial-v1#dual .#lib` produces both `-dev` and portable variants in a single `.lgx` file, which works with dev and portable builds of `logos-basecamp`.

Registry packages downloaded with `lgpd` currently ship portable variants only.

{% hint style="info" %}
`lgpm` error messages report the platform as `linux-x86_64` while LGX manifests label it `linux-amd64`. These refer to the same architecture.
{% endhint %}

### `nix build .#lib` does nothing or fails silently

Some shells (notably zsh) treats `#` as a comment character outside quotes. Quote the flake reference so the `#` reaches nix intact.

```bash
nix build '.#lib'
```

### First build is slow

The first `nix build` downloads Qt 6, the Logos C++ SDK, the code generator, and the rest of the build dependencies. This is a one-time cost, subsequent builds reuse the cache and typically complete in under 30 seconds.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.logos.co/build-an-app/build-modules/build-and-run-a-logos-core-module.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
