feat(kyberforge): add agent-author skill for Claude Code and Copilot CLI agents
## Why
skill-author explicitly excludes agent definition files ("Do not use to author
agent definition files"). No factory skill existed to create or improve the
.md / .agent.md files that define Claude Code subagents and Copilot CLI agents
in a plugin, project, or user scope. This fills that gap.
## Implementation Notes
Single-root scaffold convention: new-agent.sh <name> <root> derives both
provider file paths from the root by convention — plugin scope (plugin.json
present) writes both files into <root>/agents/; non-plugin scope writes
.claude/agents/<name>.md and .github/agents/<name>.agent.md. This keeps
input minimal while always generating both provider files. See ADR-0015.
Routing is file-level (not directory-level like skill-author): neither file
exists → create flow; at least one exists → improve flow; scaffold is a
file-by-file no-op so retries are safe.
No companion agent-audit skill — inline validation in the close step covers
the simpler agent field contract. agent-audit is tracked as a follow-on.
## Impact
Closes the skill-author gap for agent definitions. Follow-ons tracked in
Gitea #11: agent-audit skill and --copilot-dest override flag for non-standard
Copilot project paths.
---
ADR: docs/adr/0015-agent-author-dual-provider-scaffold.md
Refs: #10
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
13
plugins/kyberforge/skills/agent-author/scripts/README.md
Normal file
13
plugins/kyberforge/skills/agent-author/scripts/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# scripts/
|
||||
|
||||
## new-agent.sh
|
||||
|
||||
Scaffolds agent definition files for both Claude Code and GitHub Copilot CLI from a single root directory input.
|
||||
|
||||
```
|
||||
Usage: new-agent.sh <agent-name> <root>
|
||||
```
|
||||
|
||||
Detects scope from the root: `plugin.json` present → plugin scope (both files in `<root>/agents/`); `~` → user scope (`~/.claude/agents/` + `~/.copilot/agents/`); otherwise project scope (`.claude/agents/` + `.github/agents/`). Each file is a no-op if it already exists. See `--help` for full usage.
|
||||
|
||||
Tests: `tests/new-agent.bats` (requires `bats-support` and `bats-assert`).
|
||||
169
plugins/kyberforge/skills/agent-author/scripts/new-agent.sh
Executable file
169
plugins/kyberforge/skills/agent-author/scripts/new-agent.sh
Executable file
@@ -0,0 +1,169 @@
|
||||
#!/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 <<EOF
|
||||
Usage: new-agent.sh <agent-name> <root>
|
||||
|
||||
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 <root>/agents/<name>.md
|
||||
→ creates <root>/agents/<name>.agent.md
|
||||
→ creates <root>/agents/sources.md (if absent)
|
||||
project scope : root is a project directory (no plugin.json)
|
||||
→ creates <root>/.claude/agents/<name>.md
|
||||
→ creates <root>/.github/agents/<name>.agent.md
|
||||
user scope : root is ~ (home directory)
|
||||
→ creates ~/.claude/agents/<name>.md
|
||||
→ creates ~/.copilot/agents/<name>.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/agents"
|
||||
;;
|
||||
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
|
||||
|
||||
<!-- List research sources that informed agents in this directory.
|
||||
Follow the format below. Only include entries with `extracted` status.
|
||||
Delete this file if no research sources informed these agents. -->
|
||||
|
||||
<!-- ## source-slug
|
||||
- **URL:** <url>
|
||||
- **Research doc:** <relative-path-to-upstream-research-sources-file>
|
||||
- **Description:** <what this source covers>
|
||||
- **Contributing files:** agents/<name>.md, agents/<name>.agent.md
|
||||
- **Status:** `extracted` -->
|
||||
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
|
||||
Reference in New Issue
Block a user