Skip to content

OpenCode -- Sandbox Analysis Report

Analysis Date: 2026-02-12 Repository: https://github.com/opencode-ai/opencodeGit Commit: 73ee493265acf15fcd8caab2bc8cd3bd375b63cbLatest Version: 0.0.55 License: MIT (Go module: github.com/opencode-ai/opencode) Source Availability: Open source


1. Overview

OpenCode is an open-source AI coding agent written in Go (version 1.24.0). It operates primarily as a terminal TUI application using Charmbracelet's Bubble Tea framework. It does NOT have a web UI and does NOT listen on any HTTP/TCP ports for its own interface.

The version is defined in internal/version/version.go and set via build-time -ldflags (falls back to debug.ReadBuildInfo() for go install builds):

go
var Version = "unknown"

func init() {
    info, ok := debug.ReadBuildInfo()
    if !ok { return }
    mainVersion := info.Main.Version
    if mainVersion == "" || mainVersion == "(devel)" { return }
    Version = mainVersion
}

2. UI & Execution Modes

OpenCode uses Charmbracelet's Bubble Tea (bubbletea) as its terminal TUI framework.

Key TUI Dependencies

PackagePurpose
github.com/charmbracelet/bubbletea v1.3.5Core TUI framework (Elm-architecture terminal app)
github.com/charmbracelet/bubbles v0.21.0TUI components (textarea, etc.)
github.com/charmbracelet/lipgloss v1.1.0Terminal styling/layout
github.com/charmbracelet/glamour v0.9.1Markdown rendering in terminal
github.com/charmbracelet/x/ansi v0.8.0ANSI escape code handling
github.com/lrstanley/bubblezoneMouse zone support for bubbletea
github.com/catppuccin/go v0.3.0Catppuccin color theme
github.com/alecthomas/chroma/v2 v2.15.0Syntax highlighting

Evidence from cmd/root.go:

go
import tea "github.com/charmbracelet/bubbletea"
// ...
zone.NewGlobal()
program := tea.NewProgram(
    tui.New(app),
    tea.WithAltScreen(),
)

The TUI uses alternate screen mode (tea.WithAltScreen()), meaning it takes over the entire terminal.

Non-Interactive Mode

OpenCode also supports a non-interactive CLI mode via -p flag:

go
rootCmd.Flags().StringP("prompt", "p", "", "Prompt to run in non-interactive mode")

In this mode, it bypasses the TUI entirely and runs a spinner to stdout.

3. Authentication & Credentials

3.1 Credential Storage

OpenCode does NOT use macOS Keychain, go-keyring, or any OS-level credential storage. It does NOT use OAuth flows. All authentication is via environment variables and config files.

3.2 API Key Sources and Priority Order

API keys can be provided via environment variables or stored in JSON config files. The config struct includes:

go
type Provider struct {
    APIKey   string `json:"apiKey"`
    Disabled bool   `json:"disabled"`
}

Environment Variables Read for API Keys

Environment VariableProvider
ANTHROPIC_API_KEYAnthropic (Claude)
OPENAI_API_KEYOpenAI
GEMINI_API_KEYGoogle Gemini
GROQ_API_KEYGroq
OPENROUTER_API_KEYOpenRouter
XAI_API_KEYxAI (Grok)
AZURE_OPENAI_ENDPOINTAzure OpenAI
AZURE_OPENAI_API_KEYAzure OpenAI
AZURE_OPENAI_API_VERSIONAzure OpenAI
GITHUB_TOKENGitHub Copilot
AWS_ACCESS_KEY_IDAWS Bedrock
AWS_SECRET_ACCESS_KEYAWS Bedrock
AWS_PROFILEAWS Bedrock
AWS_DEFAULT_PROFILEAWS Bedrock
AWS_REGIONAWS Bedrock
AWS_DEFAULT_REGIONAWS Bedrock
AWS_CONTAINER_CREDENTIALS_RELATIVE_URIAWS Bedrock (EC2)
AWS_CONTAINER_CREDENTIALS_FULL_URIAWS Bedrock (EC2)
VERTEXAI_PROJECTGoogle VertexAI
VERTEXAI_LOCATIONGoogle VertexAI
GOOGLE_CLOUD_PROJECTGoogle VertexAI
GOOGLE_CLOUD_REGIONGoogle VertexAI
GOOGLE_CLOUD_LOCATIONGoogle VertexAI
LOCAL_ENDPOINTLocal LLM (LM Studio, etc.)

Viper Environment Variable Binding

Viper is configured with OPENCODE prefix and AutomaticEnv():

go
viper.SetEnvPrefix(strings.ToUpper(appName))  // "OPENCODE"
viper.AutomaticEnv()

This means any config key can be overridden with OPENCODE_* environment variables.

3.3 OAuth Flows

None. OpenCode does not use OAuth.

3.4 Credential File Locations and Formats

GitHub Copilot Token Loading

OpenCode reads GitHub Copilot tokens from the filesystem. From internal/config/config.go:

go
func LoadGitHubToken() (string, error) {
    // First check environment variable
    if token := os.Getenv("GITHUB_TOKEN"); token != "" {
        return token, nil
    }
    // ...
    filePaths := []string{
        filepath.Join(configDir, "github-copilot", "hosts.json"),
        filepath.Join(configDir, "github-copilot", "apps.json"),
    }
    // Reads oauth_token from these JSON files
}

On macOS, this reads:

  • ~/.config/github-copilot/hosts.json
  • ~/.config/github-copilot/apps.json

Or $XDG_CONFIG_HOME/github-copilot/hosts.json if XDG_CONFIG_HOME is set.

4. Configuration & Filesystem

4.1 User-Level Config Paths

OpenCode uses Viper for configuration and searches these locations (in order):

go
viper.SetConfigName(".opencode")     // filename: .opencode.json
viper.SetConfigType("json")
viper.AddConfigPath("$HOME")                           // ~/.opencode.json
viper.AddConfigPath("$XDG_CONFIG_HOME/opencode")       // $XDG_CONFIG_HOME/opencode/.opencode.json
viper.AddConfigPath("$HOME/.config/opencode")          // ~/.config/opencode/.opencode.json

When writing config updates (e.g., changing models), the config file is written to:

  • The file Viper found, OR
  • ~/.opencode.json if none was found

4.2 Project-Level Config Paths

A local config is merged from the current working directory:

go
local.AddConfigPath(workingDir)  // $CWD/.opencode.json

4.3 System/Enterprise Config Paths

None identified.

4.4 Data & State Directories

The primary data directory defaults to .opencode relative to the working directory:

go
const defaultDataDirectory = ".opencode"

This means $CWD/.opencode/ is the default data directory. It contains:

PathPurpose
.opencode/opencode.dbSQLite database (sessions, messages, files)
.opencode/initFlag file marking project as initialized
.opencode/debug.logDebug log file (only if OPENCODE_DEV_DEBUG=true)
.opencode/messages/Message debug logs (only if OPENCODE_DEV_DEBUG=true)
.opencode/messages/<session-prefix>/Per-session message logs
.opencode/commands/Project-specific custom commands (.md files)

SQLite Database

The database is at .opencode/opencode.db (WAL mode). Schema includes:

  • sessions -- chat sessions with token counts
  • messages -- chat messages with parts (JSON)
  • files -- file version history per session

Database pragmas set:

sql
PRAGMA foreign_keys = ON;
PRAGMA journal_mode = WAL;
PRAGMA page_size = 4096;
PRAGMA cache_size = -8000;
PRAGMA synchronous = NORMAL;

This means 3 files total for the DB:

  • .opencode/opencode.db
  • .opencode/opencode.db-wal
  • .opencode/opencode.db-shm

Custom Commands Directories

go
// User commands from XDG
filepath.Join(xdgConfigHome, "opencode", "commands")   // ~/.config/opencode/commands/
// User commands from home
filepath.Join(home, ".opencode", "commands")            // ~/.opencode/commands/
// Project commands
filepath.Join(cfg.Data.Directory, "commands")           // .opencode/commands/

Panic Log Files

On panic, creates files in the current working directory:

go
filename := fmt.Sprintf("opencode-panic-%s-%s.log", name, timestamp)
file, err := os.Create(filename)

Pattern: opencode-panic-<component>-<timestamp>.log in CWD.

4.5 Workspace Files Read

OpenCode reads these project-specific instruction files from the working directory:

go
var defaultContextPaths = []string{
    ".github/copilot-instructions.md",
    ".cursorrules",
    ".cursor/rules/",
    "CLAUDE.md",
    "CLAUDE.local.md",
    "opencode.md",
    "opencode.local.md",
    "OpenCode.md",
    "OpenCode.local.md",
    "OPENCODE.md",
    "OPENCODE.local.md",
}

GitHub Copilot Config Files (read-only, for token extraction)

~/.config/github-copilot/hosts.json
~/.config/github-copilot/apps.json

4.6 Temp Directory Usage

OpenCode uses os.TempDir() (which respects $TMPDIR on macOS) for temporary files.

Shell Command Temp Files

From internal/llm/tools/shell/shell.go:

go
tempDir := os.TempDir()
stdoutFile := filepath.Join(tempDir, fmt.Sprintf("opencode-stdout-%d", time.Now().UnixNano()))
stderrFile := filepath.Join(tempDir, fmt.Sprintf("opencode-stderr-%d", time.Now().UnixNano()))
statusFile := filepath.Join(tempDir, fmt.Sprintf("opencode-status-%d", time.Now().UnixNano()))
cwdFile    := filepath.Join(tempDir, fmt.Sprintf("opencode-cwd-%d", time.Now().UnixNano()))

These are created and cleaned up (os.Remove) after each shell command execution.

Temp file pattern: $TMPDIR/opencode-{stdout,stderr,status,cwd}-<nanosecond-timestamp>

Editor Temp Files

When the user presses ctrl+e to open an external editor:

go
tmpfile, err := os.CreateTemp("", "msg_*.md")

Pattern: $TMPDIR/msg_<random>.md -- cleaned up after use.

No Custom Temp Dir Logic

OpenCode does NOT create its own temp directories. It relies entirely on os.TempDir() / os.CreateTemp().

5. Tools Available to the LLM

The following tools are provided to the LLM for autonomous use:

ToolInternal NamePurpose
File Readview / FileReadReads any file by absolute path
EditEditReplaces content in existing files, creates new files
File Writewrite / FileWriteOverwrites or creates files
PatchPatchApplies multi-file patches
GrepGrepSearches file contents (via ripgrep)
GlobGlobSearches for files by pattern
LSLSLists directory contents
Bash / ShellShell toolPersistent shell for command execution
FetchFetch toolWeb content retrieval (with permission)
SourcegraphSourcegraph toolPublic code search via sourcegraph.com/.api/graphql

Banned Commands in Bash Tool

go
var bannedCommands = []string{
    "alias", "curl", "curlie", "wget", "axel", "aria2c",
    "nc", "telnet", "lynx", "w3m", "links", "httpie", "xh",
    "http-prompt", "chrome", "firefox", "safari",
}

6. Host System Interactions

6.1 Subprocess Execution

CommandLocationPurpose
$SHELL -l (or /bin/bash -l)internal/llm/tools/shell/shell.goPersistent shell for bash tool
rg (ripgrep)internal/llm/tools/grep.go, internal/fileutil/fileutil.goFile content searching
fzfinternal/fileutil/fileutil.goFuzzy file finding
pgrep -P <pid>internal/llm/tools/shell/shell.goFinding child processes to kill on timeout
$EDITOR (or nvim)internal/tui/components/chat/editor.goExternal editor for message composition
LSP server commands (e.g., gopls, typescript-language-server)internal/lsp/client.goLanguage Server Protocol integration
MCP server commands (user-configured)internal/llm/agent/mcp-tools.goModel Control Protocol tool servers

Shell Details

The persistent shell:

  • Spawns with $SHELL -l (login shell) or configurable via shell.path and shell.args
  • Sets GIT_EDITOR=true in environment (to prevent interactive git editors)
  • Inherits the full process environment (os.Environ())
  • Runs in the working directory
  • Commands have a default timeout of 1 minute, max 10 minutes

6.2 Network Requests

LLM Provider API Endpoints

ProviderEndpointProtocol
Anthropichttps://api.anthropic.com (via SDK)HTTPS
OpenAIhttps://api.openai.com (via SDK)HTTPS
Google Geminihttps://generativelanguage.googleapis.com (via SDK)HTTPS
Groqhttps://api.groq.com/openai/v1HTTPS
OpenRouterhttps://openrouter.ai/api/v1HTTPS
xAIhttps://api.x.ai/v1HTTPS
GitHub Copilothttps://api.githubcopilot.comHTTPS
GitHub (token exchange)https://api.github.com/copilot_internal/v2/tokenHTTPS
Azure OpenAI$AZURE_OPENAI_ENDPOINT (user-configured)HTTPS
AWS BedrockAWS Bedrock endpoint (via SDK, region-based)HTTPS
Google VertexAIGoogle Cloud VertexAI endpoint (via SDK)HTTPS
Local LLM$LOCAL_ENDPOINT (user-configured, e.g., http://localhost:1234)HTTP/HTTPS

Tool Network Requests

ToolEndpointPurpose
FetchAny user-specified URLWeb content retrieval (with permission)
Sourcegraphhttps://sourcegraph.com/.api/graphqlPublic code search
Local model discovery$LOCAL_ENDPOINT/v1/models or $LOCAL_ENDPOINT/api/v0/modelsList local models at startup

MCP Server Connections

MCP servers configured by the user can connect via:

  • stdio: Spawns a subprocess, communicates via stdin/stdout
  • SSE: Connects to an HTTP URL with Server-Sent Events

6.3 Port Binding

OpenCode does NOT bind to any ports. It does NOT run an HTTP server. There are no net.Listen or http.ListenAndServe calls.

6.4 Browser Launching

OpenCode does NOT directly launch browsers. The pkg/browser package is listed as an indirect dependency in go.mod, pulled in by Azure Identity SDK (azidentity).

6.5 Clipboard Access

The atotto/clipboard package is listed as an indirect dependency in go.mod. It is pulled in by Charmbracelet's bubbles textarea component. There is no direct clipboard usage in OpenCode's own code.

6.6 File System Watchers

OpenCode uses fsnotify for LSP workspace watching:

go
watcher, err := fsnotify.NewWatcher()

From internal/lsp/watcher/watcher.go:

  • Recursively watches the entire working directory tree
  • Excludes: .git, node_modules, dist, build, out, bin, .idea, .vscode, .cache, coverage, target, vendor
  • Monitors: Create, Write, Remove, Rename events
  • Notifies LSP servers of file changes
  • Uses debouncing (300ms) to reduce notification spam

6.7 Other

Signal Handling

No explicit signal.Notify usage found. Signal handling is delegated to bubbletea which handles terminal signals (SIGINT, SIGTERM, SIGWINCH) internally.

Process Management

  • Sends SIGTERM to child processes of the persistent shell on timeout
  • Uses pgrep -P <pid> to find child processes
  • Kills LSP server processes on shutdown (with 2-second timeout before Kill())

7. Extension Points

7.1 Hook/Lifecycle System

None identified. OpenCode does not have a hook or lifecycle event system.

7.2 Plugin/Extension Architecture

None identified. OpenCode does not have a plugin system.

7.3 MCP Integration

MCP servers configured by the user can connect via:

  • stdio: Spawns a subprocess, communicates via stdin/stdout
  • SSE: Connects to an HTTP URL with Server-Sent Events

MCP is implemented via github.com/mark3labs/mcp-go v0.17.0.

7.4 Custom Commands/Skills/Agents

Custom commands are markdown (.md) files loaded from:

  • ~/.config/opencode/commands/ (user commands from XDG)
  • ~/.opencode/commands/ (user commands from home)
  • .opencode/commands/ (project commands)

7.5 SDK/API Surface

None identified. OpenCode does not expose an SDK or API for programmatic use.

8. Sandbox & Security Model

8.1 Built-in Sandboxing

None. OpenCode does not implement any built-in sandboxing mechanism.

8.2 Permission System

None identified beyond the banned commands list in the Bash tool (see Section 5).

8.3 Safety Mechanisms

Banned Commands in Bash Tool

go
var bannedCommands = []string{
    "alias", "curl", "curlie", "wget", "axel", "aria2c",
    "nc", "telnet", "lynx", "w3m", "links", "httpie", "xh",
    "http-prompt", "chrome", "firefox", "safari",
}

The shell also sets GIT_EDITOR=true in the environment to prevent interactive git editors.

8.4 Known Vulnerabilities

None identified.

8.5 Enterprise/Managed Security Controls

None identified.

9. Key Dependencies

DependencyImpact
github.com/ncruces/go-sqlite3 v0.25.0SQLite database (uses Wasm via tetratelabs/wazero -- no CGo!)
github.com/tetratelabs/wazero v1.9.0WebAssembly runtime for SQLite (no CGo dependency)
github.com/fsnotify/fsnotify v1.8.0File system event watching (uses kqueue on macOS)
github.com/charmbracelet/bubbletea v1.3.5Terminal TUI (raw terminal mode, alternate screen)
github.com/charmbracelet/x/term v0.2.1Terminal capability detection
github.com/atotto/clipboard v0.1.4Clipboard access (indirect, via bubbles textarea)
github.com/pkg/browser v0.0.0-20240102092130Browser opening (indirect, via Azure Identity)
github.com/spf13/viper v1.20.0Config file reading/writing
github.com/subosito/gotenv v1.6.0.env file reading (indirect, via viper)
github.com/mark3labs/mcp-go v0.17.0MCP client (spawns subprocesses, HTTP SSE)
github.com/anthropics/anthropic-sdk-go v1.4.0Anthropic API client
github.com/openai/openai-go v0.1.0-beta.2OpenAI API client
google.golang.org/genai v1.3.0Google Generative AI client
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0Azure credential management
github.com/aws/aws-sdk-go-v2AWS SDK for Bedrock
github.com/pressly/goose/v3 v3.24.2Database migration runner
github.com/disintegration/imaging v1.6.2Image processing for attachments
github.com/bmatcuk/doublestar/v4 v4.8.1Glob pattern matching
github.com/gorilla/websocket v1.5.3WebSocket (indirect, used by MCP SSE client)

Notable: SQLite uses Wasm, not CGo

The SQLite implementation (ncruces/go-sqlite3) compiles SQLite to WebAssembly and runs it via wazero. This means:

  • No CGo dependency
  • No need for a C compiler
  • Pure Go binary
  • The Wasm runtime has its own memory sandbox

10. Environment Variables

Authentication

Environment VariablePurpose
ANTHROPIC_API_KEYAnthropic (Claude) API key
OPENAI_API_KEYOpenAI API key
GEMINI_API_KEYGoogle Gemini API key
GROQ_API_KEYGroq API key
OPENROUTER_API_KEYOpenRouter API key
XAI_API_KEYxAI (Grok) API key
AZURE_OPENAI_ENDPOINTAzure OpenAI endpoint
AZURE_OPENAI_API_KEYAzure OpenAI API key
AZURE_OPENAI_API_VERSIONAzure OpenAI API version
GITHUB_TOKENGitHub Copilot token
AWS_ACCESS_KEY_IDAWS Bedrock access key
AWS_SECRET_ACCESS_KEYAWS Bedrock secret key
AWS_PROFILEAWS Bedrock profile
AWS_DEFAULT_PROFILEAWS Bedrock default profile
AWS_REGIONAWS Bedrock region
AWS_DEFAULT_REGIONAWS Bedrock default region
AWS_CONTAINER_CREDENTIALS_RELATIVE_URIAWS Bedrock (EC2) credentials
AWS_CONTAINER_CREDENTIALS_FULL_URIAWS Bedrock (EC2) credentials
VERTEXAI_PROJECTGoogle VertexAI project
VERTEXAI_LOCATIONGoogle VertexAI location
GOOGLE_CLOUD_PROJECTGoogle VertexAI project
GOOGLE_CLOUD_REGIONGoogle VertexAI region
GOOGLE_CLOUD_LOCATIONGoogle VertexAI location
LOCAL_ENDPOINTLocal LLM endpoint (e.g., LM Studio)

Configuration

Environment VariablePurpose
OPENCODE_DEV_DEBUGEnable development debug logging (set to "true")
SHELLDefault shell path for bash tool
EDITORExternal editor for message composition (ctrl+e)
HOMEHome directory for config resolution
XDG_CONFIG_HOMEXDG config directory
LOCALAPPDATAWindows AppData (Windows only)

Viper Auto-Binding

Any config key can be overridden with OPENCODE_* environment variables (prefix: OPENCODE).

11. Summary Tables

11.1 All Filesystem Paths Accessed

PathAccessPurposeCreated by Agent?
$CWD/.opencode/Read/WriteData directoryYes
$CWD/.opencode/opencode.dbRead/WriteSQLite DBYes
$CWD/.opencode/opencode.db-walRead/WriteSQLite WALYes
$CWD/.opencode/opencode.db-shmRead/WriteSQLite shared memoryYes
$CWD/.opencode/initRead/WriteProject init flagYes
$CWD/.opencode/debug.logRead/WriteDebug log (when OPENCODE_DEV_DEBUG=true)Yes
$CWD/.opencode/messages/Read/WriteMessage debug logs (when OPENCODE_DEV_DEBUG=true)Yes
$CWD/.opencode/commands/ReadProject custom commandsNo
$CWD/.opencode.jsonReadLocal config (optional)No
~/.opencode.jsonRead/WriteGlobal configYes
~/.config/opencode/.opencode.jsonReadGlobal config (XDG)No
$XDG_CONFIG_HOME/opencode/.opencode.jsonReadGlobal config (XDG)No
~/.config/opencode/commands/ReadUser custom commandsNo
~/.opencode/commands/ReadUser custom commandsNo
~/.config/github-copilot/hosts.jsonReadGitHub Copilot tokenNo
~/.config/github-copilot/apps.jsonReadGitHub Copilot tokenNo
$CWD/.github/copilot-instructions.mdReadContext instructionsNo
$CWD/.cursorrulesReadContext instructionsNo
$CWD/.cursor/rules/ReadContext instructions (directory)No
$CWD/CLAUDE.mdReadContext instructionsNo
$CWD/CLAUDE.local.mdReadContext instructionsNo
$CWD/opencode.mdReadContext instructionsNo
$CWD/opencode.local.mdReadContext instructionsNo
$CWD/OpenCode.mdReadContext instructionsNo
$CWD/OpenCode.local.mdReadContext instructionsNo
$CWD/OPENCODE.mdReadContext instructionsNo
$CWD/OPENCODE.local.mdReadContext instructionsNo
$TMPDIR/opencode-stdout-*Read/WriteShell command temp (cleaned up)Yes
$TMPDIR/opencode-stderr-*Read/WriteShell command temp (cleaned up)Yes
$TMPDIR/opencode-status-*Read/WriteShell command temp (cleaned up)Yes
$TMPDIR/opencode-cwd-*Read/WriteShell command temp (cleaned up)Yes
$TMPDIR/msg_*.mdRead/WriteExternal editor temp (cleaned up)Yes
$CWD/opencode-panic-*.logWritePanic logYes
$CWD/** (any file)Read/WriteVia LLM tools (edit, write, view, etc.)Yes

11.2 All Network Endpoints

EndpointPurposeWhen Triggered
https://api.anthropic.comAnthropic LLM APIWhen using Anthropic provider
https://api.openai.comOpenAI LLM APIWhen using OpenAI provider
https://generativelanguage.googleapis.comGoogle Gemini APIWhen using Gemini provider
https://api.groq.com/openai/v1Groq LLM APIWhen using Groq provider
https://openrouter.ai/api/v1OpenRouter APIWhen using OpenRouter provider
https://api.x.ai/v1xAI APIWhen using xAI provider
https://api.githubcopilot.comGitHub Copilot LLM APIWhen using Copilot provider
https://api.github.com/copilot_internal/v2/tokenCopilot token exchangeWhen using Copilot provider
Azure endpoint (user-configured)Azure OpenAI APIWhen using Azure provider
AWS Bedrock (region-based)AWS Bedrock APIWhen using Bedrock provider
VertexAI (Google Cloud)Google VertexAI APIWhen using VertexAI provider
$LOCAL_ENDPOINTLocal LLM APIWhen using local provider
https://sourcegraph.com/.api/graphqlCode searchSourcegraph tool use
Any URLWeb fetchFetch tool use (with permission)
MCP SSE URL (user-configured)MCP toolsMCP SSE server configured

11.3 All System Interactions

TypeMechanismDetails
Terminal raw modebubbletea / x/termTUI takes over terminal
Alternate screen bufferbubbletea (tea.WithAltScreen())Full-screen TUI mode
File system watchingfsnotify (uses kqueue on macOS)LSP workspace watching
Process spawningos/execShell, ripgrep, fzf, editor, LSP, MCP
Signal sending (SIGTERM)syscall.SIGTERM to child processesShell command timeout
Process ID lookupos.Getpid() (for LSP init)LSP initialization
Environment readingos.Getenv(), os.Environ()Config and credential loading
Working directoryos.Getwd(), os.Chdir()Shell and file operations
Temp file creationos.TempDir(), os.CreateTemp()Shell output capture, editor

12. Sandboxing Recommendations

Based on this analysis, a sandbox for OpenCode should:

  1. Allow filesystem access to:

    • The working directory tree (read/write for LLM tools)
    • $CWD/.opencode/ (data directory, SQLite DB)
    • ~/.opencode.json and ~/.config/opencode/ (config, read-only may suffice)
    • ~/.config/github-copilot/ (read-only, for token loading)
    • $TMPDIR/opencode-* and $TMPDIR/msg_* (temp files)
  2. Allow network access to:

    • LLM provider APIs (Anthropic, OpenAI, GitHub, Google, etc.)
    • sourcegraph.com (for code search tool)
    • Any URL the fetch tool targets (user-controlled with permission prompt)
    • Local endpoints (localhost) if using local LLM
  3. Allow process spawning for:

    • Shell (/bin/bash, /bin/zsh, etc.)
    • rg, fzf, pgrep
    • $EDITOR (nvim, vim, etc.)
    • LSP servers (gopls, typescript-language-server, etc.)
    • MCP server commands
  4. Allow terminal access (PTY/TTY for bubbletea TUI)

  5. No port binding is needed (OpenCode does not listen on any ports)

  6. No keychain/keyring access needed

  7. No browser launching by OpenCode directly (indirect dependency only from Azure SDK)

Open source under the Apache 2.0 License.