MetabindAssistantView — that handles most cases. When you need full control over the UI (a different layout, a non-chat interaction model, custom branding beyond what theming covers), use the SDK’s lower-level API to drive your own surface. On Android there’s no default surface — you always build the chat UI yourself; see the Android SDK.
Why go custom
Most teams ship the default UI for the first release and customize later. Cases where custom is right from day one:- Your assistant lives inside a non-chat surface — a sidebar, an inline panel, a voice-first interaction.
- You want UI primitives that don’t fit a chat metaphor — e.g., a multi-pane workspace where the assistant is one component.
- Your design system mandates components that diverge significantly from the SDK’s chat default.
- You’re building an agent UI (open-ended task execution) rather than a chat UI.
What the lower-level API gives you
The default chat surface is built on a small public API on theMetabindAssistant object:
Tool result UI is rendered through the BindJS native renderer —
BindJSView on iOS, and BindJSView from bindjs-android on Android. Each message’s tool results carry the BindJS spec; you hand it to the renderer.
iOS example
MetabindAssistant is an ObservableObject — bind it with @ObservedObject or @StateObject. Tool results render through BindJSView, the SwiftUI renderer for BindJS specs.
Android
The Android SDK doesn’t expose aMetabindAssistant object — on Android you build the chat UI directly on the streaming API (MetabindAgentProvider.streamMessage(...)) and render tool results with bindjs-android. That flow, and the demo app that implements it end to end, are covered in the Android SDK.
What the default UI does that you’ll need to handle
If you replace the default UI, replicate (or skip) these as needed:Conversation state observability
The conversation state is the source of truth. Patterns:- Read-only views. Render the conversation in a different surface (e.g., a summary sidebar) by subscribing to the same state.
- Multi-pane layouts. A chat pane on one side, a tool result detail pane on the other — both subscribed to the same state, both displaying different slices.
- Server-side replay. Persist messages to your backend (the SDK does not ship a persistence adapter today); rehydrate on next session by re-creating the assistant and replaying messages.
Persistence
Conversation state is held in memory by theConversation observable on the assistant. If your app needs persistence across launches or reloads, serialize assistant.conversation.messages to your platform’s storage (Core Data, SwiftData, Room, IndexedDB, your backend) and rehydrate on next launch.
Related
iOS SDK
Default chat surface and configuration.
Android SDK
Default chat surface and configuration.
LLM provider configuration
Agent proxy vs. BYOK for the LLM call.
Assistant SDK overview
Conceptual: when to embed and what’s in the box.