Want sandman66666/openclaw-ui knowledge in your AI?

React

A Next.js web dashboard for managing and interacting with OpenClaw, an AI agent platform. It provides a GUI frontend that proxies to the OpenClaw CLI/backend, allowing users to chat with AI agents, manage skills, channels, cron jobs, and sessions through a browser-based interface instead of the command line.

Tech Stack

ReactNext.js

Key Features

  • AI Agent Chat Interface
  • Skills Management
  • Agents & Channels Overview
  • Cron Job Monitoring
  • Gateway Connection Settings
  • Tabbed Navigation App Shell
  • Theme & Appearance Management

Entry Points

Start here when working with this codebase

Root Page
src/app/page.tsx

The root Next.js page component that dynamically loads the main application shell

Start here when debugging initial page load, understanding the app bootstrap sequence, or modifying what renders at the root URL

App Shell
src/components/app-shell.tsx

Orchestrates the main application layout, applies themes, and routes between different view components (chat, settings, etc.) based on user navigation state

Start here when adding a new top-level view/tab, changing the overall layout structure, or modifying how navigation between views works

Global State Store
src/stores/app-store.ts

Zustand store managing all global application state including user preferences, connection settings, active view, chat messages, and persistent storage

Start here when adding new global state, modifying user preferences, or understanding what data is available across the app

Data Fetching Hooks
src/hooks/use-data.ts

Custom React hooks that fetch data from API routes and synchronize results into the Zustand app store

Start here when adding a new data fetching hook for a new API endpoint, or debugging why data isn't loading into the UI

OpenClaw API Client
src/lib/openclaw-api.ts

Server-side bridge to the OpenClaw CLI/config system, providing typed functions to read skills, agents, channels, and sessions

Start here when adding a new data source from the OpenClaw backend, or modifying how existing data is fetched from the CLI/config layer

App Layout & Metadata
src/app/layout.tsx

Configures app-wide metadata, viewport settings, fonts, and provides the root HTML structure wrapping all pages

Start here when changing global metadata, adding a new font, modifying the HTML document structure, or adding a global provider

How to Make Changes

Common modification patterns for this codebase

Add a new API endpoint

1
src/lib/openclaw-api.ts

Add a new typed async function that fetches data from the OpenClaw backend. Export a function like `getMyNewResource()` that returns typed data.

Pattern: Follow the pattern of `getSkills()` or `getAgents()` in src/lib/openclaw-api.ts — each function calls the OpenClaw CLI or reads config, parses the result, and returns a typed array/object

2
src/app/api/{resource}/route.ts

Create a new directory under src/app/api/ with a route.ts file. Export an async `GET` (or `POST`) function that calls the openclaw-api function and returns `NextResponse.json()`.

Pattern: Copy the exact structure of src/app/api/agents/route.ts — it imports from src/lib/openclaw-api.ts, calls the data function in a try/catch, and returns NextResponse.json() with the result or a 500 error response

3
src/hooks/use-data.ts

Add a new custom hook (e.g., `useMyNewResource`) that fetches from your new `/api/{resource}` endpoint and writes the result into the Zustand store.

Pattern: Follow the pattern of existing hooks in src/hooks/use-data.ts — each hook uses useEffect to fetch from an API route, parses the JSON response, and calls a setter from the app store (accessed via `useAppStore`)

4
src/stores/app-store.ts

Add new state fields and setter actions to the Zustand store for the new resource data (e.g., `myResources: []` and `setMyResources: (data) => set({ myResources: data })`).

Pattern: Follow how `skills`, `agents`, `channels` state slices are defined in src/stores/app-store.ts — each has a typed array field initialized to `[]` and a corresponding setter action

Conventions to follow:

API route files must be named `route.ts` inside a directory matching the resource name under src/app/api/All API route handlers use try/catch and return NextResponse.json() with appropriate status codes (200 for success, 500 for errors)Data fetching hooks in src/hooks/use-data.ts always sync results into the Zustand store rather than returning local stateThe OpenClaw API client in src/lib/openclaw-api.ts is server-side only — never import it directly in client components

Add a new feature view (e.g., a new tab/page in the app)

1
src/components/views/{feature}-view.tsx

Create a new view component file. This is the main UI for the feature. Export a default React component.

Pattern: Follow the structure of src/components/views/settings-view.tsx — it's a self-contained view component that reads from the Zustand store via `useAppStore()` and renders a complete feature UI with its own local state as needed

2
src/stores/app-store.ts

Add the new view name to the navigation/active-view type union and add any feature-specific state fields and setters the view needs.

Pattern: Look at how existing view names (like the chat and settings views) are defined as valid values for the active view state in src/stores/app-store.ts, and add your new view identifier to that type

3
src/components/app-shell.tsx

Import the new view component and add a conditional render branch that displays it when the active view state matches your new view identifier.

Pattern: Follow how src/components/app-shell.tsx conditionally renders src/components/views/chat-view.tsx and src/components/views/settings-view.tsx based on the current active view from the store — add an equivalent branch for your new view

4
src/components/layout/sidebar.tsx

Add a new navigation item/tab button that sets the active view to your new view identifier when clicked.

Pattern: Follow the existing tab buttons in src/components/layout/sidebar.tsx — each has an icon, label, and onClick handler that updates the active view in the Zustand store

5
src/hooks/use-data.ts

If the feature needs backend data, add a data fetching hook here (see 'Add a new API endpoint' guide for the full backend chain).

Pattern: Follow existing hooks in src/hooks/use-data.ts that fetch from /api/ routes and sync into the store

Conventions to follow:

View components live in src/components/views/ and are named {feature}-view.tsxViews read global state from the Zustand store via useAppStore() — they do not accept props for global dataNavigation state (which view is active) is managed in src/stores/app-store.ts, not via URL routingThe sidebar in src/components/layout/sidebar.tsx is the single source of navigation — all view switching goes through it

Add a new reusable UI component

1
src/components/ui/{component-name}.tsx

Create a new primitive UI component file. Export a named React component that accepts props and uses Tailwind CSS classes for styling.

Pattern: Follow the shadcn-style pattern used by existing components in src/components/ui/ — components use className merging, accept standard HTML element props via React.ComponentProps or similar, and are purely presentational with no business logic or store access

2
src/components/views/{consuming-view}.tsx

Import and use the new UI component in the view or parent component that needs it.

Pattern: See how src/components/views/chat-view.tsx or src/components/views/settings-view.tsx import and compose UI primitives from src/components/ui/

Conventions to follow:

UI primitives in src/components/ui/ must be stateless and reusable — no Zustand store access, no API callsUse Tailwind CSS utility classes for all styling — no CSS modules or inline style objectsComponents should accept a `className` prop and merge it with internal classes for composabilityFollow shadcn/ui naming conventions: lowercase-kebab-case filenames, PascalCase component exports

Modify the chat functionality

1
src/components/views/chat-view.tsx

Modify the chat UI, message display, user input handling, or how messages are sent/received. This file handles the POST to /api/chat and manages conversation state.

Pattern: The chat view in src/components/views/chat-view.tsx sends messages by POSTing to /api/chat with the user message, then reads the response and appends both user and assistant messages to the conversation state in the Zustand store

2
src/app/api/chat/route.ts

Modify the backend chat endpoint that bridges the Next.js app with the openclaw CLI agent. Change how messages are processed, add parameters, or modify the response format.

Pattern: src/app/api/chat/route.ts exports a POST handler that extracts the message from the request body, invokes the openclaw agent CLI tool, and returns the agent's text response as JSON

3
src/stores/app-store.ts

Modify chat-related state fields (messages array, active session, etc.) or add new chat state like typing indicators or message metadata.

Pattern: Chat state in src/stores/app-store.ts includes the messages array and related setters — follow the existing pattern of immutable state updates via the Zustand `set()` function

Conventions to follow:

Chat messages are stored in the Zustand store, not in component-local state, so they persist across view switchesThe POST /api/chat endpoint is the only place that communicates with the openclaw CLI — the frontend never calls the CLI directlyError handling in the chat flow should show user-friendly messages in the chat UI, not browser alerts

Modify global app settings or preferences

1
src/components/views/settings-view.tsx

Add or modify settings UI controls (toggles, inputs, dropdowns) for the new preference.

Pattern: src/components/views/settings-view.tsx reads current settings from useAppStore() and calls store setter actions when the user changes a value — each setting maps to a specific store field

2
src/stores/app-store.ts

Add the new preference field with a default value and a setter action. If it should persist across sessions, ensure it's included in the persist configuration.

Pattern: Existing preferences in src/stores/app-store.ts use Zustand's persist middleware — add your new field to the state interface, provide a default in the initial state, add a setter, and include the field in the persist partialize config if it should survive page reloads

3
src/components/app-shell.tsx

If the setting affects the app shell (e.g., theme, layout), consume the new store value here and apply it.

Pattern: src/components/app-shell.tsx reads theme preferences from the store and applies them to the root layout — follow this pattern for any setting that affects the overall app appearance or behavior

Conventions to follow:

All user preferences are stored in the Zustand store in src/stores/app-store.ts with persist middlewareSettings that should survive page reloads must be included in the Zustand persist configurationThe settings view reads and writes to the store — it does not manage its own persistent state

Modify build configuration or project tooling

1
next.config.ts

Modify Next.js build settings, add redirects/rewrites, configure image domains, or adjust webpack settings.

Pattern: next.config.ts exports a Next.js configuration object — add new configuration properties according to the Next.js docs while preserving existing settings

2
postcss.config.mjs

Modify PostCSS plugins if changing CSS processing (e.g., adding autoprefixer or other PostCSS plugins alongside Tailwind).

Pattern: postcss.config.mjs exports a plugins object with tailwindcss — add new plugins to the same plugins object

3
eslint.config.mjs

Add or modify ESLint rules, add ignore patterns, or configure new ESLint plugins.

Pattern: eslint.config.mjs uses the flat config format — add rules or overrides following the existing structure in the file

Conventions to follow:

Configuration files use ESM exports (export default) as indicated by .mjs or .ts extensionsnext.config.ts uses TypeScript — maintain type safety when adding configurationTest build after any config changes with `next build` to catch configuration errors early

Coding Conventions

Standards and patterns used in this codebase

Architecture

Use Next.js App Router with client-side rendering for the main application shell by dynamically importing with SSR disabled, treating Next.js primarily as an API proxy and static shell

dynamic(() => import('@/components/app-shell'), { ssr: false })
src/app/page.tsx
State Management

Use Zustand for global application state management with a single centralized store

Zustand store managing views, themes, chat sessions, and UI state in one app-store.ts file
src/stores/app-store.ts
Data Fetching

Use custom React hooks for data fetching from internal API routes with automatic polling intervals (30-second refresh), not direct backend calls from the client

Custom hook that loads skills, channels, cron jobs, and agents from /api/* endpoints with setInterval-based refresh
src/hooks/use-data.ts
API Design

Next.js API routes act as a proxy layer to the OpenClaw CLI backend, keeping backend interaction server-side only via a dedicated API client library

API routes in src/app/api/ proxy requests to openclaw-api.ts which wraps CLI tool calls
src/lib/openclaw-api.tssrc/app/api
UI Components

Use shadcn-style reusable primitive UI components in src/components/ui/ with Tailwind CSS for styling

Primitive components in src/components/ui/ directory following shadcn patterns, PostCSS configured with Tailwind
src/components/uipostcss.config.mjs
Component Organization

Separate components into views (feature-level pages), layout (shell/navigation), and ui (primitives) directories under src/components/

chat-view.tsx in views/, sidebar.tsx in layout/, primitives in ui/
src/components/views/chat-view.tsxsrc/components/layout/sidebar.tsxsrc/components/app-shell.tsx
Responsive Design

App shell manages desktop/mobile responsive layout with view routing handled at the component level rather than via file-based routing

AppShell component manages layout, theme, and view routing for desktop/mobile responsive application
src/components/app-shell.tsxsrc/components/layout/sidebar.tsx
TypeScript & Linting

Use TypeScript throughout with ESLint configured for Next.js core web vitals and TypeScript-specific rules

ESLint config extends next/core-web-vitals and next/typescript; config files use .ts/.mjs extensions
eslint.config.mjsnext.config.ts
Imports

Use @/ path alias for absolute imports from the src directory

import('@/components/app-shell')
src/app/page.tsx