@nospt/open-copilot-bridge
v0.1.1
Published
OpenCode plugin that bridges GitHub Copilot Enterprise features (org instructions, custom agents, path-specific instructions, MCP configs) into OpenCode
Readme
An OpenCode plugin that bridges GitHub Copilot Enterprise features into OpenCode -- bringing org instructions, custom agents, path-specific instructions, MCP server configs, prompt files, skills, and lifecycle hooks to the terminal.
Use your full Copilot Enterprise customization ecosystem without being tied to VS Code.
Features
- Instruction Injection -- Aggregates and injects organization, repository, and path-specific instructions into the system prompt. Path-specific instructions activate dynamically based on which files the LLM is working with.
- Feature Selection -- Browse and manage remote Copilot features (agents, prompts, skills, MCP servers) via interactive TUI commands. Select which features to enable and choose local (project-scoped) or global (user-scoped) installation. Selections persist across restarts.
- Agent Sync -- Fetches Copilot Enterprise custom agents from GitHub's API and maps them to OpenCode's agent format. Only syncs agents the user has explicitly selected. Safely manages plugin-owned vs. user-created files.
- MCP Server Configs -- Extracts Model Context Protocol server configurations from Copilot agent profiles and writes them to OpenCode's global config.
- Prompt Files -- Discovers
.prompt.mdfiles from local, global, and remote sources. Supports argument substitution and file reference resolution. - Skills -- Discovers
SKILL.mdfiles and exposes them via acopilot_skilltool. - Local Agents -- Discovers
.agent.mdfiles with per-agent hook registries and tool restrictions. - Lifecycle Hooks -- Supports
preToolUse,postToolUse,sessionStart,sessionEnd,userPromptSubmitted,agentStop, anderrorOccurredhooks with bash command execution. - Cloud Agent Delegation -- Delegate tasks to GitHub Copilot's cloud agent (
copilot-swe-agent[bot]) which runs autonomously in GitHub Actions. Create tasks via REST API, or list/view tasks viaghCLI. The/copilot-cloud-taskTUI command can generate detailed task descriptions from your current conversation context using a temporary hidden session. - Code Review -- A
copilot_reviewtool that performs code review using your org/repo instructions. - Hot-Reload -- File watcher integration that re-discovers resources when source files change on disk.
- Toast Notifications -- Shows brief visual feedback in the TUI when bridge tools are used or path-specific instructions activate. Individually suppressible via
toast.deny. - Graceful Degradation -- Works without GitHub authentication. Remote features are disabled but all local features remain active.
Installation
The recommended way to install is via the OpenCode plugin command, which automatically registers both the server and TUI plugins in a single step:
opencode plugin @nospt/open-copilot-bridgePackage: @nospt/open-copilot-bridge on npm
This detects the plugin's ./server and ./tui exports and patches both opencode.json and tui.json for you.
If your current repo belongs to a GitHub organization, the plugin auto-detects the org from the git remote — no extra configuration needed. Set org manually only if auto-detection doesn't apply (no GitHub auth, personal account repo, or cross-org usage):
{
"plugin": [
["@nospt/open-copilot-bridge", { "org": "my-org" }]
]
}Manual installation
If you prefer to configure manually:
Server plugin -- add to opencode.json:
{
"plugin": ["@nospt/open-copilot-bridge"]
}TUI plugin (optional) -- add to .opencode/tui.json or ~/.config/opencode/tui.json:
{
"$schema": "https://opencode.ai/tui.json",
"plugin": ["@nospt/open-copilot-bridge"]
}Why a separate file? OpenCode uses two separate config files for two separate processes.
opencode.jsonis read by the server process only.tui.jsonis read by the TUI process only. If you register the plugin only inopencode.json, the TUI process never sees it and the slash commands will silently not appear -- no error is shown. You must add the plugin totui.jsonto get the TUI commands.
The server plugin enables all core features: agent sync, instruction injection, MCP configs, prompt files, skills, hooks, and tools. The TUI plugin adds interactive slash commands (see TUI Commands).
Configuration
Configure the plugin via inline options in opencode.json:
{
"plugin": [
[
"@nospt/open-copilot-bridge",
{
"org": "my-org",
"sync": {
"on-startup": true,
"cache-ttl": 3600
}
}
]
]
}The plugin reads configuration from both global and local opencode.json files, merging them with the following precedence (later wins):
- Built-in defaults
- Global
~/.config/opencode/opencode.jsonplugin options - Local
<project>/opencode.jsonplugin options
This allows you to set organization-wide defaults in the global config and override per-project as needed.
### Options
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `org` | `string \| null` | Auto-detected from git remote (if owner is a GitHub org and auth is available) | GitHub organization login. Set manually if auto-detection fails (no auth, personal repo, or cross-org). |
| `enterprise` | `string \| null` | `null` | GitHub Enterprise slug |
| `github-private-repo` | `string` | `".github-private"` | Repo name containing org-level configs |
| `sync.agents` | `boolean` | `true` | Sync enterprise custom agents |
| `sync.instructions` | `boolean` | `true` | Sync org/repo/path-specific instructions |
| `sync.mcp` | `boolean` | `true` | Sync MCP server configs from agent profiles |
| `sync.prompts` | `boolean` | `true` | Sync prompt files |
| `sync.skills` | `boolean` | `true` | Sync skill files |
| `sync.hooks` | `boolean` | `true` | Sync hook configurations |
| `sync.on-startup` | `boolean` | `true` | Auto-sync when plugin loads |
| `sync.cache-ttl` | `number` | `3600` | Cache TTL in seconds for remote resources |
| `instructions.org-file` | `string` | `"org-instructions.md"` | Filename in `.github-private` for org instructions |
| `instructions.org-text` | `string \| null` | `null` | Inline org instructions text (fallback) |
| `disable` | `string[]` | `[]` | Features to disable (see [Disabling Features](#disabling-features)) |
| `toast.deny` | `string[]` | `[]` | Toast categories to suppress (see [Toast Notifications](#toast-notifications)) |
#### TUI Plugin Options
The TUI plugin accepts options in `tui.json` when using the tuple format:
```json
{
"$schema": "https://opencode.ai/tui.json",
"plugin": [
["@nospt/open-copilot-bridge", { "context-messages": 10 }]
]
}| Option | Type | Default | Description |
| --- | --- | --- | --- |
| context-messages | number | 5 | Number of recent messages to include as context when generating cloud agent task descriptions. Range: 1--50. |
Disabling Features
The disable array accepts any of the following keys. Everything is enabled by default.
Tools: review, sync, inspect, prompt, skill, agent, cloud-agent
Hooks: system-prompt, compaction, file-tracking, hot-reload, session-hooks, tool-hooks, chat-hooks, command-intercept
Subsystems: command-stubs
{
"plugin": [
["@nospt/open-copilot-bridge", { "disable": ["hot-reload", "command-stubs"] }]
]
}Toast Notifications
The plugin shows brief toast notifications in the TUI when:
- A bridge tool (
copilot_review,copilot_sync, etc.) is executed - A file tool touches a file that activates path-specific instructions
All toasts are shown by default. Suppress individual categories with toast.deny:
| Category | Trigger |
| --- | --- |
| tool-review | copilot_review tool used |
| tool-sync | copilot_sync tool used |
| tool-inspect | copilot_inspect tool used |
| tool-prompt | copilot_prompt tool used |
| tool-skill | copilot_skill tool used |
| tool-agent | copilot_agent tool used |
| tool-cloud-agent | copilot_cloud_agent tool used |
| instructions | Path-specific instructions activated for a file |
{
"plugin": [
["@nospt/open-copilot-bridge", { "toast": { "deny": ["instructions", "tool-inspect"] } }]
]
}Authentication
The plugin resolves a GitHub token using the same precedence as the Copilot CLI:
COPILOT_GITHUB_TOKENenvironment variablegh auth token(GitHub CLI)GH_TOKENenvironment variableGITHUB_TOKENenvironment variable
For GitHub Enterprise Server, set GH_HOST to your server hostname.
If no token is found, remote features (org instructions, enterprise agents, remote prompts/skills) are disabled. All local features continue to work.
Tools
The plugin registers the following tools in OpenCode:
| Tool | Description |
| --- | --- |
| copilot_sync | Manually trigger a sync of enterprise agents, instructions, and MCP configs. Pass force: true to bypass cache. |
| copilot_review | Review code changes using your org/repo Copilot instructions. Accepts a diff, optional files, and focus. |
| copilot_inspect | Show diagnostic report of all plugin subsystems: auth, config, agents, instructions, prompts, skills, hooks. |
| copilot_prompt | List or run Copilot prompt files. Supports argument substitution. |
| copilot_skill | Load a skill by name. Only registered when skills are discovered. |
| copilot_agent | Load a local agent by name. Only registered when local agents are discovered. |
| copilot_cloud_agent | Delegate tasks to GitHub Copilot's cloud agent. Supports create (via REST API), list, and view (via gh CLI) actions. |
TUI Commands
The TUI plugin provides interactive slash commands in the OpenCode terminal UI.
Commands not appearing? These commands require the TUI plugin to be registered in
tui.json(.opencode/tui.jsonfor project scope, or~/.config/opencode/tui.jsonglobally). Registering the plugin only inopencode.jsonis not enough -- that file is only read by the server process. See Manual installation.
| Command | Description |
| --- | --- |
| /copilot-dashboard | View a read-only overview of all active Copilot configs -- agents, prompts, skills, MCP servers, and hooks -- with their enabled status and scope |
| /copilot-agents | Browse and manage organization Copilot agents -- select which to enable, choose local or global scope |
| /copilot-prompts | Browse and manage remote prompt files -- select which to enable, choose local or global scope |
| /copilot-skills | Browse and manage remote skills -- select which to enable, choose local or global scope |
| /copilot-mcp | Browse and manage MCP server configs extracted from agent profiles |
| /copilot-cloud-task | Create a cloud agent task with optional context-aware description generation |
| /copilot-cloud-list | List recent cloud agent tasks and their status |
/copilot-dashboard
The /copilot-dashboard command opens a scrollable, read-only overview of every Copilot config the plugin has discovered for the current repo. Configs are grouped by type and each item shows its status:
| Icon | Meaning |
| --- | --- |
| [L] | Remote feature, enabled locally (project-scoped) |
| [G] | Remote feature, enabled globally (user-scoped) |
| [ ] | Remote feature, not enabled |
| [◉] | Local file in this repo (.github/) |
Press Esc or select any item to close.
Feature Selection Flow
The /copilot-agents, /copilot-prompts, /copilot-skills, and /copilot-mcp commands share a common UX flow:
- Browse available features -- View all remote features fetched from your organization
- Select a feature -- Pick one from the list to manage
- Choose scope -- Select where to install it:
- Local -- Project-scoped, written to
.opencode/<type>/in the current worktree - Global -- User-scoped, written to
~/.config/opencode/<type>/ - Disable -- Remove the feature if previously enabled
- Local -- Project-scoped, written to
- Immediate effect -- Files are synced and configs are updated immediately, no restart required
Selections persist in copilot-bridge-selections.json files:
- Global:
~/.config/opencode/copilot-bridge-selections.json - Local:
<project>/.opencode/copilot-bridge-selections.json(overrides global)
Note: Agents require explicit selection -- they are not synced until you select them. Prompts and skills load all available features by default if no selections have been made.
/copilot-cloud-task -- Context-Aware Task Generation
The /copilot-cloud-task command supports two modes for creating cloud agent tasks:
Write manually -- Type the full task description yourself and submit it directly.
Generate from conversation -- Provide a brief hint describing what you need, and the plugin generates a detailed, structured task description by analyzing your current conversation context. This is useful when you've been debugging an issue or discussing a feature and want to hand off the work to the cloud agent without rewriting all the context.
The generation flow:
- Choose method -- Select "Generate from conversation" or "Write manually"
- Describe what you need -- Type a brief hint (e.g., "Fix the timezone bug we just discussed")
- Review generated description -- The plugin reads the last N messages from your session, creates a temporary hidden session, and uses the LLM to produce a structured task with title, description, and acceptance criteria
- Edit or regenerate -- Review the generated text, edit it directly, or cancel to provide refinement feedback and regenerate
- Select base branch -- Choose which branch the cloud agent should work from
- Submit -- The task is created as a GitHub issue with the cloud agent assigned
The generation uses a temporary session that is automatically deleted after the response -- it does not pollute your current conversation.
If no messages exist in the current session, the command skips straight to manual entry.
Cloud Agent
The cloud agent feature lets you delegate tasks to GitHub Copilot's cloud agent (copilot-swe-agent[bot]), which runs autonomously in an ephemeral GitHub Actions environment. It can research code, write changes, run tests, commit, and open pull requests.
Creating Tasks
Tasks are created via the GitHub REST API by opening an issue with an agent_assignment payload. This works with any authenticated GitHub account that has access to a repository with the cloud agent enabled.
/copilot-cloud-taskOr via the server-side tool directly:
Use the copilot_cloud_agent tool to create a task: "Add input validation to the signup form"Listing and Viewing Tasks
The list and view actions use the gh agent-task CLI (requires gh v2.80.0+). If the gh CLI is not installed or too old, these actions gracefully degrade with an informative message.
/copilot-cloud-listRequirements
- Create: GitHub authentication (any method -- see Authentication)
- List/View:
ghCLI v2.80.0+ withagent-tasksubcommand (optional)
Resource Discovery
The plugin discovers resources from multiple tiers, in priority order:
- Remote --
.github-privaterepo via GitHub API (org instructions, enterprise agents, remote prompts/skills) - Local project --
.github/and.opencode/directories in the current repo - Global --
~/.config/opencode/and~/.copilot/directories - VS Code user data -- VS Code Copilot customization directories
Directory Structure
.github/
copilot-instructions.md # Repo-level instructions
instructions/*.instructions.md # Path-specific instructions (with applyTo frontmatter)
prompts/*.prompt.md # Prompt files (slash commands)
skills/<name>/SKILL.md # Skills
agents/*.agent.md # Local agents
hooks/*.json # Lifecycle hooks
.opencode/
agents/ # Plugin-synced agents (local scope)
prompts/ # Plugin-synced prompts (local scope)
skills/ # Plugin-synced skills (local scope)
copilot-bridge-selections.json # Feature selection persistence (local)
~/.config/opencode/
agents/ # Plugin-synced agents (global scope)
prompts/ # Plugin-synced prompts (global scope)
skills/ # Plugin-synced skills (global scope)
copilot-bridge-selections.json # Feature selection persistence (global)Path-Specific Instructions
Instructions with an applyTo glob pattern in their frontmatter activate dynamically based on which files the LLM is working with during the session:
---
applyTo: "**/*.ts"
---
Use strict TypeScript with explicit return types.Prompt Files
Prompt files support argument substitution and file references:
---
description: "Generate unit tests"
---
Write unit tests for the following code:
#file:src/utils.ts
Use {{framework}} as the test framework.Hooks
Define lifecycle hooks in .github/hooks/*.json. Each file uses a version: 1 schema with hook types as object keys:
{
"version": 1,
"hooks": {
"preToolUse": [
{
"bash": "cat - | jq -r '.toolName' >&2",
"timeoutSec": 5,
"comment": "Log tool names to stderr before execution"
}
],
"sessionStart": [
{
"bash": "./scripts/on-session-start.sh",
"timeoutSec": 10
}
]
}
}Supported hook types: preToolUse, postToolUse, sessionStart, sessionEnd, userPromptSubmitted, agentStop, errorOccurred.
Command fields
| Field | Type | Required | Description |
| --- | --- | --- | --- |
| bash | string | Yes | Shell command to run (also accepts command as an alias) |
| timeoutSec | number | No | Timeout in seconds (default: 30) |
| cwd | string | No | Working directory, relative to project root |
| env | object | No | Additional environment variables to inject |
| comment | string | No | Human-readable description of this hook |
Hook stdin/stdout protocol
Every hook script receives a JSON object on stdin:
{
"hookType": "preToolUse",
"sessionID": "abc123",
"toolName": "terminal",
"toolArgs": { "command": "rm -rf build/" }
}| Field | Present for |
| --- | --- |
| hookType | All hooks |
| sessionID | All hooks |
| toolName | preToolUse, postToolUse (Copilot name convention — e.g. terminal for bash, view for read, search for glob/grep) |
| toolArgs | preToolUse, postToolUse |
| toolOutput | postToolUse |
| userMessage | userPromptSubmitted |
| error | errorOccurred |
For preToolUse, write a JSON decision to stdout to control execution:
{"permissionDecision": "deny", "permissionDecisionReason": "Blocked by policy"}| permissionDecision | Effect |
| --- | --- |
| "deny" | Tool is blocked; reason is shown to the user |
| "ask" | Execution pauses for user confirmation; approval grants a one-shot bypass for the same tool+args |
| "allow" or no output | Tool proceeds normally |
Only preToolUse reads the stdout decision — other hook types ignore stdout. For preToolUse, execution stops at the first deny or ask result.
Execution order
When hooks exist in multiple sources, all of them run in this order per hook type:
- Remote hooks from
{org}/.github-private/hooks/(requiressync.hooks: trueand GitHub auth) - Project hooks from
.github/hooks/ - Global hooks from
~/.copilot/hooks/ - VS Code user data hooks (if VS Code Copilot is installed)
- Agent-scoped hooks (if an agent is active via
copilot_agent)
Authoring Local Agents
Place *.agent.md or *.md files in .github/agents/ to define local project agents. They are injected directly into OpenCode's agent system via a config hook — they appear in the native agent picker immediately, without any file being copied and without a restart.
Each file is a markdown document with a YAML frontmatter block at the top, followed by the agent's system prompt as the body.
Discovery paths
Agents are loaded from the following locations in priority order. The first occurrence of a name wins across all sources.
| Location | Scope |
| --- | --- |
| .github/agents/ | Project (local) |
| .opencode/agents/ | Project (local, secondary — user-placed or plugin-synced) |
| ~/.copilot/agents/ | Global user |
| ~/.config/opencode/agents/ | Global (OpenCode native and plugin-synced remote agents) |
Frontmatter reference
All fields are optional.
| Field | Type | Default | Description |
| --- | --- | --- | --- |
| description | string | "" | Short description shown in tool listings and the agent picker |
| tools | string[] | [] | Copilot tool names to allow. When non-empty and not ["*"], a deny-all policy is applied and only listed tools are permitted. See Tool permissions. |
| model | string | OpenCode default | Preferred model ID (informational — OpenCode makes the final choice) |
| user-invocable | boolean | true | When false, the agent is hidden from copilot_agent's user-facing list. It can still be loaded by name via another agent's handoffs. Use this for sub-agents that should never be called directly by the user. |
| target | string | — | Set to "github-copilot" to mark this as a cloud-only agent. It will be skipped entirely during local discovery and will not appear in OpenCode. Useful for .github/agents/ files that are shared with GitHub Copilot but are not meant for OpenCode. |
| handoffs | object[] | [] | Suggested next-step agents appended to copilot_agent output. See Handoffs. |
| hooks | object | — | Agent-scoped lifecycle hooks that only fire when this agent is the active session agent. See Agent-scoped hooks. |
Example:
---
description: Writes TypeScript unit tests
tools: [read, search, write]
model: claude-sonnet-4-5
handoffs:
- label: "Review the tests"
agent: "code-reviewer"
---
You write thorough unit tests using Bun's test runner.
Always check existing tests before writing new ones. Follow the
project's testing conventions in `.github/instructions/`.Tool permissions
The tools field uses Copilot tool names. When the list is non-empty and does not contain "*", all other OpenCode tools are denied. A fixed set of utility tools is always allowed regardless: list, question, skill, task, todowrite.
| Copilot name | OpenCode tools granted |
| --- | --- |
| read | read |
| edit | edit |
| write | edit |
| bash | bash |
| fetch | webfetch |
| search | glob, grep |
| * | All tools (no deny policy applied) |
Handoffs
The handoffs field declares suggested next-step agents. After loading an agent via copilot_agent, a Suggested Next Steps section is appended to its output, listing each handoff as a call-to-action.
---
description: Designs system architecture
handoffs:
- label: "Start implementation"
agent: "code-writer"
prompt: "Implement the architecture described above, starting with the data layer."
- label: "Get a second opinion"
agent: "code-reviewer"
---| Field | Type | Required | Description |
| --- | --- | --- | --- |
| label | string | Yes | Text shown in the suggested next step |
| agent | string | Yes | Name of the target agent (must match an agent file) |
| prompt | string | No | Pre-filled prompt injected when the handoff is followed |
Agent-scoped hooks
Agents can declare hooks directly in their frontmatter. These only fire while that agent is the active session agent (i.e., after the user calls copilot_agent).
---
description: Security auditor
hooks:
preToolUse:
- bash: |
echo '{"permissionDecision":"ask","permissionDecisionReason":"Security agent requires confirmation"}'
timeoutSec: 3
sessionStart:
- bash: "echo 'Security audit session started' >&2"
---
Audit code for security vulnerabilities...Both camelCase (preToolUse) and PascalCase (PreToolUse) hook type names are accepted. Hook command fields are the same as project-level hooks — see Hooks for the full reference including the stdin/stdout protocol.
Where Resources Are Written
| Resource | Global Location | Local Location |
| --- | --- | --- |
| Synced agents | ~/.config/opencode/agents/copilot-bridge--*.md | .opencode/agents/copilot-bridge--*.md |
| Synced prompts | ~/.config/opencode/prompts/copilot-bridge--*.prompt.md | .opencode/prompts/copilot-bridge--*.prompt.md |
| Synced skills | ~/.config/opencode/skills/copilot-bridge--*/SKILL.md | .opencode/skills/copilot-bridge--*/SKILL.md |
| MCP configs | ~/.config/opencode/opencode.json (prefixed copilot-bridge/) | -- |
| Feature selections | ~/.config/opencode/copilot-bridge-selections.json | .opencode/copilot-bridge-selections.json |
| Feature manifest | ~/.cache/open-copilot-bridge/<org>/feature-manifest.json | -- |
| Agent cache | ~/.cache/open-copilot-bridge/<org>/agents-<org> | -- |
| Command stubs | ~/.config/opencode/commands/ | -- |
Plugin-managed files are prefixed with copilot-bridge-- or copilot-bridge/ and include a <!-- synced-by: open-copilot-bridge --> metadata comment. The plugin never overwrites user-created files.
Development
Prerequisites
- Bun runtime
- Node.js (for TypeScript tooling)
Setup
bun installType Check
bun run typecheckRun Tests
bun testLocal Development
Point your opencode.json to the local plugin directory:
{
"plugin": ["/path/to/open-copilot-bridge"]
}For the TUI plugin, add to tui.json using a relative path to the TUI entry point:
{
"$schema": "https://opencode.ai/tui.json",
"plugin": ["./src/tui.ts"]
}The plugin supports hot-reload for instructions, agents, prompts, and skills during development. Hooks require a restart.
Tech Stack
- TypeScript -- Strict mode, ESM
- Bun -- Runtime and test runner
- @opencode-ai/plugin -- OpenCode plugin SDK
- @opentui/core, @opentui/solid -- TUI plugin framework (optional, for the agent picker)
- picomatch -- Glob pattern matching for path-specific instructions
- yaml -- YAML frontmatter parsing
License
MIT
