2026-02-21 06:41:57 +00:00
# Meister-Eder
2026-02-21 13:34:58 +00:00
AI-powered conversational registration agent for **Spielgruppe Pumuckl** (Familienverein Fällanden, Switzerland). Parents register their child and ask questions via email — the agent handles the conversation, validates all required fields, and notifies the playgroup admin on completion.
2026-02-20 22:14:45 +00:00
Replaces a static Google Forms workflow with an AI agent that guides parents through child registration via natural conversation — over email or a web chat interface.
## What it does
- Guides parents through registration one question at a time, adapting to their responses
- Answers questions about fees, schedule, and policies from a curated knowledge base
- Validates and stores completed registrations as structured data
- Notifies playgroup administrators on completion, routed by playgroup type
2026-02-21 22:13:33 +00:00
- Responds in any language the parent uses; defaults to German
2026-02-20 22:14:45 +00:00
## Channels
| Channel | Description |
|---------|-------------|
| Web chat | Real-time, session-based |
| Email | Async, thread-tracked; reminders on days 3, 10, 25 |
2026-02-21 13:34:58 +00:00
## Prerequisites
2026-02-20 22:14:45 +00:00
2026-02-21 13:34:58 +00:00
- Python 3.13+
- [uv ](https://docs.astral.sh/uv/ ) (dependency manager)
2026-02-21 14:24:33 +01:00
2026-02-21 13:34:58 +00:00
## Installation
2026-02-21 06:41:57 +00:00
2026-02-21 13:34:58 +00:00
```bash
git clone https://github.com/gurix/Meister-Eder.git
cd Meister-Eder
uv sync
2026-02-21 06:41:57 +00:00
```
2026-02-21 13:34:58 +00:00
## Configuration
2026-02-21 06:41:57 +00:00
2026-02-21 13:34:58 +00:00
Copy the example env file and fill in your values:
```bash
cp .env.example .env
```
### Required variables
| Variable | Description |
|---|---|
2026-02-26 17:43:35 +01:00
| `AI_MODEL` | Primary model (litellm string), e.g. `anthropic/claude-opus-4-6` |
2026-02-21 13:34:58 +00:00
| `IMAP_HOST` | IMAP server hostname for receiving parent emails |
| `IMAP_USERNAME` | Email account username |
| `IMAP_PASSWORD` | Email account password |
| `SMTP_HOST` | SMTP server hostname for sending replies |
| `REGISTRATION_EMAIL` | Sender address shown to parents |
2026-02-21 22:13:33 +00:00
The API key variable depends on your chosen provider — see [Switching AI providers ](#switching-ai-providers ) below.
2026-02-21 13:34:58 +00:00
### Optional variables
| Variable | Default | Description |
|---|---|---|
2026-02-26 17:43:35 +01:00
| `SIMPLE_MODEL` | _(falls back to `AI_MODEL` )_ | Lightweight model for simple tasks (e.g. email-label translation). Can be from a different provider. Logs a warning if unset. |
| `THINKING_BUDGET` | _(disabled)_ | Token budget for extended thinking — Anthropic models only. Recommended: `8000` . |
2026-02-21 13:34:58 +00:00
| `IMAP_PORT` | `993` | IMAP port |
| `IMAP_USE_SSL` | `true` | Use SSL for IMAP |
| `SMTP_PORT` | `587` | SMTP port |
| `SMTP_USE_TLS` | `true` | Use STARTTLS for SMTP |
2026-02-26 17:43:35 +01:00
| `CHAINLIT_HOST` | `localhost` | Host the web chat binds to. Set to `0.0.0.0` to expose externally. |
2026-02-21 13:34:58 +00:00
| `DATA_DIR` | `data/` | Directory for conversation state and completed registrations |
| `KNOWLEDGE_BASE_DIR` | `openspec/…/knowledge-base` | Path to admin-editable knowledge base markdown files |
| `POLL_INTERVAL` | `60` | Seconds between inbox polls (only used when running as a daemon) |
### Switching AI providers
2026-02-26 17:43:35 +01:00
Both `AI_MODEL` and `SIMPLE_MODEL` use [litellm ](https://docs.litellm.ai/docs/providers ) model strings — any supported provider works without code changes. The two models can be from different providers:
2026-02-21 13:34:58 +00:00
```bash
2026-02-26 17:43:35 +01:00
# Anthropic for both (default)
2026-02-21 13:34:58 +00:00
AI_MODEL = anthropic/claude-opus-4-6
2026-02-26 17:43:35 +01:00
SIMPLE_MODEL = anthropic/claude-haiku-4-5-20251001
2026-02-21 13:34:58 +00:00
ANTHROPIC_API_KEY = sk-ant-...
2026-02-26 17:43:35 +01:00
# Google Gemini for both
AI_MODEL = gemini/gemini-3-pro-preview
SIMPLE_MODEL = gemini/gemini-3-flash-preview
2026-02-21 13:34:58 +00:00
GEMINI_API_KEY = ...
2026-02-26 17:43:35 +01:00
# Mixed providers
AI_MODEL = gemini/gemini-3-pro-preview
SIMPLE_MODEL = anthropic/claude-haiku-4-5-20251001
GEMINI_API_KEY = ...
ANTHROPIC_API_KEY = sk-ant-...
2026-02-21 13:34:58 +00:00
```
## Running
2026-02-22 08:09:37 +00:00
### Web chat
2026-02-21 13:34:58 +00:00
2026-02-22 08:09:37 +00:00
Start the web chat interface:
```bash
uv run chainlit run chat_app.py
```
The chat opens at **http://localhost:8000** by default.
To listen on a different port or host:
```bash
uv run chainlit run chat_app.py --port 8080 --host 0.0.0.0
```
**Minimum required env vars for the web chat:**
| Variable | Description |
|---|---|
| `AI_MODEL` | litellm model string, e.g. `anthropic/claude-opus-4-6` |
| `ANTHROPIC_API_KEY` | (or the key for your chosen provider) |
| `SMTP_HOST` / `SMTP_PORT` | For admin notification emails on registration completion |
| `IMAP_USERNAME` / `IMAP_PASSWORD` | Used as SMTP credentials |
| `ADMIN_EMAIL_INDOOR` | Andrea Sigrist — notified when indoor group is booked |
| `ADMIN_EMAIL_OUTDOOR` | Barbara Gross — notified when outdoor group is booked |
| `ADMIN_EMAIL_CC` | Markus Graf — always CC'd on notifications |
IMAP variables (`IMAP_HOST` , etc.) are not required for the web chat — only for the email channel.
### Email channel
The email agent polls an IMAP inbox and replies via SMTP. No web server required.
**As a cron job (recommended)**
Schedule with cron and use `flock` to prevent overlapping runs:
2026-02-21 13:34:58 +00:00
```cron
*/5 * * * * flock -n /tmp/meister-eder-email.lock uv run python main.py
```
`flock -n` exits immediately if a previous run is still in progress, so the script is always safe to schedule aggressively.
2026-02-22 08:09:37 +00:00
**Manually**
2026-02-21 13:34:58 +00:00
```bash
uv run python main.py
```
2026-02-22 08:09:37 +00:00
### Running both channels together
The web chat and email agent are independent processes — run them side by side:
```bash
# Terminal 1 — web chat
uv run chainlit run chat_app.py
# Terminal 2 — email polling
uv run python main.py
```
Completed registrations from both channels are stored in the same `DATA_DIR` (default: `data/` ) and share the same admin notification configuration.
2026-02-27 14:13:16 +01:00
### Docker Compose (recommended for production)
A `docker-compose.yml` is provided that runs both services together with shared persistent storage:
```bash
cp .env.example .env
# fill in .env, then:
docker compose up -d
```
| Service | What it runs |
|---|---|
| `web` | Chainlit web chat at `http://localhost:8000` |
| `email-worker` | Email polling agent (`main.py` ) |
Both services mount `./data` for shared registration storage and `./openspec` (read-only) for the knowledge base. Restarting a service does not lose conversation state.
To view logs:
```bash
docker compose logs -f
```
To rebuild after a code change:
```bash
docker compose up -d --build
```
2026-02-21 13:34:58 +00:00
## Development
### Running tests
```bash
uv run pytest
```
All tests are unit tests — no network access or API keys required.
### Knowledge base
The agent answers parent questions from markdown files in the knowledge base directory. These files are designed to be edited directly by playgroup admins — no code changes needed to update fees, schedules, or policies.
### Adding a new AI provider
2026-02-26 17:43:35 +01:00
Set `AI_MODEL` (and optionally `SIMPLE_MODEL` ) to any [litellm-supported model string ](https://docs.litellm.ai/docs/providers ) and set the corresponding API key environment variable. No code changes required.