Skip to content
Guide Intermediate 12 min

OpenCode + Neovim + tmux: the complete setup

Sébastien Giband · Dev Symfony/TypeScript · terminal-first workflow · AI-assisted coding since 2021 · · Updated on
Neovim tmux OpenCode SSH Mac -> Ubuntu PHP/Symfony 7

TL;DR

OpenCode integrates naturally into a Neovim/tmux workflow: a dedicated tmux split, the agent in one pane, your editor in the other. The client/server architecture lets you start OpenCode server-side and connect via SSH with no extra configuration. Full setup in 30 minutes.

opencode neovim tmux workflow

Update, July 2026 — OpenCode is no longer my daily agent (back to Claude Code, documented in Anthropic, the Apple of AI). This guide remains valid for an OpenCode setup, and the transferable patterns — per-folder AGENTS.md, a versioned command library — apply to any agent.

OpenCode is a coding agent built for the terminal. Its client/server Go architecture and vim-like TUI make it the most natural tool for a Neovim/tmux workflow — the only one that doesn’t ask you to compromise on how you work.

This guide documents the setup I use daily: Mac locally, Ubuntu remotely via SSH, Neovim + tmux as the work environment, OpenCode in a dedicated split.

How do you install OpenCode?

Installation is a single binary. No node_modules, no Python runtime, no IDE extension.

# Installation via the official script
curl -fsSL https://opencode.ai/install | bash

# Verification
opencode --version

# On remote Ubuntu/Debian — same command
# The binary goes to ~/.local/bin/ or /usr/local/bin/

If you’d rather not pipe to bash, binaries are available directly on GitHub Releases for Linux AMD64, ARM64, macOS Intel and Apple Silicon.

How do you configure LLM providers?

OpenCode uses a JSON config file. The first thing to do is define at least one provider with its API key.

// ~/.config/opencode/config.json
{
  "providers": {
    "anthropic": {
      "apiKey": "sk-ant-..."
    },
    "openrouter": {
      "apiKey": "sk-or-..."
    }
  },
  "model": "anthropic/claude-sonnet-4-5",
  "theme": "dark"
}

OpenRouter is worth configuring in parallel: it gives access to Gemini Flash, MiniMax, and dozens of other models via a single API key. Switching models then becomes a matter of seconds.

Note (from when I used this setup): Kilo Code CLI — a fork of OpenCode — also offers Kilo Gateway, which provides access to free models (including MiniMax 2.5). An interesting alternative if you want to reduce costs to zero on mechanical tasks — setup since abandoned, see the callout at the top of this guide.

# Switching models from OpenCode / Kilo Code CLI
# In the TUI: press 'm' to open the model selector
# Or directly:
opencode --model openrouter/google/gemini-2.0-flash-001

For a specific project, you can override the global config with a local file:

// myproject/.opencode/config.json
{
  "model": "openrouter/google/gemini-2.0-flash-001"
}

This local file is committed to Git — the whole team uses the same default model on this project.

How do you integrate OpenCode into tmux?

The tmux integration is simple and produces a very natural result. The idea: a permanent vertical split, Neovim on the left, OpenCode on the right.

Basic layout:

# From any tmux session
# Create a vertical split and launch OpenCode
tmux split-window -h -l 40% 'opencode'

# Or via a tmux binding in ~/.tmux.conf
bind-key a split-window -h -l 40% 'opencode'

Recommended tmux configuration for this workflow:

# ~/.tmux.conf — relevant excerpts

# More accessible prefix
set -g prefix C-a
unbind C-b

# Vim-style pane navigation
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R

# Launch OpenCode in a right split
bind-key a split-window -h -l 38% 'opencode'

# Launch a named OpenCode session (for remote)
bind-key A new-session -d -s opencode 'opencode' \; switch-client -t opencode

# Quick resize
bind-key -r H resize-pane -L 3
bind-key -r L resize-pane -R 3

For a remote SSH setup:

# On the remote server — start OpenCode in a persistent tmux session
tmux new-session -d -s oc 'opencode'

# From your local machine
ssh user@server -t 'tmux attach -t oc'

# If the session doesn't exist yet
ssh user@server -t 'tmux new-session -A -s oc opencode'

The session survives SSH disconnections. You find your agent exactly where you left it.

How do you set up the project context file?

An AGENTS.md (or CLAUDE.md) file at the project root is automatically read by OpenCode at the start of each session. It’s the agent’s permanent memory for your project.

# AGENTS.md — myproject

## Stack
- PHP 8.3 · Symfony 7.1 · API Platform 3
- TypeScript 5 · React 18 · Vite 5
- Tests: PHPUnit 11 (backend) · Vitest (frontend)
- DB: PostgreSQL 16

## Critical conventions
- Symfony services are `final` by default
- Repositories inherit from `AbstractRepository`
- Tests: `AbstractServiceTest` for services, `AbstractApiResourceTest`
  for endpoints
- No logic in constructors

## What the agent does NOT do without asking
- Modify the public interface of an existing service
- Create Doctrine migrations
- Modify Symfony config files (`services.yaml`, `security.yaml`)

## Useful commands
- Backend tests: `php bin/phpunit --filter TestName`
- Frontend tests: `npx vitest run`
- TypeScript check: `npx tsc --noEmit`
- Dev server: `symfony serve -d`

For subdirectory-specific conventions, a local AGENTS.md is read in addition to the root file:

# src/Service/AGENTS.md
- Services: final, constructor injection only
- Public methods > 20 lines -> split them
- No direct dependency on Repositories from Services
  (use interfaces instead)

How do you create custom commands?

Custom commands are OpenCode’s most powerful mechanism for capitalizing on recurring workflows. They’re Markdown files in .opencode/commands/, versioned in Git.

mkdir -p .opencode/commands

Example — create a complete API Platform endpoint:

# .opencode/commands/new-endpoint.md

Create a complete API Platform 3 endpoint for the `$ARGUMENTS` entity.

Files to create:
1. `src/ApiResource/{Entity}Resource.php`
   - Operations: GetCollection, Get, Post, Patch, Delete
   - Groups: `{entity}:read`, `{entity}:write`

2. `tests/ApiResource/{Entity}ResourceTest.php`
   - Extends AbstractApiResourceTest
   - Covers: list, detail, valid/invalid creation, update, delete

3. `tests/fixtures/{Entity}Fixtures.php`

Then run: `php bin/phpunit tests/ApiResource/{Entity}ResourceTest.php`
Fix errors until all tests pass.

Usage:

> /new-endpoint Order

Other useful commands to create depending on your project:

.opencode/commands/
├── new-endpoint.md        # Complete API Platform endpoint
├── new-service.md         # Symfony service with tests
├── review-pr.md           # Code review with checklist
├── write-tests.md         # Tests for an existing file
└── explain-error.md       # Stack trace analysis

What are the essential TUI keymaps?

OpenCode has vim-like navigation. The essentials to be productive on day one:

ShortcutAction
i or EnterEnter insert mode (write)
EscapeExit insert mode
j / kNavigate through history
/Search the conversation
mOpen the model selector
nNew session
qQuit
/add path/fileAdd a file to the context
/clearClear the session context

To add files to context — the most-used feature:

> /add src/Service/OrderService.php
> /add tests/Service/OrderServiceTest.php

What does this change in the daily workflow?

After several months with this setup, the habits that have settled in:

A dedicated agent tmux split runs permanently during coding sessions. Neovim on the left, agent on the right. When a task comes up, I brief the agent without leaving Neovim. The agent reads the files, produces the code, I switch back to Neovim for the review.

Custom commands now cover ~70% of recurring tasks on the Symfony project. Creating an endpoint, writing tests for a service, analyzing a stack trace — these are commands, not instructions reconstructed every time.

Model switching based on the task had become a reflex on this setup: mechanical task (boilerplate tests, migration) → budget or free model via Kilo Gateway, reasoning task (architecture, complex debugging) → Claude Sonnet. The OpenCode/Kilo Code CLI ecosystem enabled this routing with zero friction.

Resources

Frequently Asked Questions

Does OpenCode work remotely via SSH?
Yes, that's one of its main advantages. The Go binary installs server-side, you launch it in a tmux session, and you attach from your local machine via SSH. No tunnel, no extension, no VS Code Server. It's the first coding agent that actually works well in a native SSH setup.
How do you share context between Neovim and OpenCode?
Two approaches. The simplest: copy the current buffer content to the system clipboard, paste into OpenCode. The more integrated: a Neovim keymap that sends the buffer or visual selection to the OpenCode HTTP server via curl. This guide covers both.
Can you run multiple OpenCode sessions in parallel?
Yes via the client/server architecture. Each OpenCode session is independent. In practice: one tmux split per task, one agent in each split. Sessions don't share context — that's by design, to avoid cross-task pollution.
How do you persist sessions across SSH disconnections?
tmux is the answer. OpenCode runs in a named tmux session, you disconnect, reconnect, run `tmux attach -t opencode` — the session is there. The agent wasn't interrupted.
Do you need to configure anything in Neovim specifically?
Not for basic usage — OpenCode is editor-independent. For advanced integration (sending the current buffer to the agent, displaying responses in a Neovim split), a few keymaps are enough. No dedicated plugin needed.