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>
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
Using Nix (Recommended)
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)