| #!/bin/bash |
| |
| |
|
|
| set -euo pipefail |
|
|
| |
| if [ $# -eq 0 ]; then |
| echo "Usage: $0 <path/to/agent.md>" |
| echo "" |
| echo "Validates agent file for:" |
| echo " - YAML frontmatter structure" |
| echo " - Required fields (name, description, model, color)" |
| echo " - Field formats and constraints" |
| echo " - System prompt presence and length" |
| echo " - Example blocks in description" |
| exit 1 |
| fi |
|
|
| AGENT_FILE="$1" |
|
|
| echo "π Validating agent file: $AGENT_FILE" |
| echo "" |
|
|
| |
| if [ ! -f "$AGENT_FILE" ]; then |
| echo "β File not found: $AGENT_FILE" |
| exit 1 |
| fi |
| echo "β
File exists" |
|
|
| |
| FIRST_LINE=$(head -1 "$AGENT_FILE") |
| if [ "$FIRST_LINE" != "---" ]; then |
| echo "β File must start with YAML frontmatter (---)" |
| exit 1 |
| fi |
| echo "β
Starts with frontmatter" |
|
|
| |
| if ! tail -n +2 "$AGENT_FILE" | grep -q '^---$'; then |
| echo "β Frontmatter not closed (missing second ---)" |
| exit 1 |
| fi |
| echo "β
Frontmatter properly closed" |
|
|
| |
| FRONTMATTER=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$AGENT_FILE") |
| SYSTEM_PROMPT=$(awk '/^---$/{i++; next} i>=2' "$AGENT_FILE") |
|
|
| |
| echo "" |
| echo "Checking required fields..." |
|
|
| error_count=0 |
| warning_count=0 |
|
|
| |
| NAME=$(echo "$FRONTMATTER" | grep '^name:' | sed 's/name: *//' | sed 's/^"\(.*\)"$/\1/') |
|
|
| if [ -z "$NAME" ]; then |
| echo "β Missing required field: name" |
| ((error_count++)) |
| else |
| echo "β
name: $NAME" |
|
|
| |
| if ! [[ "$NAME" =~ ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$ ]]; then |
| echo "β name must start/end with alphanumeric and contain only letters, numbers, hyphens" |
| ((error_count++)) |
| fi |
|
|
| |
| name_length=${#NAME} |
| if [ $name_length -lt 3 ]; then |
| echo "β name too short (minimum 3 characters)" |
| ((error_count++)) |
| elif [ $name_length -gt 50 ]; then |
| echo "β name too long (maximum 50 characters)" |
| ((error_count++)) |
| fi |
|
|
| |
| if [[ "$NAME" =~ ^(helper|assistant|agent|tool)$ ]]; then |
| echo "β οΈ name is too generic: $NAME" |
| ((warning_count++)) |
| fi |
| fi |
|
|
| |
| DESCRIPTION=$(echo "$FRONTMATTER" | grep '^description:' | sed 's/description: *//') |
|
|
| if [ -z "$DESCRIPTION" ]; then |
| echo "β Missing required field: description" |
| ((error_count++)) |
| else |
| desc_length=${#DESCRIPTION} |
| echo "β
description: ${desc_length} characters" |
|
|
| if [ $desc_length -lt 10 ]; then |
| echo "β οΈ description too short (minimum 10 characters recommended)" |
| ((warning_count++)) |
| elif [ $desc_length -gt 5000 ]; then |
| echo "β οΈ description very long (over 5000 characters)" |
| ((warning_count++)) |
| fi |
|
|
| |
| if ! echo "$DESCRIPTION" | grep -q '<example>'; then |
| echo "β οΈ description should include <example> blocks for triggering" |
| ((warning_count++)) |
| fi |
|
|
| |
| if ! echo "$DESCRIPTION" | grep -qi 'use this agent when'; then |
| echo "β οΈ description should start with 'Use this agent when...'" |
| ((warning_count++)) |
| fi |
| fi |
|
|
| |
| MODEL=$(echo "$FRONTMATTER" | grep '^model:' | sed 's/model: *//') |
|
|
| if [ -z "$MODEL" ]; then |
| echo "β Missing required field: model" |
| ((error_count++)) |
| else |
| echo "β
model: $MODEL" |
|
|
| case "$MODEL" in |
| inherit|sonnet|opus|haiku) |
| |
| ;; |
| *) |
| echo "β οΈ Unknown model: $MODEL (valid: inherit, sonnet, opus, haiku)" |
| ((warning_count++)) |
| ;; |
| esac |
| fi |
|
|
| |
| COLOR=$(echo "$FRONTMATTER" | grep '^color:' | sed 's/color: *//') |
|
|
| if [ -z "$COLOR" ]; then |
| echo "β Missing required field: color" |
| ((error_count++)) |
| else |
| echo "β
color: $COLOR" |
|
|
| case "$COLOR" in |
| blue|cyan|green|yellow|magenta|red) |
| |
| ;; |
| *) |
| echo "β οΈ Unknown color: $COLOR (valid: blue, cyan, green, yellow, magenta, red)" |
| ((warning_count++)) |
| ;; |
| esac |
| fi |
|
|
| |
| TOOLS=$(echo "$FRONTMATTER" | grep '^tools:' | sed 's/tools: *//') |
|
|
| if [ -n "$TOOLS" ]; then |
| echo "β
tools: $TOOLS" |
| else |
| echo "π‘ tools: not specified (agent has access to all tools)" |
| fi |
|
|
| |
| echo "" |
| echo "Checking system prompt..." |
|
|
| if [ -z "$SYSTEM_PROMPT" ]; then |
| echo "β System prompt is empty" |
| ((error_count++)) |
| else |
| prompt_length=${#SYSTEM_PROMPT} |
| echo "β
System prompt: $prompt_length characters" |
|
|
| if [ $prompt_length -lt 20 ]; then |
| echo "β System prompt too short (minimum 20 characters)" |
| ((error_count++)) |
| elif [ $prompt_length -gt 10000 ]; then |
| echo "β οΈ System prompt very long (over 10,000 characters)" |
| ((warning_count++)) |
| fi |
|
|
| |
| if ! echo "$SYSTEM_PROMPT" | grep -q "You are\|You will\|Your"; then |
| echo "β οΈ System prompt should use second person (You are..., You will...)" |
| ((warning_count++)) |
| fi |
|
|
| |
| if ! echo "$SYSTEM_PROMPT" | grep -qi "responsibilities\|process\|steps"; then |
| echo "π‘ Consider adding clear responsibilities or process steps" |
| fi |
|
|
| if ! echo "$SYSTEM_PROMPT" | grep -qi "output"; then |
| echo "π‘ Consider defining output format expectations" |
| fi |
| fi |
|
|
| echo "" |
| echo "ββββββββββββββββββββββββββββββββββββββββ" |
|
|
| if [ $error_count -eq 0 ] && [ $warning_count -eq 0 ]; then |
| echo "β
All checks passed!" |
| exit 0 |
| elif [ $error_count -eq 0 ]; then |
| echo "β οΈ Validation passed with $warning_count warning(s)" |
| exit 0 |
| else |
| echo "β Validation failed with $error_count error(s) and $warning_count warning(s)" |
| exit 1 |
| fi |
|
|