Wiesn Agent
πΊ AI-powered Oktoberfest reservation agent β monitors 38 beer tent portals, sends push alerts when evening slots open, and helps you book via chat. Web dashboard + MCP server + CLI.
Ask AI about Wiesn Agent
Powered by Claude Β· Grounded in docs
I know everything about Wiesn Agent. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
πΊ Wiesn-Agent
AI-powered Oktoberfest reservation monitor β watches 38 beer tent portals, alerts you when slots open, and helps you book before anyone else.
π¬ Example Prompts
"Check all portals and tell me which tents have evening slots on September 25th."
"Go to the Hacker-Festzelt and fill out the reservation form for me."
"Keep monitoring all portals and send me a notification when new dates appear."
"What tents currently have open reservations? Show me a summary."
βοΈ How It Works
Three ways to use Wiesn-Agent:
Option A β Web Dashboard (wiesn-agent web / Docker)
graph LR
SCAN["π Scanner\nauto every 30 min"] -->|new slots| ALERT["π² Push + π Toast"]
SCAN -->|results| DASH["πΊ Dashboard"]
DASH -->|chat: fill form| FILL["π€ AI pre-fills"]
FILL -->|never submits| YOU["β You click submit"]
Option B β MCP Tools (VS Code Copilot, Claude Desktop, Cursor, β¦)
graph LR
AI["π¬ AI Client"] -->|MCP| TOOLS["π οΈ 15 tools\nscan Β· fill Β· notify"]
TOOLS -->|browser actions| PORTAL["π Portal"]
PORTAL -->|never auto-submits| YOU["β You confirm"]
Option C β CLI Workflow (wiesn-agent once/watch)
graph LR
MON["Monitor"] --> ANA["Analyzer"] --> NOT["Notifier\n+ approval prompt"]
NOT -->|approved| FILL["Filler"]
NOT -->|declined| END["End run"]
In
watchmode, the workflow repeats every N minutes.
All three options share the same scanner, tools, and config. Forms are never submitted automatically.
β οΈ Continuous monitoring requires a running process. For Option A, keep
wiesn-agent webrunning (or usedocker compose up -dfor background). For Option C, usewiesn-agent watch. The scanner checks every 30 minutes and sends push notifications when new slots appear β but only while the process is alive.
π Quick Start
1. Docker (recommended β zero setup)
git clone https://github.com/annawiewer/wiesn-agent.git && cd wiesn-agent
cp config.example.yaml config.yaml # edit with your details
cp .env.example .env # edit tokens if needed
docker compose up # β http://localhost:5000
The dashboard includes a chat window β ask questions, trigger scans, or fill forms directly from the browser. Add a GITHUB_TOKEN to .env for LLM-powered chat (see Agent Workflow).
2. Manual
Prerequisites: Python 3.10+, Node.js 18+ (for building the frontend)
git clone https://github.com/annawiewer/wiesn-agent.git && cd wiesn-agent
python -m venv .venv
# Linux/macOS: source .venv/bin/activate
# Windows: .venv\Scripts\activate
pip install -e ".[web]"
playwright install chromium # Linux: add --with-deps if missing system libs
cp config.example.yaml config.yaml # edit with your details
cp .env.example .env # edit tokens if needed
cd web && npm install && npm run build && cd ..
wiesn-agent web # β http://localhost:5000
Note: The backend (
wiesn-agent web) must be running before the frontend works. It serves both the API and the built React app on port 5000. For development, start the backend first (wiesn-agent web), then the frontend dev server (cd web && npm run dev) β the Vite dev server on :5173 proxies API calls to :5000.
π MCP Server
Connect any AI assistant (Copilot, Claude, Cursor, etc.) to 15 MCP tools via the Model Context Protocol.
Prerequisites: Install the package and Playwright browser first:
cd wiesn-agent
pip install -e .
playwright install chromium
cp config.example.yaml config.yaml # edit with your details
Install in VS Code
Add to .vscode/mcp.json:
{
"servers": {
"wiesn-agent": {
"command": "python",
"args": ["-m", "wiesn_agent.mcp_server"],
"cwd": "${workspaceFolder}"
}
}
}
Install in Claude Desktop
Add to your Claude MCP config (set cwd to the repo directory where config.yaml lives):
{
"mcpServers": {
"wiesn-agent": {
"command": "python",
"args": ["-m", "wiesn_agent.mcp_server"],
"cwd": "/path/to/wiesn-agent"
}
}
}
π οΈ Available Tools
| Tool | Description | Input Parameters |
|---|---|---|
check_portal | Navigate to a portal and check for changes | url (string), name (string, optional) |
check_all_portals | Scan all configured portals at once | β |
detect_forms | Detect form fields, selects, and buttons on the page | β |
fill_field | Fill a text input field | selector (string), value (string) |
select_option | Select a dropdown option (with Livewire support) | selector (string), value (string) |
click_element | Click a button or element | selector (string), force (bool, optional) |
fill_reservation_form | Auto-fill entire reservation form with user data | β |
switch_to_iframe | Switch context to an iframe (for KΓ€fer, Tradition) | selector (string) |
run_js | Execute JavaScript on the page | script (string) |
wait_for_element | Wait for an element to appear | selector (string), timeout (int, optional), state (string, optional) |
navigate_to | Navigate to a URL | url (string), wait_until (string, optional) |
take_screenshot | Take a screenshot of the current page | name (string, optional) |
get_page_content | Get the text content of the page | selector (string, optional) |
monitor_availability | Scan all portals and compare with last snapshot | portal_name (string, optional), check_date (string, optional), notify (bool, optional) |
send_notification | Send notification via 130+ services (ntfy, Telegram, etc.) | title (string), message (string), notify_type (string, optional) |
Note: The web dashboard chat exposes 14 of these tools β
run_jsis excluded from chat agents for safety. It remains available via direct MCP connection.
Resources: wiesn://config Β· wiesn://portale Β· wiesn://slots
Prompts: Check all portals Β· Monitor availability Β· Check single portal Β· FestZelt OS Wizard
π€ Agent Workflow (Optional β requires GITHUB_TOKEN)
Built on Microsoft's Microsoft Agent Framework β instead of one monolithic LLM prompt, the system uses 4 specialized agents that each have their own instructions and tools. A triage layer routes every message to the right agent automatically.
π What is Triage?
The TriageExecutor is a custom routing layer built on top of the Agent Framework's Executor base class. The framework provides the workflow graph infrastructure (executors, edges, context passing), and we implement the routing logic:
- No LLM call needed β uses fast keyword matching (e.g. "slot", "available" β Scanner; "fill", "form" β Form Agent)
- Context-aware β "Fill the form for Sep 25" routes to Form Agent (not Scanner), even though a date is present
- Bilingual β recognizes both German and English keywords
- Structured handoffs β agents signal follow-up intent via invisible markers, so "Ja" correctly routes to the offered action
- Cancel handling β "Nein", "Stop", "Cancel" resets pending actions and routes to Chat
- Zero latency β routing happens instantly, only the chosen agent calls the LLM
β‘ Why Multi-Agent?
| Single Prompt | Multi-Agent (Wiesn-Agent) |
|---|---|
| One LLM sees all 15 tools | Each agent sees only its tools |
| Long, unfocused system prompt | Short, expert prompt per agent |
| Can accidentally call form tools while scanning | Scanner cannot access form tools |
| Hard to debug | Triage log shows exactly which agent ran |
ποΈ Architecture
User Message
β
ββββββββββββββββββββββββββ
β TriageExecutor β keyword classification (no LLM needed)
β "Evening slots?" β β detected: scan intent
ββββββββββββββ¬ββββββββββββ
β routes to one of 4 agents:
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Scanner β β Form β β Notifier β β Chat β
β Agent β β Agent β β Agent β β Agent β
β β β β β β β β
β Tools: β β Tools: β β Tools: β β No tools β
β β’ monitor β β β’ navigate β β β’ send β β (text only) β
β β’ check β β β’ fill β β notif. β β β
β β’ check_all β β β’ select β β β β β
β β β β’ click β β β β β
β β β β’ detect β β β β β
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
π§© Framework Building Blocks
| Component | What it does |
|---|---|
| Agent | LLM with own system prompt + own tools |
| TriageExecutor | Routes user messages by keyword (no LLM cost) |
| WorkflowBuilder | Defines the agent graph (who talks to whom) |
| WorkflowAgent | Wraps the graph as a session-aware agent API |
| InMemoryHistoryProvider | Conversation memory across turns |
| MCPStdioTool | Connects Playwright MCP tools to agents |
| OpenAIChatCompletionClient | LLM via GitHub Models (GPT-4o) |
π Two Workflow Modes
Web Chat (wiesn-agent web) β star graph with triage:
graph LR
USER["π¬ User"] --> TRIAGE["π Triage"]
TRIAGE -->|scan| SCANNER["π Scanner"]
TRIAGE -->|form| FORM["π Form Agent"]
TRIAGE -->|notify| NOTIFY["π Notifier"]
TRIAGE -->|chat| CHAT["π Chat Agent"]
CLI Pipeline (wiesn-agent once/watch) β linear graph:
graph LR
MON["Monitor"] --> ANA["Analyzer"] --> NOT["Notifier\n+ approval"]
NOT -->|approved| FILL["Filler"]
NOT -->|declined| END["End run"]
In
watchmode, the pipeline repeats automatically every N minutes.
π§ Follow-up Intelligence
The triage layer uses structured handoff signals β agents append invisible markers to their responses that tell the triage what action was offered:
- Scanner found no matching slots β offers notification test
<!-- handoff:notify -->β user says "Ja" β routes to Notifier - Scanner found matching slots β offers form fill
<!-- handoff:form -->β user says "Ja" β routes to Form Agent - User says "Nein" or "Cancel" β resets pending action, routes to Chat
This works in both German and English, no LLM call needed for routing.
Setup & Usage
pip install -e ".[web]"
playwright install chromium
echo "GITHUB_TOKEN=ghp_..." > .env # github.com/settings/tokens (models:read)
wiesn-agent web # web dashboard + chat at :5000
wiesn-agent web --host 0.0.0.0 --port 8080 # LAN access on custom port
wiesn-agent once # single CLI run
wiesn-agent watch # continuous CLI monitoring (interactive β prompts for approval)
Note:
watchmode is interactive β it prompts via stdin when a matching slot is found. It is not suitable as an unattended background daemon. For unattended monitoring, usewiesn-agent webwhich runs the scanner automatically and sends push/web notifications.
Without
GITHUB_TOKEN, the dashboard chat falls back to keyword-based responses (scan, status, matches, portals) β no LLM required.
π Dashboard
wiesn-agent web β Dashboard (live results, scan trigger) Β· Portals (38 tents, filter) Β· Statistics (charts) Β· Settings (config editor)
Background scanner runs automatically with deep-scan on your preferred dates.
βοΈ Configuration
# config.yaml β keys use German field names (keep them unchanged)
user:
vorname: "Max"
nachname: "Mustermann"
email: "max@example.com"
telefon: "+49 170 1234567"
personen: 10
reservierung:
wunsch_tage: ["2026-09-19", "2026-09-25", "2026-09-26"]
slots:
morgens: { enabled: true, von: "10:00", bis: "12:00", prioritaet: 3 }
mittags: { enabled: true, von: "12:00", bis: "16:00", prioritaet: 2 }
abends: { enabled: true, von: "16:00", bis: "23:00", prioritaet: 1 }
notifications:
desktop: true
apprise_urls:
- "ntfy://wiesn-alert" # free phone push via ntfy.sh
All 38 tents are pre-configured. Enable/disable in the portale section or via the Dashboard.
ποΈ Portal Architectures
Auto-detected: Livewire (LΓΆwenbrΓ€u, Fischer-Vroniβ¦) Β· WordPress (Hacker, Schottenhamelβ¦) Β· iFrame (KΓ€fer, Tradition) Β· Standard (Augustiner, Paulanerβ¦)
Custom per-portal adapters can be registered for high-value tents that use non-standard UI patterns (see portal_adapters.py).
π Notifications
Apprise-powered β ntfy (recommended), Telegram, Slack, Email, 130+ more.
π² Phone Push Notifications (ntfy β free, 2 minutes)
-
Install the ntfy app on your phone:
-
Open the app β tap "+" β enter your channel name (e.g.
wiesn-alert) -
Add the channel to your config (
config.yamlβ notifications β apprise_urls):notifications: apprise_urls: - "ntfy://wiesn-alert" # must match your app subscription -
Done! You'll receive push notifications when new evening slots are found.
Tip: Your channel name is public on ntfy.sh. Use something unique like
wiesn-yourname-2026for privacy. Or self-host ntfy for full control.
No app? Open
https://ntfy.sh/your-channelin any browser to see notifications.
Other Notification Channels
Add any Apprise URL to apprise_urls:
| Service | Config Example |
|---|---|
| Telegram | tgram://BOT_TOKEN/CHAT_ID |
| Slack | slack://TOKEN_A/TOKEN_B/TOKEN_C |
| Discord | discord://WEBHOOK_ID/WEBHOOK_TOKEN |
mailtos://user:pass@gmail.com | |
whatsapp://TOKEN@PHONE/TARGET |
π Quiet Hours
Notifications are suppressed during quiet hours (default: 22:00β08:00). Alerts found overnight are queued and delivered as a morning digest when quiet hours end. Web browser toasts are always shown immediately.
π Security
- API Auth: Set
WIESN_API_TOKENin.envto require bearer token auth on all/api/endpoints (except/api/health). When not set, the API is open (localhost-only use). - PII Redaction: Config endpoints and MCP resources automatically redact email, phone, notification secrets, and tokens. Personal names are kept (needed for form filling).
- Human-in-the-Loop: Forms are never auto-submitted. The CLI workflow prompts for approval via stdin before pre-filling. In web mode, form filling is chat-driven β the agent pre-fills, you review and submit manually.
- run_js Gating: The
run_jstool (arbitrary JS execution) is excluded from chat agent tools. It remains available via direct MCP connection for expert users. All executed scripts are logged. - Prompt Injection Defense: Agent instructions explicitly treat portal page content as untrusted and ignore any instructions found in page text.
- Audit Log: Scan events and notifications are logged to
data/audit.log(append-only, not subject to ring buffer limits). - Atomic Snapshots: Availability snapshots use temp-file + rename to prevent corruption from concurrent writes.
π Project Structure
src/wiesn_agent/
βββ mcp_server.py # MCP Server (15 tools)
βββ api.py # FastAPI backend + background scanner
βββ scanner.py # Portal scanner (deep scan, snapshots)
βββ chat_agent.py # Multi-agent chat workflow (TriageExecutor)
βββ workflow.py # CLI agent workflow graph (once/watch)
βββ portal_adapters.py # Per-portal scanning adapters (extensible)
βββ agents/ # 4 AI agents (CLI workflow)
βββ tools/ # Browser + notification tools
web/src/ # React dashboard (Vite + Tailwind)
β Troubleshooting
| Issue | Solution |
|---|---|
playwright install chromium fails | Run with sudo on Linux, or use playwright install --with-deps chromium for missing system libraries |
| Livewire forms don't populate next selects | Increase wait time between select_option calls (Livewire needs 2β3s for server roundtrip) |
| CSS selector fails on FestZelt OS portals | IDs contain dots β use run_js with document.getElementById() instead |
| iframe portals (KΓ€fer, Tradition) show no forms | Call switch_to_iframe first to enter the iframe context |
GITHUB_TOKEN errors in chat | Create a token at github.com/settings/tokens with models:read scope, add to .env |
| Scanner finds no dates | Most portals only open reservations ~3 months before Oktoberfest (mid-June 2026) |
| API returns 401 Unauthorized | Set Authorization: Bearer <token> header, or remove WIESN_API_TOKEN from .env |
π License
MIT
