← All posts

Plainva 0.6.3: a reminder that only fires while the window is open is not a reminder

August 11, 2026

Plainva has had a calendar since 0.4.0 and mail since the same release. Both could show you things. Neither could do the one thing you actually want from them when you close the laptop lid: tell you about something later.

That is the thread through this release. Not “add reminders” — the interesting part is where a reminder has to live for it to work at all.

A reminder is not a feature of a window

If Plainva schedules a notification inside itself, then Plainva has to be running when the moment comes. Close the window and the reminder is gone, and nothing tells you. So reminders are handed to the operating system’s own notification centre, which is awake when your app is not.

On the desktop that still leaves a gap: the app has to have run at least once to hand anything over, and a machine that was off all morning has nothing queued. So Plainva can optionally keep running in the background — autostart and a tray icon, both off by default, offered at the moment you switch reminders on rather than buried in a settings page. And the setting says plainly what it means: with it off, a reminder can only reach you while the window is open.

There is a limit underneath, and it is stated rather than hidden. Both operating systems cap how many notifications an app may have pending. Plainva schedules up to that cap and then tells you from which date on it can no longer promise one. Swallowing the rest quietly was the one answer that was not available.

A rule belongs where it takes effect

The same question, one layer up. A mail rule that runs inside Plainva only files your mail while Plainva is open, on the machine it is open on. That is not what anyone means by “move newsletters to a folder”.

So a rule is translated into whatever your provider actually speaks: Sieve where the server offers ManageSieve, Microsoft’s own message rules over Graph, and — where there is nothing — executed locally and labelled as local, so you can tell the two apart.

That decision costs something, and it is worth naming: the rule model is the smallest common denominator of those servers rather than everything Plainva could express. A condition Sieve cannot represent is a condition that would work on your desk and nowhere else.

One more thing about Sieve. Your script may already contain rules you wrote by hand or another client wrote for you. Plainva owns a section of that file, marked as its own, and never the file. A script it cannot parse with confidence is reported, not overwritten.

Nothing to measure is not zero

The second strand: databases learned to plan a project.

A rollup column computes a value from the notes on the other side of a relation — how many tasks are open, what they add up to, the share that is done, the earliest date. It is computed on read and stored nowhere, and it refuses to be edited, because there is nothing behind the cell to write to.

Building it turned up a rule that then came back three more times. What should a sum of nothing show? Zero is the obvious answer and the wrong one: a zero beside a planned effort reads as a measurement — we measured, and it was nothing. A dash says the truth: there was nothing here to measure. The same question appeared under the column footer, in the actual-time column of a vault with no calendar account, and on a project with no tasks yet. Same answer each time.

Alongside it: milestones (a dated entry with no end, drawn as a diamond), dependencies in the format an Obsidian plugin already writes, effort in minutes, and actual time read from the calendar entries a task blocked rather than stored as a number — so it stays true when you drag the appointment to another afternoon.

Dependencies report a scheduling conflict; they never fix one. If a task starts before the one it waits on has finished, the arrow turns red and stays red. Moving your plan around behind your back is not a favour.

A password with six names

The third strand started with an error message that was right.

“missing mail credentials” for a Gmail account whose calendar and files were working perfectly. Not data loss — a missing surface. Mail runs on IMAP with an app password, which is a different secret from the OAuth tokens sitting beside it, and the place to enter it existed only on the phone.

Chasing that turned up something larger. The identifier under which a password was stored in the shared document came from the local account id — the one each device makes up for itself. Measured on a real vault: six entries for one password, identical in every way that matters, written by three devices, five of them tombstones. Every device was reading the other devices’ names as accounts that had vanished.

The identifier now comes from what the credential is: service, type, user, endpoint. The migration everyone dreads mostly did not happen, because the import always resolved by that binding anyway.

And the keychain is no longer write-only. There is a surface that lists what Plainva stores for a vault; “forget vault” takes the account, calendar, mail and master-key slots with it; and the entries carry readable names — plainva · wiki · Mail · fcb8f9ff instead of a wall of Base64. That rename is deliberately timid: write the new name, read it back, and only then delete the old one. A keychain write can fail quietly, and deleting first turns that into a lost password.

Two small things that were mine

A WebDAV server on a custom port was refused, with a message about a permission scope. The scope was set to http://**, which reads like “any http URL” and is not: the pattern fills in placeholders for the path, the query and the fragment — but not for the port. An empty port component matches the default port and nothing else. Every self-hosted server on :8080 or :8082 bounced.

And an error message that said “Reason:” and then nothing. Not truncated — empty. Errors that come across from the system layer are plain strings, and the code asked them for a .message they do not have; an undefined value renders as nothing at all. So the one message whose entire job was to name a cause said nothing. What gave it away was the line two statements above it, which wrote the same error to the diagnostics log correctly.

Also in this release

Windows installers are code-signed for the first time. A blank window now says what is missing instead of staying blank. And the supported floor is written down: macOS 12 or newer with Safari kept current — the requirement that actually decides is Safari 16.4, because on macOS the engine inside an app arrives with Safari rather than with the system. No macOS version can promise it, which is why the check that decides is a probe inside the app rather than a version number.

Download Plainva 0.6.3