# Compose and Send Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add the write half of qtmaildir: compose, reply, forward and send, with markdown bodies, autosaved drafts and a cancellable send delay, without the application ever speaking a network protocol. **Architecture:** Four new units. `MessageBuilder` turns an `OutgoingMessage` into RFC822 bytes using GMime and cmark-gfm. `DraftStore` writes those bytes into a Maildir folder. `MessageSender` pipes them to a per-account `send_command` over stdin. `ComposeWindow` is the only one that owns widgets, and composes the other three. Three of the four are tested without a painter. **Tech Stack:** Qt 6.11 (Widgets, Test), GMime 3.0 (already linked), cmark-gfm 0.29 (new, stock Slackware), notmuch (read-only, unchanged), CMake + Ninja, QTest. **Implementation branch:** `compose-and-send`, currently identical to `master`. This plan lives on `master` so it is readable from either. --- ## Before starting Read these, in this order. They are not optional context; each one records a trap this plan walks past. 1. The spec: `docs/superpowers/specs/2026-08-20-compose-and-send-design.md`. 2. `CLAUDE.md`, in particular **Web view security**, **Adding an action is FIVE places**, and the gmime include-order rule. 3. `src/mailsync.cpp:172-205`, the `QProcess` precedent `MessageSender` copies. **Verified facts this plan rests on** (measured on 2026-08-20, not assumed): - `pkg-config --modversion libcmark-gfm` reports `0.29.0.gfm.13`. - **`libcmark-gfm-extensions` has NO pkg-config file.** Only `libcmark-gfm.pc` exists. The extensions library is `/usr/lib64/libcmark-gfm-extensions.so` and must be found with `find_library`, the way notmuch already is. The spec's "a `pkg_check_modules` line" covers only half of it. - With `CMARK_OPT_SAFE` and the three extensions attached, a probe confirmed: autolink wraps a bare URL, `~~x~~` becomes ``, `- [ ]` becomes ``, a table renders as literal pipes (the extension is not attached), and `\n\nafter")); QVERIFY2(!html.contains(QStringLiteral("