From 6179d6149d54a638fe590a07516b261b90a0cdb2 Mon Sep 17 00:00:00 2001 From: Cora 7 Date: Thu, 4 Dec 2025 10:18:19 +1100 Subject: [PATCH] feat: add Claude Code skill documentation and package validation (MT-35) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge skill-creator functionality into metool: - Add comprehensive "Claude Code Skills" section to SKILL.md explaining skill structure, progressive disclosure, and best practices - Add `mt package validate` command to validate package structure and SKILL.md (checks frontmatter, name conventions, README.md, bin/ permissions) - Add MT_ROOT override support to bin/mt for testing worktrees Package creation uses existing `mt package new` which includes SKILL.md.example template. Rename to SKILL.md to activate the skill. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- SKILL.md | 173 ++++++++++++++++++++++++++++++++++++++++++++++++- bin/mt | 6 +- lib/package.sh | 171 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 348 insertions(+), 2 deletions(-) diff --git a/SKILL.md b/SKILL.md index 3051f0d..8ca296d 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,6 +1,6 @@ --- name: metool -description: Package management system for organizing, installing, and managing shell scripts, dotfiles, and development tools. Use this skill when creating, modifying, reviewing, or installing metool packages, or when working with metool commands and package structure. +description: Package management system for organizing, installing, and managing shell scripts, dotfiles, and development tools. This skill should be used when creating, modifying, reviewing, or installing metool packages, working with metool commands and package structure, or creating Claude Code skills for metool packages. --- # Metool Package Management @@ -18,6 +18,8 @@ Use this skill when: - Working with metool commands (install, cd, edit, etc.) - Setting up configuration files or dotfiles via metool - Managing shell functions, aliases, or executables +- Creating or updating Claude Code skills for metool packages +- Adding SKILL.md to existing packages ## Core Concepts @@ -28,6 +30,7 @@ Every metool package follows this standard structure: ``` package-name/ ├── README.md # Package documentation (REQUIRED) +├── SKILL.md # Claude Code skill (optional, enables AI assistance) ├── bin/ # Executable scripts (symlinked to ~/.metool/bin) ├── shell/ # Shell functions, aliases, completions ├── config/ # Config files (use dot- prefix for dotfiles) @@ -364,6 +367,174 @@ metool-packages-work/ # Work-specific packages 4. **Tested** - Test packages before installing 5. **Dependencies** - Document and check for dependencies +## Claude Code Skills + +Skills extend Claude's capabilities by providing specialized knowledge, workflows, and tools. Metool packages can include a `SKILL.md` file to enable AI assistance for the package's domain. + +### What Skills Provide + +1. **Specialized workflows** - Multi-step procedures for specific domains +2. **Tool integrations** - Instructions for working with specific file formats or APIs +3. **Domain expertise** - Package-specific knowledge, schemas, conventions +4. **Bundled resources** - Scripts, docs, and assets accessible to Claude + +### Human-AI Collaborative Infrastructure + +Metool packages with skills create infrastructure that serves both humans and AI: + +**For Humans:** +- Scripts in `bin/` provide CLI tools available in PATH +- Shell functions and aliases in `shell/` enhance interactive workflows +- Configuration in `config/` manages dotfiles and settings +- `README.md` documents the package for human users + +**For AI (Claude):** +- `SKILL.md` provides procedural knowledge and workflow guidance +- References to `bin/` scripts tell Claude what tools are available +- Documentation in `docs/` enables progressive disclosure +- Understanding of `shell/` functions helps Claude guide interactive usage + +### SKILL.md Structure + +Every skill requires a `SKILL.md` file with YAML frontmatter: + +```markdown +--- +name: package-name +description: Brief explanation of what the skill does and when to use it. This skill should be used when [specific scenarios]. +--- + +# Package Name + +## Overview + +[1-2 sentences explaining what this skill enables] + +## When to Use + +[Specific triggers and use cases] + +## Workflows + +[Step-by-step procedures, tool references, examples] + +## Resources + +[References to bin/ scripts, docs/ files, and other package components] +``` + +**Frontmatter Requirements:** +- `name`: Must be hyphen-case (lowercase letters, digits, hyphens only) +- `description`: Clear explanation of when Claude should use this skill. Use third-person ("This skill should be used when..." not "Use this skill when...") + +### Progressive Disclosure + +Skills use a three-level loading system: + +1. **Metadata** (~100 words) - Always in context (name + description) +2. **SKILL.md body** (<5k words) - Loaded when skill triggers +3. **Package resources** (unlimited) - Loaded as needed by Claude + +Scripts in `bin/` can be executed without loading into context, making them token-efficient. + +### Adding a Skill to an Existing Package + +When adding a skill to an existing metool package: + +1. **Create only the SKILL.md file** - Do not overwrite existing README.md or other files +2. **Reference existing tools** - Review what scripts, functions, and docs already exist +3. **Adapt to existing structure** - The SKILL.md should work with the package's current organization + +Example: Adding a skill to a `git-tools` package that already has `bin/git-branch-clean`: + +```markdown +--- +name: git-tools +description: Git workflow utilities for branch management and repository maintenance. This skill should be used when cleaning up git branches, managing worktrees, or automating git workflows. +--- + +# Git Tools + +## Overview + +Provides utilities for git branch management and repository maintenance. + +## Available Tools + +- `git-branch-clean` - Remove merged local branches +- `git-worktree-list` - List all worktrees with status + +## Workflows + +### Cleaning Up Branches + +To clean up merged branches, run: +\`\`\`bash +git-branch-clean +\`\`\` +``` + +### Creating a New Package with Skill + +To create a new metool package with skill support: + +```bash +mt package new my-package /path/to/module +``` + +This creates a package from the template including `SKILL.md.example`: +``` +my-package/ +├── README.md # Human documentation template +├── SKILL.md.example # Claude skill template (rename to SKILL.md to activate) +├── bin/ # Executable scripts directory +├── shell/ # Shell functions directory +├── config/ # Configuration files +└── lib/ # Library functions directory +``` + +To enable the skill, rename `SKILL.md.example` to `SKILL.md` and complete the TODOs. + +### Skill Commands + +Metool provides commands for skill management: + +```bash +# Create a new package (includes SKILL.md.example template) +mt package new [directory] + +# Validate package structure and SKILL.md +mt package validate +``` + +### Documentation Strategy + +- **README.md** - Human-facing: installation, usage examples, requirements +- **SKILL.md** - AI-facing: procedural knowledge, workflows, tool references +- **docs/** - Shared reference: detailed schemas, APIs, conventions + +Avoid duplication between README.md and SKILL.md. Each should serve its audience. + +### Writing Effective Skills + +**Writing Style:** Use imperative/infinitive form (verb-first instructions), not second person. Write "To accomplish X, do Y" rather than "You should do X". + +**Content Guidelines:** +- Focus on procedural knowledge that Claude cannot infer +- Reference package tools by their command names (they're in PATH after install) +- Point to docs/ files for detailed reference material +- Include concrete examples with realistic scenarios +- Keep SKILL.md under 5k words; move details to docs/ + +### Skill Installation + +When a package with `SKILL.md` is installed via `mt package install`, metool automatically creates symlinks to make the skill available to Claude Code: + +1. Package directory → `~/.metool/skills/` +2. `~/.metool/skills/` → `~/.claude/skills/` + +Claude Code discovers skills by scanning `~/.claude/skills/` for `SKILL.md` files. + ## Troubleshooting ### Conflicts During Installation diff --git a/bin/mt b/bin/mt index 1966427..1cd8425 100755 --- a/bin/mt +++ b/bin/mt @@ -34,8 +34,12 @@ fi # Find metool installation and export MT_ROOT before sourcing # This prevents shell/mt from calculating MT_ROOT incorrectly when sourced from snapshots +# If MT_ROOT is already set, use it (allows explicit override) +if [[ -n "$MT_ROOT" ]] && [[ -f "$MT_ROOT/shell/mt" ]]; then + source "$MT_ROOT/shell/mt" + # Check if already installed in home -if [[ -d "$HOME/.metool" ]] && [[ -f "$HOME/.metool/shell/metool/mt" ]]; then +elif [[ -d "$HOME/.metool" ]] && [[ -f "$HOME/.metool/shell/metool/mt" ]]; then export MT_ROOT="$HOME/.metool" source "$MT_ROOT/shell/metool/mt" diff --git a/lib/package.sh b/lib/package.sh index 5d8dce4..b90e1a7 100644 --- a/lib/package.sh +++ b/lib/package.sh @@ -686,6 +686,9 @@ _mt_package() { new) _mt_package_new "$@" ;; + validate) + _mt_package_validate "$@" + ;; -h|--help|"") cat < [options] @@ -701,6 +704,7 @@ Commands: uninstall ... [opts] Uninstall package(s) (remove symlinks) service Manage package services (systemd/launchd) new NAME [PATH] Create a new package from template + validate Validate package structure and SKILL.md Install/Uninstall Options: --no-bin Skip bin/ directory @@ -865,6 +869,173 @@ EOF echo "" } +# Validate package structure and SKILL.md +_mt_package_validate() { + local package_spec="$1" + local package_path="" + local package_name="" + local errors=() + local warnings=() + + # Show help if no argument + if [[ -z "$package_spec" ]] || [[ "$package_spec" == "-h" ]] || [[ "$package_spec" == "--help" ]]; then + cat < + +Validates: + - README.md exists (required) + - SKILL.md structure if present (frontmatter, name, description) + - Executable permissions in bin/ + - Package naming conventions + +Examples: + mt package validate my-package # Package in working set + mt package validate ./path/to/package # Package by path + mt package validate . # Current directory + +EOF + return 0 + fi + + # Resolve package path + if [[ -d "$package_spec" ]]; then + # Direct path provided + package_path="$(cd "$package_spec" && pwd)" + package_name="$(basename "$package_path")" + elif [[ -L "${MT_PACKAGES_DIR}/${package_spec}" ]]; then + # Package in working set + package_path="$(readlink -f "${MT_PACKAGES_DIR}/${package_spec}")" + package_name="$package_spec" + else + _mt_error "Package not found: $package_spec" + _mt_info "Provide a path or package name from working set" + return 1 + fi + + if [[ ! -d "$package_path" ]]; then + _mt_error "Package directory not found: $package_path" + return 1 + fi + + echo "Validating package: $package_name" + echo "Path: $package_path" + echo "" + + # Check README.md (required) + if [[ ! -f "$package_path/README.md" ]]; then + errors+=("README.md not found (required for metool packages)") + fi + + # Check bin/ executables + if [[ -d "$package_path/bin" ]]; then + while IFS= read -r -d '' script; do + if [[ ! -x "$script" ]]; then + warnings+=("Not executable: bin/$(basename "$script")") + fi + done < <(find "$package_path/bin" -type f -print0 2>/dev/null) + fi + + # Check SKILL.md if present + if [[ -f "$package_path/SKILL.md" ]]; then + _mt_validate_skill "$package_path" "$package_name" errors warnings + elif [[ -f "$package_path/SKILL.md.example" ]]; then + _mt_info "SKILL.md.example found - rename to SKILL.md to enable skill" + fi + + # Check package name convention + if [[ ! "$package_name" =~ ^[a-z0-9-]+$ ]]; then + warnings+=("Package name should be hyphen-case (lowercase, digits, hyphens)") + fi + + # Report results + echo "" + if [[ ${#errors[@]} -eq 0 ]] && [[ ${#warnings[@]} -eq 0 ]]; then + _mt_log INFO "✅ Package is valid" + return 0 + fi + + if [[ ${#warnings[@]} -gt 0 ]]; then + echo "Warnings:" + for warning in "${warnings[@]}"; do + echo " ⚠️ $warning" + done + fi + + if [[ ${#errors[@]} -gt 0 ]]; then + echo "Errors:" + for error in "${errors[@]}"; do + echo " ❌ $error" + done + return 1 + fi + + return 0 +} + +# Validate SKILL.md structure (internal helper) +_mt_validate_skill() { + local package_path="$1" + local package_name="$2" + local -n _errors=$3 + local -n _warnings=$4 + local skill_file="$package_path/SKILL.md" + + # Read first few lines to check frontmatter + local content + content=$(<"$skill_file") + + # Check for YAML frontmatter + if [[ ! "$content" =~ ^--- ]]; then + _errors+=("SKILL.md: No YAML frontmatter (must start with ---)") + return + fi + + # Extract frontmatter (only the first YAML block between --- markers) + local frontmatter + frontmatter=$(echo "$content" | awk '/^---$/{if(++n==1)next; if(n==2)exit} n==1{print}') + + if [[ -z "$frontmatter" ]]; then + _errors+=("SKILL.md: Invalid frontmatter format (missing closing ---)") + return + fi + + # Check required fields + if ! echo "$frontmatter" | grep -q '^name:'; then + _errors+=("SKILL.md: Missing 'name' field in frontmatter") + else + # Validate name format and match (get first match only) + local skill_name + skill_name=$(echo "$frontmatter" | grep -m1 '^name:' | sed 's/^name:[[:space:]]*//') + + if [[ ! "$skill_name" =~ ^[a-z0-9-]+$ ]]; then + _errors+=("SKILL.md: Name '$skill_name' must be hyphen-case") + elif [[ "$skill_name" =~ ^-|-$|-- ]]; then + _errors+=("SKILL.md: Name cannot start/end with hyphen or have consecutive hyphens") + elif [[ "$skill_name" != "$package_name" ]]; then + _warnings+=("SKILL.md: Name '$skill_name' doesn't match package name '$package_name'") + fi + fi + + if ! echo "$frontmatter" | grep -q '^description:'; then + _errors+=("SKILL.md: Missing 'description' field in frontmatter") + else + local description + description=$(echo "$frontmatter" | grep -m1 '^description:' | sed 's/^description:[[:space:]]*//') + + # Check for TODO placeholder + if [[ "$description" =~ \[TODO ]] || [[ "$description" =~ ^\[ ]]; then + _errors+=("SKILL.md: Description contains TODO placeholder - please complete it") + fi + + # Check minimum length + if [[ ${#description} -lt 20 ]]; then + _warnings+=("SKILL.md: Description is very short (recommend 20+ characters)") + fi + fi +} + # Copy template files and replace placeholders _mt_package_copy_template() { local template_dir="$1"