An email-based personal AI agent built on Val Town. Interact entirely via email β send messages, tasks, ideas, and memories to memory-do@valtown.email and the agent classifies, stores, executes, and replies.
Send an email. The agent reads it, figures out what you mean, and acts on it.
You β "Remind me Thursday to call the dentist"
β "I like chickens"
β "What's the latest news on WebAssembly?"
β "Every Monday, give me a summary of my active tasks"
Under the hood:
Emails sent via voice transcription work great. The classifier is tuned for misspellings, run-on sentences, and implicit intent β it interprets what you mean, not what you literally typed.
The agent doesn't just make a single LLM call and reply. It runs an iterative tool-use loop β Claude can call tools mid-task to gather information, search the web, query your stored knowledge, and create follow-up work.
βββββββββββββββββββββββββββββββββββββββββββββββ
β 1. Load user context (memories, tasks, etc) β
β 2. Send task + context + tools to Claude β
β 3. Claude responds: β
β ββ Final answer? β Done, send reply β
β ββ Tool call? β Execute tool, loop to 2 β
β 4. Safety: max 15 iterations β
β 5. Extract attachments, generate subject β
βββββββββββββββββββββββββββββββββββββββββββββββ
| Tool | What It Does |
|---|---|
search_memories | Full-text search across all your stored entries |
get_entries | Browse entries by type (all tasks, all people, all ideas, etc.) |
get_linked_entries | Traverse the relationship graph between entries |
store_memory | Save new facts discovered during task execution |
create_task | Create follow-up tasks β instant, future, or recurring |
fetch_url | Fetch live data from the web (news, APIs, weather, docs) |
This means the agent can do multi-step research: search your memories, fetch a web page, cross-reference with your stored projects, save what it learned, and compose a rich reply β all in one email exchange.
Everything is an entry with a type. The system is extensible β new types need zero code changes.
| Type | Example |
|---|---|
memory | "I work at Acme Corp", "I like chickens" |
task | "Remind me Thursday to call the dentist" |
idea | "I have an idea for a recipe app..." |
person | "My friend Sarah works at Google" |
meeting | "Lunch with Bob on Friday at noon" |
project | "I'm building a Chrome extension" |
interaction | Every email sent/received (automatic) |
Entries are linked to each other in a relationship graph β "this idea became this project", "these entries came from the same email", "this person is connected to this meeting".
| Type | Behavior | Example |
|---|---|---|
| Instant | Executes immediately, reply in same email | "What's the weather in London?" |
| Future | Scheduled for a specific time | "Remind me Thursday at 10am to call dentist" |
| Recurring | Repeats on a schedule | "Every Monday, summarize my active tasks" |
Future and recurring tasks are processed by a task runner that checks every 15 minutes.
Each user gets a persistent system prompt β a personal "CLAUDE.md" that shapes how the agent behaves for them.
Set it by emailing instructions:
These are extracted automatically and applied to every future interaction.
Full bidirectional support:
email-agent/
README.md β You are here
CLAUDE.md β Internal dev guide and conventions
main.ts β HTTP admin/debug endpoint
email-handler.ts β Email ingestion (memory-do@valtown.email)
task-runner.ts β Scheduled task processor (runs every 15 min)
lib/
classifier.ts β Claude-powered email β structured entries
agent.ts β Agentic task execution with tool-use loop
scheduler.ts β Natural language β ISO datetime
attachments.ts β Blob storage for inbound/outbound files
db/
schema.ts β SQLite schema (entries + FTS5 + links)
queries.ts β CRUD, search, user context builder
ββββββββββββββββ
β Incoming β
β Email β
ββββββββ¬ββββββββ
β
ββββββββΌββββββββ
β Classifier β β Claude: extract entries, instructions, follow-ups
β (1 LLM call) β
ββββββββ¬ββββββββ
β
ββββββββΌββββββββ
β Store in DB β β Entries, FTS sync, cross-links
ββββββββ¬ββββββββ
β
βββββββββ΄βββββββββ
β β
ββββββΌββββββ βββββββΌβββββββ
β Instant β β Future / β
β Tasks β β Recurring β
β β β Tasks β
β βββββββββ β β β
β β Agent β β β Queued for β
β β Loop β β β task-runnerβ
β β β» β β ββββββββββββββ
β βββββ¬ββββ β
β β β
βββββββΌββββββ
β
βββββββΌββββββ
β Reply β β Results + attachments + follow-up questions
β Email β
ββββββββββββββ
| Variable | Required | Description |
|---|---|---|
ANTHROPIC_API_KEY | Yes | Used by all Claude API calls (classifier, scheduler, agent) |
The HTTP endpoint (main.ts) provides:
GET / or GET /stats β System-wide entry counts, entries by type, link countsGET /user/:email β Full user profile with entries grouped by typeBuilt on Val Town. Do what you want with it.