Copilot App Link
Your applications. Your workflows. Your authorized Copilot access.
Connect local applications to GitHub Copilot in VS Code through an OpenAI-style chat API.
Build the interface and workflow that fit your work, using the models available through
your authorized Copilot access—without creating a separate GitHub personal access token.
By RIAI Solutions LLC · Local application access · Explicit client approval · Session metrics
Version 1.0.5: free under the included distribution terms. Install the stable release from the VS Code Marketplace.
macOS Apple Silicon has received local testing; Windows installation and listener startup are user-confirmed.
Windows functional/security testing, Linux and managed-policy acceptance remain unconfirmed. Validate your intended environment before organizational rollout.

Quick links: Setup · API examples · Metrics · Commands · Settings · Support
📚 Documentation included
Run Copilot App Link: Open Documentation to browse overview, setup, metrics,
company policy, support, privacy, release notes and license pages inside VS Code.
All pages are included in the package and can be read without a website.
💡 Build the experience your team needs
Copilot App Link provides the connection. Your application provides the experience.
| Build your own |
Connect it to |
| Custom chat workspace |
A conversational interface with your preferred layout and workflows |
| Development assistant |
Questions about code, troubleshooting and change summaries from context you supply |
| Reporting companion |
Draft daily updates and technical reports from selected information |
| Internal workflow tool |
Text assistance inside a locally running application |
Conversation history, document retrieval, tools and automation belong to your application.
They are not built-in extension features. Review generated output before using or sharing it.
🔗 A local connection you control
- Approve each application. Issue a separate credential with explicit model permissions.
- Start when you need it. Access stays stopped until you enable it in VS Code.
- Use JSON or streaming responses. Choose a complete response or incremental text events.
- See what is happening. Inspect request outcomes and latency without collecting conversation content.
- Stop or revoke access. Disconnect applications or remove an individual client grant.
Your local application
↕ Authenticated loopback API
Copilot App Link in VS Code
↕ VS Code Language Model API
Your authorized GitHub Copilot provider
The application connection is local. Model inference may occur remotely through the provider.
🚀 Get started
Install
Search for riai360.copilot-app-link in VS Code Extensions and select Install.
If you previously selected pre-release updates, use Switch to Release Version in the extension menu.
Illustrated setup walkthrough

Command Palette → Approve Client → Reload → Review Clients → Start → Configure → Test.
The illustrated walkthrough uses placeholder credentials; follow the written instructions below.
Approve and connect
You need a trusted local desktop VS Code workspace, working GitHub Copilot access,
and permission from your organization to use this connection. Model availability and
provider terms still apply. No separate publisher account is required.
Stopped is the expected initial status. Installation and window reload do not enable access.
Open the Command Palette with ⌘⇧P on macOS or Ctrl+Shift+P on Windows/Linux.
Reopen it for each command below.
- Approve your application. Run Copilot App Link: Approve Client, enter an
application name, and select the models it may use.
- Copy its credential. Select Copy credential and store it securely for your
application. It cannot be recovered later. Other applications may read your clipboard.
- Reload VS Code. Run Developer: Reload Window. Credential changes stop access
and require this reload before starting again.
- Enable the connection. Run Copilot App Link: Start, review and accept the packaged terms if you agree, then select Enable.
- Check the status. The status bar should show Running. Run
Copilot App Link: Show Bridge Status to see the endpoint—normally
127.0.0.1:9090.
- Connect your application. Supply its bearer credential and an exact approved model
ID. Run Copilot App Link: Setup Guide for the bundled instructions and local example.
Running confirms the listener has started; it does not confirm a successful provider request.
After later window reloads, run Start again. Unexpired client approvals are retained.
New credentials default to 3 days. In User Settings, set Copilot App Link: Credential Days (copilotAppLink.credentialDays) to an integer from 1–30. Company policy caps the lifetime; workspace overrides are ignored. Changes apply only to new approvals, without extending or shortening existing grants. Approval shows the effective lifetime and estimated local expiry; the dashboard flags less than 24 hours remaining. List Clients shows expiry and model permissions.
Rotate a client credential
Replace a credential while keeping the client's ID, name and model permissions:
- Run Copilot App Link: Rotate Client Credential, or select Rotate credential in the dashboard.
- Select the client by name and full ID, review the effective lifetime and confirm. Cancel changes nothing.
- Copy the replacement once and update your application's secret storage.
- Run Developer: Reload Window, then Copilot App Link: Start.
Rotation stops access and immediately invalidates the old token; there is no grace period.
The replacement uses the current credential lifetime (default 3 days), capped by company policy.
Expired clients may be rotated; revoked clients cannot be restored. If model grants no longer
meet policy, revoke and approve a replacement with permitted models.
If copying is dismissed or fails, choose revocation or keep the client and rotate again after
reload. For storage errors and recovery instructions, run Setup Guide → Rotate a client credential.
🔌 Connect to the API
Default base URL: http://127.0.0.1:9090. Use your configured port if different.
- Health check:
GET /health requires no bearer token. It returns {"status":"up"} when the local listener is running.
- All other API routes: require the approved client credential in the
Authorization: Bearer <credential> header.
Health confirms listener liveness only; it does not confirm Copilot availability or client access.
| Endpoint |
Purpose |
POST /v1/chat/completions |
Text chat with JSON or server-sent event responses |
GET /v1/models |
Exact model IDs permitted for the authenticated client |
GET /v1/capabilities |
Implemented request features and limits |
GET /health |
Token-free local listener liveness only (status: up) |
Example request body—replace the model placeholder with an approved ID:
{
"model": "<approved-model-id>",
"messages": [
{ "role": "user", "content": "Draft a short status update for a sample project." }
],
"stream": false
}
Supported today: text user and assistant messages, explicit model selection,
JSON responses and streaming responses. /models is also available as an alias.
Not supported: system messages, tool calls, images, embeddings, sampling options,
direct browser connections or remote/shared access. Unsupported request fields are
rejected. This is a defined OpenAI-style subset, not full OpenAI API compatibility.
For application examples and streaming/error handling, run Open Documentation → Application integration.
A custom browser UI needs a local backend that holds the credential; do not put it in browser code.
Supported connections at a glance
| Capability |
Support |
| Local desktop VS Code with authorized Copilot access |
✅ Required environment; see platform validation status above |
| Local native applications and backends |
✅ Authenticated loopback API |
Text user and assistant messages |
✅ Supported |
| Complete JSON or streaming SSE responses |
✅ Supported |
| Direct browser requests or remote/shared access |
❌ Not supported |
system, developer, tool, function roles and tool calling |
❌ Not supported |
| Images, embeddings, token usage, billing or Copilot quota reporting |
❌ Not supported |
Message roles and compatibility
Current release supports text messages with user and assistant roles only. The table covers common OpenAI-style chat roles, including the legacy function role; it is not a claim of full OpenAI API compatibility.
| Role |
Purpose in chat APIs |
Supported here |
Current behavior |
user |
The user's question, request or supplied context |
✅ Supported |
Text content accepted; at least one user message is required per request. |
assistant |
Previous model replies included as conversation history |
✅ Supported — text only |
Text content accepted; assistant tool-call fields are not supported. |
system |
Application-level instructions or behavior constraints |
❌ Not supported |
Rejected; not silently converted into user text. |
developer |
Application/developer instructions in APIs that expose this role |
❌ Not supported |
Rejected; no equivalent privileged-role mapping in the current integration. |
tool |
A result returned for a model-requested tool call |
❌ Not supported |
Rejected; tool definitions, calls, IDs and results are not implemented. |
function (legacy) |
A function result in older function-calling conversations |
❌ Not supported |
Rejected; legacy function-calling fields are not implemented. |
Unsupported roles return HTTP 400 (unsupported_message). Unsupported request fields such as tools return HTTP 400 (unsupported_parameter). Only role and text content are accepted inside each message; extra message fields are rejected. Your application must supply history with each request; the extension does not retain conversations.
Provider API versus extension scope: the VS Code language-model interface used here exposes user/assistant roles, without equivalent system/developer priority. VS Code also provides structured tool-call and tool-result APIs, but this extension has not implemented their OpenAI-style translation. Tool support is a potential enhancement, not a current capability or a guarantee for every Copilot model. See the VS Code Language Model API reference.
Check authenticated GET /v1/capabilities for the installed build's actual contract: currently roles: ["user", "assistant"], system_role: false, and tools: false. Future plans do not change the installed API behavior.
Copy-and-paste API examples (Bruno)
Create a Bruno environment variable baseUrl with value http://127.0.0.1:9090 (use your configured port). For protected requests, select Auth → Bearer Token and use your approved client credential as a private/local secret; do not commit it. Set modelId to an exact ID returned by /v1/models. Chat requests use Body → JSON and Content-Type: application/json. Do not add an Origin header.
The responses below are illustrative examples, not captured customer traffic. Model IDs, completion IDs, timestamps, text and chunk boundaries vary. Replace placeholder values before sending.
Health — no authentication
GET {{baseUrl}}/health
Set Auth to No Auth for this request. Expected: 200.
{"status":"up"}
This confirms listener liveness only, not model availability.
Models — bearer authentication
GET {{baseUrl}}/v1/models
Expected: 200. Only available models permitted for this client are returned; the list may be empty.
{
"object": "list",
"data": [
{"id": "<approved-model-id>", "object": "model", "created": 0, "owned_by": "copilot"}
]
}
Capabilities — bearer authentication
GET {{baseUrl}}/v1/capabilities
Expected: 200. Representative response excerpt (the full response also includes limits and other fields):
{
"api_version": "1",
"provider": "copilot",
"chat": {
"json": true,
"sse": true,
"roles": ["user", "assistant"],
"tools": false,
"system_role": false
},
"scope": "local-desktop",
"direct_browser_access": false
}
Chat — JSON response
POST {{baseUrl}}/v1/chat/completions
Content-Type: application/json
Use bearer authentication and paste this JSON body:
{
"model": "{{modelId}}",
"messages": [
{"role": "user", "content": "This is a synthetic connectivity test. Reply with: Connection successful."}
],
"stream": false
}
Expected: 200. Representative response:
{
"id": "chatcmpl-<generated-uuid>",
"created": 1789600000,
"model": "<approved-model-id>",
"object": "chat.completion",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "Connection successful."},
"finish_reason": "stop"
}
]
}
Read choices[0].message.content. No token usage or billing estimates are supplied.
Chat — streaming response
Use the same POST URL, bearer authentication and JSON header:
{
"model": "{{modelId}}",
"messages": [
{"role": "user", "content": "Reply with: Connection successful."}
],
"stream": true
}
Expected: 200, Content-Type: text/event-stream. Representative raw SSE response:
data: {"id":"chatcmpl-example","created":1789600000,"model":"<approved-model-id>","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-example","created":1789600000,"model":"<approved-model-id>","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Connection successful."},"finish_reason":null}]}
data: {"id":"chatcmpl-example","created":1789600000,"model":"<approved-model-id>","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]
Bruno may display the raw stream. A response can contain many content events. An event: error or a stream ending without [DONE] is not a successful completion, even if HTTP initially returned 200.
Conversation history
Use the same chat URL and bearer authentication. Send previous messages with each request:
{
"model": "{{modelId}}",
"messages": [
{"role": "user", "content": "Our fictional project is called Atlas."},
{"role": "assistant", "content": "Understood. The project is called Atlas."},
{"role": "user", "content": "What is the project called?"}
],
"stream": false
}
The response has the same JSON envelope as above, with text such as The project is called Atlas. Only user and assistant roles are currently supported, and at least one user message is required. History is supplied by your application, not retained by the extension. System/developer/tool roles and tool-calling fields are not currently supported.
Expected rejection examples
Disable authentication on a protected request: expected 401, for example:
{"error":{"code":"unauthorized","message":"Valid client credentials are required."}}
Use an unapproved model ID in an otherwise valid chat request: expected 403:
{"error":{"code":"model_not_allowed","message":"model_not_allowed"}}
Use a system message in the chat body: expected 400:
{"error":{"code":"unsupported_message","message":"unsupported_message"}}
After successful chats, open Copilot App Link: Show Metrics to confirm outcomes. Stop All Access closes the listener, including health; connection failure is then expected rather than an HTTP response. Revocation testing should use a disposable client because the old credential cannot be restored.
📊 See local activity at a glance
Run Copilot App Link: Show Metrics to explore:
- Approved models: all locally granted model IDs, client grants and policy/expiry status, even before requests.
- Request outcomes: completed, failed, cancelled, timed out and active requests.
- Response performance: latency histograms, median/p95 and first streamed content.
- Model and application activity: outcome breakdowns and per-model timing.
- Minute trends: request activity and mean response timing, with Live, Pause and Refresh.
- Connection controls: inspect status, Start, Stop All Access and manage client access.

Search the client table by name, full ID or model; filter by grant status or upcoming expiry. Filters affect the table only; Copy client details still copies all clients.
Run Check Connection from the palette or dashboard to inspect local listener state, a selected client grant and Copilot model discovery. This sends no chat prompt and does not start access. It cannot verify the bearer token stored in your external application or prove a chat request will succeed.
The client section summarizes expired credentials and those expiring in less than 24 hours.
Use Rotate credential to select a client and replace its credential.
Copy Connection Configuration uses the running port, or the configured port with a Stopped label.
Replace <YOUR_CLIENT_CREDENTIAL> securely in your application; the copy contains no stored token.
Metrics stay in session memory and contain no prompts, responses or credentials.
Timing charts use bounded samples and identify small sample sizes. Token usage,
billing and Copilot quota are not reported. Clear Metrics resets the collection
window; it does not stop access. Reload clears metrics too.
Run Open Documentation → Metrics guide for measurement definitions, sample windows
and privacy details. Preview Diagnostics lets you review aggregate counts and timings
before optionally saving a copy; nothing is automatically uploaded.
🏢 Company policy controls
Administrators can restrict models, credential lifetimes and resource limits, and
control diagnostics and optional minute activity. Invalid required policy blocks access.
Detected changes stop the listener and require explicit Start.
Run Open Documentation → Company policy for provisioning instructions and platform
limitations. Windows/Linux and managed-policy acceptance remain unconfirmed; validate your intended environment.
🔒 Privacy and access boundaries
- No publisher content destination. The extension does not send prompts, responses or client credentials to
RIAI360 or RIAI Solutions LLC.
- Your provider path. Requests use authorized Copilot access through VS Code. Provider
processing and retention remain subject to the applicable provider terms and settings.
- Your application's data practices. Connected applications may retain or share content
under their own policies. Choose context deliberately and follow your organization's rules.
- Loopback only. The listener binds to
127.0.0.1 and rejects direct browser origins.
Do not expose it as a public or shared service.
- Explicit control. Use Stop All Access to disconnect clients or Revoke Client
to remove a grant. Cancellation cannot recall content already submitted to the provider.
⌨️ Commands at a glance
Open the Command Palette with Ctrl+Shift+P (Windows/Linux) or ⌘⇧P (macOS),
then type Copilot App Link. The names below match the extension's commands.
Setup and help
| Command |
When to use it |
What to expect |
| Setup Guide |
Connect your first application |
Opens the bundled setup walkthrough |
| Open Documentation |
Find examples, policies or troubleshooting |
Opens the offline guide chooser |
| Approve Client |
Connect a new application |
Creates its credential and model permissions; copy, reload and Start |
Daily use
| Command |
When to use it |
What to expect |
| Start |
Enable the local connection |
Reviews terms when required and asks for confirmation |
| Stop All Access |
Disconnect applications |
Stops the listener; client grants remain stored |
| Show Bridge Status |
Check the listener and endpoint |
Running does not establish provider readiness |
| Copy Connection Configuration |
Configure an approved application |
Select a client/model; copies base URL, model and credential placeholder |
| Check Connection |
Inspect a connection without generating a response |
Reports listener, local client grant and model discovery separately; no prompt sent |
| Show Metrics |
Inspect session activity and client/model grants |
Opens the dashboard |
Client management
| Command |
When to use it |
What to expect |
| List Clients |
Inspect existing approvals |
Opens the dashboard with IDs, expiry and model grants; no credentials |
| Rotate Client Credential |
Replace a token while keeping client identity |
Old token becomes invalid; update the app, reload and Start |
| Revoke Client |
Remove an application's access |
Invalidates that client's credential |
Troubleshooting and reset
| Command |
When to use it |
What to expect |
| Restart Bridge Server |
Restart the listener |
Stops first, then runs the normal Start checks and confirmation |
| Reset Consent |
Review the terms and access consent again |
Stops access and clears the stored consent receipt |
| Clear Metrics |
Begin a fresh collection window |
Resets metrics and diagnostics preview; does not stop access or revoke clients |
| Preview Diagnostics |
Inspect aggregate counts and timings |
Asks for confirmation; nothing is automatically saved or uploaded |
Dashboard shortcuts
These dashboard controls include shortcuts to palette commands and dashboard-only actions:
| Control |
Purpose |
| Copy connection configuration |
Launch the same configuration-copy flow as the palette command |
| Credential settings |
Open the credential lifetime setting |
| Copy client details |
Copy displayed client IDs, names, permissions, expiry and endpoint as JSON; no tokens or digests |
| Rotate credential |
Launch the same credential rotation flow as the palette command |
| Live / Pause / Refresh |
Update automatically, freeze the view or request a fresh snapshot |
The copied endpoint is null when stopped. Review client metadata before sharing it.
Settings
Open VS Code User Settings and search for Copilot App Link.
| Setting |
Default |
Meaning |
Port (copilotAppLink.port) |
9090 |
Local listener port, from 1024 to 65535; update your application if changed |
Credential Days (copilotAppLink.credentialDays) |
3 |
Integer from 1–30 for new approvals and rotations; company policy may shorten it |
Diagnostics Preview Enabled (copilotAppLink.diagnosticsPreviewEnabled) |
true |
Allow manual aggregate diagnostics preview; company policy may disable it |
Changing Port stops the listener; explicitly Start again after reviewing the change.
Changing Credential Days or Diagnostics Preview Enabled does not interrupt requests.
Changing the diagnostics preference clears any existing diagnostics preview. Changing the lifetime does not rewrite existing credential expirations.
Workspace values do not override the User credential lifetime setting.
Requests must specify an exact approved model ID; the legacy Default Model setting does not select it.
🛠️ Troubleshooting
| What you see |
What to do |
| Stopped after installation or reload |
Run Start, then select Enable |
| Credential change / access blocked |
Run Developer: Reload Window, then Start |
| No models during approval |
Check Copilot sign-in, entitlement and organization policy |
| Start fails |
Check workspace trust, use a local window, and confirm the configured port is free |
| 401 response |
Check for a missing, expired or revoked credential |
| 403 response |
Check model permissions and use the approved local application connection |
| 429 response |
Wait for the active request to finish; requests are not queued |
| Credential lost or expired |
Rotate an existing non-revoked client, copy the replacement, update your app, reload and Start |
| Remove access or change model permissions |
Revoke the client; approve a replacement only if access is still needed |
| Rotation fails or client is missing |
Reload, inspect List Clients and follow Setup Guide recovery; approve a replacement if the grant is missing |
For more detail, run Copilot App Link: Setup Guide in the VS Code Command Palette. The guide is included with the extension and does not require a website account.
💬 Support and security
Run Open Documentation → Support and troubleshooting for recovery steps and safe
reporting guidance. Support is best-effort; share only sanitized diagnostics and synthetic
reproductions. Never include credentials or confidential conversation content.
Contact support@riai360.com for assistance and
security@riai360.com for private vulnerability reports.
Both mailboxes are active and monitored.
For organizational incidents, follow your own IT/security process.
ℹ️ About Copilot App Link
Copilot App Link is an independent product by RIAI Solutions LLC, with extension
identifier riai360.copilot-app-link. It is not affiliated with or endorsed
by GitHub or Microsoft. GitHub Copilot access is separate from this extension.
Read the release notes and license on Marketplace, or use Open Documentation inside VS Code. The license is presented for review before enabling access.
Copilot App Link — a RIAI360 extension by RIAI Solutions LLC.