A temporary inbox for raw information before it's processed into an Obsidian vault.
My "capture" mindset is different from my "organize" mindset.
When I'm capturing information—forwarding an email, saving a link, jotting down a thought—I'm in flow. I don't want to stop and think about where it belongs in my PKM system, what tags it needs, or how to structure it as a proper note.
But I also don't want to just fire random shit directly into my carefully organized Obsidian vault.
This inbox solves that tension. It's a holding area where I can quickly flag things now and thoughtfully organize them later when I'm in the right headspace.
This service is a buffer between raw sources (email, API, messages, etc) and your personal knowledge management system.
Instead of directly processing incoming content into notes, this inbox:
- Receives raw information from multiple sources (email, API calls)
- Stores unprocessed items temporarily with their attachments
- Provides a simple API for clients to retrieve and process items
- Manages the lifecycle: unprocessed → processed → auto-deleted after 30 days
This separation allows you to capture freely in the moment, then process intentionally when you're ready—using different clients (Claude Desktop via MCP, custom scripts, etc.).
See CLAUDE.md for AI assistant guidelines and PROJECT.md for detailed architecture.
-
Remix on Val.town
-
Run one-time setup
Run the one-time setup script to create the database table in your val.town sqlite.
-
Configure Environment Variables
In Val.town, set these secrets:
INBOX_API_TOKEN- Create a secure random token for API auth (via e.g.openssl rand -hex 32)INCOMING_EMAIL_ALLOWLIST- Comma-separated email addresses allowed to send records to the inbox (e.g.name@gmail.com,name@work.org)
-
Set up MCP Server (for Claude Desktop integration)
Create
~/Library/Application Support/Claude/claude_desktop_config.json:{ "mcpServers": { "inbox": { "command": "deno", "args": [ "run", "--allow-net", "--allow-env", "/path/to/inbox/localMcpServer.ts" ], "env": { "INBOX_API_URL": "https://your-username-httphandler.web.val.run", "INBOX_API_TOKEN": "your-api-token" } } } }Alternatively, use the published val URL:
"command": "deno", "args": [ "run", "--allow-net", "--allow-env", "https://esm.town/v/your-username/inbox/localMcpServer.ts" ]
- SQLite database via standard library
- Blob storage for binary attachments
- Email sending/receiving built-in
- HTTP endpoints for API access
- Cron scheduling for cleanup tasks
obsidian-inbox/
├── server/ # Core http server logic
├── mcp/ # Model Context Protocol server
├── emailHandler.ts # Val.town email trigger
├── httpHandler.ts # Val.town HTTP endpoint
├── cleanupCron.ts # Val.town cron job
├── localMcpServer.ts # Entry point for local MCP
└── apiClient.ts # HTTP client (used by MCP)
Via Email: Send email to your Val.town email address from an allowlisted sender. The email body and attachments are automatically saved.
Via HTTP API:
curl -X POST https://your-val.web.val.run/api/record \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "raw": "Content to process later", "subject": "Meeting notes", "from": "manual-entry", "date": "2025-10-21T10:00:00Z", "attachmentBlobIds": [] }'
With Claude Desktop (MCP): In Claude Desktop, ask:
- "What's in my inbox?"
- "Download the attachments from inbox item XYZ"
- "Mark inbox item ABC as processed"
With Custom Scripts:
# Get unprocessed items curl https://your-val.web.val.run/api/inbox \ -H "Authorization: Bearer YOUR_TOKEN" # Mark item as processed curl -X PATCH https://your-val.web.val.run/api/record/{id}/processed \ -H "Authorization: Bearer YOUR_TOKEN"
All endpoints require Authorization: Bearer YOUR_TOKEN header.
| Method | Path | Description |
|---|---|---|
GET | / | Health check (no auth required) |
GET | /api/inbox | Retrieve all unprocessed records |
POST | /api/record | Create new inbox record |
PATCH | /api/record/:id/processed | Mark record as processed |
GET | /api/record/:recordId/attachments | Get attachment metadata |
GET | /api/record/:recordId/attachments/:blobId | Download attachment file |
Schema Changes:
- Update
inboxRecordSchemainserver/InboxService.ts - Increment table name in
server/db.ts(e.g.,inbox_records_2) - Redeploy vals to Val.town
Adding Endpoints:
- Add route in
server/app.ts - Add auth middleware if needed
- Update this README
Adding MCP Tools:
- Create tool file in
mcp/tools/ - Register in
mcp/tools/index.ts - Test with Claude Desktop
- Simple buffer - Not a full app, just a temporary holding area
- Client-side processing - Complex logic lives in clients, not here
- Stateless - Each record is independent
- Val.town native - Leverage platform features over external services
- Fail-fast - Let errors bubble with context
- Send email with notes/attachments to Val.town address
- Email handler saves to inbox
- Ask Claude Desktop: "What's in my inbox?"
- Claude reads items, processes into Obsidian vault
- Claude marks items as processed
- Auto-deleted after 30 days
- POST content via HTTP API
- Poll
/api/inboxendpoint - Process items with your script
- PATCH to mark processed
- Auto-deleted after 30 days
Go nuts