# API Reference
URL: /tap/docs/store/api-reference

All exports from @assistant-ui/store.

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

## Hooks

### useAui()

```
function useAui(): AssistantClient;
```

Returns the store from the nearest `AuiProvider`. Does not re-render when scopes change — returns a stable reference.

### useAui(scopes)

```
function useAui(scopes: useAui.Props): AssistantClient;
```

Takes the store from the nearest `AuiProvider` and extends it by filling the provided scopes. Returns a new `AssistantClient` that includes both the parent's scopes and the newly provided ones.

```
type useAui.Props = {
  [K in ClientNames]?: ClientElement<K> | DerivedElement<K>;
};
```

### useAuiState

```
function useAuiState<T>(selector: (state: AssistantState) => T): T;
```

Subscribes to a slice of state. Re-renders only when the selected value changes (compared by `Object.is`). The selector must return a specific value — not the entire state object.

### useAuiEvent

```
function useAuiEvent<TEvent extends AssistantEventName>(
  selector: AssistantEventSelector<TEvent>,
  callback: AssistantEventCallback<TEvent>,
): void;
```

Subscribes to events. The selector can be a string (`"scope.event"`) or an object (`{ scope, event }`). Unsubscribes on unmount.

---

## Components

### AuiProvider

```
<AuiProvider value={aui}>{children}</AuiProvider>
```

Provides an `AssistantClient` to the React tree. Child components can access it via `useAui()`.

### AuiIf

```
<AuiIf condition={(s) => s.counter.count > 0}>
  <ResetButton />
</AuiIf>
```

Renders children only when the condition returns `true`. Uses `useAuiState` internally.

### RenderChildrenWithAccessor

```
<RenderChildrenWithAccessor
  getItemState={(aui) => aui.todoList().todo({ index }).getState()}
>
  {(getItem) =>
    children({
      get todo() {
        return getItem();
      },
    })
  }
</RenderChildrenWithAccessor>
```

Sets up a lazy item accessor for list rendering. The `getItem` function defers reading state until the consumer accesses it — if the children render function never reads the item, no subscription is created. When children returns a propless component (e.g. `{() => <Todo />}`), the output is automatically memoized.

| Prop           | Type                              |
| -------------- | --------------------------------- |
| `getItemState` | `(aui: AssistantClient) => T`     |
| `children`     | `(getItem: () => T) => ReactNode` |

See [Rendering Lists](/tap/docs/store/rendering-lists) for the full pattern.

---

## Resource utilities

### Derived

```
function Derived<K extends ClientNames>(config: Derived.Props<K>): DerivedElement<K>;
```

Creates a derived scope that points to data in a parent scope.

```
Derived({
  source: "thread",
  query: { index: 0 },
  get: (aui) => aui.thread().message({ index: 0 }),
});
```

The `get` function receives the current `AssistantClient` and must return the result of calling a parent scope method. The meta (`source`, `query`) acts as identity: when `query` changes between renders, a new derived client function is returned in the same render pass — useful for keying child consumers like `MessageByIndex` by index.

### attachTransformScopes

```
function attachTransformScopes<T extends (...args: any[]) => ResourceElement<any>>(
  resource: T,
  transform: (scopes: ScopesConfig, parent: AssistantClient) => ScopesConfig,
): void;
```

Attaches a transform function to a resource. When the resource is mounted via `useAui`, the transform runs and can add or modify sibling scopes. Transforms are applied iteratively — new root scopes trigger their own transforms.

One transform per resource. Throws on duplicate.

---

## Resource hooks

These are used inside Tap resources to integrate with Store.

### useClientResource

```
function useClientResource<TMethods extends ClientMethods>(
  element: ResourceElement<TMethods>,
): {
  state: InferClientState<TMethods>;
  methods: TMethods;
  key: string | number | undefined;
};
```

Wraps a single resource element into a client. Adds the client to the internal client stack for event scoping.

`state` is inferred from the element's `getState()` return type. If `getState` is not defined, `state` is `undefined`.

### useClientLookup

```
function useClientLookup<TMethods extends ClientMethods>(
  elements: readonly ResourceElement<TMethods>[],
): {
  state: InferClientState<TMethods>[];
  get: (lookup: { index: number } | { key: string }) => TMethods;
};
```

Wraps a list of resource elements into clients. Each element must have a key (via `withKey`). Uses `useClientResource` internally for each element.

`get` resolves a client by index or key. Throws if the lookup doesn't match.

### useClientList

```
function useClientList<TData, TMethods extends ClientMethods>(
  props: useClientList.Props<TData, TMethods>,
): {
  state: InferClientState<TMethods>[];
  get: (lookup: { index: number } | { key: string }) => TMethods;
  add: (data: TData) => void;
};
```

Manages a dynamic list of clients with add/remove. Built on `useClientLookup`.

```
type useClientList.Props<TData, TMethods> = {
  initialValues: TData[];
  getKey: (data: TData) => string;
  resource: ContravariantResource<TMethods, useClientList.ResourceProps<TData>>;
};

type useClientList.ResourceProps<TData> = {
  key: string;
  getInitialData: () => TData;
  remove: () => void;
};
```

`getInitialData()` is called once on mount. `remove()` removes the item from the list. Throws on duplicate key.

### useAssistantClientRef

```
function useAssistantClientRef(): {
  parent: AssistantClient;
  current: AssistantClient | null;
};
```

Returns a ref to the store being built. `current` is `null` during resource creation and populated after all sibling scopes are mounted. Use in `useEffect` to access sibling scopes at runtime.

### useAssistantEmit

```
function useAssistantEmit(): <TEvent extends Exclude<AssistantEventName, "*">>(
  event: TEvent,
  payload: AssistantEventPayload[TEvent],
) => void;
```

Returns a stable emit function. Events are delivered via microtask — listeners fire after the current state update settles.

---

## Types

### ScopeRegistry

```
interface ScopeRegistry {}
```

Module augmentation point. Augment this interface to register scopes:

```
declare module "@assistant-ui/store" {
  interface ScopeRegistry {
    counter: {
      methods: {
        getState: () => { count: number };
        increment: () => void;
      };
      meta?: { source: ClientNames; query: Record<string, unknown> };
      events?: { "counter.incremented": { newCount: number } };
    };
  }
}
```

`methods` is required. `meta` and `events` are optional.

### ClientOutput

```
type ClientOutput<K extends ClientNames> = ClientSchemas[K]["methods"] & ClientMethods;
```

The return type for a resource implementing scope `K`. Use as the return type annotation on your resource function.

### ClientNames

```
type ClientNames = keyof ClientSchemas;
```

Union of all registered scope names.

### AssistantClient

```
type AssistantClient = {
  [K in ClientNames]: AssistantClientAccessor<K>;
} & {
  subscribe(listener: () => void): Unsubscribe;
  on<TEvent extends AssistantEventName>(
    selector: AssistantEventSelector<TEvent>,
    callback: AssistantEventCallback<TEvent>,
  ): Unsubscribe;
};
```

The store object returned by `useAui()`. Each scope is an accessor. `subscribe` fires on any state change. `on` subscribes to typed events.

### AssistantClientAccessor

```
type AssistantClientAccessor<K extends ClientNames> =
  (() => ClientSchemas[K]["methods"]) &
  (
    | ClientMeta<K>
    | { source: "root"; query: Record<string, never> }
    | { source: null; query: null }
  ) &
  { name: K };
```

A scope accessor. Call it (`aui.counter()`) to resolve the scope's methods. Read `.source`, `.query`, and `.name` for metadata.

### AssistantState

```
type AssistantState = {
  [K in ClientNames]: ClientSchemas[K]["methods"] extends {
    getState: () => infer S;
  }
    ? S
    : never;
};
```

The state object passed to `useAuiState` selectors. Each key is the return type of that scope's `getState()`.

### ClientMeta

```
type ClientMeta<K extends ClientNames> =
  "meta" extends keyof ClientSchemas[K]
    ? Pick<ClientSchemas[K]["meta"], "source" | "query">
    : never;
```

The `source` and `query` shape for scope `K`, if `meta` is declared in `ScopeRegistry`.

### ClientElement

```
type ClientElement<K extends ClientNames> = ResourceElement<ClientOutput<K>>;
```

A resource element that implements scope `K`.

### Unsubscribe

```
type Unsubscribe = () => void;
```

---

## Event types

### AssistantEventName

```
type AssistantEventName = keyof AssistantEventPayload;
```

Union of all registered event names, plus `"*"`.

### AssistantEventPayload

```
type AssistantEventPayload = ClientEventMap & {
  "*": { [K in keyof ClientEventMap]: { event: K; payload: ClientEventMap[K] } }[keyof ClientEventMap];
};
```

Maps event names to their payload types. The `"*"` key receives a wrapped `{ event, payload }` object.

### AssistantEventSelector

```
type AssistantEventSelector<TEvent extends AssistantEventName> =
  | TEvent
  | { scope: AssistantEventScope<TEvent>; event: TEvent };
```

A string (`"scope.event"`) or object (`{ scope, event }`). Strings default to `scope` matching the event's source.

### AssistantEventScope

```
type AssistantEventScope<TEvent extends AssistantEventName> =
  | "*"
  | EventSource<TEvent>
  | AncestorsOf<EventSource<TEvent>>;
```

Valid scopes to listen at: the event's source scope, any ancestor of that scope, or `"*"` for all.

### AssistantEventCallback

```
type AssistantEventCallback<TEvent extends AssistantEventName> = (
  payload: AssistantEventPayload[TEvent],
) => void;
```

### normalizeEventSelector

```
function normalizeEventSelector<TEvent extends AssistantEventName>(
  selector: AssistantEventSelector<TEvent>,
): { scope: AssistantEventScope<TEvent>; event: TEvent };
```

Converts a string selector to `{ scope, event }` form. Strings like `"counter.incremented"` become `{ scope: "counter", event: "counter.incremented" }`.