hatch3r 1.7.0 → 1.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +38 -12
  2. package/agents/hatch3r-a11y-auditor.md +4 -0
  3. package/agents/hatch3r-architect.md +5 -1
  4. package/agents/hatch3r-ci-watcher.md +4 -0
  5. package/agents/hatch3r-context-rules.md +4 -0
  6. package/agents/hatch3r-creator.md +4 -0
  7. package/agents/hatch3r-dependency-auditor.md +4 -0
  8. package/agents/hatch3r-devops.md +4 -0
  9. package/agents/hatch3r-docs-writer.md +4 -0
  10. package/agents/hatch3r-fixer.md +5 -1
  11. package/agents/hatch3r-handoff-loader.md +243 -0
  12. package/agents/hatch3r-handoff-preparer.md +134 -0
  13. package/agents/hatch3r-implementer.md +5 -1
  14. package/agents/hatch3r-learnings-loader.md +4 -0
  15. package/agents/hatch3r-lint-fixer.md +4 -0
  16. package/agents/hatch3r-perf-profiler.md +8 -0
  17. package/agents/hatch3r-researcher.md +5 -1
  18. package/agents/hatch3r-reviewer.md +92 -0
  19. package/agents/hatch3r-security-auditor.md +24 -0
  20. package/agents/hatch3r-test-writer.md +4 -0
  21. package/agents/modes/requirements-elicitation.md +5 -1
  22. package/agents/modes/similar-implementation.md +6 -0
  23. package/agents/modes/user-flows.md +76 -0
  24. package/agents/shared/quality-charter.md +129 -0
  25. package/agents/shared/user-question-protocol.md +95 -0
  26. package/commands/board/shared-azure-devops.md +2 -0
  27. package/commands/board/shared-github.md +17 -0
  28. package/commands/board/shared-gitlab.md +4 -0
  29. package/commands/hatch3r-board-fill.md +2 -1
  30. package/commands/hatch3r-board-pickup.md +1 -1
  31. package/commands/hatch3r-board-shared.md +21 -0
  32. package/commands/hatch3r-create.md +2 -0
  33. package/commands/hatch3r-handoff.md +126 -0
  34. package/commands/hatch3r-pr-resolve.md +672 -0
  35. package/commands/hatch3r-quick-change.md +5 -3
  36. package/commands/hatch3r-report.md +167 -0
  37. package/commands/hatch3r-revision.md +1 -1
  38. package/commands/hatch3r-workflow.md +3 -1
  39. package/dist/cli/index.js +3144 -979
  40. package/dist/cli/index.js.map +1 -1
  41. package/package.json +4 -2
  42. package/rules/hatch3r-accessibility-standards.md +21 -0
  43. package/rules/hatch3r-accessibility-standards.mdc +21 -0
  44. package/rules/hatch3r-agent-orchestration.md +32 -1
  45. package/rules/hatch3r-agent-orchestration.mdc +32 -1
  46. package/rules/hatch3r-ai-evals.md +158 -0
  47. package/rules/hatch3r-ai-evals.mdc +154 -0
  48. package/rules/hatch3r-ai-ux-patterns.md +131 -0
  49. package/rules/hatch3r-ai-ux-patterns.mdc +127 -0
  50. package/rules/hatch3r-api-design.md +67 -9
  51. package/rules/hatch3r-api-design.mdc +67 -9
  52. package/rules/hatch3r-api-versioning.md +119 -0
  53. package/rules/hatch3r-api-versioning.mdc +115 -0
  54. package/rules/hatch3r-auth-patterns.md +170 -0
  55. package/rules/hatch3r-auth-patterns.mdc +166 -0
  56. package/rules/hatch3r-component-conventions.md +30 -0
  57. package/rules/hatch3r-component-conventions.mdc +30 -0
  58. package/rules/hatch3r-container-hardening.md +131 -0
  59. package/rules/hatch3r-container-hardening.mdc +127 -0
  60. package/rules/hatch3r-contract-testing.md +117 -0
  61. package/rules/hatch3r-contract-testing.mdc +113 -0
  62. package/rules/hatch3r-deep-context.md +3 -1
  63. package/rules/hatch3r-deep-context.mdc +3 -1
  64. package/rules/hatch3r-dependency-management.md +73 -1
  65. package/rules/hatch3r-dependency-management.mdc +72 -0
  66. package/rules/hatch3r-design-system-detection.md +142 -0
  67. package/rules/hatch3r-design-system-detection.mdc +138 -0
  68. package/rules/hatch3r-event-schema-evolution.md +90 -0
  69. package/rules/hatch3r-event-schema-evolution.mdc +86 -0
  70. package/rules/hatch3r-handoff-readiness.md +45 -0
  71. package/rules/hatch3r-handoff-readiness.mdc +40 -0
  72. package/rules/hatch3r-i18n.md +13 -0
  73. package/rules/hatch3r-i18n.mdc +13 -0
  74. package/rules/hatch3r-iteration-summary.md +2 -0
  75. package/rules/hatch3r-iteration-summary.mdc +2 -0
  76. package/rules/hatch3r-migrations.md +61 -16
  77. package/rules/hatch3r-migrations.mdc +61 -16
  78. package/rules/hatch3r-observability-logging.md +1 -1
  79. package/rules/hatch3r-observability-logging.mdc +1 -1
  80. package/rules/hatch3r-observability-metrics.md +1 -1
  81. package/rules/hatch3r-observability-metrics.mdc +1 -1
  82. package/rules/hatch3r-observability-tracing-detail.md +1 -1
  83. package/rules/hatch3r-observability-tracing-detail.mdc +1 -1
  84. package/rules/hatch3r-observability-tracing.md +1 -1
  85. package/rules/hatch3r-observability-tracing.mdc +1 -1
  86. package/rules/hatch3r-observability.md +1 -0
  87. package/rules/hatch3r-observability.mdc +1 -0
  88. package/rules/hatch3r-operability.md +149 -0
  89. package/rules/hatch3r-operability.mdc +145 -0
  90. package/rules/hatch3r-passkey-server.md +181 -0
  91. package/rules/hatch3r-passkey-server.mdc +177 -0
  92. package/rules/hatch3r-progressive-delivery.md +120 -0
  93. package/rules/hatch3r-progressive-delivery.mdc +116 -0
  94. package/rules/hatch3r-resilience-patterns.md +154 -0
  95. package/rules/hatch3r-resilience-patterns.mdc +150 -0
  96. package/rules/hatch3r-secrets-management.md +29 -0
  97. package/rules/hatch3r-secrets-management.mdc +29 -0
  98. package/rules/hatch3r-testing.md +139 -43
  99. package/rules/hatch3r-testing.mdc +139 -43
  100. package/rules/hatch3r-ux-states-and-flows.md +149 -0
  101. package/rules/hatch3r-ux-states-and-flows.mdc +145 -0
  102. package/skills/hatch3r-a11y-audit/SKILL.md +14 -0
  103. package/skills/hatch3r-ai-feature/SKILL.md +134 -0
  104. package/skills/hatch3r-api-spec/SKILL.md +5 -0
  105. package/skills/hatch3r-architecture-review/SKILL.md +14 -0
  106. package/skills/hatch3r-bug-fix/SKILL.md +5 -0
  107. package/skills/hatch3r-ci-pipeline/SKILL.md +14 -0
  108. package/skills/hatch3r-cli-aichat/SKILL.md +84 -0
  109. package/skills/hatch3r-cli-ast-grep/SKILL.md +85 -0
  110. package/skills/hatch3r-cli-az-devops/SKILL.md +89 -0
  111. package/skills/hatch3r-cli-bat/SKILL.md +85 -0
  112. package/skills/hatch3r-cli-comby/SKILL.md +85 -0
  113. package/skills/hatch3r-cli-csvkit/SKILL.md +84 -0
  114. package/skills/hatch3r-cli-delta/SKILL.md +86 -0
  115. package/skills/hatch3r-cli-difftastic/SKILL.md +84 -0
  116. package/skills/hatch3r-cli-docker/SKILL.md +89 -0
  117. package/skills/hatch3r-cli-duckdb/SKILL.md +84 -0
  118. package/skills/hatch3r-cli-fd/SKILL.md +85 -0
  119. package/skills/hatch3r-cli-fzf/SKILL.md +84 -0
  120. package/skills/hatch3r-cli-gh/SKILL.md +90 -0
  121. package/skills/hatch3r-cli-glab/SKILL.md +89 -0
  122. package/skills/hatch3r-cli-jq/SKILL.md +85 -0
  123. package/skills/hatch3r-cli-lazygit/SKILL.md +78 -0
  124. package/skills/hatch3r-cli-llm/SKILL.md +84 -0
  125. package/skills/hatch3r-cli-miller/SKILL.md +84 -0
  126. package/skills/hatch3r-cli-mods/SKILL.md +84 -0
  127. package/skills/hatch3r-cli-overview/SKILL.md +60 -0
  128. package/skills/hatch3r-cli-playwright/SKILL.md +89 -0
  129. package/skills/hatch3r-cli-podman/SKILL.md +84 -0
  130. package/skills/hatch3r-cli-ripgrep/SKILL.md +85 -0
  131. package/skills/hatch3r-cli-rtk/SKILL.md +91 -0
  132. package/skills/hatch3r-cli-sd/SKILL.md +85 -0
  133. package/skills/hatch3r-cli-stagehand/SKILL.md +79 -0
  134. package/skills/hatch3r-cli-taplo/SKILL.md +84 -0
  135. package/skills/hatch3r-cli-xsv/SKILL.md +89 -0
  136. package/skills/hatch3r-cli-yq/SKILL.md +85 -0
  137. package/skills/hatch3r-cli-zstd/SKILL.md +85 -0
  138. package/skills/hatch3r-context-health/SKILL.md +14 -0
  139. package/skills/hatch3r-cost-tracking/SKILL.md +14 -0
  140. package/skills/hatch3r-customize/SKILL.md +14 -0
  141. package/skills/hatch3r-dep-audit/SKILL.md +14 -0
  142. package/skills/hatch3r-design-system-detect/SKILL.md +162 -0
  143. package/skills/hatch3r-feature/SKILL.md +2 -0
  144. package/skills/hatch3r-gh-agentic-workflows/SKILL.md +13 -0
  145. package/skills/hatch3r-handoff-prepare/SKILL.md +160 -0
  146. package/skills/hatch3r-handoff-resume/SKILL.md +171 -0
  147. package/skills/hatch3r-incident-response/SKILL.md +14 -0
  148. package/skills/hatch3r-issue-workflow/SKILL.md +5 -0
  149. package/skills/hatch3r-logical-refactor/SKILL.md +14 -0
  150. package/skills/hatch3r-migration/SKILL.md +14 -0
  151. package/skills/hatch3r-observability-verify/SKILL.md +133 -0
  152. package/skills/hatch3r-perf-audit/SKILL.md +14 -0
  153. package/skills/hatch3r-pr-creation/SKILL.md +14 -0
  154. package/skills/hatch3r-qa-validation/SKILL.md +18 -0
  155. package/skills/hatch3r-recipe/SKILL.md +14 -0
  156. package/skills/hatch3r-refactor/SKILL.md +14 -0
  157. package/skills/hatch3r-release/SKILL.md +14 -0
  158. package/skills/hatch3r-reliability-verify/SKILL.md +144 -0
  159. package/skills/hatch3r-ui-ux-verify/SKILL.md +136 -0
  160. package/skills/hatch3r-visual-refactor/SKILL.md +15 -1
@@ -0,0 +1,131 @@
1
+ ---
2
+ id: hatch3r-ai-ux-patterns
3
+ type: rule
4
+ description: 2026 AI/agentic UX patterns for end-user projects shipping AI features — streaming, tool-call UI, human-approval gates, cancel/abort/undo, citations
5
+ scope: "**/*.vue,**/*.jsx,**/*.tsx,**/*.svelte,**/ai/**,**/chat/**,**/assistant/**,**/agents/**,**/llm/**,**/copilot/**"
6
+ tags: [ux, ai, frontend]
7
+ quality_charter: agents/shared/quality-charter.md
8
+ cache_friendly: true
9
+ ---
10
+ # AI/Agentic UX Patterns (2026)
11
+
12
+ ## Scope
13
+
14
+ This rule applies when the end-user project ships LLM-driven UI — chat, assistant, copilot, agent dashboards, generative UI surfaces. It does NOT govern the LLM backend itself (model selection, prompt engineering, retrieval pipeline). For non-AI UX rules (loading, empty, error, partial states; form patterns; microcopy), cross-reference `rules/hatch3r-ux-states-and-flows.md`. When both rules apply to the same surface, the non-AI rule sets the baseline and this rule layers AI-specific behavior on top.
15
+
16
+ Backend companion: `rules/hatch3r-ai-evals.md` defines eval harness, prompt versioning, cost telemetry, prompt caching, model fallback, and hallucination-as-SLI. Apply both rules for any LLM-driven feature.
17
+
18
+ Detection: this rule activates when the project imports an AI SDK (`ai`, `@ai-sdk/*`, `openai`, `@anthropic-ai/sdk`, `@google/generative-ai`), or contains files under `ai/`, `chat/`, `assistant/`, `agents/`, `llm/`, `copilot/`. Adding any of these to a project that previously had no AI surface triggers the full ruleset on the next agent run.
19
+
20
+ ## Streaming-First Defaults
21
+
22
+ - Every LLM-driven surface uses framework-agnostic streaming hooks: `useChat`, `useCompletion`, or `useObject` from Vercel AI SDK UI (or equivalent for non-React stacks). Hand-rolled SSE or `fetch` against the model endpoint is a regression in 2026.
23
+ - Render progressive tokens from the moment the request starts. Pair with a skeleton state during the pre-token window (request-sent, first-token-pending). A blank surface during model latency is a regression.
24
+ - Render markdown incrementally without re-parsing the whole buffer on every chunk (Vercel AI Elements `MessageResponse` pattern). Use a streaming-safe markdown renderer that tracks last-rendered offset and appends from there.
25
+ - Emit chunk-level error boundaries. If a stream fails mid-flight, retain prior tokens, render an inline retry control adjacent to the truncated response, and do not blank the surface or reset the message body.
26
+ - Indicate completion explicitly via a final-token marker or `onFinish` callback transition. Stale "thinking" indicators after stream-end erode trust and waste user attention.
27
+ - Non-streaming responses on LLM-driven surfaces are a regression. The narrow exception is structured-output endpoints that must return a single validated JSON payload (`useObject` already streams partial objects — prefer that).
28
+ - Typing indicator policy: show only while no token has arrived; switch to streamed content the moment the first delta lands. Two-second indicator timeouts that linger past first-token are a regression.
29
+ - Backpressure: when the model emits faster than the renderer can paint, batch deltas to one paint per animation frame (`requestAnimationFrame`) rather than dropping tokens or queuing into an unbounded buffer.
30
+
31
+ ## Generative UI (RSC Streaming)
32
+
33
+ - For dynamic dashboards, cards, and surfaces driven by tool calls, use the `streamUI()` RSC pattern (or framework equivalent). The model returns a tool invocation, the server renders an RSC fragment per tool, the client merges fragments into the thread without re-hydrating.
34
+ - Build on shadcn primitives via Vercel AI Elements — 20+ shadcn-based React components for AI surfaces: messages, input, reasoning panel, tool-call display, response actions. Reuse before authoring; bespoke equivalents are a duplication regression.
35
+ - Keep AI-generated UI off the client JS bundle. RSC streaming keeps the payload server-side; do not ship a client-side renderer that duplicates server-rendered output.
36
+ - Each RSC fragment is independently hydratable — never wrap two tool outputs in a single fragment that requires both to complete before render.
37
+ - For non-React stacks, the equivalent is server-rendered HTML fragments streamed via Server-Sent Events and merged into the DOM with explicit anchor elements per tool call. Do not bypass the server-render boundary with raw `innerHTML` of model output.
38
+
39
+ ## Tool-Call UI Cards
40
+
41
+ Every tool invocation is user-visible by default. Hidden tool calls are a regression — transparency is the trust contract with the user.
42
+
43
+ - Render each tool call as a structured card with: tool name, args (collapsed by default, expandable on click), status (`pending` → `in-progress` → `complete` / `failed`), elapsed duration, result preview (truncated, expand to full).
44
+ - Indicate state through both color and icon — a single channel (color only) fails for color-vision-deficient users.
45
+ - Args display redacts secrets (API keys, tokens, bearer credentials) and PII per project data-classification rules. Show a `[redacted]` placeholder so the user knows a value was scrubbed, not omitted.
46
+ - Async sub-flows — a tool that triggers more tools — render as nested cards. Do not collapse a multi-tool sub-flow to a single line; the user must see every external action.
47
+ - Failed tool calls show the error message in plain language plus a single-click retry control. Stack traces and raw API responses belong behind an "Details" toggle, not in the user-visible card body.
48
+ - Result preview length: cap at 200 characters or 5 lines (whichever first); always paired with an "Expand" affordance. Long binary or base64 payloads display size + content-type, not the raw bytes.
49
+ - Tool-call cards are keyboard-focusable and announce status transitions via `aria-live="polite"` regions so screen-reader users perceive state changes without polling the visual surface.
50
+
51
+ ## Human-Approval Gates for Side-Effects
52
+
53
+ Required for any tool that:
54
+
55
+ - Mutates external state (database write, email send, post to Slack/GitHub/external service)
56
+ - Spends money (paid-API call, transaction, billable inference run on a third-party provider)
57
+ - Modifies the user's environment (file write, shell command, git push, package install)
58
+
59
+ Gate pattern:
60
+
61
+ 1. Pause execution before invoking the tool.
62
+ 2. Render an approval card showing tool name, full args (no collapse), diff preview if the tool mutates a file, named target ("Send email to alice@example.com", not "Send email").
63
+ 3. Require explicit user confirm (`Approve` button, not Enter-to-dismiss).
64
+ 4. On approve, invoke the tool and transition the card to `in-progress`. On deny, surface a cancel-reason field and persist the rejection in the run transcript.
65
+
66
+ Read-only tools (search, fetch, list, read) do not require approval — gating them adds friction without trust value.
67
+
68
+ Destructive irreversible actions (drop table, delete repo, permanent send) disclose irreversibility on the approval card with a typed-confirmation pattern (user types the named target to enable the confirm button).
69
+
70
+ Auto-approve scopes (the "trusted tool" pattern) live behind a per-tool setting with a named scope ("Auto-approve git status, never git push"). Default to opt-in, never opt-out. Scopes are revocable from a single settings surface and revocation takes effect for in-flight runs, not just future runs.
71
+
72
+ ## Cancel / Abort / Undo
73
+
74
+ Three distinct affordances — do not collapse them into a single control:
75
+
76
+ - **Cancel** — every long-running tool call (>2s expected duration) and every streaming response renders a visible cancel control adjacent to the surface. Wire to an `AbortController` covering both the model stream and the tool worker. Cancellation produces a clean stop with a "Cancelled by user" marker in the transcript — not a hang, not a silent terminate.
77
+ - **Abort** — distinct from cancel. Aborts the entire agent task (a multi-tool plan). Persists prior tool results so the user can resume from any completed step. Renders as a separate control on the agent-task header, not the in-flight tool card.
78
+ - **Undo** — every reversible action (file write, message send, database row insert, configuration change) renders an undo affordance for 5-30s after completion (named target shown: "Undo: deleted file foo.txt"). Maps to a compensating tool call (delete-after-write, recall-after-send, soft-delete-restore). Destructive irreversible actions disclose this on the approval card per the previous section.
79
+ - Keyboard shortcuts: cancel = `Esc` while the surface is focused; abort = `Esc` then confirm (double-tap pattern) to prevent accidental task termination; undo = `Cmd/Ctrl+Z` while the undo affordance is visible.
80
+ - All three controls remain operable after the user navigates away from the surface — running streams and undo windows persist in a thread-level state, not component-local state. A user closing the panel does not cancel the in-flight task.
81
+
82
+ ## Citations and Grounding
83
+
84
+ - Factual claims from retrieval show inline citations with span-level linkage. Hovering or clicking the citation highlights the source passage in the retrieved document.
85
+ - Cite the retrieval source URL or document anchor, not just the document name — "Knowledge Base / Onboarding" without an anchor is unverifiable.
86
+ - Ungroundable claims are flagged in the response surface ("I'm not certain — this isn't in your retrieved sources") rather than silently emitted. Span-level verification is preferred when the model exposes it.
87
+ - Do not show uncalibrated confidence badges. A "90% confident" indicator without empirical calibration data actively misleads — drop it or replace with grounding framing ("Based on [doc]" or "Not found in your data").
88
+ - When retrieval returns zero results, say so explicitly. Silent fall-through to model parametric memory is a regression — the user cannot distinguish retrieved from confabulated content.
89
+ - Citation rendering: superscript number link in the response body that opens a side panel (or popover on hover) with source title, URL, and highlighted span. Avoid footnote-only patterns that force the user to scroll.
90
+ - Source freshness indicator: when retrieval metadata includes document timestamps, surface the source date on the citation popover. Stale sources flagged at >12 months by default; threshold configurable per project domain.
91
+
92
+ ## Multi-Step Agent UX
93
+
94
+ - Render the agent's plan as an ordered checklist before execution. Allow the user to edit step text, reorder, or skip individual steps before approving the plan. A pre-execution plan view is required for any agent run with >3 steps.
95
+ - As each step completes, mark with status (success/failure/skipped) plus elapsed duration. Failed steps show the failure cause and a retry control; retry restarts from the failed step, not from the beginning.
96
+ - Streaming reasoning (when the model exposes it via a reasoning channel) renders in a collapsed "Reasoning" panel that the user opens on click. Never inline reasoning with the user-facing message body — it dilutes the response and conflates the user-facing answer with internal model state.
97
+ - Maintain a thread or run ID per conversation for resumption, audit trail, and observability backlink. The run ID is visible in the UI (footer or thread metadata) so users and support can reference a specific run.
98
+ - Plan revision: when the model revises its plan mid-run (adds, removes, or reorders remaining steps), diff the previous plan against the new plan and surface the diff to the user before continuing. Silent plan mutation defeats the pre-execution review.
99
+ - Parallel steps: when the plan contains independent steps that the agent runs in parallel, render them as a horizontal group with shared progress, not a flat vertical list — the user must see the parallelism to interpret elapsed time.
100
+
101
+ ## Failure Modes and Degradation
102
+
103
+ - **Model timeout** — render a fallback card with a single-click recovery ("Model is slow — retry?" or "Switching to faster model"). Do not silently retry; the user must know the model failed.
104
+ - **Rate limit** — show a countdown timer and queue position when available. Surface vendor rate-limit headers, not raw API error JSON. "Try again in 47s" beats "429 Too Many Requests".
105
+ - **Token budget exceeded** — indicate context truncation in-line ("Conversation truncated — earlier turns dropped") and offer a summary/restart control. Do not silently truncate; the user must know which turns are still in context.
106
+ - **Tool unavailability** — degrade gracefully. Disable the affected feature with a tooltip explaining why ("Slack integration offline — reconnect in Settings"), not a crash or an unhandled exception bubbled to the user.
107
+ - **Stream interruption mid-response** — retain the partial response, render a "Stream interrupted" marker, offer continue-from-here (resume the stream from the last received token) and restart-from-scratch (drop partial, restart) as two separate controls.
108
+ - **Content-policy refusal** — when the model refuses to answer (safety filter, policy violation), render the refusal verbatim in a distinct style (not a normal assistant message), and surface a single-click "Report this" affordance so users can flag false-positive refusals.
109
+ - **Stale session** — if the user returns to a tab where the stream has died (network sleep, tab discard), detect on focus and offer a "Reconnect" control rather than silently re-issuing the request and double-billing the user.
110
+
111
+ ## Verification Gate
112
+
113
+ Before declaring an AI surface "done":
114
+
115
+ - Streaming verified end-to-end: scripted Playwright test that asserts progressive token render (first token <1s after request, last token marked complete).
116
+ - Tool-call card snapshot per state (`pending`, `in-progress`, `complete`, `failed`) — missing any state is a blocker.
117
+ - Approval-gate test: simulate a side-effecting tool, assert execution pauses, approval card renders required fields, deny path persists rejection in transcript.
118
+ - Cancel/abort/undo each have at least one end-to-end test exercising the AbortController wire-up; cancellation produces a transcript marker, not a silent terminate.
119
+ - Citation rendering: snapshot of a grounded response shows inline citation with source URL or anchor; an ungroundable claim renders the flag string, not silent emission.
120
+ - Failure-mode coverage: at least one test per failure mode in this rule (timeout, rate limit, token budget, tool unavailability, stream interruption, content-policy refusal, stale session). Missing coverage is a blocker.
121
+ - Accessibility: axe-core scan against every AI surface state (idle, streaming, tool-call pending, approval card open, error) returns 0 serious or critical violations.
122
+
123
+ ## References
124
+
125
+ - Vercel — Introducing AI Elements (`vercel.com/changelog/introducing-ai-elements`)
126
+ - Vercel AI SDK UI docs (`ai-sdk.dev/docs/ai-sdk-ui`) — `useChat`, `useCompletion`, `useObject`
127
+ - Vercel — AI SDK 3 Generative UI / `streamUI()` (`vercel.com/blog/ai-sdk-3-generative-ui`)
128
+ - Anthropic — Building agents with the Claude Agent SDK (`anthropic.com/engineering/building-agents-with-the-claude-agent-sdk`)
129
+ - OpenAI Apps SDK — UI guidelines (`developers.openai.com/apps-sdk/concepts/ui-guidelines`)
130
+ - ClarityArc — Hallucination, grounding, and citation in enterprise systems
131
+ - Lakera — LLM hallucinations in 2026
@@ -0,0 +1,127 @@
1
+ ---
2
+ description: 2026 AI/agentic UX patterns for end-user projects shipping AI features — streaming, tool-call UI, human-approval gates, cancel/abort/undo, citations
3
+ globs: ["**/*.vue", "**/*.jsx", "**/*.tsx", "**/*.svelte", "**/ai/**", "**/chat/**", "**/assistant/**", "**/agents/**", "**/llm/**", "**/copilot/**"]
4
+ alwaysApply: false
5
+ ---
6
+ # AI/Agentic UX Patterns (2026)
7
+
8
+ ## Scope
9
+
10
+ This rule applies when the end-user project ships LLM-driven UI — chat, assistant, copilot, agent dashboards, generative UI surfaces. It does NOT govern the LLM backend itself (model selection, prompt engineering, retrieval pipeline). For non-AI UX rules (loading, empty, error, partial states; form patterns; microcopy), cross-reference `rules/hatch3r-ux-states-and-flows.md`. When both rules apply to the same surface, the non-AI rule sets the baseline and this rule layers AI-specific behavior on top.
11
+
12
+ Backend companion: `rules/hatch3r-ai-evals.md` defines eval harness, prompt versioning, cost telemetry, prompt caching, model fallback, and hallucination-as-SLI. Apply both rules for any LLM-driven feature.
13
+
14
+ Detection: this rule activates when the project imports an AI SDK (`ai`, `@ai-sdk/*`, `openai`, `@anthropic-ai/sdk`, `@google/generative-ai`), or contains files under `ai/`, `chat/`, `assistant/`, `agents/`, `llm/`, `copilot/`. Adding any of these to a project that previously had no AI surface triggers the full ruleset on the next agent run.
15
+
16
+ ## Streaming-First Defaults
17
+
18
+ - Every LLM-driven surface uses framework-agnostic streaming hooks: `useChat`, `useCompletion`, or `useObject` from Vercel AI SDK UI (or equivalent for non-React stacks). Hand-rolled SSE or `fetch` against the model endpoint is a regression in 2026.
19
+ - Render progressive tokens from the moment the request starts. Pair with a skeleton state during the pre-token window (request-sent, first-token-pending). A blank surface during model latency is a regression.
20
+ - Render markdown incrementally without re-parsing the whole buffer on every chunk (Vercel AI Elements `MessageResponse` pattern). Use a streaming-safe markdown renderer that tracks last-rendered offset and appends from there.
21
+ - Emit chunk-level error boundaries. If a stream fails mid-flight, retain prior tokens, render an inline retry control adjacent to the truncated response, and do not blank the surface or reset the message body.
22
+ - Indicate completion explicitly via a final-token marker or `onFinish` callback transition. Stale "thinking" indicators after stream-end erode trust and waste user attention.
23
+ - Non-streaming responses on LLM-driven surfaces are a regression. The narrow exception is structured-output endpoints that must return a single validated JSON payload (`useObject` already streams partial objects — prefer that).
24
+ - Typing indicator policy: show only while no token has arrived; switch to streamed content the moment the first delta lands. Two-second indicator timeouts that linger past first-token are a regression.
25
+ - Backpressure: when the model emits faster than the renderer can paint, batch deltas to one paint per animation frame (`requestAnimationFrame`) rather than dropping tokens or queuing into an unbounded buffer.
26
+
27
+ ## Generative UI (RSC Streaming)
28
+
29
+ - For dynamic dashboards, cards, and surfaces driven by tool calls, use the `streamUI()` RSC pattern (or framework equivalent). The model returns a tool invocation, the server renders an RSC fragment per tool, the client merges fragments into the thread without re-hydrating.
30
+ - Build on shadcn primitives via Vercel AI Elements — 20+ shadcn-based React components for AI surfaces: messages, input, reasoning panel, tool-call display, response actions. Reuse before authoring; bespoke equivalents are a duplication regression.
31
+ - Keep AI-generated UI off the client JS bundle. RSC streaming keeps the payload server-side; do not ship a client-side renderer that duplicates server-rendered output.
32
+ - Each RSC fragment is independently hydratable — never wrap two tool outputs in a single fragment that requires both to complete before render.
33
+ - For non-React stacks, the equivalent is server-rendered HTML fragments streamed via Server-Sent Events and merged into the DOM with explicit anchor elements per tool call. Do not bypass the server-render boundary with raw `innerHTML` of model output.
34
+
35
+ ## Tool-Call UI Cards
36
+
37
+ Every tool invocation is user-visible by default. Hidden tool calls are a regression — transparency is the trust contract with the user.
38
+
39
+ - Render each tool call as a structured card with: tool name, args (collapsed by default, expandable on click), status (`pending` → `in-progress` → `complete` / `failed`), elapsed duration, result preview (truncated, expand to full).
40
+ - Indicate state through both color and icon — a single channel (color only) fails for color-vision-deficient users.
41
+ - Args display redacts secrets (API keys, tokens, bearer credentials) and PII per project data-classification rules. Show a `[redacted]` placeholder so the user knows a value was scrubbed, not omitted.
42
+ - Async sub-flows — a tool that triggers more tools — render as nested cards. Do not collapse a multi-tool sub-flow to a single line; the user must see every external action.
43
+ - Failed tool calls show the error message in plain language plus a single-click retry control. Stack traces and raw API responses belong behind an "Details" toggle, not in the user-visible card body.
44
+ - Result preview length: cap at 200 characters or 5 lines (whichever first); always paired with an "Expand" affordance. Long binary or base64 payloads display size + content-type, not the raw bytes.
45
+ - Tool-call cards are keyboard-focusable and announce status transitions via `aria-live="polite"` regions so screen-reader users perceive state changes without polling the visual surface.
46
+
47
+ ## Human-Approval Gates for Side-Effects
48
+
49
+ Required for any tool that:
50
+
51
+ - Mutates external state (database write, email send, post to Slack/GitHub/external service)
52
+ - Spends money (paid-API call, transaction, billable inference run on a third-party provider)
53
+ - Modifies the user's environment (file write, shell command, git push, package install)
54
+
55
+ Gate pattern:
56
+
57
+ 1. Pause execution before invoking the tool.
58
+ 2. Render an approval card showing tool name, full args (no collapse), diff preview if the tool mutates a file, named target ("Send email to alice@example.com", not "Send email").
59
+ 3. Require explicit user confirm (`Approve` button, not Enter-to-dismiss).
60
+ 4. On approve, invoke the tool and transition the card to `in-progress`. On deny, surface a cancel-reason field and persist the rejection in the run transcript.
61
+
62
+ Read-only tools (search, fetch, list, read) do not require approval — gating them adds friction without trust value.
63
+
64
+ Destructive irreversible actions (drop table, delete repo, permanent send) disclose irreversibility on the approval card with a typed-confirmation pattern (user types the named target to enable the confirm button).
65
+
66
+ Auto-approve scopes (the "trusted tool" pattern) live behind a per-tool setting with a named scope ("Auto-approve git status, never git push"). Default to opt-in, never opt-out. Scopes are revocable from a single settings surface and revocation takes effect for in-flight runs, not just future runs.
67
+
68
+ ## Cancel / Abort / Undo
69
+
70
+ Three distinct affordances — do not collapse them into a single control:
71
+
72
+ - **Cancel** — every long-running tool call (>2s expected duration) and every streaming response renders a visible cancel control adjacent to the surface. Wire to an `AbortController` covering both the model stream and the tool worker. Cancellation produces a clean stop with a "Cancelled by user" marker in the transcript — not a hang, not a silent terminate.
73
+ - **Abort** — distinct from cancel. Aborts the entire agent task (a multi-tool plan). Persists prior tool results so the user can resume from any completed step. Renders as a separate control on the agent-task header, not the in-flight tool card.
74
+ - **Undo** — every reversible action (file write, message send, database row insert, configuration change) renders an undo affordance for 5-30s after completion (named target shown: "Undo: deleted file foo.txt"). Maps to a compensating tool call (delete-after-write, recall-after-send, soft-delete-restore). Destructive irreversible actions disclose this on the approval card per the previous section.
75
+ - Keyboard shortcuts: cancel = `Esc` while the surface is focused; abort = `Esc` then confirm (double-tap pattern) to prevent accidental task termination; undo = `Cmd/Ctrl+Z` while the undo affordance is visible.
76
+ - All three controls remain operable after the user navigates away from the surface — running streams and undo windows persist in a thread-level state, not component-local state. A user closing the panel does not cancel the in-flight task.
77
+
78
+ ## Citations and Grounding
79
+
80
+ - Factual claims from retrieval show inline citations with span-level linkage. Hovering or clicking the citation highlights the source passage in the retrieved document.
81
+ - Cite the retrieval source URL or document anchor, not just the document name — "Knowledge Base / Onboarding" without an anchor is unverifiable.
82
+ - Ungroundable claims are flagged in the response surface ("I'm not certain — this isn't in your retrieved sources") rather than silently emitted. Span-level verification is preferred when the model exposes it.
83
+ - Do not show uncalibrated confidence badges. A "90% confident" indicator without empirical calibration data actively misleads — drop it or replace with grounding framing ("Based on [doc]" or "Not found in your data").
84
+ - When retrieval returns zero results, say so explicitly. Silent fall-through to model parametric memory is a regression — the user cannot distinguish retrieved from confabulated content.
85
+ - Citation rendering: superscript number link in the response body that opens a side panel (or popover on hover) with source title, URL, and highlighted span. Avoid footnote-only patterns that force the user to scroll.
86
+ - Source freshness indicator: when retrieval metadata includes document timestamps, surface the source date on the citation popover. Stale sources flagged at >12 months by default; threshold configurable per project domain.
87
+
88
+ ## Multi-Step Agent UX
89
+
90
+ - Render the agent's plan as an ordered checklist before execution. Allow the user to edit step text, reorder, or skip individual steps before approving the plan. A pre-execution plan view is required for any agent run with >3 steps.
91
+ - As each step completes, mark with status (success/failure/skipped) plus elapsed duration. Failed steps show the failure cause and a retry control; retry restarts from the failed step, not from the beginning.
92
+ - Streaming reasoning (when the model exposes it via a reasoning channel) renders in a collapsed "Reasoning" panel that the user opens on click. Never inline reasoning with the user-facing message body — it dilutes the response and conflates the user-facing answer with internal model state.
93
+ - Maintain a thread or run ID per conversation for resumption, audit trail, and observability backlink. The run ID is visible in the UI (footer or thread metadata) so users and support can reference a specific run.
94
+ - Plan revision: when the model revises its plan mid-run (adds, removes, or reorders remaining steps), diff the previous plan against the new plan and surface the diff to the user before continuing. Silent plan mutation defeats the pre-execution review.
95
+ - Parallel steps: when the plan contains independent steps that the agent runs in parallel, render them as a horizontal group with shared progress, not a flat vertical list — the user must see the parallelism to interpret elapsed time.
96
+
97
+ ## Failure Modes and Degradation
98
+
99
+ - **Model timeout** — render a fallback card with a single-click recovery ("Model is slow — retry?" or "Switching to faster model"). Do not silently retry; the user must know the model failed.
100
+ - **Rate limit** — show a countdown timer and queue position when available. Surface vendor rate-limit headers, not raw API error JSON. "Try again in 47s" beats "429 Too Many Requests".
101
+ - **Token budget exceeded** — indicate context truncation in-line ("Conversation truncated — earlier turns dropped") and offer a summary/restart control. Do not silently truncate; the user must know which turns are still in context.
102
+ - **Tool unavailability** — degrade gracefully. Disable the affected feature with a tooltip explaining why ("Slack integration offline — reconnect in Settings"), not a crash or an unhandled exception bubbled to the user.
103
+ - **Stream interruption mid-response** — retain the partial response, render a "Stream interrupted" marker, offer continue-from-here (resume the stream from the last received token) and restart-from-scratch (drop partial, restart) as two separate controls.
104
+ - **Content-policy refusal** — when the model refuses to answer (safety filter, policy violation), render the refusal verbatim in a distinct style (not a normal assistant message), and surface a single-click "Report this" affordance so users can flag false-positive refusals.
105
+ - **Stale session** — if the user returns to a tab where the stream has died (network sleep, tab discard), detect on focus and offer a "Reconnect" control rather than silently re-issuing the request and double-billing the user.
106
+
107
+ ## Verification Gate
108
+
109
+ Before declaring an AI surface "done":
110
+
111
+ - Streaming verified end-to-end: scripted Playwright test that asserts progressive token render (first token <1s after request, last token marked complete).
112
+ - Tool-call card snapshot per state (`pending`, `in-progress`, `complete`, `failed`) — missing any state is a blocker.
113
+ - Approval-gate test: simulate a side-effecting tool, assert execution pauses, approval card renders required fields, deny path persists rejection in transcript.
114
+ - Cancel/abort/undo each have at least one end-to-end test exercising the AbortController wire-up; cancellation produces a transcript marker, not a silent terminate.
115
+ - Citation rendering: snapshot of a grounded response shows inline citation with source URL or anchor; an ungroundable claim renders the flag string, not silent emission.
116
+ - Failure-mode coverage: at least one test per failure mode in this rule (timeout, rate limit, token budget, tool unavailability, stream interruption, content-policy refusal, stale session). Missing coverage is a blocker.
117
+ - Accessibility: axe-core scan against every AI surface state (idle, streaming, tool-call pending, approval card open, error) returns 0 serious or critical violations.
118
+
119
+ ## References
120
+
121
+ - Vercel — Introducing AI Elements (`vercel.com/changelog/introducing-ai-elements`)
122
+ - Vercel AI SDK UI docs (`ai-sdk.dev/docs/ai-sdk-ui`) — `useChat`, `useCompletion`, `useObject`
123
+ - Vercel — AI SDK 3 Generative UI / `streamUI()` (`vercel.com/blog/ai-sdk-3-generative-ui`)
124
+ - Anthropic — Building agents with the Claude Agent SDK (`anthropic.com/engineering/building-agents-with-the-claude-agent-sdk`)
125
+ - OpenAI Apps SDK — UI guidelines (`developers.openai.com/apps-sdk/concepts/ui-guidelines`)
126
+ - ClarityArc — Hallucination, grounding, and citation in enterprise systems
127
+ - Lakera — LLM hallucinations in 2026
@@ -12,10 +12,10 @@ cache_friendly: true
12
12
  - Use consistent request/response schemas. Document in spec files.
13
13
  - All endpoints versioned (URL prefix or header). Backward-compatible changes only.
14
14
  - Additive changes only: add fields, never rename or remove without migration.
15
- - Error responses follow standard shape: `{ code, message, details? }`.
16
- - Idempotency keys for mutation endpoints. Reject duplicate requests.
15
+ - Error responses follow RFC 9457 Problem Details (`application/problem+json`) see "Error Envelope" below.
16
+ - Idempotency keys for mutation endpoints. See `rules/hatch3r-api-versioning.md` for header name, TTL, and replay semantics.
17
17
  - Request validation at the boundary: validate and sanitize before processing.
18
- - List endpoints return envelopes: `{ data, pagination }`. Never raw arrays.
18
+ - List endpoints return cursor-paginated envelopes see "Pagination Standards" below for the exact shape.
19
19
  - Rate limiting enforced server-side. Return 429 with `Retry-After` when exceeded.
20
20
  - API contracts documented in project specs. Update on schema changes.
21
21
 
@@ -24,7 +24,7 @@ cache_friendly: true
24
24
  - Validate JWT signature, expiration (`exp`), audience (`aud`), and issuer (`iss`) on every request.
25
25
  - Enforce algorithm in server config (`RS256` for asymmetric, `HS256` for symmetric). Reject `alg: none`.
26
26
  - Access tokens short-lived (15–60 min). Use opaque refresh tokens with rotation and revocation.
27
- - OAuth 2.0 with PKCE for SPAs and mobile clients. Never use implicit flow.
27
+ - OAuth 2.1 (draft-ietf-oauth-v2-1) with mandatory PKCE for SPAs, mobile, and confidential clients. Implicit + password grants removed. Detail in `rules/hatch3r-api-versioning.md`; cross-reference `rules/hatch3r-auth-patterns.md`.
28
28
  - API keys identify applications, not users. Scope keys to specific services and rotate on schedule.
29
29
  - Authorization middleware checks permissions before handler execution. Fail closed on missing claims.
30
30
  - Apply principle of least privilege: scope tokens to the minimum required permissions.
@@ -51,13 +51,12 @@ cache_friendly: true
51
51
 
52
52
  ## Pagination Standards
53
53
 
54
- - Default to cursor-based pagination for ordered data with high write frequency or deep traversal.
55
- - Use offset-based pagination only for small, stable datasets where total count is cheap.
54
+ - Default to cursor-based pagination with a stable composite sort key (e.g., `(created_at, id)` using ULID/UUIDv7 as deterministic tiebreaker).
55
+ - Use offset-based pagination only for small, bounded, append-immutable datasets (e.g., admin reports) where total count is cheap.
56
56
  - Enforce a maximum page size server-side (e.g., 100 items). Ignore client requests exceeding the limit.
57
- - Return `nextCursor` (or `null`) in the envelope. Clients must not construct cursors—they are opaque.
58
- - Total count is optional: provide it only when the query cost is bounded. Use `hasMore` boolean otherwise.
57
+ - Cursors are opaque base64 strings. Clients must not parse or construct them.
59
58
  - Reject deep offset pagination beyond a threshold (e.g., offset > 10000) to protect database performance.
60
- - Include pagination metadata in the envelope: `{ data, pagination: { nextCursor, hasMore, pageSize } }`.
59
+ - Standard envelope: `{ data, page_info: { has_next_page, end_cursor }, links: { next } }`. Add `has_previous_page` + `start_cursor` for bidirectional cursor navigation (Relay-style). Total count is optional — provide only when the query cost is bounded.
61
60
 
62
61
  ## Request Security
63
62
 
@@ -179,3 +178,62 @@ Follow the IETF draft standard (`draft-ietf-httpapi-ratelimit-headers`) for rate
179
178
  - When the rate limit is exceeded, return HTTP `429 Too Many Requests` with `Retry-After` header.
180
179
  - Document rate limits per endpoint tier in the API specification (e.g., auth endpoints: 100/min, read endpoints: 1000/min, write endpoints: 500/min).
181
180
  - Apply rate limiting by authenticated identity (API key, user token) as the primary key. Fall back to IP-based limiting for unauthenticated endpoints.
181
+
182
+ ## Spec Floor: OpenAPI 3.1 / 3.2 and AsyncAPI 3.1.0
183
+
184
+ - **OpenAPI 3.1** is the 2026 floor for REST APIs. OpenAPI 3.2.0 (Sep 2025) is emerging — use only when its features (deeper webhook coverage, `pathItems`) are required; tooling lag is real.
185
+ - **AsyncAPI 3.1.0** (Jan 2026, non-breaking over 3.0) is the canonical spec for event-driven and webhook APIs. Define every event channel, message schema, and binding (Kafka/AMQP/MQTT/WebSocket/HTTP) in an AsyncAPI document.
186
+ - Generate code, mocks, and reference docs from the spec — never hand-write client SDKs or hand-roll mocks when a spec exists. Use Prism (Stoplight) for OAS-driven mock servers.
187
+
188
+ ## Error Envelope: RFC 9457 Problem Details
189
+
190
+ Every error response uses `Content-Type: application/problem+json` and the RFC 9457 shape, superseding any local `{code, message, details?}` convention:
191
+
192
+ | Field | Required | Purpose |
193
+ |-------|----------|---------|
194
+ | `type` | yes | URI identifying the error class (e.g., `https://errors.example.com/validation`). Stable across versions. |
195
+ | `title` | yes | Short human-readable summary. Constant per `type`. |
196
+ | `status` | yes | HTTP status code as integer. Mirrors the response status. |
197
+ | `detail` | yes | Human-readable explanation specific to this occurrence. May include user input. |
198
+ | `instance` | yes | URI reference identifying this specific occurrence (e.g., a log/trace URL). |
199
+ | `trace_id` (extension) | recommended | W3C Trace Context trace ID for observability correlation. Alternative: propagate via `traceparent` response header. |
200
+
201
+ - Extension fields are allowed for machine-readable detail (e.g., `errors: [{ field, code }]` for validation).
202
+ - Frameworks emitting Problem Details by default (Spring 6, ASP.NET 8, Hono): keep the default — do not override with a custom shape.
203
+
204
+ ## GraphQL: Trusted Documents
205
+
206
+ - Production GraphQL endpoints accept **only** registered query IDs (Apollo Persisted Queries, Relay Persisted Queries, or Hive). Reject ad-hoc queries from web clients. Apollo's APQ is performance-only — use pre-registered trusted documents for security parity.
207
+ - Annotate fields with `@cost` (per-field cost) and lists with `@listSize` (assumed size, slicing args, `requireOneSlicingArgument: true`) for query-cost analysis. Block requests exceeding the global cost budget.
208
+ - Federation v2 (`@key`, `@shareable`, `@external`, `@inaccessible`, `@override`) is the floor — Federation 1.0 supergraphs are deprecated in GraphOS.
209
+
210
+ ## gRPC / Connect-RPC
211
+
212
+ - **Connect-RPC** (`buf/connect-go|web|swift|kotlin`) is the 2026 recommendation for web-facing gRPC — replaces gRPC-Web; supports HTTP/1.1, HTTP/2, and the Connect protocol.
213
+ - **REST transcoding:** add `google.api.http` annotations per AIP-127 to map RPC to HTTP/JSON; expose via Envoy `grpc_json_transcoder` or grpc-gateway.
214
+ - **Removed fields:** reserve both the tag and the field name (`reserved 4; reserved "password";`) to block accidental reuse.
215
+ - Mark deprecated fields/methods with `[deprecated = true]` and `// Deprecated:` comments; consumers see the deprecation in generated code.
216
+
217
+ ## tRPC / Hono RPC
218
+
219
+ - Choose tRPC v11 or Hono RPC **only** when both ends are TypeScript in a closed monorepo with no external consumers. Types flow via TS inference — no codegen, no cross-language interop.
220
+ - The moment a non-TS consumer or public SDK is required, switch to OpenAPI emission. **oRPC** bridges tRPC ergonomics with OpenAPI for cross-language use (Standard Schema: Zod/Valibot/ArkType).
221
+ - All tRPC routers use Zod (or Standard Schema) for input/output validation and a structured error formatter mapping errors to RFC 9457 Problem Details on the HTTP boundary.
222
+
223
+ ## Breaking-Change CI Gate
224
+
225
+ Every PR that touches an API contract runs the matching diff tool against the last shipped tag. Breaking changes block merge unless paired with an RFC 9745 Deprecation + RFC 8594 Sunset lifecycle (see `rules/hatch3r-api-versioning.md`) or a major-version bump.
226
+
227
+ | Contract type | Path glob | Tool | Action |
228
+ |---------------|-----------|------|--------|
229
+ | OpenAPI | `**/openapi.{yaml,yml,json}`, `**/openapi/**` | `oasdiff breaking` (450+ rules, OAS 3.0 + 3.1) | PR comment + fail on `breaking` exit |
230
+ | Protobuf | `**/*.proto` | `buf breaking` (default `FILE` rule set) | PR comment + fail on wire/source incompatibility |
231
+ | GraphQL | `**/*.graphql`, `**/*.gql` | `graphql-inspector diff` | PR comment + fail on breaking-classified changes |
232
+
233
+ The reviewer agent (`agents/hatch3r-reviewer.md` item 11 "Contract preservation") invokes the matching tool on every PR touching `**/api/**`, `**/proto/**`, or schema files — verifies both in-repo and cross-repo consumers.
234
+
235
+ ## Cross-References
236
+
237
+ - Versioning, deprecation, idempotency, OAuth 2.1, webhook signing: `rules/hatch3r-api-versioning.md`.
238
+ - Pact / Schemathesis / `can-i-deploy` gate: `rules/hatch3r-contract-testing.md`.
239
+ - OAuth 2.1, DPoP, Resource Indicators, mTLS: `rules/hatch3r-auth-patterns.md`.
@@ -8,10 +8,10 @@ alwaysApply: false
8
8
  - Use consistent request/response schemas. Document in spec files.
9
9
  - All endpoints versioned (URL prefix or header). Backward-compatible changes only.
10
10
  - Additive changes only: add fields, never rename or remove without migration.
11
- - Error responses follow standard shape: `{ code, message, details? }`.
12
- - Idempotency keys for mutation endpoints. Reject duplicate requests.
11
+ - Error responses follow RFC 9457 Problem Details (`application/problem+json`) see "Error Envelope" below.
12
+ - Idempotency keys for mutation endpoints. See `rules/hatch3r-api-versioning.md` for header name, TTL, and replay semantics.
13
13
  - Request validation at the boundary: validate and sanitize before processing.
14
- - List endpoints return envelopes: `{ data, pagination }`. Never raw arrays.
14
+ - List endpoints return cursor-paginated envelopes see "Pagination Standards" below for the exact shape.
15
15
  - Rate limiting enforced server-side. Return 429 with `Retry-After` when exceeded.
16
16
  - API contracts documented in project specs. Update on schema changes.
17
17
 
@@ -20,7 +20,7 @@ alwaysApply: false
20
20
  - Validate JWT signature, expiration (`exp`), audience (`aud`), and issuer (`iss`) on every request.
21
21
  - Enforce algorithm in server config (`RS256` for asymmetric, `HS256` for symmetric). Reject `alg: none`.
22
22
  - Access tokens short-lived (15–60 min). Use opaque refresh tokens with rotation and revocation.
23
- - OAuth 2.0 with PKCE for SPAs and mobile clients. Never use implicit flow.
23
+ - OAuth 2.1 (draft-ietf-oauth-v2-1) with mandatory PKCE for SPAs, mobile, and confidential clients. Implicit + password grants removed. Detail in `rules/hatch3r-api-versioning.md`; cross-reference `rules/hatch3r-auth-patterns.md`.
24
24
  - API keys identify applications, not users. Scope keys to specific services and rotate on schedule.
25
25
  - Authorization middleware checks permissions before handler execution. Fail closed on missing claims.
26
26
  - Apply principle of least privilege: scope tokens to the minimum required permissions.
@@ -47,13 +47,12 @@ alwaysApply: false
47
47
 
48
48
  ## Pagination Standards
49
49
 
50
- - Default to cursor-based pagination for ordered data with high write frequency or deep traversal.
51
- - Use offset-based pagination only for small, stable datasets where total count is cheap.
50
+ - Default to cursor-based pagination with a stable composite sort key (e.g., `(created_at, id)` using ULID/UUIDv7 as deterministic tiebreaker).
51
+ - Use offset-based pagination only for small, bounded, append-immutable datasets (e.g., admin reports) where total count is cheap.
52
52
  - Enforce a maximum page size server-side (e.g., 100 items). Ignore client requests exceeding the limit.
53
- - Return `nextCursor` (or `null`) in the envelope. Clients must not construct cursors—they are opaque.
54
- - Total count is optional: provide it only when the query cost is bounded. Use `hasMore` boolean otherwise.
53
+ - Cursors are opaque base64 strings. Clients must not parse or construct them.
55
54
  - Reject deep offset pagination beyond a threshold (e.g., offset > 10000) to protect database performance.
56
- - Include pagination metadata in the envelope: `{ data, pagination: { nextCursor, hasMore, pageSize } }`.
55
+ - Standard envelope: `{ data, page_info: { has_next_page, end_cursor }, links: { next } }`. Add `has_previous_page` + `start_cursor` for bidirectional cursor navigation (Relay-style). Total count is optional — provide only when the query cost is bounded.
57
56
 
58
57
  ## Request Security
59
58
 
@@ -175,3 +174,62 @@ Follow the IETF draft standard (`draft-ietf-httpapi-ratelimit-headers`) for rate
175
174
  - When the rate limit is exceeded, return HTTP `429 Too Many Requests` with `Retry-After` header.
176
175
  - Document rate limits per endpoint tier in the API specification (e.g., auth endpoints: 100/min, read endpoints: 1000/min, write endpoints: 500/min).
177
176
  - Apply rate limiting by authenticated identity (API key, user token) as the primary key. Fall back to IP-based limiting for unauthenticated endpoints.
177
+
178
+ ## Spec Floor: OpenAPI 3.1 / 3.2 and AsyncAPI 3.1.0
179
+
180
+ - **OpenAPI 3.1** is the 2026 floor for REST APIs. OpenAPI 3.2.0 (Sep 2025) is emerging — use only when its features (deeper webhook coverage, `pathItems`) are required; tooling lag is real.
181
+ - **AsyncAPI 3.1.0** (Jan 2026, non-breaking over 3.0) is the canonical spec for event-driven and webhook APIs. Define every event channel, message schema, and binding (Kafka/AMQP/MQTT/WebSocket/HTTP) in an AsyncAPI document.
182
+ - Generate code, mocks, and reference docs from the spec — never hand-write client SDKs or hand-roll mocks when a spec exists. Use Prism (Stoplight) for OAS-driven mock servers.
183
+
184
+ ## Error Envelope: RFC 9457 Problem Details
185
+
186
+ Every error response uses `Content-Type: application/problem+json` and the RFC 9457 shape, superseding any local `{code, message, details?}` convention:
187
+
188
+ | Field | Required | Purpose |
189
+ |-------|----------|---------|
190
+ | `type` | yes | URI identifying the error class (e.g., `https://errors.example.com/validation`). Stable across versions. |
191
+ | `title` | yes | Short human-readable summary. Constant per `type`. |
192
+ | `status` | yes | HTTP status code as integer. Mirrors the response status. |
193
+ | `detail` | yes | Human-readable explanation specific to this occurrence. May include user input. |
194
+ | `instance` | yes | URI reference identifying this specific occurrence (e.g., a log/trace URL). |
195
+ | `trace_id` (extension) | recommended | W3C Trace Context trace ID for observability correlation. Alternative: propagate via `traceparent` response header. |
196
+
197
+ - Extension fields are allowed for machine-readable detail (e.g., `errors: [{ field, code }]` for validation).
198
+ - Frameworks emitting Problem Details by default (Spring 6, ASP.NET 8, Hono): keep the default — do not override with a custom shape.
199
+
200
+ ## GraphQL: Trusted Documents
201
+
202
+ - Production GraphQL endpoints accept **only** registered query IDs (Apollo Persisted Queries, Relay Persisted Queries, or Hive). Reject ad-hoc queries from web clients. Apollo's APQ is performance-only — use pre-registered trusted documents for security parity.
203
+ - Annotate fields with `@cost` (per-field cost) and lists with `@listSize` (assumed size, slicing args, `requireOneSlicingArgument: true`) for query-cost analysis. Block requests exceeding the global cost budget.
204
+ - Federation v2 (`@key`, `@shareable`, `@external`, `@inaccessible`, `@override`) is the floor — Federation 1.0 supergraphs are deprecated in GraphOS.
205
+
206
+ ## gRPC / Connect-RPC
207
+
208
+ - **Connect-RPC** (`buf/connect-go|web|swift|kotlin`) is the 2026 recommendation for web-facing gRPC — replaces gRPC-Web; supports HTTP/1.1, HTTP/2, and the Connect protocol.
209
+ - **REST transcoding:** add `google.api.http` annotations per AIP-127 to map RPC to HTTP/JSON; expose via Envoy `grpc_json_transcoder` or grpc-gateway.
210
+ - **Removed fields:** reserve both the tag and the field name (`reserved 4; reserved "password";`) to block accidental reuse.
211
+ - Mark deprecated fields/methods with `[deprecated = true]` and `// Deprecated:` comments; consumers see the deprecation in generated code.
212
+
213
+ ## tRPC / Hono RPC
214
+
215
+ - Choose tRPC v11 or Hono RPC **only** when both ends are TypeScript in a closed monorepo with no external consumers. Types flow via TS inference — no codegen, no cross-language interop.
216
+ - The moment a non-TS consumer or public SDK is required, switch to OpenAPI emission. **oRPC** bridges tRPC ergonomics with OpenAPI for cross-language use (Standard Schema: Zod/Valibot/ArkType).
217
+ - All tRPC routers use Zod (or Standard Schema) for input/output validation and a structured error formatter mapping errors to RFC 9457 Problem Details on the HTTP boundary.
218
+
219
+ ## Breaking-Change CI Gate
220
+
221
+ Every PR that touches an API contract runs the matching diff tool against the last shipped tag. Breaking changes block merge unless paired with an RFC 9745 Deprecation + RFC 8594 Sunset lifecycle (see `rules/hatch3r-api-versioning.md`) or a major-version bump.
222
+
223
+ | Contract type | Path glob | Tool | Action |
224
+ |---------------|-----------|------|--------|
225
+ | OpenAPI | `**/openapi.{yaml,yml,json}`, `**/openapi/**` | `oasdiff breaking` (450+ rules, OAS 3.0 + 3.1) | PR comment + fail on `breaking` exit |
226
+ | Protobuf | `**/*.proto` | `buf breaking` (default `FILE` rule set) | PR comment + fail on wire/source incompatibility |
227
+ | GraphQL | `**/*.graphql`, `**/*.gql` | `graphql-inspector diff` | PR comment + fail on breaking-classified changes |
228
+
229
+ The reviewer agent (`agents/hatch3r-reviewer.md` item 11 "Contract preservation") invokes the matching tool on every PR touching `**/api/**`, `**/proto/**`, or schema files — verifies both in-repo and cross-repo consumers.
230
+
231
+ ## Cross-References
232
+
233
+ - Versioning, deprecation, idempotency, OAuth 2.1, webhook signing: `rules/hatch3r-api-versioning.md`.
234
+ - Pact / Schemathesis / `can-i-deploy` gate: `rules/hatch3r-contract-testing.md`.
235
+ - OAuth 2.1, DPoP, Resource Indicators, mTLS: `rules/hatch3r-auth-patterns.md`.
@@ -0,0 +1,119 @@
1
+ ---
2
+ id: hatch3r-api-versioning
3
+ type: rule
4
+ description: API versioning, deprecation lifecycle, and idempotency — RFC 9457 errors, RFC 9745 Deprecation header, RFC 8594 Sunset, OAuth 2.1, Idempotency-Key, semver vs CalVer for APIs
5
+ scope: "**/api/**,**/openapi*,**/asyncapi*,**/*.proto,**/routes/**,**/handlers/**,**/controllers/**"
6
+ tags: [implementation, devops]
7
+ quality_charter: agents/shared/quality-charter.md
8
+ cache_friendly: true
9
+ ---
10
+ # API Versioning, Deprecation & Idempotency
11
+
12
+ Lifecycle rules for evolving REST, GraphQL, and gRPC contracts without breaking consumers. Pairs with `rules/hatch3r-api-design.md` (shape) and `rules/hatch3r-contract-testing.md` (verification).
13
+
14
+ ## Versioning Scheme
15
+
16
+ - **Semver (`v1`, `v2`)** for stable contracts and published SDKs: major version goes in the URL prefix (`/v2/users`) for breaking changes; minor and patch updates are field-level additive and stay within the same major.
17
+ - **CalVer (`2026-05-15`)** for rolling APIs that change frequently (Stripe-style date-based versioning): clients pin a date via `Stripe-Version` / `Api-Version` header; the server transforms newer responses down to the pinned date.
18
+ - Pick one scheme per API and document it in the spec — never mix semver and CalVer in the same surface.
19
+ - Within a major (semver) or pinned date (CalVer), only additive changes ship: new fields, new endpoints, new enum values (when consumers handle `unknown` fallback).
20
+
21
+ ## Deprecation Lifecycle (RFC 9745 + RFC 8594)
22
+
23
+ Every retirement passes three stages. Skipping any stage breaks downstream consumers.
24
+
25
+ | Stage | Header(s) | Action |
26
+ |-------|-----------|--------|
27
+ | Announce | `Deprecation: @<unix-ts>` (RFC 9745, Mar 2025 Standards Track) + `Link: <https://docs.example.com/migrate/v2>; rel="deprecation"` | Emit on every deprecated endpoint/field response; log usage by `X-Api-Key` / authenticated identity. |
28
+ | Sunset | `Sunset: <HTTP-date>` (RFC 8594) | Set N months before removal: N=6 public, N=3 partner, N=1 internal. Pair with continued `Deprecation` header. |
29
+ | Remove | HTTP 410 Gone + Problem Details (`type: https://errors.example.com/sunset`, `title: Endpoint removed`) | Only after the sunset date passes AND analytics show <0.1% usage for two consecutive 7-day windows. |
30
+
31
+ - Field-level deprecation: emit `Deprecation` per endpoint that still returns the field; GraphQL uses `@deprecated(reason: "...")`; protobuf uses `[deprecated = true]`.
32
+ - Document the migration in the `Link: ...rel="deprecation"` target — include before/after code samples, fallback strategy, and the removal date.
33
+
34
+ ## Idempotency-Key (draft-ietf-httpapi-idempotency-key-header)
35
+
36
+ Every side-effectful endpoint (POST / PATCH / PUT / DELETE that mutates state) accepts an `Idempotency-Key: <client-generated-uuid>` request header.
37
+
38
+ - **Key format:** UUIDv4 or ULID, max 255 chars. Clients generate; servers never accept server-generated keys.
39
+ - **Storage:** server persists `(tenant_id, api_key, idempotency_key, request_body_hash, response_status, response_body)` for 24 hours (configurable per API; Stripe uses 24h, recommended range 24h-7d).
40
+ - **Replay semantics:**
41
+ - Exact replay (same key + same request body hash) -> return the original response (same status, same body, same `Idempotency-Replay: true` header).
42
+ - Conflicting replay (same key + different request body hash) -> 422 with Problem Details `type: https://errors.example.com/idempotency-conflict`.
43
+ - In-flight replay (same key, original still processing) -> 409 Conflict + `Retry-After: <seconds>`.
44
+ - **Scope:** per `(tenant_id, api_key)`, never global. Hashing the body prevents replay-with-mutation attacks.
45
+
46
+ ## Rate Limit Headers (draft-ietf-httpapi-ratelimit-headers)
47
+
48
+ Emit structured-field headers on every response (not just 429):
49
+
50
+ | Header | Value | Purpose |
51
+ |--------|-------|---------|
52
+ | `RateLimit-Policy` | `100;w=60` | Quota + window length (seconds). |
53
+ | `RateLimit-Limit` | `100` | Maximum requests in current window. |
54
+ | `RateLimit-Remaining` | `42` | Remaining quota in current window. |
55
+ | `RateLimit-Reset` | `30` | Seconds until the window resets. |
56
+
57
+ - On 429, also include `Retry-After: <seconds>` (RFC 9110).
58
+ - Vendor-specific `X-RateLimit-*` headers may be emitted alongside for backward compatibility, but the IETF draft headers are the floor.
59
+
60
+ ## OAuth 2.1 (draft-ietf-oauth-v2-1)
61
+
62
+ - **PKCE mandatory on all clients** (public and confidential) — `code_challenge` + `code_challenge_method=S256`.
63
+ - **Implicit and password (ROPC) grants removed.** Use authorization code + PKCE for interactive; client credentials for server-server; device code for input-constrained.
64
+ - **Exact redirect-URI matching** — no wildcards, no partial paths. Pre-register each callback URL.
65
+ - **Refresh-token rotation with reuse detection** — on every refresh, issue a new refresh token and invalidate the old one. If the old token is presented after rotation, revoke the entire token family (replay attack signal).
66
+ - Access tokens short-lived (5-15 min). Long-lived refresh tokens, sender-constrained (DPoP or mTLS) for public clients.
67
+ - Full auth detail: `rules/hatch3r-auth-patterns.md`.
68
+
69
+ ## Resource Indicators (RFC 8707)
70
+
71
+ - Token requests include a `resource=<uri>` parameter naming the protected resource the token will be presented to.
72
+ - Authorization servers bind the token's `aud` claim to the requested resource — prevents audience-confusion attacks across multi-tenant AS deployments.
73
+ - Multi-resource consent flows pass multiple `resource` params; the AS issues separate tokens per audience.
74
+
75
+ ## DPoP (RFC 9449)
76
+
77
+ - Sender-constrained access and refresh tokens for browser-resident clients (SPAs) — alternative to mTLS for public clients.
78
+ - Client generates a key pair (non-extractable in the browser via WebCrypto), signs a fresh DPoP JWT per request, sends in `DPoP: <jwt>` header.
79
+ - Server binds the access token's `cnf.jkt` claim (JWK thumbprint) to the client's public key; rejects token presentation from any other key.
80
+ - Recommended floor for any token leaving the first-party boundary (third-party SDK consumers, mobile apps with insecure storage).
81
+
82
+ ## Webhook Signing (Standard Webhooks convention)
83
+
84
+ - Headers: `webhook-id` (unique delivery ID), `webhook-timestamp` (unix seconds), `webhook-signature` (`v1,<base64-HMAC-SHA256(<id>.<timestamp>.<body>)>`).
85
+ - HMAC-SHA256 with a per-tenant shared secret, constant-time comparison.
86
+ - Reject deliveries where `|now - webhook-timestamp| > 300` seconds (5-minute replay window).
87
+ - `webhook-id` doubles as the idempotency key on the receiver — cache for >=5 minutes (Redis/SQLite) to dedupe duplicate deliveries.
88
+ - **Key rotation:** signature spec supports comma-separated versions (`v1,sig1 v2,sig2`); receivers accept any valid version during the rollover window.
89
+ - Deliveries that fail signature verification return HTTP 401 + Problem Details `type: https://errors.example.com/invalid-signature`.
90
+
91
+ ## Backward Compatibility Policy
92
+
93
+ - **Field additions** are always safe.
94
+ - **Field removal or rename** requires the full RFC 9745 + RFC 8594 lifecycle (Announce -> Sunset -> Remove). Never remove without the lifecycle.
95
+ - **Enum extension** is safe only when consumers handle an `unknown` fallback value. Generated client code (OpenAPI Generator, openapi-typescript) must emit the `unknown` branch.
96
+ - **Nullable transitions** (required -> optional, or non-null -> nullable) require a feature flag and a deprecation window — clients written against the stricter shape will break on `null`.
97
+ - **Type changes** (e.g., `int32` -> `int64` in protobuf, `string` -> `string | null` in OpenAPI) require a new major version unless the wire format is unchanged (protobuf int32->int64 is wire-compatible for small values; document the edge case).
98
+
99
+ ## CI Gates
100
+
101
+ Every PR touching an API contract runs the matching diff tool against the last shipped tag. Breaking changes block merge.
102
+
103
+ - `oasdiff breaking` (OpenAPI 3.0 + 3.1, 450+ rules, CNCF Sandbox) — comments on the PR with the breaking-change list.
104
+ - `buf breaking` (Protobuf, default `FILE` rule set) — blocks wire + source incompatibility.
105
+ - `graphql-inspector diff` — blocks GraphQL schema breaking changes.
106
+
107
+ All three integrate with PR comments and fail the build on a breaking exit code. Cross-reference the gate set in `rules/hatch3r-api-design.md` "Breaking-Change CI Gate".
108
+
109
+ ## References
110
+
111
+ - RFC 9457 — Problem Details for HTTP APIs (March 2025, obsoletes RFC 7807).
112
+ - RFC 9745 — The Deprecation HTTP Response Header Field (March 2025, Standards Track).
113
+ - RFC 8594 — The Sunset HTTP Response Header Field.
114
+ - RFC 8707 — Resource Indicators for OAuth 2.0.
115
+ - RFC 9449 — OAuth 2.0 Demonstrating Proof of Possession (DPoP).
116
+ - draft-ietf-oauth-v2-1 — The OAuth 2.1 Authorization Framework.
117
+ - draft-ietf-httpapi-idempotency-key-header — The Idempotency-Key HTTP Header Field.
118
+ - draft-ietf-httpapi-ratelimit-headers — RateLimit Header Fields for HTTP.
119
+ - Standard Webhooks — https://github.com/standard-webhooks/standard-webhooks