aliabadi@thepersianflaw:~/projects/DATHL Inbox$_

DATHL Inbox

Drop a link and let the machine figure out what it is and where it belongs.

Why does this exist?

Imagine this. You’re doom scrolling and you come across something interesting. For me it’s often a #3d-printing or a project I want to try. Sometimes it’s a recipe that my wife sends me on instagram that we fancy giving a go.

That isn’t where this project started though, I had setup some homelab services to help with this problem. Linkwarden and Mealie, originally Mealie was just for some of our own/family recipes that had originally been hand written in a book. Like all good projects, an inconvenience (in our case moving house) caused us to realise that we wanted a more robust way of keeping these things.

It quickly expanded into the ‘we don’t know what to have for dinner’ space but the UI was difficult and hard to use (relative to our laziness when hungry) and I had a real desire to just be able to prompt an LLM something like:

We have chicken thighs, aubergine and tomatoes that need using up. Neither of us fancy pasta. What can we make with this that won’t take longer than 20-30 minutes.

and the inevitable:

No, we don’t fancy any of that but based on our preferences what else do you suggest?

The first is pretty easy to cover off with an LLM but the second one requires some sort of reference for the types of foods we like. So I built an MCP server for Mealie.

The Architecture

Design Choices & Issues

Claude

For now, I’m using the Claude Code CLI to be the brains of the LLM part. I did this mainly because I was already paying for it and already had a config with all the MCPs that I would use configured.

I plan to replace that with a local LLM running in the #homelab at somepoint. I haven’t built any detection for usage limits, so whenever I run out of tokens the whole system breaks.

Discord

Discord has great support for bots, it’s easy for me to add in friends and family but also restrict where they can go. This gives me basically free IAM for the bots without needing an overly complex auth mechansim for them.

It essentially goes, if you can access the channel then you can use the bot. If you can use the bot, the bot will only do the things the bot will do.

That lets me do things like let my wife access the inbox channel so she can push recipes or whatever to it. I had originally wanted to use a whatsapp group but that wasn’t so easy and no one in my family uses telegram and won’t switch (not tech savvy).

Getting Content from Instagram

Recipes on Instagram are annoying! There are a few formula’s you see:

  1. There is no recipe, it’s just someone chatting while cooking - Nothing we can do about this one right now.
  2. There is a recipe but it’s hidden in their profile and down some link chain.
  3. The recipe is included in the body of the post or in a comment

The other challenge here is that Instagram doesn’t just have an API that can I get this content from (if it does, let me know). You also can’t pull the content anonymously.

This is where Playwright on a VNC container came into play. The VNC container has an instagram login session and allows playwright to subsequently navigate to the content and pull it. The LLM controlling it can then process it from there. This works great for other content like #3d-printing on makerworld, I can direct the LLM to store the right link from there or even trigger another job to download the file.

Using Ruby for the Bot

I like ruby and if I am going to work with LLMs on code. I want a language that’s easy to read.

n8n

It was/is kind of hot right now. I wanted to see how it worked and would apply. In the #aws world you might use something like step functions with lambda. I don’t need all that, this is good enough and can spawn a #kubernetes container running a job like dathl-extractor to do the work when it needs too.

Future Plans

The diagram above shows the phased rollout. Right now it’s just the core loop. Discord in, Claude processes, MCP servers store. That already handles recipes, bookmarks, tasks and links. But the inbox part is doing the heavy lifting and there’s a lot more surface area to cover. The animations in the diagram walk through how some of these would actually play out end to end.

Email Scanning

My inbox is full of stuff that should end up somewhere else and I hate organising it or even reading it. Receipts, event invites, articles I’ve starred that I’ll never go back to. The original idea was to just point the same extraction pipeline at Gmail.

Since designing this though, I’ve already built a NATS-based email pipeline in the #homelab that handles ingestion and categorisation. I use it in my job application tracker app and built it with NATS so we can have a pub-sub model for it. So the challenge now isn’t building email scanning from scratch, it’s figuring out how to bridge the two. The NATS pipeline already knows what type of email it’s looking at. The inbox just needs to subscribe and route it to the right MCP server.

Notes & Budgeting

Obsidian has an MCP server already but it’s read-only. I use it for retrieving homelab docs. The missing piece is writes. I want to be able to say “save this as a research note” and have it land in the right vault, right folder, right tags. That probably means building a separate vault that acts as an inbox for the pipeline to drop content into.

For budgeting, right now we track everything in a Google Sheet and it’s a nightmare. Updating it is manual, things get missed, and there’s no single view of where we actually stand. What I want is something #self-hosting that pulls from open banking APIs and investment platforms automatically, gives us one place to see everything, and lets the inbox pipeline feed receipts and invoices into it. Actual Budget is the current front-runner but I haven’t committed to it yet.

Documents & Media

Photos in Google Photos, documents in Google Drive, receipts in my email, insurance paperwork in a drawer somewhere. Everything is scattered and I can never find anything when I actually need it. Paperless-ngx and Immich are already running in the #homelab as part of a wider de-Google effort. The inbox integration is about actually getting stuff into them without me having to think about it. Someone mentions car insurance in Discord, Claude pulls last year’s policy from Paperless for context. Birthday dinner photos get uploaded to Immich the next day and Claude ties them back to the event. If Playwright pulls a 20 minute article, queue it in a read-it-later service rather than losing it in a bookmark folder I’ll never open again.

Calendar & Output

I forget things. Deadlines sneak up, birthdays get missed, renewals expire because I didn’t set a reminder. But even when I do remember, the coordination around it is exhausting. Organising dinner means picking a restaurant, booking it, sorting childcare, sending invites. That’s a lot of back and forth for something that should be straightforward.

The calendar MCP gives Claude awareness of when things are happening. If I casually mention renewing insurance, it can check when the policy expires and set a reminder with a buffer. For birthdays it can proactively prompt about dinner reservations, coordinate childcare via WhatsApp, and follow up after the event to ask how it went. The output layer is what makes the whole system feel less like a filing cabinet. Discord confirmations, email responses, calendar invites, WhatsApp messages for coordination. Less storing, more doing.

Persistent Memory

Right now every job is stateless. Claude spins up, does the work, dies. It doesn’t remember that last week my wife said she doesn’t like coriander, or that I already bookmarked that link three days ago. It can’t connect the dots between things it’s seen before. Someone sends a recipe with coriander and it happily saves it. I send the same link twice and it saves it twice. Some kind of memory layer that persists across sessions would make the whole thing significantly less robotic.

Autonomous Scheduling

Right now the system only does things when I tell it to. I have to drop a link, ask a question, send a message. The whole point of building all of this is that it should eventually be smart enough to do things on its own. Not in a creepy way, just in a “you haven’t planned dinner this week and you have chicken going off tomorrow” kind of way. Or “you saved 12 bookmarks last month and haven’t read any of them, here’s a digest”. This is the one that probably needs a local LLM the most, I don’t want to burn tokens on cron jobs.