Skip to content

Skill Consolidation Design โ€‹

Date: 2026-03-28 Goal: Eliminate duplicate AI agent skills across .github/skills/, .gemini/skills/, and .claude/skills/ by establishing a single canonical source in tooling/skills/ with automated sync to each tool's expected location.

Problem โ€‹

Custom skills (pr-workbench, monitor-ci) are manually duplicated across three directories:

DirectoryUsed byFormat
.github/skills/GitHub Copilot / VS CodeSKILL.md, YAML frontmatter, $ARGUMENTS
.github/prompts/GitHub Copilot slash commands.prompt.md, YAML frontmatter, ${input:args}
.gemini/skills/Gemini CLIskill.md, YAML frontmatter, $ARGUMENTS
.gemini/commands/Gemini CLI slash commands.toml, TOML format,
.claude/skills/Claude Code skillsSKILL.md, YAML frontmatter, $ARGUMENTS

All three skill directories currently have byte-for-byte identical content (except filename casing). Claude Code has nothing โ€” its commands directory doesn't exist.

Scope โ€‹

In scope: Custom project skills only โ€” pr-workbench and monitor-ci (plus any future custom skills).

Out of scope: Nx plugin skills (nx-workspace, nx-generate, nx-run-tasks, nx-plugins, nx-import, link-workspace-packages). These are managed by the nrwl/nx-ai-agents-config marketplace plugin and should not be touched by the sync script.

Design โ€‹

Canonical Source โ€‹

tooling/skills/<skill-name>/skill.md โ€” the single source of truth.

Canonical format matches the existing .github/skills/ convention:

markdown
---
name: <skill-name>
description: <trigger description>
command: true  # optional โ€” generate slash command files for this skill
---

# Skill Title

...skill content using $ARGUMENTS for user input...

Supporting files (scripts, references) live alongside the skill file:

tooling/skills/
  pr-workbench/
    skill.md
  monitor-ci/
    skill.md
    scripts/
      ci-poll-decide.mjs
      ci-state-update.mjs
    references/
      fix-flows.md

Sync Script โ€‹

tooling/scripts/sync-skills.js โ€” a Node.js script (ESM, no external deps) that reads tooling/skills/ and writes to the three target directories.

Run via: npm run sync:skills (new script in root package.json)

Sync Targets โ€‹

For each skill in tooling/skills/:

1. .github/skills/<name>/SKILL.md

  • Rename skill.md to SKILL.md
  • Prepend auto-sync comment
  • Copy supporting files (scripts/, references/) as-is with auto-sync comment where applicable

2. .gemini/skills/<name>/skill.md

  • Direct copy (canonical format matches Gemini's)
  • Prepend auto-sync comment
  • Copy supporting files as-is

3. .claude/skills/<name>/SKILL.md

  • Rename skill.md to SKILL.md (Claude Code convention)
  • Prepend auto-sync comment
  • Copy supporting files (scripts/, references/) as-is โ€” Claude Code supports subdirectories in skills

Command Generation โ€‹

For skills with command: true in frontmatter:

1. .github/prompts/<name>.prompt.md

  • YAML frontmatter with description and argument-hint fields
  • Replace $ARGUMENTS with ${input:args} in body
  • Prepend auto-sync comment

2. .gemini/commands/<name>.toml

  • TOML format with description string and prompt triple-quoted string
  • Replace $ARGUMENTS with in body
  • Escape backslashes for TOML string embedding

3. Claude Code

  • No separate command file needed โ€” Claude Code skills are invocable as /skill-name by default

Auto-Sync Comment โ€‹

Every generated file gets this as the first line:

markdown
<!-- AUTO-SYNCED from tooling/skills/<name>/skill.md โ€” do not edit directly -->

For TOML files:

toml
# AUTO-SYNCED from tooling/skills/<name>/skill.md โ€” do not edit directly

For JS/MJS files:

javascript
// AUTO-SYNCED from tooling/skills/<name>/scripts/<file> โ€” do not edit directly

Safety Rules โ€‹

  1. Never delete files the script didn't create. Only overwrite files that have the auto-sync comment on line 1. If a file exists without the comment, warn and skip.
  2. Never touch Nx plugin skills. The script only processes skills found in tooling/skills/. Other skills in target directories are ignored.
  3. Dry-run mode. npm run sync:skills -- --dry-run prints what would change without writing.

Script Behavior โ€‹

1. Scan tooling/skills/ for skill directories
2. For each skill:
   a. Read skill.md and parse frontmatter
   b. For each target (.github/skills, .gemini/skills, .claude/skills):
      - Check if target file exists and has auto-sync comment
      - If file exists WITHOUT auto-sync comment: warn and skip
      - Otherwise: generate and write the transformed file
   c. If command: true, generate command files for each platform
   d. Copy supporting files (scripts/, references/) to .github and .gemini targets
3. Print summary: X files written, Y skipped, Z warnings

npm Script โ€‹

Add to root package.json:

json
{
  "scripts": {
    "sync:skills": "node tooling/scripts/sync-skills.js"
  }
}

Validation Integration โ€‹

Add a check to npm run validate (or as a standalone lint) that verifies synced files are up to date. Compares generated output against what's on disk โ€” fails if they differ. This catches forgotten sync runs.

Migration โ€‹

One-time migration to move existing custom skills into the canonical source:

  1. Create tooling/skills/pr-workbench/skill.md โ€” copy from .github/skills/pr-workbench/skill.md (already lowercase)
  2. Create tooling/skills/monitor-ci/ โ€” copy skill.md, scripts/, references/ from .github/skills/monitor-ci/
  3. Add command: true to monitor-ci's frontmatter
  4. Run npm run sync:skills โ€” overwrites existing files with auto-sync comment
  5. Verify all three target directories match
  6. Commit

Future: Skill Creation โ€‹

Update the superpowers writing-skills skill to:

  • Default new skill location to tooling/skills/<name>/skill.md
  • Remind the author to run npm run sync:skills after creating/editing a skill
  • This is a documentation/convention change, not a code change

Built with VitePress