Skills and Toolchain Integration

By integrating with external toolchains, Skills can accomplish tasks that Claude alone cannot.

This article introduces how to call command-line tools, system tools, and third-party libraries in a Skill, and provides a complete integration example.


Tool Types That Skills Can Call

Tool TypeExampleInvocation Method
System Commandsls、cp、find、wcsubprocess.run()
Language Runtimepython、node、bashsubprocess.run()
Document Processing Toolspandoc、pdflatexsubprocess.run()
Media Processing Toolsffmpeg、imagemagicksubprocess.run()
Python Librariespandas、openpyxl、pypdfCall directly after import
Node.js Toolsprettier、eslintInvoke via npx

Before calling external tools, confirm that the tools are installed in the runtime environment. Common tools (python3, pip, node, npm) are preinstalled in the Claude sandbox, but pandoc, ffmpeg, etc. need to be installed separately.


Calling External Commands in Scripts

Python'ssubprocess`subprocess` module is the standard way to call external commands. It is recommended to wrap it uniformly into reusable utility functions.

Example

# File path: scripts/tool_integration.py
import subprocess
import sys
import json

def run_command(cmd: list, timeout: int = 60) -> dict:
    """
Run an external command and capture the output

Parameters:
cmd: command list, e.g., ["pandoc", "--version"]
timeout: timeout in seconds, default 60

Returns:
a dict containing success, stdout, stderr, returncode
    """

    try:
        result = subprocess.run(
            cmd,
            capture_output=True,   # Capture both stdout and stderr
            text=True,             # Return as a string, not bytes
            timeout=timeout
        )
        return {
            "success":    result.returncode == 0,
            "returncode": result.returncode,
            "stdout":     result.stdout.strip(),
            "stderr":     result.stderr.strip()
        }
    except FileNotFoundError:
        return {
            "success":    False,
            "returncode": -1,
            "stdout":     "",
            "stderr":     f"Command not found: {cmd
        }
    except subprocess.TimeoutExpired:
        return {
            "success":    False,
            "returncode": -1,
            "stdout":     "",
            "stderr":     f"Command execution timed out (exceeded {timeout} seconds)"
        }

# Example: use pandoc to convert Markdown to HTML
if __name__ == "__main__":
    result = run_command([
        "pandoc",
        "/mnt/user-data/uploads/readme.md",
        "-o", "/mnt/user-data/outputs/readme.html",
        "--standalone"
    ])
    if result["success"]:
        print("Conversion successful")
    else:
        print(f"Conversion failed: {result['stderr']}")
        sys.exit(1)

Checking Whether a Tool Is Available

Checking whether the required tools are installed before executing a Skill provides clear feedback before the task fails midway.

Example

# File path: scripts/check_tools.py
import shutil
import sys

REQUIRED_TOOLS = [
    ("pandoc",  "sudo apt-get install pandoc"),
    ("ffmpeg",  "sudo apt-get install ffmpeg"),
    ("convert", "sudo apt-get install imagemagick"),
]

def check_tools(tools: list) -> bool:
    """Check the tool list, return True if all are ready"""
    all_ok = True
    for tool, install_cmd in tools:
        path = shutil.which(tool)   # Find the tool path in PATH
        if path:
            print(f" Installed: {tool} → {path}")
        else:
            print(f" Not installed: {tool} Install command: {install_cmd}")
            all_ok = False
    return all_ok

if __name__ == "__main__":
    print("Checking tool dependencies...")
    if not check_tools(REQUIRED_TOOLS):
        print("\n"Please install the missing tools first.")
        sys.exit(1)
    print("\n"All tools are ready, continue execution.")
检查工具依赖...
  已安装:pandoc → /usr/bin/pandoc
  未安装:ffmpeg  安装命令:sudo apt-get install ffmpeg
  未安装:convert  安装命令:sudo apt-get install imagemagick

请先安装缺少的工具。

Declaring Tool Dependencies in SKILL.md

Use YAML frontmatter'scompatibility`dependencies` field to list all external dependencies, so users know what to prepare before installing the Skill.

---
name: doc-converter
description: >
  将文档在不同格式间转换,支持 Markdown、HTML、PDF、Word。
  当用户需要格式转换、导出文档时触发。
compatibility:
  tools:
    - pandoc >= 2.14   # 文档格式转换
    - python >= 3.8    # 运行辅助脚本
  python_packages:
    - pypdf >= 3.0     # PDF 处理
    - python-docx >= 1.0
---

Integrating Node.js Tools

Throughnpx`npx`, you can directly call CLI tools from npm packages without global installation.

Example

# File path: scripts/use_node_tool.py
import subprocess
import sys

def run_prettier(file_path: str) -> bool:
    """Format code files with prettier"""
    result = subprocess.run(
        ["npx", "--yes", "prettier", "--write", file_path],
        capture_output=True,
        text=True
    )
    if result.returncode == 0:
        print(f"Formatting successful: {file_path}")
        return True
    print(f"Formatting failed: {result.stderr}")
    return False

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python use_node_tool.py <file path>")
        sys.exit(1)
    sys.exit(0 if run_prettier(sys.argv[1]) else 1)

npx --yesOn first run, the tool package is downloaded automatically, requiring a network connection to the npm registry. In network-restricted environments, install it globally in advance:npm install -g prettier。


Standardizing Tool Call Results

Different tools have different output formats. It is recommended to wrap them uniformly at the Skill layer, exposing only a consistent structure externally.

Handling MethodApplicable ScenarioTypical Tools
Capture stdoutThe tool outputs the result to standard outputpandoc、wc、cat
Check the return codeThe tool returns 0 on success and non-zero on failureAlmost all CLI tools
Read the output fileThe tool writes the result to a specified fileffmpeg、pandoc -o
Parse JSON outputThe tool supports the --json parametereslint --format json

Complete Integration Example: Markdown to PDF Report

The following example combines pandoc with a Python script to implement a complete Markdown → PDF generation Skill script.

Example

# File path: scripts/md_to_pdf.py
# Complete workflow: check tool → validate input → call pandoc → confirm output

import subprocess
import shutil
import sys
import os
import json
from datetime import datetime

def check_pandoc() -> bool:
    """Check whether pandoc is available"""
    if not shutil.which("pandoc"):
        print("Error: pandoc not found, please run: sudo apt-get install pandoc")
        return False
    return True

def validate_input(md_path: str) -> bool:
    """Validate the input Markdown file"""
    if not os.path.exists(md_path):
        print(f"Error: file does not exist → {md_path}")
        return False
    if not md_path.lower().endswith(".md"):
        print(f"Error: file must be in .md format → {md_path}")
        return False
    return True

def convert_to_pdf(md_path: str, output_dir: str) -> dict:
    """Call pandoc to convert Markdown to PDF"""
    os.makedirs(output_dir, exist_ok=True)

    # Generate an output filename with a timestamp to avoid overwriting old files
    base_name   = os.path.splitext(os.path.basename(md_path))[0]
    timestamp   = datetime.now().strftime("%Y%m%d_%H%M%S")
    output_path = os.path.join(output_dir, f"{base_name}_{timestamp}.pdf")

    result = subprocess.run(
        [
            "pandoc", md_path,
            "-o", output_path,
            "--pdf-engine=xelatex",      # Support Chinese
            "-V", "CJKmainfont=SimSun",  # Chinese font (adjust according to the environment)
            "-V", "geometry:margin=2cm"  # Page margin
        ],
        capture_output=True,
        text=True,
        timeout=120
    )

    if result.returncode == 0 and os.path.exists(output_path):
        size_kb = os.path.getsize(output_path) // 1024
        return {
            "status":  "success",
            "output":  output_path,
            "size_kb": size_kb
        }
    return {
        "status": "error",
        "message": result.stderr or "pandoc did not generate an output file"
    }

def main():
    if len(sys.argv) < 2:
        print("Usage: python md_to_pdf.py <Markdown file path>")
        sys.exit(1)

    md_path    = sys.argv[1]
    output_dir = "/mnt/user-data/outputs"

    # Check step by step; exit immediately if any step fails
    if not check_pandoc():
        sys.exit(1)
    if not validate_input(md_path):
        sys.exit(1)

    print(f"Converting: {md_path}")
    result = convert_to_pdf(md_path, output_dir)
    print(json.dumps(result, ensure_ascii=False, indent=2))

    sys.exit(0 if result["status"] == "success" else 1)

if __name__ == "__main__":
    main()
正在转换:/mnt/user-data/uploads/example_report.md
{
  "status": "success",
  "output": "/mnt/user-data/outputs/example_report_20260518_102305.pdf",
  "size_kb": 248
}

Call this script in SKILL.md:

## 执行转换

获取用户上传的 .md 文件路径后,运行:

```bash
python scripts/md_to_pdf.py <文件路径>
```

解析 JSON 输出:
- status 为 "success":调用 present_files 展示 output 路径的文件
- status 为 "error":将 message 内容展示给用户,说明可能原因
Other Extensions