The OpenAPI document is the machine-readable contract for a UI integration, but it is only one input. Use it for routes, request and response types, and generated clients. Use the authored guides for lifecycle and interaction semantics that a schema cannot express.
Give a UI coding agent these sources#
A UI-focused coding agent should receive this guide and the OpenAPI 3.1 document. It should also consult:
- Review patterns to choose actions, popups, and typed responses.
- How Agent Outbox works to model asynchronous state and the check, read, and acknowledgement boundaries.
- Reliability to design retries, errors, files, and recovery states.
Do not ask the agent to infer product behavior from OpenAPI schemas alone. Do not give it internal control-plane, billing, or operator specifications unless it is working on those systems explicitly.
Keep the credential behind your UI#
A caller credential is a service secret. Never ship it in browser JavaScript, a mobile application bundle, client-visible environment variables, HTML, or telemetry.
For a web product, call Agent Outbox from your trusted backend, server action, or backend-for-frontend. Your browser UI should call your own application boundary, and that trusted boundary should attach the caller bearer credential when it calls Agent Outbox.
Browser UI → your trusted backend → Agent Outbox caller API
↓
Human review UI ← Agent Outbox queue decision
↓
Browser UI ← your trusted backend ← read and handle output
Generate an API client or types from the OpenAPI document on the trusted side of that boundary. Keep generated files reproducible instead of editing them by hand.
Link directly to a review card#
Agents and integrations can construct a human review link from their caller_id
(available from caller/status) and the same caller_item_id used to submit
the card and copied by its Copy identifier button:
https://app.agent-outbox.dev/human?caller_id=<caller_id>&caller_item_id=<URL-encoded caller_item_id>
Build the query with URLSearchParams or an equivalent URL encoder; IDs may
contain spaces, punctuation, or Unicode. Humans can choose Copy link from
the card's More actions menu to copy the complete URL.
The link opens the details dialog and positions the queue at the card, including cards beyond the first page and answered cards. Closing the dialog leaves the card in view. Shared links use the normal unfiltered priority ordering; they do not carry the sender's search, filters, or page number.
The recipient must sign in to the card's account. Missing cards and cards
outside that account show Review unavailable. A link addresses the current
live item for (caller_id, caller_item_id): after deletion, acknowledgement, or
expiry it becomes unavailable, and reusing that ID later makes the link address
the new card. It is not a permanent historical reference.
Model the asynchronous lifecycle#
Agent Outbox is not a synchronous modal API. Your interface should let the initiating workflow finish or move on while the human review remains pending.
| Application state | What happened | Appropriate UI treatment |
|---|---|---|
| Pending | input/send accepted the review request. |
Show that review was requested; do not keep a request or spinner open. |
| Ready | output/check returned an output_result_id. |
Schedule trusted backend work to read it; no answer content is available yet. |
| Read | output/read or output/read-all returned the decision. |
Reconcile by output_result_id; the person's undo is now disabled. |
| Handled | Your application durably recorded the decision or completed its effect. | Reflect the resulting product state before acknowledging. |
| Acknowledged | output/ack succeeded. |
Treat the live Agent Outbox item as removed; retain your own durable history. |
ready_count includes all live results awaiting acknowledgement, including
results already read. Do not label it as an unread count.
Use separate UI surface models#
Do not flatten the Agent Outbox review row and your application's status or history row into one universal component. They have different owners, data availability, and behavior. Treat action popups as a third, follow-on surface owned by each individual action.
Agent Outbox review row#
The human decision row separates caller-content slots from product controls, responsive infrastructure, and row modifiers so API fields are not confused with product-owned layout.
The anatomy below is rendered by the same row-frame component and responsive CSS as the human review queue. Its labels replace caller content, but its slot placement, wrapping, truncation, breakpoints, and action layout are the live product implementation—not a diagrammatic approximation.
Use Show example beside each preview to replace the explanatory overlays with realistic caller content without changing the component or responsive layout. Open preview preserves the selected Anatomy or Example mode.
When a preview is wider than the documentation column, use its horizontal scrollbar, a horizontal trackpad gesture, or open that exact-width preview in a separate page. Ordinary vertical scrolling always continues down the page.
Border colors describe how content can resize a slot inside the current responsive layout. Viewport-driven reflow is shown separately at each exact width below.
- Fixed width + height
- Content does not change the slot's width or height.
- Width can grow
- A single-line slot can widen with content until its available space is exhausted.
- Height can grow
- The slot keeps its column width while additional or variant content can increase its height.
- Width + height can grow
- Content can consume available width and add lines vertically.
| Element | Category | API setting | Owner | Content sizing | Description |
|---|---|---|---|---|---|
| Row type | Content slot | row_type.displayrow_type.icon | Caller | Width can grow | Classifies the review with a display label and icon. |
| Card time | Content slot | card_time | Caller | Width can grow | Optional caller-owned event timestamp, shown as an unlabeled relative time. Missing values render nothing, independently of corner content. |
| Corner metadata | Content slot | corner | Caller | Width can grow | Optional generic context such as an amount, environment, or count. Separate from card time; missing content renders nothing. |
| Context links | Content slot | link_buttons[] | Caller | Width + height can grow | Zero to 32 link buttons, each with a display label, icon, and HTTP(S) URL. |
| Copy identifier | Product control | caller_item_id | Agent Outbox | Fixed width + height | Copies the caller-provided caller_item_id rather than the internal database ID. The icon confirms success; failures show inline feedback and allow retrying the same control. |
| Feedback | Product control | Product layout | Agent Outbox | Fixed width + height | Icon-only control for a local feedback draft, separate from answer buttons. The tooltip is Add feedback when empty and Edit feedback when a draft is present; a dot marks the latter. Saving does not submit an answer. |
| Snooze | Product control | skip_disabled | Agent Outbox | Fixed width + height | Moves the review behind other entries locally, without scheduling a reminder. skip_disabled makes it unavailable. The icon-only button keeps a tooltip and accessible name at every width. |
| More actions | Product control | actions[].overflow | Agent Outbox | Fixed width + height | Appears on pending rows when one or more actions use overflow: true. Answered rows keep the result and undo flow instead of live overflow decision controls. |
| Title + subtitle | Content slot | titlesubtitle | Caller | Height can grow | Required title and subtitle. The queue title opens details, so nested links in those fields are flattened to text in the row. |
| Card visual | Content slot | card_visual | Caller | Height can grow | No visual, or one numeric_bar, progress_ring, or pill card visual. |
| Summary | Content slot | summary | Caller | Height can grow | Required summary describing the decision being requested. |
| Details | Product control | Product layout | Agent Outbox | Fixed width + height | Always available; opens the complete decision surface. The optional caller details field supplies a rich-content section labeled Details inside that surface. |
| Action rail | Content slot | actions[] | Caller | Height can grow | Primary actions with overflow: false, each with a display label, icon, stable value, optional fixed tone and style, and its own popup. |
| Scrollbar gutter | Responsive infrastructure | Product layout | Agent Outbox | Fixed width + height | Reserved scrollbar gutter; not caller content. |
| Row accent | Row modifier | row_accent_color | Caller | Not a content box | Decorates the row container. |
| Priority treatment | Row modifier | priority | Caller | Not a content box | Controls ordering and a restrained visible Low, Normal, High, or Urgent treatment; it never implies an unsupplied deadline. |
Responsive reflow is separate from content-driven sizing. Above 800 CSS pixels, the action rail is a fixed-width right column and the visual/Details column is fixed within the fluid content area. At 800 pixels and below, actions move below the content. At 520 pixels and below, the metadata links, title, visual, summary, and Details reflow into one column, with Details below the summary. The row height is always content-driven. Context links stay on one line and scroll horizontally when they overflow; edge fades indicate more content, with a thin native scrollbar and keyboard-accessible links. Each link keeps its complete label. Other metadata and titles can wrap, visual labels ellipsize, summaries clamp to two lines, and the number of actions can increase row height. Subtitles are single-line on larger layouts and clamp to two wrapped lines at 520 pixels and below. The review queue uses document scrolling, with pagination following the cards. Its summary reports the number shown on the current page and the total matching the active status, search, and filters. Each card shows a compact priority pill immediately after its title, wrapping with the title when space is limited. Urgent, High, Normal, and Low pills each have a distinct appearance; priority never changes the row's caller accent tint.
The anatomy table describes the represented slots, product controls, and row modifiers.
Optional card_time appears as an unlabeled relative timestamp after the row
type pill, before independent corner content and context links. Missing values
render nothing; the header does not substitute the request's update time. The
exact UTC value is also available on hover and through a semantic time element
with an accessible Card time prefix. See
timestamp field rules.
Details group Card time when supplied, Added to Outbox (created_at), and
Updated in Outbox (updated_at) into a compact row of icons and readable
relative timestamps, in both review and action-compose modes. Field names and
exact UTC values are available on hover, on keyboard focus, and to assistive
technology. The row wraps when needed. Card time, Created, and Last updated are
independent sort choices. Missing card times remain last in either direction;
ties continue to later sort rules. Changing the sort does not add metadata to
the cards.
Visual variants contain these fields:
numeric_bar:label, numericvalue, formatteddisplay, optionalunit,min_value, andmax_value;progress_ring: the numeric-bar fields plus optionalcolor;pill:text, optionalicon, andcolor.
Paired actions[].tone and actions[].style select a semantic button treatment
from fixed API values rather than arbitrary colors or CSS.
The review row has ordinary interaction states such as rest, focus, and selection. Its lifecycle states are pending and answered-but-undoable. After a person answers, Agent Outbox can offer undo until the first successful caller read permanently disables it.
Safe HTML applies across corner, title, subtitle, summary, and
details; it is not a separate slot. The supported elements are paragraphs,
line breaks, headings h3 through h6, emphasis, inline and preformatted code,
ordered and unordered lists, blockquotes, tables, spans, and links. Icons and
colors remain constrained by the OpenAPI allowlists and safe-color rules.
Per-action popup#
Each actions[] entry owns its own popup. A row does not have one shared
interaction slot. Selecting an action opens a follow-on popup surface keyed by
actions[].popup.kind:
| Variant | Contents |
|---|---|
none |
No popup fields; choosing the action completes it immediately. |
free_text |
label, optional placeholder and default_value, multiline, and optional length bounds. |
single_select |
label and one to 64 options containing display, stable value, and optional icon. |
multi_select |
The select-option fields plus optional min_selected and max_selected. |
date_picker |
label, mode, optional placeholder, optional display_timezone, and optional min_value and max_value. |
file_upload |
label and optional accept_mime_types; omitting the MIME list declares no request-level type restriction. |
Date-picker mode is part of the interaction shape. date represents a civil
date, while datetime represents a UTC instant with optional review-timezone
context. Agent Outbox renders placeholder, when supplied, as accessible helper
text for both modes because native date-input placeholder behavior is not
consistent. Both modes enforce inclusive min_value and max_value; datetime
bounds are converted from UTC into the displayed timezone for the local picker.
Caller status and history row#
The consuming product owns this surface and applies its own design system. It has seven logical slots:
| Slot | Contents |
|---|---|
| Identity and context | output_result_id, caller_id, caller_item_id, and caller-cached immutable request context. |
| Status | Pending, ready, read, caller-owned handled, or acknowledged state. |
| Decision | action_value, rendered through the caller's label map. |
| Typed response | response, branched on kind and date-picker mode. |
| Attribution | UTC answered_at and nullable answered_by. |
| File handling | output_result_id, file metadata, authenticated download state, and acknowledgement gating until downloaded bytes are durable. |
| Recovery | unavailable_outputs[].output_result_id, code, and message, rendered as a bounded-retry error rather than a lifecycle badge. |
Use output_result_id for reconciliation and duplicate-delivery safety. Do not
key history solely by caller_item_id; that identifier is only unique while the
caller's item is live. caller_id may remain hidden in a single-caller UI, but
it still belongs to identity.
Typed response variants contain:
none: no additional value;free_text:text, which may be empty when the original popup allowed it;single_select: one stablevalue;multi_select: stablevalues, possibly an intentional empty array;- date mode:
value_dateand nullabledisplay_timezone; - datetime mode:
value_utcand nullabledisplay_timezone; file_upload:file_id,filename,mime_type,size_bytes, andsha256.
Pending operation feedback may also expose revision and idempotency metadata. Acknowledgement reports whether the result was newly or already acknowledged. Once acknowledged, Agent Outbox removes the live pair; durable history belongs to the consuming application.
Keep collection and system UI outside the row model#
Loading, empty state, pagination, ready_count, returned and unavailable
counts, account limits, caller credential status, global errors, validation
fields, upgrade prompts, rate-limit timing, and request or correlation ids are
page-, collection-, account-, or system-level concerns. Do not allocate row
slots for them.
Render typed decisions deliberately#
The hosted review app offers a Dark mode toggle in its top bar beside the account menu. Light mode is the default. The choice applies to the review queue, history, menus, and dialogs, and is remembered in browser-local storage across navigation and reloads. It does not sync between devices. If browser storage is unavailable, the toggle still changes the current page and reports that the preference could not be saved.
On narrow screens, the app header stays on one line. Its navigation overflow menu contains Review queue and History and marks the current view. Selecting a view, pressing Escape, or clicking outside closes the menu. Undo and error feedback remain visible separately without expanding the header.
The hosted review card includes an icon-only feedback utility, separate from answer buttons. Its tooltip is “Add feedback” when empty and “Edit feedback” when a draft is present; a dot marks the latter state. The popup's Save button keeps feedback in browser-local storage scoped to the account, user, and entry. Saving does not submit an answer. Cancel, Escape, and clicking outside dismiss the popup without saving edits. Saved drafts survive reloads in that browser, but do not sync between devices or modify the input queue. Browser storage failures are shown to the user.
Selecting an answer sends its feedback in the same submission, including each entry's own draft during bulk answers. Drafts clear only for successfully answered entries; failures retain them. See the output feedback contract for delivery.
The request defines the human interaction; the output reports the selected
action and its typed response. Keep action and option value fields stable even
when labels change.
Branch on response.kind. Date-picker responses require the additional mode
field: date returns a civil date, while datetime returns a UTC instant and
the displayed timezone. File responses return metadata; download bytes from the
authenticated file route before acknowledgement.
The API schema describes data, not visual styling. Use your own product design system for caller-side status and history surfaces. The human decision surface itself is rendered by Agent Outbox from the submitted title, context, visuals, actions, and popup definitions.
Design loading and error states by code#
Use stable error.code values for behavior and human-readable messages for
display only. In particular:
- Ask the user or caller to correct validation failures before retrying.
- Resolve content conflicts by replacing genuinely changed pending work.
- Use bounded backoff for transient failures and honor
Retry-Afterwhen it is present. - Resolve storage and retention limits by deleting pending work or acknowledging handled output; waiting alone may not help.
- Preserve
request_idandcorrelation_idin content-safe support context.
UI integration checklist#
- The OpenAPI document drives network types and generated clients.
- Caller credentials exist only in a trusted process or secure native store.
- Pending review never leaves a browser request or loading indicator open.
- Stable ids, not labels, drive reconciliation and downstream behavior.
- Every response kind and both date-picker modes have an explicit UI path.
- Duplicate output delivery is harmless because handling is keyed by
output_result_id. - Files are downloaded before acknowledgement.
- Error states branch on
error.codeand offer an actionable recovery. - Accessibility, responsive layout, and visual styling come from the consuming product's design system rather than assumptions encoded in the API schema.