--- title: Quickstart description: Install Store and connect your first Tap resource to React. --- Store (`@assistant-ui/store`) connects Tap resources to React with scoped, type-safe state management. ## Installation ```sh npm install @assistant-ui/store @assistant-ui/tap ``` ## Define your scope types Register your scopes by augmenting the `ScopeRegistry` interface. This gives you type safety across all Store hooks. ```ts title="lib/store/counter-scope.ts" import "@assistant-ui/store"; declare module "@assistant-ui/store" { interface ScopeRegistry { counter: { methods: { getState: () => { count: number }; increment: () => void; }; }; } } ``` ## Create a resource Define a Tap resource that returns `ClientOutput<"counter">`. This connects the resource's methods to the scope type you just registered. ```ts title="lib/store/counter-store.ts" import { resource } from "@assistant-ui/tap"; import { useState, useMemo } from "react"; import type { ClientOutput } from "@assistant-ui/store"; const useCounterResource = ({ initialCount = 0, }: { initialCount?: number; }): ClientOutput<"counter"> => { const [count, setCount] = useState(initialCount); const state = useMemo(() => ({ count }), [count]); return { getState: () => state, increment: () => setCount((c) => c + 1), }; }; export const CounterResource = resource(useCounterResource); ``` ## Use it in React Use `useAui` to create a store, `AuiProvider` to provide it to the tree, and `useAuiState` to subscribe to state. ```tsx title="app/CounterApp.tsx" "use client"; import { useAui, AuiProvider } from "@assistant-ui/store"; import { CounterResource } from "@/lib/store/counter-store"; import { CounterDisplay } from "./CounterDisplay"; export const CounterApp = () => { const aui = useAui({ counter: CounterResource({ initialCount: 0 }), }); return ( ); }; ``` ```tsx title="app/CounterDisplay.tsx" "use client"; import { useAui, useAuiState } from "@assistant-ui/store"; export const CounterDisplay = () => { const count = useAuiState((s) => s.counter.count); const aui = useAui(); return (

Count: {count}

); }; ``` `useAuiState((s) => s.counter.count)` subscribes to just the `count` value, so the component only re-renders when it changes. `aui.counter()` returns the methods object, so `aui.counter().increment()` calls the `increment` method you defined in the resource. ## Next steps Nest scopes with Derived and AuiProvider. Emit and subscribe to typed events.