Catalog npm
PACKAGE EXPLORERView in registry

@0xdon0/opencode-local-provider

npm

OpenCode plugin that adds a 'local' provider with auto-detection for Ollama, LMStudio, llama.cpp, vLLM, Exo, llama-swap, oMLX, MLX-VLM, and other OpenAI-compatible servers, with optional per-server API keys

exollama.cppllmlmstudiolocalmlx-vlmollamaomlxopencodepluginvllm
Versions collected4
Direct dependencies6From release 0.3.1
Last observed20 Oct, 23:05 UTC

README

Current package documentation

opencode-local-provider OpenCode Plugin

Fork of goniz/opencode-local-provider, published as @0xdon0/opencode-local-provider. It adds optional per-server API keys, adding servers from /connect, listing every llama-swap model, and a fallback for any OpenAI-compatible server. Don't install it alongside the original package.

OpenCode plugin that adds a single local provider with runtime model detection for local OpenAI-compatible servers.

It currently supports the following local backends:

  • Ollama
  • LM Studio
  • llama.cpp server
  • vLLM
  • Exo
  • llama-swap
  • oMLX
  • MLX-VLM
  • Any other server with an OpenAI-compatible /v1/models endpoint (openai, used when nothing more specific matches)

Instead of creating one provider per server, this plugin keeps one local provider and lets you register multiple named targets. Each target is probed at runtime, and its models are exposed automatically.

Features

  • Adds a local provider to OpenCode
  • Supports multiple servers under one provider
  • Includes supported default 127.0.0.1 targets automatically
  • Detects models at runtime and fills in context size, tool calling, and vision support where the server reports them
  • Routes each model to the correct target URL
  • Optional API key per target, sent as Authorization: Bearer <key>
  • Uses OpenCode global config, not project-local config

Example

https://github.com/user-attachments/assets/8693fd22-c311-4cb4-913b-93d5a531b23c

Install

opencode plugin --global @0xdon0/opencode-local-provider

On OpenCode v2:

opencode plugin add @0xdon0/opencode-local-provider

OpenCode will install the package and update the config for you. Upgrading from v1? See Migrating from v1 to v2.

Provider Setup

Default targets are enabled automatically for these backends and ports:

  • Ollama: http://127.0.0.1:11434
  • LM Studio: http://127.0.0.1:1234
  • llama.cpp: http://127.0.0.1:8080
  • vLLM: http://127.0.0.1:8000
  • Exo: http://127.0.0.1:52415
  • llama-swap: http://127.0.0.1:8080
  • oMLX: http://127.0.0.1:8000
  • MLX-VLM: http://127.0.0.1:8080

If your local servers run on these ports and do not need an API key, you can start using the local provider immediately.

Note: oMLX with API authentication enabled needs a custom target with its API key set (see below).

Custom Targets

Add a server on another host or port, or one that needs an API key, with Add Custom Target. Run it from the TUI with /connect → Local LLM Provider, or from the CLI:

opencode auth login --provider local --method "Add Custom Target"

It asks for:

  • a target ID, like studio or remote-ollama
  • the server URL, with or without /v1
  • the server's API key. Leave it empty if the server has none. Enter {env:VAR_NAME} to store a reference to an environment variable instead of the key itself
  • which models to list: only loaded models, or every model the server offers (useful for llama-swap, which loads models on demand)

The plugin checks that the server answers before it saves anything, then adds the target to your OpenCode global config. Run it again to add more servers.

/connect only lists Local LLM Provider once the provider has at least one model. If none of your servers are reachable yet, add the first target from the CLI.

You can also add targets manually in config:

{
  "provider": {
    "local": {
      "options": {
        "includeDefaults": true,
        "targets": {
          "studio": {
            "url": "http://192.168.1.10:1234/v1",
            "kind": "lmstudio"
          },
          "swap": {
            "url": "https://llama-swap.example.com/v1",
            "kind": "llamaswap",
            "apiKey": "{env:LLAMA_SWAP_API_KEY}",
            "includeUnloaded": true
          }
        }
      }
    }
  }
}

Target fields:

  • url (required): the server URL
  • kind (optional): one of ollama, lmstudio, llamacpp, vllm, exo, llamaswap, omlx, mlxvlm, openai. If you leave it out, the backend is detected. openai treats any server as a plain OpenAI-compatible endpoint
  • apiKey (optional): sent as Authorization: Bearer <key> when probing the server and with every chat request to its models. Use {env:VAR_NAME} to keep the key out of the config file
  • includeUnloaded (optional, llama-swap only): list every model llama-swap offers, not only the loaded ones. The plugin reads their details from /v1/models and does not load them

Explicit targets override the built-in defaults when they use the same ID. A key set in provider.local.options.apiKey applies to every target that has no apiKey of its own.

With includeDefaults: true, the built-in default 127.0.0.1 targets are also checked at runtime even though they are not written into config. Set it to false if you only use custom targets.

OpenCode v2

The same package works with OpenCode v2. Setup differs in a few places:

  • Adding a server: run /connect → Local LLM Servers → Add Custom Target. It asks the same questions and checks the server the same way. Each target is saved as one of that integration's connections, with its API key kept in OpenCode's credential store, so you remove a target by removing its connection there.

  • Config targets: v2 has no provider.local.options. Put targets, includeDefaults and a shared apiKey in the plugin's own entry instead:

    {
      "plugins": [
        {
          "package": "@0xdon0/opencode-local-provider",
          "options": {
            "includeDefaults": true,
            "targets": {
              "studio": { "url": "http://192.168.1.10:1234/v1", "kind": "lmstudio" }
            }
          }
        }
      ]
    }
    
  • Refreshing: the plugin probes again every minute and whenever a target is added or removed, so you don't need to restart OpenCode to see newly loaded models. Remembered llama-swap context sizes are kept in the plugin's own storage instead of ~/.cache.

  • Model overrides: they go under providers.local.models (note providers), keyed by <target>/<model>, and use v2's model fields. OpenCode applies them on top of what the plugin detected:

    {
      "providers": {
        "local": {
          "models": {
            "swap/qwen3.6-35b-a3b": {
              "name": "Qwen 3.6 (swap)",
              "limit": { "context": 262144, "output": 32000 },
              "capabilities": { "tools": true, "input": ["text", "image"] }
            }
          }
        }
      }
    }
    

    Useful fields are name, limit (context, input, output), capabilities (tools, input, output), variants and disabled. The v1 fields modalities, tool_call and attachment don't exist in v2.

Each target's key comes from its own config entry or /connect connection. A key saved for the local provider itself is ignored.

Migrating from v1 to v2

v2 doesn't read v1's plugin or provider config keys, so after upgrading the local provider shows no models until you move your settings. Your old config stays in the file; v2 just ignores it.

  1. Rename plugin to plugins and turn the plugin's entry into an object.
  2. Move everything under provider.local.options (targets, includeDefaults, apiKey) into that entry's options.
  3. Move model overrides from provider.local.models to providers.local.models and switch them to v2's fields (see above).

v1:

{
  "plugin": ["@0xdon0/opencode-local-provider"],
  "provider": {
    "local": {
      "options": {
        "targets": {
          "swap": {
            "url": "https://llama-swap.example.com/v1",
            "kind": "llamaswap",
            "apiKey": "{env:LLAMA_SWAP_API_KEY}",
            "includeUnloaded": true
          }
        }
      }
    }
  }
}

v2:

{
  "plugins": [
    {
      "package": "@0xdon0/opencode-local-provider",
      "options": {
        "targets": {
          "swap": {
            "url": "https://llama-swap.example.com/v1",
            "kind": "llamaswap",
            "apiKey": "{env:LLAMA_SWAP_API_KEY}",
            "includeUnloaded": true
          }
        }
      }
    }
  ]
}

Instead of editing config, you can also add each server again with /connect → Local LLM Servers → Add Custom Target.

If chats fail with Missing auth credential: apiKey, update the plugin to 0.3.1 or later. v1's Add Custom Target saved an empty key for the local provider, v2 copies it over on upgrade, and earlier versions of the plugin let it replace every target's key.

How Models Appear

Models are discovered dynamically from each configured target. By default, only loaded models are listed.

To avoid collisions, model IDs are prefixed with the target ID:

  • ollama/llama3.2
  • studio/qwen2.5-coder

Each generated model keeps its own target URL and API key internally, so requests go to the correct backend.

Models that don't chat in text, such as speech-to-text, rerankers, or embeddings, are skipped when the server's listing says so.

Context Size and Model Settings

OpenCode compacts a conversation once it nears the model's context size, so each model needs the right one. The plugin uses the first of these that it finds:

  1. Settings for the model in your OpenCode config (see below)
  2. What the running server reports: llama.cpp, or a llama-swap model that is currently loaded
  3. The server's /v1/models listing (context_length, context_window, max_model_len or meta.n_ctx)
  4. What a llama-swap model reported the last time it was loaded when OpenCode started. These values are kept in ~/.cache/opencode-local-provider/models.json
  5. 32,768 tokens

The output limit is a quarter of the context, capped at 32,000 tokens. Sizes are read when OpenCode starts, so restart it to pick up changes.

llama-swap servers

llama-swap only reports a model's context size while the model is loaded. To advertise every model's size, the server admin can add a capabilities block to each model in the llama-swap config (v225 or later). The listing then includes the context size, tool support and input types:

models:
  qwen3.6-35b-a3b:
    cmd: llama-server --port ${PORT} -m /models/Qwen3.6-35B-A3B.gguf --mmproj /models/mmproj.gguf -c 262144
    capabilities:
      context: 262144 # the -c value from cmd
      tools: true
      in: [text, image] # image only when cmd loads an --mmproj
      out: [text]
  whisper:
    cmd: whisper-server --port ${PORT} -m /models/ggml-large-v3.bin
    capabilities:
      in: [audio] # not a chat model, so the plugin skips it
      out: [text]

Set context to the -c value in cmd. Without -c, llama-server chooses the size when it loads the model, and may reduce it to fit in memory.

Overriding a model

Settings under provider.local.models, keyed by <target>/<model>, replace what the plugin detected (v1 format; for v2 see OpenCode v2):

{
  "provider": {
    "local": {
      "models": {
        "swap/qwen3.6-35b-a3b": {
          "limit": { "context": 262144, "output": 32000 },
          "modalities": { "input": ["text", "image"] }
        }
      }
    }
  }
}

This works for any OpenCode model field, such as name, limit, modalities, attachment, tool_call, reasoning, options or variants. OpenCode requires both context and output when limit is set.

Notes

  • Model detection is runtime-based, not static
  • If loaded models change in your local server, OpenCode will see the updated list on the next provider refresh
  • Built-in default 127.0.0.1 targets are enabled unless you set includeDefaults to false
  • If a custom target cannot be probed, the reason (for example HTTP 401 for a wrong key) is written to the OpenCode log

Development

Build the plugin:

bun run build

Run the provider integration suite:

bun run test:providers

Run a single provider suite:

PROVIDER_SUITE=ollama bun run test:providers

Notes:

  • The suite starts provider containers for ollama, lmstudio, llamacpp, vllm, exo, llamaswap, omlx, and mlxvlm from tests/docker/compose.providers.yml.
  • The Bun test runner talks to each service over the Docker Compose network using each container's internal IP. It does not require publishing ports to the host.
  • The first run can be slow because the containers may need to download model assets, LM Studio bootstraps its headless runtime at startup, and Exo warms models to a real ready state before the suite proceeds.
  • CI runs the same suite per provider via .github/workflows/provider-tests.yml.
  • If you change provider models or startup behavior, update tests/docker/compose.providers.yml and the Bun orchestration helpers in tests/docker/ instead of duplicating those details here.

Install it locally in OpenCode with a file path plugin entry, for example:

opencode plugin $PWD

License

MIT

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 4

Collected releases
VersionPublishedDirect dependenciesOpen version
0.3.1Registry latest12 Oct 20266
0.3.012 Oct 20266
0.2.117 Sept 20265
0.2.016 Sept 20265

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
thedonmon/opencode-local-provider

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 23:05 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:25184e30270c3bfef2fa8127bb04323be951ff79415e5695d354fed9bda6b8cc