---
title: Build a Coding Agent Using OpenCode Web and Daytona
description: Step-by-step guide to running OpenCode's web interface, an open source coding agent, inside Daytona sandboxes.
---

import { Image } from 'astro:assets'

import opencodeResult from '../../../../../assets/docs/images/opencode-web-agent.gif'

This guide demonstrates how to run the [OpenCode](https://opencode.ai/) coding agent inside a Daytona sandbox environment using OpenCode's easy-to-use [web interface](https://opencode.ai/docs/web/).

The agent can develop web apps, write code in any language, install dependencies, and run scripts. It supports over 75 different LLM providers and can start dev servers with preview links for live apps.

---

### 1. Workflow Overview

When you launch the main script, a Daytona sandbox is created and OpenCode is installed inside it. OpenCode is configured with a custom Daytona-aware agent.

The script provides a preview link to access the web interface, where you can create, configure and interact with agent sessions:

```
$ npm run start
Creating sandbox...
Installing OpenCode...
Starting OpenCode web server...
Press Ctrl+C to stop.


             ▄
█▀▀█ █▀▀█ █▀▀█ █▀▀▄ █▀▀▀ █▀▀█ █▀▀█ █▀▀█
█░░█ █░░█ █▀▀▀ █░░█ █░░░ █░░█ █░░█ █▀▀▀
▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀  ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀

  Web interface:      https://3000-1e0f775c-c01b-40e7-8c64-062fd3dadd75.proxy.daytona.works/
```

The agent can host web apps and provide you with a preview link using the [Daytona Preview Links](/docs/en/preview-and-authentication/) feature. When your task involves running or previewing a web application, the agent automatically reasons about this need, hosts the app, and generates a preview link for you to inspect the live result:

<Image
  src={opencodeResult}
  alt="Web app demo generated by OpenCode coding agent"
  width={600}
  style="max-width: 100%; height: auto; margin: 1rem 0;"
/>

You can continue interacting with your agent until you are finished. When you exit the program, the sandbox will be deleted automatically.

### 2. Project Setup

#### Clone the Repository

First, clone the Daytona [repository](https://github.com/daytonaio/daytona.git) and navigate to the example directory:

```bash
git clone https://github.com/daytonaio/daytona.git
cd daytona/guides/typescript/opencode
```

#### Configure Environment

Get your API key from the [Daytona Dashboard](https://app.daytona.io/dashboard/keys).

Copy `.env.example` to `.env` and add your key:

```bash
DAYTONA_API_KEY=your_daytona_key
```

#### Local Usage

:::note[Node.js Version]
Node.js 18 or newer is required to run this example. Please ensure your environment meets this requirement before proceeding.
:::

Install dependencies:

```bash
npm install
```

Run the example:

```bash
npm run start
```

The OpenCode web interface will start and wait for you to open it in your browser.

### Models and API Providers

OpenCode works with [over 75 LLM providers](https://opencode.ai/docs/providers/), with a free provider selected by default. You can change the model or provider at any time using the menu below the prompt input in the web interface. If your chosen provider needs an API key, you’ll be prompted to enter it.

#### Persisting API Keys

To persist API keys between uses of the script, you can set them as environment variables when creating the Daytona sandbox.

For example, to use an Anthropic API key, modify the `daytona.create()` call in `src/index.ts` to include your desired API key:

```typescript
sandbox = await daytona.create({
  envVars: {
    ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY || '',
  },
})
```

### 3. Understanding the Script

This example consists of a Node.js script that installs, configures and runs OpenCode inside a Daytona sandbox.

#### Initialization

On initialization, the main script:
1. Creates a new [Daytona sandbox](/docs/en/sandboxes).
2. Installs OpenCode globally inside the sandbox using npm with [process execution](/docs/en/process-code-execution#process-execution).
3. Creates and uploads a [custom agent configuration](https://opencode.ai/docs/agents/) with Daytona-specific system prompt.
4. Starts the OpenCode web server inside the sandbox on port 3000.
5. Substitutes the URL in OpenCode's output with a [Daytona preview link](/docs/en/preview-and-authentication/) for the web interface.

#### Main Script Code

The script creates a session and executes OpenCode as an asynchronous command, which allows it to stream output while keeping the process alive:

```typescript
const command = await sandbox.process.executeSessionCommand(sessionId, {
  command: `${envVar} opencode web --port ${OPENCODE_PORT}`,
  runAsync: true,
})
```

When OpenCode starts its web server, it prints a link to its web UI using a localhost address (e.g., `http://127.0.0.1:3000`). However, since the sandbox runs remotely, this localhost link is only accessible inside the sandbox itself. To solve this, the script parses OpenCode’s output, and replaces the URL with the corresponding Daytona preview link.

```typescript
const opencodePreviewLink = await sandbox.getPreviewLink(OPENCODE_PORT)
const replaceUrl = (text: string) =>
  text.replace(
    new RegExp(`http:\\/\\/127\\.0\\.0\\.1:${OPENCODE_PORT}`, 'g'),
    opencodePreviewLink.url
  )
```

#### OpenCode Agent Configuration

A custom system prompt is used to instruct the agent on how to use Daytona sandbox paths and preview links. This prompt is packaged into a JSON configuration string, which is passed to the sandbox as the `OPENCODE_CONFIG_CONTENT` environment variable:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "default_agent": "daytona",
  "agent": {
    "daytona": {
      "description": "Daytona sandbox-aware coding agent",
      "mode": "primary",
      "prompt": "You are running in a Daytona sandbox. Use the /home/daytona directory instead of /workspace for file operations. When running services on localhost, they will be accessible as: <PREVIEW_URL_PATTERN>. When starting a server, always give the user the preview URL to access it. When starting a server, start it in the background with & so the command does not block further instructions."
    }
  }
}
```

The `<PREVIEW_URL_PATTERN>` in the agent prompt is a template URL where `{PORT}` is a placeholder for the port to access on the Daytona sandbox. This template string is created by generating a [preview link](/docs/en/preview-and-authentication/) for a specific port number and then replacing the port number with `{PORT}`.

#### Clean up

When you press `Ctrl+C`, the script automatically cleans up by deleting the sandbox:

```typescript
process.once('SIGINT', async () => {
  console.log('\nCleaning up...')
  if (sandbox) await sandbox.delete()
  process.exit(0)
})
```

**Key advantages:**

- Secure, isolated execution in Daytona sandboxes
- OpenCode Web interface accessible via browser
- Support for 75+ LLM providers
- All agent code execution happens inside the sandbox
- Automatic preview link generation for deployed services
- Custom agent configuration for Daytona-specific workflows
- Clean resource management with automatic sandbox cleanup