ocaml-matrix#
Status: SUBSTANTIALLY COMPLETE
OCaml Matrix SDK providing protocol types and a full HTTP client for the Matrix chat protocol (spec v1.17). Uses requests for HTTP and jsont for JSON encoding/decoding. Provides an Eio-idiomatic wrapper for structured concurrency.
Specification#
The Matrix spec is vendored at spec/matrix-spec as a git submodule (currently tracking v1.17).
See: https://github.com/matrix-org/matrix-spec
Client-Server API Feature Coverage#
The Matrix spec defines 41 feature modules for clients. Here is the implementation status for each:
Authentication & Session Management#
| Feature |
Status |
Module |
Notes |
| Login (password) |
✅ Complete |
Auth |
Username/password with device settings |
| Login (token/SSO) |
✅ Complete |
Auth |
Token-based login for SSO flows |
| Token refresh |
✅ Complete |
Auth |
Refresh expired access tokens |
| Logout |
✅ Complete |
Auth |
Single session or all sessions |
| Registration |
✅ Complete |
Auth |
Guest or user account creation |
| Whoami |
✅ Complete |
Auth |
Query current user/device |
| UIAA |
✅ Complete |
Uiaa |
Password, recaptcha, email, dummy flows |
| Soft logout |
⚠️ Partial |
Auth |
Token expiry detected, re-auth supported |
| Account locking |
❌ Not implemented |
- |
Server-side feature |
| OAuth 2.0 |
❌ Not implemented |
- |
Industry-standard auth (new in spec) |
Synchronization#
| Feature |
Status |
Module |
Notes |
/sync endpoint |
✅ Complete |
Sync |
Full parameter support |
| Long-polling |
✅ Complete |
Sync |
Configurable timeout |
| Incremental sync |
✅ Complete |
Sync |
next_batch token tracking |
| Sync filters |
✅ Complete |
Sync |
Create, retrieve, apply filters |
| Event filters |
✅ Complete |
Sync |
Type/sender filtering with limits |
| Room event filters |
✅ Complete |
Sync |
Lazy load members, contains_url |
| Sync loop |
✅ Complete |
Sync |
Callback-based continuous polling |
| Sliding sync (MSC3575) |
⚠️ Stub |
Sliding_sync |
Data structures only |
Rooms & Membership#
| Feature |
Status |
Module |
Notes |
| Room creation |
✅ Complete |
Rooms |
Name, topic, visibility, preset, type |
| Join room (by ID) |
✅ Complete |
Rooms |
With server routing |
| Join room (by alias) |
✅ Complete |
Rooms |
Alias resolution included |
| Leave room |
✅ Complete |
Rooms |
Standard leave |
| Forget room |
✅ Complete |
Rooms |
Remove from history |
| Invite user |
✅ Complete |
Rooms |
By user ID |
| Kick user |
✅ Complete |
Rooms |
With optional reason |
| Ban/unban user |
✅ Complete |
Rooms |
With optional reason |
| Get joined rooms |
✅ Complete |
Rooms |
List all joined rooms |
| Get room members |
✅ Complete |
Rooms |
With membership state filtering |
| Public room list |
✅ Complete |
Rooms |
Browse with pagination |
| Power levels |
✅ Complete |
Rooms |
Get/set room and user permissions |
| Knocking |
✅ Complete |
Event |
Join rule and membership type defined |
| Restricted join rules |
✅ Complete |
Event |
Room-based access control |
| Room upgrades |
⚠️ Partial |
Event |
Tombstone event type, no upgrade API |
Messaging#
| Feature |
Status |
Module |
Notes |
| Text messages |
✅ Complete |
Messages |
Plain text with msgtype |
| Emotes |
✅ Complete |
Messages |
m.emote support |
| Notices |
✅ Complete |
Messages |
m.notice support |
| HTML formatting |
✅ Complete |
Messages, Event |
format + formatted_body |
| Image messages |
✅ Complete |
Messages, Event |
With media info |
| File messages |
✅ Complete |
Messages, Event |
With media info |
| Audio messages |
✅ Complete |
Messages, Event |
With media info |
| Video messages |
✅ Complete |
Messages, Event |
With media info |
| Location messages |
✅ Complete |
Event |
geo_uri with location info |
| Stickers |
✅ Complete |
Event |
Sticker content type |
| Redaction |
✅ Complete |
Messages |
With optional reason |
| Get messages |
✅ Complete |
Messages |
Pagination forward/backward |
| Get event context |
✅ Complete |
Messages |
Events before/after |
| Rich replies |
✅ Complete |
Relations |
m.in_reply_to structure |
| Threads |
✅ Complete |
Relations |
m.thread relation type |
| Reactions |
✅ Complete |
Relations |
m.annotation with emoji key |
| Edits |
✅ Complete |
Relations |
m.replace relation type |
| Polls |
✅ Complete |
Event |
Start, response, end content types |
Room State#
| Feature |
Status |
Module |
Notes |
| Get state events |
✅ Complete |
State |
By type and state key |
| Set state events |
✅ Complete |
State |
Returns event ID |
| Room name |
✅ Complete |
State, Event |
Get/set with content type |
| Room topic |
✅ Complete |
State, Event |
Get/set with content type |
| Room avatar |
✅ Complete |
State, Event |
Get/set with image info |
| Room canonical alias |
✅ Complete |
Event |
Primary alias with alternates |
| Join rules |
✅ Complete |
Event |
Public/invite/knock/restricted/private |
| History visibility |
✅ Complete |
Event |
Invited/joined/shared/world_readable |
| Guest access |
✅ Complete |
Event |
Can_join/forbidden |
| Room encryption |
✅ Complete |
Event |
Algorithm and rotation settings |
| Pinned events |
✅ Complete |
Event |
List of pinned event IDs |
| Server ACLs |
✅ Complete |
Event |
Allow/deny rules |
| Room creation event |
✅ Complete |
Event |
Creator, version, predecessor |
User Profile & Presence#
| Feature |
Status |
Module |
Notes |
| Get profile |
✅ Complete |
Profile |
Display name and avatar |
| Set display name |
✅ Complete |
Profile |
Update own name |
| Set avatar |
✅ Complete |
Profile |
Update own avatar URL |
| Get presence |
✅ Complete |
Presence |
Online/offline/unavailable |
| Set presence |
✅ Complete |
Presence |
With status message |
| Last active time |
✅ Complete |
Presence |
Activity timestamp |
Ephemeral Events#
| Feature |
Status |
Module |
Notes |
| Typing notifications |
✅ Complete |
Typing |
Set typing state with timeout |
| Read receipts |
✅ Complete |
Receipts |
Send with receipt type |
| Read markers |
✅ Complete |
Receipts |
Set fully_read position |
End-to-End Encryption#
| Feature |
Status |
Module |
Notes |
| Ed25519 key generation |
✅ Complete |
Keys |
Signing keys |
| Curve25519 key generation |
✅ Complete |
Keys |
Key exchange |
| One-time key generation |
✅ Complete |
Keys |
Batch generation with signing |
| Fallback keys |
⚠️ Partial |
Keys |
Structure defined, upload untested |
| Device key upload |
✅ Complete |
Keys |
With signatures |
| Device key query |
✅ Complete |
Keys |
Fetch keys for users |
| One-time key claim |
✅ Complete |
Keys |
Obtain keys for Olm setup |
| Key change tracking |
✅ Complete |
Keys |
Between syncs |
| Olm sessions |
✅ Complete |
Olm |
Create, store, retrieve |
| X3DH key exchange |
✅ Complete |
Olm |
Triple Diffie-Hellman |
| Double Ratchet |
✅ Complete |
Olm |
Per-session encryption |
| Megolm sessions |
✅ Complete |
Olm |
Outbound/inbound group keys |
| Message encryption |
✅ Complete |
Olm |
With authentication |
| Message decryption |
✅ Complete |
Olm |
With verification |
| Session pickling |
⚠️ Partial |
Olm |
Simplified JSON format |
| Encrypted event type |
✅ Complete |
Event |
Olm and Megolm algorithms |
Device & Key Verification#
| Feature |
Status |
Module |
Notes |
| List devices |
✅ Complete |
Devices |
All devices for user |
| Get device info |
✅ Complete |
Devices |
IP and timestamp |
| Update device |
✅ Complete |
Devices |
Display name |
| Delete device |
✅ Complete |
Devices |
Single or batch |
| Cross-signing keys |
✅ Complete |
Verification |
Master, self, user signing |
| SAS verification |
⚠️ Partial |
Verification |
20/64 emoji, no to-device |
| QR verification |
⚠️ Partial |
Verification |
Structures only, no encode/decode |
| Device trust |
✅ Complete |
Verification |
Trust state tracking |
| Signature verification |
⚠️ Partial |
Verification |
Existence check only |
| Verification events |
✅ Complete |
Event |
Ready, start, accept, key, mac, cancel, done |
Key Backup#
| Feature |
Status |
Module |
Notes |
| Backup encryption |
✅ Complete |
Backup |
m.megolm_backup.v1.curve25519-aes-sha2 |
| Backup decryption |
✅ Complete |
Backup |
AES-CTR with HKDF |
| Recovery key generation |
⚠️ Partial |
Backup |
Uses base64, not base58 |
| Recovery key parsing |
❌ Stub |
Backup |
Needs implementation |
| Backup upload |
❌ Not implemented |
- |
No server API integration |
| Backup download |
❌ Not implemented |
- |
No server API integration |
| Backup version management |
❌ Not implemented |
- |
No server API integration |
| Feature |
Status |
Module |
Notes |
| Upload media |
✅ Complete |
Media |
Binary with content type |
| Download media |
✅ Complete |
Media |
By server/media ID |
| Thumbnails |
✅ Complete |
Media |
Scaled/cropped versions |
| MXC URI parsing |
✅ Complete |
Media |
Parse mxc:// URIs |
| MXC to HTTP URL |
✅ Complete |
Media |
With thumbnail options |
| Upload size limit |
✅ Complete |
Media |
Query configuration |
| Encrypted media |
✅ Complete |
Event |
Encrypted file structure |
Account Management#
| Feature |
Status |
Module |
Notes |
| Global account data |
✅ Complete |
Account |
Get/set arbitrary data |
| Room account data |
✅ Complete |
Account |
Per-room data |
| Third-party IDs |
✅ Complete |
Account |
Query, add, delete 3PIDs |
| Email verification |
✅ Complete |
Account |
Request tokens |
| Phone verification |
✅ Complete |
Account |
Request tokens |
| Password change |
✅ Complete |
Account |
With device logout option |
| Account deactivation |
✅ Complete |
Account |
Irreversible with erasure |
| Ignored users |
✅ Complete |
Account |
Maintain ignore list |
Room Directory#
| Feature |
Status |
Module |
Notes |
| Alias resolution |
✅ Complete |
Directory |
Alias to room ID |
| Create alias |
✅ Complete |
Directory |
New room alias |
| Delete alias |
✅ Complete |
Directory |
Remove alias |
| Room visibility |
✅ Complete |
Directory |
Get/set directory visibility |
| Public room search |
✅ Complete |
Directory |
With term and type filtering |
Spaces#
| Feature |
Status |
Module |
Notes |
| Space child events |
✅ Complete |
Event |
Via servers, order, suggested |
| Space parent events |
✅ Complete |
Event |
Via servers, canonical |
| Space hierarchy |
✅ Complete |
Spaces |
Navigate structure |
| Space management |
✅ Complete |
Spaces |
Parent/child relationships |
Voice/Video Calling#
| Feature |
Status |
Module |
Notes |
| Call invite |
✅ Complete |
Event, Calls |
SDP offer, lifetime |
| Call answer |
✅ Complete |
Event, Calls |
SDP answer |
| Call hangup |
✅ Complete |
Event, Calls |
With reason codes |
| ICE candidates |
✅ Complete |
Event, Calls |
Candidate exchange |
| Call member |
✅ Complete |
Event |
LiveKit support, foci_active |
Push Notifications#
| Feature |
Status |
Module |
Notes |
| Get push rules |
✅ Complete |
Push |
User notification rules |
| Set push rules |
✅ Complete |
Push |
Update rules |
| Enable/disable rules |
✅ Complete |
Push |
Toggle specific rules |
| Delete rules |
✅ Complete |
Push |
Remove rules |
| Push gateway |
❌ Not implemented |
- |
Separate API |
Additional Features#
| Feature |
Status |
Module |
Notes |
| Room preview |
✅ Complete |
Room_preview |
Info before joining |
| Room tagging |
⚠️ Partial |
Account |
Via account data |
| Server notices |
❌ Not implemented |
- |
Server-side feature |
| OpenID |
❌ Not implemented |
- |
Token provisioning |
| Third-party invites |
❌ Not implemented |
- |
Email/phone invites |
| Third-party networks |
❌ Not implemented |
- |
Bridge support |
| Server-side search |
❌ Not implemented |
- |
Full-text search |
| Reporting content |
❌ Not implemented |
- |
Event flagging |
| Moderation policy lists |
✅ Complete |
Event |
Policy rule content type |
| Server ACLs |
✅ Complete |
Event |
Allow/deny in state |
| Secret storage |
❌ Not implemented |
- |
m.secret_storage.v1 |
| Recently used emoji |
❌ Not implemented |
- |
Client-side typically |
Protocol Types Coverage#
Identifiers (Matrix_id)#
| Type |
Status |
Notes |
| Server_name |
✅ Complete |
Hostname validation |
| User_id |
✅ Complete |
@localpart:server format |
| Room_id |
✅ Complete |
!opaque_id:server format |
| Event_id |
✅ Complete |
v1-3 and v4 formats |
| Room_alias |
✅ Complete |
#alias:server format |
| Device_id |
✅ Complete |
Opaque string |
| Session_id |
✅ Complete |
Megolm session IDs |
| Transaction_id |
✅ Complete |
With generate() |
Event Content Types (Matrix_event)#
| Category |
Types |
Status |
| Room state |
16 types |
✅ Complete |
| Space events |
2 types |
✅ Complete |
| Call events |
5 types |
✅ Complete |
| Verification events |
7 types |
✅ Complete |
| Message events |
8 types |
✅ Complete |
| Encrypted content |
1 type |
✅ Complete |
| Relations |
3 types |
✅ Complete |
| Location/Beacons |
2 types |
✅ Complete |
| Policy rules |
1 type |
✅ Complete |
Sync Response (Matrix_sync)#
| Component |
Status |
Notes |
| Timeline |
✅ Complete |
Events, limited, pagination |
| Ephemeral |
✅ Complete |
Typing, receipts |
| Account data |
✅ Complete |
Per-room and global |
| Room state |
✅ Complete |
State events |
| Joined rooms |
✅ Complete |
Full room state |
| Invited rooms |
✅ Complete |
Invite state |
| Left rooms |
✅ Complete |
Leave state |
| Knocked rooms |
✅ Complete |
Knock state |
| Device lists |
✅ Complete |
Changed/left tracking |
| To-device |
✅ Complete |
Direct messages |
| Presence |
✅ Complete |
User presence |
Client Architecture#
Libraries#
| Library |
Purpose |
Status |
matrix_proto |
Protocol types with jsont codecs |
✅ Complete |
matrix_client |
HTTP client (Result-based) |
✅ Complete |
matrix_eio |
Eio wrapper (exception-based) |
✅ Complete |
Client Modules#
All 23 modules have Eio wrappers:
| Module |
Lines |
Status |
Notes |
| Auth |
304 |
✅ Complete |
All login flows |
| Sync |
246 |
✅ Complete |
Sync loop with callbacks |
| Rooms |
461 |
✅ Complete |
Full room management |
| Messages |
232 |
✅ Complete |
All message types |
| State |
139 |
✅ Complete |
State get/set |
| Keys |
447 |
✅ Complete |
E2EE key management |
| Olm |
895 |
✅ Complete |
Session management |
| Verification |
535 |
⚠️ Partial |
SAS incomplete |
| Backup |
466 |
⚠️ Partial |
No server API |
| Media |
118 |
✅ Complete |
Upload/download |
| Profile |
108 |
✅ Complete |
Name/avatar |
| Presence |
72 |
✅ Complete |
Status management |
| Typing |
31 |
✅ Complete |
Typing indicators |
| Receipts |
39 |
✅ Complete |
Read receipts |
| Devices |
89 |
✅ Complete |
Device management |
| Account |
329 |
✅ Complete |
Account data, 3PIDs |
| Directory |
182 |
✅ Complete |
Aliases, search |
| Relations |
330 |
✅ Complete |
Reactions, edits, threads |
| Uiaa |
435 |
✅ Complete |
Multi-stage auth |
| Timeline |
423 |
⚠️ Partial |
TODO: trimming |
| Store |
1001 |
⚠️ Partial |
In-memory only |
| Send_queue |
466 |
⚠️ Partial |
No HTTP integration |
| Push |
368 |
✅ Complete |
Push rules |
| Spaces |
212 |
✅ Complete |
Hierarchy |
| Calls |
193 |
✅ Complete |
VoIP events |
| Room_preview |
257 |
✅ Complete |
Preview info |
| Sliding_sync |
500 |
❌ Stub |
MSC3575 structures only |
Known Limitations#
Verification Module#
- SAS emoji table has 20 entries (spec requires 64)
verify_cross_signing_signature checks existence, not cryptographic validity
- QR code verification has structures but no encoding/decoding
- No to-device message sending for verification flow
Backup Module#
- Recovery key uses base64 encoding instead of base58
parse_recovered_key is a stub
- No server API calls for backup upload/download/version management
Send_queue Module#
- Provides queue management but no HTTP integration
- Caller must implement
send_fn for actual sending
- No automatic persistence
Store Module#
- All stores (STATE_STORE, CRYPTO_STORE, EVENT_CACHE_STORE) are in-memory only
- Pluggable architecture defined but only memory backends exist
- No SQLite or file-based implementations
Timeline Module#
- LinkedChunk
push_back has TODO for trimming when over max_events
- LRU eviction removes oldest room without access-time preservation
Olm Module#
- Session pickle/unpickle uses simplified JSON format
- Needs real-world validation
- No session recovery from corrupted state
Test Coverage#
| Area |
Tests |
Status |
| Protocol types |
39 roundtrip tests |
✅ Complete |
| Sync response |
Fixture-based |
✅ Complete |
| Integration tests |
None |
❌ Needed |
Dependencies#
jsont / jsont.bytesrw - JSON encoding/decoding
requests - HTTP client
eio - Async I/O with structured concurrency
uri - URI handling
ptime - Timestamps
base64 - Base64 encoding
mirage-crypto - AES-CBC encryption
mirage-crypto-ec - Ed25519/X25519 cryptography
mirage-crypto-rng - Secure random number generation
digestif - SHA-256 hashing
kdf.hkdf - HKDF key derivation
Room Versions#
The implementation supports room version events but does not enforce version-specific behavior:
| Version |
Key Feature |
Event Support |
| v1-v6 |
Core messaging |
✅ |
| v7 |
Knocking |
✅ |
| v8 |
Restricted joins |
✅ |
| v9 |
Redaction fixes |
✅ |
| v10 |
Integer power levels |
✅ |
| v11 |
Redaction clarification |
✅ |
| v12 |
Creator infinite power |
✅ |
Summary#
Overall completion: ~85%
- Core features: 95% complete (auth, sync, rooms, messages, state, presence)
- E2EE primitives: 90% complete (keys, Olm, Megolm - verification partial)
- Advanced features: 70% complete (backup, sliding sync, secret storage incomplete)
- Infrastructure: 80% complete (storage in-memory only, no integration tests)
The SDK is suitable for building Matrix clients with basic E2EE support. Full production use requires completing verification flows, backup server integration, and persistent storage backends.