ForgeKitFORGEKIT

Build Log

Event location polls and AI-drafted inquiry replies

July 29, 2026

MedinaCHF's first live Anthropic call — grounded, human-reviewed AI in two places: coordinator-facing location poll suggestions, and coordinator-facing inquiry reply drafts.

MedinaCHFAICoordinator
2
new coordinator-facing AI features (poll suggestions, inquiry draft replies)
1
shared thin AI wrapper (lib/ai.ts) both features call
0
AI-sent messages — every draft requires a human click to send

Timeline

Start
lib/ai.ts wrapper added
Lazy-client-init, same discipline as lib/email.ts and lib/db/index.ts
Mid
Event location polls built
Coordinator turns on a poll; Claude suggests 3-4 places grounded in past event locations; members vote; coordinator closes and sets the event location
End
AI-drafted inquiry replies built
Coordinator clicks 'Draft with AI'; Claude drafts a reply grounded only in the approved Answer Library; coordinator reviews/edits/sends

What shipped

lib/ai.ts — a narrow, single-purpose draftWithClaude(system, userPrompt) wrapper; lazy client init (throws only when actually called, not at module load); every caller owns its own parsing and must handle a thrown error with a safe fallback

Event location polls: pollOptions/pollVotes tables (already migrated in an earlier commit), enablePollWithAiSuggestions/addPollOption/castPollVote/closePoll server actions, EventPollPanel (coordinator) + PollVoteForm (member) client components

AI-suggested poll options grounded in listPastEventLocations — every past event's real location for the org, so Claude can point out repeats vs. genuinely new suggestions instead of inventing anything

One vote per family per event — a repeat vote replaces the prior choice rather than accumulating a second row

Closing a poll sets the event's real location field directly — the poll's only job is picking a value for events.location, not becoming a parallel field

AI-drafted inquiry replies: draftInquiryResponse server action, grounded exclusively in active answerLibraryEntries (the same single source of truth every other response level in this app already uses) — never invents a fact not present in the approved answers

InquiryReplyPanel gets a second 'Draft with AI' button alongside the existing 'Send Response' — drafting only ever fills the textarea, sending is always the coordinator's separate, deliberate action