diff --git a/.env.example b/.env.example
index 970bb9f3cf..5cc3c964c2 100644
--- a/.env.example
+++ b/.env.example
@@ -1648,6 +1648,16 @@ APP_LOG_TO_FILE=true
# Used by: src/shared/constants/featureFlagDefinitions.ts, src/lib/arenaEloSync.ts
# ARENA_ELO_SYNC_ENABLED=true
+# How model ids are prefixed in GET /v1/models. "dual" (default) advertises BOTH the
+# short alias prefix and the canonical provider prefix for each model (cc/claude-sonnet-4-6
+# AND claude/claude-sonnet-4-6) so client configs that hardcoded either form keep working β
+# which roughly doubles the catalog. "alias" emits one id per model; "canonical" emits only
+# the full provider-id prefix (and drops providers whose alias is already canonical).
+# A client can override per request with GET /v1/models?prefix=alias instead.
+# Also configurable from Dashboard > Settings > Feature Flags.
+# Used by: src/shared/constants/featureFlagDefinitions.ts, src/app/api/v1/models/catalog.ts
+# MODELS_CATALOG_PREFIX_MODE=dual
+
# Sync interval in seconds. Default: 86400 (24 hours).
# ARENA_ELO_SYNC_INTERVAL=86400
diff --git a/AGENTS.md b/AGENTS.md
index 7c6255a318..1ac759c0bc 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -433,6 +433,7 @@ For any non-trivial change, read the matching deep-dive first:
| Provider catalog (auto-generated) | `docs/reference/PROVIDER_REFERENCE.md` |
| Tunnels | `docs/ops/TUNNELS_GUIDE.md` |
| Electron desktop app | `docs/guides/ELECTRON_GUIDE.md` |
+| VS Code Copilot Chat (OmniCopilot extension) | `docs/guides/VSCODE-COPILOT.md` |
| Release flow | `docs/ops/RELEASE_CHECKLIST.md` |
| Embedded services | `docs/frameworks/EMBEDDED-SERVICES.md` |
| Quality gates (~80 scripts, allowlist policy) | `docs/architecture/QUALITY_GATES.md` |
diff --git a/README.md b/README.md
index a5ef67269e..607c411121 100644
--- a/README.md
+++ b/README.md
@@ -737,6 +737,8 @@ From inside the editor: open the **Extensions** view, search **"OmniRoute"**, cl
β works the same way on both stores. Source, issues and the publishing runbook live at
[diegosouzapw/OmniCopilot](https://github.com/diegosouzapw/OmniCopilot).
+π [VS Code Copilot Chat guide](docs/guides/VSCODE-COPILOT.md) β setup, what the picker shows, dashboard-in-a-tab, troubleshooting
+
diff --git a/docs/guides/CLI-INTEGRATIONS.md b/docs/guides/CLI-INTEGRATIONS.md
index 893476668e..a0eed99510 100644
--- a/docs/guides/CLI-INTEGRATIONS.md
+++ b/docs/guides/CLI-INTEGRATIONS.md
@@ -24,6 +24,8 @@ per-tool deep dives:
- [Claude Code configuration](./CLAUDE-CODE-CONFIGURATION.md)
- [Codex CLI configuration](./CODEX-CLI-CONFIGURATION.md)
- [Remote Mode](./REMOTE-MODE.md) β drive a remote OmniRoute (VPS / Tailnet) from your laptop
+- [VS Code Copilot Chat](./VSCODE-COPILOT.md) β the OmniCopilot extension; it can also run these
+ `setup-*` commands for you from inside the editor
---
diff --git a/docs/guides/VSCODE-COPILOT.md b/docs/guides/VSCODE-COPILOT.md
new file mode 100644
index 0000000000..ccdbcadcb0
--- /dev/null
+++ b/docs/guides/VSCODE-COPILOT.md
@@ -0,0 +1,138 @@
+---
+title: "VS Code Copilot Chat β OmniCopilot extension"
+version: 3.8.50
+lastUpdated: 2026-08-18
+---
+
+# VS Code Copilot Chat β OmniCopilot extension
+
+**OmniCopilot** puts every model your OmniRoute serves into the *native* GitHub Copilot Chat
+model picker. No second sidebar, no separate chat UI β Copilot's agent mode, tool calling,
+MCP servers and custom instructions all keep working, just running on the model you pick.
+
+| | |
+| --- | --- |
+| **Install (VS Code)** | [Marketplace β `diegosouzapw.omnicopilot`](https://marketplace.visualstudio.com/items?itemName=diegosouzapw.omnicopilot) |
+| **Install (forks)** | [Open VSX](https://open-vsx.org/extension/diegosouzapw/omnicopilot) β Cursor, Windsurf, VSCodium, Theia, code-server, Gitpod, Antigravity, Kiro |
+| **Source / issues** | [github.com/diegosouzapw/OmniCopilot](https://github.com/diegosouzapw/OmniCopilot) (MIT) |
+| **Requires** | VS Code 1.104+ |
+
+> **No Copilot subscription needed.** Since VS Code 1.122 a language-model provider works
+> without a GitHub sign-in and without any Copilot plan. Inline completions and
+> embeddings-based features stay outside the provider API and still require Copilot.
+
+---
+
+## Setup
+
+1. **Run OmniRoute** β `npm install -g omniroute && omniroute` (dashboard on `http://localhost:20128`).
+2. **Install the extension** β search "OmniRoute" in the Extensions view.
+3. **Pick a model** β Copilot Chat β model picker β **Manage Modelsβ¦** β **OmniRoute**, then tick
+ what you want.
+
+Nothing to configure when OmniRoute runs on the default port. For a remote instance, open the
+**OmniRoute icon in the Activity Bar** (or run `OmniRoute: Manage Connection`) and set:
+
+- **Server URL** β the server root, e.g. `http://192.168.0.15:20128`. The `/v1` suffix is
+ appended by the extension; do not include it.
+- **API key** β only when the server sets `REQUIRE_API_KEY`. Stored in the OS keychain via VS
+ Code SecretStorage, never in `settings.json`.
+
+---
+
+## What the picker will show
+
+The extension does not show the raw `GET /v1/models` payload β it shapes it, and the count you
+see is lower than the catalog size for two deliberate reasons.
+
+### It asks for one id per model
+
+`MODELS_CATALOG_PREFIX_MODE` defaults to **`dual`**, which advertises every model twice β once
+under the short alias prefix and once under the canonical provider prefix β so older client
+configs keep resolving either form:
+
+```
+cc/claude-sonnet-4-6 β alias prefix
+claude/claude-sonnet-4-6 β canonical prefix, same model
+```
+
+The extension requests **`GET /v1/models?prefix=alias`** so one id arrives per model, without
+changing the server-wide setting for your other clients. On a reference instance this collapsed
+**2345 entries to 1396 β 949 duplicates, zero models lost.**
+
+If you would rather fix it server-wide for *every* client, set the
+`MODELS_CATALOG_PREFIX_MODE` feature flag to `alias` in the dashboard. See
+[API_REFERENCE β prefix](../reference/API_REFERENCE.md#model-id-prefixes-prefix) for the
+query parameter and the warning about `canonical`.
+
+### It hides models that cannot chat
+
+The catalog also lists image, video, audio, rerank, embedding and moderation models. Those are
+rejected on a chat request anyway:
+
+```
+HTTP 400 β Model '' is an image-generation model and cannot be used on
+/v1/chat/completions. Use POST /v1/images/generations instead.
+```
+
+so they are filtered out by their `type` field before reaching the picker. **Responses-API
+models are kept** β every Codex / GPT-5.x entry advertises `supported_endpoints: ["responses"]`,
+and OmniRoute translates those for `/v1/chat/completions`, so they are perfectly usable.
+
+### Providers you never configured
+
+The catalog lists models from providers with an **active connection** *plus* every **noAuth**
+provider β the keyless ones that make up much of the free tier. That is intentional. To hide
+them, add them to `blockedProviders` in the dashboard settings; nothing changes in the
+extension.
+
+---
+
+## Dashboard inside a VS Code tab
+
+`omnicopilot.dashboardOpen: "editor"` renders the OmniRoute dashboard in an editor tab via the
+Simple Browser instead of an external browser. Embedding is **opt-in on the server**: start
+OmniRoute with
+
+```bash
+DASHBOARD_ALLOW_EMBED=vscode omniroute
+```
+
+which serves the HTML pages with `frame-ancestors 'self' vscode-webview:` instead of the default
+`frame-ancestors 'none'` + `X-Frame-Options: DENY`. The API surface (`/api`, `/v1`, `/v1beta`,
+`/a2a`, `/healthz`) keeps the strict headers either way. Without the variable the page refuses to
+frame and the extension falls back to the external browser β nothing breaks. See
+[`ENVIRONMENT.md`](../reference/ENVIRONMENT.md) and issue
+[#10273](https://github.com/diegosouzapw/OmniRoute/issues/10273).
+
+---
+
+## Configuring your other tools from inside VS Code
+
+**`OmniRoute: Configure Coding CLI`** drives the `omniroute` CLI to write ready-to-use profiles
+for Codex CLI, Claude Code, Cline, Continue, Cursor, Aider, OpenCode, Goose, Crush, Qwen Code,
+Kilo and Roo β the same configs described in
+[`CLI-INTEGRATIONS.md`](CLI-INTEGRATIONS.md). The API key is handed to the CLI through the
+`OMNIROUTE_API_KEY` environment variable, never on the command line.
+
+---
+
+## Troubleshooting
+
+| Symptom | Cause / fix |
+| --- | --- |
+| No OmniRoute models in the picker | Server unreachable. The status-bar dot goes grey; run `OmniRoute: Check Connection`. Discovery is silent by design and contributes no models rather than prompting. |
+| Every model appears twice | You are on an OmniCopilot older than 1.0.1 β update. The extension now requests `?prefix=alias`. |
+| An image/audio model used to be listed and is gone | Intentional since 1.0.1 β it could never answer a chat request. |
+| Panel missing from the Activity Bar | VS Code moves extra view containers into the **"β¦"** overflow at the bottom of the Activity Bar, and a container hidden via right-click stays hidden. Right-click the Activity Bar β tick **OmniRoute**, or open it with `OmniRoute: Manage Connection`. |
+| Dashboard opens in the browser despite `editor` mode | The server is not started with `DASHBOARD_ALLOW_EMBED=vscode` (see above). The fallback is deliberate. |
+| Models list is stale after changing providers | `OmniRoute: Refresh Models`, or the β» link in the panel. |
+
+---
+
+## See also
+
+- [`CLI-INTEGRATIONS.md`](CLI-INTEGRATIONS.md) β every other coding tool
+- [`REMOTE-MODE.md`](REMOTE-MODE.md) β driving a remote OmniRoute
+- [`../reference/API_REFERENCE.md`](../reference/API_REFERENCE.md) β the `/v1/models` contract
+- [`docs/CATALOG.md`](https://github.com/diegosouzapw/OmniCopilot/blob/main/docs/CATALOG.md) β the extension's own catalog notes
diff --git a/docs/guides/meta.json b/docs/guides/meta.json
index 7f9506b4cf..d7a3a94fdb 100644
--- a/docs/guides/meta.json
+++ b/docs/guides/meta.json
@@ -16,6 +16,7 @@
"CLAUDE-CODE-CONFIGURATION",
"CODEX-CLI-CONFIGURATION",
"CLI-INTEGRATIONS",
+ "VSCODE-COPILOT",
"MANAGEMENT-AUTH",
"REMOTE-MODE",
"PWA_GUIDE",
diff --git a/docs/reference/API_REFERENCE.md b/docs/reference/API_REFERENCE.md
index 2d843f8ba9..c7b9b4cc87 100644
--- a/docs/reference/API_REFERENCE.md
+++ b/docs/reference/API_REFERENCE.md
@@ -270,6 +270,31 @@ Authorization: Bearer your-api-key
β Returns all chat, embedding, and image models + combos in OpenAI format
```
+### Model id prefixes (`?prefix=`)
+
+Most models are advertised under a **provider prefix**. Which prefix you get is controlled by
+the `MODELS_CATALOG_PREFIX_MODE` feature flag, and can be overridden **per request** with a
+query parameter β useful for a client that wants a clean list without changing the server-wide
+setting for everyone else:
+
+```bash
+GET /v1/models?prefix=alias # one id per model β the short alias prefix
+GET /v1/models?prefix=dual # both forms (server default)
+GET /v1/models?prefix=canonical # only the full provider-id prefix
+```
+
+| Mode | Emits | Notes |
+| --- | --- | --- |
+| `dual` | `cc/claude-sonnet-4-6` **and** `claude/claude-sonnet-4-6` | **Default.** Both ids route to the same model; kept so client configs that hardcoded either form keep working. Roughly doubles the catalog. |
+| `alias` | `cc/claude-sonnet-4-6` | One entry per model. Providers without a distinct alias still emit their entry, so nothing is lost. |
+| `canonical` | `claude/claude-sonnet-4-6` | β οΈ The canonical row is only emitted when the canonical provider id **differs** from the alias, so providers without a distinct alias emit nothing in this mode. Prefer `alias` for a de-duplicated list. |
+
+A `dual`-mode mirror can also be recognised without the query parameter: it carries a `parent`
+field pointing at the primary id.
+
+Clients that render a model picker should request `?prefix=alias` β this is what the
+[OmniCopilot VS Code extension](../guides/VSCODE-COPILOT.md) does.
+
### No-thinking model variants
For thinking-capable Claude models, `/v1/models` also advertises a **no-thinking** variant whose id is prefixed with `claude-3-omniroute-no-thinking/`:
diff --git a/docs/reference/ENVIRONMENT.md b/docs/reference/ENVIRONMENT.md
index a47db4ed0c..5c6cb65e08 100644
--- a/docs/reference/ENVIRONMENT.md
+++ b/docs/reference/ENVIRONMENT.md
@@ -881,6 +881,7 @@ Automatic model pricing data synchronization from external sources.
| Variable | Default | Source File | Description |
| ------------------------- | ------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `ARENA_ELO_SYNC_ENABLED` | `true` | `src/shared/constants/featureFlagDefinitions.ts` | Periodic Arena AI leaderboard ELO sync, configurable from Dashboard Feature Flags or with `false` to opt out. |
+| `MODELS_CATALOG_PREFIX_MODE` | `dual` | `src/shared/constants/featureFlagDefinitions.ts`, `src/app/api/v1/models/catalog.ts` | Prefix form used for model ids in `GET /v1/models`. `dual` advertises both the short alias prefix and the canonical provider prefix for every model (backward compatibility β roughly doubles the catalog); `alias` emits one id per model; `canonical` emits only the full provider-id prefix and omits providers whose alias already is the canonical id. Clients can override per request with `?prefix=alias`. See [API_REFERENCE](API_REFERENCE.md#model-id-prefixes-prefix). |
| `ARENA_ELO_SYNC_INTERVAL` | `86400` (24h) | `src/lib/arenaEloSync.ts` | Sync interval in seconds. |
---
diff --git a/scripts/check/check-fabricated-docs.mjs b/scripts/check/check-fabricated-docs.mjs
index aba493b7d4..0a1d043032 100644
--- a/scripts/check/check-fabricated-docs.mjs
+++ b/scripts/check/check-fabricated-docs.mjs
@@ -114,6 +114,12 @@ const ENV_VAR_ALLOWLIST = new Set([
"LINUX_GPG_KEY", // electron AppImage signing key, CI/build only (ELECTRON_GUIDE.md)
"BRANCH_LOCK_TOKEN", // release branch-protection ops token (QUALITY_GATE_PLAYBOOK.md)
"NEXT_LOCALE", // next-intl locale cookie name (I18N.md)
+ // Feature flags are resolved by key at runtime β `resolveFeatureFlag()` reads
+ // `process.env[key]` (src/shared/utils/featureFlags.ts), never a literal
+ // `process.env.MODELS_CATALOG_PREFIX_MODE`, so this scan cannot see the read.
+ // The flag is real: defined in featureFlagDefinitions.ts, overridable from the
+ // dashboard or the environment. (API_REFERENCE.md, VSCODE-COPILOT.md)
+ "MODELS_CATALOG_PREFIX_MODE",
// Telegram Mini App integration (proposal TELEGRAM-MINIAPP.md, not yet implemented): env vars named in the feasibility analysis but no code reads them yet.
"TELEGRAM_WEBHOOK_URL", // proposal-only: Telegram webhook public endpoint (TELEGRAM-MINIAPP.md, future feature)
"TELEGRAM_WEBHOOK_SECRET", // proposal-only: Telegram webhook HMAC secret (TELEGRAM-MINIAPP.md, future feature)