nshskill
Ship Claude Code skills from Python packages with zero boilerplate.
Why
Claude Code skills are markdown files that live in .claude/skills/ and teach Claude how to use your library. If you maintain a Python package, you probably want users to install your skill with a single command — but wiring up the file copying, frontmatter parsing, and CLI yourself is tedious and repetitive. nshskill handles all of that so you can focus on writing the skill content.
Install
pip install nshskill
# or
uv add nshskill
Requires Python 3.10+.
Quick start
Option A: Let Claude do it
Install the init-skill skill, then invoke it in Claude Code:
nshskill skill install # install to current project
nshskill skill install --global # install at user level
Then in Claude Code, run /init-skill and Claude will analyze your codebase and set up the full nshskill integration — _skill/ directory, SKILL.md, CLI wiring, and dependency.
Option B: Manual setup
1. Create a skill directory
Add a _skill/ directory inside your package with a SKILL.md file:
src/myproject/
├── __init__.py
├── ...
└── _skill/
├── SKILL.md
└── references/ # optional extra files
└── api-cheatsheet.md
2. Write SKILL.md with frontmatter
The file must start with YAML frontmatter containing at least a name field:
---
name: using-myproject
description: Short description of when Claude should use this skill.
---
# myproject
Instructions for Claude on how to use your library go here.
3. Add a CLI entry point
The simplest approach — a standalone CLI with just the skill command:
# src/myproject/cli.py
from pathlib import Path
from nshskill import Skill, create_skill_cli
skill = Skill.from_dir(Path(__file__).resolve().parent / "_skill")
main = create_skill_cli("myproject", skill)
# pyproject.toml
[project.scripts]
myproject = "myproject.cli:main"
Users can then run:
myproject skill install # install to .claude/skills/using-myproject/
myproject skill install --global # install to ~/.claude/skills/using-myproject/
myproject skill uninstall # remove it
API
Skill
from nshskill import Skill
A dataclass with two fields:
| Field | Type | Description |
|---|---|---|
name |
str |
Skill name (used as the directory name under .claude/skills/) |
skill_dir |
Path |
Path to the source directory containing SKILL.md |
Skill.from_dir(skill_dir: Path) -> Skill
Parse a Skill from a directory. Reads the name from the YAML frontmatter in SKILL.md. Raises FileNotFoundError if the directory or SKILL.md is missing, and ValueError if the frontmatter is missing or lacks a name field.
skill = Skill.from_dir(Path(__file__).resolve().parent / "_skill")
skill.install(target=None, *, global_=False) -> Path
Copy the skill directory contents into <target>/.claude/skills/<name>/. Returns the destination path.
- If
global_=True, installs to~/.claude/skills/<name>/(ignorestarget). - If
targetisNone, defaults to the current working directory. - Overwrites any existing installation at the destination.
- Skips
__init__.pyand__pycache__when copying.
skill.uninstall(target=None, *, global_=False) -> bool
Remove an installed skill directory. Returns True if something was removed, False if the skill wasn't installed at that location.
add_skill_commands
from nshskill import add_skill_commands
def add_skill_commands(subparsers, skill: Skill) -> None
Add skill install and skill uninstall subcommands to an existing argparse subparsers action. Use this when your package already has a CLI and you want to add skill management alongside other commands:
import argparse
from pathlib import Path
from nshskill import Skill, add_skill_commands, dispatch_skill
def main():
parser = argparse.ArgumentParser(prog="myproject")
subs = parser.add_subparsers(dest="command")
# Your other commands...
subs.add_parser("run", help="Run the thing")
# Add skill install/uninstall
skill = Skill.from_dir(Path(__file__).resolve().parent / "_skill")
add_skill_commands(subs, skill)
args = parser.parse_args()
if args.command == "skill":
dispatch_skill(args)
elif args.command == "run":
...
dispatch_skill
from nshskill.cli import dispatch_skill
def dispatch_skill(args: argparse.Namespace) -> None
Route a parsed skill subcommand to the appropriate install/uninstall method. Call this after parse_args() when args.command == "skill".
create_skill_cli
from nshskill import create_skill_cli
def create_skill_cli(prog: str, skill: Skill) -> Callable[[], None]
Return a ready-to-use main() function for packages that only need skill commands in their CLI. The returned function parses sys.argv and dispatches automatically:
# src/myproject/cli.py
from pathlib import Path
from nshskill import Skill, create_skill_cli
main = create_skill_cli("myproject", Skill.from_dir(Path(__file__).resolve().parent / "_skill"))
Skill directory layout
A skill directory can contain any files you want to ship to users. The only requirement is a SKILL.md at the root:
_skill/
├── SKILL.md # required — frontmatter + skill instructions
└── references/ # optional — supplementary docs
├── api.md
└── examples.md
To include existing docs from your repo without duplicating them, use symlinks:
ln -s ../../docs/api.md src/myproject/_skill/references/api.md
When installed, the entire directory tree is copied to .claude/skills/<name>/, preserving structure. __init__.py and __pycache__ are excluded automatically.
SKILL.md format
---
name: using-myproject
description: When to activate this skill.
---
Your skill content in markdown. This is what Claude reads
to learn how to use your library.
The frontmatter must contain:
name(required): Used as the subdirectory name under.claude/skills/.description(optional): Helps Claude decide when the skill is relevant.
License
MIT
Metadata
Release files for nshskill 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nshskill-0.1.0.tar.gz | 5.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nshskill-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.0 kB
Release files / nshskill-0.1.0.tar.gz
| Download URL | nshskill-0.1.0.tar.gz |
|---|---|
| Size | 5.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
636d308f34fc5a92d44a6d7e4c2aa292398bc7c5ab6fcfc6ed6f1e1a08401690
|
|
BLAKE2b-256 checksum How to use checksums |
fbe4faa55b7ded98356ce40843f49250a3c4fe7f315002afdea67303329f2012
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / nshskill-0.1.0-py3-none-any.whl
| Download URL | nshskill-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8612478edb6520f0c88bcf0a5fe44a5b3fb4d75abc132d15acb5b1e50fcf4716
|
|
BLAKE2b-256 checksum How to use checksums |
dc2259e0a209de3adcb740db24e13b5bf703af3a681b62bf1c5d4db2320f0195
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|