Logoscore Weekly Update — 2026-08-31
Highlights
- A module can ask for a signature; only a human can produce one. The keystore’s unlocked-signer cache is gone —
unlock,lockand everysign_*were deleted from the contract rather than gated, the key is now derived from the vault password insideapprove()and zeroized before the call returns, and admission is tiered by caller identity. The wallet backend became a pure requester, the wallet UI stopped handling the vault password, andsigner_uiwas proven end-to-end against a live secp256k1 signature that exists only because a password was typed into it logos-evm-keystore-module#6, logos-evm-signer-ui#2, logos-evm-wallet-backend-module#12, logos-evm-wallet-ui#25 - App-to-app intents shipped. Three deliberately frozen QML symbols (
logos.request,logos.intentRequested,logos.respond) over a host-side broker that checks the caller’s ownusesdeclaration and mints a dispatch id the requester never sees — so no app can forge a response or hold a handle on whoever answered.provideslanded in the package format and intent names carried through the downloader, the lgx bundler and the module templates logos-view-module-runtime#28, logos-basecamp#363, logos-package#35, logos-package-downloader#34, nix-bundle-lgx#13 - A grant one way was a grant both ways.
TokenManagerwas one flat map with no direction tag, written from both sides of every relationship — so B could call A purely because A had called B. INBOUND and OUTBOUND are now genuinely separated without moving a single byte of the struct (its layout is a cross-package ABI), and a private token store is created empty instead of being seeded with the host’s own anchor logos-protocol#73, #71, logos-logoscore-cli#104, logos-plugin-qt#26 - Module state stopped being polled. liblogos turns load, unload and crash into sequenced facts and feeds them to a new
modules_statemodule — retiring Basecamp’s 2sQTimerthat inferred module state from package-install events, and the install/uninstall ack handshake between Basecamp and PMUI logos-liblogos#189, logos-modules-state-module#1, logos-basecamp#362, logos-package-manager-ui#74 - A declared dependency range is now enforced, end to end. A module declaring
^2.0.0loaded happily against an installed 1.0.0 —module_metadata.cppdropped the constraint before the registry ever saw it. The range now rides the wire, the package manager evaluates it without masking a deeper mismatch, liblogos refuses at load (fails closed on an unparseable range), and Basecamp finally shows the difference logos-liblogos#196, logos-package-manager#38, logos-package-manager-module#64, logos-basecamp#361
Initiatives
Human-approved signing — the EVM wallet stops holding keys
The week’s largest user-visible security change: signing moved from something a caller can ask for to something a person authorises, once, for a payload they were shown.
- The hole: once an account was unlocked, any module could sign —
sign_*checked only is-unlocked, never who was calling, andunlockpassedttl: Nonewhile eviction only fired forSome, making every unlock a permanent, unattributable signing oracle.render == signwas vacuously true: the keystore signed bytes it had never described logos-evm-keystore-module#6 - What replaced it: three admission tiers by caller identity — the configured approver only, any named module plus a receipt, and ungated account management. Tiers A and B return an identical refusal string so a caller cannot probe which one it failed logos-evm-keystore-module#6
- The approver:
signer_uimade to work and proven end to end; five defects found by running it rather than reading it logos-evm-signer-ui#2 - The requester: both vault-password passthroughs deleted; signing became a two-phase request that parks the job rather than a dispatch thread; history is written when a transaction is BROADCAST, not when it is requested logos-evm-wallet-backend-module#12, logos-evm-wallet-ui#25
- Parked, honestly: RAILGUN dropped from the backend and its Private tab removed from the UI until it is migrated off
keystore.sign_digestlogos-evm-wallet-backend-module#13, logos-evm-wallet-ui#27 - Also: fees taken from
fee_moduleinstead of derived fromgasPrice; leaf modules pinned to the backend’s own locked inputs logos-evm-wallet-backend-module#14, logos-evm-wallet-ui#26
App-to-app intents
- The frozen surface:
request()returns void deliberately — the requester never receives a request id, so it cannot forge arespond()for its own request nor hold a handle to whoever answered. That single property is what lets the router underneath be replaced without any app noticing. The bridge does no policy;LogosIntent.hcarries the shared vocabulary so a host’s broker and the bridge can never disagree about a legal name or a legal error logos-view-module-runtime#28 - The broker, on the host/shell split: it checks the caller’s
usesdeclaration, resolves a provider, mints a separate dispatch id, has the presenter load and present the provider, and routes the answer back to that requester alone. The shell is a provider like any other for dispatch — and emphatically not an app, so it must never be loaded logos-basecamp#363 - Through the packaging chain: a
providesfield in the package format, intent names in the downloader and the lgx bundler, intents in the module templates, and docs logos-package#35, logos-package-downloader#34, nix-bundle-lgx#13, logos-module-builder#219, logos-modules-release-tool#7, logos-tutorial#85 - First consumer: PMUI asks for Settings → Repositories via an intent rather than reaching for the shell logos-package-manager-ui#73
Caller identity, put to work
Protocol 0.6’s caller accessor landed the week before; this week it started retiring the tokens it makes unnecessary.
capability_moduleidentifies therequestModulecaller from the RPC token logos-capability-module#26, #27modules_stategates ingest onlogos::currentCaller().isHost()— authority became structural, retiring an ingest-token nonce and theModuleDescriptor.envplumbing it would have required logos-modules-state-module#1logos::CallCallerexposed fromlogos_test.h; a Rust module announces its OWN name, notcorelogos-test-framework#7, logos-rust-sdk#51
Token direction and consumer admission
- Direction: inbound and outbound separated without changing
TokenManager’s layout — splitting it into three members would have movedm_mutexunderQMutex::fastTryLock()’s compare-exchange offset, and host and modules ship as separate.lgxthat mix versions at runtime by design logos-protocol#73 - Empty by default: a private store no longer copies the host’s bootstrap tokens, which had let a sandboxed view present basecamp’s anchor and be answered as
HostAnchor. Half of it was live, not latent: reading a caller needed generated glue, writing one didn’t logos-protocol#71 - One home for admitting a non-module:
logos::admitConsumerreplaces the same three steps hand-rolled in two applications — the pure-QML identity bug was one of them getting the order wrong. Adopted by Basecamp, the standalone app, and the ui-host adopting its parent’s credential logos-plugin-qt#27, logos-basecamp#359, logos-standalone-app#42, logos-view-module-runtime#27 - The plumbing and its docs:
informModuleTokenrouted through the INBOUND door,logos_module_accept_inbound_tokendefined for cdylibs, the CLI daemon filing its client’s token as INBOUND; two-sided load-time token injection and outbound core/capability tokens documented logos-plugin-qt#26, logos-cpp-sdk#151, logos-logoscore-cli#104, logos-liblogos#187, logos-module-loader-qt#10
modules_state — lifecycle as sequenced facts
- The observer and the feed ship together because the observer alone is inert. Two load-bearing rules: never dispatch under
loadMutex()(a sink doing an RPC from inside the load path is the shape of the ui-host startup deadlock and a ~417s Basecamp stall already paid for), and one sequence counter logos-liblogos#189 - Bundled and auto-loaded in liblogos, Basecamp and logosctl;
readykept across a snapshot logos-liblogos#193, #191, logos-basecamp#362, logos-logoscore-cli#110 - Consumers stopped guessing: logosctl draws the line at LOADED rather than merely known, for both
watchandcall; the Basecamp↔PMUI ack handshake for install/uninstall/upgrade is gone logos-logoscore-cli#109, logos-package-manager-ui#74
Dependency ranges, signatures and package identity
- Ranges: evaluated by the package manager without masking a deeper mismatch, carried on the wire, enforced at load, and surfaced in Basecamp’s sidebar and dialogs — where the gate’s predicate had literally been
status == "not_installed", so absence was the only condition it could express. Hyphen ranges documented as supported logos-package-manager#38, logos-package-manager-module#64, logos-liblogos#196, logos-basecamp#361, logos-package#38 - A pin was satisfiable by a signature that does not verify: the resolver compared the pinned DID against a claimed
signer_didpopulated before verification, so a forgedmanifest.signaming the pinned DID bound to the pin. Fixed at the resolver and taken downstream logos-package-downloader#33, logos-package-downloader-module#31, #29 - Signature surface: an unknown signing key now says so instead of failing mutely; a consumer can carry a package’s signature and check it against a DID of its own; an installed package can be checked, not just an archive logos-package-manager#37, logos-package#36, #37
- Install robustness: read-only bits cleared on the destination and a partial install rolled back; the variant table and
mainresolution taken from logos-package rather than duplicated; a module is the directory it is installed in; multi-download concurrency enabled logos-package-manager#40, #41, logos-module#24, logos-package-downloader#32, logos-package-downloader-module#28
Error channel and arity
Last week’s cross-SDK sweep continued into the sites it had missed.
- A void method’s REFUSAL is not a successful void call — both generated sites, then relocked into module-builder logos-plugin-qt#28, #29, logos-module-builder#218
- A reply the consumer cannot read must not be reported as a provider refusal, in both the Qt and C++ consumers logos-qt-sdk#44, logos-cpp-sdk#150
- The argument count is bounded above in both SDKs, and the Rust identity arm gated logos-cpp-sdk#150, logos-rust-sdk#50, logos-module-builder#216
- The signer half of
malformedConstraintcovered logos-module#25
Conformance — the consumer axis
- The ext table gained the axis its own comment said it lacked:
44 × 2 × 1→44 × 2 × 3, via a Qt proxy fixture. It found a real defect — a record-bearing contract could not be consumed through a proxy at all, because generated record codecs were file-scope statics named after the record alone and the umbrella amalgamates every<name>_api.cppinto one TU logos-test-modules#50, logos-qt-sdk relock via logos-module-builder#215 - The same axis in Python, plus the two races two relocks exposed logos-logoscore-py#22
- Table hygiene: the null-vs-failure classes expressed as cells, one shape for
echoOptionaland three retirements, the arity work closed on measurement, the isolate rule moved to the table where it belongs, and module-not-loaded answering one token again logos-test-modules#49, #51, #52, #54, #55, #56
Protocol 0.8 / 0.9, and the relock train
onEventWhenAvailabletakes the wildcard, likeonEvent, and the deferred subscription carried into both Qt carriers logos-protocol#74, logos-plugin-qt#30, logos-qt-sdk#46- liblogos onto protocol 0.8 and then
303ab08across all three carriers; logosctl to 0.9 logos-liblogos#186, #190, logos-logoscore-cli#105 - Relocks across the module stack, plus one logos-package-manager resolved for the whole staged tree logos-module-builder#217, #221, logos-module-loader-qt#11, logos-qt-sdk#45, logos-capability-module#28, logos-test-modules#53, logos-package-manager-module#63, #65, #66, logos-package-manager#39, logos-package-downloader-module#30, logos-liblogos#188, #194, #195, logos-logoscore-cli#112, #114, nix-bundle-logos-module-install#6
Modules and releases
- libp2p: the inbound accept queue restored — the cbind migration had rewritten
onIncomingStreamto only emit an event, leaving the queue with no writer, and nothing caught it because CI skips every integration test whenlib/libp2p.sois absent. Peer id now reported,pingPeeradded, queue depth and drops instrumented; the context pointer guarded against a concurrent destroy, and the integration tests build again logos-libp2p-module#103, #107, #106 - delivery: migrated to the nim-ffi 0.3 C ABI, released as 0.2.1, demo cut alongside it, and bumped in the release set logos-delivery-module#90, #92, #93, logos-delivery-demo#24, #25, logos-modules-release#51
- blockchain module 0.2.3 released logos-modules-release#49
- storage:
version()renamed tolibstorageVersion()(breaking) logos-storage-module#81 - execution zone: the persistent path exposed via
LogosModuleContextlogos-execution-zone-module#53
UI — design system rollout
- New designs landed across the blockchain and chat surfaces logos-chat-ui#59, logos-blockchain-ui#61, lez-explorer-ui#21, logos-execution-zone-wallet-ui#45
- The execution-zone wallet moved onto LogosDesignSystem components, reworked onboarding into two paths (create a wallet, or use an existing one), and turned tests on in CI logos-execution-zone-wallet-ui#46, #43, #41, #42
- App-manager icons fixed in Basecamp logos-basecamp#376
Basecamp test layer (MCP-driven UI tests)
- Preparation work for MCP-driven UI tests, the first real assertion (welcome → “Install now” navigates to Applications), and a pre-seeded
test_qml_onlyapp so integration tests have something to boot logos-basecamp#338, #342, #343
Tooling, diagnostics and docs
- logosctl: catalog package versions shown;
package searchgives one version per row with the rest named inpackage show; releases tagged fromVERSIONlogos-logoscore-cli#106, #111, #107 - standalone app: logs to stderr by default — its own diagnostics were invisible — and loads the backend library the plugin actually declares logos-standalone-app#43, #44
- doctests unpinned from logoscore-cli, with the archived accounts module retired logos-liblogos#192
- tutorials updated so UI modules use QML hot reloading correctly logos-tutorial#86, #78
Appendix: all merged PRs, by repo
lez-explorer-ui, logos-basecamp, logos-blockchain-ui, logos-capability-module, logos-chat-ui, logos-cpp-sdk, logos-delivery-demo, logos-delivery-module, logos-evm-keystore-module, logos-evm-signer-ui, logos-evm-wallet-backend-module, logos-evm-wallet-ui, logos-execution-zone-module, logos-execution-zone-wallet-ui, logos-liblogos, logos-libp2p-module, logos-logoscore-cli, logos-logoscore-py, logos-module, logos-module-builder, logos-module-loader-qt, logos-modules-release, logos-modules-release-tool, logos-modules-state-module, logos-package, logos-package-downloader, logos-package-downloader-module, logos-package-manager, logos-package-manager-module, logos-package-manager-ui, logos-plugin-qt, logos-protocol, logos-qt-sdk, logos-rust-sdk, logos-standalone-app, logos-storage-module, logos-test-framework, logos-test-modules, logos-tutorial, logos-view-module-runtime, nix-bundle-lgx, nix-bundle-logos-module-install
lez-explorer-ui
logos-basecamp
- Fix/app manager icons (#376)
- feat(intents): app-to-app intents, on the host/shell split (#363)
- feat: bundle modules_state (#362)
- feat(deps): refuse a UI plugin whose dependency version does not satisfy its range (#361)
- refactor(plugins): admit consumers through the shared verb (#359)
- Test/pre-seed test_qml_only app for integration-test boot (#343)
- Test/MCP UI welcome Install now navigates to Applications (#342)
- Test/MCP preparation UI tests (#338)
logos-blockchain-ui
logos-capability-module
- feat: bump flake.lock (#28)
- chore(deps): relock caller-aware module builder (#27)
- Identify requestModule caller from the RPC token (#26)
logos-chat-ui
logos-cpp-sdk
- feat(cdylib): define logos_module_accept_inbound_token (#151)
- fix: bound the argument count above; and an lp reply it cannot read (#150)
logos-delivery-demo
logos-delivery-module
- chore: bump logos delivery to latest master (#93)
- fix: set metadata version to 0.2.1 (#92)
- chore: bump logos-delivery and migrate to the nim-ffi 0.3 C ABI (#90)
logos-evm-keystore-module
logos-evm-signer-ui
logos-evm-wallet-backend-module
- feat: take fees from fee_module instead of deriving them from gasPrice (#14)
- drop railgun_module until it is migrated off keystore.sign_digest (#13)
- feat(wallet-backend): become a pure requester of human-approved signatures (#12)
logos-evm-wallet-ui
- drop the Private (RAILGUN) tab until railgun is migrated (#27)
- flake: pin the leaf modules to the backend’s own locked inputs (#26)
- feat(wallet-ui): stop handling the vault password (#25)
logos-execution-zone-module
logos-execution-zone-wallet-ui
- chore: use LogosDesignSystem components (#46)
- feat: use new designs (#45)
- chore: use LogosDesignSystem components (#43)
- chore: enabled tests on ci (#42)
- fix: imrpove the onaboaridng flow, 2 options create wallet using wall… (#41)
logos-liblogos
- feat: enforce a dependency’s declared version range at load (#196)
- chore(deps): bump logos-package-manager fb8fb6a -> d88abaa (#195)
- feat: bump flake.lock (#194)
- feat: bundle and auto-load modules_state (#193)
- fix(doctests): unpin logoscore-cli, and retire the archived accounts … (#192)
- fix(core): keep
readyacross a snapshot (#191) - chore(deps): protocol 303ab08 across all three carriers (#190)
- feat(core): turn module lifecycle into sequenced facts, and feed them to modules_state (#189)
- chore(deps): relock module loader stack (#188)
- Document two-sided load-time token injection (#187)
- chore(deps): move onto logos-protocol 0.8 and logos-plugin-qt master (#186)
logos-libp2p-module
- fix(ctx): guard the libp2p context pointer against a concurrent destroy (#107)
- fix(tests): find liblibp2p.so, so the integration tests build again (#106)
- feat(bridge): restore the inbound accept queue, report the peer id, add pingPeer (#103)
logos-logoscore-cli
- chore(flake): resolve one logos-package-manager for the whole staged tree (#114)
- chore(deps): bump logos-package-manager-module and logos-liblogos (install stages and swaps) (#112)
- fix(search): one version per row, and name the rest in
package show(#111) - feat: bundle modules_state, and stop claiming the doc-tests pin an exact list (#110)
- fix: draw the line at LOADED, not merely known — for both watch and call (#109)
- fix(release): tag releases from VERSION (#107)
- feat(logosctl): show catalog package versions (#106)
- chore: bump protocol to 0.9 (#105)
- fix(daemon): file the CLI client’s token as INBOUND, not outbound (#104)
logos-logoscore-py
logos-module
- test: cover the signer half of malformedConstraint (#25)
- feat: the module is the directory it is installed in (#24)
logos-module-builder
- feat: bump flake.lock (#221)
- feat: add support for intents in templates and bump flake.lock (#219)
- chore(deps): bump logos-plugin-qt for the second void-refusal site (#218)
- chore(deps): relock protocol 0.8 module stack (#217)
- chore(deps): bump the three SDKs for the arity bound and the result decode (#216)
- chore(deps): bump logos-qt-sdk for the record-codec qualification (#215)
logos-module-loader-qt
logos-modules-release
- Bump delivery module to 0.2.1 and add delivery demo (#51)
- chore: Bump blockchain module to 0.2.3 (#49)
logos-modules-release-tool
logos-modules-state-module
logos-package
- docs: hyphen ranges are supported (#38)
- feat: check an installed package, not just an archive (#37)
- feat(sig): let a consumer carry a package’s signature and check it against a DID of their own (#36)
- feat: suport provides field for intents (#35)
logos-package-downloader
- feat: support intent names and bump flake.lock (#34)
- fix(resolver): a signer pin must not bind to a signature that did not verify (#33)
- feat concurrency multi (#32)
logos-package-downloader-module
- chore(deps): take the fix for a signer binding that never checked the signature (#31)
- feat: bump flake.lock (#30)
- chore(deps): take the resolver fix for the empty-signer pin (#29)
- chore: enable concurrency multi (#28)
logos-package-manager
- refactor: take the variant table and
mainresolution from logos-package (#41) - fix(install): clear read-only bits on the destination, and roll back a partial (#40)
- feat: bump flake.lock (#39)
- feat(deps): evaluate a dependency’s version range, and do not mask a deeper mismatch (#38)
- fix(signature): say something when an unknown key signed the package (#37)
logos-package-manager-module
- chore(deps): bump logos-package-manager to d88abaa (install stages and swaps) (#66)
- feat: bump flake.lock (#65)
- feat(abi): put dependency constraints on the wire (#64)
- chore(deps): relock caller-aware module builder (#63)
logos-package-manager-ui
- feat: remove the ack process between basecamp and pmui to confirm install/uninstall/upgrades (#74)
- feat: request Settings → Repositories via an intent (#73)
logos-plugin-qt
- chore(deps): protocol 303ab08 — the wildcard deferred subscription (#30)
- fix(glue): the OTHER void site discarded the refusal too (#29)
- fix(glue): a void method’s REFUSAL is not a successful void call (#28)
- feat(consumer): logos::admitConsumer — one home for admitting a non-module (#27)
- fix(glue): route informModuleToken through the INBOUND door (#26)
logos-protocol
- fix(deferred): let onEventWhenAvailable take the wildcard, like onEvent (#74)
- fix(tokens): separate INBOUND from OUTBOUND, without moving a single byte (#73)
- feat(tokens): a private store is created EMPTY, not seeded with the host anchor (#71)
logos-qt-sdk
- chore(deps): protocol 303ab08 — the wildcard deferred subscription (#46)
- chore(deps): relock qt host stack (#45)
- fix(qt-consumer): a reply it cannot read must not become a provider refusal (#44)
logos-rust-sdk
- fix(origin): a module announces its OWN name, not “core” (#51)
- fix: bound the argument count above, and gate the identity arm (#50)
logos-standalone-app
- fix(plugins): load the backend library the plugin declares (#44)
- fix: log to stderr by default — the app’s own diagnostics were invisible (#43)
- refactor(plugins): admit consumers through the shared verb (#42)
logos-storage-module
logos-test-framework
logos-test-modules
- conformance: restore isolate on module-not-loaded (#56)
- conformance: module-not-loaded answers one token again (#55)
- docs(conformance): the isolate rule belongs to the table, not to one case (#54)
- chore(deps): relock caller-aware module builder (#53)
- conformance: close the arity work — retire B-arity-overflow, on measurement (#52)
- fix(ext): one contract, one shape for echoOptional — and three retirements (#51)
- conformance(ext): the consumer axis, and what it found (#50)
- conformance: the null-vs-failure classes, as cells (#49)
logos-tutorial
- feat: update tutorials for ui modules ot use qml hot reloading correc… (#86)
- feat: updated documentation and tests for the implemented intents mec… (#85)
- feat: update tutorials for ui modules ot use qml hot reloading correctly as per latest changes (#78)
logos-view-module-runtime
- feat(intents): add the frozen app-to-app intent surface (#28)
- feat(ui-host): adopt the parent’s credential through the shared verb (#27)