- Python 82.8%
- Shell 17.2%
| .claude | ||
| bb_mcp | ||
| knowledge | ||
| scripts | ||
| .env.example | ||
| .gitignore | ||
| .mcp.json | ||
| CLAUDE.md | ||
| config.yml | ||
| CONTROLLER.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
BB-Agent — Buchhaltungsbutler Auto-Kontierung
Ein lokal laufender Agent, der offene Bankumsätze und Belege in Buchhaltungsbutler (BB) autonom kontiert und verbucht. Mitarbeiter pflegen Belege/Umsätze weiterhin manuell ein — der Agent übernimmt nur die Buchungslogik.
Sicherheitsmodell: Vollautonom mit Schwellenwerten — sichere Fälle direkt verbuchen, unklare in eine lokale Review-Queue, niedrige Konfidenz wird eskaliert. Erste 1-2 Wochen läuft alles im DRY_RUN-Modus (keine BB-Schreibvorgänge), damit du die Vorschläge vor der Aktivierung kalibrieren kannst.
Wie es funktioniert
Cron (alle 15min) ─→ Trigger-Datei ──┐
▼
tmux-Session mit Claude Code (im /loop)
│
┌──────────────┴──────────────┐
▼ ▼
bb_mcp Tools Wissensbasis
├─ list/get/search ├─ SKR03/04
├─ propose (review-queue) ├─ Änderungen 2026
└─ commit (BB-API) └─ Eigene Regeln
│
▼
BuchhaltungsButler API
(HTTPS Basic + api_key)
Pro Tick (Verarbeitungsrunde):
- Offene Posten holen (Umsätze + Belege ohne Verbuchung)
- Vendor-Historie und Wissensbasis konsultieren
- Kontierung vorschlagen (Konten, USt, Buchungstexte, ggf. Splits)
- Konfidenz schätzen + validieren (Konto existiert, Periode offen, Idempotenz, Caps)
- Verzweigung: ≥0.90 commit · 0.60-0.90 review-queue · <0.60 escalate
- Audit-Log + Heartbeat
Voraussetzungen
| OS | macOS (Apple Silicon getestet); Linux mit minimalen Anpassungen |
| Tools | Homebrew, uv, tmux, Claude Code |
| Account | Claude.ai-Subscription mit Claude Code |
| BB-Zugang | Buchhaltungsbutler ab Plan Buchhaltung Pro (API verfügbar). API-Credentials: API Client, API Secret, API Key — zu finden in BB → Einstellungen → API |
Installation
# 1) Voraussetzungen (macOS)
brew install uv tmux
# 2) Repo klonen
git clone https://git.mngd.io/patrick/bb-agent.git ~/projects/bb-agent
cd ~/projects/bb-agent
# 3) Abhängigkeiten
uv sync
Konfiguration
.env mit BB-Credentials
cp .env.example .env
# .env in einem Editor öffnen und ausfüllen:
# BB_API_CLIENT=...
# BB_API_SECRET=...
# BB_API_KEY=...
# MANDANT_NAME=meine_gmbh # nur fürs Logging
.env ist in .gitignore — wird nie committet.
config.yml: Schwellenwerte und Sicherheitsgeländer
thresholds:
auto_post_confidence: 0.90 # ≥ → direkt verbuchen
review_confidence: 0.60 # < → eskalieren
guards:
max_amount_auto_post: 5000 # Cap deckelt Konfidenz auf 0.85
blocked_accounts: ["1200","1210","1800"] # Bank/Kasse — nie hier buchen
require_receipt_for_expenses: true # keine Aufwandsbuchung ohne Beleg
hard_max_postings_per_hour: 50 # Notbremse
max_posting_age_days: 90 # ältere Buchungen → abgelehnt
dry_run: true # solange true: keine BB-Writes
Konfidenz-Bänder
| Konfidenz | Verhalten |
|---|---|
≥ auto_post_confidence |
direkt verbuchen (nur wenn dry_run: false) |
| zwischen den Schwellen | Vorschlag in review_queue — manuell via /bb-review |
< review_confidence |
Eskalation in errors, kein Vorschlag |
Konfidenz-Berechnung
LLM-Selbsteinschätzung + Validator-Anpassungen:
| Bedingung | Δ |
|---|---|
| Vendor bekannt (count > 5) und Betrag in ±2σ | +0.10 |
| Vendor unbekannt | −0.20 |
| Betrag > 2σ vom Vendor-Mittel | −0.20 |
| Belegtext widerspricht historischem Konto | −0.30 |
Betrag > max_amount_auto_post |
Cap auf 0.85 (erzwingt Review) |
Tuning-Hinweise
| Setting | Default | Wann anders setzen |
|---|---|---|
auto_post_confidence |
0.90 |
Pilot mit 0.95 starten, später Richtung 0.85 wenn High-Confidence-Vorschläge sauber sind |
review_confidence |
0.60 |
auf 0.50 wenn viele Vorschläge bei 0.50–0.65 hängen |
max_amount_auto_post |
5000 |
im Pilot bei ~500 starten, schrittweise hochziehen |
blocked_accounts |
siehe oben | Pflicht anzupassen an dein SKR (siehe bb_mcp.skr_detect-Output): SKR03 → 1200/1210 Bank, 1000 Kasse, 1800 Privatentnahmen — SKR04 → 1800 Bank, 1600 Kasse |
require_receipt_for_expenses |
true |
nur auf false wenn du bewusst auf den Belegzwang verzichten willst (steuerlich riskant) |
hard_max_postings_per_hour |
50 |
bei sehr hohem Buchungsvolumen hochziehen |
max_posting_age_days |
90 |
730 bei aktiven Vorjahres-Korrekturen, 35 bei strenger Monats-Schließung |
dry_run und Aktivierungspfad
dry_run: true ist der sichere Default — alle Vorschläge gehen in review_queue, keine BB-Writes. Der PreToolUse-Hook in Claude Code blockt bb_commit_*-Aufrufe direkt.
Pfad zur Aktivierung:
- Pilot mit
dry_run: true, Vorschläge täglich via/bb-reviewdurchsehen - Konfidenzen aus
audit_logkalibrieren max_amount_auto_postklein setzen (z.B.500)dry_run: false- Cap schrittweise hochziehen, sobald committete Buchungen seit ≥1 Woche fehlerfrei laufen
Erster Lauf
Empfohlen: ein einziger Befehl macht alles — Voraussetzungen prüfen, beim Erst-Run SKR detecten + Historie syncen + (falls konfiguriert) Embeddings indexieren, tmux-Session aufmachen, Claude Code starten:
bash scripts/start.sh
Optionen:
| Flag | Wirkung |
|---|---|
--bypass-permissions |
Claude Code mit --dangerously-skip-permissions — Tools ohne Approval-Prompts. Alternativ via BB_BYPASS_PERMISSIONS=true in .env persistieren. |
--attach |
Nur an bestehende tmux-Session attachen (kein Neustart). |
--session NAME |
tmux-Session-Name überschreiben (default bb-agent). |
--skip-first-run |
Initialisierungsschritte überspringen, falls die DB neu angelegt wurde aber bewusst leer bleiben soll. |
Manuell (wenn du nicht das Start-Skript nutzen willst):
uv run python -m bb_mcp.skr_detect # SKR-Profil + Kontenrahmen-Cache
uv run python scripts/sync_history.py --full # Historie (24 Monate)
tmux new -s bb-agent
claude --model claude-sonnet-4-6 # Worker im Projektverzeichnis
BB-Controller — optionaler Supervisor
Zwei-Modell-Setup: der Worker (scripts/start.sh) macht die Kontierungs-Arbeit mit Sonnet (schnell, günstig, ausreichend für Routinefälle). Der Controller (scripts/controller.sh) ist ein paralleler Supervisor mit Opus 4.7, der den Worker beobachtet, Vorschläge auf Plausibilität prüft und bei Bedarf den Worker wiederbelebt oder steuert.
bash scripts/controller.sh # eigene tmux-Session "bb-controller"
bash scripts/controller.sh --bypass-permissions # für autonome Kontroll-Loops
Der Controller liest beim Start CONTROLLER.md und wartet dann auf Anweisungen oder /bb-control.
Was /bb-control macht (eine Kontroll-Runde):
- Health-Check: tmux-Session
bb-agentaktiv?data/status.jsonaktuell?claude-Prozess am Leben? - Plausibilität: Top-10 pending Vorschläge gegen
historical_postingsundchart_of_accounts_cachecross-checken — passt das Konto zum Vendor/Belegtext? Halluzinierte Konten? - Diagnose: Muster-Erkennung (immer derselbe Fehler?
knowledge/regeln.mderweitern?) - Empfehlung (max. 6 Zeilen) + Vorschlag für eine nächste Aktion. Aktionen werden erst nach User-OK ausgeführt:
- Worker-Restart:
tmux kill-session -t bb-agent && bash scripts/start.sh - Tick erzwingen:
tmux send-keys -t bb-agent '/bb-tick' Enter - Klärfrage in den Worker tippen
- oder: nichts tun
- Worker-Restart:
Hard rules für den Controller (in CONTROLLER.md festgeschrieben):
- bucht nicht selbst (keine
bb_commit_*) - ändert keine Daten in
bookings.db(nur SELECT) - führt Aktionen nur mit User-Bestätigung aus
Modell-Override:
# Worker mit anderem Modell
BB_MODEL=claude-haiku-4-5-20251001 bash scripts/start.sh
# Controller mit anderem Modell
BB_CONTROLLER_MODEL=claude-sonnet-4-6 bash scripts/controller.sh
In Claude Code:
/bb-tick # einen Tick manuell auslösen
/bb-status # Heartbeat + Queue-Status
/bb-review # Vorschläge interaktiv durchsehen + freigeben
/bb-sync # Historie aktualisieren
Im DRY_RUN-Modus landen alle Vorschläge in data/bookings.db → Tabelle review_queue. Nichts wird in BB geschrieben.
Cron einrichten (Automatik)
bash scripts/install_cron.sh
Installiert drei Einträge in deiner User-Crontab:
*/15 * * * *→ Tick-Trigger0 */6 * * *→ History-Sync* * * * *→ Watchdog (lokales Monitoring + macOS-Notification bei Stillstand)
Die tmux-Session muss laufen, damit der Agent die Tick-Dateien abarbeitet.
Logging und Audit
Der Agent loggt auf drei Ebenen — alles lokal, alles in data/:
1. data/logs/agent.log — Python-Anwendungs-Log
Was du hier findest: jeder BB-API-Call (Pfad, Status, Dauer; niemals Bodies/Secrets), jedes bb_propose_posting/bb_commit_*/bb_escalate mit Konto, Betrag und Konfidenz. Rotierend (5 × 5 MB).
tail -f data/logs/agent.log # live mitlesen
grep ERROR data/logs/agent.log # nur Fehler
grep COMMIT data/logs/agent.log # nur echte Verbuchungen
Log-Level steuern: BB_LOG_LEVEL=DEBUG uv run python … für mehr Details.
2. data/logs/{tick,sync,watchdog}.log — Cron-Logs
Stdout/stderr der Cron-Jobs:
tick.log— Trigger-Generierung (jede 15min eine Zeile)sync.log— Historie-Sync (alle 6h)watchdog.log— Watchdog-Output
3. SQLite — data/bookings.db
Strukturierte Aufzeichnung der Agent-Entscheidungen:
# Alle Aktionen heute
sqlite3 data/bookings.db "SELECT ts, action, ref_type, ref_id, account, amount, confidence
FROM audit_log WHERE ts > datetime('now','start of day') ORDER BY ts DESC"
# Eskalierte Fälle der letzten 7 Tage
sqlite3 data/bookings.db "SELECT ts, ref_id, message FROM errors
WHERE ts > datetime('now','-7 days')"
# Pending Review-Queue mit Konfidenz absteigend
sqlite3 data/bookings.db "SELECT id, ref_type, ref_id, confidence, reason
FROM review_queue WHERE status='pending' ORDER BY confidence DESC"
Schneller Status-Überblick:
uv run python scripts/status_cli.py
Was wird nicht geloggt
.env-Werte, API-Keys, HTTP-Bodies- Belegrohdaten (die bleiben in BB)
- Inhalte der Markdown-Wissensbasis
Pilot-Phase und Aktivierung
- Woche 1-2:
dry_run: true, alle Vorschläge täglich via/bb-reviewdurchsehen. Konfidenzen tunen. - Aktivierung:
dry_run: falsesetzen,max_amount_auto_post: 500als Anfangs-Cap. - Schrittweise hochziehen: Cap erhöhen, sobald die committeten Buchungen seit 1 Woche fehlerfrei laufen.
Sicherheit
- Belege bleiben in BB — werden nie ins lokale Repo gespiegelt.
- GoBD-Trail: jede Buchung trägt eine
justification(1-3 Sätze), die zusätzlich via/comments/addan die BB-Buchung gehängt wird. - Idempotenz: SHA-256-Hash aus
(ref_id, account, amount, date)verhindert Doppelbuchungen. - Notbremse:
hard_max_postings_per_hourstoppt den Agenten, falls er amok läuft. - PreToolUse-Hook: blockt schreibende Tools im DRY_RUN-Modus auf Claude-Code-Ebene.
- Tool-Scope: Agent darf nur
bb_mcp__*-Tools nutzen — andere globale MCP-Server (n8n, Gmail, Drive etc.) sind in.claude/settings.jsondeny-gelistet.
Semantische Suche (RAG, optional)
Die statistische Vendor-Map (vendor_account_mapping) reicht für wiederkehrende Lieferanten. Für Schreibvarianten, neue Vendors mit ähnlichem Pattern, Splits und Kostenstellen macht ein semantisches Retrieval mehr Sinn — der Agent ruft dafür das Tool bb_search_similar(query, k=5) auf, das die Top-k ähnlichsten historischen Buchungen via Cosine-Similarity über Embeddings liefert.
Drei Backends, alle optional, alle in .env umschaltbar:
| Backend | Setup | Modell (Default) | Dim | Setup-Größe | Pro Anfrage | Privatsphäre |
|---|---|---|---|---|---|---|
voyage |
API-Key | voyage-3-lite |
512 | — | API-Roundtrip ~150 ms | Texte verlassen den Host |
openai |
API-Key | text-embedding-3-small |
1536 | — | API-Roundtrip ~200 ms | Texte verlassen den Host |
local |
uv sync --group local |
google/embeddinggemma-300m |
768 | ~600 MB (einmalig) | ~30 ms (CPU/M1) | komplett offline |
Anthropic hat keine eigene Embeddings-API. Die offiziell empfohlene Option für die "Anthropic-Welt" ist Voyage AI (Anthropic-Partner) → Backend voyage.
Aktivierung
# In .env eines wählen:
BB_EMBEDDING_BACKEND=local # oder: voyage / openai
# bei voyage: VOYAGE_API_KEY=...
# bei openai: OPENAI_API_KEY=...
# Modell-Override optional via BB_EMBEDDING_MODEL=...
# Bei local einmalig:
uv sync --group local
# Index aufbauen:
uv run python scripts/reindex_embeddings.py # nur neue/geänderte
uv run python scripts/reindex_embeddings.py --force # alles neu (z.B. nach Backend-Wechsel)
Beim regulären scripts/sync_history.py werden neue Postings automatisch mit-indexiert.
Was wird embedded? Pro Buchung der Text "{vendor} | {posting_text} | D:{debit} C:{credit}". Wenn du später Belegtext-OCR oder Kostenstellen-Hinweise einbeziehen willst, anpassen in bb_mcp/embeddings.py:posting_embed_text.
Wann hilft RAG? Erst ab ~100+ historischen Buchungen mit unterschiedlichen Pattern. Bei deinem Demo (13 AfA-Buchungen) merkst du keinen Unterschied — sinnvoll wird es im Echtbetrieb.
Wissensbasis pflegen
In knowledge/regeln.md kommen deine eigenen Buchungsregeln rein, z.B.:
- Notion, Linear, GitHub → SKR04 6815 (Bürobedarf), VAT 19% (deutsche Anbieter) bzw. RC (USA)
- Bewirtung: 70/30-Split nach knowledge/bewirtungen.md
Je besser dein Agent die Konventionen kennt, desto präziser werden seine Vorschläge.
Troubleshooting
| Symptom | Ursache | Fix |
|---|---|---|
tmux: command not found |
brew shellenv nicht im PATH | source ~/.zprofile oder neues Terminal |
400 Bad Request von BB |
API-Endpoint braucht zusätzliche Pflichtfelder | bb_mcp/server.py und scripts/sync_history.py prüfen |
dry_run is true — refusing to commit |
richtig so | erst nach Pilot dry_run: false setzen |
Lizenz
Lizenziert unter der GNU Affero General Public License v3.0 (AGPL-3.0) — siehe LICENSE.
Kurz: du darfst den Code frei nutzen, modifizieren und weitergeben. Wenn du modifizierte Versionen über ein Netzwerk anbietest (z.B. als gehosteten Service), musst du den Quellcode deiner Modifikationen unter derselben Lizenz veröffentlichen.
Beitragen
Pull Requests willkommen — das Repo lebt unter https://git.mngd.io/patrick/bb-agent.