aboutsummaryrefslogtreecommitdiffstats
path: root/TODO.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-03 11:30:06 +0200
committerDanilo M. <danix@danix.xyz>2026-08-03 11:30:06 +0200
commit9f586a8e79c73cba5267aa1848c72123ded37f9b (patch)
tree011a0ea05a9858dd0759b9c267712fc218084b5c /TODO.md
downloadmailctl-master.tar.gz
mailctl-master.zip
Initial commit: agent-safe notmuch wrapperHEADmaster
mailctl is a deliberately narrow CLI wrapper around notmuch, built so an AI coding agent can search and organize local mail with no ability to send. There is no SMTP, reply, or compose code path in the tool. Safety model: - reads run freely, mutations are gated - tag changes are dry-run until --apply - cross-account mutations need an explicit --all-accounts - destructive tags need --apply and --confirm-destructive - bulk mutations are capped by --max-messages - every applied mutation is audited to a local log Accounts are not in the source. They load from ~/.config/mailctl/accounts.json and are validated against both the schema and the actual maildirs on disk at import time, so a typo cannot produce a query matching nothing or a draft under the wrong identity. Ships with mailsync.sh (a separate mbsync + notmuch new driver, meant for cron) and mail-organize, a Claude Code skill that makes mailctl the only sanctioned interface to the user's mail. Licensed GPLv2-only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'TODO.md')
-rw-r--r--TODO.md46
1 files changed, 46 insertions, 0 deletions
diff --git a/TODO.md b/TODO.md
new file mode 100644
index 0000000..5d59385
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,46 @@
+# TODO
+
+Open items for mailctl. The three original feature gaps (`--max-messages`,
+`senders`, `subjects`) are implemented and were removed from this list on
+2026-08-01.
+
+The list of concrete senders that warrant a `post-new` hook rule is personal
+data, so it lives in a local-only `HOOK-RULES.md` rather than in the repo. The
+method for deriving it is below.
+
+## 1. `--actor` audit tag (not urgent)
+
+Already noted in the module docstring. Distinguish agent-run from user-run
+mutations in `~/.local/state/mailctl/audit.log`. Matters for trust; has not
+slowed any session's work so far.
+
+## Method notes for writing hook rules
+
+These are the traps found while sweeping a large backlog. They cost real
+mis-tagging when skipped, so they are worth keeping even though the senders
+that produced them are not recorded here.
+
+- **Verify every predicate with `mailctl count` before acting on it.** `from:`
+ matches whole tokens, and local parts split on punctuation, so per-sender
+ probes silently undercount: one bucket of 24 messages returned 16 across ten
+ probed addresses.
+- **Scope vendor rules to local parts, not domains.** A domain that sends
+ marketing usually also sends order confirmations and password resets from
+ other local parts on the same domain. A `from:<domain>` rule sweeps those
+ into promo.
+- **Check for transactional terms before any bulk promo tag.** Marketing
+ senders hide real order, shipping, and billing mail in the same bucket. This
+ caught genuine transactional messages in five separate batches; the one batch
+ where it was skipped produced the only mis-tagging that reached the index.
+- **A sender is not always one rule.** Forum and mailing-list senders mix
+ bulletins, automated notices, and real replies to threads you posted in.
+ Split by subject, or a blanket rule buries correspondence.
+- **Subject substring tests overmatch.** A common word in a subject test can
+ pull in unrelated threads that merely discuss the topic.
+- **Dead senders need no rule.** Most backlog volume comes from senders that
+ stopped mailing years ago. A rule for a dead sender is dead code that whoever
+ edits the hook next still has to read and trust. Check last-seen dates first.
+- **Join multiple `id:` terms in Python, not the shell.** `paste -sd' or '`
+ cycles the two delimiter characters between lines and glues message-ids
+ together, failing silently with a plausible-looking match count. Always
+ assert the match count equals the number of ids.