Files
mesh-catalog/modules/betterbird/README.md
T
jschoubben 2d2c694306
mesh/merge-gate pass: builds new: modules/betterbird, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
betterbird: know a composer by its instance alone, and bound a restart's worst case (review of #155)
A composer window whose class is not Betterbird's own was not seen, so a restart could lose its message.
Each step of a restart now has a bound short enough that all of them together, taken in full, stay
under the runtime's 30 s: 3 s for the window tree, 8 s to quit, 3 and 5 s to start, 4 s to see it.
2026-10-09 12:34:06 +02:00

123 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# betterbird
Betterbird, the mail and calendar client of g14 and shanks (a Thunderbird fork, with the operator's
Exchange calendar through the Owl add-on), as a module (novox/hq issue 345, ADR 0208). It requires
`x11-display`, so it is assigned only where a display server is held on the same machine.
It exists because a symptom had no tools: on a workstation, a calendar reminder appeared as a
transparent window with nothing in it (2026-10-09). Nothing in the mesh could say which window that
was, how the compositor treats it, or which preferences Betterbird ran with. The diagnosis is in hq
issue 345.
## Owns
| what | where |
|---|---|
| the module's directory | `~/.config/betterbird/` |
| the module's `user.js`, filled from the setting `prefs` | `~/.config/betterbird/user.js` |
Nothing else. It holds no seat and adds no start.
- **No package.** g14 and shanks both run `betterbird-bin` 153.1.0esr-1, installed explicitly from the
AUR: `pacman` counts it as foreign. The node-engine installs packages from the official
repositories only, so the module does not declare it, and **installing and upgrading Betterbird stay
the operator's** (an AUR helper). `betterbird_status` says the version and that it is from the AUR;
`betterbird_check` says when it is missing.
- **No start.** Betterbird is started by the operator from the launcher (on the workstation measured,
it runs in the login session's scope, started by hand, with no autostart entry and no line in i3's
configuration). `betterbird_restart` starts it as the transient user unit `mesh-betterbird`, so its
output then goes to the journal.
- **The profile is Betterbird's** (ADR 0182): `~/.thunderbird/` holds the mail, the address books,
the calendars' caches, the logins and the keys. The module declares none of it.
## The user.js: how a preference is declared
Betterbird reads `user.js` in its profile when it starts, and a preference set there wins over the
one it saved in `prefs.js`. The profile's directory has a random name per machine
(`<random>.default-default`), which a manifest cannot name. So:
1. the node-engine writes `~/.config/betterbird/user.js` from the module's setting `prefs`, one line of
`user_pref("name", value);` statements (default: a comment, no preference);
2. the module's tools copy that file whole into the profile: `betterbird_user_js` with `apply`, or
`betterbird_restart`, which places it before it starts Betterbird again;
3. Betterbird reads it at that start.
**The profile is found** as the one the running Betterbird holds open; with none running, as the
installation's default in `profiles.ini` (`[Install…] Default`), else the profile marked `Default=1`.
On the workstation measured these differ: `Profile1` is marked `Default=1`, and the installation's
default, the one in use, is the other.
**A user.js the module did not write is never overwritten.** The module's begins with the line
`// Betterbird's user.js (module betterbird`; any other is the operator's, and `apply` refuses with
what to do. The tools refuse a declared file that holds anything but comments and `user_pref`
statements, or that sets a preference whose name can hold a credential.
The file is **trusted** (it carries no `"trusted": false`): a preference can weaken how the mail client
checks a server, so the setting is changed only at the controller's terminal, never through a verb
(novox/hq issue 339).
## Tools
They are served by the node's runtime as the operator account (ADR 0175). **No answer carries mail, a
calendar entry, an account, an address or a credential.**
| tool | does |
|---|---|
| `betterbird_status` (r) | whether it runs (pid, since, scope, children), the package and version and that it is from the AUR, where its output goes, the profile and how it was found, the user.js (declared, placed, in effect), the add-ons the operator installed (ids), and the preferences that decide how its windows and notifications look |
| `betterbird_prefs` (r) | named preferences or prefixes (ending in `.` or `*`, at most 200; an empty name, `*` or `.` is refused): value and source (user.js, prefs.js or the default). Withheld without its value: a name that can hold a credential (`password`, `token`, `oauth`, `signon`, …); one that names an account, server, calendar, recent folder or person (`mail.server.`, `mail.identity.`, `mail.last_msg…`, `messenger.account.`, `mail.cloud_files.`, `calendar.registry.`, …); and every `extensions.*` but the theme's id (`extensions.activeThemeID`). In every value answered, the home is `~`, and a mail address, a `user%40domain@host` URI and a host name are masked |
| `betterbird_user_js` (r; a with `apply`) | the declared user.js against the profile's; `apply` places it |
| `betterbird_log` (r) | the last lines of the journal of `mesh-betterbird` (or of the reminder test), addresses and credentials masked (the value after `password=`, `token:` and the like, and the token after `Bearer`/`Basic`). A Betterbird the module did not start prints elsewhere, and the answer says where |
| `betterbird_restart` (a) | ends Betterbird (asked to quit, forced after 8 s), places the user.js where allowed, starts it as `mesh-betterbird`. **Refused while a composer window is open** (X instance `Msgcompose`, whatever its class), because the unsent message would be lost, unless `discard_unsent` is true, which only the operator's yes justifies. It answers within the runtime's 30 s: a start not yet seen after 4 s is said in `note`, and `betterbird_status` shows it |
| `betterbird_check` (r) | installed; one running; profile found; the user.js on the machine, valid, placed, in effect; its output read |
| `betterbird_reminder_test` (a) | a reminder on demand without the operator's calendar (below) |
### A reminder on demand
`betterbird_reminder_test` starts a **second** Betterbird with `--no-remote` in a throw-away profile
under `/run/user/<uid>/mesh-betterbird-reminder-test/`, as the user unit
`mesh-betterbird-reminder-test` (ended after 10 minutes at most). The profile holds the module's
user.js and one calendar: a local `.ics` file with one event, "Mesh reminder test", whose reminder is
due `after` seconds from the call (default 40). `carry` copies named preferences of the operator's
profile into it (a theme, a colour switch), under the same limits as `betterbird_prefs`. Then:
- `xorg_windows` with class `Calendar` answers the reminder window: role `AlarmWindow`, type `Dialog`,
its depth (32: a visual with alpha, which the compositor blends), its map state;
- `xorg_screenshot` with that window shows it as the screen shows it.
The unit removes its profile when it ends, however it ends (`ExecStopPost`): at its 10 minutes, on
`stop`, or when the test window is closed. The test Betterbird is never counted as the operator's: its
command line names its own profile, and `status`, `check`, `restart` and the user.js leave it out.
The running Betterbird, its profile and its calendars are not touched: `--no-remote` keeps the two
apart. **`profiles.ini` and `installs.ini` are not rewritten either**, measured on the workstation
(2026-10-09): their content and modification time (June 2023) were the same before a `--profile` start,
while it ran, and after it ended.
## The reminder window, as measured (2026-10-09, workstation, i3 and picom with glx)
| | |
|---|---|
| X class / instance | `eu.betterbird.Betterbird` / `Calendar` |
| role, type | `AlarmWindow`, `_NET_WM_WINDOW_TYPE_DIALOG` (i3 floats it) |
| depth | 32 (ARGB visual), like every Betterbird window there |
| size | 600×300, kept in the profile's `xulstore.json` |
A window of depth 32 that its program has not drawn is transparent under a compositor, not black:
that is why the symptom looks the way it does. Why Betterbird did not draw it is hq issue 345's
question.
## What changes when it is assigned
| | g14 | shanks |
|---|---|---|
| files | `~/.config/betterbird/` and its `user.js` (no preference) | the same |
| the profile | untouched until `betterbird_user_js` with `apply` or `betterbird_restart` | the same; the profile has no user.js today, so `apply` may place one |
| Betterbird | keeps running as started | keeps running as started (since 2026-10-04, its output on the session's pipe nobody reads: `betterbird_check` names it until `betterbird_restart`) |
## Relies on
- A display server on the same machine (`x11-display`, ADR 0208 §3).
- **`xorg`** for `xorg_windows` and `xorg_screenshot`, which look at Betterbird's windows. This module
carries no window code of its own.
- `systemd-run` and `journalctl` of the account's user manager.