• Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
paulkinlan

paulkinlan

email-agent

Public
Like
email-agent
Home
Code
7
db
2
lib
4
CLAUDE.md
README.md
E
email-handler.ts
H
main.ts
C
task-runner.ts
Connections
Environment variables
1
Branches
1
Pull requests
Remixes
History
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
Code
/
Search
README.md

📧 Email Agent

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.

How It Works

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:

  1. Classify — Claude analyzes your email and extracts structured entries (memories, tasks, ideas, people, meetings, projects)
  2. Store — Everything goes into a unified SQLite database with full-text search and a relationship graph linking entries together
  3. Execute — Instant tasks run immediately through an agentic loop; future/recurring tasks get scheduled
  4. Reply — You get an email back with results, follow-up questions, and any generated file attachments

Voice-Friendly

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.

Agentic Execution

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     │
└─────────────────────────────────────────────┘

Available Tools

ToolWhat It Does
search_memoriesFull-text search across all your stored entries
get_entriesBrowse entries by type (all tasks, all people, all ideas, etc.)
get_linked_entriesTraverse the relationship graph between entries
store_memorySave new facts discovered during task execution
create_taskCreate follow-up tasks — instant, future, or recurring
fetch_urlFetch 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.

What Gets Stored

Everything is an entry with a type. The system is extensible — new types need zero code changes.

TypeExample
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"
interactionEvery 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".

Task Types

TypeBehaviorExample
InstantExecutes immediately, reply in same email"What's the weather in London?"
FutureScheduled for a specific time"Remind me Thursday at 10am to call dentist"
RecurringRepeats on a schedule"Every Monday, summarize my active tasks"

Future and recurring tasks are processed by a task runner that checks every 15 minutes.

Per-User Personalization

Each user gets a persistent system prompt — a personal "CLAUDE.md" that shapes how the agent behaves for them.

Set it by emailing instructions:

  • "Be more casual and use emojis"
  • "Call me Paul"
  • "Always use bullet points"
  • "Don't be so wordy"

These are extracted automatically and applied to every future interaction.

Attachments

Full bidirectional support:

  • Inbound — Email attachments (CSV, JSON, text, code files, etc.) are stored and their content is fed to both the classifier and the agent as context
  • Outbound — The agent can generate files (reports, CSV exports, data dumps) and send them back as email attachments

Architecture

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

Tech Stack

  • Runtime: Val Town (Deno-based serverless)
  • LLM: Claude Sonnet via Anthropic SDK
  • Database: Project-scoped SQLite with FTS5 full-text search
  • Storage: Val Town Blob API for attachments
  • Email: Val Town email sending/receiving

Data Flow

        ┌──────────────┐
        │  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     │
  └────────────┘

Environment Variables

VariableRequiredDescription
ANTHROPIC_API_KEYYesUsed by all Claude API calls (classifier, scheduler, agent)

Admin / Debugging

The HTTP endpoint (main.ts) provides:

  • GET / or GET /stats — System-wide entry counts, entries by type, link counts
  • GET /user/:email — Full user profile with entries grouped by type

Limitations

  • No conversation threading — Each email is independent (though recent history is loaded as context)
  • Plain text replies — No HTML email rendering
  • No admin auth — HTTP endpoints are open
  • No rate limiting — No flood protection
  • No memory deduplication — Semantic similarity dedup not yet implemented
  • No system prompt reset — Users can add instructions but can't easily clear them yet

License

Built on Val Town. Do what you want with it.

Code
dblibCLAUDE.mdREADME.md
E
email-handler.ts
H
main.ts
C
task-runner.ts
FeaturesVersion controlCode intelligenceCLIMCP
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
© 2026 Val Town, Inc.