Lost threads
The lost-thread detector finds outbound emails you sent that never got replied to. It surfaces them so you can chase, drop, or draft a follow-up.
The premise
You sent an email. You waited. They didn't respond. Now you've forgotten and the deal is rotting.
Laurelin scans your outbound mail (the same Outlook sync that creates interactions) and flags threads where:
- The most recent message is outbound (sent by you, or by another Valinor team member),
- The recipient(s) are external,
- The thread has gone stale (no inbound response within the threshold for its urgency tier),
- And it's not a one-shot newsletter or a routine acknowledgment.
These flagged threads become lost-thread candidates — rows in the lost_thread_candidates table — and surface in the Laurelin UI for your review.
Two urgency tiers
normal— outbound sent N+ days ago with no reply. The typical case.emergency— same shape, but the detector noticed signals suggesting it shouldn't have gone unanswered (a deal-stage company, a project with an upcoming key date, a high-importance recipient). These surface separately and louder.
The classifier is deterministic. There's no AI deciding urgency; it's rules based on the company/project context attached to the recipients.
What you see
Each candidate shows you:
- The original message (subject, snippet, date, recipients).
- How long it's been stale (
days_stale). - The detected urgency tier and why (
urgency_reason— e.g., "high importance company inactivestage", "key date 5 days away"). - A suggested next action: chase, drop, log a reply if you replied off-platform.
What you can do with a candidate
Four options per item:
1. Resolve
Mark the thread closed. Use when:
- They actually replied (the detector missed an inbound message, rare but happens with forwarded threads).
- You replied off-platform (a phone call, a Telegram message, an in-person chat).
- The thread is genuinely closed without a reply — they're not going to respond and you're at peace with that.
When you resolve, you can optionally link the resolution to an interaction (the call you had instead, the in-person meeting).
2. Dismiss — once
"Don't show this again for this specific message." If the next outbound on the same thread also gets ignored, that becomes a new candidate.
3. Dismiss — forever
"Don't show this thread again, ever." Use when you've decided not to follow up. The thread can still surface for new outbound messages, but this specific stale state is hidden permanently.
4. Draft a reply
Click "Draft" and Laurelin asks Claude to generate a follow-up draft based on the thread context, your usual voice (set in your profile), and a chosen intent (chase / friendly check-in / specific ask). It puts the draft in the candidate row (draft_body) for you to copy into Outlook.
Two important guardrails:
- Drafts are not sent. Laurelin never sends mail. You copy into Outlook and send it yourself.
- Drafts are gated. You explicitly request a draft per candidate. Nothing auto-drafts on detection.
State of the draft flow is recorded on the candidate row: draft_requested_at, draft_intent, draft_voice, draft_started_at, draft_completed_at, draft_body, draft_body_preview. So you can see whether one is in flight.
How candidates are tied to people and companies
Each candidate is also linked to the people and companies involved via lost_thread_candidate_people and lost_thread_candidate_companies. That's how the company-detail and person-detail views surface the candidate ("3 stale threads with this contact") without you having to go hunting in a global list.
Dedup
The detector uses a content_hash on each candidate to avoid re-flagging the same thread on every scan. If you dismiss-forever and the underlying message gets re-summarized (rare but possible if the parser updates), it won't re-surface.
Daily flow
The pragmatic way to use it:
- Once a day or so, open the Lost Threads view.
- Skim emergencies first. There usually aren't many. Resolve / draft / dismiss.
- Skim normals. The good ones to chase are the ones where you go "oh, right, I meant to follow up."
- Anything older than a couple of weeks that you're never going to chase — dismiss-forever in bulk. The list shouldn't carry permanent debt.
If you're spending more than 5 minutes a day in here, the urgency thresholds need tuning. Flag in #laurelin.
What it doesn't do
- Doesn't chase inbound that you've ignored. This is about your outbound going dark, not your inbox piling up.
- Doesn't track non-email channels. Slack DMs and Telegram chats aren't covered by this detector (they're noisier and the assumption of "should have replied within X days" doesn't hold).
- Doesn't surface meeting messages. Calendar invites, updates, cancellations, and RSVPs are excluded — they're not threads that need a reply. The meeting itself is tracked separately on the calendar interaction. New-domain meeting invites still go through Intake so you can attach a company/contact.
- Doesn't send anything on your behalf. Drafts are drafts.
Engineering note
If you want the deeper view of how the detector works — what counts as outbound, the content-hash algorithm, urgency rules, draft state machine — see Sync internals → Lost-thread detector.