DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

umerkhalid204 /

umerkhalid204/dsh-plugin-local-llm

Verified

DeepSeek Harness plugin: run the agent on local engines - LM Studio, Ollama, Strata, Lemonade Server, or any OpenAI-compatible endpoint - as provider routes you pick in the model selector.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@b0b9f2c9

dsh-plugin-local-llm

Run the agent on models served by your own machine. The plugin registers local inference engines as ordinary Harness provider routes, so a local model is picked in the composer's model selector exactly like a hosted one, and each engine is declared as a configurable third-party provider.

Engines it knows

Provider id Default endpoint Catalog dialect
lmstudio http://127.0.0.1:1234/v1 LM Studio (/api/v0/models enrichment: load state, quantization, vision)
ollama http://127.0.0.1:11434/v1 Ollama (/api/tags plus per-model sizes and quantization)
strata http://127.0.0.1:8080/v1 Strata (packs named by quantization)
lemonade http://127.0.0.1:13305/v1 Lemonade Server (labels: chat, vision, tool-calling, reasoning)
local-openai http://127.0.0.1:8081/v1 llama.cpp server, vLLM, LocalAI, TGI, anything OpenAI-compatible — off by default so two engines never fight over one port

All five speak OpenAI-compatible /v1/chat/completions; what differs is how a model list is described. Strata's listing is not a documented contract, so providers.strata.models declares the packs you serve (names and context windows), and that declaration fills whatever the server leaves out.

Install

Build a package from this checkout and install that, rather than the directory:

npm pack --pack-destination dist     # -> dist/dsh-plugin-local-llm-<version>.tgz

Then in the Harness: Settings → Plugins → Install bundle, and point it at the .tgz. A bundle is a patch layer over the Loader entry list, so if you prefer declaring it, add one row to ~/.dsh/profiles/<profile>/cordis.patch.yml:

- insert:
    - id: local-llm
      name: 'dsh-plugin-local-llm'

The row id local-llm is what its config, settings namespace and /local-llm/api routes are keyed by; name is the package specifier, whose version comes from what you installed. Installing a package is the supported layout — only then can the plugin resolve its own dependencies, which is what gives it a settings form (see below).

Use it

local_models scan                       # what is up, and what it can serve
local_models use provider=strata model=iq3_s
local_models ping provider=lemonade model=Qwen3-0.6B-GGUF
local_models settings                   # can a settings surface edit these engines?

use writes the profile's default model, so new sessions start on that route. Any registered route is accepted — including one owned by another adapter.

Settings, and why the install layout matters

providers.<id> in this row's config is the single source of truth for an engine: endpoint, the baseURLEnv names allowed to override it, apiKey, enabled, and a hand-declared models catalog. The plugin declares each engine in the configurable-provider directory with settingsNs: local-llm and settingsPath: ["providers", <id>], which is what the third-party provider list reads.

An auto-generated editing form additionally needs the plugin's Config schema, and that needs @deepseek-ai/schemastery importable from the installed package. Two install layouts behave differently:

  • Installed as a package (tarball or registry) — the copy lives at ~/.dsh/profiles/<profile>/node_modules/dsh-plugin-local-llm, where its declared dependencies resolve. This is the layout you want: npm pack --pack-destination ..\pkg-out, then install the .tgz.
  • Linked from a source checkout (install_bundle pointed at the directory) — Node resolves bare imports from the checkout, where no @deepseek-ai/* packages exist. The plugin still activates because index.js treats the Harness modules as optional and falls back to vendor/llm-contract.js, but Config stays undefined, so no generated fields appear and endpoint edits go through the profile patch (~/.dsh/profiles/<profile>/cordis.patch.yml).

Both were observed in one profile: linked, the engines were claimed, scanned, pinged and listed in the provider directory while Config reported absent; packed, the same sources resolved the dependency.

Provider ids are contested territory

Provider ids are global, and both the adapter registry and the configurable-provider directory are all-or-nothing registrations. So this plugin claims an id only when nothing else owns it and reports the rest:

served by local-llm: lmstudio, ollama, lemonade | left to another owner: strata@http://127.0.0.1:8080/v1

If you declared strata yourself (for instance as a pi-ai provider), that owner keeps serving it — which is what keeps an existing brain working — and this plugin still scans, pings and selects that endpoint. To hand the route to this engine, delete the other provider declaration and reload the profile.

Development notes

  • node --check index.js; ESM, no build step.
  • node test/dry-run.mjs runs 27 offline checks. It stages a throwaway tree first: the runtime sources are copied to test/shim/pkg and the stand-ins in test/shims/ are placed at test/shim/node_modules/@deepseek-ai/{dsh-llm,schemastery}, so the copy's bare imports resolve there and nothing in the package or the workspace gains a node_modules (test/shim/ is gitignored). That staging matters: a stand-in inside the checkout's own module chain would satisfy a linked install and silently replace the real Harness module.
  • test/shims/schemastery.js mirrors the real v3 surface — lowercase factories, nesting instead of chaining — so calling a builder method that does not exist fails offline rather than at activation.
  • Five fake servers, one per catalog dialect, back the suite and can be run by hand: PORT=1234 ENGINE=lmstudio node test/fake-openai-server.mjs, with ENGINE=lmstudio|ollama|strata|lemonade|openai. They also answer /v1/chat/completions: a prompt containing TOOLTEST streams a split tool call, HALFTOKEN ends with finish_reason length.
  • Host code hot-reloads on a plugin off/on toggle. package.json and cordis.patch.yml changes need a reinstall.
  • There is no Client half: no composer-dock line and no chip. Local models appear only in the model selector and in Settings.

Configuration reference

- insert:
    - id: local-llm
      name: 'dsh-plugin-local-llm'
      config:
        probeTimeoutMs: 2500      # per listing request
        scanTtlMs: 15000          # reuse a scan for this long
        maxTokens: 0              # 0 = leave the cap to the server
        apiKey: 'dsh-local'       # default bearer
        providers:
          lemonade:
            baseURL: 'http://192.168.1.20:13305/v1'
            apiKey: 'set when that server exports LEMONADE_API_KEY'
          local-openai:
            enabled: true
            baseURL: 'http://127.0.0.1:8080/v1'

MIT licensed; see LICENSE.

—/ 5

No ratings yet

Verified DSH bundle

Commit b0b9f2c9ccb5

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout