This is a family manager Telegram bot running on Val Town. It uses Claude (Anthropic) for natural language understanding, Google Calendar, and SQLite for storage.
| File | Type | Purpose |
|---|---|---|
main.ts | HTTP | Telegram webhook handler, system prompt, agent call |
email.ts | Email forwarding handler, system prompt, agent call | |
cron.ts | Interval (Sun 7pm ET) | Weekly briefing — Claude synthesizes "what does this week require?" |
morning-cron.ts | Interval (daily 7am ET) | Daily morning briefing with today's events, weather, tasks |
reminder-cron.ts | Interval (every 15 min) | Proactive reminder pings — fires when a task's remind_at is reached |
llm.ts | Script | Shared LLM layer: model config, createMessage() (one-shot), runAgent() (agentic tool-use loop — both Anthropic and GPT paths) |
tools.ts | Script | Shared toolset: TOOLS array (10 tools) + executeTool() switch |
db.ts | Script | Shared DB layer: initDb(), all task/info/message/user functions, rowsToObjects, localToUtcIso |
google.ts | Script | Shared Google Calendar layer: auth + token refresh, fetchCalendarEvents(), all CRUD helpers |
weather.ts | Script | Shared weather layer: Open-Meteo, fetchForecast() (raw), getWeather() (formatted) |
changelog.md | File | Release history (crayon versioning — see below) |
updates.md | File | Feature backlog and implementation plans |
CLAUDE.md | File | This file |
Each deployable val (main.ts, email.ts, crons) handles its own I/O surface and passes context to the shared layer:
┌─────────────────┐ ┌──────────────────┐ ┌────────────────────┐
│ main.ts │ │ email.ts │ │ cron.ts / │
│ (Telegram I/O) │ │ (Email I/O) │ │ morning-cron.ts │
└────────┬────────┘ └────────┬─────────┘ └─────────┬──────────┘
│ │ │
▼ ▼ ▼
runAgent() runAgent() createMessage()
└──────────────────────┘ │
│ │
llm.ts (shared) llm.ts (shared)
│
┌─────────┴─────────┐
▼ ▼
tools.ts db.ts / google.ts / weather.ts
(TOOLS + executeTool) (all shared helpers)
TELEGRAM_TOKEN — Telegram bot tokenGROUP_CHAT_ID — Family group chat IDANTHROPIC_API_KEY — Anthropic API keyGOOGLE_TOKEN_JSON — Base64-encoded Google OAuth token (Calendar)GOOGLE_CREDENTIALS_JSON — Base64-encoded Google OAuth client credentialsCALENDAR_ID — Google Calendar ID (or "primary")HOME_LOCATION — Home city for weather (e.g. "Newton, MA")MODEL — Claude model override (default: claude-sonnet-4-6)RESPOND_TO_ALL — "true" to respond to all group messages (default: @mention only)BOT_USERNAME — Telegram bot username (optional, avoids a getMe API call)STEEL_API_KEY — Steel (steel.dev) API key for JS-rendered web page scraping. Optional: when set, fetch_url uses Steel's /v1/scrape endpoint for regular web pages instead of plain fetch. Get a free key at app.steel.dev ($30 credit included).fm_tasks — household task list (id, text, created_by, due_date, completed, owner, remind_at, reminded)fm_info — key/value store for household infofm_messages — conversation history per chat_idfm_users — Telegram user identity map (telegram_id, first_name, username) — auto-populated from inbound messages, used to resolve owner names to @mentionsAdding a new tool (e.g. add_note):
db.tsAnthropic.Tool definition to TOOLS in tools.tsexecuteTool in tools.tsmain.ts and email.ts both pick it up automaticallyAdding a new cron (e.g. Friday outing suggestions):
*.ts interval filecreateMessage from ./llm.ts, data helpers from ./db.ts, ./google.ts, ./weather.tscreateMessage({ prompt, maxTokens })Adding a new DB table:
CREATE TABLE IF NOT EXISTS + any migrations to initDb() in db.tsdb.tstools.ts and/or whichever val needs themEvery release gets a crayon name. This is the versioning system:
Current version: Navy Blue (v2.1). Next minor would be Cerulean (v2.2). Next major would be Green (v3.0).
Minor release — new tool, new capability added to existing era (e.g. web search, open loops, family memory):
changelog.md — prepend a new ## 🖍️ [Color] (vX.Y) — [Short title] section/changelog response text in main.ts (the CHANGELOG_LATEST constant)Major release — new capability era (e.g. proactive behavior, email integration, trip planning):
changelog.md — prepend a new ## 🖍️ [Color] (vX.0) — [Era name] sectionCHANGELOG_LATEST in main.tsannounceRelease.ts with the new version notesannounceRelease.ts (use Val Town's run_file tool) to post the announcement to the family chat## 🖍️ [Color] (vX.Y) — [Punchy era/feature name]
*Month Year*
One-sentence summary of what changed and why it matters.
**Feature 1** — What it does, concretely.
**Feature 2** — What it does, concretely.
Keep entries short. Focus on what the family can do with each release, not implementation details.