macltok
macltok is a compact Rust application backend built above matrix-sdk and
matrix-sdk-ui. It aims to provide the stateful behavior needed by a useful
Matrix client without depending on a GUI toolkit or inventing another protocol
SDK.
The crate currently provides
- typed commands, owned UI-safe events and bounded per-client transport
- Sliding Sync with normalized connection and room-list state
- independently retained live room timelines and backwards pagination
- text, emote, reply, edit, redaction, reaction, receipt and typing operations
- raw encrypted or unencrypted media acquisition with configurable byte limits
- encryption state, recovery-key import and SAS verification
- password login and session restoration with caller-owned encrypted SQLite stores
Matrix room, event, user, device and transaction identifiers remain strongly typed. A toolkit timeline identity covers local echoes without pretending they already have remote event IDs.
Consuming the engine
spawn Engine::run, drain the EventStream from its own task, and talk to the
engine through ClientHandle. every command answers once, awaited
(handle.send_message(..).await?) or as a Pending you can await later or
drop. a sent message answers when the sdk send queue has it, delivery shows up
as the timeline item’s send state. reads like rooms, members and media
go straight to the sdk. the stream only carries state
start a timeline from TimelineReset, then apply TimelineChanged diffs with
TimelineDiff::try_apply. when one doesn’t fit, stop applying, call resync,
and pick up from the next TimelineReset
With sqlite, persist the initial Session::record() separately from its
encrypted SQLite store. On SessionTokensChanged, obtain a new record from
ClientHandle::session_record() and replace the saved record atomically in
protected storage. Restore with the same store path and passphrase.
LoggedOut and SessionAccessRejected both stop the engine. after a logout or a
hard rejection the record and the store are dead, bin them. a soft logout wants
the store kept and a fresh login with PasswordLogin::device_id set to the old
device, or the e2ee keys go with it. a bare Stopped means keep everything. one
store directory per login, the sdk won’t share a crypto store between devices.
The headless example is
login-only; it does not persist sessions across runs.
Dependency policy
UI frameworks, image decoders, application-directory discovery and logging
subscribers do not belong in this crate. SQLite remains optional through the
sqlite and bundled-sqlite features. Media decoding belongs to the consumer.
Verification
nix develop --command cargo fmt -- --check
nix develop --command cargo test --all-targets
nix develop --command cargo test --all-targets --features sqlite
nix develop --command cargo clippy --all-targets -- -D warnings
nix develop --command cargo clippy --all-targets --features sqlite -- -D warnings
nix flake check