# SKILL.md Schema for CLI-Anything: A Complete Guide to Metadata Extraction and Structure

> Learn the SKILL.md schema for CLI-Anything. Extract metadata from Python code, READMEs, and package info using structured Markdown for powerful CLI tools.

- Repository: [✨Data Intelligence Lab@HKU✨/CLI-Anything](https://github.com/HKUDS/CLI-Anything)
- Tags: deep-dive
- Published: 2026-05-18

---

**The SKILL.md schema defines a structured Markdown format for CLI "skills" that combines YAML front-matter with auto-generated sections extracted from Python source code, README files, and package metadata.**

CLI-Anything uses the **SKILL.md** document to create machine-readable specifications for command-line wrappers. The schema follows a deterministic Markdown structure generated by [`skill_generator.py`](https://github.com/HKUDS/CLI-Anything/blob/main/skill_generator.py) that bridges Python Click-based CLIs and agent systems. Understanding this schema helps developers trace how command groups, constraints, and version information flow from source code into standardized documentation.

## SKILL.md Schema Structure

The SKILL.md file follows a fixed Markdown template with eight distinct sections. Each section serves a specific purpose in describing the CLI capabilities to downstream systems.

### YAML Front-Matter

The document opens with YAML front-matter containing two required fields:

- `name` — The skill's identifier (e.g., `zotero`)
- `description` — A short tagline summarizing the tool's purpose

This block is generated by `generate_skill_md_simple` at lines 95–101 in [`zotero/agent-harness/skill_generator.py`](https://github.com/HKUDS/CLI-Anything/blob/main/zotero/agent-harness/skill_generator.py).

### Document Body Sections

Following the front-matter, the schema includes these Markdown sections:

**Title and Introduction**
- `# <skill-name>` — The main heading derived from the package directory name

- Intro paragraph — Extracted from the first non-header lines of the package's [`README.md`](https://github.com/HKUDS/CLI-Anything/blob/main/README.md) via `extract_intro_from_readme` (lines 51–68)

**Installation and Entry Points**
- **Installation** — Contains a minimal `pip install -e .` snippet (hard-coded at lines 105–108)
- **Entry Points** — Lists the CLI wrapper (`cli-anything-<software>`) and module entry point (`python -m cli_anything.<software>`) at lines 110–115

**Runtime Constraints**
- **Important Constraints** — Optional bulleted list of runtime limits or required configuration generated by `generate_important_constraints` (lines 60–70)

**Command Documentation**
- **Command Groups** — One or more groups parsed from Click decorators. Each group contains:
  - A description
  - A Markdown table with columns `| Command | Description |`
  
  This section iterates over `metadata.command_groups` at lines 124–129.

**Usage Examples**
- **Examples** — Ready-to-run command snippets with titles and descriptions, produced by `generate_examples` (lines 50–57)

**Version Tracking**
- **Version** — The package version string extracted from [`setup.py`](https://github.com/HKUDS/CLI-Anything/blob/main/setup.py) via `extract_version_from_setup` (lines 71–78)

## How Metadata Is Extracted

The extraction pipeline in [`skill_generator.py`](https://github.com/HKUDS/CLI-Anything/blob/main/skill_generator.py) transforms raw Python source code into structured metadata through seven discrete steps.

### Step 1: Detect the Software Package

The generator locates the software directory by scanning for Python packages containing [`__init__.py`](https://github.com/HKUDS/CLI-Anything/blob/main/__init__.py):

```python
harness_root = Path(harness_path)
cli_root = harness_root / "cli_anything"
software_dir = next(p for p in cli_root.iterdir()
                    if p.is_dir() and (p / "__init__.py").exists())
software_name = software_dir.name

```

This logic appears in `extract_cli_metadata` at lines 73–77.

### Step 2: Extract Introduction Text

The `extract_intro_from_readme` function (lines 51–68) reads the package's [`README.md`](https://github.com/HKUDS/CLI-Anything/blob/main/README.md) and concatenates the first non-header lines to create the human-readable introduction paragraph.

### Step 3: Parse Version Information

Version strings are extracted from [`setup.py`](https://github.com/HKUDS/CLI-Anything/blob/main/setup.py) using regular expressions that match `PACKAGE_VERSION` or standard `version` fields. See `extract_version_from_setup` at lines 71–78.

### Step 4: Parse Command Groups and Commands

The generator uses Python's `ast` module to analyze the CLI source file (e.g., [`zotero_cli.py`](https://github.com/HKUDS/CLI-Anything/blob/main/zotero_cli.py)). The `extract_commands_from_cli` function (lines 13–47) identifies:

- **Groups** — Functions decorated with `@cli.group`
- **Commands** — Functions decorated with `@cli.command` within those groups

If decorators specify explicit names, those are used; otherwise, the generator derives defaults from function names using `_default_group_name` and `_default_command_name`.

### Step 5: Generate Constraints

Runtime constraints are handled by `generate_important_constraints` (lines 60–70). While the Zotero skill returns a static list of limitations, other implementations may return empty lists if no constraints apply.

### Step 6: Create Usage Examples

The `generate_examples` function (lines 50–57) produces hard-coded usage snippets customized with the specific software name, providing ready-to-run demonstrations of common workflows.

### Step 7: Compile Metadata and Render

All extracted data is wrapped into a `SkillMetadata` dataclass (lines 39–48) and passed to `generate_skill_md`. If Jinja2 is unavailable, the fallback `generate_skill_md_simple` (lines 92–135) constructs the Markdown directly without template dependencies.

## Template-Based vs. Programmatic Generation

CLI-Anything supports two rendering strategies:

- **Jinja2 Template** — When available, the system uses `zotero/agent-harness/templates/SKILL.md.template` for flexible customization
- **Simple Generator** — The fallback `generate_skill_md_simple` function writes Markdown sections programmatically, ensuring the tool works without optional dependencies

An example rendered output appears at [`sbox/agent-harness/cli_anything/sbox/skills/SKILL.md`](https://github.com/HKUDS/CLI-Anything/blob/main/sbox/agent-harness/cli_anything/sbox/skills/SKILL.md), demonstrating the final structure produced by this pipeline.

## Summary

- The **SKILL.md schema** combines YAML front-matter with standardized Markdown sections for installation, entry points, command groups, examples, and version information.
- **Metadata extraction** relies on AST parsing of Click decorators (`@cli.group`, `@cli.command`) via `extract_commands_from_cli` to build the command documentation.
- **Auxiliary data** flows from [`README.md`](https://github.com/HKUDS/CLI-Anything/blob/main/README.md) (intro text), [`setup.py`](https://github.com/HKUDS/CLI-Anything/blob/main/setup.py) (version), and hard-coded generators (examples, constraints).
- The `SkillMetadata` dataclass (lines 39–48) serves as the central data structure before rendering through either Jinja2 templates or `generate_skill_md_simple`.

## Frequently Asked Questions

### What is the purpose of the SKILL.md file in CLI-Anything?

The SKILL.md file serves as a machine-readable contract between Python CLI tools and agent systems. It standardizes how commands, constraints, and usage patterns are declared, allowing automated systems to discover and interact with CLI wrappers without executing the code.

### How does CLI-Anything extract command groups from Python source code?

The system uses Python's `ast` module in `extract_commands_from_cli` (lines 13–47) to statically analyze the CLI file (e.g., [`zotero_cli.py`](https://github.com/HKUDS/CLI-Anything/blob/main/zotero_cli.py)). It searches for Click decorators—specifically `@cli.group` for groups and `@cli.command` for individual commands—then extracts function names or explicit decorator arguments to populate the command tables.

### What metadata is required versus optional in the SKILL.md schema?

Required sections include the YAML front-matter (`name`, `description`), the skill title, introduction paragraph, installation instructions, entry points, command groups, and version. Optional sections include **Important Constraints** and **Examples**, which the generator includes only when data is present in the source.

### Which specific files does the skill generator analyze to build the SKILL.md?

The generator reads four key locations: (1) the [`README.md`](https://github.com/HKUDS/CLI-Anything/blob/main/README.md) for introductory text, (2) [`setup.py`](https://github.com/HKUDS/CLI-Anything/blob/main/setup.py) for version strings, (3) the CLI Python file (e.g., [`zotero/agent-harness/cli_anything/zotero/zotero_cli.py`](https://github.com/HKUDS/CLI-Anything/blob/main/zotero/agent-harness/cli_anything/zotero/zotero_cli.py)) for command structures via AST parsing, and (4) optionally `templates/SKILL.md.template` if Jinja2 rendering is desired.