7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 1 | # The setup pattern |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 2 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 3 | One pattern that bot developers might find useful when using the Matrix Rust SDK |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 4 | is to use a "setup" pattern, which, simply put, consists of having a bot user |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 5 | bootstrap the bot through a dedicated `setup` (sub)command, and then run the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 6 | main executable. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 7 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 8 | Then, together with that, create an invariant in the main executable: Always |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 9 | expect state. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 10 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 11 | The latter can be done by checking if the path to a stored and serialized |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 12 | [`Session`](https://docs.rs/matrix-sdk/latest/matrix_sdk/struct.Session.html) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 13 | configuration exists (as created during the `setup` command), and/or by checking |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 14 | for files under the path provided to |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 15 | [`make_store_config`](https://docs.rs/matrix-sdk/latest/matrix_sdk/store/fn.make_store_config.html). |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 16 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 17 | If the main executable can't find this configuration, abort running. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 18 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 19 | ## Context |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 20 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 21 | The context of this pattern document, and the reason for the crystallization of |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 22 | this idea, is that currently the "modus operandi" of Instant Messaging bots is |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 23 | quite stateless. Bots might still have state pertaining to users, databases and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 24 | whatnot that contain explicit state of business logic, but it's not expected |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 25 | that the _bot itself_ has state. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 26 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 27 | This expectation becomes especially problematic when combined with E2EE, where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 28 | the running application has to not lose sight of it, or else it'll lose access |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 29 | to E2EE (group) chats. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 30 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 31 | This expectation exists both on the developer and user side of bots, and so to |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 32 | start fixing it, this pattern is recommended to bot creators, as then the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 33 | lifetime cycle of the bot (and its data) is clear to every party involved, and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 34 | errors are not necessarily "fatal" (or catastrophic while confusing). |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 35 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 36 | ## Consequence |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 37 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 38 | Some of the consequences of the above invariant (setup phase initializes state, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 39 | run phase expects it initialized) are the following; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 40 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 41 | - If the bot starts, but cannot find a state directory, it'll abort without |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 42 | implicitly creating one. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 43 | - If the setup command is ran while state already exists, it would either abort |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 44 | or offer modification (such as a different client URL) to the operator. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 45 | - E2EE state cannot easily become wedged or confusingly absent inbetween bot |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 46 | runs, as the run phase will not run (and alter E2EE server state, such as |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 47 | device keys) unless it can find the existing E2EE state, which should already |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 48 | be initialized. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 49 | - This prevents problems where a bot will try to re-create a device after it |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 50 | lost its state, and the new device/login is not verified and thus not |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 51 | trusted in E2EE rooms, which is hard to debug. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 52 | - Instead, the bot will refuse to run at all, preventing it digging itself a |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 53 | deeper ditch, letting the operator be notified something is wrong, and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 54 | either restore the state, or recover it. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 55 | - During the setup phase, while the operator is actively interacting with the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 56 | bot to set it up, an E2EE recovery phrase / password / blob could be printed |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 57 | to the terminal for safekeeping, to be used in case the original E2EE data |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 58 | ever becomes lost. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 59 | - This would be done during setup instead of a run phase to make: a. make sure |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 60 | the operator sees it, and b. if the operator forgets to point the bot's |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 61 | state directories to a persistent file system, it has already taken note of |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 62 | the recovery information separately, and so the problem with a lost E2EE |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 63 | state can be resolved as long as they still have access to that information. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 64 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 65 | ## Extra notes |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 66 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 67 | This pattern would work well in a docker environment, as a bot developer could |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 68 | recommend the following; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 69 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 70 | They can recommend a `docker-compose.yml` file to be used for keeping track of a |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 71 | container lifecycle, and recommend the `docker-compose run bot setup` command |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 72 | before `docker-compose up -d`, to give bot operators an easy time setting it up, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 73 | despite matrix's unconventional stateful nature (compared to other bot |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 74 | ecosystems). |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 75 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 76 | ## What this means for `matrix_sdk` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 77 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 78 | `matrix_sdk` could help this pattern by building in either a "create" or "open" |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 79 | intent for state, where it'll error if it can't do either. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 80 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 81 | Currently I don't see this in `make_store_config`, where it seems to implicitly |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 82 | choose either one, but if it's made more explicit to _either_ open the state |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 83 | database, _or_ create it, it would help guide developers a lot to this pattern, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 84 | which in turn could guide bot operators to follow this pattern as well. |