Configuration

Who you are, where he runs, what he may spend, and what ships switched off.

Where settings live

Everything is in .env at the top of your checkout. ./setup.sh creates it from .env.example, which describes every setting with its default. The backend loads the file itself (a variable already set in its environment wins), and the start scripts never export it. Most values are read on every call; to be sure a change applies, run ./restart.sh backend. Never commit .env.

The essentials

./setup.sh asks for these three:

VariableWhat it is
EDWARD_OWNER_NAMEWhat Edward calls you. Unset, he says “the owner”.
ANTHROPIC_API_KEYYour key from console.anthropic.com. Every model call uses it.
TIMEZONEYour IANA zone (America/New_York), until the app’s own setting (Edward tab → House → Locale) is loaded.

About you

Read by backend/services/owner.py. The code never names its owner any other way.

VariableWhat it is
EDWARD_OWNER_FULL_NAME, EDWARD_OWNER_ALIASESOther names you go by, so he recognises you in messages.
EDWARD_OWNER_HANDLESYour phone numbers, emails and Apple ID: how he recognises your iMessages and your self-chat. Set it if he reads your messages.
EDWARD_OWNER_EMAILSYour email addresses: mail from these is yours, and he never emails you.
EDWARD_HOUSEHOLDThe people at the household hub, comma-separated, you first.
EDWARD_SENSITIVE_NAMESPets, family and anyone else whose mentions his memory upkeep must never retire on its own.

This Mac

Read by backend/services/host_config.py.

VariableDefaultWhat it is
EDWARD_PUBLIC_BASE_URLhttp://localhost:3000Where you open Edward (a tunnel’s https address). Links in pushes and texts use it.
EDWARD_TUNNEL_LABELunsetYour tunnel’s LaunchAgent label, so the health check watches and restarts it.
EDWARD_BACKEND_HOST0.0.0.0The backend listens on every interface so a hub on your network can reach it; 127.0.0.1 keeps it to this Mac.
EDWARD_COOKIE_SECUREonThe session cookie assumes HTTPS (or http://localhost). off only on a plain-HTTP network you trust.
EDWARD_LAUNCHD_PREFIXcom.meet-edwardThe LaunchAgents’ label prefix.
EDWARD_BACKUP_DIR~/edward-backupsWhere the nightly backup goes. A /Volumes/… path is a removable drive (skipped while unplugged; needs Full Disk Access).
NEXT_PUBLIC_BASE_URLthe base URLThe app’s public origin for link previews, baked into the frontend build: after changing it, run bash frontend/deploy-build.sh and restart the frontend.

The model and the money

EDWARD_LLM_PROVIDER=anthropic is the default: every call goes to the Claude API, with one route per purpose.

RouteUsed forModel, effort
chatyour conversations, ping replies, scheduled eventsSonnet 5.5, medium
mindevery wake: follow-through, the nightly, free time, speaking upSonnet 5.5, medium
pulsedeciding what the widget and screens showSonnet 5.5, medium
backgroundmemory extraction and upkeep, the noticer, photo descriptionsHaiku 5.5, high
voicespoken turnsSonnet 5.5, low
judgeevaluationsOpus 5.5, high

Override any of them per purpose with EDWARD_CLAUDE_<PURPOSE>_MODEL, _EFFORT, _MAX_TOKENS, _THINKING_DISPLAY and _CACHE_TTL (for example EDWARD_CLAUDE_CHAT_MODEL).

VariableDefaultWhat it bounds
EDWARD_DAILY_SPEND_CAP_USD5Dollars over your local day. Background work stops at 60 % of it (EDWARD_BACKGROUND_SPEND_SHARE), Edward’s own turns at the cap, and your own turns may run EDWARD_INTERACTIVE_RESERVE_USD (3) past it.
EDWARD_TURN_MAX_USD3.00One turn you asked for.
EDWARD_AUTONOMOUS_TURN_MAX_USD1.00One turn you didn’t (a wake, a ping from a friend, an event).
EDWARD_CREDITS_START_USD, EDWARD_CREDITS_START_DATEunsetSet both to count prepaid credits down on the Fuel card (console.anthropic.com stays the authority).

Every call is priced and shown in the app (Edward tab → Work → Usage) and at GET /api/health/spend.

The Codex fallback: EDWARD_LLM_PROVIDER=codex runs GPT through the Codex CLI’s ChatGPT login. That is not an official API for third-party apps, may break at any time and may conflict with OpenAI’s terms; use it at your own risk. OPENAI_API_KEY switches it to the public API.

Off by default, and the switch for each

A fresh install reads nothing private and reaches no one. Each feature below stays off, or does nothing, until you turn it on.

WhatHow to turn it on
Every skillEdward tab → Mind → Skills (Shell/Bash, Web Search, iMessage, Push Notifications, iOS Widget, Voice…)
Reading your iMessages, and @Edward pingsEdward tab → Attention → Listening → Configuration → Messages; Full Disk Access; Messages on this Mac signed into your Apple ID; EDWARD_OWNER_HANDLES. Pings then follow EDWARD_PINGS (on). Read this first.
Mail.appListening → Configuration → Email; Full Disk Access; keep Mail.app running
GmailAn OAuth client (GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET; gmail-setup.md), then Attention → Gmail → Watch my inbox
Noticing (speaking up unasked)EDWARD_PROACTIVITY=shadow (decides, never speaks), then notice
Hands in your ChromeLoad chrome-extension/ unpacked in Chrome, then EDWARD_CHROME_HANDS=on
His shell, editor, your Chrome and the screens in friends’ pingsEDWARD_FRIENDS_FULL_TOOLSET=on, at a risk: a friend’s message then drives a shell that runs as you
Approvals for tainted turnsEDWARD_TAINT_APPROVALS=shadow (log only) or on
VoiceELEVENLABS_API_KEY, ELEVENLABS_VOICE_ID
Push notificationsnpx web-push generate-vapid-keys into VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY, then allow notifications in the app (HTTPS)
The hub’s pets and careCopy backend/hub_seed.example.json to backend/hub_seed.json, describe your own, set EDWARD_HUB_SEED=hub_seed.json
The hub’s peopleEDWARD_HOUSEHOLD (just you until set)
The household photo door (a photos-only login)PHOTO_DOOR_PASSWORD_HASH: a bcrypt hash, in single quotes (.env.example has the command)
Twilio SMS and WhatsApp (a number of Edward’s own)TWILIO_* and EDWARD_OWNER_HANDLES. Webhooks are refused without TWILIO_AUTH_TOKEN, and only your own numbers get an answer; EDWARD_TWILIO_ANSWER_ANYONE=on answers everyone, at a risk
The WhatsApp bridgeRun the whatsapp-mcp Go bridge yourself, then MCP_WHATSAPP_ENABLED=true
apple-mcp (a fallback for reading your calendar)Install bun, clone apple-mcp, MCP_APPLE_ENABLED=true
Alexa and Home AssistantALEXA_SKILL_ID, HOME_ASSISTANT_URL, HOME_ASSISTANT_TOKEN. Inbound Alexa requests are not signature-checked yet: leave ALEXA_SKILL_ID unset unless you use the skill
Brave SearchBRAVE_SEARCH_API_KEY, only needed with the Claude server-side web tools off (EDWARD_SERVER_WEB_TOOLS=off) or on the Codex fallback
The knowledge graphGRAPHITI_ENABLED=true (queues every new memory) and GRAPHITI_INGEST_ENABLED=true (fills the graph from the queue), then bash scripts/install-launchagents.sh --with-graph. Each memory costs a few background model calls
Hosted pagesHTML_HOSTING_URL and HTML_HOSTING_API_KEY. There is no default host
A daily cap on his own pushesEDWARD_PUSH_BUDGET=<n> (none by default)
Deep health checks for a hub kiosk and for mailEDWARD_HEALTH_HUB_KIOSK=1, EDWARD_HEALTH_EMAIL=1
The Codex fallbackEDWARD_LLM_PROVIDER=codex (unofficial, at your own risk)

On by default

Know these before you leave Edward running:

  • The daily spend cap, $5 over your local day.
  • Quiet hours, 22:00–07:00 (EDWARD_QUIET_HOURS=22-7; equal hours mean none). Pushes and spoken lines wait for morning.
  • Two scheduled wakes a day: a silent nightly at 03:00, skipped when nothing happened, and one free-time run at 13:00 (about $0.50 at most) that reaches nobody.
  • The surfaces pulse: a check every 15 minutes that runs a model turn only when the board, the calendar, a screen or the widget changed.
  • The nightly backup at 03:30 to ~/edward-backups, on the same disk, unless you install with --without-backup or point EDWARD_BACKUP_DIR elsewhere. Keep a copy off the Mac too.
  • The late-dose alert (EDWARD_CARE_WATCH=on), which has nothing to watch until the hub has timed care items.
  • The egress secret scan and the shell sandbox. Their off values are emergency switches only.

Everything else

The full annotated list is .env.example; the environment section of CLAUDE.md has the main ones with their defaults on one screen. Nothing reads GITHUB_TOKEN, USPS_API_USER_ID or the LangSmith variables any more.

The iPhone widget has its own token, set up in Widget, screen & hub.