#!/usr/bin/env bash set -euo pipefail SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SKILL_ROOT="$(cd "$SKILL_DIR/.." && pwd)" TEMPLATES_DIR="$SKILL_ROOT/assets/templates" usage() { cat < Scaffold agent definition files for Claude Code and GitHub Copilot CLI. Arguments: agent-name Kebab-case agent identifier (e.g. code-reviewer, deploy-assistant). root Root directory — determines scope: plugin scope : root contains plugin.json → creates /agents/.md → creates /agents/.agent.md → creates /sources.md (if absent) project scope : root is a project directory (no plugin.json) → creates /.claude/agents/.md → creates /.github/agents/.agent.md user scope : root is ~ (home directory) → creates ~/.claude/agents/.md → creates ~/.copilot/agents/.agent.md Each file is created only if it does not already exist (no-op per file). Exit codes: 0 Files created or already existed (no-op) 1 Invalid arguments, missing root, or templates not found EOF } if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then usage exit 0 fi if [[ $# -lt 2 ]]; then echo "Error: agent-name and root are required." >&2 echo "" >&2 usage >&2 exit 1 fi AGENT_NAME="$1" ROOT="$2" # Validate agent name format if ! echo "$AGENT_NAME" | grep -qE '^[a-z0-9]+(-[a-z0-9]+)*$'; then echo "Error: agent-name must use lowercase letters, numbers, and hyphens only." >&2 echo " No leading, trailing, or consecutive hyphens." >&2 echo " Received: '$AGENT_NAME'" >&2 exit 1 fi # Validate templates directory if [[ ! -d "$TEMPLATES_DIR" ]]; then echo "Error: templates directory not found at '$TEMPLATES_DIR'." >&2 echo " Run this script from its original location inside the agent-author skill." >&2 exit 1 fi # Expand tilde ROOT="${ROOT/#\~/$HOME}" # Validate root exists if [[ ! -d "$ROOT" ]]; then echo "Error: root directory '$ROOT' does not exist." >&2 exit 1 fi # Detect scope if [[ -f "$ROOT/plugin.json" || -f "$ROOT/.claude-plugin/plugin.json" || -f "$ROOT/.plugin/plugin.json" || -f "$ROOT/.github/plugin/plugin.json" ]]; then SCOPE="plugin" elif [[ "$ROOT" == "$HOME" ]]; then SCOPE="user" else SCOPE="project" fi # Determine file destinations case "$SCOPE" in plugin) CC_DIR="$ROOT/agents" CP_DIR="$ROOT/agents" SOURCES_DIR="$ROOT" ;; project) CC_DIR="$ROOT/.claude/agents" CP_DIR="$ROOT/.github/agents" SOURCES_DIR="" ;; user) CC_DIR="$HOME/.claude/agents" CP_DIR="$HOME/.copilot/agents" SOURCES_DIR="" ;; esac CC_FILE="$CC_DIR/$AGENT_NAME.md" CP_FILE="$CP_DIR/$AGENT_NAME.agent.md" # Create directories mkdir -p "$CC_DIR" mkdir -p "$CP_DIR" # Copy Claude Code template (no-op if exists) created_any=false if [[ -f "$CC_FILE" ]]; then echo "Skipping '$CC_FILE' — already exists." >&2 else sed "s/AGENT_NAME/$AGENT_NAME/g" "$TEMPLATES_DIR/claude-code.md" > "$CC_FILE" echo "Created: $CC_FILE" >&2 created_any=true fi # Copy Copilot template (no-op if exists) if [[ -f "$CP_FILE" ]]; then echo "Skipping '$CP_FILE' — already exists." >&2 else sed "s/AGENT_NAME/$AGENT_NAME/g" "$TEMPLATES_DIR/copilot.agent.md" > "$CP_FILE" echo "Created: $CP_FILE" >&2 created_any=true fi # Create sources.md at plugin scope (no-op if exists) if [[ -n "$SOURCES_DIR" ]]; then SOURCES_FILE="$SOURCES_DIR/sources.md" if [[ -f "$SOURCES_FILE" ]]; then echo "Skipping '$SOURCES_FILE' — already exists." >&2 else cat > "$SOURCES_FILE" <<'SOURCES' # Sources SOURCES echo "Created: $SOURCES_FILE" >&2 created_any=true fi fi if [[ "$created_any" == false ]]; then echo "All files already exist — nothing to do." >&2 else echo "" >&2 echo "Scope: $SCOPE" >&2 echo "" >&2 echo "Next steps:" >&2 echo " 1. Fill in $CC_FILE — replace all FILL IN: placeholders" >&2 echo " 2. Fill in $CP_FILE — replace all FILL IN: placeholders" >&2 if [[ -n "$SOURCES_DIR" ]]; then echo " 3. Populate $SOURCES_DIR/sources.md with research sources, or delete it" >&2 echo " 4. Validate: check required fields (name, description, system prompt) in both files" >&2 else echo " 3. Validate: check required fields (name, description, system prompt) in both files" >&2 fi fi