| name | inbox-info |
| description | Research and answer questions about email in the user's Maildir via mu
(maildir-utils). Use proactively when: (1) user asks about emails, inbox,
flagged messages, senders, subjects, or specific correspondence,
(2) user asks "what do I need to handle / respond to?" — flagged emails
are the user's marker for actionable items, (3) user mentions mu, mutt,
neomutt, or Maildir, (4) user wants to convert email-derived work into
nytid todos. Strictly read-only; never modifies mail state.
|
Inbox Information Research
Overview
The user reads email with NeoMutt against a Maildir indexed by mu
(maildir-utils). This skill wraps mu find / mu view to answer questions
about the inbox without scanning Maildir files directly. It also helps
convert flagged emails into themed nytid todo items.
Canonical "needs handling" signal: the user flags every email they
need to act on (the \Flagged / "starred" IMAP flag). Default to
flag:flagged for triage queries — not flag:unread.
This skill is strictly read-only: query mu, suggest nytid todo
commands, and let NeoMutt own flag/state changes.
Known Setup
Embedded so the skill activates with zero tool calls. Re-verify with
mu info only if a query misbehaves.
- Maildir+ account root (use with
mu — it indexes the whole tree):
/home/dbosk/mail/kth
- Key leaf folders — encode the lifecycle of a message, not just
routing:
INBOX/ — waiting / not yet processed. Unread mail lives here
by definition; flagged mail here is active work. For triage,
this is the folder to target.
Processed/ — done. Messages the user has handled and moved
out of INBOX. The user intentionally keeps flags here — a flag
in Processed means "I had to act on this", retained as a labeled
signal for tuning ~/.muttrc.scores and spotting patterns. Do
not treat them as actionable triage items, but do not ignore
them as noise either — they're training data.
Processed-archived/ — archived, not interesting. Older
Processed mail. Even less relevant than Processed/ for triage.
- Xapian DB:
/home/dbosk/.cache/mu/xapian
- Verified: 2026-05-27
The account root contains subfolders (INBOX/, Sent/, Archive/,
Processed/, Processed-archived/, etc.) but no cur/new/tmp of its
own. Pointing neomutt -f at the root opens the folder browser, not
messages — limits then filter an empty set. Always target a specific
leaf for mutt.
Implication for triage queries: unread mail = "waiting to be
processed" (the user moves mail to Processed/ when done; unread mail
still in INBOX is therefore by-definition actionable). Old unread mail
in INBOX is stale — never got around to it. Flagged mail in
Processed/ is not a triage target — it's done — but it is a
historical record of "things that needed action", deliberately
retained for score-tuning. Use the user's flag-discipline to your
advantage:
- Flag-cleared anywhere = "I didn't have to act on this" (FYI/noise).
- Flagged in INBOX = "this needs action, still pending".
- Flagged in Processed/ = "this needed action and is now done"
(labeled training point).
Lazy fallback — call mu info only if:
- a query returns unexpectedly zero results,
- the user reports the index seems stale,
- or
mu find errors out.
Research Workflow
Step 1: Pick the right query
| Question | Query |
|---|
| "What needs handling?" | mu find 'flag:flagged' --fields 'd f s' --sortfield date --reverse |
| "What's been flagged forever?" | mu find 'flag:flagged AND date:..1m' --fields 'd f s' --sortfield date |
| "Recent from X?" | mu find 'from:NAME date:1m..' --fields 'd f s' --maxnum 20 |
| "Anything on topic Y?" | mu find 'subject:Y OR body:Y' --threads --fields 'd f s' |
| "How many of Z?" | mu find QUERY --fields i | wc -l |
| "Show me message N" | mu view <path> (path from --fields l) |
Bound output: always use --maxnum N and --fields to keep results compact.
Step 2: Classify against the user's taxonomy
The authoritative classifier lives in ~/.muttrc.scores. For the full
extracted taxonomy — every category regex, every high-signal sender,
every noise filter — see
references/muttrc-scores-taxonomy.md. Read it when classification is
non-trivial or when the user updates their scoring config.
The common categories (priority order) are:
| Category | Subject regex | Notes |
|---|
| Missing grades / Ladok | ladok|betyg|tillgodoräk | First-class — always its own bucket |
| Urgent | brådska|bråttom|urgent|viktig|important | |
| TA management | assning|asse|assistent|\bTA\b | |
| Course operations | kompletter|examin|rättning|redovis|labb?|rapport|rest(er|labb|uppgift|inlämn) | grading, make-ups, lab reports |
| Course analysis / PM | (kurs)?.?(analys|PM|pm|utvärdering) | |
| Timesheets / pay | tidrapport|timersättning|timesheet|lön|timmar|arvode | |
| Sick / personal | sjuk|sick|\bill\b | |
| Reviewing | reviewer.*invitation|invitation.*reviewer | |
| Scheduling | from schema@admin.kth.se or @timeedit.com | |
Course codes to recognize:
- DD1301 (
datorintro/dataintro)
- DD131[057] (
programmering/prg)
- DD1320 (
tilda)
- DD1337 (
inda)
- DD2520 (
tilkry/tillkry)
- DA2215, DD2302 (
vetcyb, science/security)
- DA150X (
dkex/dkand/kex, bachelor thesis)
- DA231X (
exjobb, master thesis)
- LH219V (pedagogy)
Programme tags to recognize: CINEK|CMAST|CITEH|CDATE|CFATE|CTMAT|CTFYS|CLGYM.
High-signal senders (from ~/.muttrc.scores): Celina Soori, Yara Faris,
Yasmina Altayy, Liisa Wettemark, Edita Korlat, Francisco Gomes, Bedour
Alshaigy, plus institutional addresses (schema@admin.kth.se,
service@eecs.kth.se, education-support@eecs.kth.se, etc.). When a
flagged email is from one of these, give it its own cluster.
Known noise (excluded from triage even if flagged): Google Scholar,
KTH Magazine, IEEE, ACM, SIAM, Nature Briefing, The Download, KTH Alumni,
etc. — see negative scores in ~/.muttrc.scores.
Step 3: Handle ambiguous subjects (students often write bad ones)
Many emails arrive with vague subjects: "Hi", "Hej", "Question", "Help",
"Course", a bare first name, or just a course code. Don't trust subject
regex alone. Two-tier approach:
- Subject regex first (cheap) — sort flagged emails into the
obvious buckets.
- Body query for ambiguous matches:
mu find 'flag:flagged AND body:/ladok|betyg/' --fields 'd f s'
catches grade-adjacent emails whose subjects don't mention grades.
- Read the full message with
mu view <path> only for the
borderline cases — never as a default step.
- If still unclassified, put it in a residual "uncategorized flagged"
group rather than forcing a wrong bucket.
Step 4: Group flagged emails into themed todos
When the user asks for todos from flagged email, propose themed batches
— never one todo per message. Cluster by category, course code, sender, or
topic, then suggest one nytid todo add per group.
For the full rules with rationale and worked examples, see
references/todo-conversion-rules.md. Headlines:
- NEVER use
--who dan-claude. Email-derived todos are for the user
themselves. dan-claude doesn't answer the user's email. Omit --who
entirely so the default (current user) applies.
- Missing grades is always its own group, separate from other course
traffic, even when only 1–2 messages match.
- Every todo description must embed a review command so the user can
re-open the relevant emails with one paste.
Step 5: Choose the right review-command form
Two forms. Default to Form A unless you specifically need mu's richer
query language for read-only browsing.
Form A — mutt limit on the real Maildir (DEFAULT). State changes
(mark read, reply, unflag) persist to the real inbox:
neomutt -f /home/dbosk/mail/kth/INBOX \
-e 'push "<limit>~F ~s \"betyg\\|ladok\\|grade\"<enter>"'
Note INBOX, not the account root — see "Known Setup" above.
Mutt patterns: ~F flagged, ~s "regex" subject, ~b "regex" body,
~f "regex" from, !~s "regex" negation. Combine with space (AND) or | (OR
within a single regex). Date filters: ~d "<3m" newer than 3 months ago
(within last 3 months), ~d ">3m" older than 3 months ago. Offsets: d day,
w week, m month, y year. Absolute range: ~d "01/27/26-02/27/26" (US
MM/DD/YY). When embedding in a shell string, escape inner double quotes:
~d \"<3m\".
Form B — mu virtual maildir, READ-ONLY browsing only. Use when a
query can't be expressed as mutt patterns (cross-folder, mu's richer
operators):
mu find 'flag:flagged AND (subject:/grade|betyg|ladok/ OR body:/ladok|betyg/)' \
--format links --linksdir ~/.cache/mu-results/missing-grades --clearlinks \
&& neomutt -f ~/.cache/mu-results/missing-grades
Form B caveat — symlinks don't propagate state. Marking a message
as read in the linksdir renames the symlink, not the underlying file.
State changes do NOT reach the real inbox. Pick Form A whenever the
user will mutate state.
Use a per-group slug under ~/.cache/mu-results/<slug>/ for Form B
so concurrent uses don't collide.
Step 6: Suggest the todo (don't run it)
Print the command for the user to run. Prefer --command (-c) over
--description for the review command — that way nytid todo start <id>
runs it directly, no copy-paste. Put context/rationale in --description
for view, put the executable command in -c.
nytid todo add MAIL \
-t "Resolve missing grades — 5 student emails" \
--description "5 flagged emails about missing grades (Ladok/betyg)." \
-c "neomutt -f /home/dbosk/mail/kth/INBOX -e 'push \"<limit>~F ~s \\\"betyg|ladok|grade\\\"<enter>\"'"
Escape ladder (bash → nytid storage → shell on start → mutt -e
parser → mutt push string). Inside a bash double-quoted argument, use
\\\" for every literal " that mutt's push-string parser must see — \\
becomes \ and \" becomes ", yielding the stored \" that mutt
unescapes back to ". When you splice variables into the template, make
sure they're bare (no quotes baked in) and let the template add the
\\\" around them.
For adding email context to an existing todo, suggest:
nytid todo note <ID> -m "Saw a follow-up email from <sender> on <date>".
See the nytid-todo skill for broader todo-workflow details, including
auto-parenting behavior (a new nytid todo add without --top-level
parents under the currently active todo — handy when the user has an
"Clear inbox" todo in-progress and wants each bucket as a child).
Quick Reference
| Operator | Meaning |
|---|
from:NAME | sender match |
to:NAME | recipient match |
subject:TEXT | subject contains |
body:TEXT | body contains |
flag:flagged | starred / actionable |
flag:unread | unread |
date:1w.. | last week to now |
date:..1m | older than 1 month |
date:20260101..20260131 | absolute range |
mime:TYPE | attachment mime type |
AND / OR / NOT | boolean combiners |
--fields letters: d date, f from, t to, s subject, l path,
i message-id, g flags.
Output Handling
- Default fields:
d f s. Add l only when feeding mu view.
- For large result sets, summarize aggregates ("12 flagged from this
month, mostly course ops") instead of dumping the full list.
- Use
--threads for topic/thread questions.
- Output is tab-delimited by default; pipe through
column -t -s$'\t' for readability when showing to the user.
Scope
Strictly read-only. Never run mu index, mu remove, mu mkdir, or
anything that writes to the Maildir or Xapian DB. Never compose, send, or
modify mail state — defer to NeoMutt. Never create nytid todo items
directly; only suggest commands. Don't print email bodies unless the
user asks.
Common Pitfalls
Stale index. Results miss new mail until mu index runs. If the
user reports missing emails, run mu info to check the last index time
and suggest they reindex.
Shell quoting. Always single-quote mu queries: 'flag:flagged',
'from:foo AND date:1w..'.
mu regex /.../ is fragile. Spaces and parentheses inside the slashes
silently match zero results — e.g. subject:/applied crypto/ and
subject:/(foo|bar)/ both return nothing instead of erroring. For
multi-word terms or grouped alternations, use boolean OR of word terms:
(subject:applied OR subject:crypto), (subject:foo OR subject:bar).
Single-word alternations like subject:/foo|bar|baz/ do work. When a
count looks suspiciously low, sanity-check by running each clause
separately with --fields i | wc -l.
Folder lifecycle is asymmetric — flag in Processed/ ≠ actionable.
Tempting reflex: query flag:flagged everywhere and assume each hit
is a triage target. Wrong here. Flags in Processed/ and
Processed-archived/ are intentional — the user keeps them as a
labeled "had-to-act" signal for tuning ~/.muttrc.scores. They are
not noise to ignore, but they are not work-to-do either. The only
triage-relevant folder is INBOX/. Always constrain mu queries
with maildir:/INBOX when building todos for "what needs handling":
mu find 'flag:unread AND maildir:/INBOX AND date:3m.. AND <category>'
If a folder-distribution check is ever needed (e.g. to confirm a
category really is empty in INBOX vs. just sitting in Processed):
mu find '<query>' --fields l --maxnum 500 \
| sed 's|^/home/dbosk/mail/kth/||; s|/cur/.*||; s|/new/.*||' \
| sort | uniq -c | sort -rn
A bucket with zero unread/flagged in INBOX is correctly empty — the
user has already processed it (the data is in Processed/, which is
done). Don't try to "rescue" Processed mail into a triage view.
Filter choice cheat-sheet (all assume maildir:/INBOX):
| Goal | Filter | Notes |
|---|
| Waiting to be processed | ~U | Canonical signal; INBOX-resident |
| Manually-marked important & waiting | ~F | Subset of unread+read in INBOX |
| Most-pressing | ~U ~F | Important AND not yet opened |
| Stale to-do (never finished) | ~U ~d ">3m" or ~F ~d ">3m" | Months in INBOX = forgotten |
Score-tuning queries (use Processed flagged mail)
If the user asks "which senders/subjects keep needing action?" or
wants to improve ~/.muttrc.scores, that's exactly what flagged
mail in Processed/ is for — it's the user's hand-labeled corpus
of "things that turned out to need action". Useful queries:
# Top senders of acted-on mail in the last year
mu find 'flag:flagged AND maildir:/Processed AND date:1y..' --fields f \
| sort | uniq -c | sort -rn | head -20
# Common subject tokens in acted-on mail
mu find 'flag:flagged AND maildir:/Processed AND date:6m..' --fields s \
| tr ' ' '\n' | sort | uniq -c | sort -rn | head -30
Compare against ~/.muttrc.scores to find under-scored senders/terms.
Form B is read-only. Symlink renames stay in the linksdir; the real
inbox is untouched. Use Form A whenever state must persist.
Trusting subjects. Student emails frequently have unhelpful subjects.
Use body queries or mu view for ambiguous cases.
Wrong todo ownership. Never assign email-derived todos to
dan-claude. They belong to the user.