SystemOperation
SystemOperation is the protocol/MLS operations envelope in Cryptid. It carries messages that change group state, cryptographic operations, and protocol-level events. NOT user-facing chat content.
Why Separate from CryptidMessage
Section titled “Why Separate from CryptidMessage”We separate SystemOperation from CryptidMessage for:
- Clarity of semantics:
- Clients can treat
CryptidMessageas “chat stuff” andSystemOperationas “protocol stuff” - Keeps UI and state machines cleaner
- Clients can treat
- Different handling paths:
CryptidMessagegoes to: decrypt -> store in message DB -> render in UI -> mabye sync reactions/editsSystemOperationgoes to: feed into MLS/group engine -> update permissions/metadata/address mappings -> maybe emit internal events
- Security and robustness:
- By having a distinct type, it’s easier to enforce “only MLS-validated, permission-checked commits can change group state”
- Reject or quarantine bogus
SystemOperationpayloads without risking the chat message pipeline
- UX isolation:
SystemOperationevents are mostly invisible or minimally surfaced- Keeping them distinct avoids accidental exposing low-level events as messages
SystemOperation Structure
Section titled “SystemOperation Structure”/// Protocol operation identifier (UUIDv7)pub struct OperationId(Uuidv7);
/// Protocol/MLS operations envelopestruct SystemOperation { // UUIDv7 for ordering/sequencing operation_id: OperationId,
// Device that initiated this operation sender: DeviceId,
// MLS group this applies to group_id: GroupId,
// The actual operation inner: SystemOperationInner,}Field Specification
Section titled “Field Specification”operation_id- OperationId (wrapper around Uuidv7)
- Unique identifier for this operation
- Used for ordering and deduplication
sender- DeviceId of the device that created this operation
- Authenticated by MLS group signature
- Cannot be spoofed
group_id- GroupId this operation applies to
- MUST be a valid MLS group
innerSystemOperationInnerenum variant- Determines the type of operation
SystemOperationInner Structure
Section titled “SystemOperationInner Structure”enum SystemOperationInner { // MLS commits and welcomes MLSCommit { proposals: Vec<Proposal>, path: Vec<u8>, }, MLSWelcome { welcome: Vec<u8> },
// Group context extension updates GroupContextExtension { permissions: Option<PermissionExtension>, metadata: Option<GroupMetadataExtension>, custom_media: Option<CustomMediaExtension>, thread_metadata: Option<ThreadMetadataExtension>, },
// Sent by the adding member to a joiner immediately after Welcome. // MLS carries creds but not addresses, so we need a way for someone // to supply an initial set of delivery addresses of group members // to new joiners. AddressBookSnapshot { addresses: Vec<(DeviceId, DeliveryAddress)>, },
// Distributes mailbox public keys, not just routing hints. A member // who misses this cannot reach the sender at all, which is what the // rotation overlap window covers. None means first announcement on join. AddressRotation { old_addresses: Option<Vec<DeliveryAddress>>, new_addresses: Vec<DeliveryAddress>, },
// Epoch change notification EpochChange { new_epoch: u64 },}SystemOperationInner Variants
Section titled “SystemOperationInner Variants”MLSCommit
Section titled “MLSCommit”Carries MLS commit messages that add or remove members from the group.
SystemOperationInner::MLSCommit { proposals: Vec<Proposal>, path: Vec<u8>,}proposals: List of proposals (Add, Remove, Update)path: Commit path for ratchet tree updates- All commits MUST be validated against group permissions before processing
- See MLS Integration for MLS details
MLSWelcome
Section titled “MLSWelcome”Carries welcome messages for newly added members.
SystemOperationInner::MLSWelcome { welcome: Vec<u8> }welcome: MLS welcome message ciphertext- Used to add new members to the group
- Contains encrypted group state for the new member
GroupContextExtension
Section titled “GroupContextExtension”Carries updates to group context extensions.
SystemOperationInner::GroupContextExtension { permissions: Option<PermissionExtension>, metadata: Option<GroupMetadataExtension>, custom_media: Option<CustomMediaExtension>, thread_metadata: Option<ThreadMetadataExtension>,}- PermissionExtension:
- Updates to group permissions (see Moderation Architecture)
- Contains device_id -> Permission mappings
- Cryptographically enforced via MLS group extensions
- GroupMetadataExtension:
- Updates to group name, description, picture
- Contains group display information
- CustomMediaExtension:
- Updates to group’s custom emoji and sticker packs
- Contains emoji definitions, sticker references
- ThreadMetadataExtension:
- Updates to thread metadata
- Contains thread titles, settings
AddressBookSnapshot
Section titled “AddressBookSnapshot”Sent by the adding member to a joiner immediately after Welcome. MLS carries credentials but not addresses, so a new member otherwise knows every device_id in the group and no addresses at all.
SystemOperationInner::AddressBookSnapshot { addresses: Vec<(DeviceId, DeliveryAddress)>,}addresses: every current group member’s delivery address for this group- MUST be sent before the joiner is expected to participate
- The joiner replies with an
AddressRotationcarryingold_addresses: None
AddressRotation
Section titled “AddressRotation”Distributes a device’s mailbox public keys to the group. This is key distribution, not merely a routing hint. A member who misses it cannot reach the sender at all, which is what the overlap window covers.
SystemOperationInner::AddressRotation { old_addresses: Option<Vec<DeliveryAddress>>, new_addresses: Vec<DeliveryAddress>,}old_addresses: previous addresses being replaced, for cleanup.Noneon first announcement after joining a groupnew_addresses: new addresses, including themailbox_publicsenders encrypt to- Members update their address book, which is keyed by
(DeviceId, GroupId) - Old addresses remain deliverable until the sender deregisters them
- See Mailbox Keypairs for derivation and rotation
EpochChange
Section titled “EpochChange”Notifies that the MLS epoch has changed.
SystemOperationInner::EpochChange { new_epoch: u64 }new_epoch: New MLS epoch number- Clients update their local group state
- Triggers key derivation for new epoch
Requirements
Section titled “Requirements”Security Requirements
Section titled “Security Requirements”-
Permission Enforcement:
- Clients MUST verify sender has required permissions before accepting commits
- Permission checks MUST use the MLS group extension (not local state)
- Modified clients that skip verification are isolated from honest clients because they’ll brick their own state
-
Commit Validation:
- All MLSCommit operations MUST be validated against group permissions
- Unauthorized commits MUST be rejected
- See Moderation Architecture
Processing Requirements
Section titled “Processing Requirements”- Message Handling:
- SystemOperation messages MUST be processed before CryptidMessage messages
- Group state changse affect message decryption
- Clients MUST apply SystemOperations before processing messages in the same epoch
- Ordering:
- SystemOperation messages provide causal ordering within an epoch
- Clients MUST process in MLS epoch order
- Within same epoch, use operation_id for ordering
NOT Protocol Responsibilities
Section titled “NOT Protocol Responsibilities”- Enforcing UI display of system operations
- Determining when to show “X joined the group” messages
- Storing operation history
- Reverting failed operations (MLS handles this)
Example Operations
Section titled “Example Operations”Member Added
Section titled “Member Added”{ "operation_id": "019e3eb4-2fbf-7863-9118-8c80709fdce1", "sender": "admin-device-id", "group_id": "group-uuid-v4", "inner": { "type": "MLSCommit", "proposals": [ { "type": "Add", "new_member": "device-xyz" } ], "path": "base64encodedpath..." }}Group Permissions Updated
Section titled “Group Permissions Updated”{ "operation_id": "019e3eb4-2fbf-7863-9118-8c80709fdce1", "sender": "admin-device-id", "group_id": "group-uuid-v4", "inner": { "type": "GroupContextExtension", "permissions": { "device_permissions": { "device-abc": 1, "device-xyz": 2 }, "founder": "device-abc", "version": 5 }, "metadata": null, "custom_media": null, "thread_metadata": null }}Address Rotation
Section titled “Address Rotation”{ "operation_id": "019e3eb4-2fbf-7863-9118-8c80709fdce1", "sender": "device-xyz", "group_id": "group-uuid-v4", "inner": { "type": "AddressRotation", "old_addresses": [ { "prefix": "oldaddress123", "server": "chat.example.com", "mailbox_public": "base64_x25519_public_key", "created_at": 1787798678, "active": true } ], "new_addresses": [ { "prefix": "newaddress456", "server": "chat.example.com", "mailbox_public": "base64_x25519_public_key", "created_at": 1787798706, "active": true } ] }}