Skip to content

annawiewer/wiesn-agent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🍺 Wiesn-Agent

Python 3.10+ License: MIT Microsoft Agent Framework MCP FastAPI React

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"]
Loading

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"]
Loading

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"]
Loading

In watch mode, 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 web running (or use docker compose up -d for background). For Option C, use wiesn-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_js is 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 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"]
Loading

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"]
Loading

In watch mode, 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: watch mode is interactive β€” it prompts via stdin when a matching slot is found. It is not suitable as an unattended background daemon. For unattended monitoring, use wiesn-agent web which 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)

  1. Install the ntfy app on your phone:

  2. Open the app β†’ tap "+" β†’ enter your channel name (e.g. wiesn-alert)

  3. Add the channel to your config (config.yaml β†’ notifications β†’ apprise_urls):

    notifications:
      apprise_urls:
        - "ntfy://wiesn-alert"    # must match your app subscription
  4. 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-2026 for privacy. Or self-host ntfy for full control.

No app? Open https://ntfy.sh/your-channel in 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
Email mailtos://user:pass@gmail.com
WhatsApp 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_TOKEN in .env to 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_js tool (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

About

🍺 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.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors