Skills Script Extension

In addition to writing instructions in SKILL.md, you can also add executable code to a skill through the scripts directory.

This section will teach you how to use scripts to extend the functionality of a skill.


Why Use Scripts

Using scripts allows you to:

  • Encapsulate complex logic and avoid writing large amounts of code in SKILL.md
  • Provide tested, reliable implementations
  • Allow agents to reuse the same tools and functions
  • Handle more complex input/output operations

Tip: When you notice the agent repeatedly implementing the same logic across multiple executions, that's often a good time to create a script.


Script Directory Structure

Scripts should be placed in the scripts/ subdirectory of the skill directory:

Directory Structure

my-skill/
├── SKILL.md
└── scripts/
    ├── script1.py
    ├── script2.sh
    └── helper.js

Script Writing Guidelines

1. Self-containment

Scripts should be as self-contained as possible, or clearly document their dependencies.

Self-contained Script Example

#!/usr/bin/env python3
"""
PDF Text Extraction Script

Dependency: pip install pdfplumber
Run: python scripts/extract_pdf.py input.pdf
"""


import sys
import pdfplumber

def extract_text_from_pdf(pdf_path):
    """Extract text from a PDF file"""
    with pdfplumber.open(pdf_path) as pdf:
        text = ""
        for page in pdf.pages:
            text += page.extract_text() or ""
    return text

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python extract_pdf.py <pdf file>")
        sys.exit(1)

    pdf_path = sys.argv[1]
    text = extract_text_from_pdf(pdf_path)
    print(text)

2. Clear Error Handling

Scripts should provide useful error messages to help agents understand what went wrong.

Error Handling Example

import sys

def main():
    if len(sys.argv) < 2:
        print("Error: Missing required argument", file=sys.stderr)
        print("Usage: python script.py <input file> [output file]", file=sys.stderr)
        sys.exit(1)

    input_file = sys.argv[1]

    try:
        # Execute main logic
        process_file(input_file)
    except FileNotFoundError:
        print(f"Error: File {input_file} not found", file=sys.stderr)
        sys.exit(1)
    except PermissionError:
        print(f"Error: No permission to read file {input_file}", file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print(f"Error: Unknown error occurred while processing file: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()

3. Handling Edge Cases

Scripts should gracefully handle various edge cases instead of crashing.

Edge Case Handling Example

def validate_input(text):
    """Validate whether the input is valid"""
    if not text:
        return False, "Input cannot be empty"

    if len(text) > 10000:
        return False, "Input length exceeds the limit (max 10000 characters)"

    return True, ""

# Use validation
is_valid, error_msg = validate_input(user_input)
if not is_valid:
    print(f"Validation failed: {error_msg}")
    sys.exit(1)

Referencing Scripts in SKILL.md

When a skill needs to execute a script, describe in SKILL.md how to call it.

Referencing scripts:

## PDF 文本提取

使用脚本提取 PDF 中的文本:

```bash
python scripts/extract_pdf.py input.pdf
```

脚本会从 input.pdf 提取所有文本并输出到标准输出。

如果需要将结果保存到文件:

```bash
python scripts/extract_pdf.py input.pdf > output.txt
```

Note: Use paths relative to the skill root directory when referencing scripts.


Supported Script Languages

The supported script languages depend on the agent implementation you use. Common options include:

Language Description
Python The most commonly used choice, powerful and easy to write
Bash Suitable for system operations and command-line tools
JavaScript Suitable for Web-related tasks

Tip: When choosing a script language, consider the target user's runtime environment. If unsure, Python is the safest choice.


Complete Example: PDF Processing Skill

Let's look at a complete example showing how to combine SKILL.md and scripts:

Skill Structure

pdf-tool/
├── SKILL.md
└── scripts/
    ├── extract.py
    ├── fill_form.py
    └── merge.py

SKILL.md content:

---
name: pdf-tool
description: 处理 PDF 文件,包括提取文本、填写表单、合并文件。使用场景:处理 PDF、提取文本、填写表单、合并 PDF。
---

## 提取 PDF 文本

从 PDF 文件中提取文本内容:

```bash
python scripts/extract.py input.pdf
```

输出是提取的纯文本内容。

## 填写 PDF 表单

使用 JSON 数据填写 PDF 表单:

```bash
python scripts/fill_form.py input.pdf data.json output.pdf
```

data.json 格式:
```json
{
  "field_name": "字段值",
  "another_field": "另一个值"
}
```

## 合并 PDF

将多个 PDF 文件合并为一个:

```bash
python scripts/merge.py output.pdf input1.pdf input2.pdf input3.pdf
```

## 依赖安装

需要安装 pdfplumber 和 PyPDF2:

```bash
pip install pdfplumber PyPDF2
```

Two Usage Modes

There are two ways to use code in a Skill:

Method Applicable Scenario Whether scripts/ directory is needed
One-shot Command Only need to call existing tools, no custom logic required Not needed
Self-contained Script Complex logic that needs to be reused Needed

One-shot Commands

When existing package manager tools already meet the requirements, you can directly reference them in the SKILL.md instructions without creating a scripts/ directory.

The following are common execution methods in each language ecosystem:

uvx(Python)

uvx is the tool-running command that comes with uv. It runs Python packages in an isolated environment, and with aggressive caching, repeated runs are nearly instantaneous.

Example

# Run the specified version of ruff to check code
uvx ruff@0.8.0 check .

# Run the specified version of black to format code
uvx black@24.10.0 .

pipx(Python)

pipx is a mature alternative to uvx and can be installed via system package managers (e.g.,brew install pipx)。

Example

# Run the specified version of black
pipx run 'black==24.10.0' .

# Run the specified version of ruff
pipx run 'ruff@0.8.0' check .

npx(Node.js)

npx comes with npm and downloads and runs npm packages on demand.

Example

# Run ESLint check
npx eslint@9 --fix .

# Create a project with Vite
npx create-vite@6 my-app

go run(Go)

Go's built-in tool-running command compiles and runs remote packages directly.

Example

# Run goimports to format imports
go run golang.org/x/tools/cmd/goimports@v0.28.0 .

# Run golangci-lint check
go run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.0 run

Recommendations for writing one-shot commands: Pin version numbers (e.g.,npx eslint@9.0.0) to ensure consistent behavior; declare prerequisites in SKILL.md (e.g., "Node.js 18+ required"); when commands become complex, extract them into the scripts/ directory.


Referencing Scripts in SKILL.md

Use paths starting from the Skill directory rootrelative pathsto reference packaged files.

The agent will automatically resolve these paths; there is no need to use absolute paths.

First, list the available scripts in SKILL.md:

Example

## Available Scripts

- **`scripts/validate.sh`** — Validate configuration files
- **`scripts/process.py`** — Process input data
- **`scripts/report.py`** — Generate analysis reports

Then reference them in the operation steps:

Example

## Operation Workflow

1. Run the validation script:
   ```bash
   bash scripts/validate.sh "$INPUT_FILE"
   ```

2. Process data:
   ```bash
   python3 scripts/process.py --input results.json
   ```

Script execution paths are relative to the Skill directory root, because the Agent runs commands from the Skill directory. This also applies to auxiliary files such as references/*.md.


Self-contained Scripts

When you need reusable logic, you can package scripts in thescripts/directory and declare dependencies within the script.

The Agent can run it with a single command, with no additional installation steps.

Python Self-contained Script (PEP 723)

PEP 723 defines a standard format for declaring dependencies inside Python scripts.

Use# ///markers to wrap the TOML-format dependency declaration:

Example: Python Self-contained Script

# /// script
# dependencies = [
#   "beautifulsoup4",
# ]
# ///

from bs4 import BeautifulSoup

# Example HTML content
html = '<html><body><h1>Welcome</h1><p class="info">EXAMPLE Test</p></body></html>'

# Parse HTML with BeautifulSoup
soup = BeautifulSoup(html, "html.parser")

# Extract the paragraph text with class="info"
info_text = soup.select_one("p.info").get_text()
print(info_text)

How to run:

Example

# Run with uv (recommended)
uv run scripts/extract.py

# Run with pipx
pipx run scripts/extract.py
EXAMPLE 测试

Deno Self-contained Script

Deno usesnpm:andjsr:import specifiers to achieve self-containment:

Example: Deno Self-contained Script

#!/usr/bin/env -S deno run

import * as cheerio from "npm:cheerio@1.0.0";

const html = `<html><body><h1>Welcome</h1><p class="info">EXAMPLE Test</p></body></html>`;
const $ = cheerio.load(html);
console.log($("p.info").text());

Example

deno run scripts/extract.ts

Bun Self-contained Script

When Bun has nonode_modulesdirectory, it automatically installs missing packages:

Example: Bun Self-contained Script

#!/usr/bin/env bun

import * as cheerio from "cheerio@1.0.0";

const html = `<html><body><h1>Welcome</h1><p class="info">EXAMPLE Test</p></body></html>`;
const $ = cheerio.load(html);
console.log($("p.info").text());

Example

bun run scripts/extract.ts

Ruby Self-contained Script

Ruby usesbundler/inlineto declare gem dependencies in the script:

Example: Ruby Self-contained Script

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'nokogiri'
end

html = '<html><body><h1>Welcome</h1><p class="info">EXAMPLE Test</p></body></html>'
doc = Nokogiri::HTML(html)
puts doc.at_css('p.info').text

Example

ruby scripts/extract.rb

Key Points for Designing Scripts for Agents

The Agent determines its next actions by reading stdout and stderr, so script design should take the Agent's usage characteristics into account.

Avoid Interactive Prompts

This is a hard requirement. The Agent runs in a non-interactive shell and cannot respond to TTY prompts, password dialogs, or confirmation menus.

All input should be passed via command-line arguments, environment variables, or stdin.

Example: Wrong Approach vs Correct Approach

# Wrong: will hang waiting for input
$ python scripts/deploy.py
Target environment: _

# Right: clear error message and guidance
$ python scripts/deploy.py
Error: --env is required. Options: development, staging, production.
Usage: python scripts/deploy.py --env staging --tag v1.2.3

Provide --help Documentation

--helpOutput is the primary way for the Agent to understand the script's interface.

Include a brief description, available parameters, and usage examples:

Example: Good --help Output

Usage: scripts/process.py [OPTIONS] INPUT_FILE

Process input data and generate a summary report.

Options:
  --formatFORMAT Output format: json, csv, table(Default: json)
  --outputFILE Write output to a file instead of stdout
  --verbosePrint progress information to stderr

Examples:
  scripts/process.py data.csv
  scripts/process.py --format csv --output report.csv data.csv

Write Useful Error Messages

When the Agent sees an error message, it adjusts its strategy accordingly; the more specific the message, the easier it is for the Agent to self-correct.

Example

# Poor error message
Error: invalid input

# Good error message
Error: --format must be one of: json, csv, table.
       Received: "xml"

Use Structured Output

Prefer structured formats such as JSON, CSV, and TSV for output, rather than free-form text.

Structured formats can be consumed by both the Agent and standard tools (jq, cut, awk), making them easy to combine.

Example

# Not recommended: aligned text is hard to parse programmatically
NAME          STATUS    CREATED
my-service    running   2025-01-15

# Recommended: JSON format with clear field boundaries
{"name": "my-service", "status": "running", "created": "2025-01-15"}

Output structured data to stdout, and progress messages and diagnostic information to stderr. This way the Agent gets clean, parseable output while still being able to view diagnostic information when needed.


More Script Design Suggestions

Suggestion Description
Idempotency The Agent may retry commands. "Create if it doesn't exist" is safer than "create and error on duplicates"
Input constraints Reject ambiguous input with a clear error, rather than guessing the user's intent
Dry-run support For destructive or stateful operations, provide a--dry-runflag to let the Agent preview the operation
Meaningful exit codes Use different exit codes for different failure types (not found, invalid argument, authentication failure, etc.)
Predictable output size Output a summary by default and provide--offsetother parameters so the Agent can get more information as needed.
Safe defaults Destructive operations should require an explicit confirmation flag (--confirm、--force)

Complete Skill Script Example

Below is a complete Skill directory structure containing scripts:

Example

csv-analyzer/
├── SKILL.md              # Main instruction file
├── scripts/
│   ├── overview.py       # Data overview script
│   ├── summary.py        # Statistical summary script
│   └── validate.py       # Data validation script
├── references/
│   └── api-errors.md     # API error reference
└── assets/
    └── report-template.md  # Report template

The corresponding SKILL.md content:

Example

---
name: csv-analyzer
description: >
Analyze CSV and tabular data files. When the user has CSV, TSV, or Excel files
and wants to explore, transform, or visualize data, use this.
---

# CSV data analysis

## Available scripts

- **`scripts/overview.py`** — Displays the data overview (row count, column names, types)
- **`scripts/summary.py`** — Generates a statistical summary
- **`scripts/validate.py`** — Validates data quality

## Workflow

1. First, run the overview script to understand the data structure:
   ```bash
   uv run scripts/overview.py input.csv
   ```

2. Generate the statistical summary:
   ```bash
   uv run scripts/summary.py input.csv --output summary.json
   ```

3. Validate the data quality:
   ```bash
   uv run scripts/validate.py input.csv
   ```

## Notes

- For large files, use the `--chunk-size` parameter to process in chunks
- For Chinese CSV files, try the `--encoding gbk` parameter

Script Distribution and Dependencies

If your scripts need external dependencies, you have several options:

1. Document Dependencies in SKILL.md

The simplest way is to record the required dependencies in SKILL.md.

2. Use Virtual Environments

For complex projects, you can create a virtual environment.

3. Use Docker

If a complete runtime environment is needed, you can use a Docker container.

Note: Make sure the scripts can run in the target environment. Before writing scripts, understand the target user's runtime environment.


Summary

In this section, we learned how to use scripts to extend Skill functionality:

  • Place scripts in the scripts/ directory
  • Scripts should be self-contained and have clear error handling
  • Use relative paths when referencing scripts in SKILL.md
  • Make sure the scripts can run in the target environment
Other extensions