Translating a Claude Code Workflow to GitHub Copilot

I wrote previously about building a multi-agent AI development system with Claude Code - a comprehensive setup with slash commands, enforcement hooks, session logging, multi-agent orchestration, and a reproducible config system that deploys to a new machine in one command.

That system runs on my personal Mac. Then I needed to use GitHub Copilot on a Windows VM for work, and the question became: how much of this workflow translates?

The answer is most of it. Not all of it, and not one-to-one, but the core ideas carry over surprisingly well. This post walks through the translation and what I learned along the way.


Table of Contents

Why not just use Claude Code on both?

My employer provides a Windows VM with GitHub Copilot Enterprise. The work happens there. Claude Code is a terminal-native tool that runs best on macOS/Linux. Even if I could run it on the VM, Copilot is what the team uses, and there's value in working within the same tool ecosystem as your coworkers.

But the workflow patterns I've built, the commit conventions, the session logging, the quality gates, those aren't Claude-specific ideas. They're development workflow ideas that happen to be implemented in Claude Code. Translating them to Copilot was about carrying the workflow forward, not the tool.


The mapping

Here's the high-level translation table. Each Claude Code concept has a Copilot equivalent, though the implementation details differ.

Claude Code Copilot Equivalent Location
~/.claude/CLAUDE.md (global instructions) VS Code user settings + copilot-instructions.md .vscode/settings.json + .github/copilot-instructions.md
~/.claude/commands/*.md (slash commands) Prompt files .github/prompts/*.prompt.md
~/.claude/hooks/*.py (enforcement hooks) Husky git hooks .husky/pre-commit, .husky/commit-msg
.claudeignore .copilotignore Root of each repo
~/.claude/log-system.md Reference doc docs/log-system.md
~/.claude/multi-agent-system.md Reference doc docs/multi-agent-system.md
Per-project CLAUDE.md Per-project copilot-instructions.md .github/copilot-instructions.md
N/A (Claude loads context hierarchy) Conditional instruction files .github/instructions/*.instructions.md

Global instructions: CLAUDE.md to copilot-instructions.md

In Claude Code, ~/.claude/CLAUDE.md is a single markdown file that gets loaded into every conversation. It contains everything: commit conventions, code standards, error handling patterns, common mistakes to avoid, security rules. One file, always present.

My initial translation split this across two mechanisms: inline JSON instruction arrays in VS Code user settings, and a copilot-instructions.md file per repo. The settings approach looked like this:

{
  "github.copilot.chat.codeGeneration.instructions": [
    { "text": "Never add AI attribution to git commits or PR descriptions." },
    { "text": "Use functional React components with TypeScript interfaces for props." }
  ],
  "github.copilot.chat.commitMessageGeneration.instructions": [
    { "text": "Format: {issue_number}: {brief description}. Never include AI attribution." }
  ]
}

This seemed nicer than Claude Code's approach - instructions scoped to specific Copilot behaviors (code generation, commit messages, reviews, PR descriptions) instead of one big file where the model has to figure out what applies.

Then I actually set it up on the VM. VS Code immediately flagged every one of these with deprecation warnings: "Use instructions files instead." The github.copilot.chat.*.instructions inline settings are deprecated in favor of the instruction file system. All those carefully structured JSON arrays? Unnecessary. The same rules belong in .github/copilot-instructions.md and .github/instructions/*.instructions.md.

This was a good lesson in the gap between documentation and reality. The settings API still technically works, but VS Code actively warns against it. The instruction files are the correct path forward.

copilot-instructions.md (.github/copilot-instructions.md) is where all the rules actually live. Git workflow documentation, session logging protocols, code standards with examples, commit conventions, the full "common mistakes to avoid" section. This file lives in each repo and is loaded automatically when Copilot operates in that workspace. It's the direct equivalent of CLAUDE.md.


Slash commands: commands/ to prompts/

Claude Code's slash commands live in ~/.claude/commands/ as markdown files with YAML frontmatter. They use ! prefix syntax to execute shell commands inline when the command is invoked, which means the command can pre-load git state, issue lists, and other context before Claude even starts thinking.

Copilot's equivalent is .prompt.md files in .github/prompts/. These appear in the / autocomplete menu in Copilot Chat when you're in Agent mode. The frontmatter is slightly different:

---
agent: 'agent'
tools: ['#runInTerminal', '#readFile', '#editFiles']
description: 'Stage all changes and commit with conventional format'
---

The tools array explicitly declares which capabilities the prompt needs. #runInTerminal lets it execute shell commands, #readFile lets it read files, #editFiles lets it make changes, and #codebase lets it search across the project.

Here's how the nine Claude Code commands mapped:

Claude Code Copilot Notes
/startup /startup Same concept. Copilot version instructs agent to run commands as steps instead of pre-loading context with ! syntax
/commit /commit Direct translation. Uses ${input:commitMessage} for user input
/pr /pr Direct translation. Includes PR template check
/sync /sync Direct translation
/new-issue /new-issue Direct translation
/gs /gs Direct translation
/walkthrough /walkthrough Direct translation
/audit /audit Simplified from 7-phase parallel to sequential single-agent
/dotsync Not migrated Claude-specific dotfiles sync
/promote-rule Not migrated Claude-specific instruction management
/cpm /cpm (new) Commit + PR + Merge one-shot workflow

The biggest behavioral difference is how context gets loaded. In Claude Code, the /startup command runs shell commands with ! prefix and injects the output directly into the conversation context before Claude processes anything. The model sees the git status, open issues, and log files as pre-loaded data.

In Copilot, the prompt file is just instructions. It tells the agent "run git status", "run gh pr list", "run gh issue list". The agent then executes these as sequential steps, which means it takes longer and the model processes each result individually rather than seeing everything at once.

For most commands this difference doesn't matter. For /startup, which gathers context from five or six different sources, it's noticeably slower. But the end result is the same: the agent has a full picture of the project state.


VS Code settings: what actually goes in settings.json

With the inline instruction arrays removed, settings.json becomes much cleaner. It handles the behavioral configuration that applies globally across all workspaces - things that aren't project-specific rules, but rather how VS Code and Copilot should behave.

Here's what survived the setup process:

Copilot behavior settings:

Setting What It Does
chat.useClaudeMdFile: true Copilot reads CLAUDE.md files in your repos. If you have repos with existing Claude Code configs, Copilot respects those instructions too.
chat.agent.enabled: true Enables Agent Mode - the closest equivalent to Claude Code's default behavior. Without this, chat is ask-only.
github.copilot.nextEditSuggestions.enabled: true After you make an edit, Copilot predicts where you'll edit next. Rename a parameter, and it suggests updating all usages.

Editor settings that affect the Copilot workflow:

Setting What It Does
editor.formatOnSave: true Auto-formats on Ctrl+S. Prevents style inconsistencies without thinking about it.
editor.codeActionsOnSave Auto-fixes ESLint errors and organizes imports on save. "explicit" means manual save only, not auto-save.
git.postCommitCommand: "none" After committing, VS Code does nothing (no auto-push). Intentional for the issue-first workflow where you review before pushing.

Context exclusion settings:

Setting Why It Matters for Copilot
files.exclude (node_modules, dist, build) Hides generated directories from file explorer and Ctrl+P.
search.exclude (same + lock files) Excludes from Ctrl+Shift+F search. Also reduces noise when Copilot searches your codebase via #codebase.

A few things I learned during setup:

  • chat.instructionsFilesLocations was supposed to point at .github/instructions/, but VS Code rejected the schema format. Turns out .github/instructions/ is auto-scanned by default - the setting is unnecessary.
  • editor.defaultFormatter: "esbenp.prettier-vscode" fails validation if the Prettier extension isn't installed. Comment it out until you install it, or install it first.
  • Extension dependencies are real. Four extensions are needed for full functionality: GitHub Copilot, GitHub Copilot Chat, Prettier, and ESLint. The settings file should document these prerequisites (ours now does).

The full settings reference with every setting explained is in the copilot-configs README.


Conditional instructions: something Claude Code doesn't have

Copilot has a feature that Claude Code doesn't: .instructions.md files in .github/instructions/ that apply conditionally based on file glob patterns.

---
name: 'React TypeScript Standards'
applyTo: '**/*.{tsx,ts}'
---
## Component Patterns
- Always use functional components with TypeScript interfaces
- Never export components and non-components from the same file
---
name: 'SQL Migration Standards'
applyTo: '**/migrations/**/*.sql'
---
## Reserved Keywords
Always double-quote: position, order, user, offset, limit, key, value, type...

This is genuinely useful. In Claude Code, the React conventions, the SQL migration rules, and the Go patterns all live in the same CLAUDE.md file. The model gets all of them regardless of what file it's working on. With Copilot's instruction files, the React rules only load when you're editing .tsx files, and the SQL rules only load when you're in a migration directory.

I created two instruction files to start: react-typescript.instructions.md for TypeScript/React conventions, and sql-migrations.instructions.md for Supabase migration patterns. Adding more is straightforward.


Enforcement hooks: Python hooks to Husky

This is where the translation gets lossy.

Claude Code's enforcement hooks are Python scripts that intercept tool calls at the PreToolUse and UserPromptSubmit layers. They run before Claude executes any action, and they can block it, modify it, or inject context. Four hooks in my setup:

  • enforce-git-workflow.py - blocks commits on main, enforces issue-number prefixes in commit messages, blocks pushes to main
  • enforce-issue-workflow.py - detects work-request prompts and injects a "create an issue first" reminder
  • auto-approve-bash.py - reimplements the permission allow/deny list at the hook layer (workaround for a Claude Code bug)
  • auto-approve-file-ops.py - same for file read/write/edit operations

Copilot doesn't have a hook/interception system. There's no way to run code before Copilot executes a command, and there's no way to programmatically block actions based on content inspection.

The workaround is Husky git hooks, which operate at the git level rather than the AI level:

Pre-commit (.husky/pre-commit):

#!/bin/sh
BRANCH=$(git branch --show-current)
if [ "$BRANCH" = "main" ]; then
  echo "ERROR: Cannot commit on main. Create a feature branch first."
  exit 1
fi

Commit-msg (.husky/commit-msg):

#!/bin/sh
MSG=$(cat "$1")
if ! echo "$MSG" | grep -qE "^[0-9]+:"; then
  echo "ERROR: Commit message must start with issue number."
  echo "  Format: {issue_number}: {description}"
  exit 1
fi

These cover the two most important enforcement rules (no commits on main, issue-number prefix in messages). But they miss the subtler ones. The enforce-issue-workflow.py hook that detects work-request verbs and reminds Claude to check for issues first? That has no Copilot equivalent. The permission deny list that blocks rm and git reset --hard? That's in the instructions as soft guidance, not hard enforcement.

The tradeoff is clear: Husky hooks enforce rules at the git boundary, where they catch mistakes regardless of whether a human or AI made them. Claude Code hooks enforce rules at the AI boundary, which catches mistakes earlier but only applies to AI-initiated actions.


Session logging and multi-agent coordination

The session logging system and multi-agent coordination protocols are workflow documentation, not tool-specific features. They translate as reference docs that Copilot reads when instructed to.

In Claude Code, log-system.md and multi-agent-system.md live in ~/.claude/ and are referenced by the slash commands. The /startup command reads agent logs, checks cross-agent state, and creates new log entries. The logging triggers (after every commit, after PR creation, after merge) are enforced by instructions in CLAUDE.md.

In Copilot, these same documents live in docs/ and are referenced by the prompt files. The /startup prompt instructs the agent to pull logs, read today's log, check other agents' logs, and create a new entry if needed. The logging triggers are documented in copilot-instructions.md.

The implementation is softer. Claude Code's hooks can't force the model to update logs, but the tight integration between commands and instructions makes it reliable in practice. With Copilot, it's entirely instruction-based, so compliance depends on the model following the prompt. In my experience, both tools follow logging instructions consistently once the prompts are well-written.

One adaptation for the Windows environment: all paths in the docs reference both Unix-style (~/code/agent-logs/) and Windows-style (C:\code\agent-logs\) conventions, since Copilot on Windows might use either depending on whether it's running in PowerShell or Git Bash.


The setup.sh approach

The original Claude Code setup uses a setup.sh script that symlinks config files and generates settings.json with path expansion. The copilot-configs repo takes a different approach: placeholder replacement.

All config files use {{PLACEHOLDER}} tokens for values that vary per user:

  • {{GITHUB_USERNAME}} - your GitHub handle
  • {{FULL_NAME}} - your name for attribution
  • {{LOG_REPO_NAME}} - the name of your agent logs repo

The setup script prompts for these values (auto-detecting from gh CLI and git config where possible), then does a find/sed across all .md and .json files to replace every placeholder. It can also create the agent logs repo on GitHub.

git clone https://github.com/lucasmccomb/copilot-configs.git
cd copilot-configs
./setup.sh

Or non-interactively:

./setup.sh --github-user octocat --full-name "Octo Cat" --log-repo my-agent-logs

This makes the configs genuinely portable. Someone can fork the repo, run setup, and have a complete Copilot workflow configured in under a minute. The placeholder approach is simpler than the symlink/template system I use for Claude Code, but it works well for a repo that's meant to be forked and customized rather than centrally managed.


What didn't translate

Some things are Claude Code-specific and have no meaningful Copilot equivalent:

Feature Why it didn't translate
hooks/*.py (tool-call interception) Copilot has no pre-execution hook system
settings.json permission deny list No way to block specific commands in Copilot
MCP servers Copilot has .vscode/mcp.json support, but the server ecosystem is different
/dotsync command Specific to the Claude dotfiles reverse-sync workflow
/promote-rule command Specific to the CLAUDE.md instruction hierarchy
Plugin ecosystem Copilot extensions exist but operate differently than Claude Code plugins
Inline context pre-loading (! syntax) Copilot prompts instruct; they don't pre-execute

The permission system is the most significant loss. Claude Code's deny list blocks destructive operations (rm, git reset --hard, DROP TABLE) at the tool level. In Copilot, these are documented as "don't do this" in the instructions. The model generally respects them, but there's no hard gate.


Key differences in practice

After using both systems side by side, a few practical differences stand out:

Context loading is explicit in Copilot. Claude Code automatically reads referenced files, loads the CLAUDE.md hierarchy, and ingests MCP server data. Copilot requires you to explicitly reference context with #file, #codebase, or #changes. This means you need to be more intentional about what the model sees, which is both a feature (less noise) and a limitation (more manual work).

Agent mode is opt-in. In Claude Code, the model always has access to tools. In Copilot, you need to open Agent mode specifically (Ctrl+Shift+I instead of Ctrl+I) and the / commands only appear there. Default chat is ask-only with no tool access.

Model switching is per-chat. Claude Code switches models with a --model flag. Copilot uses Ctrl+Alt+. to cycle through available models within a chat. Different models are better at different tasks, and Copilot makes it easy to switch mid-conversation.

The instruction hierarchy is different. Claude Code loads CLAUDE.md files from root to working directory, creating a three-tier inheritance (global, workspace, project). Copilot has user settings (global), copilot-instructions.md (per-repo), and .instructions.md files (per-file-type). The layering is flatter but more granular at the file level.


The result

The copilot-configs repo is public. It contains:

  • .github/copilot-instructions.md - global rules translated from CLAUDE.md
  • .github/prompts/ - 9 prompt files (commit, pr, gs, startup, sync, new-issue, walkthrough, cpm, audit)
  • .github/instructions/ - 2 conditional instruction files (React/TypeScript, SQL migrations)
  • .vscode/settings.json - user-level Copilot behavior settings (with a full reference guide in the README)
  • .copilotignore - context exclusion rules
  • docs/ - log system, multi-agent system, and GitHub repo protocols
  • setup.sh - one-command personalization

The workflow I've built over months with Claude Code now has a Copilot equivalent that captures maybe 80% of the functionality. The missing 20% is mostly the enforcement layer (hooks, permissions, tool-call interception) and the deeper MCP integration. For day-to-day development work, the Copilot version covers what matters: consistent commit conventions, session continuity, quality gates, and a standardized workflow that any new project can adopt immediately.

The translation process itself was instructive. Several assumptions I made from reading Copilot documentation didn't survive contact with reality - deprecated settings, schema mismatches, extension dependencies. The best way to validate any AI tool configuration is to actually set it up and watch what VS Code complains about. Documentation lags behind the tool.

If you're using Claude Code and need to work with Copilot (or vice versa), the concepts transfer. The specific files and syntax are different, but the underlying ideas (global instructions, scoped commands, enforcement at boundaries, session logging for continuity) are tool-agnostic. Build the workflow first, then implement it in whatever tool your environment requires.

Enjoy this post?

Consider leaving a small donation to support the blog.

$