Skip to content

feat(server): Add live context capability to OpenCode - #318

Open
itsmeyaw wants to merge 9 commits into
nickjvandyke:mainfrom
itsmeyaw:main
Open

feat(server): Add live context capability to OpenCode#318
itsmeyaw wants to merge 9 commits into
nickjvandyke:mainfrom
itsmeyaw:main

Conversation

@itsmeyaw

@itsmeyaw itsmeyaw commented Aug 7, 2026

Copy link
Copy Markdown

Tasks

  • I read CONTRIBUTING.md
  • I ensured my changes pass automated checks
  • I reviewed and understand the AI-generated code in my changes (if any)

Description

TL:DR; Add live context capability to OpenCode as in claude code (see claudecode.nvim as example)

This implementation adds real-time WebSocket-based live context broadcasting to opencode.nvim, enabling OpenCode TUI to track the current file/selection in Neovim.

Architecture

Components

  1. WebSocket Server (lua/opencode/server/websocket/)

    • init.lua - Main server module with start/stop/broadcast functions
    • tcp.lua - TCP server using vim.uv
    • frame.lua - WebSocket frame encoder/decoder (RFC 6455)
    • handshake.lua - WebSocket upgrade handshake with auth
    • client.lua - Client connection management
    • utils.lua - Pure Lua utilities (SHA-1, base64, UTF-8)
  2. Selection Tracking (lua/opencode/editor/selection.lua)

    • Autocommands for CursorMoved, ModeChanged, BufEnter, TextChanged
    • Debounced updates (100ms)
    • Visual selection and cursor position capture
  3. Lockfile Manager (lua/opencode/editor/lockfile.lua)

    • Creates ~/.claude/ide/[port].lock
    • Compatible with Claude Code lockfile format
    • Atomic file creation
    • Auto-cleanup of stale lockfiles

Protocol

JSON-RPC 2.0 Messages:

// Selection Changed (Neovim -> OpenCode)
{
  "jsonrpc": "2.0",
  "method": "selection_changed",
  "params": {
    "text": "selected text",
    "filePath": "/path/to/file",
    "fileUrl": "file:///path/to/file",
    "selection": {
      "start": { "line": 10, "character": 5 },
      "end": { "line": 15, "character": 20 },
      "isEmpty": false
    }
  }
}

// At-Mentioned (Neovim -> OpenCode)
{
  "jsonrpc": "2.0",
  "method": "at_mentioned",
  "params": {
    "filePath": "/path/to/file",
    "lineStart": 10,
    "lineEnd": 20
  }
}

Usage

Configuration

Note: this must live inside the init instead of config because live_context options should present before the plugin load.

vim.g.opencode_opts = {
  live_context = {
    enabled = true,  -- Auto-start when the plugin loads
    port = 0,        -- 0 for random port
    auth_token = nil -- Optional: set to string or true to generate
  }
}

Command

  • :OpenCodeLiveContextStart - Start WebSocket server
  • :OpenCodeLiveContextStop - Stop WebSocket server
  • :'<,'>OpenCodeAttach - Attach visual selection (no submit)

API

local opencode = require("opencode")

-- Start live context
opencode.start_live_context({ port = 0, auth_token = nil })

-- Stop live context
opencode.stop_live_context()

-- Attach current selection without submitting
opencode.attach_context()

Recommended Keymap

vim.keymap.set("n", "<leader>ol", function()
  require("opencode").start_live_context()
end, { desc = "Start OpenCode live context" })

vim.keymap.set("x", "<leader>oa", function()
  require("opencode").attach_context()
end, { desc = "Attach selection to OpenCode" })

OpenCode TUI Integration

OpenCode TUI automatically discovers the WebSocket server via:

  1. Lockfile at ~/.claude/ide/[port].lock

    {
      "pid": 12345,
      "workspaceFolders": ["/path/to/project"],
      "ideName": "Neovim",
      "transport": "ws",
      "authToken": "optional-token"
    }
  2. Environment Variable: for a fixed configured port, OPENCODE_EDITOR_SSE_PORT or CLAUDE_CODE_SSE_PORT can bypass lockfile discovery

Implementation Note

No External Dependencies

All WebSocket code is pure Lua using Neovim's vim.uv (libuv) - no external Lua packages required.

Compatibility

  • Compatible with Claude Code's WebSocket protocol
  • Uses same lockfile location and format
  • Can share environment variables for discovery

Testing

  1. Start OpenCode TUI (opencode)
  2. Start Nvim in other terminal (nvim and :OpenCodeLiveContextStart
  3. Move cursor arounds

Related Issue(s)

No related Issue

Screenshots/Videos

CleanShot.2026-08-07.at.18.13.56.mp4

- Implement pure Lua WebSocket server (RFC 6455) with no external dependencies
- Add selection tracking with autocommands and debounced updates
- Create lockfile manager for editor discovery (~/.claude/ide/[port].lock)
- Add configuration options for live context feature
- Provide user commands and API for programmatic control
- Support both auto-start and manual activation modes
- Broadcast selection_changed and at_mentioned events to OpenCode TUI
- Compatible with Claude Code WebSocket protocol

Components:
- WebSocket server (lua/opencode/editor/)
  - TCP server using vim.uv
  - Frame encoder/decoder
  - Handshake with auth
  - Client connection management
  - Pure Lua utilities (SHA-1, base64, UTF-8)
- Selection tracking (lua/opencode/editor/selection.lua)
  - CursorMoved, ModeChanged, BufEnter, TextChanged autocommands
  - 100ms debounced updates
- Lockfile manager (lua/opencode/editor/lockfile.lua)
  - Atomic file creation
  - Stale lockfile cleanup

API:
- start_live_context(opts)
- stop_live_context()
- attach_context()

Commands:
- :OpenCodeLiveContextStart
- :OpenCodeLiveContextStop
- :OpenCodeAttach (visual mode)

Configuration:
- live_context.enabled (default: false)
- live_context.port (default: 0 for random)
- live_context.auth_token (optional)
Copilot AI lite review requested due to automatic review settings August 7, 2026 17:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a “Live Context” feature to opencode.nvim, allowing Neovim to broadcast the current file/cursor/visual selection to the OpenCode TUI in real time via a local WebSocket server, discovered through a Claude Code–compatible lockfile.

Changes:

  • Added a pure-Lua WebSocket server (handshake + frame encode/decode + TCP plumbing) with JSON-RPC notifications for selection_changed and at_mentioned.
  • Implemented editor-side selection tracking with debounced autocmd updates, plus an attach action that emits at_mentioned.
  • Exposed public API + user commands for starting/stopping live context, and documented configuration/usage in the README.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
README.md Documents Live Context feature, config timing (init), API and commands.
plugin/live-context.lua Adds :OpenCodeLiveContextStart/Stop and :OpenCodeAttach, plus auto-start/shutdown wiring.
lua/opencode.lua Exposes start_live_context, stop_live_context, and attach_context in the public API.
lua/opencode/config.lua Adds live_context options and LuaLS types.
lua/opencode/editor/selection.lua Tracks cursor/visual selection and broadcasts updates / emits at_mentioned.
lua/opencode/editor/lockfile.lua Creates/removes/cleans Claude Code–style lockfiles and generates auth tokens.
lua/opencode/editor/init.lua Adds an opencode.editor module entrypoint.
lua/opencode/server/websocket/init.lua Orchestrates server lifecycle, client management, and JSON-RPC broadcasts.
lua/opencode/server/websocket/tcp.lua Provides libuv TCP server/client helpers.
lua/opencode/server/websocket/client.lua Implements per-connection buffering, handshake parsing, and frame dispatch.
lua/opencode/server/websocket/frame.lua Encodes/decodes WebSocket frames (RFC 6455).
lua/opencode/server/websocket/handshake.lua Validates upgrade requests and generates the accept response (optional auth).
lua/opencode/server/websocket/utils.lua Adds SHA-1/base64, header parsing, and small binary/UTF-8 helpers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lua/opencode/server/websocket/client.lua
Comment thread lua/opencode/editor/selection.lua
Comment thread lua/opencode/server/websocket/init.lua Outdated
@itsmeyaw itsmeyaw changed the title Add live context capability to OpenCode feat(server): Add live context capability to OpenCode Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants