# bmad-plus uat

> Referenz zu bmad-plus uat (Alias recette): lint, build, serve, import, read, gate und order für menschliche Abnahmeprotokolle, mit Optionen, Exit-Codes und Beispielausgaben.

Canonical: https://bmad-plus.rochetta.fr/de/docs/reference/cli-uat/
Language: de
BMAD+ version: 0.23.1
Documentation reviewed: 2026-10-19
Author: Laurent Rochetta
License: MIT

BMAD+ Dokumentation › [Referenz](https://bmad-plus.rochetta.fr/de/docs/reference/) › bmad-plus uat

`bmad-plus uat` (Alias `bmad-plus recette`) steuert menschliche Abnahmeprotokolle. Ein Protokoll (französisch recette) ist eine JSON-Spezifikation von Schritten, die eine Person am Bildschirm durchspielt. Der Befehl prüft die Spezifikation, baut eine eigenständige HTML-Seite für die testende Person, speichert deren Antworten als JSON-Lauf, listet die Fehler auf und leitet daraus ein Gate-Urteil ab. Du brauchst ihn, wenn eine Lieferung von einem Menschen funktionierend gesehen werden muss und nicht nur von Tests. Sentinel bedient ihn für dich; du nutzt ihn, um den Ablauf zu skripten, einen CI-Schritt anzubinden oder zu prüfen, was der Agent behauptet.

> **Hinweis · Was das Gate beweist und was nicht** Das Gate stellt fest, dass ein Lauf beendet, aktuell, vollständig beantwortet und triagiert ist. Es stellt nie fest, dass die testende Person an der richtigen Stelle geschaut hat; deshalb trägt jedes Urteil das Etikett „human-observed“. Ein Gate mit passed kann trotzdem auf Fehlern ruhen: Sie müssen nur klassifiziert sein, jeder mit einer Entscheidung.

<a id="synopsis"></a>
## Synopsis

**Im Terminal deines Projekts**

```sh
npx bmad-plus uat <action> [target] [options]
npx bmad-plus recette <action> [target] [options]
```

`action` ist eine der sieben Aktionen unten. `target` ist die ID eines Protokolls (der Befehl sucht `<dir>/specs/<id>.json`, danach jede Spezifikation in diesem Ordner mit passender `id`) oder der Pfad einer `.json`-Datei. `order` braucht kein Ziel.

**Die sieben Aktionen**

| Aktion | Was sie tut | Schreibt |
| --- | --- | --- |
| `lint` | Prüft die Spezifikation: Schema, unbekannte Schlüssel, Markup, IDs von Schritten und Erwartungen, Zeugen, das Budget von 15 Schritten / 30 Minuten. Mit `--src` wird geprüft, dass jede zitierte Bildschirmbeschriftung in einer Quelldatei vorkommt. | nichts |
| `build` | Führt zuerst das Lint aus, bricht bei jedem Fehler ab und schreibt dann die Seite für die testende Person. | `<dir>/pages/uat-<id>.html` |
| `serve` | Liefert die gebaute Seite auf 127.0.0.1 aus und speichert jede Antwort, die die Seite sendet. Läuft bis Strg+C. | `<dir>/results/<id>/<runId>.json` |
| `import` | Speichert ein von der Seite exportiertes Ergebnis-JSON (Datei oder Standardeingabe). | `<dir>/results/<id>/<runId>.json` |
| `read` | Listet jeden Lauf und jede fehlgeschlagene oder blockierte Erwartung mit Text und Notiz der testenden Person. | nichts |
| `gate` | Leitet das Urteil ab: passed, failed, awaiting oder stale. `--emit-check` schreibt zusätzlich einen eigenständigen Prüfer. | `<dir>/checks/gate-<id>.cjs` (nur mit `--emit-check`) |
| `order` | Berechnet die Spielreihenfolge aller Protokolle in `<dir>/specs` aus ihrem `after` und gemeinsamen Zeugen. | `<dir>/ORDER.md` |

**Optionen**

| Option | Argument | Standard | Wirkung |
| --- | --- | --- | --- |
| `-d, --directory` | `<path>` | aktuelles Verzeichnis | Projektverzeichnis. |
| `--dir` | `<path>` | `_bmad-output/uat` | Protokollordner im Projekt: `specs/`, `pages/`, `results/`, `triage/`, `checks/`. |
| `--src` | `<path>` | keiner | Quellordner, der nach Bildschirmbeschriftungen durchsucht wird (lint, build). Wiederholbar. |
| `--language` | `<code>` | siehe unten | Sprache der Seite: ein Code (`fr`), ein Name (`Français`) oder ein Locale-Tag. |
| `--input` | `<file>` | keiner | nur import: zu speichernde Ergebnisdatei; `-` liest die Standardeingabe. Für `import` Pflicht. |
| `--port` | `<number>` | `4173` | nur serve: Port, ausschließlich an 127.0.0.1 gebunden. |
| `--emit-check` | keiner | aus | nur gate: schreibt zusätzlich den Nexus-Prüfer `checks/gate-<id>.cjs`. |
| `--json` | keiner | aus | Maschinenlesbare Ausgabe mit `schemaVersion: 1`. |

Sprache der Seite in dieser Rangfolge: das Feld `language` des Protokolls, dann `--language`, dann das `communication_language` aus `_bmad/config.yaml`, zuletzt Englisch. Die Seite enthält immer die zehn Installer-Sprachen (en, fr, es, de, pt-br, ru, zh, he, ja, it); die testende Person kann auf der Seite wechseln.

<a id="reads-writes"></a>
## Was gelesen und geschrieben wird

- Liest: die Spezifikationen in `<dir>/specs` (abgelehnt über 4 MiB oder bei symbolischem Link), `_bmad/config.yaml` (nur build, für `communication_language`), die Ergebnisse in `<dir>/results/<id>/` und die Triage-Datei `<dir>/triage/<id>.json`.
- Mit `--src`: liest nur Quelldateien mit diesen Endungen: ts, tsx, js, jsx, mjs, cjs, vue, svelte, html, htm, php, py, rb, java, kt, cs, go, json, yaml, yml, md. Übersprungen werden symbolische Links, Punkt-Ordner, `node_modules`, `.git`, `dist`, `build`, `coverage`, `.next`, `.nuxt`, `vendor`, `__pycache__`, `.venv`, `venv`, `target` und `out`; Dateien über 512 KiB werden ignoriert, nach 20000 Dateien ist Schluss.
- Schreibt: nur die in der Tabelle oben genannten Dateien. Zugangsdaten-ähnliche Werte in einer Notiz werden vor dem Speichern eines Laufs durch `[REDACTED]` ersetzt (`import` und `serve`); der Lauf hält die Zahl der Ersetzungen in `redactions` fest.
- Netzwerk: keines, außer `serve`, das nur auf 127.0.0.1 lauscht. Die gebaute Seite fragt bei keiner anderen Origin etwas an. Wer auf einer anderen Maschine testet, nutzt die Seite als Datei oder Artefakt und schickt das JSON für `import` zurück.
- `serve` antwortet nur auf die Hostnamen `127.0.0.1:<port>` und `localhost:<port>` (jeder andere Host-Header erhält HTTP 403), weist einen Request-Body über 4 MiB ab und antwortet mit HTTP 409, wenn eine ältere Kopie eines Laufs eine neuere ersetzen würde.

<a id="gate-rules"></a>
## Wie das Gate entscheidet

Das Gate nimmt den zuletzt beendeten Lauf des Protokolls. Gibt es keinen, ist der Status awaiting. Hat dieser Lauf eine andere Revision der Spezifikation beantwortet (sein `specSha256` weicht ab), ist der Status stale. Sonst ist der Status failed, solange mindestens ein Grund unten zutrifft, und passed, wenn keiner zutrifft.

- Eine Erwartung wurde nie beantwortet (optionale Schritte werden übersprungen).
- Eine fehlgeschlagene oder blockierte Erwartung hat keinen Eintrag in `<dir>/triage/<id>.json`, ihre Klasse ist `undecided` oder ihre Entscheidung ist keine von `fix`, `amend-spec`, `remeasure`, `accept-risk`, `ask-tester`.
- Eine Entscheidung ist `accept-risk` ohne `decidedBy`.
- Eine Erwartung ist blockiert und die Entscheidung ist nicht `accept-risk`: Es wurde nichts beobachtet, also wiederholen oder das Risiko namentlich akzeptieren lassen.
- Ein Schritt mit `writes: true` ist bestanden, aber die Triage hat keinen `writeChecks`-Eintrag mit `verified: true` und einem `evidence`-Text: Ein Haken bei einem schreibenden Schritt ist eine Beobachtung, den Ausschlag gibt der schreibgeschützte Beleg.

**Triage-Vokabular**

| Klasse | Bedeutung | Übliche Entscheidung |
| --- | --- | --- |
| `product` | Der Bildschirm weicht von dem ab, was der Code anzeigen sollte. | `fix` |
| `recipe` | Der Bildschirm ist richtig, die Erwartung beschrieb ihn falsch. | `amend-spec` |
| `data` | Der Zeuge ist nicht mehr im angenommenen Zustand. | `remeasure` |
| `undecided` | Keine Notiz oder nicht zuordenbar: die testende Person fragen. Hält das Gate rot. | `ask-tester` |

<a id="exit-codes"></a>
## Exit-Codes

**Exit-Code je Aktion**

| Aktion | 0 | 1 | 2 | 3 |
| --- | --- | --- | --- | --- |
| `lint` | kein Fehler | mindestens ein Fehler oder jede Störung | - | - |
| `build` | Seite geschrieben | Lint-Fehler, Vorlage hat eine Garantie verloren oder jede Störung | - | - |
| `import` | Lauf gespeichert | jede Störung | - | - |
| `read` | Läufe gelesen, nichts fehlgeschlagen | eine fehlgeschlagene oder blockierte Erwartung oder jede Störung | noch kein Lauf (awaiting) | neuester Lauf beantwortet eine andere Revision (stale) |
| `gate` | passed | failed (oder jede Störung) | awaiting | stale |
| `order` | Reihenfolge geschrieben | ein Zyklus, keine Spezifikation im Ordner oder jede Störung | - | - |

Eine Störung ist jeder geworfene Fehler: unbekannte Aktion, fehlendes Ziel, Spezifikation nicht gefunden, unlesbare Datei, fehlendes `--input`. Sie gibt `uat: <message>` auf der Fehlerausgabe aus, mit `--json` `{"schemaVersion":1,"status":"error","message":...}`, und endet mit 1. Ein Release-Skript, das ein gescheitertes Gate (1) von einem nicht lauffähigen Gate unterscheiden muss, nutzt das Projekt-Gate `uat-release-gate.mjs`, das für den zweiten Fall den Code 4 ergänzt.

<a id="real-output"></a>
## Beispielausgaben

Der erste Block wurde mit der Beispielspezifikation nachgespielt, die im Skill `bmad-plus-uat` mitgeliefert wird; die Blöcke `read` und `gate` sind aus den Meldungsvorlagen des Befehls zusammengesetzt, als simuliert gekennzeichnet und verwenden die Fixture aus `tests/unit/uat-cli.test.js`. Dateizahlen, Größen und Hashes hängen von deinem Projekt ab.

**Ein Protokoll prüfen und bauen**

```text
$ npx bmad-plus uat lint example-1.0.0
example-1.0.0: 3 steps, 5 expectations, 8 on-screen labels
  no error
$ npx bmad-plus uat build example-1.0.0
/work/app/_bmad-output/uat/pages/uat-example-1.0.0.html — 3 steps, 83 KiB, spec a4a4850b284d
opens in English; the tester can switch to any of the 10 languages on the page
carries the 17 page guarantees: hidden-before-start, no-answer-before-run, verified-local-write, honest-save-status, save-on-every-change, restore-before-capabilities, newer-copy-wins, revision-guard, other-tab-notice, unreadable-draft-kept, progress-accessible, storage-explained, finished-is-not-accepted, unload-guard, utf8-and-escaped-diacritics, export-is-the-run, no-third-party-requests
$ npx bmad-plus uat lint example-1.0.0 --src src
example-1.0.0: 3 steps, 5 expectations, 8 on-screen labels
  error   step 0-setup: do: the label "Folders" is in no source file — copy it from the component, accents included or not
  error   step 1-nominal: where: the label "Technical" is in no source file — copy it from the component, accents included or not
# Vier weitere Fehler derselben Art folgen, und der Befehl endet mit 1: Hier ist `src` ein leerer Ordner, also wird keine Beschriftung der Spezifikation gefunden. `--src` muss auf die Ordner zeigen, die die Beschriftungen deiner Bildschirme wirklich enthalten.
```

Ausgabe eines echten Laufs. Quelle: Mit dem Paket 0.23.0 und der Beispielspezifikation des Skills bmad-plus-uat in einem Wegwerfprojekt nachgespielt; der Projektpfad ist durch /work/app ersetzt

**Einen Lauf lesen, dann das Gate abfragen** (Simuliert)

```text
$ npx bmad-plus uat read demo-1.0.0

■ Demo 1.0.0 — Sarah — 2026-09-16 08:00, finished
  1 passed · 1 failed · 0 blocked · 0 skipped · 0 to do   (_bmad-output/uat/results/demo-1.0.0/20260916-sarah-aaaa.json)
  ✗ 1-confirm/a (failed) — Confirm
      expectation: The line reads OPCO confirmed.
      seen instead: the line still reads OPCO to confirm
# Exit-Code 1: Es gibt einen Fehlschlag.
$ npx bmad-plus uat gate demo-1.0.0
demo-1.0.0: failed (run 20260916-sarah-aaaa by Sarah)
  - 1-confirm/a is failed and not triaged
# Exit-Code 1. Sobald der Fehlschlag in triage/demo-1.0.0.json eingestuft ist (Klasse product, Entscheidung fix), gibt derselbe Befehl „demo-1.0.0: passed ...“ aus und endet mit 0.
```

Beispielhafter Ablauf, nicht bei einem echten Lauf aufgezeichnet. Quelle: tools/cli/commands/uat.js (Vorlagen von read und gate); tests/unit/uat-cli.test.js (Fixture demo-1.0.0, Lauf 20260916-sarah-aaaa)

<a id="errors"></a>
## Fehler und was zu tun ist

**Von uat ausgegebene Meldungen**

| Meldung | Ursache | Was tun |
| --- | --- | --- |
| `uat: an id or a spec file is required` | Kein Ziel für eine Aktion, die eines braucht. | Gib die ID des Protokolls oder den Pfad der `.json`-Datei an. |
| `uat: no spec with the id "<id>" in <dir>/specs` | Keine Datei im Specs-Ordner trägt diese `id`. | Prüfe `--dir` und `--directory`; verglichen wird das Feld `id`, nicht nur der Dateiname. |
| `step <id>: ...` oder `unknown key at spec level: "<key>" ...` (als `error` gelistet) | Ein Tippfehler oder ein fehlendes Feld in der Spezifikation: unbekannte Schlüssel werden abgelehnt, nicht ignoriert. | Spezifikation korrigieren und `lint` erneut starten. |
| `the label "<text>" is in no source file` | Eine zitierte Bildschirmbeschriftung steht in keinem der mit `--src` angegebenen Ordner. | Beschriftung aus der Komponente kopieren, mit oder ohne Akzente. Ohne `--src` läuft diese Prüfung nicht. |
| `<id>: not built, N error(s)` | `build` führt das Lint aus und schreibt bei jedem Fehler keine Seite. | Die aufgelisteten Fehler beheben. |
| `the page template ... lost a guarantee — not built` | Die Seitenvorlage trägt eine der 17 Garantien nicht mehr. | BMAD+ neu installieren oder aktualisieren; die Vorlage nicht von Hand ändern. |
| `no page at <file> — run "bmad-plus uat build <id>" first` | `serve` braucht eine gebaute Seite. | `build` ausführen, dann `serve`. |
| `--input <file> or --input - is required` | `import` ohne `--input`. | Das exportierte JSON oder `-` für die Standardeingabe angeben. |
| `these results answer <a>, not <b>` | Der importierte Lauf gehört zu einem anderen Protokoll. | Mit der ID importieren, die er beantwortet. |
| `unsupported results schema: ...` oder `results without runId` | Die Datei ist kein von der Seite exportierter Lauf. | Erneut von der Seite exportieren oder den Artefakt-Export nutzen. |
| `<id>: no run yet` (Code 2) | Kein JSON in `<dir>/results/<id>/`. | Die Seite ausliefern oder verschicken, dann die Antworten mit `import` übernehmen. |
| `unknown action "<x>" (lint, build, serve, import, read, gate, order)` | Aktion falsch geschrieben. | Eine der sieben Aktionen verwenden. |

<a id="examples"></a>
## Beispiele

<a id="example-cli-uat-write-and-build"></a>
### Sentinel das Protokoll schreiben und bauen lassen

Eine Version ist bereit für die Testumgebung. Du möchtest eine Seite, die ein nicht technischer Kollege durchspielen kann.

**In deinem KI-Assistenten**

```text
Sentinel, schreibe das Abnahmeprotokoll für diese Lieferung auf unserer Testumgebung. Prüfe es mit lint gegen src, baue die Seite und sag mir, welche Schritte wirklich schreiben.
```

**Das solltest du erhalten** Sentinel schreibt die Spezifikation nach `_bmad-output/uat/specs/<id>.json`, führt `bmad-plus uat lint <id> --src src` aus und behebt, was gemeldet wird, und führt dann `bmad-plus uat build <id>` aus, das `_bmad-output/uat/pages/uat-<id>.html` schreibt und die Garantien der Seite auflistet. Du erhältst den Link oder die Datei, die Dauer und die Schritte mit `writes: true`, jeweils mit ihrer schreibgeschützten `verify`-Prüfung. Ist die CLI nicht verfügbar, sagt Sentinel das, statt zu behaupten, die Seite sei gebaut.

<a id="example-cli-uat-read-and-gate"></a>
### Lauf lesen, triagieren, Gate abfragen

Die testende Person hat die Seite beendet und das JSON zurückgeschickt.

**In deinem KI-Assistenten**

```text
Sentinel, importiere die Ergebnisdatei results.json für das Protokoll demo-1.0.0, lies den Lauf, klassifiziere jeden Fehler und sag mir, ob das Gate besteht.
```

**Das solltest du erhalten** Sentinel führt `uat import demo-1.0.0 --input results.json` aus, dann `uat read demo-1.0.0`, das jede fehlgeschlagene oder blockierte Erwartung mit Text und Notiz der testenden Person ausgibt. Für jede schreibt es Klasse und Entscheidung nach `_bmad-output/uat/triage/demo-1.0.0.json`, fragt dich, wenn eine Notiz den Fehler nicht erklärt (Klasse `undecided` hält das Gate rot), und berichtet zuletzt `uat gate demo-1.0.0` mit Status und Exit-Code (0 passed, 1 failed, 2 awaiting, 3 stale). Die Belege werden als human-observed gekennzeichnet.

**Das Gate in ein Release-Skript einbinden (Projekt-Gate aus templates/ kopiert)**

```sh
node scripts/uat-release-gate.mjs || exit 1
# deploy only below this line
```

Der Skill liefert zwei Projekt-Gates in `.agents/skills/bmad-plus-uat/templates/`: `uat-spec-present.mjs` schlägt fehl, wenn kein Protokoll die Version aus `package.json` nennt, und `uat-release-gate.mjs` führt `uat gate` mit der im Projekt installierten CLI aus (0 passed, 1 failed, 2 kein beendeter Lauf, 3 andere Revision, 4 das Gate konnte nicht laufen, was kein Bestehen ist).

**Siehe auch**

- [CLI-Überblick](https://bmad-plus.rochetta.fr/de/docs/reference/cli-overview/)
- [nexus: dauerhafte Läufe, die das Gate als Prüfung nutzen können](https://bmad-plus.rochetta.fr/de/docs/reference/cli-nexus/)
- [review: derselbe Belegansatz für Code-Reviews](https://bmad-plus.rochetta.fr/de/docs/reference/cli-review/)
- [Der uat-Block der config.yaml](https://bmad-plus.rochetta.fr/de/docs/reference/config-yaml/)
- [Fehlerbehebung](https://bmad-plus.rochetta.fr/de/docs/faq/troubleshooting/)

[BMAD+ Dokumentation](https://bmad-plus.rochetta.fr/de/docs/) · [Referenz](https://bmad-plus.rochetta.fr/de/docs/reference/)

[Quellcode auf GitHub](https://github.com/lrochetta/BMAD-PLUS)
