Back to Runbook
๐Ÿงฉ Chapter 7

Skills & Tools

Build AgentSkills with hard constraints to avoid token bloat, use the quota checker script, and integrate tools safely. Includes prompt templates and the full check-quotas.sh script.

๐Ÿ“– 12 min read๐Ÿ› ๏ธ 2 tools
Part 1

Skill Builder

About AgentSkills

The AgentSkills specification provides a structure for creating maintainable, token-efficient skills. This prompt follows that model.

Why hard constraints matter

Vague instructions produce bloated, token-hungry skills every time. The hard constraint on line count (~500 lines) forces the agent to:

  • Put core workflow in SKILL.md
  • Move details into references/ for on-demand loading
  • Keep token usage low
  • Make the skill maintainable
โš ๏ธ

Without constraints, you'll get a 2,000-line skill file that eats half your context window.

Skill structure

A well-structured skill looks like:

File Structure
skills/
โ””โ”€โ”€ your-skill-name/
    โ”œโ”€โ”€ SKILL.md              # Core workflow (~500 lines max)
    โ”œโ”€โ”€ references/           # Loaded on-demand
    โ”‚   โ”œโ”€โ”€ api-docs.md
    โ”‚   โ””โ”€โ”€ examples.md
    โ””โ”€โ”€ scripts/              # Optional executables
        โ””โ”€โ”€ helper.sh

Prompt template

Copy and customize this prompt to have your agent create or refactor a skill:

Prompt โ€” Create or optimize a skill
I need help creating or optimizing an AgentSkill.

Skill name:
[your-skill-name]

Purpose:
What the skill does and when it should activate.

Triggers:
What kinds of tasks or questions should activate this skill.

Tools needed:
Any tools, commands, or APIs the skill will use.

Reference docs:
Docs or specs that should live in references/ for on-demand loading.

Existing skill (if applicable):
Path to the current SKILL.md if this is a refactor.

Please:
- Create or optimize the skill following AgentSkills best practices
- Keep the core workflow in SKILL.md and move details into references/
- Keep SKILL.md under ~500 lines
- Validate the structure using the AgentSkills validator
- Show the final file structure and contents

Example: Creating a new skill

Prompt โ€” Weather checker skill
I need help creating an AgentSkill.

Skill name:
weather-checker

Purpose:
Check current weather and forecasts using wttr.in (no API key required).

Triggers:
Questions about weather, temperature, forecast.

Tools needed:
curl to fetch from wttr.in, parsing text output.

Reference docs:
wttr.in documentation should live in references/wttr-in-docs.md

Please:
- Create the skill following AgentSkills best practices
- Keep the core workflow in SKILL.md under ~500 lines
- Move API details into references/
- Show the final file structure and contents

Example: Refactoring an existing skill

Prompt โ€” Refactor bloated skill
I need help optimizing an AgentSkill.

Existing skill:
~/.openclaw/workspace/skills/my-bloated-skill/SKILL.md

Purpose:
The skill works but SKILL.md is 1,800 lines and burns too many tokens.

Please:
- Refactor following AgentSkills best practices
- Keep core workflow in SKILL.md under ~500 lines
- Move details into references/ for on-demand loading
- Validate the structure
- Show what changed

Best practices

๐Ÿ“ Keep SKILL.md focused

  • โ€ข Describe when to trigger
  • โ€ข Show the core workflow
  • โ€ข Reference details in references/

๐Ÿ“ Use references/ for

  • โ€ข API documentation
  • โ€ข Detailed examples
  • โ€ข Error handling tables
  • โ€ข Command syntax reference

๐Ÿงช Test before deploying

  • โ€ข Run a test task
  • โ€ข Check token usage
  • โ€ข Verify it loads only what it needs

Community skills

โš ๏ธ

Be cautious with third-party skills. A poorly written or malicious skill can cause real problems. Treat community skills as inspiration rather than drop-ins.

Building your own gives you:

  • Full understanding of what it does
  • Control over token usage
  • No dependency on external maintainers
  • Better debugging at 2am

Skill security

Set basic rules in your workspace memory files:

  • Never expose secrets or API keys
  • Ask before external actions
  • Verify before destructive operations

Not foolproof, but it helps as a guardrail. See the Security Hardening chapter for more.

Part 2

Quota Checker Script

check-quotas.sh

Simple script to check API quota status across multiple providers. Returns JSON so you can pipe it to jq or use it in agent prompts.

Installation

bash
cp check-quotas.sh ~/.local/bin/check-quotas
chmod +x ~/.local/bin/check-quotas

# Verify ~/.local/bin is in your PATH
echo $PATH | grep -q "$HOME/.local/bin" || \
  echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc

Configuration

The script looks for API keys in ~/.openclaw/credentials/ by default.

bash โ€” Set up credentials
mkdir -p ~/.openclaw/credentials

# Add your API keys (raw tokens only, no quotes)
echo "your-api-key-here" > ~/.openclaw/credentials/openrouter
echo "your-api-key-here" > ~/.openclaw/credentials/synthetic
echo "your-api-key-here" > ~/.openclaw/credentials/anthropic

# Set proper permissions
chmod 700 ~/.openclaw/credentials
chmod 600 ~/.openclaw/credentials/*
โœ… Correct
sk-ant-api03-xxxxx

raw token only

โŒ Wrong
API_KEY=sk-ant...

no ENV format

โŒ Wrong
"sk-ant-api03..."

no quotes

Full script

check-quotas.sh
#!/bin/bash
# Check API quotas for various providers
# Returns JSON with quota status
#
# Usage: ./check-quotas.sh
#
# Configure paths below or set environment variables:
#   OPENCLAW_SECRETS_DIR - Path to your secrets directory
#   CLAUDE_KEYCHAIN_ITEM - macOS Keychain item name for Claude credentials

set -euo pipefail

# Configuration - adjust these paths for your setup
CREDENTIALS_DIR="${OPENCLAW_CREDENTIALS_DIR:-$HOME/.openclaw/credentials}"
CLAUDE_KEYCHAIN="${CLAUDE_KEYCHAIN_ITEM:-Claude Code-credentials}"

# Check Claude Code quota (macOS Keychain)
check_claude_code() {
    if ! command -v security &> /dev/null; then
        echo "null"
        return
    fi

    local token=$(security find-generic-password \
        -s "$CLAUDE_KEYCHAIN" -w 2>/dev/null | \
        jq -r '.claudeAiOauth.accessToken' 2>/dev/null || echo "")

    if [ -z "$token" ] || [ "$token" = "null" ]; then
        echo "null"
        return
    fi

    curl -s https://api.anthropic.com/api/oauth/usage \
        -H "Accept: application/json" \
        -H "Content-Type: application/json" \
        -H "User-Agent: claude-code/2.0.32" \
        -H "Authorization: Bearer $token" \
        -H "anthropic-beta: oauth-2025-04-20" 2>/dev/null || echo "null"
}

# Check Synthetic quota
check_synthetic() {
    local api_key=$(cat "$CREDENTIALS_DIR/synthetic" 2>/dev/null || echo "")
    if [ -z "$api_key" ]; then echo "null"; return; fi
    curl -s https://api.synthetic.new/v2/quotas \
        -H "Authorization: Bearer $api_key" 2>/dev/null || echo "null"
}

# Check OpenRouter quota
check_openrouter() {
    local api_key=$(cat "$CREDENTIALS_DIR/openrouter" 2>/dev/null || echo "")
    if [ -z "$api_key" ]; then echo "null"; return; fi
    curl -s https://openrouter.ai/api/v1/key \
        -H "Authorization: Bearer $api_key" 2>/dev/null || echo "null"
}

# Check Anthropic API quota (direct API key)
check_anthropic() {
    local api_key=$(cat "$CREDENTIALS_DIR/anthropic" 2>/dev/null || echo "")
    if [ -z "$api_key" ]; then echo "null"; return; fi
    curl -s https://api.anthropic.com/v1/messages \
        -H "x-api-key: $api_key" \
        -H "anthropic-version: 2023-06-01" \
        -H "content-type: application/json" \
        -d '{"model":"claude-3-haiku-20240307","max_tokens":1,
             "messages":[{"role":"user","content":"test"}]}' \
        2>/dev/null | \
        jq -r 'if .error then "error" else "valid" end' || echo "null"
}

# Build combined JSON output
claude_quota=$(check_claude_code)
synthetic_quota=$(check_synthetic)
openrouter_quota=$(check_openrouter)
anthropic_quota=$(check_anthropic)

jq -n \
    --argjson claude "$claude_quota" \
    --argjson synthetic "$synthetic_quota" \
    --argjson openrouter "$openrouter_quota" \
    --arg anthropic "$anthropic_quota" \
    '{
        claude_code: $claude,
        synthetic: $synthetic,
        openrouter: $openrouter,
        anthropic_api: $anthropic,
        checked_at: (now | strftime("%Y-%m-%dT%H:%M:%SZ"))
    }'

Output format

JSON output
{
  "claude_code": { "usage": {...}, "limit": {...} },
  "synthetic": { "credits_remaining": 1000 },
  "openrouter": { "usage": 45.23, "limit": 100.00 },
  "anthropic_api": "valid",
  "checked_at": "2026-02-09T20:28:00Z"
}

Parsing output

bash
# Check if a provider is over 90% quota
check-quotas | jq '.openrouter | (.usage / .limit) > 0.9'

# Get remaining Synthetic credits
check-quotas | jq -r '.synthetic.credits_remaining'

# Pretty print for humans
check-quotas | jq .

Integration with OpenClaw

bash โ€” Use in agent prompts or skills
# Before spawning expensive agent, check quotas
QUOTAS=$(check-quotas)
OPENROUTER_USAGE=$(echo $QUOTAS | jq -r '.openrouter.usage // 0')

if [ "$OPENROUTER_USAGE" -gt 90 ]; then
    echo "OpenRouter quota high, using fallback"
fi

Adding new providers

bash โ€” Template
check_yourprovider() {
    local api_key=$(cat "$CREDENTIALS_DIR/yourprovider" 2>/dev/null || echo "")

    if [ -z "$api_key" ]; then
        echo "null"
        return
    fi

    curl -s https://api.yourprovider.com/quota \
        -H "Authorization: Bearer $api_key" 2>/dev/null || echo "null"
}

Then add it to the final jq output.

Requirements & limitations

๐Ÿ“ฆ Requirements

  • โ€ข bash
  • โ€ข curl
  • โ€ข jq
  • โ€ข security (macOS only, for Keychain)

โš ๏ธ Limitations

  • โ€ข Claude Code check only works on macOS
  • โ€ข Anthropic API has no public quota endpoint โ€” just verifies key
  • โ€ข Rate limits may apply to quota check APIs