# Shared State (Tandem)

Sync your app's UI state with the agent in real time for two-way, state-aware experiences.

## What is Shared State?

While AI Actions let the agent perform tasks, Shared State gives the agent eyes and hands inside your application. It creates a two-way sync between your app's UI state (like a form or settings panel) and the agent. The agent reads the current state of your UI in real time and writes changes back to it.

## Why use Shared State?

- **Contextual awareness** — the agent sees exactly what the user sees, so it can give relevant help without asking clarifying questions.
- **Interactive guidance** — instead of just describing steps, the agent can highlight fields, pre-fill values, and walk users through complex workflows.
- **Seamless task automation** — the agent can update your UI directly, turning multi-step processes into a single conversation.

## How it works: a two-way street

- **Your App → Agent**: your app calls `shareState()` whenever the UI changes, keeping the agent's picture of the current screen up to date.
- **Agent → Your App**: when the agent decides to act, it pushes updates through the handler you registered, and your UI re-renders instantly.

<Mermaid chart={`flowchart LR
    subgraph Your App
        UI[UI Component]
        SF["shareState(key, state)"]
    end
    subgraph Foldspace
        AG[Agent]
    end
    UI -- "User types ➜ setForm()" --> SF
    SF -- "State snapshot" --> AG
    AG -- "Agent updates ➜ handler(key, next)" --> UI
`} />

:::note
This page assumes you've already initialized your agent.
:::

## Methods

Two methods on the agent instance manage the whole process.

### `shareState(key, state, handler, stateDescription)`

Establish and update synchronized state. Call it once on initialization, then again
every time the user-side state changes.

| Parameter | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `key` | `string` | Yes | A unique string identifier for this piece of state (e.g. `"contact_form"`). |
| `state` | `object` | Yes | A snapshot of the current UI state object (e.g. `{ name: "", email: "" }`). |
| `handler` | `(key: string, nextState: any) => void` | No | Optional, but required to let the agent push updates back to your UI. Pass it for two-way sync. |
| `stateDescription` | `string` | No | A free-form string that adds context about the state. Can describe the type/model, usage instructions, or provide a human-readable explanation. |
| `persistAcrossPages` | `boolean` | No | |

```javascript
// Initial sync: Register the state key, initial data, and the handler
const agentKey = "YOUR_AGENT_KEY";
const agent = window.foldspace?.agent(agentKey);
agent.current?.shareState(stateKey, form, handleStateChange, stateDescription);
```

#### Guide the agent with `stateDescription`

`stateDescription` is optional but gives context to both developers and the agent.
Though concise by design, it can carry different kinds of guidance:

- **Naming conventions**: e.g. `"All keys in this state should be snake_case"`.
- **Model structure hints**: e.g. `"If 'items' is an empty array, each entry should contain { id: string, quantity: number }"`.
- **Purpose description**: e.g. `"Tracks the shipping address details required for checkout"`.

`stateDescription` enriches the state with descriptive or instructional metadata, so
the UI and the agent interpret the state consistently.

### `clearState(key)`

Tell the agent to stop tracking a piece of state. Call it for cleanup when a component
unmounts or the user navigates away, preventing memory leaks.

| Parameter | Type | Required | Description |
| :--- | :--- | :---: | :--- |
| `key` | `string` | Yes | The unique string identifier for the state you wish to clear. |

## Sync a React form

Synchronize a React form component's state with the agent using hooks.

```typescript

type FormState = {
  name: string;
  email: string;
  company?: string;
};

interface Props {
  agentKey: string;
}

export default function SharedStateForm({ agentKey }: Props) {
  // 1. Local UI state is kept minimal.
  const [form, setForm] = useState<FormState>({ name: "", email: "", company: "" });

  // 2. The agent instance is created once and stored in a ref.
  const agentRef = useRef<any | null>(null);
  const stateKey = "contact_form";
  const stateDescription = `
    type FormState = {
      name: string;
      email: string;
      company?: string;
    };

    interface Props {
      agentKey: string;
    }`;

  // 3. `useEffect` handles the entire lifecycle: setup, subscription, and cleanup.
  useEffect(() => {
    // Initialize the agent
    agentRef.current = window.foldspace?.agent(agentKey);

    // Agent -> UI: Define the handler to receive updates FROM the agent
    const handleStateChange = (key: string, nextState: unknown) => {
      if (key === stateKey) {
        setForm(nextState as FormState); // Update local state
      }
    };

    // Initial sync: Register the state key, initial data, and the handler
    agentRef.current?.shareState(stateKey, form, handleStateChange, stateDescription);

    // Cleanup function: Tell the agent to stop tracking on unmount
    return () => {
      agentRef.current?.clearState(stateKey);
      agentRef.current = null;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [agentKey]);

  // 4. UI -> Agent: Call this on user input to keep the agent's snapshot fresh.
  const updateField = <K extends keyof FormState>(key: K, value: FormState[K]) => {
    const next = { ...form, [key]: value };
    setForm(next);
    // Send the fresh snapshot to the agent
    agentRef.current?.shareState(stateKey, next);
  };

  // 5. Render your form inputs and call updateField on change.
  return <>...</>;
}
```

<Mermaid chart={`sequenceDiagram
    participant App as Your App
    participant SDK as Foldspace SDK
    participant Agent as Agent
    App->>SDK: shareState("form", data, handler)
    SDK->>Agent: State snapshot
    Note right of Agent: Agent reads form context
    Agent-->>SDK: Updated state
    SDK-->>App: handler("form", nextState)
    App->>App: setForm(nextState)
`} />

## Related

- [AI Actions](./actions-1): give your agent custom actions that automate workflows and return context-aware responses.
- [Knowledge Base](./knowledge-base): connect a knowledge base for accurate, context-rich answers.
