Skip to content

Third-party core plugins have no token bootstrap path — cannot call other modules via IPC #150

Description

@xAlisher

Summary

A third-party core plugin calling logosAPI->getClient("storage_module")->invokeRemoteMethod(...) silently times out (~40s) even when storage_module is running and healthy. No error is surfaced — LogosAPIClient just returns an invalid QVariant.

cc @dlipicar

Root cause

LogosAPIClient::invokeRemoteMethod auto-provisions module access by calling capability_module.requestModule(origin, target). But that call needs a pre-existing capability_module token in the process-wide TokenManager. Third-party core plugins never receive this bootstrap token at load time — main_ui gets it, arbitrary core plugins do not.

From logos_api_client.cpp:

if (token.isEmpty() && objectName != "capability_module") {
    QString capabilityToken = getToken("capability_module");  // empty for third-party plugins
    QVariant result = pmc->invokeRemoteMethod(
        capabilityToken,   // empty string
        "capability_module", "requestModule",
        QVariantList() << m_origin_module << objectName,
        timeout);
    token = result.toString();
}

callRemoteMethod in module_proxy.cpp rejects the empty capabilityToken at line 229:

if (authToken.isEmpty()) {
    return QVariant();  // silent fail — caller gets invalid QVariant after full timeout
}

Secondary finding: token validation check is inverted

module_proxy.cpp:235:

if (!tokenManager->getToken(authToken).isEmpty()) {
    // labelled "INVALID" in debug output
    return QVariant();
}

authToken is a UUID token value, but getToken() uses it as a module-name key. UUID strings are never module names, so getToken() always returns empty, and the "INVALID" branch is never taken. Effectively any non-empty string passes the token check. This will cause subtle breakage if fixed without also fixing the bootstrap gap.

Steps to reproduce

  1. Create a third-party core plugin (type: core, .so loaded by logos_host)
  2. In initLogos(LogosAPI* api): call api->getClient("storage_module")->invokeRemoteMethod("storage_module", "someMethod", {})
  3. Launch LogosBasecamp with both plugins installed
  4. Observe: 40s block, then invalid QVariant returned. No error logged by the framework.

Question

Is there an intended mechanism for core plugins to obtain cross-module IPC access?

Options we considered:

  • Manifest "dependencies" field — load-order only, no token provisioning
  • Manifest "capabilities" field — declarative metadata only
  • logos_core_get_token("capability_module") (C API) — reads the host's TokenManager, but async IPC plumbing still required
  • informModuleToken — not token-gated (Q_UNUSED(authToken)) so the loader could inject a bootstrap token when loading any core plugin

If core-to-core IPC is not a supported pattern today, that's useful to know too — we'll route through QML instead.

Environment

  • LogosBasecamp AppImage: 9b52529-160
  • SDK: logos-cpp-sdk-headers-0.1.0 (nix store)
  • Ubuntu 24.04

[Claude Code] — filed on behalf of a notes module developer

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions