---
type: skill
agent_ready: true
schema_version: 1
bundle_version: "0.28.0"
name: gmi-accountant
bundle_skill: true
scope: vault
default_active:
  allgemein: false
  business: true
depends_on:
  - getmyinvoices
conflicts_with: []
description: "Vorbereitender Finanzbuchhalter auf dem getmyinvoices-Skill. Findet unbearbeitete Belege, extrahiert Pflichtfelder aus PDFs, dispatcht bei Bedarf einen Critic und schreibt validierte Felder mit Audit-Stempel zurück. Einsetzen wenn 'gmi-accountant', 'buchhaltung machen', 'belege abarbeiten', 'batch buchhaltung', 'rechnungen prüfen' oder 'pflichtfelder ergänzen' erwähnt wird."
tags:
  - skill
  - buchhaltung
  - gmi-accountant
  - api-consumer
  - business
created: 2026-05-16
updated: 2026-05-16
---

# gmi-accountant

Jede Buchungsregel wird per Critic-Subagent gegen SKR-JSONs validiert. Extraktion, Confidence-Gate, Audit-Stempel und Re-Read nach dem Schreiben sind kein Komfort, sondern Pflicht. Der Skill übergibt die Kontrolle erst, wenn alle Pflichtfelder belegt und geprüft sind.

Der Skill ist API-Konsument: er besitzt keinen eigenen HTTP-Client, sondern importiert `GmiClient` und `GmiHttpError` aus dem `getmyinvoices`-Bundle-Skill über den Cross-Skill-Resolver. Ohne installierten `getmyinvoices`-Skill ist `gmi-accountant` nicht funktionsfähig.

## Abgrenzung

**Nutze diesen Skill** für Batch-Vorgänge: Belege abarbeiten, Pflichtfelder automatisch ergänzen, Critic-Prüfung, Tag-Ampel setzen, Audit-Stempel im Notizfeld pflegen, Bericht über einen Lauf erzeugen.

**Nimm stattdessen einen anderen Skill** bei: einzelnen Rechnungen abrufen oder filtern (→ [getmyinvoices](../getmyinvoices/SKILL.md)), API-Konfiguration, Stammdatenpflege, Bank-Transaktionen oder generellen Wissensfragen zur GMI-Spec.

## Abhängigkeit von getmyinvoices

`gmi-accountant` deklariert `depends_on: [getmyinvoices]` und importiert zwei Symbole aus `.skills/getmyinvoices/gmi_client.py`:

- `GmiClient` — der HTTP-Client mit X-API-KEY-Auth und Paginier-Helfer
- `GmiHttpError` — Exception-Klasse für API-Fehler, mit `.status` und `.code`-Attributen

Der Import läuft über `_lib/cross_skill.import_helper("getmyinvoices", "gmi_client", bundle_root=...)`. Fehlt der `getmyinvoices`-Skill, bricht `gmi_bridge.py` mit einer klaren `FileNotFoundError`-Meldung ab (Exit ungleich 0). Exportiert `gmi_client.py` nur einen Teil der erwarteten Symbole (z.B. nur `GmiHttpError`, kein `GmiClient`), wird ein `ImportError` mit Hinweis-Text erhoben.

Für Tests kann der Bundle-Root via Umgebungsvariable `BUNDLE_ROOT` oder CLI-Argument `--bundle-root` auf ein Test-Verzeichnis gesetzt werden, damit Eval-Fixtures isoliert arbeiten können.

## Sekret-Hygiene

`gmi-accountant` greift mittelbar auf den GMI-API-Key zu. Drei Regeln gelten ohne Ausnahme:

- **`GETMYINVOICES_API_KEY` darf NICHT in Logs, Berichten oder dem Lauf-Log auftauchen.** Der Workflow loggt höchstens die Existenz und die Länge des Keys (Validierungs-Smoke), niemals den Wert.
- **`EnvVarMissingError` fangen, ohne den Wert weiterzureichen.** Wenn die Env-Var fehlt, gibt der onboarding-Workflow eine Anleitung auf stderr aus und endet mit Exit-Code 2. Der Exception-Inhalt enthält per Vertrag aus `_lib/env_loader.require_env_var` niemals den Var-Wert, aber der Skill darf den Fehler auch nicht selbst rohem stderr durchreichen ohne `try/except`-Filter.
- **`fileContent` (base64-PDF) darf niemals in JSON-Output, stdout oder Lauf-Log.** Die Bridge-Helfer entfernen `fileContent` rekursiv aus jedem API-Response. Der download-Workflow schreibt PDF-Bytes direkt auf Disk, nicht durch Python-Returns.

`.env`-Dateien werden weder angelegt noch gelesen. Der Key kommt ausschließlich aus der Windows-Benutzer-Env-Var oder dem POSIX-Shell-Env.

### Setup-Anweisung für den API-Key

`GETMYINVOICES_API_KEY` muss vor dem ersten onboarding-Lauf gesetzt sein. Drei unterstützte Wege:

```bash
# Windows (PowerShell, persistente User-Env-Var):
setx GETMYINVOICES_API_KEY "<dein-key>"
# Neue Terminal-Session öffnen, damit setx greift.

# POSIX (Bash/Zsh, persistent via Profile):
echo 'export GETMYINVOICES_API_KEY="<dein-key>"' >> ~/.profile
source ~/.profile

# 1Password CLI (empfohlen für Multi-Mandant-Setups):
op item get "GetMyInvoices API" --fields api_key | \
  xargs -I {} setx GETMYINVOICES_API_KEY "{}"   # Windows
# bzw. via op inject in einem Shell-Wrapper für POSIX
```

Der Key wird beim ersten `onboarding`-Aufruf gegen einen `getCompanyList`-Smoke geprüft. Bei fehlender oder ungültiger Env-Var endet onboarding mit Exit-Code 2 plus Setup-Hinweis. Wert nie in Skill-Logs oder Berichten echoen — Sekret-Hygiene-Regeln oben.

## Workflows

Sechs Workflows unter `.skills/gmi-accountant/workflows/`. Direkter Aufruf per Python ohne Wrapper-Skript:

```bash
python .skills/gmi-accountant/workflows/<mode>.py [args]
```

### 1. onboarding — Env-Var und API-Verbindung prüfen

```bash
python .skills/gmi-accountant/workflows/onboarding.py
```

Prüft, ob `GETMYINVOICES_API_KEY` gesetzt ist (über `_lib/env_loader.require_env_var`), baut einen `GmiClient` und ruft `getCompanyList` mit `limit=1` als Smoke-Test.

- Exit 0: Env-Var vorhanden und API erreichbar
- Exit 2: Env-Var fehlt oder API-Antwort nicht ok (Setup-Anleitung in stderr)
- Exit 3: Konfigurations-Fehler

Optionales Argument `--mandant <name>` ist akzeptiert, wird im MVP nur als Lauf-Log-Prefix verwendet (keine Multi-Mandanten-Logik).

### 2. trigger — unbearbeitete Belege finden

```bash
python .skills/gmi-accountant/workflows/trigger.py [--limit N] [--single UID]
```

Filtert `getDocumentList` nach drei Kriterien: `isArchived=false`, kein blockierender Tag (`agent-done`, `agent-skip`, `agent-review`, `agent-compliance-hold`), mindestens ein Pflichtfeld fehlt oder alle vorhanden. Pflichtfeld-Liste kommt aus skill-lokalem `pflichtfelder.json` (vom Setup-Agent aus Template kopiert).

Jeder Treffer bekommt ein `mode`-Feld:

- `extract` — Pflichtfeld fehlt, Beleg muss durch den extract-Pfad (PDF-Read, Felder schreiben)
- `verify` — alle Pflichtfelder gefüllt, Beleg geht den verify-Pfad (nur Tag plus Audit-Stempel)

`enable_verify_mode: false` zwingt alle Belege in den extract-Pfad.

### 3. download — PDF in Temp-Ordner laden

```bash
python .skills/gmi-accountant/workflows/download.py --uid <uid> [--target <pfad>]
```

Lädt das PDF nach `tempfile.gettempdir()/gmi-accountant/<uid>.pdf` (Default-Target). Liefert JSON mit `pdf_path` und `ocr_metadata`. **`fileContent` ist garantiert NICHT im JSON.**

### 4. write — Felder schreiben, Re-Read, Tag, Stempel

```bash
python .skills/gmi-accountant/workflows/write.py --uid <uid> --fields-file <pfad> [--tag agent-done] [--dry-run]
```

Schreibt die extrahierten Pflichtfelder via `updateDocument`, liest sie via `getDocumentList`-Helper zurück (nicht `getOneDocument`, weil das gegen das Per-UID-Daily-Limit zählt) und prüft auf silently_dropped. Setzt den Status-Tag exklusiv und hängt einen Audit-Stempel ins Notizfeld an. Bei silently_dropped wird der Tag automatisch auf `agent-review` umgestellt.

### 5. verify — nur Tag plus Stempel, keine Feld-Änderung

```bash
python .skills/gmi-accountant/workflows/verify.py --uid <uid> --critic-file <pfad> [--dry-run]
```

Pfad für Belege im verify-Modus: GMI-OCR hat alle Pflichtfelder bereits gesetzt, der Agent bestätigt nur Critic-Ergebnis. Setzt `agent-done` bei `passed: true`, `agent-review` sonst.

### 6. report — Lauf-Log zu Bericht formatieren

```bash
python .skills/gmi-accountant/workflows/report.py --runfile <pfad-zur-jsonl> [--format markdown|json] [--quiet]
```

Liest die JSONL-Datei eines Laufs und formatiert die Belege als Markdown-Tabelle (Default) oder JSON. Jede Zeile bekommt einen klickbaren `[PDF](file://...)`-Link.

## Tag-Ampel

| Tag | Bedeutung |
|---|---|
| keine Tags | Agent hat den Beleg noch nicht gesehen — läuft beim nächsten trigger durch |
| `agent-skip` | Der Nutzer hat den Beleg ausdrücklich vom Agent-Workflow ausgenommen |
| `agent-done` | Agent war durch, alle Pflichtfelder gesetzt UND Critic positiv (bei Confidence-Gate-Treffer). Nichts mehr zu tun. |
| `agent-review` | Agent ist sich unsicher (silently_dropped, Critic-Fail, Mehrdeutigkeit). Manuelle Prüfung nötig. |
| `isArchived=true` | GMI-seitig endgültig fertig, Hände weg |

Die Tag-Ampel ist Bundle-Standard ab v0.10.0. Erweiterungen (z.B. `agent-compliance-hold`) gehören in spätere v0.10.x-Wellen.

## Audit-Stempel-Format

Jeder schreibende Workflow hängt einen Audit-Stempel ins Notizfeld:

```
[Agent v1, 2026-05-16 14:23] Ergaenzt: documentNumber, documentDate. Critic: pass.
```

`v1` ist die Bundle-Format-Version, eingefroren ab Bundle 0.10.0. Die Bundle-Format-Version ist NICHT dieselbe wie die Skill-Version (`bundle_version` im Frontmatter). Änderungen am Stempel-Format erfordern einen Major-Bump auf `v2` mit dokumentierter Migration für bestehende Belege.

## Confidence-Gate

Der Critic wird dispatcht, wenn eine der zwei Bedingungen zutrifft:

- `grossAmount` über `critic_threshold_gross_eur` (Default 1000 EUR)
- Mindestens ein extrahiertes Feld hat `quote: null` (Extractor war unsicher)

**Serielle Degradierung (`features.codex_subagent_fallback: true`):** Steht kein Subagent-Dispatch zur Verfügung (z. B. unter Codex), wird das Confidence-Gate **nicht abgeschaltet**, sondern vom Hauptagenten selbst erfüllt. Bei einem Gate-Treffer (Betrag über Schwelle oder `quote: null`) führt der Hauptagent die Critic-Prüfung inline und seriell durch: er liest die SKR-JSONs selbst und validiert die Buchungsregel, statt einen Critic-Subagenten zu dispatchen. Das unterscheidet sich von `enable_critic: false`, das die Prüfung ganz überspringt und produktiv unsicher ist. Das Pflicht-Gate (>`critic_threshold_gross_eur` oder `quote: null`) bleibt also in beiden Codex- und Claude-Code-Läufen wirksam.

Bei `enable_critic: false` wird der Critic übersprungen. Maximal eine Refinement-Runde, also höchstens zwei Extraktions-Pässe.

## Feature-Flags

Konfigurierbar in `skill.config.yaml`:

| Schlüssel | Typ | Default | Wirkung |
|---|---|---|---|
| `features.enable_critic` | bool | `true` | Critic-Sub-Agent bei Confidence-Gate-Treffer |
| `features.enable_verify_mode` | bool | `true` | trigger emittiert `mode`-Feld, verify-Workflow verfügbar |
| `features.enable_dry_run_default` | bool | `false` | write/verify operieren ohne `--dry-run`-Flag im Dry-Run-Modus |
| `features.codex_subagent_fallback` | bool | `false` | Wenn `true`: kein Critic-Subagent-Dispatch; Gate bleibt aktiv, Hauptagent prüft inline und seriell (z. B. unter Codex) |
| `critic_threshold_gross_eur` | int | `1000` | Brutto-Schwelle für Critic-Dispatch (Top-Level, nicht unter features) |

Alle fünf Werte werden im Body dieser SKILL.md mindestens einmal namentlich erwähnt (Symmetrie-Vertrag für `skill_md_mentions_all_feature_flags`).

## Lauf-Log persistieren

Per Default schreibt der Workflow das JSONL-Lauf-Log nach `tempfile.gettempdir()/gmi-accountant/run-<timestamp>.jsonl` und löscht es nicht automatisch.

Wer das Lauf-Log persistent im Vault archivieren will, setzt in `skill.config.yaml`:

```yaml
paths:
  run_log_dir: "{logbuch}/A Buchhaltung"
```

Der Loader löst `{logbuch}` über `bundle.json.vault_layout` auf. Der Workflow erstellt das Zielverzeichnis bei Bedarf. Geheime Daten landen nicht im Lauf-Log (`fileContent` ist gefiltert, der API-Key taucht nirgends auf), aber die Belegnummern und Lieferanten-Namen sehr wohl — Persistenz ist eine bewusste Entscheidung.

## Nicht im Bundle (Vault-only Stand v0.10.0)

Folgende Funktionen sind im Vault-Skill vorhanden, aber bewusst NICHT im Bundle-MVP:

- Compliance-Checks (Empfänger-Validierung, GoBD-Pflichtangaben)
- Cashflow-Forecast
- Health-Score
- Anomalie-Erkennung
- supplier_fix (Company-Enrichment plus USt-ID-Validierung via BZSt/VIES)
- vies (EU-USt-ID-Prüfung)
- Kategorisierung (kat-* Tags, dynamische Kategorien)
- persistence (Multi-Mandanten-Mapping in einem Home-Verzeichnis-Verzeichnis)
- timer (Bearbeitungs-Stoppuhr)
- orphan-companies (verwaiste Companies löschen)
- batch-intelligence (preflight, Duplikat-Check, recurring)
- StB-Übergabepaket
- Skonto-Alarm
- Lieferanten-Intelligence (Spend-Analyse, Concentration Risk)
- doctype_fix (Dokumententyp-Korrektur)

Diese Module folgen als eigene v0.10.x-Wellen mit jeweils eigener Spec.

## Eval-Set

Eingefrorene Assertions unter `.skills/gmi-accountant/eval/gmi-accountant.eval.json`. Der Runner ist `run_evals.py` im Skill-Ordner, arbeitet mit `tempfile.TemporaryDirectory()`-Fixtures. Pass-Rate muss 100 Prozent sein.

```bash
PYTHONUTF8=1 python .skills/gmi-accountant/run_evals.py --verbose
```

## Verknüpfungen

- [[INDEX|INDEX.md]]
- [[AGENTS|AGENTS.md]]
- [getmyinvoices](../getmyinvoices/SKILL.md)
