Two files, one repository
Shubhamsaboo/awesome-llm-apps ships 2 formats across 2 indexed files. The question worth asking is whether the second one says anything the first does not.
CompareAGENTS.md ↔ CLAUDE.md
| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 9 | 23 | 0% |
| Commands | 4 | 4 | 1 | 44% |
| Section tags | 4 | 6 | 2 | 33% |
What each file covers
Sections
0 shared · 9 only in A · 23 only in B- − Repository Guidelines
- − Project Structure & Module Organization
- − Build, Test, and Development
- − Coding Style & Naming Conventions
- − Testing Guidelines
- − Commit & Pull Request Guidelines
- − Environment, Security & Config
- − Charts & CopilotKit Tips
- − Architecture Overview
- + CopilotKit + LangGraph Todo Demo
- + Purpose
- + Core Concept
- + Architecture
- + Repository Structure
- + Key Pattern: Agent State with CopilotKit v2
- + How It Works
- + Why This Pattern?
- + Implementation Details
- + Agent Backend
- + Frontend
- + How State Flows
- + Tech Stack
- + Development
- + Install dependencies (also sets up agent via postinstall)
- + Start both frontend and agent
- + Start individually
- + Build
- + Environment Setup
- + Set OpenAI API key
- + Edit .env and add your OPENAI_API_KEY
- + Design Principles
- + Key Takeaways for Developers
Commands
4 shared · 4 only in A · 1 only in B- − eslint.config.mjs
- − npm start
- − npm run lint
- − pytest
- + npm install
- npm run dev
- npm run dev:ui
- npm run dev:agent
- npm run build
Section tags
4 shared · 6 only in A · 2 only in B- − test
- − lint-format
- − code-style
- − git-pr
- − security
- − do-not
- + dependencies
- + agent-behaviour
- setup
- build
- architecture
- api
Line diff
Shubhamsaboo/awesome-llm-apps · generative_ui_agents/ai-dashboard-canvas-agent/AGENTS.md
@@ −1 @@
1# Repository Guidelines
2
3## Project Structure & Module Organization
4
5- Frontend (Next.js + TypeScript): `src/app/**` (pages: `page.tsx`, `layout.tsx`, styles: `globals.css`). API route for CopilotKit: `src/app/api/copilotkit/route.ts`.
6- Agent (ADK/Python): `agent/agent.py`, virtual env in `agent/.venv`, deps in `agent/requirements.txt`.
7- Public assets: `public/`. Config: `next.config.ts`, `tsconfig.json`, `eslint.config.mjs`.
8- Scripts: `scripts/run-agent.sh`, `scripts/setup-agent.sh`.
9
10## Build, Test, and Development
11
12- `npm run dev` — runs UI (`next dev --turbopack`) and the Python agent concurrently.
13- `npm run dev:ui` — frontend only; useful for UI iteration.
14- `npm run dev:agent` — agent only; activates `.venv` and runs `agent.py`.
15- `npm run build` — production build for the Next.js app.
16- `npm start` — serve the built app.
17- `npm run lint` — lint the frontend with Next/ESLint.
18- First-time setup installs the agent via `postinstall` (creates `.venv` and installs Python deps).
19
20## Coding Style & Naming Conventions
21
22- TypeScript/React: 2-space indent, PascalCase components, camelCase variables, file-based routing under `src/app/**`.
23- Python agent: follow PEP 8; keep modules small and composable.
24- Linting: Next.js ESLint config (`npm run lint`). Prefer explicit types in exported APIs.
25- Components: colocate with usage; export from an `index.ts` when creating reusable modules.
26
27## Testing Guidelines
28
29- Currently no test harness. When adding tests:
30 - Frontend: Jest/Vitest in `src/__tests__/` with `*.test.ts(x)`.
31 - Agent: `pytest` in `agent/tests/` with `test_*.py`.
32 - Aim for high coverage on data shaping (dashboard spec generation, adapters).
33
34## Commit & Pull Request Guidelines
35
36- Conventional Commits: `type(scope): message`.
37 - Types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `ci`.
38 - Example: `feat(charts): support pie charts`.
39- PRs: clear description, linked issue, before/after screenshots or JSON spec samples, and testing notes.
40- Keep PRs focused; call out env/config changes explicitly.
41
42## Environment, Security & Config
43
44- Place secrets in `.env.local` (frontend) and `agent/.env` (agent). Never commit secrets.
45- Example keys (adjust to your provider):
46 - Frontend: `NEXT_PUBLIC_CPK_ENDPOINT=/api/copilotkit`.
47 - Agent: `GOOGLE_API_KEY=...` (Gemini), or `OPENAI_API_KEY=...` if applicable.
48- Validate/sanitize prompts; avoid logging PII. Prefer `INFO` logs with redaction.
49
50## Charts & CopilotKit Tips
51
52- Dashboard spec (example): `{ "type": "line", "title": "Revenue", "x": "date", "y": "revenue" }`.
53- Supported types to target in UI: `line`, `bar`, `pie`
54- Naming: use singular `x`/`y` for series
55- Recharts via CPK: map spec→props; e.g., `LineChart` with `dataKey={spec.y}` and `XAxis dataKey={spec.x}`;
56
57## Architecture Overview
58
59- Next.js app hosts CopilotKit UI and API route; Python agent performs ADK/Gemini orchestration. `npm run dev` runs both together.
60
Shubhamsaboo/awesome-llm-apps · generative_ui_agents/generative-ui-starter-project/CLAUDE.md
@@ +1 @@
1# CopilotKit + LangGraph Todo Demo
2
3## Purpose
4
5This repository serves as both a **showcase** and **template** for building AI agents with CopilotKit and LangGraph. It demonstrates how CopilotKit can drive interactive UI beyond just chat, using a **collaborative todo list** as the primary example.
6
7**Target audience:** Developers evaluating CopilotKit or starting new projects with AI agents.
8
9## Core Concept
10
11The todo list demonstrates **agent-driven UI** where:
12
13- The agent can manipulate application state (adding todos, updating status, organizing tasks)
14- Users can interact with the same state (editing titles, checking off tasks, deleting todos)
15- Both agent and user changes update the same shared state
16- The UI reactively updates based on agent state changes
17
18This uses CopilotKit's **v2 agent state pattern** where state lives in the agent and syncs to the frontend.
19
20## Architecture
21
22This is a **flat npm project** with a Next.js frontend at the root and a Python agent in `agent/`.
23
24### Repository Structure
25
26```
27├── src/
28│ ├── app/
29│ │ ├── page.tsx # Main page - wires up all components
30│ │ └── api/copilotkit/ # CopilotKit API route
31│ ├── components/
32│ │ ├── canvas/ # Todo list UI
33│ │ │ ├── index.tsx # Canvas container
34│ │ │ ├── todo-list.tsx # Todo list with columns
35│ │ │ ├── todo-column.tsx # Column (pending/completed)
36│ │ │ └── todo-card.tsx # Individual todo card
37│ │ ├── example-layout/ # Layout: chat + canvas side-by-side
38│ │ └── generative-ui/ # Example generative UI components
39│ └── hooks/
40│ ├── use-generative-ui-examples.tsx # Example CopilotKit patterns
41│ └── use-example-suggestions.tsx # Chat suggestions
42├── agent/ # LangGraph Python agent
43│ ├── main.py # Agent entry point
44│ └── src/
45│ ├── todos.py # Todo tools and state schema
46│ └── query.py # Example data query tool
47├── scripts/ # Agent setup and run scripts
48│ ├── setup-agent.sh / .bat
49│ └── run-agent.sh / .bat
50├── package.json # Root project config (npm + concurrently)
51└── next.config.ts
52```
53
54## Key Pattern: Agent State with CopilotKit v2
55
56The todo list uses **CopilotKit v2's agent state pattern** where state lives in the agent backend and syncs bidirectionally with the frontend.
57
58### How It Works
59
601. **Agent defines state schema and tools** (Python)
61
62 ```python
63 # agent/src/todos.py
64 class Todo(TypedDict):
65 id: str
66 title: str
67 description: str
68 emoji: str
69 status: Literal["pending", "completed"]
70
71 class AgentState(TypedDict):
72 todos: list[Todo]
73
74 @tool
75 def manage_todos(todos: list[Todo], runtime: ToolRuntime) -> Command:
76 """Manage the current todos."""
77 return Command(update={"todos": todos, ...})
78 ```
79
802. **Frontend reads from agent state**
81
82 ```typescript
83 // src/components/canvas/index.tsx
84 const { agent } = useAgent();
85
86 return (
87 <TodoList
88 todos={agent.state?.todos || []}
89 onUpdate={(updatedTodos) => agent.setState({ todos: updatedTodos })}
90 isAgentRunning={agent.isRunning}
91 />
92 );
93 ```
94
953. **User interactions update agent state**
96
97 ```typescript
98 // User clicks checkbox → frontend calls agent.setState()
99 const toggleStatus = (todo) => {
100 const updated = todos.map((t) =>
101 t.id === todo.id
102 ? { ...t, status: t.status === "completed" ? "pending" : "completed" }
103 : t,
104 );
105 agent.setState({ todos: updated });
106 };
107 ```
108
1094. **Agent can manipulate state via tools**
110 - The agent calls `manage_todos` tool to update the todo list
111 - Both user and agent changes update the same `agent.state.todos`
112 - Frontend automatically re-renders when state changes
113
114### Why This Pattern?
115
116- **Single source of truth**: State lives in the agent, not duplicated in frontend
117- **Bidirectional sync**: User changes → agent state, Agent changes → UI update
118- **Simple**: No need for separate frontend state management
119- **Observable**: Agent has full visibility into state changes
120
121## Implementation Details
122
123### Agent Backend
124
125**Agent Definition** (`agent/main.py`):
126
127```python
128from langchain.agents import create_agent
129from copilotkit import CopilotKitMiddleware
130from src.todos import todo_tools, AgentState
131
132agent = create_agent(
133 model="gpt-5.5",
134 tools=[*todo_tools, ...], # manage_todos, get_todos
135 middleware=[CopilotKitMiddleware()],
136 state_schema=AgentState, # Defines state shape
137 system_prompt="You are a helpful assistant..."
138)
139```
140
141**Todo Tools** (`agent/src/todos.py`):
142
143```python
144@tool
145def manage_todos(todos: list[Todo], runtime: ToolRuntime) -> Command:
146 """Manage the current todos."""
147 # Ensure todos have unique IDs
148 for todo in todos:
149 if "id" not in todo or not todo["id"]:
150 todo["id"] = str(uuid.uuid4())
151
152 # Update agent state
153 return Command(update={
154 "todos": todos,
155 "messages": [ToolMessage(...)]
156 })
157
158@tool
159def get_todos(runtime: ToolRuntime):
160 """Get the current todos."""
161 return runtime.state.get("todos", [])
162```
163
164### Frontend
165
166**Canvas Component** (`src/components/canvas/index.tsx`):
167
168```typescript
169export function Canvas() {
170 const { agent } = useAgent(); // CopilotKit v2 hook
171
172 return (
173 <div className="h-full p-8 bg-gray-50">
174 <TodoList
175 // Read state from agent
176 todos={agent.state?.todos || []}
177 // Update state in agent
178 onUpdate={(updatedTodos) => agent.setState({ todos: updatedTodos })}
179 // React to agent execution
180 isAgentRunning={agent.isRunning}
181 />
182 </div>
183 );
184}
185```
186
187**Todo List** (`src/components/canvas/todo-list.tsx`):
188
189```typescript
190export function TodoList({ todos, onUpdate, isAgentRunning }: TodoListProps) {
191 const toggleStatus = (todo: Todo) => {
192 const updated = todos.map((t) =>
193 t.id === todo.id
194 ? { ...t, status: t.status === "completed" ? "pending" : "completed" }
195 : t
196 );
197 onUpdate(updated); // Calls agent.setState()
198 };
199
200 const addTodo = () => {
201 const newTodo = { id: crypto.randomUUID(), ... };
202 onUpdate([...todos, newTodo]);
203 };
204
205 return (
206 <div className="flex gap-8">
207 <TodoColumn title="To Do" todos={pendingTodos} onAddTodo={addTodo} ... />
208 <TodoColumn title="Done" todos={completedTodos} ... />
209 </div>
210 );
211}
212```
213
214### How State Flows
215
2161. **User adds/edits todo** → Frontend calls `agent.setState({ todos: [...] })`
2172. **Agent state updates** → CopilotKit syncs to backend
2183. **Agent observes change** → Can respond via `manage_todos` tool
2194. **Agent modifies todos** → Calls `manage_todos` tool
2205. **State syncs to frontend** → `agent.state.todos` updates
2216. **UI re-renders** → React sees new state and updates display
222
223**Key insight**: State lives in the agent, frontend just reads/writes to it via CopilotKit hooks.
224
225## Tech Stack
226
227- **Frontend**: Next.js 16, React 19, TailwindCSS 4
228- **Agent**: LangGraph (Python), OpenAI GPT-5.2
229- **CopilotKit**: React hooks for agent integration (v2)
230- **Build**: npm with concurrently for parallel dev processes
231- **Other**: Recharts for generative UI examples
232
233## Development
234
235```bash
236# Install dependencies (also sets up agent via postinstall)
237npm install
238
239# Start both frontend and agent
240npm run dev
241
242# Start individually
243npm run dev:ui # Next.js frontend on port 3000
244npm run dev:agent # LangGraph agent on port 8123
245
246# Build
247npm run build
248```
249
250### Environment Setup
251
252```bash
253# Set OpenAI API key
254cp .env.example .env
255# Edit .env and add your OPENAI_API_KEY
256```
257
258## Design Principles
259
2601. **Simple over complex** - The todo list is intentionally simple and focused
2612. **CopilotKit v2 patterns** - Uses modern agent state management
2623. **Template-first** - Code is meant to be forked and extended
2634. **Showcasing agent-driven UI** - Demonstrates AI manipulating application state beyond chat
264
265---
266
267## Key Takeaways for Developers
268
269**State Management Pattern**: This app uses CopilotKit v2's agent state pattern where:
270
271- State is defined in the agent backend (Python TypedDict)
272- Frontend reads via `agent.state.todos`
273- Frontend writes via `agent.setState({ todos: ... })`
274- Agent can modify state via tools (`manage_todos`)
275- Changes sync bidirectionally automatically
276
277**When extending this template**:
278
279- Define state schema in the agent (`AgentState`)
280- Create tools that manipulate state via `Command(update={...})`
281- Use `useAgent()` hook in frontend to read/write state
282- Let CopilotKit handle the sync - no manual state management needed
283
284This pattern works great for **agent-driven applications** where the AI needs to manipulate structured application state, not just chat.
285
@@ −1 +1 @@
1−# Repository Guidelines
1+# CopilotKit + LangGraph Todo Demo
22
3−## Project Structure & Module Organization
3+## Purpose
44
5−- Frontend (Next.js + TypeScript): `src/app/**` (pages: `page.tsx`, `layout.tsx`, styles: `globals.css`). API route for CopilotKit: `src/app/api/copilotkit/route.ts`.
6−- Agent (ADK/Python): `agent/agent.py`, virtual env in `agent/.venv`, deps in `agent/requirements.txt`.
7−- Public assets: `public/`. Config: `next.config.ts`, `tsconfig.json`, `eslint.config.mjs`.
8−- Scripts: `scripts/run-agent.sh`, `scripts/setup-agent.sh`.
5+This repository serves as both a **showcase** and **template** for building AI agents with CopilotKit and LangGraph. It demonstrates how CopilotKit can drive interactive UI beyond just chat, using a **collaborative todo list** as the primary example.
96
10−## Build, Test, and Development
7+**Target audience:** Developers evaluating CopilotKit or starting new projects with AI agents.
118
12−- `npm run dev` — runs UI (`next dev --turbopack`) and the Python agent concurrently.
13−- `npm run dev:ui` — frontend only; useful for UI iteration.
14−- `npm run dev:agent` — agent only; activates `.venv` and runs `agent.py`.
15−- `npm run build` — production build for the Next.js app.
16−- `npm start` — serve the built app.
17−- `npm run lint` — lint the frontend with Next/ESLint.
18−- First-time setup installs the agent via `postinstall` (creates `.venv` and installs Python deps).
9+## Core Concept
1910
20−## Coding Style & Naming Conventions
11+The todo list demonstrates **agent-driven UI** where:
2112
22−- TypeScript/React: 2-space indent, PascalCase components, camelCase variables, file-based routing under `src/app/**`.
23−- Python agent: follow PEP 8; keep modules small and composable.
24−- Linting: Next.js ESLint config (`npm run lint`). Prefer explicit types in exported APIs.
25−- Components: colocate with usage; export from an `index.ts` when creating reusable modules.
13+- The agent can manipulate application state (adding todos, updating status, organizing tasks)
14+- Users can interact with the same state (editing titles, checking off tasks, deleting todos)
15+- Both agent and user changes update the same shared state
16+- The UI reactively updates based on agent state changes
2617
27−## Testing Guidelines
18+This uses CopilotKit's **v2 agent state pattern** where state lives in the agent and syncs to the frontend.
2819
29−- Currently no test harness. When adding tests:
30− - Frontend: Jest/Vitest in `src/__tests__/` with `*.test.ts(x)`.
31− - Agent: `pytest` in `agent/tests/` with `test_*.py`.
32− - Aim for high coverage on data shaping (dashboard spec generation, adapters).
20+## Architecture
3321
34−## Commit & Pull Request Guidelines
22+This is a **flat npm project** with a Next.js frontend at the root and a Python agent in `agent/`.
3523
36−- Conventional Commits: `type(scope): message`.
37− - Types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `ci`.
38− - Example: `feat(charts): support pie charts`.
39−- PRs: clear description, linked issue, before/after screenshots or JSON spec samples, and testing notes.
40−- Keep PRs focused; call out env/config changes explicitly.
24+### Repository Structure
4125
42−## Environment, Security & Config
26+```
27+├── src/
28+│ ├── app/
29+│ │ ├── page.tsx # Main page - wires up all components
30+│ │ └── api/copilotkit/ # CopilotKit API route
31+│ ├── components/
32+│ │ ├── canvas/ # Todo list UI
33+│ │ │ ├── index.tsx # Canvas container
34+│ │ │ ├── todo-list.tsx # Todo list with columns
35+│ │ │ ├── todo-column.tsx # Column (pending/completed)
36+│ │ │ └── todo-card.tsx # Individual todo card
37+│ │ ├── example-layout/ # Layout: chat + canvas side-by-side
38+│ │ └── generative-ui/ # Example generative UI components
39+│ └── hooks/
40+│ ├── use-generative-ui-examples.tsx # Example CopilotKit patterns
41+│ └── use-example-suggestions.tsx # Chat suggestions
42+├── agent/ # LangGraph Python agent
43+│ ├── main.py # Agent entry point
44+│ └── src/
45+│ ├── todos.py # Todo tools and state schema
46+│ └── query.py # Example data query tool
47+├── scripts/ # Agent setup and run scripts
48+│ ├── setup-agent.sh / .bat
49+│ └── run-agent.sh / .bat
50+├── package.json # Root project config (npm + concurrently)
51+└── next.config.ts
52+```
4353
44−- Place secrets in `.env.local` (frontend) and `agent/.env` (agent). Never commit secrets.
45−- Example keys (adjust to your provider):
46− - Frontend: `NEXT_PUBLIC_CPK_ENDPOINT=/api/copilotkit`.
47− - Agent: `GOOGLE_API_KEY=...` (Gemini), or `OPENAI_API_KEY=...` if applicable.
48−- Validate/sanitize prompts; avoid logging PII. Prefer `INFO` logs with redaction.
54+## Key Pattern: Agent State with CopilotKit v2
4955
50−## Charts & CopilotKit Tips
56+The todo list uses **CopilotKit v2's agent state pattern** where state lives in the agent backend and syncs bidirectionally with the frontend.
5157
52−- Dashboard spec (example): `{ "type": "line", "title": "Revenue", "x": "date", "y": "revenue" }`.
53−- Supported types to target in UI: `line`, `bar`, `pie`
54−- Naming: use singular `x`/`y` for series
55−- Recharts via CPK: map spec→props; e.g., `LineChart` with `dataKey={spec.y}` and `XAxis dataKey={spec.x}`;
58+### How It Works
5659
57−## Architecture Overview
60+1. **Agent defines state schema and tools** (Python)
5861
59−- Next.js app hosts CopilotKit UI and API route; Python agent performs ADK/Gemini orchestration. `npm run dev` runs both together.
62+ ```python
63+ # agent/src/todos.py
64+ class Todo(TypedDict):
65+ id: str
66+ title: str
67+ description: str
68+ emoji: str
69+ status: Literal["pending", "completed"]
70+
71+ class AgentState(TypedDict):
72+ todos: list[Todo]
73+
74+ @tool
75+ def manage_todos(todos: list[Todo], runtime: ToolRuntime) -> Command:
76+ """Manage the current todos."""
77+ return Command(update={"todos": todos, ...})
78+ ```
79+
80+2. **Frontend reads from agent state**
81+
82+ ```typescript
83+ // src/components/canvas/index.tsx
84+ const { agent } = useAgent();
85+
86+ return (
87+ <TodoList
88+ todos={agent.state?.todos || []}
89+ onUpdate={(updatedTodos) => agent.setState({ todos: updatedTodos })}
90+ isAgentRunning={agent.isRunning}
91+ />
92+ );
93+ ```
94+
95+3. **User interactions update agent state**
96+
97+ ```typescript
98+ // User clicks checkbox → frontend calls agent.setState()
99+ const toggleStatus = (todo) => {
100+ const updated = todos.map((t) =>
101+ t.id === todo.id
102+ ? { ...t, status: t.status === "completed" ? "pending" : "completed" }
103+ : t,
104+ );
105+ agent.setState({ todos: updated });
106+ };
107+ ```
108+
109+4. **Agent can manipulate state via tools**
110+ - The agent calls `manage_todos` tool to update the todo list
111+ - Both user and agent changes update the same `agent.state.todos`
112+ - Frontend automatically re-renders when state changes
113+
114+### Why This Pattern?
115+
116+- **Single source of truth**: State lives in the agent, not duplicated in frontend
117+- **Bidirectional sync**: User changes → agent state, Agent changes → UI update
118+- **Simple**: No need for separate frontend state management
119+- **Observable**: Agent has full visibility into state changes
120+
121+## Implementation Details
122+
123+### Agent Backend
124+
125+**Agent Definition** (`agent/main.py`):
126+
127+```python
128+from langchain.agents import create_agent
129+from copilotkit import CopilotKitMiddleware
130+from src.todos import todo_tools, AgentState
131+
132+agent = create_agent(
133+ model="gpt-5.5",
134+ tools=[*todo_tools, ...], # manage_todos, get_todos
135+ middleware=[CopilotKitMiddleware()],
136+ state_schema=AgentState, # Defines state shape
137+ system_prompt="You are a helpful assistant..."
138+)
139+```
140+
141+**Todo Tools** (`agent/src/todos.py`):
142+
143+```python
144+@tool
145+def manage_todos(todos: list[Todo], runtime: ToolRuntime) -> Command:
146+ """Manage the current todos."""
147+ # Ensure todos have unique IDs
148+ for todo in todos:
149+ if "id" not in todo or not todo["id"]:
150+ todo["id"] = str(uuid.uuid4())
151+
152+ # Update agent state
153+ return Command(update={
154+ "todos": todos,
155+ "messages": [ToolMessage(...)]
156+ })
157+
158+@tool
159+def get_todos(runtime: ToolRuntime):
160+ """Get the current todos."""
161+ return runtime.state.get("todos", [])
162+```
163+
164+### Frontend
165+
166+**Canvas Component** (`src/components/canvas/index.tsx`):
167+
168+```typescript
169+export function Canvas() {
170+ const { agent } = useAgent(); // CopilotKit v2 hook
171+
172+ return (
173+ <div className="h-full p-8 bg-gray-50">
174+ <TodoList
175+ // Read state from agent
176+ todos={agent.state?.todos || []}
177+ // Update state in agent
178+ onUpdate={(updatedTodos) => agent.setState({ todos: updatedTodos })}
179+ // React to agent execution
180+ isAgentRunning={agent.isRunning}
181+ />
182+ </div>
183+ );
184+}
185+```
186+
187+**Todo List** (`src/components/canvas/todo-list.tsx`):
188+
189+```typescript
190+export function TodoList({ todos, onUpdate, isAgentRunning }: TodoListProps) {
191+ const toggleStatus = (todo: Todo) => {
192+ const updated = todos.map((t) =>
193+ t.id === todo.id
194+ ? { ...t, status: t.status === "completed" ? "pending" : "completed" }
195+ : t
196+ );
197+ onUpdate(updated); // Calls agent.setState()
198+ };
199+
200+ const addTodo = () => {
201+ const newTodo = { id: crypto.randomUUID(), ... };
202+ onUpdate([...todos, newTodo]);
203+ };
204+
205+ return (
206+ <div className="flex gap-8">
207+ <TodoColumn title="To Do" todos={pendingTodos} onAddTodo={addTodo} ... />
208+ <TodoColumn title="Done" todos={completedTodos} ... />
209+ </div>
210+ );
211+}
212+```
213+
214+### How State Flows
215+
216+1. **User adds/edits todo** → Frontend calls `agent.setState({ todos: [...] })`
217+2. **Agent state updates** → CopilotKit syncs to backend
218+3. **Agent observes change** → Can respond via `manage_todos` tool
219+4. **Agent modifies todos** → Calls `manage_todos` tool
220+5. **State syncs to frontend** → `agent.state.todos` updates
221+6. **UI re-renders** → React sees new state and updates display
222+
223+**Key insight**: State lives in the agent, frontend just reads/writes to it via CopilotKit hooks.
224+
225+## Tech Stack
226+
227+- **Frontend**: Next.js 16, React 19, TailwindCSS 4
228+- **Agent**: LangGraph (Python), OpenAI GPT-5.2
229+- **CopilotKit**: React hooks for agent integration (v2)
230+- **Build**: npm with concurrently for parallel dev processes
231+- **Other**: Recharts for generative UI examples
232+
233+## Development
234+
235+```bash
236+# Install dependencies (also sets up agent via postinstall)
237+npm install
238+
239+# Start both frontend and agent
240+npm run dev
241+
242+# Start individually
243+npm run dev:ui # Next.js frontend on port 3000
244+npm run dev:agent # LangGraph agent on port 8123
245+
246+# Build
247+npm run build
248+```
249+
250+### Environment Setup
251+
252+```bash
253+# Set OpenAI API key
254+cp .env.example .env
255+# Edit .env and add your OPENAI_API_KEY
256+```
257+
258+## Design Principles
259+
260+1. **Simple over complex** - The todo list is intentionally simple and focused
261+2. **CopilotKit v2 patterns** - Uses modern agent state management
262+3. **Template-first** - Code is meant to be forked and extended
263+4. **Showcasing agent-driven UI** - Demonstrates AI manipulating application state beyond chat
264+
265+---
266+
267+## Key Takeaways for Developers
268+
269+**State Management Pattern**: This app uses CopilotKit v2's agent state pattern where:
270+
271+- State is defined in the agent backend (Python TypedDict)
272+- Frontend reads via `agent.state.todos`
273+- Frontend writes via `agent.setState({ todos: ... })`
274+- Agent can modify state via tools (`manage_todos`)
275+- Changes sync bidirectionally automatically
276+
277+**When extending this template**:
278+
279+- Define state schema in the agent (`AgentState`)
280+- Create tools that manipulate state via `Command(update={...})`
281+- Use `useAgent()` hook in frontend to read/write state
282+- Let CopilotKit handle the sync - no manual state management needed
283+
284+This pattern works great for **agent-driven applications** where the AI needs to manipulate structured application state, not just chat.
60285
