Fehler in Config Layer → DefaultConfig + Warning-Log Fehler in RuleEngine → allow: true + Error-Log Fehler in Hook Handler → allow: true + Error-Log Fehler in Custom Tool → Error-Response an User
ADR-008: Fail-Open Prinzip bei Hook-Fehlern
Status
Accepted
Context
Das Plugin operiert innerhalb des opencode-Prozesses. Wenn ein Plugin-Hook fehlschlägt (Crash, unerwarteter Fehler, Config-Bug), gibt es zwei grundsätzliche Strategien:
-
Fail-Open — Bei Fehler wird die Tool-Ausführung erlaubt (der Agent läuft weiter)
-
Fail-Closed — Bei Fehler wird die Tool-Ausführung blockiert (der Agent stoppt)
Das Problem: - Das Plugin ist ein steering tool, kein Sicherheitslayer - Ein blockierender Fehler würde die gesamte opencode-Session lahmlegen - Der User kann das Plugin nicht "ausschalten" wenn es crasht (ausser Neustart) - Gleichzeitig: Wenn das Plugin wegen eines Fehlers nicht blockt, obwohl es sollte, entsteht ein "silent ignore"-Problem
Die Frage: Reagieren wir bei Fehlern permissiv (allow) oder restriktiv (block)?
Alternatives Considered
Option A: Fail-Open (gewählt)
Bei jedem Fehler in einem Hook gibt das Plugin { allow: true } zurück (im neuen API: kein throw, tool läuft durch). Der Fehler wird geloggt.
Vorteile: - Workflow Continuity — Der Agent läuft immer weiter, auch bei Plugin-Fehlern - Graceful Degradation — Bei Teilausfällen laufen andere Contracts weiter - Debuggability — Fehler werden geloggt, können analysiert werden - Benutzerfreundlich — Kein "Plugin abgestürzt, Session tot"-Szenario
Nachteile: - Silent Failure Risk — Ein Bug im Plugin führt dazu, dass Regeln nicht durchgesetzt werden, ohne dass der User es merkt - Security-Theater — User vertraut auf Enforcement, aber bei Fehlern läuft alles durch
Option B: Fail-Closed
Bei jedem Fehler blockt das Plugin die Tool-Ausführung.
Vorteile: - Security-First — Im Zweifel blocken, keine silent failures - Auffällig — User merkt sofort, dass das Plugin ein Problem hat
Nachteile: - Workflow Kill — Ein Plugin-Fehler blockiert die gesamte opencode-Session - Keine Graceful Degradation — Schon ein kaputter Contract legt alles lahm - Frustrierend — User kann nicht arbeiten, bis das Plugin gefixt ist - Plugin ist nicht als Sicherheitslayer designed — Fail-Closed suggeriert eine Sicherheitsgarantie, die das Plugin nicht halten kann
Option C: Hybrid — Fail-Open mit User-Notification
Fail-Open, aber der User wird bei jedem Fail-Open durch eine UI-Message informiert.
Nachteile:
- opencode Plugin SDK bietet keine Möglichkeit, UI-Messages zu senden
- client.app.log() schreibt nur ins Log — User sieht es nicht direkt
- Müsste über TUI-Notification realisiert werden (client.tui.showToast() — API unklar)
- User-Notification ist nice-to-have, aber nicht zuverlässig genug für Fail-Closed
Evaluation Criteria
| Kriterium | Gewicht | Beschreibung |
|---|---|---|
Workflow Continuity |
Hoch |
Der Agent muss weiterlaufen können |
Sicherheit |
Mittel |
Keine falsche Sicherheitsgarantie |
Fehlererkennbarkeit |
Mittel |
User muss Fehler bemerken können (via Log) |
Graceful Degradation |
Hoch |
Teilausfall = Teilfunktion, nicht Totalausfall |
Implementierungsaufwand |
Niedrig |
Einfach zu implementieren (catch + log) |
Decision
Option A: Fail-Open wurde gewählt.
Begründung:
- Das Plugin ist ein runtime steering tool, kein Sicherheitslayer. Fail-Open ist die ehrlichere Strategie.
- Workflow Continuity ist Quality Goal #3 — ein Plugin-Crash darf die Session nicht killen
- Silent Failures werden durch Logging adressiert (client.app.log({ level: "error" }))
- Fail-Open ist opencode’s eigener Ansatz (bei throw im Hook tool.execute.before fängt opencode den Fehler und lässt die Ausführung weiterlaufen)
- Fail-Closed würde eine Sicherheitsgarantie suggerieren, die das Plugin nicht leisten kann
Protection Layers
Fail-Open wird auf zwei Ebenen implementiert:
Layer 1: Hook Handler fängt RuleEngine-Fehler → catch + log + kein throw Layer 2: opencode selbst fängt Hook-Fehler → tool.execute läuft weiter
Consequences
-
Positiv: Der Agent läuft immer weiter (Quality Goal #3)
-
Positiv: Graceful Degradation — bei Config-Fehler laufen andere Contracts
-
Positiv: Einfach zu implementieren (jeder Hook ist in try/catch)
-
Positiv: opencode unterstützt dieses Pattern nativ (fängt throw im Hook)
-
Negativ: Bei einem Plugin-Bug werden Regeln still nicht durchgesetzt
-
Negativ: User muss aktiv ins Log schauen, um Fehler zu erkennen
-
Negativ: Fehlerhafte Config fällt nicht sofort auf (DefaultConfig wird geladen)
-
Trade-off: Workflow Continuity gegen Enforcement-Zuverlässigkeit — Continuity gewinnt, weil das Plugin kein Sicherheitslayer ist
Related
-
Error Handling in 05-building-block-view.md (Section "Error Handling")
-
06-runtime-view.md (Error Scenarios — Hook Throw-Error)
-
Quality Goal #3: Workflow Continuity in 01-introduction-and-goals.md
-
ADR-001: Enforcement via
tool.execute.before
Sources
-
opencode Plugin SDK — .env protection example: https://opencode.ai/docs/plugins#env-protection
-
Fail-Open Architectural Pattern: https://martinfowler.com/ieeeSoftware/failSafe.pdf (Ian Sommerville, "Design for Resilience")
-
Safety vs Security in Software Architecture (unterscheiden: Fail-Open für safety, Fail-Closed für security)
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.