From e4ef5a8dac377a9888fbdf18988c2519db704725 Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rexlorenzo@gmail.com>
Date: Thu, 19 Mar 2026 09:02:02 -0700
Subject: [PATCH 1/2] feat(code-review-loop): allow unstaged tracked changes
 during review loop

- Replace hard rejection with baseline snapshot so pre-existing
  unstaged files are preserved while agent modifications are staged
- Fix duplicate setup_temp call and consolidate after validation
---
 bin/code-review-loop | 36 ++++++++++++++----------------------
 1 file changed, 14 insertions(+), 22 deletions(-)

diff --git a/bin/code-review-loop b/bin/code-review-loop
index 6567158..71263e8 100755
--- a/bin/code-review-loop
+++ b/bin/code-review-loop
@@ -122,15 +122,18 @@ stage_review_changes() {
         done <<< "$current_staged"
     fi
 
-    # Stage any unstaged tracked modifications — the dirty-worktree guard at
-    # startup guarantees these were created by the review agent, not pre-existing
+    # Stage unstaged tracked modifications that were NOT present before the loop
+    # started — those are changes made by the review agents.  Pre-existing
+    # unstaged changes (captured in BASELINE_UNSTAGED) are left untouched.
     local unstaged_modified
-    unstaged_modified=$(git diff --name-only 2>/dev/null) || true
+    unstaged_modified=$(git diff --name-only 2>/dev/null | sort) || true
     if [[ -n "$unstaged_modified" ]]; then
+        local agent_modified
+        agent_modified=$(comm -23 <(echo "$unstaged_modified") "$BASELINE_UNSTAGED") || true
         while IFS= read -r file; do
             [[ -z "$file" ]] && continue
             git add -- "$file"
-        done <<< "$unstaged_modified"
+        done <<< "$agent_modified"
     fi
 
     # Stage newly created untracked files — these are legitimate fixes from
@@ -165,10 +168,6 @@ _required_prompts+=("$EDITOR_RESPONSE_PROMPT" "$REVIEWER_INITIAL_PROMPT" "$REVIE
 validate_tools
 validate_prompts "${_required_prompts[@]}"
 
-# ---- temp directory with cleanup -----------------------------------------
-setup_temp "code-review-loop"
-trap cleanup_temp EXIT
-
 # ---- main ----------------------------------------------------------------
 
 # Detect partially staged files (some hunks staged, others not) — these would
@@ -188,7 +187,9 @@ if [[ -n "$partially_staged" ]]; then
     exit 1
 fi
 
-setup_temp
+# ---- temp directory with cleanup -----------------------------------------
+setup_temp "code-review-loop"
+trap cleanup_temp EXIT
 
 echo ""
 echo -e "${MAGENTA}========================================${NC}"
@@ -206,19 +207,10 @@ initial_diff=$(git diff --staged --stat 2>&1) || true
 initial_diff_full=$(git diff --staged 2>&1) || true
 initial_added_files=$(git diff --staged --name-only --diff-filter=A 2>/dev/null | sort) || true
 
-# Tracked unstaged edits make it impossible to safely separate pre-existing
-# work from review-loop fixes in the same file, so reject them up front.
-tracked_unstaged=$(git diff --name-only 2>/dev/null | sort) || true
-if [[ -n "$tracked_unstaged" ]]; then
-    echo -e "${RED}ERROR: Unstaged tracked changes detected:${NC}"
-    while IFS= read -r f; do
-        [[ -z "$f" ]] && continue
-        echo "  $f"
-    done <<< "$tracked_unstaged"
-    echo ""
-    echo "Commit, stash, or fully stage these files before running the review loop."
-    exit 1
-fi
+# Baseline unstaged tracked files — only changes to files NOT in this list
+# should be staged during the loop (they come from the review agents).
+BASELINE_UNSTAGED="$TMPDIR_REVIEW/baseline-unstaged.txt"
+git diff --name-only 2>/dev/null | sort > "$BASELINE_UNSTAGED"
 
 # Baseline untracked files — only files created *during* the loop should be staged
 BASELINE_UNTRACKED="$TMPDIR_REVIEW/baseline-untracked.txt"

From 71c19873cb7d856cee6991c52ae811cac3ad71af Mon Sep 17 00:00:00 2001
From: Rex Lorenzo <rexlorenzo@gmail.com>
Date: Thu, 19 Mar 2026 19:37:36 -0700
Subject: [PATCH 2/2] feat: add Copilot CLI support and enforce MCP disabling
 across all agents

- Add skills (commitmsg, code-review, code-refinement, review-pr) to .copilot/skills/
- Extend setup script with Copilot detection, installation, and MCP config
- Disable MCP servers in Claude runs via --strict-mcp-config --mcp-config '{}'
- Switch Codex MCP override to --config long form to fix quoting issues
---
 .copilot/skills/code-refinement/SKILL.md |  16 ++++
 .copilot/skills/code-review/SKILL.md     | 109 +++++++++++++++++++++++
 .copilot/skills/commitmsg/SKILL.md       |  34 +++++++
 .copilot/skills/review-pr/SKILL.md       |  92 +++++++++++++++++++
 README.md                                |   8 ++
 lib/lib-review-loop                      |  42 ++++++---
 setup                                    |  78 ++++++++++++----
 7 files changed, 353 insertions(+), 26 deletions(-)
 create mode 100644 .copilot/skills/code-refinement/SKILL.md
 create mode 100644 .copilot/skills/code-review/SKILL.md
 create mode 100644 .copilot/skills/commitmsg/SKILL.md
 create mode 100644 .copilot/skills/review-pr/SKILL.md

diff --git a/.copilot/skills/code-refinement/SKILL.md b/.copilot/skills/code-refinement/SKILL.md
new file mode 100644
index 0000000..bd9117e
--- /dev/null
+++ b/.copilot/skills/code-refinement/SKILL.md
@@ -0,0 +1,16 @@
+---
+name: code-refinement
+description: "Review staged files for code quality (KISS, DRY, YAGNI, Clean Code) and fix linting issues."
+---
+
+# Code Refinement
+
+Review the staged files to ensure the changes adhere to the KISS, DRY, and YAGNI principles. Confirm that Clean Code standards are met (including clear, consistent naming and comments where needed).
+
+Check for opportunities to use established framework utilities, composables, or library functions instead of hand-rolled logic. If the staged code reimplements behavior that the project's framework or core libraries already provide, flag it and suggest the existing alternative.
+
+Verify that the project's UI framework components and utility classes are used where appropriate instead of custom CSS or HTML elements. Flag any custom styling that duplicates what the framework already provides.
+
+Run the project's linting command and fix all reported errors and warnings. Avoid using lint-suppression comments (e.g., eslint-disable, noqa, @ts-ignore) to make the lint pass unless absolutely necessary, and only with a clear justification in the code.
+
+Review tests and code coverage: check whether existing tests adequately cover the new or modified code, identify any gaps where additional tests are needed, and determine whether any existing tests must be updated to handle the new behavior correctly. When finished, ensure everything is ready for a high-quality code review.
diff --git a/.copilot/skills/code-review/SKILL.md b/.copilot/skills/code-review/SKILL.md
new file mode 100644
index 0000000..53c7e13
--- /dev/null
+++ b/.copilot/skills/code-review/SKILL.md
@@ -0,0 +1,109 @@
+---
+name: code-review
+description: "Review staged changes for security, correctness, performance, and clarity. Writes findings to agent-code-review.md."
+---
+
+# Role
+
+You are a senior code reviewer and security expert. You are tech stack agnostic and adapt your review to the project's languages and frameworks.
+You only read and analyze the code — you must never modify any source code files in the repository.
+The sole exception is writing your review output into a Markdown file.
+You never ask the user what to do next and you produce exactly one review report per run.
+
+## Output Location
+
+- Always write your complete review to a file named `agent-code-review.md` in the project root.
+- Overwrite the file completely on each run — do not append.
+- This file is the only file you may create or modify.
+- Do not stage, commit, or push this file.
+
+## Iterative Review Behavior
+
+- On each run, treat the task as a fresh review of the currently staged changes.
+- Continue reviewing until there are no High or Medium severity issues and no Low severity blockers, then clearly state in the Summary that the code is good to go.
+
+## Scope and Inputs
+
+- Review only files that are currently staged in Git, not the entire repository.
+- Focus on changed lines and minimal necessary surrounding context.
+- Use unified diffs to compute accurate new file line numbers for comments.
+- If information is missing, state reasonable assumptions and proceed.
+
+## How to Collect Context
+
+1. Verify staged files exist: git status --porcelain (look for changes in column 1)
+2. Get the diff: git diff --staged --unified=0 --no-color
+3. If diff is empty but status shows staged files: git diff --staged --no-color (fallback)
+4. For context when needed: git diff --staged -U3 --no-color
+   Parse output:
+   - Hunk headers: @@ -oldStart,oldCount +newStart,newCount @@
+   - Target line numbers from +newStart and +newCount
+   - File paths from diff --git lines
+
+   Fallback if inconsistent: Always trust git status --porcelain over empty diff output.
+5. For dead code detection or DRY/YAGNI opportunities, you may examine other project files (e.g., to confirm unused functions or repeated patterns). Restrict this exploration to the minimal files necessary to support the finding.
+
+## Review Policy
+
+Prioritize findings that materially improve:
+
+- Security, reliability, data integrity, privacy.
+- Correctness and performance where clearly impactful.
+- Clarity and Clean Code.
+
+Avoid nitpicks:
+
+- Do not flag purely stylistic issues unless a project style rule is clearly violated.
+- Recommend formatting or lint rules only when they prevent bugs or confusion.
+
+## Security Checklist
+
+- Map each finding to OWASP Top Ten, e.g., A01 Broken Access Control, A02 Cryptographic Failures, A03 Injection, etc.
+- For HTTP APIs, also consider OWASP API Top 10.
+- Provide actionable mitigations.
+
+## Clean Code and Clarity Checks
+
+- Prefer small, focused functions, clear names, elimination of duplication, obvious control flow.
+- Suggest local refactors near changed lines.
+- Provide minimal viable patches as examples when safe.
+- Identify dead code (unused variables, functions, imports, classes).
+- Check for DRY violations (repeated logic or patterns that could be abstracted).
+- Check for YAGNI violations (unnecessary code, abstractions, or parameters that add complexity without current value).
+
+## Output Format
+
+Write the following structure into `agent-code-review.md`:
+
+````markdown
+# Code Review Report
+
+**Iteration:** N
+**Date:** YYYY-MM-DD
+**Scope:** Staged changes only
+
+## Summary
+
+- One paragraph on overall risk and clarity.
+- Finding counts: High X, Medium Y, Low Z.
+- If no High or Medium remain and no Low blockers, state: **Verdict: good to go**.
+
+## Findings
+
+For each finding:
+
+[Severity, Impact area] path/to/file.ext, line X or lines X-Y
+- **Issue:** concise problem statement.
+- **Why it matters:** link to security, maintainability, or clarity impact.
+- **Recommendation:** specific, actionable fix.
+- **Suggested patch example, if safe:**
+
+```diff
+*** Begin Patch
+*** Update File: path/to/file.ext
+@@
+- old code
++ improved code
+*** End Patch
+```
+````
diff --git a/.copilot/skills/commitmsg/SKILL.md b/.copilot/skills/commitmsg/SKILL.md
new file mode 100644
index 0000000..eb39911
--- /dev/null
+++ b/.copilot/skills/commitmsg/SKILL.md
@@ -0,0 +1,34 @@
+---
+name: commitmsg
+description: "Propose a single git commit message for the currently staged changes."
+---
+
+# Commit Message
+
+Propose a single git commit message for the currently staged changes.
+
+## Gather context
+
+Run these commands to understand the changes:
+
+- `git diff --staged` — the actual changes
+- `git status -s` — staged file list
+- `git log -n 20 --oneline` — recent style and to avoid repetition
+- `git branch --show-current` — if it contains a ticket ID (e.g. ABC-123), prefix the subject line
+
+## Rules
+
+Use Conventional Commits. Pick the most accurate type; prefer `feat` for new behavior. Optional scope allowed.
+
+Subject: imperative, max 72 chars, no trailing period. Capture the big picture and intent, not implementation details. Optimize for future readers.
+
+Body: include bullets only when the subject alone is insufficient. Each bullet must answer "what would be unclear or risky if omitted?" Merge related items; skip internal plumbing, helpers, and test scaffolding unless they are the primary change. Wrap at 72 chars. Omit the body entirely for minor or single-focus changes.
+
+## Output
+
+```text
+[ticket] type(scope): concise subject
+
+- Important change or impact
+- Another distinct change, only if necessary
+```
diff --git a/.copilot/skills/review-pr/SKILL.md b/.copilot/skills/review-pr/SKILL.md
new file mode 100644
index 0000000..c0ee5bd
--- /dev/null
+++ b/.copilot/skills/review-pr/SKILL.md
@@ -0,0 +1,92 @@
+---
+name: review-pr
+description: "Process unresolved review comments on a GitHub PR, fix valid issues, ensure CI passes, and re-request review."
+---
+
+# Review PR Feedback Loop
+
+## Constraints
+
+ALL shell operations: `gh api` with `--jq`/`--paginate` and bash only. No Python/Node/script files. No `curl` for GitHub API. Polling loops must be inline bash `while`/`sleep`.
+
+## Arguments
+
+- `$ARGUMENTS`: PR number (default: auto-detect via `gh pr view --json number -q .number`).
+
+## Setup
+
+Extract owner/name from `gh repo view --json owner,name`. Set `IGNORED_FILE=".review-pr-ignored-${PR_NUMBER}"` and `touch` it. Run the workflow loop (max 5 iterations). Delete `$IGNORED_FILE` on exit.
+
+## Workflow
+
+### 1. Fix failing CI
+
+Run `gh pr checks`. On failure: `gh run view <run_id> --log-failed`, fix, commit, push, wait for green.
+
+### 2. Ensure bot review covers latest commit
+
+Get HEAD SHA: `gh pr view {PR_NUMBER} --json commits --jq '.commits[-1].oid'`. Bots = logins ending in `[bot]`. Fetch their latest reviews:
+
+```bash
+gh api repos/{owner}/{repo}/pulls/{PR_NUMBER}/reviews \
+  --jq '[.[] | select(.user.login | endswith("[bot]"))] | group_by(.user.login) | map(max_by(.submitted_at))'
+```
+
+If no bot review matches HEAD, request one and poll (first check 8 min, timeout 15 min, poll 60 s). GitHub's REST API fully supports requesting reviews from bot accounts — do not skip this.
+
+```bash
+gh api repos/{owner}/{repo}/pulls/{PR_NUMBER}/requested_reviewers \
+  -X POST -f "reviewers[]={bot_login}"
+
+end=$((SECONDS+900)); sleep 480
+while [ $SECONDS -lt $end ]; do
+  commit_id=$(gh api repos/{owner}/{repo}/pulls/{PR_NUMBER}/reviews \
+    --jq '[.[] | select(.user.login=="{bot}")] | max_by(.submitted_at) | .commit_id')
+  [ "$commit_id" = "$head_sha" ] && break
+  sleep 60
+done
+```
+
+Timeout → tell user to retry later and stop.
+
+### 3. Fetch unresolved threads
+
+ALWAYS re-fetch fresh each iteration. Use `gh api graphql --paginate --slurp` with `$endCursor`:
+
+```bash
+gh api graphql --paginate --slurp \
+  -f query='query($owner:String!,$repo:String!,$pr:Int!,$endCursor:String) {
+    repository(owner:$owner,name:$repo) {
+      pullRequest(number:$pr) {
+        reviewThreads(first:100,after:$endCursor) {
+          pageInfo { hasNextPage endCursor }
+          nodes { id isResolved comments(first:100){nodes{databaseId body path line author{login}}} }
+        }
+      }
+    }
+  }' \
+  -f owner="{owner}" -f repo="{repo}" -F pr={PR_NUMBER} \
+  --jq '[.[].data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false)]'
+```
+
+**Auto-resolve:** If a thread's first comment body matches any `$IGNORED_FILE` entry (`grep -qxF`), resolve via `resolveReviewThread` mutation without classifying.
+
+**Exit:** Zero unresolved threads + bot review on HEAD → success. Stop.
+
+### 4. Classify and resolve
+
+Read referenced file + context for each remaining thread, then classify:
+
+- **Already addressed / Informational / Inaccurate** — append body to `$IGNORED_FILE`, resolve (reply with brief explanation if inaccurate).
+- **Valid fix** — implement minimal change. Must meet ALL: (1) fixes a real bug — wrong behavior, data loss, security, crash, or race condition; (2) net-simpler or complexity-neutral; (3) concrete, not speculative.
+- **Nitpick / Low-value** — resolve WITHOUT implementing. Includes: style preferences not enforced by linter, docstring suggestions on clear code, subjective renames, unnecessary defensive checks, premature abstraction, "consider X instead of Y" where both work, type annotations beyond codebase norms. Append body to `$IGNORED_FILE`, reply with one-line rationale, resolve.
+
+### 5. Push fixes
+
+Stage, commit (`fix:`/`refactor:`/etc.), push, verify CI green, resolve fixed threads.
+
+### 6. Re-request bot review and loop
+
+Re-request review from the same bots and poll using the same snippet from step 2. Timeout → tell user to re-run the review-pr skill. Success → go back to step 3.
+
+Declare success when step 3 finds zero unresolved threads with bot review on HEAD. Stop at iteration 5. Report: threads resolved, fixes made, threads auto-ignored, threads remaining, CI status.
diff --git a/README.md b/README.md
index 737bba8..0721a5c 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@ Set of prompts, skills, and scripts to aid in utilizing AI coding agents in deve
   - [Claude Code](https://docs.anthropic.com/en/docs/claude-code)
   - [Gemini CLI](https://github.com/google-gemini/gemini-cli)
   - [Codex CLI](https://github.com/openai/codex)
+  - [Copilot CLI](https://docs.github.com/en/copilot/copilot-cli)
 
 ## Quick Start
 
@@ -30,6 +31,7 @@ The script detects which AI tools you have installed and walks you through insta
 | Claude Code | Markdown (`.md`) | `.claude/commands/` | `~/.claude/commands/` |
 | Gemini CLI | TOML (`.toml`) | `.gemini/commands/` | `~/.gemini/commands/` |
 | Codex CLI | Agent Skills (`SKILL.md`) | `.codex/skills/` | `~/.codex/skills/` |
+| Copilot CLI | Agent Skills (`SKILL.md`) | `.copilot/skills/` | `~/.copilot/skills/` |
 | Shared prompts | Markdown (`.md`) | `prompts/` | `~/.local/share/ai-coding-setup/prompts/` |
 
 ## Available Commands
@@ -43,6 +45,7 @@ Propose a conventional commit message for the currently staged changes. Detects
 - Claude Code: `/commitmsg`
 - Gemini CLI: `/commitmsg`
 - Codex CLI: `$commitmsg`
+- Copilot CLI: `/commitmsg`
 
 ### /review-pr
 
@@ -53,6 +56,7 @@ Process unresolved review comments on a GitHub PR, fix valid issues, ensure CI p
 - Claude Code: `/review-pr [PR_NUMBER]`
 - Gemini CLI: `/review-pr [PR_NUMBER]`
 - Codex CLI: `$review-pr [PR_NUMBER]`
+- Copilot CLI: `/review-pr [PR_NUMBER]`
 
 ### /code-refinement
 
@@ -63,6 +67,7 @@ Review staged files for code quality (KISS, DRY, YAGNI, Clean Code), fix linting
 - Claude Code: `/code-refinement`
 - Gemini CLI: `/code-refinement`
 - Codex CLI: `$code-refinement`
+- Copilot CLI: `/code-refinement`
 
 ### /code-review
 
@@ -73,6 +78,7 @@ Run a standalone code review on staged changes. Writes findings to `agent-code-r
 - Claude Code: `/code-review`
 - Gemini CLI: `/code-review`
 - Codex CLI: `$code-review`
+- Copilot CLI: `/code-review`
 
 ## Shared Prompts
 
@@ -111,6 +117,7 @@ To add a command, create the appropriate file(s) for each tool you want to suppo
 1. **Claude Code** — create `.claude/commands/command-name.md` (markdown with `$ARGUMENTS` placeholder)
 2. **Gemini CLI** — create `.gemini/commands/command-name.toml` (TOML with `description` and `prompt` fields, `{{args}}` placeholder)
 3. **Codex CLI** — create `.codex/skills/command-name/SKILL.md` (markdown with YAML front matter containing `name` and `description`)
+4. **Copilot CLI** — create `.copilot/skills/command-name/SKILL.md` (same format as Codex skills)
 
 Run `./setup` again to install.
 
@@ -121,6 +128,7 @@ Delete the command/skill from the corresponding directory:
 - Claude: `~/.claude/commands/`
 - Gemini: `~/.gemini/commands/`
 - Codex: `~/.codex/skills/`
+- Copilot: `~/.copilot/skills/`
 
 The setup script only manages commands it originally installed.
 
diff --git a/lib/lib-review-loop b/lib/lib-review-loop
index 234e344..0f994dd 100644
--- a/lib/lib-review-loop
+++ b/lib/lib-review-loop
@@ -38,7 +38,7 @@ fi
 PROMPTS_DIR="${AI_CODING_SETUP_PROMPTS_DIR:-$HOME/.local/share/ai-coding-setup/prompts}"
 
 # Valid agent names for --editor / --reviewer flags
-VALID_AGENTS="claude codex gemini"
+VALID_AGENTS="claude codex gemini copilot"
 
 # Filenames that review loops create — never treat as agent artifacts
 KNOWN_REVIEW_FILES="agent-code-review.md agent-review-summary.md feedback-plan.md plan-review-summary.md"
@@ -136,12 +136,14 @@ validate_positive_int() {
 # ---- agent execution ------------------------------------------------------
 
 # Run Claude Code with a prompt and optional tool restrictions.
+# Disables all MCP servers to keep autonomous runs scoped to local work.
 #   $1 — prompt text
 #   $2 — comma-separated allowed tools (default: Edit,Read,Write,Bash,Grep,Glob)
 run_claude() {
     local prompt="$1"
     local tools="${2:-Edit,Read,Write,Bash,Grep,Glob}"
-    claude -p "$prompt" --allowedTools "$tools"
+    claude -p "$prompt" --allowedTools "$tools" \
+        --strict-mcp-config --mcp-config '{}'
 }
 
 # Run Codex CLI with a prompt.  Wraps the prompt with a preamble that prevents
@@ -152,7 +154,7 @@ run_codex() {
     local wrapped="Execute the following task now. Do not introduce yourself. Begin immediately.
 
 $prompt"
-    echo "$wrapped" | codex exec --full-auto -c 'mcp_servers={}' -
+    echo "$wrapped" | codex exec --full-auto --config 'mcp_servers={}' -
 }
 
 # Run Gemini CLI with a prompt in non-interactive headless mode.
@@ -166,17 +168,34 @@ run_gemini() {
         2> >(grep -v -E 'Warning:.*deprecated|YOLO mode|Session cleanup disabled|Loaded cached credentials' >&2)
 }
 
+# Run Copilot CLI with a prompt in non-interactive autonomous mode.
+# Uses --autopilot for multi-step execution and --yolo for auto-approval.
+# Disables MCP servers to keep autonomous runs scoped to local review work.
+#   $1 — prompt text
+run_copilot() {
+    local prompt="$1"
+    local -a mcp_flags=(--disable-builtin-mcps)
+    local config="$HOME/.copilot/mcp-config.json"
+    if [[ -f "$config" ]]; then
+        while IFS= read -r name; do
+            mcp_flags+=(--disable-mcp-server "$name")
+        done < <(jq -r '.mcpServers // {} | keys[]' "$config" 2>/dev/null)
+    fi
+    copilot -p "$prompt" --autopilot --yolo "${mcp_flags[@]}"
+}
+
 # Dispatch to the appropriate agent runner.
-#   $1 — agent name ("claude", "codex", or "gemini")
+#   $1 — agent name ("claude", "codex", "gemini", or "copilot")
 #   $2 — prompt text
 #   $3 — allowed tools (only used by Claude; ignored by others)
 run_agent() {
     local agent="$1" prompt="$2" tools="${3:-}"
     case "$agent" in
-        claude) run_claude "$prompt" "$tools" ;;
-        codex)  run_codex "$prompt" ;;
-        gemini) run_gemini "$prompt" ;;
-        *)      echo -e "${RED}ERROR: Unknown agent: $agent${NC}"; return 1 ;;
+        claude)  run_claude "$prompt" "$tools" ;;
+        codex)   run_codex "$prompt" ;;
+        gemini)  run_gemini "$prompt" ;;
+        copilot) run_copilot "$prompt" ;;
+        *)       echo -e "${RED}ERROR: Unknown agent: $agent${NC}"; return 1 ;;
     esac
 }
 
@@ -192,9 +211,10 @@ validate_tools() {
     fi
     if [[ ${#missing[@]} -gt 0 ]]; then
         echo -e "${RED}ERROR: Missing required tools: ${missing[*]}${NC}"
-        echo "  Install Claude Code: https://docs.anthropic.com/en/docs/claude-code"
-        echo "  Install Codex CLI:   https://github.com/openai/codex"
-        echo "  Install Gemini CLI:  https://github.com/google-gemini/gemini-cli"
+        echo "  Install Claude Code:  https://docs.anthropic.com/en/docs/claude-code"
+        echo "  Install Codex CLI:    https://github.com/openai/codex"
+        echo "  Install Gemini CLI:   https://github.com/google-gemini/gemini-cli"
+        echo "  Install Copilot CLI:  https://docs.github.com/en/copilot/copilot-cli"
         exit 1
     fi
 }
diff --git a/setup b/setup
index 054e287..fee78cc 100755
--- a/setup
+++ b/setup
@@ -4,7 +4,7 @@ set -euo pipefail
 # ---------------------------------------------------------------------------
 # ai-coding-setup installer
 # Installs AI coding agent commands/skills for Claude Code, Gemini CLI,
-# and Codex CLI from this repo into user-level directories.
+# Codex CLI, and Copilot CLI from this repo into user-level directories.
 # ---------------------------------------------------------------------------
 
 RED='\033[0;31m'
@@ -181,6 +181,10 @@ is_mcp_configured() {
             [[ -f "$HOME/.codex/config.toml" ]] \
                 && grep -qF "[mcp_servers.${name}]" "$HOME/.codex/config.toml" 2>/dev/null
             ;;
+        copilot)
+            [[ -f "$HOME/.copilot/mcp-config.json" ]] \
+                && jq -e --arg n "$name" '.mcpServers[$n]' "$HOME/.copilot/mcp-config.json" &>/dev/null
+            ;;
     esac
 }
 
@@ -196,9 +200,18 @@ add_mcp_server() {
         set -- "/c" "$@"
     fi
     case "$tool" in
-        claude) claude mcp add --scope user "$name" -- "$cmd" "$@" 2>/dev/null ;;
-        gemini) gemini mcp add --scope user "$name" "$cmd" "$@" 2>/dev/null ;;
-        codex)  codex mcp add "$name" -- "$cmd" "$@" 2>/dev/null ;;
+        claude)  claude mcp add --scope user "$name" -- "$cmd" "$@" 2>/dev/null ;;
+        gemini)  gemini mcp add --scope user "$name" "$cmd" "$@" 2>/dev/null ;;
+        codex)   codex mcp add "$name" -- "$cmd" "$@" 2>/dev/null ;;
+        copilot)
+            local config="$HOME/.copilot/mcp-config.json"
+            [[ -f "$config" ]] || echo '{"mcpServers":{}}' > "$config"
+            local args_json updated
+            args_json=$(printf '%s\n' "$@" | jq -R . | jq -s .)
+            updated=$(jq --arg n "$name" --arg c "$cmd" --argjson a "$args_json" \
+                '.mcpServers[$n] = {"type":"local","command":$c,"args":$a}' "$config")
+            echo "$updated" | jq . > "$config"
+            ;;
     esac
 }
 
@@ -743,6 +756,27 @@ multi_agent = true' "$config_file"
     fi
 }
 
+# ---- Copilot CLI settings configuration -------------------------------------
+
+configure_copilot_settings() {
+    local config_file="$HOME/.copilot/config.json"
+
+    echo ""
+    echo -e "${BOLD}── Copilot CLI Settings ──${NC}"
+
+    mkdir -p "$HOME/.copilot"
+    if [[ ! -f "$config_file" ]]; then
+        echo '{}' > "$config_file"
+    fi
+
+    if ! jq empty "$config_file" 2>/dev/null; then
+        print_warning "$HOME/.copilot/config.json is not valid JSON — skipping"
+        return
+    fi
+
+    echo -e "  ${DIM}No settings to configure${NC}"
+}
+
 # ---- review loop script installer -----------------------------------------
 #
 # Symlinks executable scripts from bin/ to ~/.local/bin/ so they are on PATH.
@@ -885,8 +919,8 @@ done
 
 # ---- prerequisite checks --------------------------------------------------
 
-if [[ ! -d ".claude/commands" ]] && [[ ! -d ".gemini/commands" ]] && [[ ! -d ".codex/skills" ]]; then
-    print_error "No command directories found (.claude/commands, .gemini/commands, .codex/skills)."
+if [[ ! -d ".claude/commands" ]] && [[ ! -d ".gemini/commands" ]] && [[ ! -d ".codex/skills" ]] && [[ ! -d ".copilot/skills" ]]; then
+    print_error "No command directories found (.claude/commands, .gemini/commands, .codex/skills, .copilot/skills)."
     print_error "Please run this script from the ai-coding-setup repository root."
     exit 1
 fi
@@ -930,6 +964,10 @@ if command -v codex &>/dev/null || [[ -d "$HOME/.codex" ]]; then
     detected_tools+=("codex")
 fi
 
+if command -v copilot &>/dev/null || [[ -d "$HOME/.copilot" ]]; then
+    detected_tools+=("copilot")
+fi
+
 if [[ ${#detected_tools[@]} -eq 0 ]]; then
     print_error "No supported AI coding tools detected."
     echo ""
@@ -937,6 +975,7 @@ if [[ ${#detected_tools[@]} -eq 0 ]]; then
     echo "  - Claude Code:  https://docs.anthropic.com/en/docs/claude-code"
     echo "  - Gemini CLI:   https://github.com/google-gemini/gemini-cli"
     echo "  - Codex CLI:    https://github.com/openai/codex"
+    echo "  - Copilot CLI:  https://docs.github.com/en/copilot/copilot-cli"
     echo ""
     exit 1
 fi
@@ -950,9 +989,10 @@ echo ""
 for i in "${!detected_tools[@]}"; do
     tool="${detected_tools[$i]}"
     case "$tool" in
-        claude) echo -e "  ${BOLD}$((i + 1)))${NC} Claude Code" ;;
-        gemini) echo -e "  ${BOLD}$((i + 1)))${NC} Gemini CLI" ;;
-        codex)  echo -e "  ${BOLD}$((i + 1)))${NC} Codex CLI" ;;
+        claude)  echo -e "  ${BOLD}$((i + 1)))${NC} Claude Code" ;;
+        gemini)  echo -e "  ${BOLD}$((i + 1)))${NC} Gemini CLI" ;;
+        codex)   echo -e "  ${BOLD}$((i + 1)))${NC} Codex CLI" ;;
+        copilot) echo -e "  ${BOLD}$((i + 1)))${NC} Copilot CLI" ;;
     esac
 done
 
@@ -1002,6 +1042,13 @@ for tool in "${selected_tools[@]}"; do
             configure_codex_settings
             configure_mcp "codex" "Codex CLI" "codex"
             ;;
+        copilot)
+            install_commands "Copilot CLI Skills" \
+                ".copilot/skills" "$HOME/.copilot/skills" \
+                "skill" "$MD_MARKER" "/" "get_skill_description"
+            configure_copilot_settings
+            configure_mcp "copilot" "Copilot CLI" "copilot"
+            ;;
     esac
 done
 
@@ -1095,7 +1142,7 @@ if [[ ${#review_loop_scripts[@]} -gt 0 ]] && [[ ! -f "$config_file" ]]; then
     # code changes) and codex/gemini for reviewing (second opinion), but fall
     # back to the same agent for both roles if only one tool is available.
     _default_editor="" _default_reviewer=""
-    for _t in claude codex gemini; do
+    for _t in claude codex gemini copilot; do
         [[ " ${selected_tools[*]} " == *" $_t "* ]] || continue
         [[ -z "$_default_editor" ]] && _default_editor="$_t"
         [[ -n "$_default_editor" ]] && [[ "$_t" != "$_default_editor" ]] && _default_reviewer="$_t"
@@ -1115,10 +1162,10 @@ if [[ ${#review_loop_scripts[@]} -gt 0 ]] && [[ ! -f "$config_file" ]]; then
 # ai-coding-setup — default agent configuration for review loops.
 # These defaults can be overridden per-invocation with --editor / --reviewer flags.
 
-# Agent for editing/implementation (claude, codex, gemini)
+# Agent for editing/implementation (claude, codex, gemini, copilot)
 EDITOR_AGENT=$_default_editor
 
-# Agent for reviewing (claude, codex, gemini)
+# Agent for reviewing (claude, codex, gemini, copilot)
 REVIEWER_AGENT=$_default_reviewer
 CONF
         print_success "Created $config_file"
@@ -1136,9 +1183,10 @@ echo "Use your commands in:"
 
 for tool in "${selected_tools[@]}"; do
     case "$tool" in
-        claude) echo -e "  Claude Code — type ${BOLD}/command-name${NC} in the prompt" ;;
-        gemini) echo -e "  Gemini CLI  — type ${BOLD}/command-name${NC} in the prompt" ;;
-        codex)  echo -e "  Codex CLI   — type ${BOLD}\$skill-name${NC} to invoke a skill" ;;
+        claude)  echo -e "  Claude Code  — type ${BOLD}/command-name${NC} in the prompt" ;;
+        gemini)  echo -e "  Gemini CLI   — type ${BOLD}/command-name${NC} in the prompt" ;;
+        codex)   echo -e "  Codex CLI    — type ${BOLD}\$skill-name${NC} to invoke a skill" ;;
+        copilot) echo -e "  Copilot CLI  — type ${BOLD}/skill-name${NC} in the prompt" ;;
     esac
 done
 
