Dario LipicarandClaude Opus 5 2ddbb36f23 fix(logosctl): don't let one bundled-module failure disarm signature_policy (#90)
bootstrapPackageModules loaded "package_manager" and "package_downloader"
in a loop that `return`ed on the first failure -- before every
set*Directory / setSignaturePolicy call that followed it. Three defects
came out of that one early return:

* It left the daemon half-configured on any platform, not just Windows.
  A package_downloader that failed to load for any reason on Linux or
  macOS took the whole configuration block with it, while
  package_manager stayed up.

* The consequence was not the one originally recorded in flake.nix
  ("installs would land wherever its unset defaults point"). Every
  directory in package-manager-lib fails closed when unset --
  installPlugin refuses with "User modules directory is not set". What
  does NOT fail closed is the signature policy: it defaults to WARN, so
  an operator's `signature_policy: require` was read, advertised in
  state.json and by `logosctl config get`, and enforced nowhere.
  Unsigned packages, and packages signed by untrusted keys, would
  install with a printed warning.

* Because "package_manager" was first in the list, its failure meant
  "package_downloader" was never attempted, even when it would have
  loaded fine.

The stderr warning was wrong in the same way: both failures claimed
"package commands will be unavailable", which is untrue for either
module on its own.

The sequencing now lives in src/daemon/package_bootstrap.cpp behind
injected hooks -- it was not reachable from a test through
logos_core_load_module and a live socket. Each module loads
independently, package_manager is configured whenever it loaded, and
each failure names only the capability it actually costs.

Delivery is now checked. The setters return void, so a dispatched call
and one that never arrived are indistinguishable in the return value;
the CallError overload of invokeRemoteMethod tells them apart. A
configured policy that cannot be delivered unloads package_manager
rather than leave it enforcing less than the session advertises. An
undelivered directory only warns, since those fail closed on their own.

This matters more since cbd4c09: modules-pkg now ships on Windows, so
both modules are loaded on a platform where the daemon had never run
them before.

flake.nix already records both corrections (cbd4c09 reached them
independently); its remaining forward-reference to a defect "tracked
separately" is retired to point at the fix.

tests/test_package_bootstrap.cpp covers all three defects and the
warning text: 7 of its 12 cases fail against the old control flow.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 23:39:25 -03:00

logos-logoscore-cli

The headless CLI runtime for the Logos modular application platform. It loads Logos modules (Qt plugins) and lets you call their methods from the command line — no GUI needed.

This repo is one of two frontends for logos-liblogos:

  • logos-logoscore-cli (this repo) — headless CLI runtime for scripting, testing, and headless deployments
  • logos-basecamp — the desktop GUI application shell

Two binaries

Documentation
logoscore The tool that exists today. Commands, flags, config format and ~/.logoscore are unchanged. Keep using it. docs/logoscore.md
logosctl logoscore + lgpd + lgpm merged into one, with package management built in. New surface, own ~/.logosctl session directory. Being validated; not yet the default. docs/logosctl.md

They share the runtime but no state, so a logosctl session cannot disturb a logoscore deployment. They are built from separate flake outputs and released as separate artifacts. logoscore will be removed only once logosctl has been properly validated in real use.

Everything below applies to both. For what each tool actually does — commands, configuration, authentication, transports — follow the links above.

How to Build

The two binaries have separate flake outputs. cli is logoscore, ctl is logosctl, and each ships only its own binary — so nix build with no target, and anything already pointing at .#cli, still gets logoscore exactly as before.

Output Binary
.#cli (default) logoscore dev build
.#cli-bundle-dir logoscore portable, self-contained directory
.#cli-appimage logoscore portable, single-file AppImage (Linux)
.#ctl logosctl dev build
.#ctl-bundle-dir logosctl portable, self-contained directory
.#ctl-appimage logosctl portable, single-file AppImage (Linux)

Both come in two flavors: a dev build for local iteration and a portable build for distribution. The dev build links against dev logos-liblogos and works with dev modules; the portable build is self-contained and works with portable modules — which is what the public catalog ships, so logosctl's package commands need the portable bundle.

Dev Build

A standard Nix derivation whose dependencies live in /nix/store. It is the fastest way to iterate during development but is not portable — it only runs on the machine that built it. It works with dev modules: those produced by a local module nix build, or installed by the package manager's dev build.

nix build                        # logoscore (dev) — same as '.#cli'
nix build '.#ctl'                # logosctl (dev)
./result/bin/logoscore --help

Portable Builds

Portable builds are fully self-contained — no /nix/store references at runtime. They work with portable modules: releases from logos-modules, or modules installed by the package manager's portable build.

Output Platform Format
cli-bundle-dir / ctl-bundle-dir Linux, macOS Self-contained flat directory with bin/, lib/, and modules/
cli-appimage / ctl-appimage Linux Single-file .AppImage executable
Self-contained directory bundle (all platforms)
nix build '.#cli-bundle-dir'
./result/bin/logoscore --help
Linux AppImage (Linux only)
nix build '.#ctl-appimage'
./result/logosctl.AppImage --help

Development Shell

nix develop

Note: In zsh, quote targets containing # to prevent glob expansion (e.g., '.#cli').

If you don't have flakes enabled globally:

nix build --extra-experimental-features 'nix-command flakes'

Running Tests

Each binary has its own suite, in its own derivation, so nix builds them concurrently. tests runs both.

Check Covers
.#checks.<system>.tests both — this is what CI runs
.#checks.<system>.tests-logosctl unit + CLI + integration for logosctl
.#checks.<system>.tests-logoscore CLI + integration for logoscore

The logoscore suite is a deliberate duplicate of the logosctl one, frozen against logoscore's surface. It exists so that changes to the shared runtime cannot regress the tool people are actually using, and it gets deleted along with the binary.

# Both suites
nix build '.#checks.aarch64-darwin.tests'

# One suite, and its binaries, for local iteration
nix build '.#tests'
./result/bin/cli_tests
./result/bin/cli_tests --gtest_filter=CLITest.*

# Or via nix checks
nix flake check

Dependency Resolution

When loading modules, both binaries automatically resolve and load transitive dependencies in the correct order. For example, if logos_irc depends on waku_module and chat, loading logos_irc alone is equivalent to loading waku_module,chat,logos_irc.

Supported Platforms

  • macOS (aarch64-darwin, x86_64-darwin)
  • Linux (aarch64-linux, x86_64-linux)
S
Description
No description provided
Readme
16 MiB
Languages
C++ 89.6%
Nix 6.5%
CMake 1.9%
Shell 1.8%
Groovy 0.2%