--- topic: agentskills-scripts source_keys: - agentskills-using-scripts --- ## One-off commands When an existing package does what you need, reference it directly in `SKILL.md` without a `scripts/` directory. Use package runners that auto-resolve dependencies: | Runner | Language | Notes | |--------|----------|-------| | `uvx package@version` | Python | Recommended. Ships with `uv`. Caches aggressively. | | `pipx run 'package==version'` | Python | Mature alternative, broader OS availability. | | `npx package@version` | Node.js | Ships with npm/Node.js. Pin versions for reproducibility. | | `bunx package@version` | Node.js | Bun equivalent of npx. Only in Bun environments. | | `deno run npm:package@version` | TypeScript | Requires permission flags (`--allow-read`, etc.). | | `go run golang.org/x/...@version` | Go | Built into Go toolchain. | Tips: - Always pin versions (e.g., `npx eslint@9.0.0`) for consistent behavior over time. - State prerequisites in `SKILL.md` (e.g., "Requires Node.js 18+") or in the `compatibility` frontmatter field. - Move complex commands into `scripts/` when a one-off command is hard to get right on the first try. ## Referencing scripts from SKILL.md Use **relative paths from the skill directory root**. List available scripts so the agent knows they exist, then instruct it to run them: ```markdown ## Available scripts - **`scripts/validate.sh`** — Validates configuration files - **`scripts/process.py`** — Processes input data ## Workflow 1. Run validation: ```bash bash scripts/validate.sh "$INPUT_FILE" ``` 2. Process results: ```bash python3 scripts/process.py --input results.json ``` ``` The same relative-path convention works in `references/*.md` files. ## Self-contained scripts with inline dependencies Bundle scripts that declare their own dependencies so the agent can run them with a single command. **Python (PEP 723 + uv):** ```python # /// script # dependencies = [ # "beautifulsoup4>=4.12,<5", # ] # requires-python = ">=3.12" # /// from bs4 import BeautifulSoup # ... ``` ```bash uv run scripts/extract.py ``` **TypeScript (Deno):** ```typescript #!/usr/bin/env -S deno run import * as cheerio from "npm:cheerio@1.0.0"; // ... ``` ```bash deno run scripts/extract.ts ``` **TypeScript (Bun):** ```typescript #!/usr/bin/env bun import * as cheerio from "cheerio@1.0.0"; // ... ``` ```bash bun run scripts/extract.ts ``` **Ruby (bundler/inline):** ```ruby require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'nokogiri', '~> 1.16' end # ... ``` ```bash ruby scripts/extract.rb ``` ## Designing scripts for agentic use ### No interactive prompts (hard requirement) Agents run in non-interactive shells and cannot respond to TTY prompts. A script that blocks on input hangs indefinitely. Accept all input via command-line flags, environment variables, or stdin: ``` # Bad $ python scripts/deploy.py Target environment: _ # Good $ python scripts/deploy.py Error: --env is required. Options: development, staging, production. Usage: python scripts/deploy.py --env staging --tag v1.2.3 ``` ### Document with `--help` `--help` output is the primary way an agent learns your script's interface: ``` Usage: scripts/process.py [OPTIONS] INPUT_FILE Process input data and produce a summary report. Options: --format FORMAT Output format: json, csv, table (default: json) --output FILE Write output to FILE instead of stdout --verbose Print progress to stderr ``` Keep it concise — it enters the agent's context window. ### Write helpful error messages ``` Error: --format must be one of: json, csv, table. Received: "xml" ``` Say what went wrong, what was expected, and what to try. ### Use structured output Prefer JSON, CSV, or TSV over free-form text. Separate data from diagnostics: - **stdout** — structured data (JSON, CSV) - **stderr** — progress messages, warnings, diagnostics ``` # Hard to parse NAME STATUS CREATED my-service running 2025-01-15 # Unambiguous {"name": "my-service", "status": "running", "created": "2025-01-15"} ``` ### Further design considerations - **Idempotency.** Agents may retry. "Create if not exists" is safer than "create and fail on duplicate." - **Input constraints.** Reject ambiguous input with a clear error. Use enums and closed sets where possible. - **Dry-run support.** A `--dry-run` flag lets agents preview destructive operations. - **Meaningful exit codes.** Use distinct codes for different failure types; document them in `--help`. - **Safe defaults.** Destructive operations should require explicit confirmation flags (`--confirm`, `--force`). - **Predictable output size.** Many harnesses truncate tool output beyond 10–30K characters. Default to a summary or reasonable limit; support `--offset` for pagination, or require `--output FILE` to opt in to large stdout.