Using gh skill for a personal project is straightforward. Using it for a team of ten developers across three different AI agents — that's where you start running into architectural decisions.
This article documents the skill management system I've built and refined over the past several months: repository structure, versioning strategy, CI/CD automation, and the important differences in how different agents interpret the same skill definitions.
Why Skill Management Needs Architecture
The common early mistake is a single flat repository: one skill.yaml, a handful of Markdown files, everything in a pile. It works initially. Then a backend engineer adds a database pattern that breaks the frontend agent's context. Or two conflicting instructions about TypeScript strictness appear in the same skill set. The team starts ignoring the shared skills because they produce inconsistent behavior.
The root issue: skills have scope, and that scope needs to be modeled explicitly.
Repository Structure That Scales
Here's the structure I use for production:
team-skills/
├── skill.yaml
├── README.md
├── CHANGELOG.md
├── .github/
│ └── workflows/
│ ├── validate.yml
│ └── release.yml
├── base/
│ ├── code-style.md
│ └── git-workflow.md
├── frontend/
│ ├── react-patterns.md
│ └── testing-frontend.md
├── backend/
│ ├── api-design.md
│ └── database-patterns.md
└── agent-overrides/
├── claude-code-specific.md
└── copilot-hints.md
The skill.yaml uses profiles to bundle skills by role:
name: team-skills
version: 2.1.0
description: "Team coding standards and workflows"
maintainer: "platform-team@example.com"
agents:
- claude-code
- copilot
- cursor
- gemini-cli
profiles:
frontend:
skills:
- base/code-style.md
- base/git-workflow.md
- frontend/react-patterns.md
- frontend/testing-frontend.md
agents: [claude-code, copilot, cursor]
backend:
skills:
- base/code-style.md
- base/git-workflow.md
- backend/api-design.md
- backend/database-patterns.md
agents: [claude-code, copilot, cursor, gemini-cli]
fullstack:
extends: [frontend, backend]
agent_overrides:
claude-code:
append: agent-overrides/claude-code-specific.md
copilot:
append: agent-overrides/copilot-hints.mdDevelopers install the profile matching their role:
gh skill install team/team-skills --profile frontend
gh skill install team/team-skills --profile backendSemantic Versioning for Skills
Treat skill changes the same way you'd treat API changes:
- MAJOR: Rewrites or removals that change AI behavior substantially. Teams should review before upgrading.
- MINOR: New skills added, existing behavior unchanged.
- PATCH: Typo fixes, wording improvements, no functional changes.
Your CHANGELOG.md should call out which agents are affected:
## [2.1.0] - 2026-04-15
### Added
- `backend/database-patterns.md`: PostgreSQL jsonb handling guidelines
- Agents affected: Claude Code, Copilot, Cursor
- `agent-overrides/claude-code-specific.md`: Standard PreToolUse hook configuration
- Agents affected: Claude Code only
### Changed
- `base/code-style.md`: TypeScript strict mode is now required
- Breaking change for all agents
- Migration: Add `"strict": true` to tsconfig.jsonCI/CD Pipeline for Skill Validation
Manual review isn't enough for skill quality at scale. Here's the validation workflow:
# .github/workflows/validate.yml
name: Validate Skills
on:
pull_request:
paths:
- '**.md'
- 'skill.yaml'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup gh skill
run: gh extension install github-actions/gh-skills
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Validate structure
run: gh skill validate
- name: Check internal links
run: gh skill lint --check-links
- name: Dry-run for each agent
run: |
gh skill dry-run --agent claude-code
gh skill dry-run --agent copilot
gh skill dry-run --agent cursor
- name: Enforce CHANGELOG update
run: |
if git diff --name-only origin/main | grep -q "\.md$"; then
if ! git diff --name-only origin/main | grep -q "CHANGELOG.md"; then
echo "❌ Skill files changed without CHANGELOG update"
exit 1
fi
fiThe release workflow handles tagging and team notification:
# .github/workflows/release.yml
name: Release Skills
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Skills Release ${{ github.ref }}
body_path: CHANGELOG.md
- name: Notify team
run: |
curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
-d "{\"text\": \"🎯 team-skills ${{ github.ref }} released. Run: gh skill update team-skills\"}"Writing Agent-Specific Layers
The most impactful — and most overlooked — aspect of multi-agent skill management is that different agents have different interpretation depths.
What Claude Code Handles Well
Claude Code can follow rich, conditional instructions. Use it for the things that actually need agentic reasoning:
<!-- agent-overrides/claude-code-specific.md -->
## PreToolUse hooks
Confirm before writing to any of these paths:
- `production.env`
- `database/migrations/`
- `src/auth/`
## Tool restrictions
In production environments (NODE_ENV=production), do not run:
- `npm run migrate`
- `git push --force`
- Any SQL DELETE without a WHERE clause
## Code review workflow
When asked to review code, execute in this order:
1. Type check: `tsc --noEmit`
2. Lint: `eslint src/`
3. Test: `npm test`
4. Security scan: `npm audit --audit-level=moderate`
Only report the next step after each passes.Writing for Copilot's Simpler Parser
Copilot applies Markdown instructions more loosely. Short, direct imperatives work better than conditional logic:
<!-- agent-overrides/copilot-hints.md -->
## Style Rules
- Use TypeScript. Never use `any`
- Prefer arrow functions
- All error handlers must include a catch block with a log statement
- Comments in Japanese
## Never Do
- Leave console.log in committed code
- Hardcode URLs, tokens, or credentials
- Return undefined without a null checkCursor Integration
Cursor reads from .cursor/skills/ when installed via gh skill. If your project already has .cursorrules, use the --no-override-rules flag to avoid conflicts:
gh skill install team/team-skills --agent cursor --no-override-rulesMonorepo Configuration
For monorepos where packages need different skill sets:
monorepo/
├── skill.yaml # Shared baseline
├── packages/
│ ├── frontend/
│ │ └── skill.yaml # Extends root, adds frontend-specific skills
│ └── backend/
│ └── skill.yaml # Extends root, adds backend-specific skills
# packages/frontend/skill.yaml
extends: ../../skill.yaml
name: frontend-skills
additional_skills:
- skills/react-specific.md
- skills/storybook-patterns.mdThe Unexpected Benefit
What surprised me most about running skills through a Git PR workflow is that it makes the quality of AI instructions visible for the first time. When a skill definition is vague or contradictory, someone catches it in code review — the same review loop that keeps code quality up.
Linters enforce coding style automatically. But the quality of what you tell AI agents has always been invisible, left to individual taste. Treating SKILL.md as a versioned, reviewed artifact changes that. The skills become team knowledge, not personal config.
Start with the structure and CHANGELOG convention. The CI pipeline can come later. But having those two habits in place from the beginning makes everything else much easier to add.