# Agent Architecture The SimpleX Agent is the Layer 3 connection manager. It builds duplex encrypted connections on top of Layer 2 client libraries. This document shows its internal architecture: component topology and message processing flows. For usage and API overview, see [docs/AGENT.md](../docs/AGENT.md). For protocol specifications, see [Agent Protocol](../protocol/agent-protocol.md), [PQDR](../protocol/pqdr.md). **Split-phase encryption**: Message sending separates ratchet advancement (API thread, serialized) from body encryption (delivery worker, parallel). This prevents ratchet lock contention across queues while maintaining correct message ordering. See [infrastructure.md](agent/infrastructure.md#message-delivery). **Worker taxonomy**: Three worker families handle background operations - delivery workers (per send queue), async command workers (per connection), and NTF workers (per server). All use the same create-or-reuse pattern with restart rate limiting. See [infrastructure.md](agent/infrastructure.md#worker-framework). **Suspension cascade**: Operations drain in dependency order: `AORcvNetwork` → `AOMsgDelivery` → `AOSndNetwork` → `AODatabase`. Suspending receive processing cascades through to database access, ensuring clean shutdown. See [infrastructure.md](agent/infrastructure.md#operation-suspension-cascade). --- **Module specs**: [Agent](modules/Simplex/Messaging/Agent.md) · [Agent Client](modules/Simplex/Messaging/Agent/Client.md) · [Agent Protocol](modules/Simplex/Messaging/Agent/Protocol.md) · [Store Interface](modules/Simplex/Messaging/Agent/Store/Interface.md) · [NtfSubSupervisor](modules/Simplex/Messaging/Agent/NtfSubSupervisor.md) · [XFTP Agent](modules/Simplex/FileTransfer/Agent.md) · [Ratchet](modules/Simplex/Messaging/Crypto/Ratchet.md) ### Agent components ![Agent components](diagrams/agent.svg) ### Message receive flow ```mermaid sequenceDiagram participant R as SMP Router box Agent participant SC as smpClients
(ProtocolClient pool) participant MQ as msgQ
(TBQueue) participant S as subscriber participant St as Store participant SQ as subQ
(TBQueue) end participant App as Application R->>SC: MSG (encrypted packet) SC->>MQ: write batch S->>MQ: read batch S->>S: withConnLock
(serialize per connection) S->>St: load ratchet state
(lockConnForUpdate) S->>S: agentRatchetDecrypt
(double ratchet) S->>S: checkMsgIntegrity
(sequence + hash chain) S->>St: store received message,
update ratchet S->>SQ: write AEvt (MSG + metadata) App->>SQ: read event Note over App: application processes message App->>S: ackMessage (agentMsgId) Note over S,R: ACK is async
(enqueued as internal command) S->>SC: ACK SC->>R: ACK ``` ### Message send flow ```mermaid sequenceDiagram participant App as Application box Agent participant API as sendMessage participant St as Store participant DW as deliveryWorker
(per send queue) participant SC as smpClients
(ProtocolClient pool) end participant R as SMP Router App->>API: sendMessage
(connId, body) API->>St: agentRatchetEncryptHeader
(advance ratchet, store
encrypt key + pending message) API->>DW: signal doWork (TMVar) API->>App: return msgId DW->>St: getPendingQueueMsg DW->>DW: rcEncryptMsg
(encrypt body with stored key) DW->>DW: encode AgentMsgEnvelope DW->>SC: sendAgentMessage
(per-queue encrypt + SEND) SC->>R: SEND (encrypted packet) R->>SC: OK DW->>St: delete pending message DW->>App: SENT msgId (via subQ) ``` ### Connection establishment flow ```mermaid sequenceDiagram participant A as Alice (initiator) box Agent A participant AA as Agent end participant SMP as SMP Router box Agent B participant AB as Agent end participant B as Bob (joiner) A->>AA: createConnection AA->>SMP: NEW
(Alice's receive queue) SMP->>AA: queue ID + keys AA->>A: invitation URI
(queue address + DH keys) Note over A,B: invitation passed out-of-band
(QR code, link) B->>AB: joinConnection
(invitation) AB->>AB: initSndRatchet
(PQ X3DH key agreement) AB->>SMP: SKEY (sender auth on
Alice's queue) AB->>SMP: NEW
(Bob's receive queue) SMP->>AB: queue ID AB->>SMP: SEND confirmation to
Alice's queue (Bob's queue
address + ratchet keys) SMP->>AA: MSG (confirmation) AA->>AA: initRcvRatchet
(PQ X3DH key agreement),
decrypt confirmation AA->>A: CONF (request approval) A->>AA: allowConnection(confId) AA->>SMP: KEY (register sender key
on Alice's rcv queue) AA->>SMP: SKEY (sender auth on
Bob's queue) AA->>SMP: SEND reply to Bob's queue
(Alice's connection info) SMP->>AB: MSG (reply) AB->>SMP: KEY (register sender key
on Bob's rcv queue) AB->>SMP: SEND HELLO to Alice SMP->>AA: MSG (HELLO) AA->>SMP: SEND HELLO to Bob AA->>A: CON (connected) SMP->>AB: MSG (HELLO) AB->>B: CON (connected) ``` ### File delivery flow (XFTP) ```mermaid sequenceDiagram participant SA as Sender App box Sender Agent participant S as xftpSnd workers participant SS as Store end participant XFTP as XFTP Routers participant SMP as SMP Router box Receiver Agent participant RS as Store participant R as xftpRcv workers end participant RA as Receiver App SA->>S: xftpSendFile(file) S->>S: encrypt file
(XSalsa20-Poly1305, random key + nonce) S->>S: split into chunks
(fixed sizes: 64KB - 4MB) S->>SS: store SndFile + chunks loop each chunk S->>XFTP: FNEW (create data packet) XFTP->>S: sender ID + recipient IDs S->>XFTP: FPUT (upload encrypted chunk) end S->>S: assemble FileDescription
(chunk locations, replicas,
encryption key + nonce) S->>SA: SFDONE
(sender + recipient descriptions) Note over SA,RA: recipient description sent as
SMP message (encrypted, via double ratchet) SA->>SMP: description in A_MSG SMP->>RA: description in MSG RA->>R: xftpReceiveFile
(description) R->>RS: store RcvFile + chunks loop each chunk (parallel per server) R->>XFTP: FGET (per-recipient auth key) XFTP->>R: encrypted chunk stream end R->>R: stream chunks through
stateful decrypt (key + nonce),
verify auth tag at end R->>RA: RFDONE
(decrypted file path) ```