Core Concepts
Five decisions prevent most of the pain in a system like this. Everything else in these docs is downstream of them.
- A headless native agent; Flutter is a detachable control panel. The gateway must keep working when there is no UI — after a reboot, during backgrounding, under memory pressure. So the agent is native Kotlin in a foreground service, and Dart renders state it does not own.
- Persist before you act; at-least-once plus idempotency keys. The durable store is written before the network is trusted and before any ack is sent. Duplicates are made harmless by keying on command and event ids rather than being prevented by careful ordering.
- A versioned, transport-neutral wire protocol as the real extension point. Not a class hierarchy. A future MMS transport or a Linux modem node plugs in at the protocol, which is why it carries a version number from v1.
- Design for being killed, not for immortality. Android and OEM skins will kill the process. The answer is recovery — boot receiver, WorkManager backstop, resync handshake — not wake locks and wishful thinking.
- Backend-authoritative but client-enforced limits, and PII never in logs. Rate limits and allowlists are policy from the server, enforced again on the device, so a compromised backend still cannot turn a SIM into a spam cannon.
In this section
Responsibilities, communication flows, and the state machines that run them.
ArchitectureFrom install to paired to running, and every way back.
Device lifecycleRetry, heartbeat, resync, offline behaviour and error taxonomy.
ReliabilityEvery directory in the repository and the reason it exists.
Folder structure