Use your repository's GitHub Copilot customization from Claude Code and OpenCode — without committing a single tool-specific file.
Leia em Português (Brasil).
Your team (or company) standardizes on GitHub Copilot and its .github/ customization layout —
copilot-instructions.md, instruction files, prompt files, custom agents, skills. You prefer
developing with Claude Code (or OpenCode), but two constraints get in the way:
- That tool does not read Copilot's customization files.
- You are not allowed to commit anything tool-specific (
CLAUDE.md,.claude/,.opencode/, …) to the repo — and duplicating the content by hand rots immediately.
claupilot solves both. It bridges the Copilot structure into your tool locally, at session
start, and keeps everything it creates invisible to git. Claude Code is the default target;
--target opencode (or both) does the same for OpenCode.
| Copilot (committed, source of truth) | Claude Code (local, never committed) | How |
|---|---|---|
.github/copilot-instructions.md |
Session context | Injected by a SessionStart hook, as if it were CLAUDE.md |
AGENTS.md |
Session context | Injected (Copilot CLI reads both — so does claupilot) |
.github/instructions/*.instructions.md |
.claude/rules/*.md (path-scoped rules) |
Generated — applyTo globs become paths:, lazily loaded by Claude Code |
.github/prompts/*.prompt.md |
.claude/commands/*.md → /name |
Generated with frontmatter + variable translation |
.github/agents/*.md, *.agent.md |
.claude/agents/*.md (subagents) |
Generated with tool/model mapping |
.github/skills/*/SKILL.md, .agents/skills/ |
.claude/skills/* |
Linked (junction/symlink) — same open Agent Skills standard, zero conversion |
Everything lands under <repo>/.claude/, which claupilot hides from git via .git/info/exclude
— a local, never-committed ignore file. git status stays clean, .gitignore is never touched,
and nothing Claude-related can ever leak into a commit or PR.
Requires Node.js ≥ 18 (Claude Code ≥ 2.x).
As a Claude Code plugin (recommended) — inside Claude Code:
/plugin marketplace add slipalison/claupilot
/plugin install claupilot@claupilot
Restart Claude Code. From now on, every session that starts inside a repo with Copilot customization gets bridged automatically. No per-repo setup.
Standalone CLI (no plugin) — run it manually or from your own tooling:
npx @slipalison/claupilot sync # bridge the current repo (Claude Code)
npx @slipalison/claupilot check # dry-run: show what would change
npx @slipalison/claupilot context # preview the context that would be injected
npx @slipalison/claupilot clean # remove everything claupilot created
npx @slipalison/claupilot sync --target opencode # bridge for OpenCode instead
npx @slipalison/claupilot sync --target both # bridge for both tools at onceUser-level hook (no plugin, auto-sync) — add to ~/.claude/settings.json:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|clear|compact",
"hooks": [
{
"type": "command",
"command": "npx --yes @slipalison/claupilot sync --hook",
"timeout": 60
}
]
}
]
}
}session start
│
▼
SessionStart hook ──► node claupilot.mjs sync --hook
│
├─ discover .github/{copilot-instructions.md, instructions/, prompts/, agents/, skills/}, AGENTS.md, .agents/skills/
├─ translate frontmatter, tools, models, ${input:*} variables
├─ sync .claude/{agents,commands,rules,skills} (marker-managed, idempotent)
├─ exclude .git/info/exclude (adds a managed "/.claude/" block)
└─ inject repo-wide instructions as additionalContext
- Instruction files become native Claude Code rules (
.claude/rules/*.md): theapplyToglobs translate topaths:frontmatter, so Claude Code loads each rule only when it touches matching files — the exact semantics Copilot givesapplyTo.applyTo: "**"(or none) produces an unconditional rule; nested instruction directories are mirrored. Repo-wide files (copilot-instructions.md,AGENTS.md) are injected as session context. - Skills need no translation — Agent Skills is an open standard shared by Copilot and Claude.
claupilot links
.claude/skills/<name>→.github/skills/<name>(junction on Windows — no admin required — symlink on Linux/macOS, full copy as a fallback or with--no-links). Edits to the source are picked up live. - Agents and prompts are generated files with a translation layer (see below) and a marker comment identifying them as claupilot-managed.
Tools (Copilot canonical names, their documented aliases, the VS Code chat vocabulary, and MCP):
| Copilot | Claude Code |
|---|---|
execute, shell, bash, powershell |
Bash (+ PowerShell) |
read, NotebookRead |
Read |
edit, write, MultiEdit, NotebookEdit, editFiles |
Edit, Write (+ NotebookEdit) |
search, Grep, Glob, codebase, usages |
Grep, Glob (+ Read for codebase) |
web, WebSearch, WebFetch, fetch |
WebSearch, WebFetch |
agent, custom-agent, Task |
Agent |
todo, TodoWrite |
TodoWrite |
server/tool (MCP) |
mcp__server__tool |
If any token can't be mapped (e.g. server/*), the tools field is omitted entirely — the
subagent inherits all tools instead of silently losing a capability. The reason is recorded in a
claupilot:notes comment inside the generated file.
Models: claude-sonnet-* → sonnet, claude-opus-* → opus, claude-haiku-* → haiku.
GPT/Gemini/other models are dropped (the session model is used) and noted.
Prompt variables: one distinct ${input:x} → $ARGUMENTS; multiple → $1, $2, … in order of
first appearance (an argument-hint is derived, or passed through when the source declares one).
${selection} becomes a natural-language reference. A custom agent: in a prompt file maps to the
bridged subagent of the same name.
Everything above works for OpenCode too — pass --target opencode
(or --target both). The same .github/ sources are bridged into OpenCode's native layout under
a local, git-excluded .opencode/:
| Copilot (committed, source of truth) | OpenCode (local, never committed) | How |
|---|---|---|
.github/copilot-instructions.md |
.opencode/opencode.json → instructions |
Referenced in place — no copy; OpenCode resolves the path from the repo root |
.github/instructions/*.instructions.md |
.opencode/opencode.json → instructions |
Referenced in place (load unconditionally — OpenCode has no applyTo scoping) |
AGENTS.md |
(nothing) | OpenCode reads it natively |
.github/prompts/*.prompt.md |
.opencode/commands/*.md → /name |
Generated; ${input:*} → $ARGUMENTS/$1..$N |
.github/agents/*.md, *.agent.md |
.opencode/agents/*.md (mode: subagent) |
Generated; Copilot tool allowlist → OpenCode permission map |
.github/skills/*/SKILL.md, .agents/skills/ |
.opencode/skills/* |
Linked (junction/symlink) — same open Agent Skills standard |
Differences from the Claude Code bridge, by design:
- Instructions are referenced, not copied. OpenCode resolves relative
instructionspaths from the project root even when they're declared in.opencode/opencode.json, so.github/stays the single source of truth. Because OpenCode has noapplyToequivalent, instruction files load unconditionally — each file's frontmatter still carries its glob for the model to self-scope. .opencode/opencode.jsondeep-merges with anyopencode.jsonyou already have (OpenCode unions + dedupesinstructions), so claupilot never clobbers your config. A pre-existing.opencode/opencode.jsonthat claupilot didn't create is left untouched (skip + warn).- Models are dropped (OpenCode uses its configured model) and noted — OpenCode needs a
version-pinned
provider/modelslug that a Copilot hint can't be turned into safely.
Auto-sync (recommended) — install the OpenCode plugin so every session re-bridges on its own, the way the Claude Code plugin does:
mkdir -p ~/.config/opencode/plugin
curl -fsSL https://raw.githubusercontent.com/slipalison/claupilot/main/opencode/plugin/claupilot.js \
-o ~/.config/opencode/plugin/claupilot.jsThe plugin runs claupilot sync --target opencode at session start and also merges the discovered
instruction files into the in-memory config so they apply immediately (requires Node ≥ 18 on PATH).
Once .opencode/ exists, OpenCode drops its own node_modules/.gitignore inside it — those are
OpenCode's, ignored by its own .gitignore, and the whole directory is hidden from git by claupilot
anyway.
- Zero repo footprint. Nothing claupilot writes is visible to git. It edits only
.git/info/exclude(which itself is never committed) — never.gitignore. - Never touches your files. Generated files carry a
claupilot:managedmarker; anything without the marker — your own commands, agents, skills — is never modified or deleted. - Source of truth stays in
.github/. Edit sources, not generated files; the next session start (or/claupilot:sync) re-syncs. Deleted sources have their generated counterparts removed. - Idempotent & fast. Unchanged sources → zero writes, typically a few milliseconds.
- Never breaks a session. In hook mode any internal error is swallowed (logged to stderr) and the session starts normally.
- Offline & dependency-free. Single-file Node script, no network access, no runtime deps.
| Command | What it does |
|---|---|
/claupilot:sync |
Re-sync now and report what changed |
/claupilot:doctor |
Dry-run diagnosis: discovered assets, pending changes, git-exclude status |
- First sync in a repo: skills/agents/commands/rules materialized during session start are
discovered by Claude Code at the next session start (the injected context covers the gap with
MUST-read pointers, and repo-wide instructions are available immediately). Restart or
/clearonce after the very first bridge of a repo. - The reverse direction is native: GitHub Copilot CLI already reads
.claude/skills/,CLAUDE.mdand.mcp.json. claupilot fills the missing direction — Claude Code reading Copilot's layout. - MCP servers: both tools read
.mcp.jsonat the repo root, so MCP config needs no bridging. - Prompt files aren't supported by Copilot CLI itself (VS Code only) — claupilot bridges them to Claude Code anyway.
- Copilot
hooks(.github/hooks/*.json) are intentionally not bridged: executing hook commands cross-tool has security implications. May become an opt-in later. - Worktrees & monorepos: git worktrees are supported (the exclude block lands in the common git
dir); nested
.github/dirs inside monorepo packages are not scanned (only the repo root). - Windows: junctions are used instead of symlinks — they work without Developer Mode or admin rights.
rulesync, ruler
and dotagent all solve multi-tool config sync by owning
the source of truth in their own directory and generating the per-tool files — which are then
committed (or force .gitignore edits). claupilot is the opposite shape: Copilot's committed
layout stays the source of truth, and the Claude Code / OpenCode side is a disposable,
git-invisible, local cache. Nothing to adopt, nothing to commit, nothing for teammates to see.
npm test # fixture-based suite (plain node, no framework)
npm run test:coverage # same suite under c8 (lcov for SonarQube)
claude plugin validate . # validate plugin/marketplace manifestsCI runs the test matrix on Linux and Windows (Node 18/20/24), validates the plugin manifest, does an
npm publish dry-run and runs SonarQube with a blocking quality gate. Releases are tag-driven
(vX.Y.Z) and publish to npm with provenance.