How to Create Agent Skills: CLI API Tester Example

    Skills let you package domain expertise into reusable instruction packs that agents can auto-load. Here's how to build one from scratch, using a CLI API Tester skill as a real example.

    Tob

    Tob

    Backend Developer

    10 min readAI Engineering
    How to Create Agent Skills: CLI API Tester Example

    TL;DR: Agent skills are instruction packs that auto-load when relevant tasks appear. They're just markdown files with frontmatter. This guide walks through building a real CLI API Tester skill from scratch — covering skill anatomy, the auto-loading mechanism, tool permissions, and patterns for making skills that agents actually use correctly.

    ---

    What Are Agent Skills?

    Agent skills are specialized instruction packs that AI agents can load based on context. When you ask an agent to "test my API endpoints," a matching skill auto-loads and provides structured guidance tailored to that task.

    The skill system has three components:

    1. SKILL.md — the entry point, a markdown file with YAML frontmatter
    2. Supporting files (optional) — scripts, data files, templates
    3. Auto-loading logic — the agent matches task descriptions to skill triggers

    Skills live in .agents/skills/ in your workspace. Each skill is a directory with a SKILL.md file:

    text
    .agents/skills/
    ├── technical-writing/
    │   └── SKILL.md
    ├── cli-api-tester/         # our example
    │   ├── SKILL.md
    │   └── scripts/
    │       └── test-runner.py

    ---

    Skill Anatomy: SKILL.md Structure

    Every skill has YAML frontmatter and a markdown body:

    yaml
    ---
    name: skill-identifier                    # unique name
    description: "When to use this skill..."  # triggers auto-loading
    allowed-tools: Read Write Edit Glob Grep  # tool permissions
    metadata:
      author: your-name
      version: "1.0.0"
      tags: api, testing, cli
    ---
    
    # Skill Title
    
    Content...

    Frontmatter Fields

    FieldRequiredPurpose
    nameYesUnique identifier for the skill
    descriptionYesTrigger phrases — what tasks should load this skill
    allowed-toolsNoWhich tools the agent can use (defaults to all)
    metadataNoAuthor, version, tags, supported platforms

    The description is the most important field — it's how the agent decides when to load the skill. Make it specific and include common trigger phrases.

    ---

    Building the CLI API Tester Skill

    Let's build a skill that helps agents test REST APIs via CLI. This is a realistic use case: agents can run curl commands, validate responses, and generate test reports.

    Step 1: Create the Skill Directory

    text
    .agents/skills/cli-api-tester/
    ├── SKILL.md
    └── scripts/
        └── test-runner.py

    Step 2: Write SKILL.md

    yaml
    ---
    name: cli-api-tester
    description: "Use this skill when testing APIs, running curl commands, validating HTTP responses, or checking REST endpoints. Triggers on: 'test my API', 'check the endpoint', 'validate the response', 'run API tests', 'curl the server', 'verify HTTP status codes'."
    allowed-tools: Read Write Edit Glob Grep Bash
    metadata:
      author: your-name
      version: "1.0.0"
      tags: api, testing, curl, http, rest, cli
      platforms: Claude, ChatGPT, Gemini
    ---
    
    # CLI API Tester Skill
    
    A skill for testing REST APIs via command-line tools like curl and httpx. Use this when you need to validate API endpoints, check response bodies, verify status codes, or generate automated test reports.
    
    ## Core Testing Workflow
    
    ### 1. Discover Endpoints
    
    First, understand what you're testing:
    

    curl -s http://localhost:3000/api/routes | jq .

    text
    
    ### 2. Test Individual Endpoints
    

    curl -s -w "\nHTTP_CODE:%{http_code}\n" http://localhost:3000/api/users

    curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/profile

    curl -s -X POST http://localhost:3000/api/users \ -H "Content-Type: application/json" \ -d '{"name":"Test User","email":"test@example.com"}'

    curl -s -X PUT http://localhost:3000/api/users/123 \ -H "Content-Type: application/json" \ -d '{"name":"Updated Name"}'

    curl -s -X DELETE http://localhost:3000/api/users/123

    text
    
    ### 3. Validate Responses
    
    Always validate the response structure and data types:
    

    response=$(curl -s -w "%{http_code}" -o response.json http://localhost:3000/api/users) if [ "$response" = "200" ]; then echo "PASS: Status code 200" else echo "FAIL: Expected 200, got $response" fi

    jq -e '.users[] | has("id") and has("name")' response.json > /dev/null && echo "PASS: Valid structure"

    jq -e '.users[] | select(.email == "admin@example.com")' response.json > /dev/null && echo "PASS: Found admin user"

    text
    
    ### 4. Test Error Cases
    

    curl -s -w "%{http_code}" -o /dev/null -X POST http://localhost:3000/api/users \ -H "Content-Type: application/json" \ -d '{"email":"invalid-email"}'

    curl -s -w "%{http_code}" -o /dev/null http://localhost:3000/api/profile

    curl -s -w "%{http_code}" -o /dev/null http://localhost:3000/api/users/999999

    text
    
    ### 5. Performance Testing
    

    curl -s -w "Time: %{time_total}s\n" http://localhost:3000/api/users

    ab -n 100 -c 10 http://localhost:3000/api/users/

    for i in {1..20}; do curl -s -w "%{time_total}\n" -o /dev/null http://localhost:3000/api/users & done wait

    text
    
    ## Response Validation Patterns
    
    ### JSON Response Validation
    

    jq -e '.data[] | has("id") and has("name") and has("email")' response.json

    jq -e '.data[] | (.id | type == "number") and (.name | type == "string")' response.json

    jq -e '.data[] | .status == "active" or .status == "inactive"' response.json

    jq -e '.data[] | .age >= 18 and .age <= 120' response.json

    text
    
    ### Header Validation
    

    content_type=$(curl -sI http://localhost:3000/api/users | grep -i content-type) echo "$content_type" | grep -q "application/json" && echo "PASS" || echo "FAIL"

    curl -sI -X OPTIONS http://localhost:3000/api/users \ -H "Origin: http://localhost:3001" | grep -i "access-control"

    text
    
    ### Authentication Flow Testing
    

    curl -s -X POST http://localhost:3000/api/auth/register \ -H "Content-Type: application/json" \ -d '{"email":"test@example.com","password":"Test123!","name":"Test User"}' > register.json

    curl -s -X POST http://localhost:3000/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"test@example.com","password":"Test123!"}' > login.json

    TOKEN=$(jq -r '.token' login.json)

    curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/profile

    curl -s -w "%{http_code}" -o /dev/null -H "Authorization: Bearer invalid-token" \ http://localhost:3000/api/profile

    text
    
    ## Test Report Template
    
    Generate structured test reports:
    

    #!/bin/bash

    REPORT="api-test-report.md" echo "# API Test Report" > "$REPORT" echo "Generated: $(date)" >> "$REPORT" echo "" >> "$REPORT"

    test_endpoint() { local name=$1 local url=$2 local expected=$3

    response=$(curl -s -w "%{http_code}" -o /tmp/response.json "$url")

    if [ "$response" = "$expected" ]; then echo "✅ $name: PASS (got $response)" | tee -a "$REPORT" else echo "❌ $name: FAIL (expected $expected, got $response)" | tee -a "$REPORT" fi }

    test_endpoint "GET Users" "http://localhost:3000/api/users" "200" test_endpoint "GET User 1" "http://localhost:3000/api/users/1" "200" test_endpoint "GET Nonexistent" "http://localhost:3000/api/users/999999" "404"

    echo "" >> "$REPORT" echo "## Response Samples" >> "$REPORT" echo '``json' >> "$REPORT" cat /tmp/response.json >> "$REPORT" echo '``' >> "$REPORT"

    text
    
    ## Common Issues and Debugging
    
    | Issue | Diagnosis | Resolution |
    |-------|-----------|------------|
    | Connection refused | Server not running | Start server: `npm run dev` |
    | Timeout | Server overloaded or slow | Check server logs, increase timeout: `-m 30` |
    | 502 Bad Gateway | Upstream server error | Check reverse proxy and upstream services |
    | CORS errors | Missing CORS headers | Add `Access-Control-Allow-Origin` header |
    | SSL errors | Self-signed certs | Use `-k` flag: `curl -k https://localhost` |
    
    ## When to Use This Skill
    
    Use this skill when:
    - Testing new API endpoints during development
    - Validating API behavior after code changes
    - Checking third-party API integrations
    - Generating test reports for PRs
    - Debugging API failures in CI/CD
    
    Skip this skill when:
    - The task is to write API code (use a coding skill instead)
    - You need to set up the API server (not testing it)
    - The task is purely about API design or documentation

    Related Blog

    How to Create Agent Skills: CLI API Tester Example | Tob