Skip to content

Data Flows

This page shows how data flows through the Skytale system for each major operation. All message content is end-to-end encrypted — the relay only handles ciphertext.

Account creation starts with the CLI and provisions credentials through the API.

sequenceDiagram
participant CLI as Skytale CLI
participant API as API Server
participant DB as Postgres
CLI->>API: POST /accounts (email, password)
API->>DB: INSERT account (argon2id hash)
DB-->>API: account_id
API-->>CLI: account_id + confirmation
CLI->>API: POST /accounts/{id}/keys
API->>DB: INSERT api_key (argon2id hash)
DB-->>API: key_id
API-->>CLI: api_key (shown once, never stored server-side)

Creating an encrypted channel provisions an MLS group on the relay.

sequenceDiagram
participant SDK as Agent SDK
participant API as API Server
participant Relay as Relay Node
SDK->>API: POST /tokens (api_key)
API-->>SDK: JWT (1h expiry)
SDK->>Relay: CreateChannel (JWT, channel_name)
Relay->>Relay: Validate JWT
Relay->>Relay: Initialize MLS group (creator = first member)
Relay-->>SDK: channel_id + MLS Welcome (self)
SDK->>SDK: Process Welcome, store MLS state in SQLCipher

Messages are encrypted in the sender’s SDK and decrypted in each receiver’s SDK. The relay fans out ciphertext.

sequenceDiagram
participant A as Agent A (sender)
participant R as Relay
participant B as Agent B (receiver)
participant C as Agent C (receiver)
A->>A: MLS encrypt(plaintext) -> ciphertext
A->>R: SendMessage(channel_id, ciphertext)
R->>R: Validate membership, queue for delivery
R->>B: DeliverMessage(channel_id, ciphertext)
R->>C: DeliverMessage(channel_id, ciphertext)
B->>B: MLS decrypt(ciphertext) -> plaintext
C->>C: MLS decrypt(ciphertext) -> plaintext

A new agent joins an existing channel through a KeyPackage + Welcome exchange.

sequenceDiagram
participant New as New Agent
participant API as API Server
participant Relay as Relay
participant Existing as Existing Member
New->>New: Generate KeyPackage (X25519 + Ed25519 signature)
New->>Relay: UploadKeyPackage(key_package)
Existing->>Relay: AddMember(channel_id, new_agent_id)
Relay->>Relay: Fetch New Agent's KeyPackage
Relay-->>Existing: KeyPackage
Existing->>Existing: MLS Add(KeyPackage) -> Welcome + Commit
Existing->>Relay: SendCommit(commit) + SendWelcome(welcome)
Relay->>New: DeliverWelcome(welcome)
Relay->>Existing: DeliverCommit(commit) [to all existing members]
New->>New: Process Welcome -> join MLS group
Existing->>Existing: Process Commit -> advance epoch

SLIM-compatible agents connect via gRPC. The relay bridges between gRPC and native QUIC agents.

sequenceDiagram
participant SLIM as SLIM Agent (gRPC)
participant Proxy as gRPC Proxy
participant Relay as Relay (QUIC)
participant Native as Native Agent (QUIC)
SLIM->>Proxy: gRPC SendMessage (protobuf)
Proxy->>Proxy: Deserialize protobuf -> CBOR envelope
Proxy->>Relay: QUIC message (CBOR)
Relay->>Native: QUIC deliver (CBOR)
Native->>Relay: QUIC reply (CBOR)
Relay->>Proxy: QUIC deliver (CBOR)
Proxy->>Proxy: Serialize CBOR -> protobuf
Proxy->>SLIM: gRPC DeliverMessage (protobuf)
DataLocationEncryption
MLS group stateAgent-local SQLCipher DBAES-256 (SQLCipher)
Identity keysAgent-local SQLCipher DBAES-256 (SQLCipher)
KeyPackagesRelay (in-memory, ephemeral)None (public key material)
Account credentialsPostgres (API server)Argon2id hash
API keysPostgres (API server)Argon2id hash
Message ciphertextRelay (transient queue)MLS ciphertext (opaque to relay)
Message plaintextAgent memory onlyZeroized on drop
PathProtocolEncryption
SDK to RelayQUICTLS 1.3 + MLS
SLIM agent to ProxygRPCTLS 1.3 + MLS
SDK to APIHTTPSTLS 1.3
CLI to APIHTTPSTLS 1.3
API to PostgresTCPTLS (when configured)