--- title: 🧩 Extensions description: Pinned Open VSX extension baseline, lock file semantics, install/audit commands, optional/excluded entries, and the LiteLLM AI provider wiring. source: verified deployment on the loca operator host, 2026-08-19; AI wiring verified in the running IDE 2026-08-20 reviewed: 2026-08-20 --- # 🧩 Extension baseline ## Pinned baseline (seven entries) | id | version | platform | reason | |---|---|---|---| | `Continue.continue` | 2.1.0 | linux-x64 | Primary open-source AI agent/chat/edit/autocomplete extension. | | `Anthropic.claude-code` | 2.1.235 | linux-x64 | First-party Claude Code IDE integration. | | `formulahendry.acp-client` | 0.2.0 | universal | Generic Agent Client Protocol client; drives the local `omp` harness as a native agent panel. | | `ms-python.python` | 2026.4.0 | universal | Python language support expected in this environment. | | `ms-python.debugpy` | 2026.6.0 | linux-x64 | Explicit debugger dependency instead of relying on later bootstrap by the Python extension. | | `ms-toolsai.jupyter` | 2025.9.1 | universal | Notebook workflow support in the browser IDE. | | `ms-azuretools.vscode-containers` | 2.4.5 | universal | Current Container Tools extension; its README states it replaces the older Docker extension functionality. | All seven come from `config/extensions.lock.json` (registry: `https://open-vsx.org`). ## OMP as a native agent panel (ACP) The `omp` harness is wired into the IDE over the Agent Client Protocol. No custom extension and no marketplace exception were needed: OMP already ships an ACP server and Open VSX already ships a generic ACP client. - agent side: `omp acp` runs Oh My Pi as an ACP server over stdio. Verified against the installed binary — `initialize` returns `protocolVersion 1` and `agentInfo {name: oh-my-pi, version: 17.4.0}`, and a full `session/new` + `session/prompt` turn streams `tool_call`, `plan`, `agent_message_chunk`, `usage_update`, `stopReason: end_turn` - client side: `formulahendry.acp-client` 0.2.0, MIT, `engines.vscode ^1.85.0`. It declares no `extensionKind`, so it loads in the remote extension host where Node and `child_process` exist — a requirement, since the client spawns the agent as a child process - protocol versions differ but interoperate: the client bundles ACP SDK `^0.21.1`, OMP pins `0.25.0`, both negotiate wire version 1 - configuration lives in `data/user/User/settings.json`: ```json "acp.agents": { "Oh My Pi": { "command": "/home/loca/.local/bin/omp", "args": ["acp"], "env": {} } } ``` VS Code merges this object with the extension's own defaults, so the agent tree shows the shipped entries (Copilot, Claude Code, Gemini, Qwen and others, all of which would `npx`-fetch at runtime) plus `Oh My Pi`. Only `Oh My Pi` is a pinned local binary; treat the rest as unpinned and unsupported here. Usage: activity bar → ACP Client → `ACP: New Conversation` → pick `Oh My Pi`. The status bar shows `ACP: Oh My Pi` when connected. The chat panel renders OMP's own session config as native controls (mode Default/Plan, model, thinking level), and the agents tree lists real prior OMP sessions for the open folder, because the client calls `session/list` and OMP answers from `~/.omp/agent/sessions`. Operational notes: - credentials never move. OMP authenticates itself from `~/.omp` via its `agent` auth method; the extension is not given any key. This is why the ACP route was chosen over exposing OMP on a loopback port - the IDE runs as `loca`, which holds `NOPASSWD: ALL`. An OMP session in this panel is therefore root-equivalent, gated only by Authelia one_factor on `cdsr.loca.zone`. Leave the client's permission prompts enabled; its file and terminal handlers are not workspace-confined - OMP's own `tools.approvalMode` default is permissive and subagents are unconditionally so. Set it explicitly rather than inheriting it - one `omp acp` process serves multiple sessions, but stdio carries a single client, so the IDE panel and a CLI `omp` are separate processes. They share `~/.omp`: session transcripts are per-directory with unique filenames and atomic rewrites, so that is safe, but memory and config are shared context, not isolation - OMP cannot be reached over MCP. It implements an MCP client only, so Continue's `mcpServers` cannot point at it; ACP is the only protocol bridge ## Lock file mechanics `config/extensions.lock.json` is the single source of truth. Each entry contains `id`, `version`, `platform`, `vsix_url`, `sha256_url`, `reason`, and `mode` (`baseline` or `optional`). VSIX cache lives in `tmp/extensions/` with filenames `-@.vsix`. Install script (`scripts/install-extensions.sh`): - requires `python3` (no `jq` on this host) - downloads VSIX + `.sha256` into cache if not present - verifies sha256 before install - installs with `code-server --config config/config.yaml --install-extension --force` Audit script (`scripts/list-extension-versions.sh`): - runs `code-server --list-extensions --show-versions` - compares against lock file - exits non-zero on `MISSING` or `MISMATCH` - `--include-optional` extends the check to `mode: optional` entries ## Commands ```bash # install baseline only cd /home/loca/dev/code-server && ./scripts/install-extensions.sh # install baseline + optional ./scripts/install-extensions.sh --include-optional # audit baseline ./scripts/list-extension-versions.sh # audit baseline + optional ./scripts/list-extension-versions.sh --include-optional ``` ## Transitively installed (expected, unpinned) | id | version | note | |---|---|---| | `ms-python.vscode-python-envs` | 1.36.0 | Python extension dependency | | `ms-toolsai.jupyter-keymap` | 1.1.2 | Jupyter dependency | | `ms-toolsai.jupyter-renderers` | 1.3.0 | Jupyter dependency | | `ms-toolsai.vscode-jupyter-cell-tags` | 0.1.9 | Jupyter dependency | | `ms-toolsai.vscode-jupyter-slideshow` | 0.1.6 | Jupyter dependency | These are not in the lock file and will vary; they are expected by-products of the baseline install. ## Optional: Cody (enterprise only) | id | version | platform | reason | |---|---|---|---| | `sourcegraph.cody-ai` | 1.155.0 | universal | Useful only with a Cody Enterprise account; the Open VSX README states it is no longer available for non-enterprise users. | Opt-in: ```bash ./scripts/install-extensions.sh --include-optional ``` ## Exclusions (recorded in lock file) | id | reason | |---|---| | `TabNine.tabnine-vscode` | Open VSX listing marks it legacy and states it does not onboard new users. | | `GitHub.copilot` | Microsoft-marketplace-only AI tooling; code-server cannot rely on Microsoft marketplace terms or access. | Any Microsoft-marketplace-only AI extensions fall under the same exclusion. ## Where extension configuration actually lives Extension config is not under `data/user/`. The unit sets `HOME=/home/loca`, so extensions that resolve their own paths from `$HOME` write outside the project — see [[architecture/runtime-topology#state-outside-the-project]]. - Continue writes `/home/loca/.continue/` — its real configuration and history, not `data/user/` - `config.yaml` — mode 600, holds provider settings; never commit it, never paste its contents into the wiki or project files - also `config.ts`, `.continuerc.json`, `index/`, `sessions/`, `dev_data/`, `.utils/` - version nuance for the pinned 2.1.0 build - it still contributes `continue.remoteConfigServerUrl`, `continue.userToken` and `continue.remoteConfigSyncPeriod` for shared/team config sync, sync period defaulting to 60 minutes - none of those three carries a deprecation message; the only deprecated setting is `continue.telemetryEnabled`, whose deprecation message points at Telemetry > Allow Anonymous Telemetry on the extension's User Settings page - so Continue configuration is not local-only in this build; this deployment simply leaves remote sync unconfigured - Claude Code reuses the operator's pre-existing `/home/loca/.claude/` and `/home/loca/.claude.json`, shared with the host Claude Code CLI — it is not deployment-owned state and is not created by the extension install - backup targets: `/home/loca/dev/code-server/` plus `/home/loca/.continue/`; the project directory alone misses Continue's config and chat sessions ## AI provider wiring (LiteLLM gateway) Continue is wired to the host LiteLLM gateway (`lllm`, loopback `127.0.0.1:52001`) — no cloud provider sign-in is used. The gateway is reachable from the IDE because code-server and LiteLLM run on the same host. - credential: a dedicated LiteLLM virtual key with alias `cdsr-ide`, scoped to the three model groups below. The master key is never placed in a client config. - key file: `/home/loca/dev/code-server/.ai-credentials` (mode 600, gitignored, single line `litellm_ide_key=`). The value is also present in `/home/loca/.continue/config.yaml` (mode 600). Neither value belongs in this wiki, the repo, or a systemd unit. - client config: `/home/loca/.continue/config.yaml`, three models, all `provider: openai` against `apiBase: http://127.0.0.1:52001/v1`. Shape validated against the extension's own `config-yaml-schema.json` (`name`, `model`, `provider` required; `roles` enum accepts `chat`, `edit`, `apply`, `autocomplete`). | model | upstream | roles | live state | |---|---|---|---| | `free` | OpenRouter `nvidia/nemotron-3.5-lightning:free` | chat, edit, apply, autocomplete | working — verified chat round-trip in the Continue panel | | `oss-120b` | Groq `openai/gpt-oss-120b` | chat, edit, apply | reachable, but Groq free-tier caps 8000 tokens/minute and Continue's agent prompt is ~8.6k, so chat returns `RateLimitError` | | `fast` | Groq `llama-3.1-8b-instant` | chat, edit, apply | broken upstream — Groq decommissioned the model, every call returns `404 model_not_found`. Defect belongs to the `lllm` stack config, not this one | Practical consequence: select `free` in the model picker. Repairing `oss-120b`/`fast` means editing `dev/lllm/config/config.yaml` (a different stack) — not a cdsr change. Workspace Trust gate: a fresh browser profile opens `/home/loca` in Restricted Mode, which silently disables every third-party extension — no Continue or Claude Code icon in the activity bar and no `Continue:` commands in the palette. Fix: Command Palette → `Workspaces: Manage Workspace Trust` → Trust. Symptom is indistinguishable from a failed install, so check trust before re-installing anything. Claude Code is deliberately NOT wired to LiteLLM. The gateway does expose an Anthropic-compatible `/v1/messages` passthrough, but the reference probe model (`fast`) fails for the upstream reason above, so the extension stays on its interactive `/login` (browser OAuth) against an Anthropic account. Session state lives in the operator-wide `/home/loca/.claude/` and `/home/loca/.claude.json`, not in `data/user/`. Cody (optional, only if enabled): sign in via the Cody panel; requires an Enterprise subscription. `"extensions.autoUpdate": "off"` and `"update.mode": "manual"` are the deployed values in `data/user/User/settings.json` — code-server normalized the seeded `false` to the string `"off"` at first run, and `"off"` and `false` mean the same thing (auto-update disabled). Version drift only happens by updating `config/extensions.lock.json` and re-running the install script.