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​