Lexware-Office-Agent: autonome Kontierung & Verbuchung mit Schwellenwerten
  • Python 81%
  • Shell 19%
Find a file
Patrick 16b46c3869 init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks
- Voucher-zentrisches Modell statt postings/transactions (Lexware ist
  dokumentenzentriert; categoryId + taxRatePercentage statt SKR-Konto)
- LexClient: Bearer Token, base https://api.lexware.io/v1, 2 req/s rate-limit
- 17 MCP-Tools: list_open_vouchers, get_voucher, propose_voucher,
  commit_voucher, attach_file_to_voucher, search_similar (RAG) etc.
- Schema: historical_vouchers, category_catalog, contact_category_mapping
- Erhalten: tmux-Launcher (Sonnet), Controller-Session (Opus), Watchdog,
  Cron-Setup, dry_run-Hook, RAG mit 3 Backends, AGPL-3.0, Logging
2026-04-27 21:27:31 +02:00
.claude init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
knowledge init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
lex_mcp init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
scripts init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
.env.example init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
.gitignore feat: structured file logging (rotating); README ohne 1Password, mit Logging-Anleitung 2026-04-26 23:39:18 +02:00
.mcp.json init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
CLAUDE.md init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
config.yml init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
CONTROLLER.md init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
LICENSE license: AGPL-3.0; README: Troubleshooting-Zeilen entfernt 2026-04-27 00:08:20 +02:00
pyproject.toml init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
README.md init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00
uv.lock init: lex-agent — Lexware-Office-Variante des bb-agent-Stacks 2026-04-27 21:27:31 +02:00

Lex-Agent — Lexware Office Auto-Kontierung

Ein lokal laufender Agent, der offene Bankumsätze und Belege in Lexware Office (Lex) 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 Lex-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)
                                      │
                       ┌──────────────┴──────────────┐
                       ▼                             ▼
                 lex_mcp Tools                Wissensbasis
                 ├─ list/get/search          ├─ categoryIds
                 ├─ propose (review-queue)   ├─ USt / Bewirtungen
                 └─ commit (Lex-API)         └─ Eigene Regeln
                       │
                       ▼
                Lexware Office API
                (HTTPS + Bearer Token)

Pro Tick (Verarbeitungsrunde):

  1. Offene Vouchers + unverbuchte Files holen
  2. Contact-Historie und Wissensbasis konsultieren
  3. categoryId + taxRatePercentage vorschlagen (statt SKR-Konto)
  4. Konfidenz schätzen + validieren (categoryId existiert, Periode offen, Idempotenz, Caps)
  5. Verzweigung: ≥0.90 commit · 0.600.90 review-queue · <0.60 escalate
  6. Audit-Log + Heartbeat

Mental Model: Lexware Office ist dokumentenzentriert. Die API hat keine /postings- oder /transactions-Endpoints — stattdessen weist du Vouchers (Belegobjekten) eine categoryId und taxRatePercentage zu. Die categoryId ersetzt die SKR-Kontonummer.

Voraussetzungen

OS macOS (Apple Silicon getestet); Linux mit minimalen Anpassungen
Tools Homebrew, uv, tmux, Claude Code
Account Claude.ai-Subscription mit Claude Code
Lex-Zugang Lexware Office ab aktivierter Public-API (API verfügbar). API-Credentials: API-Token — generieren unter https://app.lexware.de/addons/public-api

Installation

# 1) Voraussetzungen (macOS)
brew install uv tmux

# 2) Repo klonen
git clone https://git.mngd.io/patrick/lex-agent.git ~/projects/lex-agent
cd ~/projects/lex-agent

# 3) Abhängigkeiten
uv sync

Konfiguration

.env mit Lexware-Token

cp .env.example .env
# .env in einem Editor öffnen und ausfüllen:
#   LEX_API_TOKEN=<aus https://app.lexware.de/addons/public-api>
#   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 Lex-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 /lex-review
< review_confidence Eskalation in errors, kein Vorschlag

Konfidenz-Berechnung

LLM-Selbsteinschätzung + Validator-Anpassungen:

Bedingung Δ
Contact bekannt (count > 5) und Betrag in ±2σ +0.10
Contact unbekannt 0.20
Betrag > 2σ vom Contact-Mittel 0.20
Beschreibung widerspricht historischer Kategorie 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.500.65 hängen
max_amount_auto_post 5000 im Pilot bei ~500 starten, schrittweise hochziehen
blocked_categories leer nach erstem /lex-sync ggf. interne Verrechnungs-Kategorien sperren
hard_max_postings_per_hour 50 bei sehr hohem Voucher-Volumen hochziehen
max_voucher_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 Lex-Writes. Der PreToolUse-Hook in Claude Code blockt lex_commit_voucher-Aufrufe direkt.

Pfad zur Aktivierung:

  1. Pilot mit dry_run: true, Vorschläge täglich via /lex-review durchsehen
  2. Konfidenzen aus audit_log kalibrieren
  3. max_amount_auto_post klein setzen (z.B. 500)
  4. dry_run: false
  5. 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 Voucher-Historie syncen + Kategorie-Katalog ableiten + (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 LEX_BYPASS_PERMISSIONS=true in .env persistieren.
--attach Nur an bestehende tmux-Session attachen (kein Neustart).
--session NAME tmux-Session-Name überschreiben (default lex-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 lex_mcp.skr_detect              # SKR-Profil + Kontenrahmen-Cache
uv run python scripts/sync_history.py --full    # Historie (24 Monate)
tmux new -s lex-agent
claude --model claude-sonnet-4-6                # Worker im Projektverzeichnis

Lex-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 "lex-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 /lex-control.

Was /lex-control macht (eine Kontroll-Runde):

  1. Health-Check: tmux-Session lex-agent aktiv? data/status.json aktuell? claude-Prozess am Leben?
  2. Plausibilität: Top-10 pending Vorschläge gegen historical_vouchers und category_catalog cross-checken — passt das Konto zum Vendor/Belegtext? Halluzinierte Konten?
  3. Diagnose: Muster-Erkennung (immer derselbe Fehler? knowledge/regeln.md erweitern?)
  4. 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 lex-agent && bash scripts/start.sh
    • Tick erzwingen: tmux send-keys -t lex-agent '/lex-tick' Enter
    • Klärfrage in den Worker tippen
    • oder: nichts tun

Hard rules für den Controller (in CONTROLLER.md festgeschrieben):

  • bucht nicht selbst (keine lex_commit_voucher)
  • ändert keine Daten in lex_state.db (nur SELECT)
  • führt Aktionen nur mit User-Bestätigung aus

Modell-Override:

# Worker mit anderem Modell
LEX_MODEL=claude-haiku-4-5-20251001 bash scripts/start.sh
# Controller mit anderem Modell
LEX_CONTROLLER_MODEL=claude-sonnet-4-6 bash scripts/controller.sh

In Claude Code:

/lex-tick      # einen Tick manuell auslösen
/lex-status    # Heartbeat + Queue-Status
/lex-review    # Vorschläge interaktiv durchsehen + freigeben
/lex-sync      # Historie aktualisieren

Im DRY_RUN-Modus landen alle Vorschläge in data/lex_state.db → Tabelle review_queue. Nichts wird in Lexware geschrieben.

Cron einrichten (Automatik)

bash scripts/install_cron.sh

Installiert drei Einträge in deiner User-Crontab:

  • */15 * * * * → Tick-Trigger
  • 0 */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 Lex-API-Call (Pfad, Status, Dauer; niemals Bodies/Secrets), jedes lex_propose_voucher/lex_commit_voucher/lex_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: LEX_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/lex_state.db

Strukturierte Aufzeichnung der Agent-Entscheidungen:

# Alle Aktionen heute
sqlite3 data/lex_state.db "SELECT ts, action, ref_type, ref_id, category_id, 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/lex_state.db "SELECT ts, ref_id, message FROM errors
  WHERE ts > datetime('now','-7 days')"

# Pending Review-Queue mit Konfidenz absteigend
sqlite3 data/lex_state.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 Lexware)
  • Inhalte der Markdown-Wissensbasis

Pilot-Phase und Aktivierung

  1. Woche 1-2: dry_run: true, alle Vorschläge täglich via /lex-review durchsehen. Konfidenzen tunen.
  2. Aktivierung: dry_run: false setzen, max_amount_auto_post: 500 als Anfangs-Cap.
  3. Schrittweise hochziehen: Cap erhöhen, sobald die committeten Buchungen seit 1 Woche fehlerfrei laufen.

Sicherheit

  • Belege bleiben in Lexware — werden nie ins lokale Repo gespiegelt.
  • GoBD-Trail: jede Aktion trägt eine justification (1-3 Sätze) im lokalen audit_log. Lexware Office hat keinen offenen Kommentar-Endpoint pro Voucher — die remark im Voucher selbst kann optional erweitert werden.
  • Idempotenz: SHA-256-Hash aus (voucher_id, category_id, amount, date) verhindert Doppel-Verbuchungen.
  • Notbremse: hard_max_postings_per_hour stoppt 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 lex_mcp__*-Tools nutzen — andere globale MCP-Server (n8n, Gmail, Drive etc.) sind in .claude/settings.json deny-gelistet.

Semantische Suche (RAG, optional)

Die statistische Contact-Kategorie-Map (contact_category_mapping) reicht für wiederkehrende Lieferanten/Kunden. Für Schreibvarianten, neue Contacts mit ähnlichem Pattern und ungewöhnliche Kategorien-Mappings macht ein semantisches Retrieval mehr Sinn — der Agent ruft dafür das Tool lex_search_similar(query, k=5) auf, das die Top-k ähnlichsten historischen Vouchers 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 intfloat/multilingual-e5-small 384 ~470 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:
LEX_EMBEDDING_BACKEND=local       # oder: voyage / openai
# bei voyage: VOYAGE_API_KEY=...
# bei openai: OPENAI_API_KEY=...
# Modell-Override optional via LEX_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 Vouchers automatisch mit-indexiert.

Was wird embedded? Pro Voucher der Text "{contact_name} | {voucher_type} | cat:{category_id} | <voucher-Felder wie remark/title>". Anpassbar in lex_mcp/embeddings_index.py:voucher_embed_text.

Wann hilft RAG? Erst ab ~100+ historischen Vouchers mit unterschiedlichen Pattern.

Wissensbasis pflegen

  • knowledge/categories.mdPflicht zu pflegen: Klartext-Mapping von Lexware-categoryIds zu Bedeutung. Nach erstem /lex-sync füllt der Agent IDs in category_catalog; die Klartext-Namen ergänzt du hier.
  • knowledge/regeln.md — eigene Buchungsregeln, z.B.:
- Notion, Linear, GitHub → categoryId <UUID> "Bürobedarf 19%"
- Bewirtung: separate Vouchers für 70%/30%-Anteile (siehe 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 Lexware API-Endpoint braucht zusätzliche Pflichtfelder lex_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/lex-agent.