# How to Embed Freebuff Agents in External Applications Using the SDK

> Easily embed Freebuff agents in your applications with the SDK. Leverage the TypeScript wrapper to load agents and stream real-time events via WebSocket for enhanced functionality.

- Repository: [Codebuff/freebuff](https://github.com/CodebuffAI/freebuff)
- Tags: how-to-guide
- Published: 2026-09-01

---

**The Freebuff SDK provides a TypeScript wrapper around the Codebuff binary that lets you instantiate a `CodebuffClient`, load agent definitions, and stream real-time events via WebSocket in any external application.**

The `@codebuff/sdk` package from the [CodebuffAI/freebuff](https://github.com/CodebuffAI/freebuff) repository exposes a pure TypeScript runtime for embedding autonomous coding agents into CLI tools, web servers, or browser-based applications. By leveraging the SDK's WebSocket-based architecture, you can orchestrate agent runs, handle streaming responses, and inject custom tools without managing the underlying binary directly.

## Initialize the CodebuffClient

The entry point for any integration is the `CodebuffClient` class exported from [`sdk/src/client.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/client.ts). This class handles API key resolution, connection health checks, and request construction.

You can instantiate the client with an explicit API key or rely on environment variable detection. According to the source code in [`sdk/src/client.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/client.ts), the constructor accepts a `cwd` (current working directory) parameter and automatically falls back to `process.env.CODEBUFF_API_KEY` if no key is provided.

```typescript
import { CodebuffClient } from '@codebuff/sdk';

const client = new CodebuffClient({
  apiKey: process.env.CODEBUFF_API_KEY, // Optional: auto-detected from env
  cwd: process.cwd()
});

```

The client maintains a persistent WebSocket connection that is reused across multiple `run()` calls, making it efficient for long-running server processes.

## Load and Configure Agent Definitions

Before running agents, you may need to load agent definitions. The SDK provides two approaches: using bundled agents or supplying custom configurations.

As implemented in [`sdk/src/agents/load-agents.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/agents/load-agents.ts), the `loadLocalAgents()` function scans for agent definitions in the specified working directory:

```typescript
import { loadLocalAgents } from '@codebuff/sdk';

const { agents } = await loadLocalAgents({ cwd: process.cwd() });
console.log('Available agents:', agents.map(a => a.id));

```

If you only use the default `base` agent, this step is optional. The `agents` array contains metadata that can be passed to `client.run()` to select specific behavior profiles.

## Execute Runs with Event Streaming

The core execution method is `client.run()`, defined in [`sdk/src/run.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/run.ts). This method accepts a `RunOptions` object and returns a promise resolving to the final run state.

Critical parameters include:
- **agent**: The agent identifier (e.g., `'base'` or a custom ID from `loadLocalAgents`)
- **prompt**: The user instruction string
- **handleEvent**: A callback function that receives `PrintModeEvent` objects for real-time UI updates
- **projectFiles** and **knowledgeFiles**: Optional file snapshots to provide context without disk access

```typescript
const runState = await client.run({
  agent: 'base',
  prompt: 'Refactor the function foo() to use async/await',
  env: { NODE_ENV: 'production' },
  handleEvent: (evt) => {
    if (evt.type === 'assistant-message') {
      process.stdout.write(evt.content); // Real-time streaming
    }
  }
});

```

The `handleEvent` callback receives events throughout the lifecycle, including assistant messages, tool calls, and errors. The final `runState.output` contains the complete response after the agent finishes execution.

## Integration Examples

### CLI Embedding

For command-line tools, instantiate the client and stream output directly to stdout. This pattern from [`sdk/src/index.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/index.ts) demonstrates minimal embedding:

```typescript
import { CodebuffClient, loadLocalAgents } from '@codebuff/sdk';

async function main() {
  const client = new CodebuffClient({ cwd: process.cwd() });
  const { agents } = await loadLocalAgents({ cwd: process.cwd() });
  
  const result = await client.run({
    agent: 'base',
    prompt: 'Explain the purpose of src/utils.ts',
    handleEvent: (ev) => {
      if (ev.type === 'assistant-message') {
        process.stdout.write(ev.content);
      }
    }
  });
  
  console.log('\nFinal output:', result.output);
}

main().catch(console.error);

```

### Web Server Integration

In server environments like Express, reuse a singleton client across requests. The SDK supports injection of file contexts via `projectFiles` and `knowledgeFiles` parameters:

```typescript
import express from 'express';
import { CodebuffClient } from '@codebuff/sdk';

const app = express();
app.use(express.json());

const client = new CodebuffClient({ 
  apiKey: process.env.CODEBUFF_API_KEY!, 
  cwd: process.cwd() 
});

app.post('/run-agent', async (req, res) => {
  const { agent = 'base', prompt, projectFiles, knowledgeFiles } = req.body;
  
  const runState = await client.run({
    agent,
    prompt,
    projectFiles,
    knowledgeFiles,
    handleEvent: (evt) => {
      // Log or broadcast events via WebSocket/SSE
      console.log('Event type:', evt.type);
    }
  });
  
  res.json({ output: runState.output });
});

app.listen(3000);

```

This approach works in serverless or edge environments where the SDK operates in WebSocket-only mode without invoking the local binary.

## Extend Functionality with Custom Tools

You can augment agent capabilities by defining custom tools via the `customTool` helper exported from [`sdk/src/custom-tool.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/custom-tool.ts). These tools become available to the agent during execution.

```typescript
import { CodebuffClient, customTool } from '@codebuff/sdk';
import { execSync } from 'child_process';

const gitBranchTool = customTool({
  name: 'git_branch',
  description: 'Returns the current Git branch name',
  inputSchema: {},
  handler: async () => {
    return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
  }
});

const client = new CodebuffClient({
  cwd: process.cwd(),
  customToolDefinitions: [gitBranchTool]
});

await client.run({
  agent: 'base',
  prompt: 'What branch am I currently on?',
  handleEvent: (ev) => console.log(ev)
});

```

Custom tools follow the same interface as built-in utilities found in `sdk/src/tools/`, allowing seamless integration with the agent's decision-making loop.

## Summary

- **Instantiate once**: Create a `CodebuffClient` from [`sdk/src/client.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/client.ts) with your API key and working directory.
- **Load definitions**: Use `loadLocalAgents` from [`sdk/src/agents/load-agents.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/agents/load-agents.ts) to discover available agent profiles.
- **Stream events**: Pass a `handleEvent` callback to `client.run()` (defined in [`sdk/src/run.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/run.ts)) to receive real-time updates via the `PrintModeEvent` interface.
- **Provide context**: Inject `projectFiles` and `knowledgeFiles` to give agents codebase awareness without filesystem access.
- **Extend capabilities**: Define custom tools using `customTool` from [`sdk/src/custom-tool.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/custom-tool.ts) to expose domain-specific functionality.

## Frequently Asked Questions

### How does the SDK authenticate with the Freebuff API?

The `CodebuffClient` automatically resolves the API key from the `CODEBUFF_API_KEY` environment variable, as referenced in `@codebuff/common/constants/paths`. You can override this by passing an explicit `apiKey` in the constructor options.

### Can I use the Freebuff SDK in a browser environment?

Yes. Because the SDK is pure TypeScript with WebSocket-only mode support, it functions in browser-based applications and edge runtimes where the Codebuff binary cannot be executed via child process. The same `client.run()` interface works across Node.js and browser contexts.

### How do I handle real-time streaming from an agent?

Provide a `handleEvent` callback in your `RunOptions` object. This function receives `PrintModeEvent` objects (defined in `@codebuff/common/types/print-mode`) throughout the agent's execution lifecycle, enabling you to display partial outputs, progress indicators, or tool call notifications as they occur.

### What is the difference between bundled and custom agents?

Bundled agents are pre-defined configurations included with the SDK that you can reference by simple IDs like `'base'`. Custom agents are loaded via `loadLocalAgents()` from [`sdk/src/agents/load-agents.ts`](https://github.com/CodebuffAI/freebuff/blob/main/sdk/src/agents/load-agents.ts), allowing you to supply your own agent definitions with specialized instructions, tool access, and behavior parameters stored in your project's working directory.