Skip to main content
Station integrates with AI coding assistants to provide powerful coding capabilities. Unlike sandbox execution which runs in isolated containers, coding backends work directly on your local filesystem with full IDE-like features.

Supported Backends

BackendTransportDescription
opencodeHTTPOpenCode server
opencode-cliCLI subprocessOpenCode CLI binary
opencode-natsNATS messagingOpenCode via NATS for distributed setups
claudecodeCLI subprocessClaude Code CLI (Anthropic’s official coding agent)

Coding Backends vs Sandbox

Coding Backends

Local development with full filesystem access. AI reads, writes, and refactors code on your machine.

Sandbox Execution

Isolated containers for safe code execution. Code runs in ephemeral Docker containers.
FeatureCoding BackendsSandbox
FilesystemDirect local accessContainer isolated
Use caseCode development, refactoringScript execution, data processing
PersistenceChanges persist on diskEphemeral (container destroyed)
Toolscoding_open, code, coding_closesandbox_run, sandbox_exec
RequirementsOpenCode or Claude Code CLIDocker

How It Works

OpenCode backend creates coding sessions that give agents access to your local filesystem:
┌─────────────────────────────────────────────────────────────┐
│  YOUR MACHINE                                               │
│                                                             │
│  ┌─────────────┐      ┌─────────────┐      ┌─────────────┐  │
│  │   Station   │─────▶│  OpenCode   │─────▶│ Filesystem  │  │
│  │   Agent     │      │   Server    │      │  /my/code   │  │
│  └─────────────┘      └─────────────┘      └─────────────┘  │
│        │                    │                               │
│        │    1. coding_open  │                               │
│        │───────────────────▶│  Creates session              │
│        │                    │                               │
│        │    2. code         │                               │
│        │───────────────────▶│  AI writes/edits files        │
│        │                    │                               │
│        │    3. coding_close │                               │
│        │───────────────────▶│  Ends session                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘
  1. Session Creation: Agent calls coding_open with a workspace path
  2. Code Operations: Agent sends tasks via code tool - OpenCode’s AI reads, writes, and modifies files
  3. Session End: Agent calls coding_close to clean up

Quick Start

1. Install OpenCode

# macOS
brew install opencode-ai/tap/opencode

# Linux (via curl)
curl -fsSL https://opencode.ai/install.sh | sh

# Or build from source
go install github.com/sst/opencode@latest

2. Start OpenCode Server

# Start OpenCode (binds to localhost:4096 by default)
opencode

# Or specify a different port
opencode --port 4000
For container mode (stn up), you must bind to all interfaces:
opencode --hostname 0.0.0.0
See Container Mode for details.

3. Configure Station

Add OpenCode URL to your Station config:
# ~/.config/station/config.yaml
coding:
  opencode:
    url: http://localhost:4096

4. Create an Agent with Coding Backend

---
metadata:
  name: "Code Assistant"
  description: "AI coding assistant with local filesystem access"
model: openai/gpt-4o
coding:
  enabled: true
  backend: opencode
---

You are an expert software engineer. Use your coding tools to:
- Read and understand existing code
- Write new files and functions
- Refactor and improve code quality
- Fix bugs and implement features

When given a task, open a coding session, complete the work, then close the session.

5. Run the Agent

stn agent run "Code Assistant" "Create a Python CLI tool that converts CSV to JSON"

Coding Tools

When coding.enabled: true and coding.backend: opencode, agents receive these tools:
ToolDescription
coding_openStart a coding session in a workspace directory
codeSend coding tasks to OpenCode (read, write, refactor)
coding_closeEnd the coding session
coding_commitCommit changes with a message (if in git repo)
coding_pushPush commits to remote (if in git repo)
coding_branchCreate and/or switch to a git branch

Tool Reference

Start a new coding session or continue an existing one.
ParameterTypeRequiredDescription
workspace_pathstringNoDirectory to work in
repo_urlstringNoGit repository to clone
branchstringNoBranch to checkout after cloning
existing_session_idstringNoContinue an existing session by ID
titlestringNoFriendly name for the session
scopestringNoagent (default) or workflow
{
  "workspace_path": "/home/user/my-project"
}
To continue an existing session:
{
  "existing_session_id": "ses_47b42f435ffeOJLjZKhPMk0Adu",
  "workspace_path": "/home/user/my-project"
}
Returns session ID for subsequent operations.

Backend Options

Station supports three backend options for OpenCode integration:
BackendTransportUse Case
opencodeHTTPLocal development, same machine
opencode-natsNATSContainers, distributed setups, remote OpenCode
opencode-cliCLI subprocessCI/CD, GitHub Actions, no server required
The backend is configured at the Station level (config.yaml), not per-agent. All agents with coding.enabled: true use the same backend. This keeps agent definitions portable across environments.

HTTP Backend (opencode)

Direct HTTP communication with OpenCode. Best for local development where OpenCode runs on the same machine.
Station Agent → HTTP → OpenCode Server → Filesystem

NATS Backend (opencode-nats)

Uses NATS messaging for communication. Best for containerized or distributed setups where OpenCode runs remotely or in a container with the Station plugin.
Station Agent → NATS → Station Plugin → OpenCode → Filesystem
The NATS backend enables:
  • Running OpenCode in a separate container
  • Decoupled architecture (Station and OpenCode can restart independently)
  • Multiple Station instances sharing one OpenCode

CLI Backend (opencode-cli)

Spawns opencode run as a subprocess for each task. No server required - OpenCode bootstraps itself on a random port for each execution.
Station Agent → spawn process → opencode run --format json "task" → Filesystem
The CLI backend is ideal for:
  • CI/CD pipelines (GitHub Actions, GitLab CI)
  • Serverless environments where you can’t run a persistent server
  • Simple setups without infrastructure dependencies
  • Session continuation across multiple agent runs

Configuration Reference

HTTP Backend Config

# ~/.config/station/config.yaml
coding:
  backend: opencode               # HTTP backend
  opencode:
    url: http://localhost:4096    # OpenCode server URL
  max_attempts: 3
  task_timeout_min: 10

NATS Backend Config

# ~/.config/station/config.yaml
coding:
  backend: opencode-nats          # NATS backend
  nats:
    url: nats://localhost:4222    # NATS server URL
    # creds_file: /path/to/creds  # Optional: NATS credentials
  max_attempts: 3
  task_timeout_min: 10
When using opencode-nats, ensure the OpenCode container has the Station plugin installed and is connected to the same NATS server. See OpenCode Container for setup instructions.

CLI Backend Config

# ~/.config/station/config.yaml
coding:
  backend: opencode-cli           # CLI subprocess backend
  cli:
    binary_path: opencode         # Path to opencode binary (default: "opencode")
    timeout_sec: 300              # Task timeout in seconds (default: 300)
  workspace_base_path: /tmp/station-coding
  cleanup_policy: on_session_end  # on_session_end | on_success | manual
The CLI backend requires opencode to be installed and available in your PATH. No server needs to be running - each task spawns a fresh OpenCode process.

Claude Code Backend Config

Claude Code is Anthropic’s official AI coding agent. It uses your Claude Max/Pro subscription or API key.
# ~/.config/station/config.yaml
coding:
  backend: claudecode              # Claude Code CLI backend
  claudecode:
    binary_path: claude            # Path to claude CLI (default: "claude")
    timeout_sec: 300               # Task timeout in seconds (default: 300)
    model: sonnet                  # Model: sonnet, opus, haiku (optional)
    max_turns: 10                  # Max agentic turns (default: 10)
    allowed_tools:                 # Whitelist specific tools (optional)
      - Read
      - Write
      - Edit
      - Bash
      - Glob
      - Grep
    disallowed_tools: []           # Blacklist tools (optional)
  workspace_base_path: /tmp/station-coding
  cleanup_policy: on_session_end
  1. Install Claude Code CLI: https://docs.anthropic.com/en/docs/claude-code
  2. Authenticate: Run claude login for Max/Pro, or set ANTHROPIC_API_KEY
# Verify installation
claude --version

# Authenticate (for Max/Pro subscribers)
claude login
Claude Code runs with --dangerously-skip-permissions for non-interactive use. Ensure workspace directories are appropriately secured.

Private Repository Authentication

To work with private repositories, configure git credentials in your Station config:
# ~/.config/station/config.yaml
coding:
  backend: opencode-cli  # or any backend
  git:
    # Option 1: Reference an environment variable (recommended)
    token_env: GITHUB_TOKEN
    
    # Option 2: Direct token (supports env expansion)
    # token: ${GITHUB_TOKEN}
    
    # Optional: Custom git identity for commits
    user_name: "My Bot"
    user_email: "bot@example.com"
Create a Personal Access Token with repo scope:
  1. Go to GitHub Settings → Developer Settings → Personal Access Tokens
  2. Generate a token with repo (full control of private repositories)
  3. Set it as an environment variable:
export GITHUB_TOKEN=ghp_xxxxxxxxxxxx
Security Notes:
  • Never commit tokens to config files - use token_env to reference environment variables
  • Tokens are automatically redacted from logs and error messages
  • In CI/CD, use secrets management (GitHub Secrets, Vault, etc.)
Example: Clone and work on a private repo
# Agent prompt
---
coding:
  enabled: true
---
Clone the private repository and add a README:

1. coding_open with repo_url="https://github.com/myorg/private-repo"
2. code with instruction="Create a comprehensive README.md"
3. coding_commit with message="Add README"
4. coding_push
5. coding_close
The git token is automatically injected into HTTPS URLs during clone/push operations.

When to Use Each Backend

ScenarioRecommended BackendReason
Claude Max/Pro subscriberclaudecodeUse your subscription, minimal setup
Prefer Anthropic’s official toolingclaudecodeFirst-party Claude integration
Local development, OpenCode on same machineopencode (HTTP)Simplest setup, direct communication
Docker/container deploymentsopencode-natsCross-container networking works reliably
Long-running tasks (>60s)opencode-natsAvoids MCP timeout issues
Multiple Station instancesopencode-natsShared OpenCode server
CI/CD pipelines (GitHub Actions)opencode-cli or claudecodeNo server required, self-bootstrapping
Serverless / ephemeral environmentsopencode-cli or claudecodeZero infrastructure dependencies
Session continuation across runsopencode-cliBuilt-in session ID tracking
Quick prototypingopencode (HTTP)Zero additional infrastructure

Long-Running Tasks and Timeouts

MCP (Model Context Protocol) has a default timeout of ~60 seconds. Complex coding tasks like project scaffolding, large refactors, or multi-file changes may exceed this limit.

Understanding the Timeout

When Station executes agent tools via MCP, each tool call has a timeout. If OpenCode takes longer than 60 seconds to complete a task, the MCP call will fail with a timeout error. Tasks that commonly timeout:
  • Generating entire project structures (scaffolding)
  • Large codebase refactors
  • Complex multi-file changes
  • Tasks requiring many LLM calls (iterative refinement)
Tasks that typically complete quickly:
  • Single file edits
  • Adding/modifying functions
  • Code review and analysis
  • Simple bug fixes

Solutions for Long-Running Tasks

Instead of one large task, use multiple smaller ones:
# ❌ Might timeout
task: "Create a full REST API with authentication, CRUD endpoints, and database models"

# ✅ Better approach
tasks:
  - "Create the database models for User and Post"
  - "Add authentication middleware"
  - "Create CRUD endpoints for User"
  - "Create CRUD endpoints for Post"
Design your agents to work incrementally.

Timeout Configuration

SettingLocationDefaultDescription
task_timeout_minconfig.yaml10Minutes to wait for OpenCode response
max_attemptsconfig.yaml3Retry attempts on failure
MCP timeoutProtocol default~60sCannot be changed easily
# config.yaml
coding:
  backend: opencode-nats
  max_attempts: 3
  task_timeout_min: 15  # Increase for complex tasks
The task_timeout_min setting only affects the NATS backend. For HTTP backend, you’re constrained by the MCP protocol timeout.

Session Continuation (CLI Backend)

The CLI backend supports session continuation - allowing multiple agent runs to share the same OpenCode context. This is useful for:
  • Multi-step workflows where each step builds on previous work
  • Interactive development with human-in-the-loop review
  • CI/CD pipelines that need to maintain state across jobs

How It Works

  1. First run creates a new session (title = your task message)
  2. Subsequent runs use --coding-session <name> to continue by title
  3. OpenCode maintains conversation history, file context, and tool state
Run 1: "Create feature branch for user-auth"
         ↓ session title: "Create feature branch for user-auth"
Run 2: --coding-session "user-auth" → finds session by title
         ↓ context preserved
Run 3: --coding-session "user-auth" → same session
         ↓ context preserved  
Run 4: --coding-session "user-auth" → commit and push

Using Session Continuation

Pass a session name or ID to continue from a previous run:
# First run - creates new session (title = first message)
stn agent run "Code Assistant" "Create a new feature branch for user-auth"
# Session title: "Create a new feature branch for user-auth"

# Second run - continue by name (partial match works!)
stn agent run "Code Assistant" "Implement the login endpoint" \
  --coding-session "user-auth"

# Or use any part of the title
stn agent run "Code Assistant" "Add unit tests for login" \
  --coding-session "feature branch"

# Or use the exact session ID
stn agent run "Code Assistant" "Final cleanup" \
  --coding-session "ses_47b42f435ffeOJLjZKhPMk0Adu"
The --coding-session flag accepts:
  • Session name - Searches titles (case-insensitive, partial match)
  • Session ID - Direct lookup (starts with ses_)
Run opencode session list to see all sessions with their titles.

Listing Sessions

You don’t need to remember session IDs - just use part of the session title. But if you want to see all sessions:
# List all sessions with titles
opencode session list

# Output:
# Session ID                      Title                              Updated
# ───────────────────────────────────────────────────────────────────────────
# ses_47b8a7be0ffe...             Create feature branch for user-auth    12:28 AM
# ses_483ea4a0bffe...             Fix login validation bug                12:26 AM
Then continue any session by name:
stn agent run "Code Assistant" "continue the work" --coding-session "user-auth"

Environment Variables

VariableDescription
STN_OPENCODE_URLOverride OpenCode HTTP URL
NATS_URLOverride NATS URL for opencode-nats backend

Agent Frontmatter

---
model: openai/gpt-4o
coding:
  enabled: true           # Enable coding tools for this agent
  workspace_path: /path   # Optional: default workspace
---
The agent frontmatter only controls whether coding tools are enabled for that agent. The backend transport (HTTP vs NATS) is determined by Station’s global config. This makes agents portable - the same agent definition works whether Station uses HTTP or NATS backend.

Agent Prompt Template

When creating agents that use coding tools, you must use the {{userInput}} template variable to pass the user’s task to the code tool. Without this, the agent won’t correctly forward the task.
---
metadata:
  name: code-assistant
  description: AI coding assistant
model: anthropic/claude-sonnet-4-5-20250929
coding:
  enabled: true
---

Execute this coding task: {{userInput}}

Steps:
1. Call coding_open with workspace_path="/path/to/project"
2. Call code with instruction="{{userInput}}"
3. Call coding_close
The {{userInput}} variable is populated by Station with the user’s task message. If you don’t reference it in your prompt, the agent won’t know what task to execute and may ask for clarification or pass incorrect instructions to the code tool.

Container Mode (stn up)

When running Station in container mode via stn up, special configuration is needed for OpenCode connectivity.

The Problem

By default, OpenCode binds to 127.0.0.1:4096 which is only accessible from localhost. Docker containers cannot reach 127.0.0.1 on the host.

The Solution

Start OpenCode with --hostname 0.0.0.0 to listen on all interfaces:
# Required for container mode
opencode --hostname 0.0.0.0
Station’s stn up command automatically rewrites the config:
# Your config (host)
coding:
  opencode:
    url: http://localhost:4096

# Rewritten config (in container)
coding:
  opencode:
    url: http://host.docker.internal:4096

Verify Connectivity

# Check OpenCode is accessible from container
docker exec station-server curl http://host.docker.internal:4096/global/health
# Should return: {"healthy":true}

Architecture

┌─────────────────────────────────────────────────────────────┐
│  HOST MACHINE                                               │
│                                                             │
│  ┌─────────────────┐       ┌─────────────────────────────┐  │
│  │  OpenCode       │◀──────│  station-server container   │  │
│  │  0.0.0.0:4096   │       │  coding.opencode.url:       │  │
│  │  (--hostname    │       │  host.docker.internal:4096  │  │
│  │   0.0.0.0)      │       │                             │  │
│  └─────────────────┘       └─────────────────────────────┘  │
│         │                                                   │
│         ▼                                                   │
│  ┌─────────────────┐                                        │
│  │  Local Files    │  ◀── Files created/modified here      │
│  │  /my/project    │                                        │
│  └─────────────────┘                                        │
└─────────────────────────────────────────────────────────────┘
Files created by OpenCode persist on the host machine, not in the container. This is the key difference from sandbox mode.

Example Workflows

Simple File Creation

stn agent run "Code Assistant" "Create hello.py with a hello world function"
Agent workflow:
  1. coding_open({"workspace_path": "/tmp/workspace"})
  2. code({"task": "Create hello.py with a hello world function"})
  3. coding_close()
Result: /tmp/workspace/hello.py created on your filesystem.

Code Refactoring

stn agent run "Code Assistant" "Refactor the database module to use connection pooling"
Agent workflow:
  1. coding_open({"workspace_path": "/home/user/my-app"})
  2. code({"task": "Read the current database.py implementation"})
  3. code({"task": "Refactor to use connection pooling with a pool size of 10"})
  4. coding_commit({"message": "Refactor: add database connection pooling"})
  5. coding_close()

Full Development Cycle

---
metadata:
  name: "Feature Developer"
  description: "Implements features end-to-end"
model: openai/gpt-4o
coding:
  enabled: true
  backend: opencode
---

You are a senior developer. When given a feature request:

1. Open a coding session in the project directory
2. Read existing code to understand the codebase
3. Implement the feature following existing patterns
4. Write tests for the new functionality
5. Commit changes with a descriptive message
6. Push to the remote branch
7. Close the session

Always follow the project's coding style and conventions.

Troubleshooting

OpenCode Not Responding

# Check if OpenCode is running
curl http://localhost:4096/global/health

# Check which port OpenCode is using
lsof -i :4096

# Restart OpenCode
pkill opencode && opencode --hostname 0.0.0.0

Container Can’t Reach OpenCode

# Verify OpenCode is bound to 0.0.0.0
netstat -tlnp | grep 4096
# Should show 0.0.0.0:4096, not 127.0.0.1:4096

# If bound to 127.0.0.1, restart with:
opencode --hostname 0.0.0.0

Session Errors

If you see “no active session” errors:
  • Ensure coding_open was called first
  • Check OpenCode logs for connection issues
  • Verify workspace path exists and is accessible

Next Steps