Skip to content

Feat - Add GitHub Copilot target (#149)#154

Open
momostallion wants to merge 13 commits into
LobsterTrap:mainfrom
StateFarmIns:feat/copilot-target
Open

Feat - Add GitHub Copilot target (#149)#154
momostallion wants to merge 13 commits into
LobsterTrap:mainfrom
StateFarmIns:feat/copilot-target

Conversation

@momostallion

@momostallion momostallion commented May 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Add GitHub Copilot as a target assistant, split into two variants to match Copilot's two runtimes:

  • copilot-cli — GitHub Copilot CLI
  • copilot-vscode — Copilot in VS Code

Both share the same project (.github/) and user (~/.copilot/) files and differ in command and MCP handling at user scope.

Layout:

  • Skills → .github/skills/<name>/SKILL.md (project) or ~/.copilot/skills/<name>/SKILL.md (user), with required name + description frontmatter — both variants
  • Agents → .agent.md (.github/agents/ project, ~/.copilot/agents/ user) — both variants
  • Commands → .prompt.md
    • copilot-cli: .github/prompts/ (project) and ~/.copilot/prompts/ (user)
    • copilot-vscode: .github/prompts/ (project only — VS Code has no user-scope prompts location)

MCP handling:

  • copilot-cli writes MCP servers with the mcpServers key (~/.copilot/mcp-config.json at user scope)
  • copilot-vscode writes to .vscode/mcp.json using VS Code's servers key
  • VS Code has no user-scope location for slash commands or MCP, so those are skipped with a warning when installing copilot-vscode at user scope
  • When no assistant is selected explicitly, copilot-vscode is preferred over copilot-cli to avoid writing the same project files twice

Related Issues

Fixes #149

Test Plan

  • 42 unit tests covering both variants: path resolution (project/user/default scope), skill generation (basic, applyTo, globs, missing source), removal, commands, agents, MCP transform/merge/remove for VS Code vs CLI, the shared-.github/ idempotency case, and target metadata
  • End-to-end tested with lola install rosa-skills -a copilot-vscode -s user — skills load in VS Code Copilot Chat

Checklist

  • Tests pass (pytest) — 1003 passed
  • Linting passes (ruff check src tests + ruff format --check)
  • Type checking passes (ty check)

AI Disclosure

AI-assisted with GitHub Copilot (Claude Opus 4.8)

Summary by CodeRabbit

  • New Features

    • Added GitHub Copilot support for generating skills, commands/prompts, agents, and project instructions with Copilot-compatible metadata and layout.
  • Documentation

    • Updated assistant reference and generation notes to include Copilot and its frontmatter behavior (name and description handling).
  • Tests

    • Added comprehensive tests covering Copilot path scopes, generation success/failure cases, frontmatter handling, filename conventions, and removal/legacy cleanup behaviors.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a CopilotTarget implementing GitHub Copilot on-disk layouts (skills, prompts, agents, global instructions, MCP), wires it into TARGETS and exports, updates AGENTS.md, and adds pytest coverage for generation, removal, and path resolution.

Changes

GitHub Copilot target support

Layer / File(s) Summary
CopilotTarget implementation
src/lola/targets/copilot.py
Defines CopilotTarget with scope-aware path helpers; generates skills (SKILL.md) with Copilot YAML frontmatter (name, description, applyTo from applyTo or globs); generates/removes commands (.prompt.md) and agents (.agent.md); performs legacy cleanup and sets name="copilot", supports_agents=True, INSTRUCTIONS_FILE="copilot-instructions.md".
Target registration and documentation
src/lola/targets/__init__.py, AGENTS.md
Imports and registers CopilotTarget in TARGETS["copilot"], exports it in __all__, and documents Copilot's output paths and frontmatter modifications in AGENTS.md.
Test coverage
tests/test_copilot_target.py
Adds pytest tests for project/user/default path resolution; positive/negative skill generation (including missing description, globs→applyTo); command and agent generation and removal; filename helpers; legacy-file cleanup; and CopilotTarget metadata assertions.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant CopilotTarget
  participant FileSystem
  Caller->>CopilotTarget: generate_skill(source_path, dest_path, skill_name)
  CopilotTarget->>FileSystem: read source SKILL.md
  CopilotTarget->>CopilotTarget: parse frontmatter (name, description, applyTo/globs)
  CopilotTarget->>FileSystem: create skill dest dir
  CopilotTarget->>FileSystem: write SKILL.md (Copilot YAML + body)
  CopilotTarget-->>Caller: return True/False

  Caller->>CopilotTarget: remove_skill(dest_path, skill_name)
  CopilotTarget->>FileSystem: delete skill dir and legacy instructions file if present
  CopilotTarget-->>Caller: return True/False

  Caller->>CopilotTarget: generate_command(...)
  CopilotTarget->>FileSystem: write <cmd>.prompt.md (and remove legacy variant on uninstall)
  CopilotTarget-->>Caller: return True/False

  Caller->>CopilotTarget: generate_agent(...)
  CopilotTarget->>FileSystem: write <agent>.agent.md (and remove legacy variant on uninstall)
  CopilotTarget-->>Caller: return True/False
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • SecKatie

Poem

🐰 A Copilot joins the fold,
Skills nest in .github bright and bold,
Prompts and agents find their place,
Frontmatter tended with gentle grace,
One rabbit hops — new paths unfold.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Feat - Add GitHub Copilot target (#149)' clearly and concisely describes the main change: adding a new Copilot target to the lola tool.
Linked Issues check ✅ Passed The PR implements all core objectives from issue #149: registers 'copilot' target in TARGETS registry, maps skills/commands/agents to Copilot paths, preserves applyTo frontmatter, requires name+description for skills, and includes comprehensive tests validating all functionality.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the GitHub Copilot target feature: new CopilotTarget implementation, target registration, documentation updates, and comprehensive test coverage. No unrelated modifications detected.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
tests/test_copilot_target.py (1)

193-214: ⚡ Quick win

Add a regression test for legacy .instructions.md cleanup.

There’s no test that verifies removing .../.github/instructions/<skill>.instructions.md. Adding one would guard backward-compat uninstall behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_copilot_target.py` around lines 193 - 214, Add a regression test
that verifies CopilotTarget.remove_skill removes legacy instruction files:
create a test (e.g., test_remove_skill_removes_legacy_instructions) which sets
up tmp_path / "skills" / "my-skill" with SKILL.md and also creates the legacy
file at dest / ".github" / "instructions" / "my-skill.instructions.md", call
CopilotTarget().remove_skill(dest, "my-skill"), assert it returns True and both
the skill_dir and the legacy instructions file no longer exist; this ensures
CopilotTarget.remove_skill handles legacy `.instructions.md` cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@AGENTS.md`:
- Around line 148-151: Section heading currently claims "Agent frontmatter is
modified during generation" but the Copilot bullet describes changes to skill
frontmatter; update the documentation to avoid the semantic mismatch by either
renaming the section heading to mention both "agent and skill frontmatter" or
moving the Copilot bullet into the relevant "skill frontmatter" section so the
Copilot note references the correct scope; update any nearby headings or bullets
that refer to "agent" only to ensure consistency with the Copilot bullet and
verify the Claude Code and Cursor bullets remain under the agent-focused
portion.

In `@src/lola/targets/copilot.py`:
- Around line 109-114: The legacy_file path is constructed with a duplicated
".github" segment causing paths like ".../.github/.github/instructions/...";
update the construction of legacy_file (the variable currently set from
dest_path.parent / ".github" / "instructions" / f"{skill_name}.instructions.md")
to avoid adding the extra ".github" segment — e.g., use dest_path.parent /
"instructions" / f"{skill_name}.instructions.md" or otherwise derive the correct
repo root so legacy_file points to the single ".github/instructions" location;
modify the assignment of legacy_file accordingly to remove the duplicate
segment.
- Around line 80-90: The code builds Copilot frontmatter with "name +
description" required but currently proceeds when frontmatter["description"] is
missing; update the validation before constructing copilot_fm (using variables
skill_name and frontmatter) to enforce that frontmatter contains a non-empty
"description" — if missing/empty, raise a clear exception or return an error
(e.g., ValueError or a logged failure) to prevent writing SKILL.md with invalid
frontmatter; ensure copilot_fm always includes the description field when
proceeding.

In `@tests/test_copilot_target.py`:
- Around line 110-126: The test test_generate_skill_basic currently writes a
SKILL.md without required frontmatter; update it so the source SKILL.md includes
YAML frontmatter with both name and description (e.g., add a leading/frontmatter
block containing name: my-skill and description: "..." before the body) so
CopilotTarget.generate_skill is exercising the valid contract, then assert
result is True and check that both name and description appear in the generated
file; alternatively, if you intend to test rejection, change the assertion to
expect False and verify no output file was created, but keep the test name and
references to test_generate_skill_basic and CopilotTarget.generate_skill
consistent.

---

Nitpick comments:
In `@tests/test_copilot_target.py`:
- Around line 193-214: Add a regression test that verifies
CopilotTarget.remove_skill removes legacy instruction files: create a test
(e.g., test_remove_skill_removes_legacy_instructions) which sets up tmp_path /
"skills" / "my-skill" with SKILL.md and also creates the legacy file at dest /
".github" / "instructions" / "my-skill.instructions.md", call
CopilotTarget().remove_skill(dest, "my-skill"), assert it returns True and both
the skill_dir and the legacy instructions file no longer exist; this ensures
CopilotTarget.remove_skill handles legacy `.instructions.md` cleanup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 70a605d0-6d82-4a2a-8a1c-4ab30f3cd9a2

📥 Commits

Reviewing files that changed from the base of the PR and between 560efa3 and ade69d5.

📒 Files selected for processing (4)
  • AGENTS.md
  • src/lola/targets/__init__.py
  • src/lola/targets/copilot.py
  • tests/test_copilot_target.py

Comment thread AGENTS.md
Comment thread src/lola/targets/copilot.py
Comment thread src/lola/targets/copilot.py
Comment thread tests/test_copilot_target.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lola/targets/copilot.py (1)

109-120: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid early return so legacy skill artifacts are always cleaned up.

Line 112 returns immediately after removing skill_dir, so legacy *.instructions.md cleanup is skipped when both files exist.

Suggested fix
     skill_dir = dest_path / skill_name
+    removed = False
     if skill_dir.exists():
         shutil.rmtree(skill_dir)
-        return True
+        removed = True
     # Legacy cleanup: old .instructions.md format
     legacy_file = (
             dest_path.parent / "instructions" / f"{skill_name}.instructions.md"
     )
     if legacy_file.exists():
         legacy_file.unlink()
-        return True
-    return False
+        removed = True
+    return removed
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lola/targets/copilot.py` around lines 109 - 120, The cleanup currently
returns immediately after removing skill_dir (using shutil.rmtree), skipping
legacy artifact removal; instead, remove the early return and implement a
boolean flag (e.g., removed = False) that is set to True when skill_dir is
removed and again when legacy_file (dest_path.parent / "instructions" /
f"{skill_name}.instructions.md") is unlinked, so both cleanup steps run and the
function returns True if either artifact was removed and False otherwise.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/lola/targets/copilot.py`:
- Around line 109-120: The cleanup currently returns immediately after removing
skill_dir (using shutil.rmtree), skipping legacy artifact removal; instead,
remove the early return and implement a boolean flag (e.g., removed = False)
that is set to True when skill_dir is removed and again when legacy_file
(dest_path.parent / "instructions" / f"{skill_name}.instructions.md") is
unlinked, so both cleanup steps run and the function returns True if either
artifact was removed and False otherwise.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5f901f76-3eca-4c42-933d-cd749b25981b

📥 Commits

Reviewing files that changed from the base of the PR and between ade69d5 and add334b.

📒 Files selected for processing (3)
  • AGENTS.md
  • src/lola/targets/copilot.py
  • tests/test_copilot_target.py

@momostallion momostallion force-pushed the feat/copilot-target branch 2 times, most recently from 0356849 to 978b12d Compare May 25, 2026 01:57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@AGENTS.md`:
- Line 142: Docs mismatch: the Copilot section of AGENTS.md omits user-scope
command/agent paths in the table and incorrectly states that agent frontmatter
is modified while the implementation's generate_agent is a passthrough. Update
AGENTS.md to add user-scope paths for commands and agents to the table (include
the same user ~/.copilot/skills and ~/.copilot/agents patterns) and change the
frontmatter text to reflect the actual behavior of generate_agent (either state
that generate_agent is passthrough and does not modify frontmatter, or if you
prefer to change behavior instead, implement frontmatter modification inside the
generate_agent code path so the docs and implementation match). Ensure you
reference generate_agent and the "frontmatter" wording in the updated text so
reviewers can verify consistency.

In `@src/lola/targets/copilot.py`:
- Around line 47-53: Both user-scope paths are wrong: update
get_instructions_path to use the Copilot user folder (Path.home() / ".copilot" /
self.INSTRUCTIONS_FILE) instead of "~/.github/<...>", and update get_mcp_path to
write the user MCP to the Copilot user config (when scope == "user" return
Path.home() / ".copilot" / "mcp.json") instead of "~/.github/copilot/mcp.json";
modify the base calculation in both get_instructions_path and get_mcp_path to
choose these user locations when scope == "user".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 324f5be9-4caf-49e0-b447-63327e35267f

📥 Commits

Reviewing files that changed from the base of the PR and between 0356849 and 978b12d.

📒 Files selected for processing (4)
  • AGENTS.md
  • src/lola/targets/__init__.py
  • src/lola/targets/copilot.py
  • tests/test_copilot_target.py

Comment thread AGENTS.md Outdated
Comment thread src/lola/targets/copilot.py Outdated
@mrbrandao mrbrandao added enhancement New feature or request good first issue Good for newcomers labels May 25, 2026
@mrbrandao mrbrandao requested a review from SecKatie May 25, 2026 17:40
@momostallion momostallion force-pushed the feat/copilot-target branch from d11643a to 7993ea1 Compare May 28, 2026 22:48
@SecKatie

Copy link
Copy Markdown
Collaborator

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7993ea157d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lola/targets/copilot.py
Comment thread src/lola/targets/copilot.py Outdated
Comment thread src/lola/targets/copilot.py Outdated
@momostallion momostallion force-pushed the feat/copilot-target branch 2 times, most recently from 8b84efe to ef12a48 Compare June 3, 2026 04:51
@momostallion momostallion force-pushed the feat/copilot-target branch from 2b7a788 to 3c6fdd1 Compare June 9, 2026 13:52
@momostallion

Copy link
Copy Markdown
Contributor Author

@SecKatie Hello! Just wondering if you had a chance to review this PR, I think I have made all the changes requested from the feedback.

@momostallion momostallion force-pushed the feat/copilot-target branch from 3c6fdd1 to 659769a Compare June 9, 2026 17:48
@momostallion momostallion force-pushed the feat/copilot-target branch from 659769a to 898a7a6 Compare June 10, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] - Add GitHub Copilot target

3 participants