<mindset-agent> is the customer-facing surface of the Mindset AI SDK. Drop it in your HTML, give it an agent UID, and an agent appears. The element handles auth, streaming, state, and (unless you opt out) rendering its own chat UI.
Two modes: chat UI vs headless
The element has one optional toggle that changes everything: theheadless attribute.
Default (chat UI rendered)
Withoutheadless, the element renders Mindset AI’s built-in chat UI inside a shadow DOM. Your users see a chat panel; you don’t write any UI code.
- You want a working chat experience in minutes
- Mindset AI’s UI matches your needs (configurable theme, customizable widgets, branded buttons)
- You don’t have strong design constraints
Headless (you render the UI)
Withheadless, the element runs the agent and dispatches DOM events but does not render any UI. You build the chat (or whatever interface you want) using events and methods.
- You have an existing UI design and want the agent to drive it
- You need a non-chat surface, like voice, slash commands, or an embedded recommendation panel
- You’re integrating into a framework (React, Vue, Svelte) and want full control
Icebreakers fire in headless mode too. If your agent is configured with an icebreaker (a turn that fires automatically when the agent starts), it runs in headless mode just like it does with the built-in chat UI. You’ll see
mindset:agent-busy → mindset:text-delta → mindset:complete → mindset:agent-idle before your first sendMessage runs. Use the sendWhenIdle pattern to handle this safely.Attributes
You set attributes once when the element is added to the DOM. The element reads them on first render. After that, use the corresponding JS methods to update values dynamically.Required
| Attribute | Type | Description |
|---|---|---|
agent-uid | string (UID) | The agent to load. Each agent in the Agent Management Studio has a unique UID. |
mindset.init({ appUid }). It’s a page-level concern and applies to every <mindset-agent> element on the page.
Mode
| Attribute | Type | Description |
|---|---|---|
headless | boolean (presence wins) | When present, the element runs the agent without rendering UI. See Two modes. |
Configuration (alternative to JS methods)
Each of these attributes mirrors a JS method on the element. The attribute path is convenient when your initial setup is static and known at render time. Use the JS method when you need to update the value later.| Attribute | Type | Equivalent method |
|---|---|---|
passthrough-params | JSON object as string | agent.setPassthroughParams(params) |
situational-awareness | JSON object as string | agent.setSituationalAwareness(sa) |
initial-question | string | Auto-sends a first message when the agent loads |
thread-uid | string (thread UID) | Resumes an existing thread on mount. Works in both modes. No icebreaker fires when this is set, because the agent loads the existing thread’s history instead. |
theme | JSON ThemeConfig as string | Per-agent theme override |
show-thread-list | "true" or "false" | Show or hide the thread list panel in the chat UI. Default: true. Ignored in headless mode. |
passthrough-params and passthroughParams work the same). Kebab-case is the recommended form because it’s the HTML standard.
Properties
Properties are read-only fields you access on the element instance after it’s registered.| Property | Type | Description |
|---|---|---|
agent.threadUid | string | null | The active thread UID. null if the element isn’t bound to a runtime yet, or if the current thread is local-only (just created via newThread(), no persisted user-message turn yet). See thread-uid persistence semantics. |
mindset:thread-changed event when it changes.
Methods
The element has methods for driving turns, configuring per-agent state, and managing threads. All documented in the methods reference. Quick summary:agent.sendMessage(text, options?)sends a user messageagent.setPageTools(tools),setSituationalAwareness(sa),setPassthroughParams(params)configure per-agent stateagent.newThread(),switchThread(uid),deleteThread(uid),renameThread(uid, title),listThreads(options?)manage threadsagent.isAgentBusy()checks turn state
Registration lifecycle
The element follows the standard custom-element lifecycle. Knowing the order helps when you’re debugging “why isn’t my listener firing” or coordinating timing across init and DOM mount.When the SDK script loads
The class is registered globally:When the element is added to the DOM
The browser firesconnectedCallback, which the element uses to:
- Set
data-mindset-element-registered="true"anddata-mindset-headless="true"(or"false") on the DOM node - Dispatch
mindset:agent-registeredwithevent.detail = { headless: boolean }
mindset:agent-idle before calling methods like setPageTools or sendMessage. See § When the element is ready to call.
When mindset.init() completes and binds the element
The init pipeline finds the element, attaches a runtime instance, and sets data-instance-id="<id>" on the DOM node. The agent begins initializing and will fire mindset:agent-initializing followed by mindset:agent-idle once ready. Methods are safe to call from mindset:agent-idle onward.
When the element is removed from the DOM
The browser firesdisconnectedCallback. The element detaches its event bridges and cleans up. State setters called after this point are no-ops.
Registration signals you can rely on
| Signal | Where | When set |
|---|---|---|
customElements.get('mindset-agent') returns the constructor | global | After the SDK bundle script loads |
data-mindset-element-registered="true" | DOM attribute | After connectedCallback |
data-mindset-headless="true" or "false" | DOM attribute | After connectedCallback |
mindset:agent-registered event | Bubbles from the element | On connectedCallback |
data-instance-id="<id>" | DOM attribute | After mindset.init() binds the element |
mindset:agent-idle event | Bubbles from the element | After init completes successfully |
mindset:agent-idle on it. If the agent has an icebreaker configured, the first mindset:agent-idle (init done) is followed immediately by an icebreaker turn, and the agent is fully ready for customer-driven sendMessage calls after the second mindset:agent-idle. Use the sendWhenIdle pattern to handle both cases without needing to know which configuration applies.
Dynamic mounting (frameworks)
The SDK uses aMutationObserver to detect <mindset-agent> elements added to the DOM after mindset.init() has run. This means React, Vue, Svelte, and other frameworks that mount the element in a component lifecycle work without extra wiring:
mindset:agent-registered. Unmounting fires disconnectedCallback and cleans up the runtime binding.
See the Examples page (Headless: React tab) for the full pattern, including refs, useEffect cleanup, and event subscription.
What’s not on the element
These are SDK-level concerns, not per-agent. Set them viamindset.init(), not on individual elements:
appUid: your app’s identity, shared by every<mindset-agent>element on the pageextendedSituationalAwareness: lifts the SA character limit from 10,000 to 20,000 for every agent on the pagefetchAuthenticationcallback- Auth state helpers (
onAuthStateChanged,signInWithGoogle, etc.)