aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-20 17:23:44 +0200
committerDanilo M. <danix@danix.xyz>2026-08-20 17:23:44 +0200
commitc06809634534ed3b6eb81a1648119428567e71a4 (patch)
treeef457fc107fed2b013d8b78c5319f6e0d10893fd /docs/superpowers/plans
parentaf902e0b2268085ff2ff4c21a4430ec4a94164bd (diff)
parentfd42550c8f51c52cb7eca86b2557e82bc173dd04 (diff)
downloadqtmaildir-c06809634534ed3b6eb81a1648119428567e71a4.tar.gz
qtmaildir-c06809634534ed3b6eb81a1648119428567e71a4.zip
merge: the item 123 compose-and-send design into master
The seven brainstorm commits are documentation of decisions already taken: the spec at docs/superpowers/specs/2026-08-20-compose-and-send-design.md, the rewritten item 123 pointing at it, and the seven backlog items the brainstorm opened (128 to 134). No implementation of 123 exists yet, so nothing premature reaches master. They are merged now because item 134 shipped to master as af902e0 while the row defining it sat on the branch, which left master carrying code for an item its own backlog had no record of. Item 132 is the same shape and is next.
Diffstat (limited to 'docs/superpowers/plans')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md97
1 files changed, 41 insertions, 56 deletions
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
index 49f4000..3d5bcc3 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
@@ -189,7 +189,7 @@ taking that too literally.
| 121 | The thread list shows nothing while a query is running | feedback | S | open, 2026-08-20, from the notes. Follows item 74, which fixed the status-bar half and left the list itself blank |
| 122 | The README documents a version of the app that no longer exists | documentation | M | open, 2026-08-20, from the notes. Delete-to-trash is entirely undocumented, including a config key a user must now set |
-| 123 | Sending mail is not designed | v2 | ? | open, 2026-08-20, from the notes. Brainstorm only, explicitly `#plan-only`; the user places most open UX behind it |
+| 123 | Sending mail is not designed | v2 | L | **specified** 2026-08-20, on branch `compose-and-send`. Design in `docs/superpowers/specs/2026-08-20-compose-and-send-design.md`; read that, not this row. Send is a per-account `send_command` on stdin, so the no-network-protocol rule stands. Composer is a separate window, body is markdown via cmark-gfm, drafts autosave to the account's drafts folder. No code written |
| 124 | The worker reads the index directory as the mail root | defect | S | **done** 2026-08-20, unreleased. `mailRootOf()` over `NOTMUCH_CONFIG_MAIL_ROOT`, correct under both layouts. Verified by migrating the developer's own index to NVMe the same day: cold start 38.6 s to 0.67 s |
@@ -197,6 +197,13 @@ taking that too literally.
| 126 | A link with `target="_blank"` does nothing when clicked | defect | S | **done** 2026-08-20, unreleased. `createWindow()` returns a relay page that receives the navigation, hands the URL to the browser and refuses. The URL cannot be read in `createWindow()` itself, which is why a relay rather than a lookup |
| 127 | A link's context menu offers four browser actions that cannot work | defect | XS | **done** 2026-08-20, unreleased. Three Open-in actions removed, `CopyLinkToClipboard` kept. Item 126 made them more dangerous rather than less: with a real `createWindow()` they would have started working |
+| 128 | No outbox: a send with no network fails instead of queueing | v2 | M | open, 2026-08-20, from the item 123 brainstorm. **Blocked on 123.** The seam is designed in (`MessageSender` is the one funnel), so this wraps it rather than reworking it. Needs its own indicator story first: items 18, 19, 28 and 54 are all an indicator lying, and 125 is one still open |
+| 129 | No inline images in a composed message | v2 | M | open, 2026-08-20, from the item 123 brainstorm. **Blocked on 123.** Wanted by the user. `cid:` from the HTML part with `multipart/related` nested inside the alternative, the most nesting-heavy part of MIME assembly, and markdown offers no syntax for it |
+| 130 | A message cannot be attached to another message directly | v2 | S | open, 2026-08-20, from the item 123 brainstorm. **Blocked on 123.** A `message/rfc822` part, which GMime builds natively. The manual route exists from 123's first commit: `save_message` writes the `.eml` and it is attached as a file |
+| 131 | The markdown dialect and extensions are fixed | v2 | S | open, 2026-08-20, from the item 123 brainstorm. **Blocked on 123.** Configurable in the shape Hugo's config uses. Deliberately fixed initially: CommonMark plus autolink, strikethrough and tasklist |
+| 132 | Every action must have a shortcut, and that no longer serves | policy | S | open, 2026-08-20, raised by the user during the item 123 brainstorm. `everyActionHasAShortcut` was written when the action list was short; item 123 adds six more, and each new action consumes a chord whether or not anyone would press it. Replacement is the shape `everyActionIsReachableFromAMenu()` already has: menu reachability required, shortcuts a chosen subset. **Not** done inside 123, which would confuse two changes |
+| 133 | The composer shows no markdown syntax highlighting | v2 | S | open, 2026-08-20, from the item 123 brainstorm. **Blocked on 123.** A `QSyntaxHighlighter` over the composer's editor, so `**bold**` reads as bold while the buffer stays plain markdown. Standard Qt, no dependency. Deliberately after 123's formatting toolbar: agreeing with the grammar about nesting and about code spans suppressing what is inside them is the expensive part, and the toolbar is what makes the feature usable |
+| 134 | The busy indicator is built inline and is about to be built twice | maintenance | S | open, 2026-08-20, raised by the user during the item 123 brainstorm. An indeterminate `QProgressBar` beside a status label, built inline in `MainWindow` as `m_syncProgress`, and item 123's composer needs the same pairing. Extract a widget class and convert `MainWindow` to it. It must expose BOTH modes, not just the indeterminate one `MainWindow` happens to need: item 123's send popup drains a determinate bar during its undo countdown and switches the same widget to indeterminate when the command starts. **Not blocked on 123**, and better done first: if 123 lands first it creates the class itself and this row closes with it. The user's position is general, build once and reuse, so the inline habit `CLAUDE.md` records is a description of the code rather than a rule to follow |
Sizes are rough: XS under an hour, S a sitting, M a session.
@@ -998,61 +1005,39 @@ likely to have drifted, since both enumerate things that have been added to.
## 123. Sending mail is not designed
-**Observed (user, from the notes):** "we should start brainstorming sending
-emails. Most of the open issues are UX. #v2 #plan-only #new-branch".
-
-**Not a defect and not implementation work.** The note tags it `#plan-only`, and
-this repo's own scope statement agrees: `CLAUDE.md` records that v1 is
-read-and-organize only and that compose and send are v2. Recorded here so the
-backlog stops being silent about the largest thing the user has written down.
-
-**What it blocks.** Item 72 (khard/khal) is explicitly placed after send by the
-user's own note, and cannot be specified before it. The completion machinery
-that would serve recipient completion already exists as `QueryCompleter`, and
-the `QLineEdit::setCompleter` trap in `CLAUDE.md` applies directly to any
-multi-recipient field, so there is prior art to reuse rather than a blank page.
-
-**What it does NOT change.** The architecture note that this application does
-**no network protocol work at all** is load-bearing: fetching is `mbsync` via
-`assets/mailsync.sh`, and sending should be an external script on the same
-model, not an SMTP client written here. A design that puts a socket in this
-process is out of scope regardless of how the UI turns out.
-
-**What exists on this machine, measured 2026-08-20, because the sentence above
-assumes something that is not there.** "Sending should be an external script on
-the same model" is easy to write and there is no such model to copy: the fetch
-side has `mbsync`, and the send side has NOTHING.
-
-- No MTA is installed at all. `msmtp` and `sendmail` are both absent.
-- neomutt sends over its OWN built-in SMTP, configured per account
- (`smtp_url` and `smtp_pass` in `~/.config/neomutt/accounts/*.rc`), so the
- working setup this application mirrors has no external send path either.
-- All five accounts already configure a `drafts` folder, so the draft half has
- somewhere to live before anything is decided.
-
-That is the first question for the user, and it is not a UX one: sending needs
-either an MTA they choose to install and configure (msmtp being the obvious
-one, and the only shape that keeps the no-network-protocol rule intact), or a
-decision to relax that rule. Do not assume the first just because it is
-tidier; installing and configuring an MTA is work they have not asked for, and
-the credentials already exist in neomutt's files.
-
-**Approach.** Brainstorm first, on its own branch, producing a spec under
-`docs/superpowers/specs/` before any code. The open questions are all UX, as the
-note says: where a composer lives, how a draft is stored so `notmuch` can see
-it, what reply and forward do to the thread the user is looking at, and how a
-queued message reaches the sending script.
-
-**Constraints.**
-
-- **Ask the user before designing.** They have not said what they pictured, and
- this is the item where guessing costs the most.
-- Drafts are already visible to the app: item 67 counts them in the placeholder
- pane, so a draft folder is configured and indexed.
-- `#new-branch` is the user's own tag on it.
-
-**Size: `?`** until the brainstorm has happened. It is the largest open item by
-some distance.
+**Specified 2026-08-20.** Read
+`docs/superpowers/specs/2026-08-20-compose-and-send-design.md` instead of this
+section. Brainstormed with the user on branch `compose-and-send`; no code
+written, which is what the note's `#plan-only` asked for.
+
+**The three constraints a reader needs before opening the spec.**
+
+- **There is no MTA on this machine**, measured 2026-08-20. `msmtp` and
+ `sendmail` are both absent, and neomutt sends over its own built-in SMTP. So
+ "an external script on the same model as `mailsync.sh`" had no model to copy.
+ The design keeps the no-network-protocol rule by making send a **per-account
+ `send_command`** taking the message on stdin, exactly as `[sync] command`
+ works. What the user installs behind it is their choice.
+- **An account with no `send_command` is receive-only by construction**, which
+ is how one of the five accounts is meant to work. Reply, reply-all and forward
+ are disabled on its mail, with a ribbon in the message pane saying why.
+- **The body is markdown**, parsed by cmark-gfm (autolink, strikethrough,
+ tasklist; tables off), sent as `multipart/alternative` or plain text per a
+ per-message toggle. A hand-written parser for a limited set was rejected
+ because it would be deleted wholesale the moment the set widened.
+
+**What it blocks and what it opened.** Item 72 (khard/khal) is placed after send
+by the user's own note. The brainstorm opened items 128 to 132: an outbox,
+inline images, attaching a message to a message, a configurable markdown
+dialect, and a review of the every-action-has-a-shortcut rule.
+
+**Size: L.** Four new units, six new actions, a formatting toolbar over the
+markdown source (whose shortcuts live in the composer's own scope and do not
+touch `KeyMap`), and one new build dependency,
+`cmark-gfm`. That dependency is cheap: it ships in stock Slackware
+(`cmark-gfm-0.29.0.gfm.13-x86_64-3`, verified 2026-08-20), so it needs a
+`pkg_check_modules` line here and **no** `REQUIRES` entry in the SlackBuild,
+which lists only non-stock dependencies.
## 125. A skipped sync leaves the spinner running for ever