LogoFreestyle

OpenCode

Add OpenCode AI coding assistant to your VMs.

The OpenCode integration installs OpenCode, an AI-powered coding assistant, and provides helper methods for exposing the web UI and creating API clients.

Installation

npm install @freestyle-sh/with-opencode freestyle-sandboxes

Usage

import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmOpenCode } from "@freestyle-sh/with-opencode";

const { vm } = await freestyle.vms.create({
  spec: new VmSpec({
    with: {
      opencode: new VmOpenCode(),
    },
  }),
});

// Expose the web UI
const { url } = await vm.opencode.routeWeb();
console.log(`OpenCode available at: ${url}`);

Options

new VmOpenCode({
  server: {
    port: 4096,        // Optional: API server port (default: 4096)
    username: "admin", // Optional: Basic auth username (default: "opencode" when password is set)
    password: "secret" // Optional: Basic auth password
  },
  web: {
    port: 4097,        // Optional: Web UI port (default: 4097)
    username: "admin", // Optional: Basic auth username (default: "opencode" when password is set)
    password: "secret" // Optional: Basic auth password
  },
  env: {
    ANTHROPIC_API_KEY: "sk-ant-...", // Environment variables for OpenCode
  },
  config: {
    model: "anthropic/claude-sonnet-4-20250514", // Default model to use
  }
})
OptionTypeDefaultDescription
server.portnumber4096Port for the OpenCode API server
server.usernamestring"opencode"Basic auth username (only used if password set)
server.passwordstring-Basic auth password for the API server
web.portnumber4097Port for the OpenCode web UI
web.usernamestring"opencode"Basic auth username (only used if password set)
web.passwordstring-Basic auth password for the web UI
envRecord<string, string>{}Environment variables passed to OpenCode services
configOpenCodeConfig-OpenCode configuration including model selection

Authentication

OpenCode supports optional HTTP Basic Authentication for both the API server and web UI. Authentication is configured separately for each service, allowing different credentials for programmatic API access vs browser-based access.

Security Considerations

  • If no password is set, the service runs without authentication (useful for private/internal VMs), but not recommended for publicly accessible instances

Example: With Authentication

import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmOpenCode } from "@freestyle-sh/with-opencode";

const { vm } = await freestyle.vms.create({
  spec: new VmSpec({
    with: {
      opencode: new VmOpenCode({
        server: {
          username: "api-user",
          password: "api-secret",
        },
        web: {
          username: "web-user",
          password: "web-secret",
        },
      }),
    },
  }),
});

// URLs will not include credentials for security
const { url } = await vm.opencode.routeWeb();
// Client is automatically configured with auth headers
const { client } = await vm.opencode.client();

Providers

OpenCode supports multiple AI providers. Pass API keys via the env option and set the model in config.

See OpenCode Providers for all supported providers and their environment variables.

Note: Environment variables are stored as plain text in the VM's startup scripts. Users with direct or indirect access to the VM may be able to view these values. Use appropriately scoped API keys and rotate them if the VM is shared or exposed.

import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmOpenCode } from "@freestyle-sh/with-opencode";

const spec = new VmSpec({
  with: {
    opencode: new VmOpenCode({
      env: {
        ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY!,
      },
      config: {
        model: "anthropic/claude-sonnet-4-5-20250929",
      },
    }),
  },
});

const { vm } = await freestyle.vms.create({ spec });

API

vm.opencode.routeWeb(options?)

Exposes the OpenCode web UI on a public domain.

// Use auto-generated domain
const { url } = await vm.opencode.routeWeb();
console.log(url); // https://abc123-opencode.style.dev

// Use custom domain
const { url } = await vm.opencode.routeWeb({
  domain: "my-opencode.example.com"
});

Parameters:

OptionTypeDefaultDescription
domainstringAuto-generatedCustom domain for the web UI

Returns: Promise<{ url: string }>

vm.opencode.client(options?)

Creates an authenticated OpenCode SDK client connected to the API server.

const { client } = await vm.opencode.client();

// Use the client to interact with OpenCode
const sessions = await client.session.list();

Parameters:

OptionTypeDefaultDescription
domainstringAuto-generatedCustom domain for the API server

Returns: Promise<{ client: OpencodeClient }>

vm.opencode.serverPort()

Returns the configured API server port.

const port = vm.opencode.serverPort(); // 4096

vm.opencode.webPort()

Returns the configured web UI port.

const port = vm.opencode.webPort(); // 4097

Example: Full Setup with API Client

import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmOpenCode } from "@freestyle-sh/with-opencode";

const { vm } = await freestyle.vms.create({
  spec: new VmSpec({
    with: {
      opencode: new VmOpenCode(),
    },
  }),
});

// Expose the web UI for browser access
const { url } = await vm.opencode.routeWeb();
console.log(`Web UI: ${url}`);

// Create an API client for programmatic access
const { client } = await vm.opencode.client();

// Create a new coding session
const session = await client.session.create({
  path: "/workspace"
});

// List files in the workspace
const files = await client.path.get({});
console.log("Files:", files.data);

Example: Custom Ports

import { freestyle, VmSpec } from "freestyle-sandboxes";
import { VmOpenCode } from "@freestyle-sh/with-opencode";

const { vm } = await freestyle.vms.create({
  spec: new VmSpec({
    with: {
      opencode: new VmOpenCode({
        server: { port: 8080 },
        web: { port: 3000 },
      }),
    },
  }),
});

const { url } = await vm.opencode.routeWeb();
console.log(`OpenCode running on custom ports`);
console.log(`API: ${vm.opencode.serverPort()}`);   // 8080
console.log(`Web: ${vm.opencode.webPort()}`);      // 3000

On this page

Freestyle AI

Documentation assistant

Experimental: AI responses may not always be accurate—please verify important details with the official documentation.

How can I help?

Ask me about Freestyle while you browse the docs.