Tell the LLM explicitly that the reply field must be plain text with no
markdown (no bold, italic, headers, bullet points, or backticks). Email
clients display raw text so markdown syntax would appear as literal
characters rather than formatting.
https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
Add standard > -prefixed quote block to outbound replies so parents can
see what they wrote in the previous message, matching natural email client
behaviour. The quote header uses the German "Am <date> schrieb <addr>:"
convention (matching Outlook/Thunderbird).
- email_channel.py: add _build_quoted_block() helper; extend send_reply()
with optional quoted_text/quoted_from params
- main.py: pass msg["body"] and msg["from"] as quoted_text/quoted_from
https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
- prompts.py: correct age restrictions (indoor ≥2 yrs, outdoor ≥2.5 yrs)
Previously had indoor ≥2.5 and outdoor ≥3, which was too restrictive
- README.md: add full setup and configuration guide covering prerequisites,
installation, env var reference, provider switching, cron scheduling,
running tests, and knowledge base editing
https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
Drops the src/providers/ package (base class, AnthropicProvider,
OpenAIProvider, factory) in favour of a single src/llm.py that calls
litellm.completion() directly. litellm handles provider routing,
authentication, and SDK differences for 100+ providers without any
code we need to maintain.
Changes:
- Delete src/providers/ entirely
- Add src/llm.py — one complete() function wrapping litellm
- src/agent/core.py: EmailAgent takes model: str instead of LLMProvider
- src/config.py: ai_provider + api key fields → single ai_model string
in litellm format (e.g. "anthropic/claude-opus-4-6")
- main.py: remove provider factory wiring; pass config.ai_model to agent
- .env.example: simplify AI section, show litellm model string examples
- pyproject.toml: replace anthropic + openai deps with litellm>=1.0.0
- uv.lock: regenerated
https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
Closes the gap where parents sending a new email (instead of replying)
would lose their registration progress. All changes follow the
email-based-conversation-matching OpenSpec change.
Key changes
-----------
storage/json_store.py
- normalize_email() helper (lowercase + trim)
- Conversations now keyed by sender email address, not thread ID
- Versioned registration storage: data/registrations/<email>/v<N>_<ts>.json
- current.json always reflects the latest version
- save_registration() returns (email_key, version) tuple
- save_registration_version() for updates with change_summary
- get_registration_history() returns all versions in order
models/conversation.py
- Added last_inbound_message_id field for reply threading (not matching)
channels/email_channel.py
- fetch_unread_messages() no longer exposes thread_id
- Conversation matching removed from channel layer (now in agent)
- Removed _resolve_thread_id() — threading headers kept for SMTP only
agent/core.py
- process_message() takes parent_email + inbound_message_id (no thread ID)
- Looks up conversation by normalized email address
- Post-completion handler: detects intent (question / update / new_child)
- Registration updates: diffs old vs new, versions storage, notifies admin
agent/prompts.py
- build_system_prompt() dispatches to registration or post-completion prompt
- Post-completion prompt guides LLM to return intent field
- Reminder language updated: no expiration threats
notifications/notifier.py
- notify_admin() accepts version parameter
- notify_registration_update() sends "Registration Updated" emails with diff
- _build_update_body() includes field-level old→new change summary
main.py
- Poll loop passes parent_email + inbound_message_id to agent (no thread_id)
https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
Documents project overview, repository structure, OpenSpec workflow,
system architecture decisions, domain knowledge (fees, schedule,
registration schema, conversation flow), and conventions for AI
assistants working in this repo.
https://claude.ai/code/session_01A6JAs2Pbg1hF1aLs7bcKhx