Skip to main content

Build Your First Custom UI

Build a standalone web interface that connects to Codebolt using the Client SDK. Everything runs outside the existing Codebolt app — you own the entire UX.

Prerequisites: Codebolt installed and running, Node.js 18+, npm.


Step 1: Start the Codebolt backend

codebolt --server

By default this listens on localhost:2719. Keep it running in a separate terminal.


Step 2: Scaffold the project

npm create vite@latest my-codebolt-ui -- --template react-ts
cd my-codebolt-ui
npm install @codebolt/client-sdk

Step 3: Create the Codebolt client

Create a single shared client instance for your entire app.

// src/services/codebolt.ts
import { CodeBoltClient, ConnectionPreset } from '@codebolt/client-sdk';

export const codebolt = new CodeBoltClient({
host: 'localhost',
port: 2719,
defaultPreset: ConnectionPreset.STANDARD,
});

The SDK automatically:

  • Creates an HTTP client for REST API calls.
  • Opens a multiplexed WebSocket connection for real-time events.
  • Lazily initializes modules on first access (unused modules cost nothing).
  • Reconnects automatically if the connection drops.

Connection presets

PresetSockets connectedUse case
MINIMALmain, systemAlertLightweight scripts, HTTP-only clients
STANDARDLow-speed + medium-speed socketsMost custom UIs
FULLAll sockets except high-speedFull-featured applications

Step 4: Make HTTP API calls

The SDK exposes 72 typed HTTP modules. Access them via codebolt.<module>.<method>():

import { codebolt } from './services/codebolt';

// Tasks
const result = await codebolt.tasks.search({ limit: 50 });
console.log(result.tasks);

// Projects
const project = await codebolt.projects.getRoot();

// Git
const status = await codebolt.git.status();
await codebolt.git.commit({ message: 'fix bug' });

// Files
const content = await codebolt.fileRead.readFile({ path: 'src/index.ts' });

// Agents
const agents = await codebolt.agents.getInstalledAgents();

// Knowledge
const collections = await codebolt.knowledge.getCollections();

Every module is lazily initialized — codebolt.git only allocates resources when you first access it.


Step 5: Listen for real-time events

The SDK exposes 34 WebSocket modules via codebolt.sockets.<module>:

import { codebolt } from './services/codebolt';

// Task updates
codebolt.sockets.tasks.on('taskAdded', (data) => {
console.log('New task:', data);
});

codebolt.sockets.tasks.on('taskUpdated', (data) => {
console.log('Task changed:', data);
});

// Agent coordination
codebolt.sockets.swarm.on('agent:status-changed', (data) => {
console.log('Agent status changed:', data);
});

// System alerts
codebolt.sockets.systemAlert.on('alert', (data) => {
console.log('Alert:', data);
});

// Debug: log every event from every connected socket
const unsub = codebolt.onAllEvents((event) => {
console.log(`[${event.socketName}] ${event.eventName}`, event.data);
});

// Filter specific events
codebolt.onEvents(
{ socketName: 'tasks', eventType: 'taskUpdated' },
(event) => console.log('Task updated:', event.data),
);

// Unsubscribe when done
unsub();

Step 6: Handle errors

The SDK provides typed error classes:

import {
CodeBoltApiError,
CodeBoltConnectionError,
CodeBoltTimeoutError,
} from '@codebolt/client-sdk';
import { codebolt } from './services/codebolt';

try {
const tasks = await codebolt.tasks.search({ status: 'pending' });
} catch (err) {
if (err instanceof CodeBoltConnectionError) {
console.error('Cannot reach Codebolt server — is it running?');
} else if (err instanceof CodeBoltTimeoutError) {
console.error(`Request timed out after ${err.timeout}ms`);
} else if (err instanceof CodeBoltApiError) {
console.error(`API error ${err.status}: ${err.message}`);
} else {
throw err;
}
}

Step 7: Use in React components

Wrap the client in a hook and use it in components:

// src/hooks/useCodebolt.ts
import { useEffect } from 'react';
import { codebolt } from '../services/codebolt';

export function useCodebolt() {
useEffect(() => {
return () => {
codebolt.disconnectAll();
};
}, []);

return codebolt;
}
// src/components/TaskList.tsx
import { useEffect, useState } from 'react';
import { useCodebolt } from '../hooks/useCodebolt';

export function TaskList() {
const client = useCodebolt();
const [tasks, setTasks] = useState<any[]>([]);

useEffect(() => {
// Load tasks via HTTP
client.tasks.search({ limit: 50 }).then((result) => {
setTasks(result.tasks ?? []);
});

// Live updates via WebSocket
client.sockets.tasks.on('taskAdded', (task) => {
setTasks((prev) => [...prev, task]);
});

client.sockets.tasks.on('taskUpdated', (task) => {
setTasks((prev) => prev.map((t) => (t.id === task.id ? { ...t, ...task } : t)));
});

client.sockets.tasks.on('taskDeleted', (data) => {
setTasks((prev) => prev.filter((t) => t.id !== (data.id ?? data.taskId)));
});
}, []);

return (
<ul>
{tasks.map((task) => (
<li key={task.id}>
{task.title}<em>{task.status}</em>
</li>
))}
</ul>
);
}

Run it

npm run dev

Step 8: Cleanup

Always disconnect when the app unmounts:

// src/App.tsx
import { useEffect } from 'react';
import { codebolt } from './services/codebolt';
import { TaskList } from './components/TaskList';

export default function App() {
useEffect(() => {
return () => {
codebolt.disconnectAll();
};
}, []);

return (
<div>
<h1>My Codebolt UI</h1>
<TaskList />
</div>
);
}

Project structure

my-codebolt-ui/
├── src/
│ ├── main.tsx
│ ├── App.tsx
│ ├── components/
│ │ └── TaskList.tsx
│ ├── hooks/
│ │ └── useCodebolt.ts
│ └── services/
│ └── codebolt.ts
├── vite.config.ts
└── package.json

One service file, one hook, and your components. The SDK handles everything else.


Available APIs

The Client SDK gives you access to 72 HTTP API modules and 34 WebSocket modules. See the Client SDK Reference for the full list.


What you learned

  • One client, two layers: codebolt.tasks.search() is an HTTP call; codebolt.sockets.tasks.on(...) is a WebSocket listener. Both go through the same CodeBoltClient.
  • Lazy initialization: Modules are only created when you first access them.
  • Connection presets control which WebSockets connect: MINIMAL for scripts, STANDARD for UIs, FULL for everything.
  • Typed errors give you structured error handling.
  • Custom UIs are standalone apps. They are different from Dynamic Panels, which inject UI surfaces inside the existing Codebolt app via agents or plugins.

Where to next

  • Full SDK reference — see Client SDK for all 72 HTTP modules and 34 WebSocket modules.
  • Drop-in chat components — see Chat Widget for ready-made React chat components from @codebolt/ui.
  • Embed UI inside the existing app — see Dynamic Panels for a different pattern where agents or plugins open panels inside Codebolt.
  • Study existing UIs — see Existing UIs to understand how the desktop, web, and terminal clients are built.

See also