Zum Inhalt springen

UIAP Workflow Extension

FeldWert
StatusDraft
Version0.1
Datum2026-03-27
Abhängigkeiten[UIAP-CORE], [UIAP-CAP], [UIAP-WEB], [UIAP-ACTION], [UIAP-POLICY]
EditorenPatrick

Die Schlüsselwörter MUSS, DARF NICHT, SOLLTE, KANN in diesem Dokument sind normativ gemäss RFC 2119 und BCP 14 zu interpretieren, wenn und nur wenn sie in GROSSBUCHSTABEN erscheinen.

UIAP Workflow Extension v0.1 definiert, wie eine Anwendung oder ein UIAP-kompatibler Agent mehrschrittige, semantische Abläufe beschreibt, startet, ausführt, pausiert, fortsetzt und beendet.

Die Extension ist für Dinge wie:

  • Onboarding-Flows
  • Guided Setup
  • wiederkehrende Produktaufgaben
  • Support-/Recovery-Abläufe
  • Mischformen aus Erklären, Zeigen, Eingeben und Hand-off

Sie baut auf diesen Teilen auf:

  • UIAP Core v0.1
  • UIAP Capability Model v0.1
  • UIAP Web Profile v0.1
  • UIAP Action Runtime Spec v0.1
  • UIAP Policy Extension v0.1

Die Workflow Extension definiert nicht:

  • wie DOM oder UI technisch gelesen werden
  • wie Actions technisch ausgeführt werden
  • wie Policy intern implementiert ist
  • wie ein LLM plant oder formuliert

Sie definiert den Vertrag für strukturierte Abläufe, nicht das Gehirn und nicht die Browsermechanik.


type ExtensionId = "uiap.workflow";
type ExtensionVersion = "0.1";

Eine Gegenstelle, die diese Extension anbietet, MUSS sie im Handshake deklarieren.

Beispiel:

{
"id": "uiap.workflow",
"versions": ["0.1"],
"required": false
}

  1. Ein Workflow MUSS als strukturierte, maschinenlesbare Definition vorliegen.
  2. Ein Workflow MUSS aus klaren Schritten bestehen.
  3. Ein Workflow DARF Actions nicht direkt „magisch“ ausführen, sondern MUSS dafür die Action Runtime verwenden.
  4. Ein Workflow MUSS Inputs, Bedingungen, Erfolgsdefinition und Recovery explizit modellieren.
  5. Ein Workflow MUSS pausierbar und fortsetzbar sein.
  6. Ein Workflow SOLLTE gegen UI-Drift robust sein, also nicht nur auf rohe Klickfolgen setzen.
  7. Ein Workflow DARF deklarativ sein, aber nicht beliebig. Sonst hat man am Ende eine Programmiersprache und nennt es aus Höflichkeit „Extension“.

Ein Workflow ist eine versionierte Definition eines fachlichen oder UX-seitigen Ablaufs.

Beispiele:

  • workspace.initial_setup
  • video.create_first_video
  • team.invite_member
  • billing.connect_payment_method

Eine Workflow Instance ist eine laufende oder pausierte Ausführung eines Workflows.

Ein Step ist ein einzelner ausführbarer oder prüfbarer Teil eines Workflows.

Ein Input ist ein benötigter Parameter, der von User, App, Kontext oder Ableitung kommen kann.

Ein Checkpoint ist ein deklarierter Wiederaufsetzpunkt.

Der Interaction Mode beschreibt, wie aktiv der Workflow handeln darf.

type WorkflowInteractionMode =
| "explain" // nur erklären
| "guide" // zeigen, highlighten, navigieren, aber nicht schreiben
| "assist" // sichere Eingaben / Entwürfe / reversible Schritte
| "auto"; // alle erlaubten Actions gemäß Policy

Der Start Mode beschreibt, wie ein Workflow initiiert wird.

type WorkflowStartMode =
| "manual" // explizit vom Nutzer gestartet
| "suggested" // vorgeschlagen, aber nicht automatisch gestartet
| "automatic"; // darf automatisch starten, sofern Policy es erlaubt

type WorkflowStatus =
| "validating"
| "running"
| "waiting_input"
| "waiting_confirmation"
| "waiting_user"
| "paused"
| "succeeded"
| "failed"
| "cancelled";
  • validating: Definition, Applicability, Inputs und Policy werden geprüft.
  • running: Workflow arbeitet aktiv Schritte ab.
  • waiting_input: Benötigte Werte fehlen.
  • waiting_confirmation: Bestätigung ist nötig.
  • waiting_user: Human Handoff oder User-Aktion erforderlich.
  • paused: bewusst unterbrochen, später fortsetzbar.
  • succeeded: erfolgreich abgeschlossen.
  • failed: beendet mit Fehler.
  • cancelled: durch Nutzer, Policy oder System beendet.

interface WorkflowCatalog {
modelVersion: "0.1";
extension: "uiap.workflow";
revision?: string;
workflows: WorkflowDefinition[];
metadata?: Record<string, unknown>;
}

interface WorkflowDefinition {
id: string;
version: string;
title: LocalizedText;
description?: LocalizedText;
category?: WorkflowCategory;
startMode?: WorkflowStartMode;
interactionModes: WorkflowInteractionMode[];
intents?: WorkflowIntent[];
triggers?: WorkflowTrigger[];
applicability?: WorkflowApplicability;
inputs?: WorkflowParameter[];
outputs?: WorkflowOutput[];
requiredGrants?: PolicyGrant[];
initialStepId: string;
steps: WorkflowStep[];
success?: WorkflowSuccessCriteria;
failure?: WorkflowFailurePolicy;
metadata?: Record<string, unknown>;
}
type WorkflowCategory =
| "onboarding"
| "setup"
| "task"
| "support"
| "education"
| "recovery"
| "custom";
type LocalizedText =
| string
| {
default: string;
byLocale?: Record<string, string>;
};
  1. id MUSS innerhalb eines Katalogs eindeutig sein.
  2. version MUSS für semantische Änderungen erhöht werden.
  3. initialStepId MUSS auf einen vorhandenen Step zeigen.
  4. Jeder Workflow MUSS mindestens einen terminalen complete- oder handoff-/failed-Pfad haben.
  5. Zyklische Abläufe SIND NUR zulässig, wenn sie explizit begrenzt sind, etwa über Retry-Limits.

interface WorkflowIntent {
phrases: string[];
locale?: string;
weight?: number; // default 1.0
}

Intents dienen dem Matching von Nutzerabsichten auf Workflows.

Beispiele:

{
"phrases": [
"hilf mir beim ersten video",
"erstes video anlegen",
"video erstellen"
],
"locale": "de-CH",
"weight": 1.0
}

type WorkflowTrigger =
| {
kind: "intent";
intents?: string[];
}
| {
kind: "route.entered";
routeIds: string[];
}
| {
kind: "first_run";
feature?: string;
}
| {
kind: "signal";
signalKinds: string[];
}
| {
kind: "custom";
name: string;
payload?: Record<string, unknown>;
};
  • Trigger beschreiben wann ein Workflow vorgeschlagen oder gestartet werden kann.
  • Ein Trigger allein DARF keinen Start erzwingen, wenn Policy oder Applicability entgegenstehen.

interface WorkflowApplicability {
routeIds?: string[];
scopeIds?: ScopeId[];
principalRoles?: string[];
requiredGrants?: PolicyGrant[];
requiredActions?: ActionId[];
conditions?: WorkflowCondition[];
}
  • Ein Workflow ist nur applicable, wenn alle gesetzten Applicability-Bedingungen erfüllt sind.
  • requiredActions MUSS gegen das Capability Model geprüft werden.
  • requiredGrants MUSS gegen die aktuelle Policy-/Principal-Lage geprüft werden.

interface WorkflowParameter {
name: string;
title?: LocalizedText;
description?: LocalizedText;
type: WorkflowValueType;
required?: boolean;
meaning?: string;
sensitive?: boolean;
sourceOrder?: WorkflowValueSource[];
default?: WorkflowValueExpr;
validation?: ParameterValidation[];
prompt?: LocalizedText;
bindTo?: ParameterBinding;
}
type WorkflowValueType =
| "string"
| "number"
| "boolean"
| "enum"
| "object"
| "array";
type WorkflowValueSource =
| "provided"
| "context"
| "route"
| "derive"
| "suggest"
| "user";
interface ParameterBinding {
stableIds?: StableId[];
actionArg?: string;
}
interface ParameterValidation {
kind: "required" | "minLength" | "maxLength" | "pattern" | "enum" | "custom";
value?: unknown;
message?: LocalizedText;
}
  1. sourceOrder definiert die Reihenfolge, in der Werte beschafft werden.
  2. provided meint Werte aus workflow.start.inputs.
  3. context meint Werte aus Session-, Route- oder App-Kontext.
  4. derive meint maschinenlesbare Ableitung aus aktuellem UI-/State-Kontext.
  5. suggest meint vom Agenten oder Template erzeugte Vorschläge.
  6. user meint explizit vom Nutzer gelieferte Werte.
  7. Sensitive Inputs SOLLTEN automatisch mit Policy- und Redaction-Regeln verknüpft werden.

interface WorkflowOutput {
name: string;
type: WorkflowValueType;
from: WorkflowValueExpr;
}

type WorkflowValueExpr =
| { from: "literal"; value: unknown }
| { from: "param"; name: string }
| { from: "route"; path: string }
| { from: "context"; path: string }
| { from: "actionResult"; stepId: string; path?: string }
| { from: "signal"; stepId?: string; kind?: string; path?: string };

Diese Ausdrücke werden für Action-Argumente, Defaults und Outputs verwendet.


interface WorkflowStepBase {
id: string;
type: WorkflowStepType;
title?: LocalizedText;
if?: WorkflowCondition[];
timeoutMs?: number;
checkpoint?: boolean;
next?: string;
onError?: WorkflowRecoveryRule[];
metadata?: Record<string, unknown>;
}
type WorkflowStepType =
| "instruction"
| "collect"
| "suggest"
| "action"
| "ensure"
| "branch"
| "handoff"
| "complete";
  • id MUSS innerhalb eines Workflows eindeutig sein.
  • Wenn if gesetzt ist und nicht erfüllt wird, gilt der Step als skipped und der Flow geht zu next oder zum lexikalisch nächsten Step.
  • checkpoint=true markiert einen potenziellen Resume-Punkt.
  • onError definiert step-lokale Recovery.

interface InstructionStep extends WorkflowStepBase {
type: "instruction";
text: LocalizedText;
presentation?: PresentationHints;
}
  • Reine Erklärung oder Einordnung.
  • Darf Overlay-/Narration-Hinweise enthalten.
  • Verändert keinen fachlichen Zustand.

interface CollectStep extends WorkflowStepBase {
type: "collect";
parameters: string[];
prompt?: LocalizedText;
allowPartial?: boolean;
autoAcceptIfResolved?: boolean;
}
  • Beschafft fehlende Parameter.
  • Prüft zuerst sourceOrder.
  • Falls danach noch Werte fehlen, geht der Workflow in waiting_input und sendet uiap.workflow.input.request.

interface SuggestStep extends WorkflowStepBase {
type: "suggest";
parameter: string;
source: "agent" | "template" | "app";
template?: string;
confirm?: "always" | "if_changed" | "never";
}
  • Erzeugt einen Vorschlagswert für genau einen Parameter.
  • Die konkrete Generierung ist Implementierungssache.
  • confirm="always" verlangt explizite Übernahme des Vorschlags.
  • confirm="never" ist nur für nicht-sensitive, reversible oder klar unkritische Fälle zu empfehlen.

interface WorkflowActionStep extends WorkflowStepBase {
type: "action";
actionId: ActionId;
target?: ActionTarget;
args?: Record<string, WorkflowValueExpr>;
preferredExecutionModes?: ExecutionMode[];
verification?: VerificationSpec;
presentation?: PresentationHints;
saveResultAs?: string;
}
  • Delegiert an die UIAP Action Runtime.
  • Policy MUSS vor Ausführung geprüft werden.
  • saveResultAs speichert strukturierte Rückgabedaten für spätere Steps.

interface EnsureStep extends WorkflowStepBase {
type: "ensure";
conditions: WorkflowCondition[];
policy?: "all" | "any";
waitFor?: boolean;
pollMs?: number;
}
  • Prüft Bedingungen.

  • Wenn waitFor=true, DARF auf Eintreten der Bedingungen gewartet werden.

  • Typische Verwendungen:

    • „Dialog ist offen“
    • „Route ist gewechselt“
    • „Toast wurde gezeigt“
    • „Feld ist nicht mehr invalid“

interface BranchStep extends WorkflowStepBase {
type: "branch";
branches: Array<{
when: WorkflowCondition[];
next: string;
}>;
otherwise?: string;
}
  • Prüft Branches in deklarierter Reihenfolge.
  • Der erste passende Branch gewinnt.
  • Wenn kein Branch passt, wird otherwise genutzt.
  • Fehlt otherwise, MUSS der Workflow fehlschlagen.

interface HandoffStep extends WorkflowStepBase {
type: "handoff";
reason: LocalizedText;
message?: LocalizedText;
resumeWhen?: WorkflowCondition[];
}
  • Erzwingt Nutzerübernahme oder externen Eingriff.
  • Der Workflow wechselt in waiting_user.
  • Fortsetzung erfolgt über workflow.resume, workflow.input.provide oder durch erfüllte resumeWhen-Bedingungen.

Typische Fälle:

  • Login / Re-Auth
  • CAPTCHA
  • Zahlungsfreigabe
  • juristische Bestätigung
  • Browser- oder Plattformgrenzen

interface CompleteStep extends WorkflowStepBase {
type: "complete";
summary?: LocalizedText;
outputs?: Record<string, WorkflowValueExpr>;
}
  • Finalisiert den Workflow.
  • Setzt Status auf succeeded, sofern keine globalen Success-Regeln verletzt sind.
  • Liefert Outputwerte zurück.

type WorkflowCondition =
| { kind: "param.present"; name: string }
| { kind: "param.equals"; name: string; value: unknown }
| { kind: "route.is"; routeId: string }
| { kind: "scope.present"; scopeId: ScopeId }
| { kind: "element.present"; target: TargetRef }
| { kind: "element.state"; target: TargetRef; state: Partial<UIState> }
| { kind: "signal.observed"; signal: SuccessSignal }
| { kind: "action.status"; stepId: string; status: "succeeded" | "failed" | "cancelled" }
| { kind: "policy.effect"; effect: PolicyEffect }
| { kind: "custom"; name: string; args?: Record<string, unknown> };
  • Conditions MÜSSEN deterministisch auswertbar sein.
  • custom ist erlaubt, aber nur für Implementierungen, die es kennen.
  • Unbekannte custom-Conditions DÜRFEN nicht stillschweigend als wahr gelten.

interface WorkflowSuccessCriteria {
policy?: "all" | "any";
conditions?: WorkflowCondition[];
signals?: SuccessSignal[];
}

Ein Workflow ist erfolgreich, wenn:

  1. ein complete-Step erreicht wurde, und
  2. globale Success-Kriterien erfüllt sind, sofern definiert.

interface WorkflowFailurePolicy {
onUnhandledError: "fail" | "handoff" | "cancel";
maxWorkflowRetries?: number;
resumable?: boolean;
}

interface WorkflowRecoveryRule {
on: WorkflowFailureMatcher;
strategy: "retry_step" | "goto_step" | "handoff" | "cancel" | "fail";
gotoStepId?: string;
maxAttempts?: number;
note?: LocalizedText;
}
interface WorkflowFailureMatcher {
runtimeCodes?: string[];
verificationFailed?: boolean;
timeout?: boolean;
policyEffects?: PolicyEffect[];
statuses?: Array<"failed" | "cancelled">;
}
  • Recovery wird step-lokal vor globaler Failure Policy ausgewertet.
  • Nicht-idempotente Actions DÜRFEN NICHT blind per retry_step wiederholt werden, wenn sideEffectState="unknown" war.
  • goto_step MUSS auf einen vorhandenen Step zeigen.
  • maxAttempts begrenzt lokale Wiederholungen.

interface WorkflowInstance {
instanceId: string;
workflowId: string;
workflowVersion: string;
status: WorkflowStatus;
mode: WorkflowInteractionMode;
currentStepId?: string;
completedStepIds: string[];
inputs: Record<string, unknown>;
outputs?: Record<string, unknown>;
checkpoint?: WorkflowCheckpoint;
history?: WorkflowHistoryEntry[];
metadata?: Record<string, unknown>;
}
interface WorkflowCheckpoint {
checkpointId: string;
stepId: string;
createdAt: string;
}
interface WorkflowHistoryEntry {
stepId: string;
status: "started" | "skipped" | "succeeded" | "failed" | "cancelled";
startedAt?: string;
finishedAt?: string;
note?: string;
}

interface WorkflowGetPayload {
category?: WorkflowCategory;
ids?: string[];
}
interface WorkflowDocumentPayload {
catalog: WorkflowCatalog;
}

Dient zum Matching von Nutzerintention und aktuellem Kontext auf Workflow-Kandidaten.

interface WorkflowMatchPayload {
intent?: string;
routeId?: string;
mode?: WorkflowInteractionMode;
maxResults?: number;
}
interface WorkflowMatchCandidate {
workflowId: string;
score: number;
reason?: string;
missingInputs?: string[];
blockedByPolicy?: boolean;
}
interface WorkflowMatchesPayload {
candidates: WorkflowMatchCandidate[];
}
  • score SOLLTE zwischen 0 und 1 liegen.
  • blockedByPolicy=true bedeutet: fachlich passend, aber derzeit nicht startbar.

interface WorkflowStartPayload {
workflowId: string;
mode?: WorkflowInteractionMode;
inputs?: Record<string, unknown>;
resumeFromCheckpointId?: string;
}
interface WorkflowStartedPayload {
instance: WorkflowInstance;
}
  • Der Workflow MUSS existieren.
  • Applicability MUSS erfüllt sein.
  • mode MUSS im Workflow erlaubt sein.
  • Policy DARF Start verhindern oder auf confirm/handoff setzen.

interface WorkflowProgressPayload {
instanceId: string;
workflowId: string;
status: WorkflowStatus;
currentStepId?: string;
currentStepType?: WorkflowStepType;
completedStepIds?: string[];
missingInputs?: string[];
note?: string;
checkpointId?: string;
}
  • Progress SOLLTE bei jedem Statuswechsel und jedem Stepwechsel emittiert werden.

interface WorkflowInputRequestPayload {
instanceId: string;
parameters: WorkflowParameter[];
prompt?: LocalizedText;
}

interface WorkflowInputProvidePayload {
instanceId: string;
values: Record<string, unknown>;
}
interface WorkflowInputAcceptedPayload {
instanceId: string;
accepted: string[];
rejected?: Array<{
name: string;
reason: string;
}>;
}

interface WorkflowPausePayload {
instanceId: string;
reason?: string;
}
interface WorkflowPausedPayload {
instanceId: string;
status: "paused";
}

interface WorkflowResumePayload {
instanceId: string;
}
interface WorkflowResumedPayload {
instanceId: string;
status: "running";
currentStepId?: string;
}

interface WorkflowCancelPayload {
instanceId: string;
reason?: string;
}
interface WorkflowCancelledPayload {
instanceId: string;
status: "cancelled";
}

interface WorkflowResultPayload {
instanceId: string;
workflowId: string;
status: "succeeded" | "failed" | "cancelled";
outputs?: Record<string, unknown>;
finalStepId?: string;
error?: {
code: string;
message: string;
};
summary?: LocalizedText;
}

interface WorkflowChangedPayload {
revision: string;
catalog: WorkflowCatalog;
}

Beim Start MUSS der Executor:

  1. Workflow finden
  2. Applicability prüfen
  3. Interaction Mode prüfen
  4. initiale Inputs übernehmen
  5. Inputs gegen Schema validieren
  6. Start-Policy prüfen
  7. Instance erzeugen
  8. bei Erfolg uiap.workflow.started senden

Wenn ein Schritt davon scheitert, MUSS der Start mit Fehler enden.


Die Abarbeitung beginnt bei initialStepId.

Für jeden Step gilt:

  1. if prüfen
  2. Falls if=false: Step überspringen
  3. Step ausführen
  4. Erfolg, Fehler oder Handoff behandeln
  5. Nächsten Step bestimmen

Wenn next gesetzt ist, MUSS es verwendet werden. Wenn next fehlt, SOLLTE der lexikalisch nächste Step im Workflow verwendet werden. branch bestimmt den nächsten Step selbst. complete beendet den Workflow.


  • erzeugt höchstens Erklärung/Präsentation
  • geht direkt weiter
  • löst fehlende Inputs auf
  • geht bei fehlenden Pflichtwerten in waiting_input
  • berechnet Vorschlag
  • bestätigt oder übernimmt je nach confirm
  • delegiert an action.request
  • spiegelt Action-Runtime-Status im Workflow-Status
  • übernimmt Resultat in History und optional in saveResultAs
  • evaluiert Bedingungen
  • wartet optional
  • scheitert bei Timeout oder Nichterfüllung
  • bestimmt Pfad
  • wenn nichts passt und otherwise fehlt: Fehler
  • setzt waiting_user
  • Fortsetzung nur nach Resume oder erfüllten Bedingungen
  • finalisiert Outputs
  • prüft globale Success-Kriterien
  • sendet workflow.result

Vor jeder action-Ausführung MUSS Policy evaluiert werden.

Regeln:

  • allow → Step darf weiterlaufen
  • confirm → Workflow MUSS in waiting_confirmation gehen
  • deny → Step schlägt fehl
  • handoff → Workflow MUSS in waiting_user gehen

Ein Workflow DARF außerdem eine strengere eigene Interaktionslogik haben als die aktuelle Policy, aber nie eine lockerere.

Beispiel: Ein Workflow im Modus guide DARF trotz allow keine schreibenden Actions ausführen.


Wenn ein Step checkpoint=true hat, SOLLTE nach erfolgreichem Abschluss ein Checkpoint erzeugt werden.

Ein Resume MUSS:

  • den letzten gültigen Checkpoint laden oder
  • den angegebenen resumeFromCheckpointId verwenden

Ein Resume DARF nicht vor einen nicht abgeschlossenen, potenziell nicht-idempotenten Side-Effect zurückspringen, ohne dass die Implementierung dessen Zustand sicher kennt. Menschen nennen so etwas sonst später „Datenproblem“.


Eine konforme [email protected]-Implementierung MUSS:

  • uiap.workflow.get
  • uiap.workflow.start
  • uiap.workflow.progress
  • uiap.workflow.input.request
  • uiap.workflow.input.provide
  • uiap.workflow.pause
  • uiap.workflow.resume
  • uiap.workflow.cancel
  • uiap.workflow.result

unterstützen.

Sie MUSS außerdem mindestens diese Step-Typen unterstützen:

  • instruction
  • collect
  • action
  • branch
  • handoff
  • complete

Sie SOLLTE zusätzlich unterstützen:

  • ensure
  • suggest

{
"id": "video.create_first_video",
"version": "0.1.0",
"title": {
"default": "Erstes Video erstellen",
"byLocale": {
"de-CH": "Erstes Video erstellen"
}
},
"description": "Führt den Nutzer durch das Anlegen des ersten Videos.",
"category": "onboarding",
"startMode": "suggested",
"interactionModes": ["guide", "assist", "auto"],
"intents": [
{
"phrases": [
"hilf mir beim ersten video",
"erstes video erstellen",
"video anlegen"
],
"locale": "de-CH",
"weight": 1
}
],
"applicability": {
"routeIds": ["dashboard", "videos", "videos.new"],
"requiredActions": [
"nav.navigate",
"ui.enterText",
"ui.activate",
"video.create"
]
},
"inputs": [
{
"name": "title",
"title": "Videotitel",
"type": "string",
"required": true,
"meaning": "title",
"sourceOrder": ["provided", "user"],
"prompt": "Wie soll dein erstes Video heissen?"
},
{
"name": "useCase",
"title": "Anwendungszweck",
"type": "string",
"required": false,
"meaning": "use_case",
"sourceOrder": ["provided", "suggest", "user"],
"prompt": "Wofür soll das Video verwendet werden?"
}
],
"outputs": [
{
"name": "videoId",
"type": "string",
"from": {
"from": "actionResult",
"stepId": "create_video",
"path": "id"
}
}
],
"initialStepId": "intro",
"steps": [
{
"id": "intro",
"type": "instruction",
"text": "Ich helfe dir, dein erstes Video anzulegen.",
"next": "collect_title"
},
{
"id": "collect_title",
"type": "collect",
"parameters": ["title"],
"next": "suggest_use_case"
},
{
"id": "suggest_use_case",
"type": "suggest",
"parameter": "useCase",
"source": "agent",
"confirm": "if_changed",
"next": "go_to_form"
},
{
"id": "go_to_form",
"type": "action",
"actionId": "nav.navigate",
"args": {
"routeId": {
"from": "literal",
"value": "videos.new"
}
},
"checkpoint": true,
"next": "fill_title"
},
{
"id": "fill_title",
"type": "action",
"actionId": "ui.enterText",
"target": {
"ref": {
"by": "stableId",
"value": "video.title"
}
},
"args": {
"text": {
"from": "param",
"name": "title"
}
},
"next": "branch_use_case"
},
{
"id": "branch_use_case",
"type": "branch",
"branches": [
{
"when": [
{
"kind": "param.present",
"name": "useCase"
}
],
"next": "fill_use_case"
}
],
"otherwise": "create_video"
},
{
"id": "fill_use_case",
"type": "action",
"actionId": "ui.enterText",
"target": {
"ref": {
"by": "stableId",
"value": "video.use_case"
}
},
"args": {
"text": {
"from": "param",
"name": "useCase"
}
},
"next": "create_video"
},
{
"id": "create_video",
"type": "action",
"actionId": "video.create",
"target": {
"ref": {
"by": "stableId",
"value": "video.submit"
}
},
"verification": {
"policy": "all",
"signals": [
{
"kind": "route.changed",
"pattern": "/videos/:id"
},
{
"kind": "toast.contains",
"text": "erstellt"
}
],
"timeoutMs": 10000,
"requireRevisionAdvance": true
},
"checkpoint": true,
"saveResultAs": "create_video_result",
"onError": [
{
"on": {
"policyEffects": ["handoff"]
},
"strategy": "handoff",
"note": "Bitte übernimm den Bestätigungsschritt selbst."
},
{
"on": {
"runtimeCodes": ["verification_failed"]
},
"strategy": "goto_step",
"gotoStepId": "verify_result"
}
],
"next": "verify_result"
},
{
"id": "verify_result",
"type": "ensure",
"conditions": [
{
"kind": "signal.observed",
"signal": {
"kind": "route.changed",
"pattern": "/videos/:id"
}
}
],
"policy": "all",
"waitFor": true,
"timeoutMs": 4000,
"next": "done"
},
{
"id": "done",
"type": "complete",
"summary": "Dein erstes Video wurde angelegt.",
"outputs": {
"videoId": {
"from": "actionResult",
"stepId": "create_video",
"path": "id"
}
}
}
],
"success": {
"policy": "all",
"signals": [
{
"kind": "route.changed",
"pattern": "/videos/:id"
}
]
},
"failure": {
"onUnhandledError": "handoff",
"maxWorkflowRetries": 0,
"resumable": true
}
}

{
"uiap": "0.1",
"kind": "request",
"type": "uiap.workflow.start",
"id": "msg_301",
"sessionId": "sess_123",
"ts": "2026-03-26T15:10:00.000Z",
"source": { "role": "agent", "id": "onboarding-agent" },
"payload": {
"workflowId": "video.create_first_video",
"mode": "assist",
"inputs": {
"title": "Produktdemo für Kunde A"
}
}
}

{
"uiap": "0.1",
"kind": "event",
"type": "uiap.workflow.progress",
"id": "msg_302",
"sessionId": "sess_123",
"ts": "2026-03-26T15:10:01.200Z",
"source": { "role": "bridge", "id": "web-runtime" },
"payload": {
"instanceId": "wf_991",
"workflowId": "video.create_first_video",
"status": "running",
"currentStepId": "fill_title",
"currentStepType": "action",
"completedStepIds": ["intro", "collect_title", "suggest_use_case", "go_to_form"],
"checkpointId": "cp_2"
}
}

{
"uiap": "0.1",
"kind": "event",
"type": "uiap.workflow.result",
"id": "msg_303",
"sessionId": "sess_123",
"ts": "2026-03-26T15:10:08.900Z",
"source": { "role": "bridge", "id": "web-runtime" },
"payload": {
"instanceId": "wf_991",
"workflowId": "video.create_first_video",
"status": "succeeded",
"outputs": {
"videoId": "vid_12345"
},
"finalStepId": "done",
"summary": "Dein erstes Video wurde angelegt."
}
}

Damit das in echten Produkten nicht nach der dritten UI-Änderung stirbt, würde ich diese Regeln als quasi-verbindlich behandeln:

  1. Workflows zuerst deklarativ, nicht promptbasiert Prompts dürfen Formulierungen liefern, aber nicht die einzige Wahrheit über Ablauf und Erfolg sein.

  2. Action Steps nur über Runtime Kein Workflow-Step darf die UI direkt „irgendwie“ verändern, ohne über Action Runtime und Policy zu gehen.

  3. Use Cases in Pakete schneiden Lieber 20 kleine, belastbare Workflows als 3 allwissende Monsterabläufe.

  4. Checkpoints nach Seiteneffekten Besonders nach app.invoke, submit, create, delete, publish.

  5. Guide/Assist/Auto strikt trennen Sonst wird aus „zeigen” plötzlich „versehentlich abgesendet”.


  • [UIAP-CORE] UIAP Core v0.1
  • [UIAP-CAP] UIAP Capability Model v0.1
  • [UIAP-WEB] UIAP Web Profile v0.1
  • [UIAP-ACTION] UIAP Action Runtime v0.1
  • [UIAP-POLICY] UIAP Policy Extension v0.1
  • [RFC2119] Key words for use in RFCs to Indicate Requirement Levels, BCP 14
  • Workflow-Definitionen SOLLTEN nur von vertrauenswürdigen Quellen geladen werden.
  • Workflows DÜRFEN Policy-Entscheidungen nicht umgehen; jeder Schritt MUSS individuell gegen die Policy geprüft werden.
  • Recovery-Mechanismen MÜSSEN sicherstellen, dass teilweise ausgeführte Workflows keine inkonsistenten Zustände hinterlassen.
  • Workflow-Variablen KÖNNEN sensitive Daten enthalten und SOLLTEN im Audit-Log redaktiert werden.
VersionDatumÄnderungen
0.12026-03-27Initialer Entwurf