# index.html.md

<!-- generated by epythet -->

# skill

AI Agent Skill Search and Management

Manage [Agent Skills](https://agentskills.io) (SKILL.md files) across multiple AI coding agents — Claude Code, Cursor, GitHub Copilot, Windsurf, and more.

## Install

```default
pip install skill
```

## Quick Start

```python
from skill import search, create, install, validate

# Create a skill locally
skill = create("my-skill", description="My custom coding rules")

# Validate it
issues = validate("/path/to/skill-dir")

# Search for skills
results = search("react best practices", local_only=True)

# Install to an agent target
install("_local/my-skill", agent_targets=["claude-code"], scope="project")
```

### Link skills from a project

If a project ships skills (in `.claude/skills/`, `{pkg}/data/skills/`, or a
dedicated folder), you can symlink them all into your agent’s skills directory
in one shot:

```python
from skill import link_skills

# Point at a project root — it finds the skills automatically
link_skills("/path/to/my-project")

# Or point at the skills folder directly
link_skills("/path/to/my-project/my_pkg/data/skills")

# Symlink into a specific target instead of ~/.claude/skills
link_skills("/path/to/my-project", target="/other/project/.claude/skills")
```

Each skill is validated before linking — invalid skills are skipped with a
warning. The target directory is also checked to ensure it’s a recognized
skills directory.

### CLI

```default
skill create my-skill --description "My custom coding rules"
skill search "react best practices" --local-only
skill validate ./my-skill/
skill list-skills
skill install _local/my-skill --agent-targets claude-code
skill link-skills /path/to/project
skill link-skills /path/to/project --target ~/.claude/skills --force
```

### Shell completion

Enable tab completion for all `skill` commands:

```bash
skill install-completion
```

This detects your shell (bash/zsh) and adds the registration line to your
shell config (`~/.bashrc` or `~/.zshrc`). Restart your shell or `source` the
config file to activate.

If you prefer to set it up manually:

```bash
# Add to your shell config:
eval "$(register-python-argcomplete skill)"
```

The first time you run any `skill` command without completion set up, you’ll
see a one-time hint reminding you to run `skill install-completion`.

## Skills

This package ships agent skills you can install into any agent host with
[`gh skill`](https://cli.github.com/manual/gh_skill) (don’t have it?
[install gh](https://cli.github.com/)):

```bash
gh skill install thorwhalen/skill skill-package-setup --agent claude-code
gh skill install thorwhalen/skill skill-build
gh skill install thorwhalen/skill skill-enable
gh skill install thorwhalen/skill skill-docs
gh skill install thorwhalen/skill skill-manage
gh skill install thorwhalen/skill skill-sync
```

| Skill                 | Use it when…                                                                               |
|-----------------------|--------------------------------------------------------------------------------------------|
| `skill-manage`        | searching, listing, inspecting, or installing/uninstalling skills across agents            |
| `skill-enable`        | shipping a package’s skills via `pip install` and deciding which to ship                   |
| `skill-package-setup` | deciding where a package’s skills live and making them `gh skill`-installable (maintainer) |
| `skill-build`         | authoring skills for a package by analyzing its code, tests, and docs (developer)          |
| `skill-docs`          | documenting a project’s skills in its README (developer)                                   |
| `skill-sync`          | keeping skills in sync with the source code they document (developer)                      |

These are dev/maintainer skills, so they’re not bundled in the wheel — install
them with `gh skill` as above. See `skill-package-setup` for the layout policy
this repo follows (real files in `skills/`, relative symlinks in `.claude/skills/`).

Packages can also install their own GitHub-published skills programmatically via
[`skill.install_from_github(repo, names, agent='claude-code')`](),
a thin wrapper over the `gh skill` CLI.

## Plugin System

`skill` has a registry-based plugin architecture with four extension points:

| Registry          | What it holds                        | Import                                    |
|-------------------|--------------------------------------|-------------------------------------------|
| **Agent targets** | Where agents expect skills installed | `from skill.install import agent_targets` |
| **Translators**   | SKILL.md → target format converters  | `from skill.translate import translators` |
| **Backends**      | Remote skill sources for search      | `from skill.search import backends`       |
| **Validators**    | Pluggable validation rules           | `from skill.create import validators`     |

Register at runtime:

```python
from skill.install import agent_targets, AgentTarget

agent_targets.register(
    "windsurf",
    AgentTarget(
        name="windsurf",
        project_path="{project}/.windsurf/rules/{name}.md",
        format="skill.md",
    ),
)
```

Or via entry points in your `pyproject.toml`:

```toml
[project.entry-points."skill.agent_targets"]
windsurf = "my_package:windsurf_target"
```

See [Plugin System Documentation]() for full details on contracts, interfaces, and built-in registrations.

<p class="epythet-aggregates">This documentation as a single file: <a href="skill.md">skill.md</a> (Markdown, for agents).</p>


# _autosummary/skill.ai.html.md

# skill.ai

Optional AI facade for semantic search and LLM-powered features.

All imports are lazy. This module works without any AI dependencies —
it gracefully degrades when providers are not installed.

### Functions

| [`chat`](_autosummary/skill.ai.html.md#skill.ai.chat)(prompt, \*[, system, model, temperature])   | Send a chat completion request to the configured AI provider.   |
|---------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|
| [`is_ai_available`](_autosummary/skill.ai.html.md#skill.ai.is_ai_available)()                                | Check if an AI provider is available.                           |

### skill.ai.chat(prompt, , system=None, model=None, temperature=0.0)

Send a chat completion request to the configured AI provider.

Provider resolution order: aisuite -> anthropic -> openai.

Raises ImportError with actionable install instructions if no
provider is available.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

### skill.ai.is_ai_available()

Check if an AI provider is available.

Returns True if any supported provider can be imported and
an API key is configured (or detectable from environment).

* **Return type:**
  [`bool`](https://docs.python.org/3/library/functions.html#bool)

```pycon
>>> isinstance(is_ai_available(), bool)
True
```


# _autosummary/skill.backends.awesome_list.html.md

# skill.backends.awesome_list

Awesome-claude-skills curated list backend for skill discovery.

### Classes

| [`AwesomeListSource`](_autosummary/skill.backends.awesome_list.html.md#skill.backends.awesome_list.AwesomeListSource)(\*[, http_get])   | SkillSource backed by the awesome-claude-skills curated list.   |
|--------------------------------------------------------------------------------------|-----------------------------------------------------------------|

### *class* skill.backends.awesome_list.AwesomeListSource(, http_get=None)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

SkillSource backed by the awesome-claude-skills curated list.

Fetches and parses the README from
`github.com/travisvn/awesome-claude-skills`.

```pycon
>>> src = AwesomeListSource()
>>> src.name
'awesome-list'
```

#### search(query, , max_results=10)

Search the curated list for skills matching *query*.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]


# _autosummary/skill.backends.composio.html.md

# skill.backends.composio

Composio backend for skill discovery and fetching.

### Classes

| [`ComposioSkillSource`](_autosummary/skill.backends.composio.html.md#skill.backends.composio.ComposioSkillSource)(\*[, token, http_get])   | SkillSource backed by the Composio API (v3).   |
|-----------------------------------------------------------------------------------------------|------------------------------------------------|

### *class* skill.backends.composio.ComposioSkillSource(, token=None, http_get=None)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

SkillSource backed by the Composio API (v3).

Requires a `COMPOSIO_API_KEY` environment variable or explicit *token*.

```pycon
>>> src = ComposioSkillSource(token="my-key")
>>> src.name
'composio'
```

#### search(query, , max_results=10)

Search Composio for tools matching *query*.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]


# _autosummary/skill.backends.github.html.md

# skill.backends.github

GitHub backend for skill discovery and fetching.

### Classes

| [`GitHubSkillSource`](_autosummary/skill.backends.github.html.md#skill.backends.github.GitHubSkillSource)(\*[, token, http_get])   | SkillSource backed by the GitHub API.   |
|---------------------------------------------------------------------------------------------|-----------------------------------------|

### *class* skill.backends.github.GitHubSkillSource(, token=None, http_get=None)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

SkillSource backed by the GitHub API.

Searches for SKILL.md files via the Code Search API and fetches
skill content via the Contents API.

```pycon
>>> src = GitHubSkillSource()
>>> src.name
'github'
>>> isinstance(src, GitHubSkillSource)
True
```

#### list_repo_skills(owner, repo)

List all skills in a GitHub repo using the Trees API.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]

#### search(query, , max_results=10)

Search GitHub for SKILL.md files matching query.

Uses the Code Search API: `filename:SKILL.md {query}`.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]


# _autosummary/skill.backends.html.md

# skill.backends

Backend protocols and local filesystem backend.

### Classes

| [`LocalDirSource`](_autosummary/skill.backends.html.md#skill.backends.LocalDirSource)(root)            | SkillSource backed by an arbitrary local directory of skills.   |
|----------------------------------------------------------------------------------|-----------------------------------------------------------------|
| [`SkillSource`](_autosummary/skill.backends.html.md#skill.backends.SkillSource)(\*args, \*\*kwargs) | Read-only source of skills (e.g., GitHub, local directory).     |

### *class* skill.backends.LocalDirSource(root)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

SkillSource backed by an arbitrary local directory of skills.

Useful for testing and for local skill packages (e.g. a git checkout).
The directory should contain `owner/name/SKILL.md` structure.

```pycon
>>> import tempfile
>>> from skill.base import Skill, SkillMeta
>>> d = Path(tempfile.mkdtemp())
>>> (d / 'alice' / 'greet').mkdir(parents=True)
>>> Skill(meta=SkillMeta(name='greet', description='Say hi'), body='Hi!').write_to(d / 'alice' / 'greet')
>>> src = LocalDirSource(d)
>>> src.name
'local'
>>> 'alice/greet' in src
True
>>> src['alice/greet'].meta.name
'greet'
```

#### search(query, , max_results=10)

Keyword search over skill names and descriptions.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]

```pycon
>>> import tempfile
>>> from skill.base import Skill, SkillMeta
>>> d = Path(tempfile.mkdtemp())
>>> (d / 'bob' / 'python-lint').mkdir(parents=True)
>>> Skill(meta=SkillMeta(name='python-lint', description='Lint Python code'), body='...').write_to(d / 'bob' / 'python-lint')
>>> src = LocalDirSource(d)
>>> results = src.search('python')
>>> len(results) > 0
True
>>> results[0].name
'python-lint'
```

### *class* skill.backends.SkillSource(\*args, \*\*kwargs)

Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol)

Read-only source of skills (e.g., GitHub, local directory).

`__iter__` and `__len__` are deliberately omitted — remote sources
may not support enumeration.

### Modules

| [`awesome_list`](_autosummary/skill.backends.awesome_list.html.md#module-skill.backends.awesome_list)       | Awesome-claude-skills curated list backend for skill discovery.   |
|--------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
| [`composio`](_autosummary/skill.backends.composio.html.md#module-skill.backends.composio)               | Composio backend for skill discovery and fetching.                |
| [`github`](_autosummary/skill.backends.github.html.md#module-skill.backends.github)                   | GitHub backend for skill discovery and fetching.                  |
| [`skillsdirectory`](_autosummary/skill.backends.skillsdirectory.html.md#module-skill.backends.skillsdirectory) | SkillsDirectory backend for skill discovery and fetching.         |
| [`smithery`](_autosummary/skill.backends.smithery.html.md#module-skill.backends.smithery)               | Smithery backend for skill discovery and fetching.                |


# _autosummary/skill.backends.skillsdirectory.html.md

# skill.backends.skillsdirectory

SkillsDirectory backend for skill discovery and fetching.

### Classes

| [`SkillsDirectorySource`](_autosummary/skill.backends.skillsdirectory.html.md#skill.backends.skillsdirectory.SkillsDirectorySource)(\*[, token, http_get])   | SkillSource backed by skillsdirectory.com.   |
|-------------------------------------------------------------------------------------------------|----------------------------------------------|

### *class* skill.backends.skillsdirectory.SkillsDirectorySource(, token=None, http_get=None)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

SkillSource backed by skillsdirectory.com.

Requires a `SKILLSDIRECTORY_API_KEY` environment variable or explicit *token*.
Free tier: 100 requests/day.

```pycon
>>> src = SkillsDirectorySource(token="my-key")
>>> src.name
'skillsdirectory'
```

#### search(query, , max_results=10)

Search SkillsDirectory for skills matching *query*.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]


# _autosummary/skill.backends.smithery.html.md

# skill.backends.smithery

Smithery backend for skill discovery and fetching.

### Classes

| [`SmitherySkillSource`](_autosummary/skill.backends.smithery.html.md#skill.backends.smithery.SmitherySkillSource)(\*[, token, http_get])   | SkillSource backed by the Smithery API.   |
|-----------------------------------------------------------------------------------------------|-------------------------------------------|

### *class* skill.backends.smithery.SmitherySkillSource(, token=None, http_get=None)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

SkillSource backed by the Smithery API.

Searches the `/skills` endpoint for agent skills.  No authentication
is required for read operations.

```pycon
>>> src = SmitherySkillSource()
>>> src.name
'smithery'
```

#### search(query, , max_results=10)

Search Smithery for skills matching *query*.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]


# _autosummary/skill.base.html.md

# skill.base

Core data model and SKILL.md parsing.

### Module Attributes

| [`KNOWN_FRONTMATTER_KEYS`](_autosummary/skill.base.html.md#skill.base.KNOWN_FRONTMATTER_KEYS)   | Top-level frontmatter keys `SkillMeta` models as named fields.   |
|---------------------------------------------------------------------------|------------------------------------------------------------------|

### Functions

| [`discover_resources`](_autosummary/skill.base.html.md#skill.base.discover_resources)(path)    | Scan a skill directory for bundled resource subdirectories.      |
|------------------------------------------------------------------------------|------------------------------------------------------------------|
| [`parse_frontmatter`](_autosummary/skill.base.html.md#skill.base.parse_frontmatter)(content)  | Parse YAML frontmatter delimited by `---` from markdown content. |
| [`parse_skill_md`](_autosummary/skill.base.html.md#skill.base.parse_skill_md)(content)     | Parse a SKILL.md string into (SkillMeta, body).                  |
| [`render_frontmatter`](_autosummary/skill.base.html.md#skill.base.render_frontmatter)(meta)    | Render a dict as YAML frontmatter block.                         |
| [`render_skill_md`](_autosummary/skill.base.html.md#skill.base.render_skill_md)(meta, body) | Render a SKILL.md string from meta and body.                     |

### Classes

| [`Skill`](_autosummary/skill.base.html.md#skill.base.Skill)(meta, body[, resources, source_path])      | A fully parsed skill: frontmatter + body + resource manifest.   |
|---------------------------------------------------------------------------------------------------|-----------------------------------------------------------------|
| [`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)(canonical_key, name, description, ...) | Lightweight metadata for search results (no body).              |
| [`SkillMeta`](_autosummary/skill.base.html.md#skill.base.SkillMeta)(name, description[, audience, ...])    | Parsed YAML frontmatter from a SKILL.md file.                   |

### skill.base.KNOWN_FRONTMATTER_KEYS *= frozenset({'allowed-tools', 'audience', 'compatibility', 'description', 'license', 'metadata', 'name'})*

Top-level frontmatter keys `SkillMeta` models as named fields. Anything else
is an unknown/namespaced key (e.g. another tool’s `coact:` block) and is kept
verbatim in [`SkillMeta.extra`](_autosummary/skill.base.html.md#skill.base.SkillMeta.extra) so it survives a parse→render round-trip.

### *class* skill.base.Skill(meta, body, resources=<factory>, source_path=None)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

A fully parsed skill: frontmatter + body + resource manifest.

```pycon
>>> s = Skill(meta=SkillMeta(name='test', description='A test'), body='# Hello')
>>> s.meta.name
'test'
```

#### *classmethod* from_path(path)

Load a Skill from a directory containing SKILL.md.

`path` should be the skill directory (containing SKILL.md).

* **Return type:**
  [`Skill`](_autosummary/skill.base.html.md#skill.base.Skill)

#### *classmethod* from_string(content)

Parse a Skill from a SKILL.md string (no resource discovery).

* **Return type:**
  [`Skill`](_autosummary/skill.base.html.md#skill.base.Skill)

```pycon
>>> s = Skill.from_string("---\nname: x\ndescription: y\n---\nbody")
>>> s.meta.name
'x'
```

#### to_string()

Render this skill as a SKILL.md string.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

#### write_to(path)

Write this skill to a directory, creating SKILL.md and resource dirs.

* **Return type:**
  [`None`](https://docs.python.org/3/library/constants.html#None)

### *class* skill.base.SkillInfo(canonical_key, name, description, source, url=None, owner=None, installed=False)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

Lightweight metadata for search results (no body).

```pycon
>>> si = SkillInfo(canonical_key='owner/test', name='test', description='A test', source='local')
>>> si.canonical_key
'owner/test'
```

### *class* skill.base.SkillMeta(name, description, audience=None, license=None, compatibility=None, metadata=<factory>, allowed_tools=<factory>, extra=<factory>)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

Parsed YAML frontmatter from a SKILL.md file.

```pycon
>>> m = SkillMeta(name='test', description='A test skill')
>>> m.name
'test'
```

Unknown/namespaced top-level keys are preserved in [`extra`](_autosummary/skill.base.html.md#skill.base.SkillMeta.extra) and re-emitted
on render, so a tool’s additive frontmatter block isn’t silently dropped:

```pycon
>>> m = SkillMeta(name='t', description='d', extra={'coact': {'model': 'sonnet'}})
>>> m.to_dict()['coact']
{'model': 'sonnet'}
```

#### extra *: [dict](https://docs.python.org/3/library/stdtypes.html#dict)[[str](https://docs.python.org/3/library/stdtypes.html#str), [Any](https://docs.python.org/3/library/typing.html#typing.Any)]*

Unknown/namespaced top-level frontmatter keys, kept verbatim for round-trip.

#### to_dict()

Convert to a dict suitable for YAML frontmatter, omitting None values.

Named fields render first (stable order); preserved [`extra`](_autosummary/skill.base.html.md#skill.base.SkillMeta.extra) keys
follow, so namespaced blocks survive `parse_skill_md` → `render_skill_md`.

* **Return type:**
  [`dict`](https://docs.python.org/3/library/stdtypes.html#dict)

### skill.base.discover_resources(path)

Scan a skill directory for bundled resource subdirectories.

* **Return type:**
  [`dict`](https://docs.python.org/3/library/stdtypes.html#dict)[[`str`](https://docs.python.org/3/library/stdtypes.html#str), [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`str`](https://docs.python.org/3/library/stdtypes.html#str)]]

```pycon
>>> import tempfile
>>> with tempfile.TemporaryDirectory() as d:
...     p = Path(d)
...     (p / 'scripts').mkdir()
...     (p / 'scripts' / 'run.py').touch()
...     r = discover_resources(p)
...     r['scripts']
['run.py']
```

### skill.base.parse_frontmatter(content)

Parse YAML frontmatter delimited by `---` from markdown content.

* **Return type:**
  [`tuple`](https://docs.python.org/3/library/stdtypes.html#tuple)[[`dict`](https://docs.python.org/3/library/stdtypes.html#dict), [`str`](https://docs.python.org/3/library/stdtypes.html#str)]

```pycon
>>> meta, body = parse_frontmatter("---\nname: test\ndescription: A test\n---\n# Hello")
>>> meta['name']
'test'
>>> body.strip()
'# Hello'
>>> parse_frontmatter("no frontmatter here")
({}, 'no frontmatter here')
```

### skill.base.parse_skill_md(content)

Parse a SKILL.md string into (SkillMeta, body).

* **Return type:**
  [`tuple`](https://docs.python.org/3/library/stdtypes.html#tuple)[[`SkillMeta`](_autosummary/skill.base.html.md#skill.base.SkillMeta), [`str`](https://docs.python.org/3/library/stdtypes.html#str)]

```pycon
>>> meta, body = parse_skill_md("---\nname: foo\ndescription: bar\n---\nHello")
>>> meta.name
'foo'
>>> body
'Hello'
```

### skill.base.render_frontmatter(meta)

Render a dict as YAML frontmatter block.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> print(render_frontmatter({'name': 'test', 'description': 'A test'}))
---
name: test
description: A test
---
```

### skill.base.render_skill_md(meta, body)

Render a SKILL.md string from meta and body.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> s = render_skill_md(SkillMeta(name='x', description='y'), 'Hello')
>>> 'name: x' in s and 'Hello' in s
True
```


# _autosummary/skill.cli_format.html.md

# skill.cli_format

Terminal-friendly formatting for CLI output.

### Functions

| [`format_path_dict`](_autosummary/skill.cli_format.html.md#skill.cli_format.format_path_dict)(d, \*[, verb])              | Format a {name: path} dict as readable output.            |
|-----------------------------------------------------------------------------------------------|-----------------------------------------------------------|
| [`format_skill`](_autosummary/skill.cli_format.html.md#skill.cli_format.format_skill)(skill, \*[, url, dep_warnings]) | Format a full Skill for terminal display.                 |
| [`format_skill_info`](_autosummary/skill.cli_format.html.md#skill.cli_format.format_skill_info)(info)                      | Format a single SkillInfo as a compact one-liner.         |
| [`format_skill_info_table`](_autosummary/skill.cli_format.html.md#skill.cli_format.format_skill_info_table)(items)               | Format a list of SkillInfo as an aligned, readable table. |
| [`format_sources`](_autosummary/skill.cli_format.html.md#skill.cli_format.format_sources)(sources)                      | Format a list of source dicts for terminal display.       |

### skill.cli_format.format_path_dict(d, , verb='Installed')

Format a {name: path} dict as readable output.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> from pathlib import Path
>>> out = format_path_dict({'claude-code': Path('/a/b')}, verb='Installed')
>>> 'claude-code' in out
True
```

### skill.cli_format.format_skill(skill, , url=None, dep_warnings=None)

Format a full Skill for terminal display.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> from skill.base import SkillMeta
>>> s = Skill(meta=SkillMeta(name='test', description='A test'), body='# Hello')
>>> 'Name:' in format_skill(s)
True
>>> 'WARNING' in format_skill(s, dep_warnings=['Missing dependencies: alice/foo'])
True
```

### skill.cli_format.format_skill_info(info)

Format a single SkillInfo as a compact one-liner.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> si = SkillInfo('owner/test', 'test', 'A test skill', 'local', installed=True)
>>> '✓' in format_skill_info(si)
True
```

### skill.cli_format.format_skill_info_table(items)

Format a list of SkillInfo as an aligned, readable table.

Shows URL on a second line when available.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> items = [
...     SkillInfo('alice/lint', 'lint', 'Lint Python code', 'local', installed=True),
...     SkillInfo('bob/react-tips', 'react-tips', 'React best practices guide', 'github',
...               url='https://github.com/bob/react-tips'),
... ]
>>> out = format_skill_info_table(items)
>>> '✓' in out and 'alice/lint' in out
True
>>> 'https://github.com/bob/react-tips' in out
True
```

### skill.cli_format.format_sources(sources)

Format a list of source dicts for terminal display.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> out = format_sources([{'name': 'github', 'homepage': 'https://github.com', 'enabled': True}])
>>> 'github' in out and 'https://github.com' in out
True
```


# _autosummary/skill.completion.html.md

# skill.completion

Shell completion setup and diagnostics.

### Functions

| [`install_completion`](_autosummary/skill.completion.html.md#skill.completion.install_completion)()       | Register shell completion for `skill` in the user's shell config.   |
|-----------------------------------------------------------------------------|---------------------------------------------------------------------|
| [`is_completion_registered`](_autosummary/skill.completion.html.md#skill.completion.is_completion_registered)() | Check whether shell completion for `skill` appears to be set up.    |
| [`maybe_hint_completion`](_autosummary/skill.completion.html.md#skill.completion.maybe_hint_completion)()    | Print a one-time hint about shell completion if it isn't set up.    |

### skill.completion.install_completion()

Register shell completion for `skill` in the user’s shell config.

Returns a status message describing what was done.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

### skill.completion.is_completion_registered()

Check whether shell completion for `skill` appears to be set up.

Looks for the `register-python-argcomplete skill` line in the
user’s shell config, or checks if argcomplete global activation is present.

* **Return type:**
  [`bool`](https://docs.python.org/3/library/functions.html#bool)

### skill.completion.maybe_hint_completion()

Print a one-time hint about shell completion if it isn’t set up.

Called on first CLI invocation. Writes a marker file so the hint
is only shown once.

* **Return type:**
  [`None`](https://docs.python.org/3/library/constants.html#None)


# _autosummary/skill.config.html.md

# skill.config

Configuration management via platformdirs and TOML.

### Functions

| [`cache_dir`](_autosummary/skill.config.html.md#skill.config.cache_dir)()                     | Return the platform-specific cache directory for skill.             |
|----------------------------------------------------------------------------------|---------------------------------------------------------------------|
| [`config_dir`](_autosummary/skill.config.html.md#skill.config.config_dir)()                    | Return the platform-specific config directory for skill.            |
| [`config_path`](_autosummary/skill.config.html.md#skill.config.config_path)()                   | Return the path to the config TOML file.                            |
| [`data_dir`](_autosummary/skill.config.html.md#skill.config.data_dir)()                      | Return the platform-specific data directory for skill.              |
| [`load_config`](_autosummary/skill.config.html.md#skill.config.load_config)([path])             | Load config from TOML, falling back to defaults for missing fields. |
| [`save_config`](_autosummary/skill.config.html.md#skill.config.save_config)(config, \*[, path]) | Save config to TOML.                                                |
| [`skills_dir`](_autosummary/skill.config.html.md#skill.config.skills_dir)()                    | Return the canonical skills storage directory.                      |

### Classes

| [`SkillConfig`](_autosummary/skill.config.html.md#skill.config.SkillConfig)([default_agent_targets, ...])   | Root configuration schema with sensible defaults for zero-config first run.   |
|----------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|

### *class* skill.config.SkillConfig(default_agent_targets=<factory>, default_scope='project', install_method='symlink', ai_provider_model='anthropic:claude-sonnet-4-20250514', ai_api_key='$ANTHROPIC_API_KEY', github_enabled=True, smithery_enabled=True, composio_enabled=True, awesome_list_enabled=True, skillsdirectory_enabled=True, search_cache_ttl=3600)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

Root configuration schema with sensible defaults for zero-config first run.

```pycon
>>> c = SkillConfig()
>>> c.default_agent_targets
['claude-code']
>>> c.install_method
'symlink'
```

### skill.config.cache_dir()

Return the platform-specific cache directory for skill.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

```pycon
>>> isinstance(cache_dir(), Path)
True
```

### skill.config.config_dir()

Return the platform-specific config directory for skill.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

```pycon
>>> isinstance(config_dir(), Path)
True
```

### skill.config.config_path()

Return the path to the config TOML file.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

```pycon
>>> config_path().name
'config.toml'
```

### skill.config.data_dir()

Return the platform-specific data directory for skill.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

```pycon
>>> isinstance(data_dir(), Path)
True
```

### skill.config.load_config(path=None)

Load config from TOML, falling back to defaults for missing fields.

* **Return type:**
  [`SkillConfig`](_autosummary/skill.config.html.md#skill.config.SkillConfig)

```pycon
>>> c = load_config(Path('/nonexistent/config.toml'))
>>> c.default_scope
'project'
```

### skill.config.save_config(config, , path=None)

Save config to TOML.

* **Return type:**
  [`None`](https://docs.python.org/3/library/constants.html#None)

```pycon
>>> import tempfile
>>> with tempfile.TemporaryDirectory() as d:
...     p = Path(d) / 'config.toml'
...     save_config(SkillConfig(), path=p)
...     p.exists()
True
```

### skill.config.skills_dir()

Return the canonical skills storage directory.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)

```pycon
>>> skills_dir().name
'skills'
```


# _autosummary/skill.create.html.md

# skill.create

### skill.create(name, , description='', body='', owner='_local', store=None)

Create a new skill and store it locally.

* **Return type:**
  [`Skill`](_autosummary/skill.base.html.md#skill.base.Skill)

```pycon
>>> import tempfile
>>> from pathlib import Path
>>> store = LocalSkillStore(root=Path(tempfile.mkdtemp()))
>>> s = create('my-skill', description='Does things', store=store)
>>> s.meta.name
'my-skill'
>>> '_local/my-skill' in store
True
```


# _autosummary/skill.html.md

# skill

AI Agent Skill Search and Management.

Simple usage:

```default
from skill import search, install, create, list_skills, validate

# Search for skills
results = search('react best practices', local_only=True)

# Create a new skill locally
skill = create('my-skill', description='My custom skill')

# Validate a skill
issues = validate('/path/to/skill-dir')
```

Plugin registries:

```default
from skill.install import agent_targets
from skill.translate import translators
from skill.search import backends
from skill.create import validators
```

### Functions

| [`list_skills`](_autosummary/skill.html.md#skill.list_skills)(\*[, agent_target, scope])   | List locally installed skills, optionally filtered by agent target.    |
|-------------------------------------------------------------------------------------------|------------------------------------------------------------------------|
| [`show`](_autosummary/skill.html.md#skill.show)(key)                                | Read and return a skill by its canonical key.                          |
| [`sources`](_autosummary/skill.html.md#skill.sources)()                                | List registered search backends with their name, homepage, and status. |

### skill.list_skills(, agent_target=None, scope='all')

List locally installed skills, optionally filtered by agent target.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]

```pycon
>>> isinstance(list_skills(), list)
True
```

### skill.show(key)

Read and return a skill by its canonical key.

Raises KeyError if the skill is not found locally.

* **Return type:**
  [`Skill`](_autosummary/skill.base.html.md#skill.base.Skill)

### skill.sources()

List registered search backends with their name, homepage, and status.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`dict`](https://docs.python.org/3/library/stdtypes.html#dict)]

```pycon
>>> isinstance(sources(), list)
True
```

### Modules

| [`ai`](_autosummary/skill.ai.html.md#module-skill.ai)                                             | Optional AI facade for semantic search and LLM-powered features.   |
|-----------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|
| [`backends`](_autosummary/skill.backends.html.md#module-skill.backends)                                 | Backend protocols and local filesystem backend.                    |
| [`base`](_autosummary/skill.base.html.md#module-skill.base)                                         | Core data model and SKILL.md parsing.                              |
| [`cli_format`](_autosummary/skill.cli_format.html.md#module-skill.cli_format)                             | Terminal-friendly formatting for CLI output.                       |
| [`completion`](_autosummary/skill.completion.html.md#module-skill.completion)                             | Shell completion setup and diagnostics.                            |
| [`config`](_autosummary/skill.config.html.md#module-skill.config)                                     | Configuration management via platformdirs and TOML.                |
| [`create`](_autosummary/skill.create.html.md#skill.create)(name, \*[, description, body, owner, ...]) | Create a new skill and store it locally.                           |
| [`install`](_autosummary/skill.install.html.md#skill.install)(key, \*[, agent_targets, scope, ...])    | Install a skill into one or more agent target directories.         |
| [`registry`](_autosummary/skill.registry.html.md#module-skill.registry)                                 | Generic plugin registry with entry point discovery.                |
| [`search`](_autosummary/skill.search.html.md#skill.search)(query, \*[, max_results, local_only, ...]) | Search for skills across local index and remote backends.          |
| [`stores`](_autosummary/skill.stores.html.md#module-skill.stores)                                     | Storage layer: LocalSkillStore and SourcedSkillStore via dol.      |
| [`translate`](_autosummary/skill.translate.html.md#module-skill.translate)                               | Format translators: SKILL.md <-> agent-specific formats.           |
| [`util`](_autosummary/skill.util.html.md#module-skill.util)                                         | Pure helpers with zero internal imports.                           |


# _autosummary/skill.install.html.md

# skill.install

### skill.install(key, , agent_targets=None, scope='project', copy=False, force=False, project_dir=None, store=None)

Install a skill into one or more agent target directories.

Returns a dict mapping agent target names to the paths where the skill
was installed.

* **Parameters:**
  * **key** ([`str`](https://docs.python.org/3/library/stdtypes.html#str)) – Canonical skill key (e.g., `'owner/skill-name'`).
  * **agent_targets** ([`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`str`](https://docs.python.org/3/library/stdtypes.html#str)] | [`None`](https://docs.python.org/3/library/constants.html#None)) – Agent targets to install into. Defaults to config’s `default_agent_targets`.
  * **scope** ([`str`](https://docs.python.org/3/library/stdtypes.html#str)) – `'project'` (default) or `'global'`.
  * **copy** ([`bool`](https://docs.python.org/3/library/functions.html#bool)) – If True, copy instead of symlink.
  * **force** ([`bool`](https://docs.python.org/3/library/functions.html#bool)) – If True, overwrite existing files/links.
  * **project_dir** ([`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path) | [`str`](https://docs.python.org/3/library/stdtypes.html#str) | [`None`](https://docs.python.org/3/library/constants.html#None)) – Project root. Auto-detected if None.
  * **store** ([`LocalSkillStore`](_autosummary/skill.stores.html.md#skill.stores.LocalSkillStore) | [`None`](https://docs.python.org/3/library/constants.html#None)) – Skill store to read from. Uses default if None.
* **Return type:**
  [`dict`](https://docs.python.org/3/library/stdtypes.html#dict)[[`str`](https://docs.python.org/3/library/stdtypes.html#str), [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path)]


# _autosummary/skill.registry.html.md

# skill.registry

Generic plugin registry with entry point discovery.

### Classes

| [`Registry`](_autosummary/skill.registry.html.md#skill.registry.Registry)(name, \*[, entry_point_group])   | A name-keyed registry of typed objects with lazy entry point discovery.   |
|--------------------------------------------------------------------------------------------|---------------------------------------------------------------------------|

### *class* skill.registry.Registry(name, , entry_point_group=None)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping), [`Generic`](https://docs.python.org/3/library/typing.html#typing.Generic)[`T`]

A name-keyed registry of typed objects with lazy entry point discovery.

Each `Registry` wraps a dict and can auto-discover plugins registered
via `importlib.metadata` entry points under the group
`skill.<registry_name>`.

```pycon
>>> r = Registry('demo')
>>> r['foo'] = 42
>>> r['foo']
42
>>> list(r)
['foo']
>>> len(r)
1
>>> del r['foo']
>>> len(r)
0
```

#### *property* name *: [str](https://docs.python.org/3/library/stdtypes.html#str)*

Registry name (also used to derive the entry point group).

```pycon
>>> Registry('agents').name
'agents'
```

#### register(name, item)

Register an item and return it (usable as a decorator factory).

* **Return type:**
  [`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`T`)

```pycon
>>> r = Registry('demo')
>>> r.register('x', lambda: 1)
<function ...>
>>> 'x' in r
True
```


# _autosummary/skill.search.html.md

# skill.search

### skill.search(query, , max_results=10, local_only=False, backends=None)

Search for skills across local index and remote backends.

With `local_only=True`, only searches locally installed skills.
Otherwise, searches both local and remote, with local results first.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]

```pycon
>>> isinstance(search('test', local_only=True, max_results=0), list)
True
```


# _autosummary/skill.stores.html.md

# skill.stores

Storage layer: LocalSkillStore and SourcedSkillStore via dol.

### Classes

| [`LocalSkillStore`](_autosummary/skill.stores.html.md#skill.stores.LocalSkillStore)([root])   | Filesystem-backed MutableMapping[str, Skill] over the canonical skills directory.   |
|----------------------------------------------------------------------------|-------------------------------------------------------------------------------------|

### *class* skill.stores.LocalSkillStore(root=None)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)

Filesystem-backed MutableMapping[str, Skill] over the canonical skills directory.

Keys are canonical `owner/name` strings. Each skill is stored as a
directory containing `SKILL.md` and optional resource subdirectories.

```pycon
>>> import tempfile
>>> store = LocalSkillStore(root=Path(tempfile.mkdtemp()))
>>> len(store)
0
>>> list(store)
[]
```

#### get_source_meta(key)

Read source metadata for a skill, or empty dict if none.

* **Return type:**
  [`dict`](https://docs.python.org/3/library/stdtypes.html#dict)

#### list_info()

Return SkillInfo for all locally stored skills.

* **Return type:**
  [`list`](https://docs.python.org/3/library/stdtypes.html#list)[[`SkillInfo`](_autosummary/skill.base.html.md#skill.base.SkillInfo)]

#### set_source_meta(key, , url=None, source=None)

Store source metadata (URL, origin) alongside a skill.

* **Return type:**
  [`None`](https://docs.python.org/3/library/constants.html#None)


# _autosummary/skill.translate.html.md

# skill.translate

Format translators: SKILL.md <-> agent-specific formats.

### Module Attributes

| [`translators`](_autosummary/skill.translate.html.md#skill.translate.translators)   | Registry of format translators (Skill -> target format string).   |
|----------------------------------------------------------------|-------------------------------------------------------------------|

### Functions

| [`from_mdc`](_autosummary/skill.translate.html.md#skill.translate.from_mdc)(content)                   | Import a Cursor `.mdc` file as a Skill.                  |
|--------------------------------------------------------------------------------------|----------------------------------------------------------|
| [`to_copilot_instructions`](_autosummary/skill.translate.html.md#skill.translate.to_copilot_instructions)(skill)      | Translate a Skill to GitHub Copilot instructions format. |
| [`to_mdc`](_autosummary/skill.translate.html.md#skill.translate.to_mdc)(skill)                       | Translate a Skill to Cursor `.mdc` format.               |
| [`translate`](_autosummary/skill.translate.html.md#skill.translate.translate)(skill, \*, target_format) | Translate a Skill to the specified target format.        |

### skill.translate.from_mdc(content)

Import a Cursor `.mdc` file as a Skill.

* **Return type:**
  [`Skill`](_autosummary/skill.base.html.md#skill.base.Skill)

```pycon
>>> content = "---\ndescription: Do things\nglobs: '*.py'\nalwaysApply: false\n---\n# Rules"
>>> s = from_mdc(content)
>>> s.meta.description
'Do things'
>>> s.meta.metadata.get('cursor.globs')
'*.py'
```

### skill.translate.to_copilot_instructions(skill)

Translate a Skill to GitHub Copilot instructions format.

Produces a Markdown section suitable for appending to
`.github/copilot-instructions.md`. Lossy: no frontmatter support
beyond `applyTo`, no progressive disclosure, no resources.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> from skill.base import SkillMeta
>>> s = Skill(meta=SkillMeta(name='lint', description='Lint rules'), body='Use ruff.')
>>> md = to_copilot_instructions(s)
>>> '## lint' in md
True
>>> 'Use ruff.' in md
True
```

### skill.translate.to_mdc(skill)

Translate a Skill to Cursor `.mdc` format.

Lossy: `allowed-tools`, `license`, bundled resources, and progressive
disclosure semantics are lost.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> from skill.base import SkillMeta
>>> s = Skill(meta=SkillMeta(name='test', description='Test skill'), body='Do stuff.')
>>> mdc = to_mdc(s)
>>> 'description: Test skill' in mdc
True
>>> 'Do stuff.' in mdc
True
```

### skill.translate.translate(skill, , target_format)

Translate a Skill to the specified target format.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> from skill.base import SkillMeta
>>> s = Skill(meta=SkillMeta(name='x', description='y'), body='z')
>>> 'alwaysApply' in translate(s, target_format='mdc')
True
```

### skill.translate.translators *: [Registry](_autosummary/skill.registry.html.md#skill.registry.Registry)[[Callable](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[Skill](_autosummary/skill.base.html.md#skill.base.Skill)], [str](https://docs.python.org/3/library/stdtypes.html#str)]]* *= Registry('translators', keys=['mdc', 'copilot_md'])*

Registry of format translators (Skill -> target format string).


# _autosummary/skill.util.html.md

# skill.util

Pure helpers with zero internal imports.

### Functions

| [`atomic_write`](_autosummary/skill.util.html.md#skill.util.atomic_write)(path, content)   | Write `content` to `path` atomically via temp-then-rename.         |
|--------------------------------------------------------------------------------|--------------------------------------------------------------------|
| [`find_project_root`](_autosummary/skill.util.html.md#skill.util.find_project_root)([start])    | Walk up from `start` looking for a project root marker.            |
| [`resolve_env_vars`](_autosummary/skill.util.html.md#skill.util.resolve_env_vars)(value)       | Resolve `$VAR` and `${VAR}` references from environment variables. |

### Classes

| [`ParsedKey`](_autosummary/skill.util.html.md#skill.util.ParsedKey)(owner, name)   | A normalized skill key.   |
|---------------------------------------------------------------------------|---------------------------|

### *class* skill.util.ParsedKey(owner, name)

Bases: [`object`](https://docs.python.org/3/library/functions.html#object)

A normalized skill key.

```pycon
>>> ParsedKey.from_string('owner/skill-name')
ParsedKey(owner='owner', name='skill-name')
>>> ParsedKey.from_string('Owner/Skill-Name')
ParsedKey(owner='owner', name='skill-name')
>>> ParsedKey.from_string('my-skill')
ParsedKey(owner='_local', name='my-skill')
>>> ParsedKey.from_string('owner/repo/skill-name')
ParsedKey(owner='owner', name='skill-name')
>>> str(ParsedKey(owner='owner', name='skill-name'))
'owner/skill-name'
```

#### *classmethod* from_string(raw)

Parse a raw key string into a normalized ParsedKey.

Supports 1-part (name only), 2-part (owner/name), and 3-part
(owner/repo/name) keys. All parts are lowercased.

* **Return type:**
  [`ParsedKey`](_autosummary/skill.util.html.md#skill.util.ParsedKey)

### skill.util.atomic_write(path, content)

Write `content` to `path` atomically via temp-then-rename.

* **Return type:**
  [`None`](https://docs.python.org/3/library/constants.html#None)

```pycon
>>> import tempfile
>>> with tempfile.TemporaryDirectory() as d:
...     p = Path(d) / 'test.txt'
...     atomic_write(p, 'hello')
...     p.read_text()
'hello'
```

### skill.util.find_project_root(start=None)

Walk up from `start` looking for a project root marker.

* **Return type:**
  [`Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path) | [`None`](https://docs.python.org/3/library/constants.html#None)

```pycon
>>> import tempfile
>>> d = Path(tempfile.mkdtemp()).resolve()
>>> p = d / 'sub' / 'deep'
>>> p.mkdir(parents=True)
>>> (d / '.git').mkdir()
>>> find_project_root(p) == d
True
>>> find_project_root(Path('/nonexistent/path/that/does/not/exist')) is None
True
```

### skill.util.resolve_env_vars(value)

Resolve `$VAR` and `${VAR}` references from environment variables.

* **Return type:**
  [`str`](https://docs.python.org/3/library/stdtypes.html#str)

```pycon
>>> import os; os.environ['_SKILL_TEST'] = 'hello'
>>> resolve_env_vars('key=$_SKILL_TEST')
'key=hello'
>>> resolve_env_vars('${_SKILL_TEST}/world')
'hello/world'
>>> resolve_env_vars('no vars here')
'no vars here'
```


# ai-agents.html.md

<!-- generated by epythet -->

# For AI agents

`skill` ships artifacts for coding agents alongside its code. This page lists
them, says where each lives in the repository, and points at the
machine-readable copies of this documentation.

## Skills

Skills are folders holding a `SKILL.md` (the [Agent Skills](https://agentskills.io) format): a description that tells an agent when to use it and a body with the procedure. Install one into your agent with `gh skill` (any host: `--agent claude-code`, `copilot`, `cursor`, `codex`, `gemini`), or use the copy bundled in the wheel.

### `skill-build`

Skill-building tooling for the skill package. Build AI agent skills for any Python package by analyzing its code, tests, and docs. Use this skill when the user wants to create skills for a package, analyze a codebase to suggest what skills would be useful, generate SKILL.md files from existing code/tests/docs, or when someone says things like “make skills for this package”, “what skills should this project have”, “create a skill from this module”, or “generate skills”. Also trigger when the user points at a package and asks for AI-powered interfaces to it.

```bash
gh skill install thorwhalen/skill skill-build --agent claude-code
```

Source: [`skills/skill-build`](https://github.com/thorwhalen/skill/tree/HEAD/skills/skill-build).

### `skill-docs`

Skill documentation tooling for the skill package. Document a project’s AI agent skills in the README and other formats. Use this skill when the user wants to add skills documentation to a README, explain what skills a project offers, write a “Skills” section, generate skill installation instructions, or when asked things like “document the skills”, “add skills to the README”, “how should I present skills to users”, or “write skill usage examples”. Also trigger when updating a README for a package that has skills in .claude/skills/ or {pkg}/data/skills/.

```bash
gh skill install thorwhalen/skill skill-docs --agent claude-code
```

Source: [`skills/skill-docs`](https://github.com/thorwhalen/skill/tree/HEAD/skills/skill-docs).

### `skill-enable`

Ship a Python package’s AI agent skills with `pip install` — and decide WHICH skills to ship. Use when the user asks how to include skills in their package distribution, make skills available after `pip install`, ship SKILL.md files with their package, set up `{pkg}/data/skills/`, configure package-data, add a skills installer/convenience function, or says “how do users get my skills after pip install”, “ship skills with my package”, “distribute skills”, “package skills”, or “enable skills in my library”. Also trigger when working on pyproject.toml and the project has skills to distribute. The overall layout decision (where real files live, the `.claude/skills/` symlink bridge, spec compliance) is owned by **skill-package-setup**; this skill covers the pip-distribution mechanics and audience classification.

```bash
gh skill install thorwhalen/skill skill-enable --agent claude-code
```

Source: [`skills/skill-enable`](https://github.com/thorwhalen/skill/tree/HEAD/skills/skill-enable).

### `skill-manage`

Skill management tooling for the skill package. Search, list, inspect, and manage AI agent skills across agents and projects. Use this skill when the user wants to find skills, see what skills are installed, check where skills are linked, inspect a skill’s contents, install or uninstall skills, compare skills across agents (Claude Code, Cursor, Copilot), or says things like “what skills do I have”, “find a skill for X”, “show me the skill”, “where are my skills”, “install this skill”, “remove that skill”, “list skills”, or “search skills”. Trigger on any skill inventory, discovery, or housekeeping request.

```bash
gh skill install thorwhalen/skill skill-manage --agent claude-code
```

Source: [`skills/skill-manage`](https://github.com/thorwhalen/skill/tree/HEAD/skills/skill-manage).

### `skill-package-setup`

Canonical, agent-agnostic policy for WHERE a package’s AI agent skills live and HOW they are distributed so they’re discoverable by `gh skill` (and any agent host — Copilot, Cursor, Codex, Gemini, Claude) AND, where wanted, shipped with `pip install`. Use this skill to set up skills for a new package, migrate an existing repo to the canonical layout, consolidate skills scattered across `.claude/skills/` / `skills/` / `{pkg}/data/skills/`, make every SKILL.md spec-clean, or answer “where should my package’s skills live”. Also the authority other skills defer to (e.g. wads-skillify). Triggers on “set up skills”, “where should skills live”, “make skills gh-skill installable”, “migrate/restructure the skills layout”, “skillify this repo”. Maintainer skill.

```bash
gh skill install thorwhalen/skill skill-package-setup --agent claude-code
```

Source: [`skills/skill-package-setup`](https://github.com/thorwhalen/skill/tree/HEAD/skills/skill-package-setup).

### `skill-sync`

Skill maintenance tooling for the skill package. Keep AI agent skills in sync with their source package code. Use this skill when a package’s code, API, or behavior has changed and its skills may be outdated, when the user says “update the skills”, “skills are stale”, “sync skills with code”, “refresh skills”, or when you notice that skill instructions reference functions/classes/patterns that no longer exist in the codebase. Also use after major refactors, API changes, or version bumps.

```bash
gh skill install thorwhalen/skill skill-sync --agent claude-code
```

Source: [`skills/skill-sync`](https://github.com/thorwhalen/skill/tree/HEAD/skills/skill-sync).

## Machine-readable documentation

This site publishes the same documentation in forms that fit an agent’s context window:

- [`llms.txt`](https://thorwhalen.github.io/skill/llms.txt): an index of every page with a one-line description ([llms.txt](https://llmstxt.org) format)
- [`skill.md`](https://thorwhalen.github.io/skill/skill.md): the whole documentation as one Markdown file
- `<page>.html.md`: a rendered Markdown twin of every page, advertised from each page’s `<head>` with `<link rel="alternate" type="text/markdown">`
- [`objects.inv`](https://thorwhalen.github.io/skill/objects.inv): the Sphinx inventory: a symbol-to-URL index (`sphobjinv convert plain objects.inv -`)


# api.html.md

# API reference

| [`skill`](_autosummary/skill.html.md#module-skill)   | AI Agent Skill Search and Management.   |
|-----------------------------------------------------------------------|-----------------------------------------|


