> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cedarcopilot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agentic State

Cedar allows your agent to understand what is happening in your application, and the ability to change it. Registering a local state in Cedar is the first step to giving your agent frontend context, letting users point out parts of the UI to the agent, and letting agents manipulate state.

In other words, it allows your agent to read and write to the local react state.

To understand how we internally execute and render actions on your state (and how to override default behavior and rendering for state changes), read [SetState Response Processing](/agent-backend-connection/custom-response-processing#setstate-type) and [SetState Message Rendering](/chat/custom-message-rendering#setstate-type).

## useRegisterState Hook

Register your existing React state with Cedar using the `useRegisterState` hook:

<CodeGroup>
  ```tsx Example theme={null}
  import { useRegisterState } from 'cedar-os';

  const [todos, setTodos] = useState([
  	{ id: 1, text: 'Learn Cedar-OS', completed: false },
  	{ id: 2, text: 'Build amazing AI apps', completed: false },
  ]);

  // Now the agent will know what the state is, how to change it,
  // and have access to calling these setters
  useRegisterState({
  	key: 'todos',
  	description: 'A list of todo items that users can check off',
  	value: todos,
  	setValue: setTodos,
  	stateSetters: {
  		addTodo: {
  			name: 'addTodo',
  			description: 'Add a new todo item',
  			execute: (currentTodos, args: { text: string }) => {
  				const newTodo = {
  					id: Date.now(),
  					text: args.text,
  					completed: false,
  				};
  				setTodos([...currentTodos, newTodo]);
  			},
  		},
  		toggleTodo: {
  			name: 'toggleTodo',
  			description: 'Toggle completion status of a todo',
  			execute: (currentTodos, args: { id: number }) => {
  				setTodos(
  					currentTodos.map((todo) =>
  						todo.id === args.id ? { ...todo, completed: !todo.completed } : todo
  					)
  				);
  			},
  		},
  		removeTodo: {
  			name: 'removeTodo',
  			description: 'Remove a todo item',
  			execute: (currentTodos, args: { id: number }) => {
  				setTodos(currentTodos.filter((todo) => todo.id !== args.id));
  			},
  		},
  	},
  });
  ```

  ```tsx Type theme={null}
  interface RegisterStateOptions<T> {
  	key: string;
  	description?: string;
  	value: T;
  	setValue?: (state: T) => void;
  	stateSetters?: Record<string, Setter<T>>;
  	argsSchema?: ZodSchema<T>; // Automatically included in agent input context as JSON Schema
  	// Deprecated - use stateSetters instead
  	customSetters?: Record<string, Setter<T>>;
  	// Deprecated - use argsSchema instead
  	schema?: ZodSchema<T>;
  }

  interface Setter<T, Args = unknown> {
  	name: string;
  	description: string;
  	argsSchema?: ZodSchema<Args>;
  	execute: (state: T, args: Args) => void;
  	// Deprecated - use argsSchema instead
  	schema?: ZodSchema;
  }

  interface Todo {
  	id: number;
  	text: string;
  	completed: boolean;
  }
  ```
</CodeGroup>

### useCedarState

Use `useCedarState` to create and manage state directly in the Cedar store. It directly replaces useState and works the exact same way, but

<CodeGroup>
  ```tsx Example theme={null}
  import { useCedarState } from 'cedar-os';

  function TodoComponent() {
  	const [todos, setTodos] = useCedarState(
  		'todos',
  		[
  			{ id: 1, text: 'Learn Cedar-OS', completed: false },
  			{ id: 2, text: 'Build amazing AI apps', completed: false },
  		],
  		'A list of todo items that users can check off',
  		{
  			addTodo: {
  				name: 'addTodo',
  				description: 'Add a new todo item',
  				execute: (currentTodos, args: { text: string }) => {
  					const newTodo = {
  						id: Date.now(),
  						text: args.text,
  						completed: false,
  					};
  					setTodos([...currentTodos, newTodo]);
  				},
  			},
  			toggleTodo: {
  				name: 'toggleTodo',
  				description: 'Toggle completion status of a todo',
  				execute: (currentTodos, args: { id: number }) => {
  					setTodos(
  						currentTodos.map((todo) =>
  							todo.id === args.id
  								? { ...todo, completed: !todo.completed }
  								: todo
  						)
  					);
  				},
  			},
  			removeTodo: {
  				name: 'removeTodo',
  				description: 'Remove a todo item',
  				execute: (currentTodos, args: { id: number }) => {
  					setTodos(currentTodos.filter((todo) => todo.id !== args.id));
  				},
  			},
  		}
  	);

  	return (
  		<div>
  			<h2>My Todos</h2>
  			{todos.map((todo) => (
  				<div key={todo.id}>
  					<input
  						type='checkbox'
  						checked={todo.completed}
  						onChange={() => {
  							// You can call the setter directly or use custom setters
  							setTodos(
  								todos.map((t) =>
  									t.id === todo.id ? { ...t, completed: !t.completed } : t
  								)
  							);
  						}}
  					/>
  					<span>{todo.text}</span>
  					<button
  						onClick={() => {
  							setTodos(todos.filter((t) => t.id !== todo.id));
  						}}>
  						Delete
  					</button>
  				</div>
  			))}
  			<button
  				onClick={() => {
  					const newTodo = {
  						id: Date.now(),
  						text: 'New todo',
  						completed: false,
  					};
  					setTodos([...todos, newTodo]);
  				}}>
  				Add Todo
  			</button>
  		</div>
  	);
  }
  ```

  ```tsx Type theme={null}
  function useCedarState<T>(
  	key: string,
  	initialValue: T,
  	description?: string,
  	stateSetters?: Record<string, Setter<T>>,
  	argsSchema?: ZodSchema<T>
  ): [T, (newValue: T) => void];

  // Legacy signature (still supported)
  function useCedarState<T>(
  	key: string,
  	initialValue: T,
  	description?: string,
  	customSetters?: Record<string, Setter<T>>,
  	schema?: ZodSchema<T>
  ): [T, (newValue: T) => void];
  ```
</CodeGroup>

## Accessing Cedar State Functions

### executeStateSetter

Execute state setter functions programmatically using the Cedar store:

<CodeGroup>
  ```tsx Example theme={null}
  import { useCedarStore } from 'cedar-os';

  function TodoActions() {
  	const executeStateSetter = useCedarStore((state) => state.executeStateSetter);

  	const handleAddTodo = async () => {
  		executeStateSetter('todos', 'addTodo', { text: 'Learn about Cedar State' });
  	};

  	const handleToggleTodo = async () => {
  		executeStateSetter('todos', 'toggleTodo', { id: 1 });
  	};

  	const handleRemoveTodo = async () => {
  		executeStateSetter('todos', 'removeTodo', { id: 1 });
  	};

  	return (
  		<div>
  			<button onClick={handleAddTodo}>Add Todo</button>
  			<button onClick={handleToggleTodo}>Toggle First Todo</button>
  			<button onClick={handleRemoveTodo}>Remove First Todo</button>
  		</div>
  	);
  }
  ```

  ```tsx Type theme={null}
  // Access through useCedarStore
  const executeStateSetter = useCedarStore((state) => state.executeStateSetter);

  // Function signature
  executeStateSetter: (
  	key: string,
  	setterKey: string,
  	args: unknown
  ) => void;
  ```
</CodeGroup>

<Warning>
  **Breaking Change in v0.1.11**: Parameter handling has changed. State setters
  now receive arguments as a single object parameter instead of multiple spread
  parameters. Update your setter functions accordingly.
</Warning>

> **Agent Actions**: State setters can be automatically invoked by your agent through structured responses. Learn more about [SetState Response Processing](/agent-backend-connection/custom-response-processing#setstate-type) and [SetState Message Rendering](/chat/custom-message-rendering#setstate-type) to see how agents can execute these setters and display the results.

> **Automatic Cleanup**: States are automatically unregistered when components unmount, ensuring clean state management without manual cleanup.

## Schema Validation with Zod

Cedar OS has runtime validation of setter arguments using Zod schemas:

<CodeGroup>
  ```tsx Example theme={null}
  import { z } from 'zod';
  import { useRegisterState } from 'cedar-os';

  // Define schemas for your setter arguments
  const addTodoSchema = z.object({
  	text: z.string().min(1, 'Todo text cannot be empty'),
  });

  const toggleTodoSchema = z.object({
  	id: z.number().positive('ID must be positive'),
  });

  const [todos, setTodos] = useState([]);

  useRegisterState({
  	key: 'todos',
  	value: todos,
  	setValue: setTodos,
  	stateSetters: {
  		addTodo: {
  			name: 'addTodo',
  			description: 'Add a new todo item',
  			argsSchema: addTodoSchema,
  			execute: (currentTodos, args) => {
  				// args is now type-safe and validated
  				const newTodo = {
  					id: Date.now(),
  					text: args.text, // TypeScript knows this is a string
  					completed: false,
  				};
  				setTodos([...currentTodos, newTodo]);
  			},
  		},
  		toggleTodo: {
  			name: 'toggleTodo',
  			description: 'Toggle completion status of a todo',
  			argsSchema: toggleTodoSchema,
  			execute: (currentTodos, args) => {
  				// args.id is validated as a positive number
  				setTodos(
  					currentTodos.map((todo) =>
  						todo.id === args.id ? { ...todo, completed: !todo.completed } : todo
  					)
  				);
  			},
  		},
  	},
  });
  ```
</CodeGroup>

## getCedarState

Retrieve the current state value for a registered Cedar state key:

<CodeGroup>
  ```tsx Example theme={null}
  import { getCedarState } from 'cedar-os';

  // Get current todos state
  const currentTodos = getCedarState('todos');
  console.log('Current todos:', currentTodos);

  // Use in a function
  function logTodoCount() {
  	const todos = getCedarState('todos');
  	if (todos && Array.isArray(todos)) {
  		console.log(`You have ${todos.length} todos`);
  	}
  }

  // Check if state exists
  function checkTodosExist() {
  	const todos = getCedarState('todos');
  	if (todos) {
  		console.log('Todos state is available');
  	} else {
  		console.log('Todos state not found');
  	}
  }
  ```

  ```tsx Type theme={null}
  function getCedarState(key: string): BasicStateValue | undefined;
  ```
</CodeGroup>

## setCedarState

Directly update the state value for a registered Cedar state key:

<CodeGroup>
  ```tsx Example theme={null}
  import { setCedarState } from 'cedar-os';

  // Set new todos state
  const newTodos = [
  	{ id: 1, text: 'Updated todo', completed: true },
  	{ id: 2, text: 'Another todo', completed: false },
  ];
  setCedarState('todos', newTodos);

  // Update based on current state
  const currentTodos = getCedarState('todos');
  if (currentTodos && Array.isArray(currentTodos)) {
  	const updatedTodos = currentTodos.map((todo) => ({
  		...todo,
  		completed: true,
  	}));
  	setCedarState('todos', updatedTodos);
  }

  // Reset state
  setCedarState('todos', []);
  ```

  ```tsx Type theme={null}
  function setCedarState<T>(key: string, value: T): void;
  ```
</CodeGroup>

## Exposing states to your agent

Now that your application states are registered in Cedar, learn how to expose just the right pieces of them to your agent:

* **Agent Input Context** – orchestrate what context is sent alongside every user message, including state subscriptions and manual entries. See [Agent Input Context](/agent-context/agent-context).
* **Mentions** – let users reference individual state items with simple `@` mentions. See [Mentions](/agent-context/mentions).

These docs walk you through granting the agent scoped, real-time access to your frontend data.
