All of this comes from #2, from @famewolf and @NotRetarded testing each piece within hours of it shipping.
Backup and restore without a browser
@famewolf, once /backup worked on Telegram: "No more having to jump from webui to webui." @NotRetarded, four hours later, asking why Discord did not have it — and then asking for the other half:
I'd love to see if it's possible to perform a /restore for Telegram by attaching that file from the backup. That will keep you out of the GUI even for restores.
Which is the case that actually counts. The day you need a restore is the day the Web UI is the thing you cannot reach.
So: /backup and /restore on Discord, and /restore on Telegram. On Telegram you drop the backup into the chat. On Discord it is /restore file:<attachment>.
Either way, the file arriving is not the decision. It reports which instance the bundle came from, when it was made and what it would overwrite, and hands back a confirm button. The press restores, once. Somebody showing somebody else a backup file must not cost them their configuration.
And a bundle is not trusted just because a person picked it. Settings go through the persistent-keys allow-list so nothing can inject arbitrary attributes; links go through the same validator the live write path uses; rejects are counted rather than swallowed, because a restore that reports success while quietly dropping entries is worse than one that fails. That logic moved out of the Web UI's import endpoint into one shared function instead of being written a second time — it is the half that carries the rules, and having it in one place means maintaining it once.
Discord keeps the real .json name. Both of them expected it would need a .txt rename or a zip, and the documented API has no extension whitelist for bot uploads. That part is not verified against the live API — I have no bot of my own, and somebody else's channel is not mine to test in. If Discord does refuse it, the answer is a zip rather than a rename: disguising a file only moves the problem to whatever has to open it later.
A restart you can ask for — that refuses when it would not come back
Restoring ends with settings that only take effect at boot, so the reply offers the restart rather than describing it. There is a /restart command too, because a restart you can only reach by restoring something first is a restart you cannot reach.
It checks the container's restart policy first. Without one, stopping would leave the container down and you without the bot you would have used to bring it back — so it stays up and tells you why. If the check itself cannot be answered, that counts as no: going down with no way back is the worse of the two mistakes.
It is our own SIGTERM, not docker restart on ourselves — that would ask the daemon to stop the very process making the request, and the answer would die mid-sentence.
Also
A restart you asked for no longer reports itself as an external stop signal. The banner used to say "Restarted after an external stop signal — e.g. a host reboot… Docksentry did not restart itself", which is true of the mechanism and backwards about what happened. A marker written just before going down keeps the next boot honest, and is ignored after an hour so an abandoned request cannot mask a genuine external restart later.