How to Create and Use Executable Skills as Python Packages in Prime Agent
Prime Agent treats an executable skill as a Python directory containing SKILL.md, pyproject.toml, and a src/ package with an async run() function, then installs it editable into the persistent IPython kernel where it becomes directly awaitable.
Prime Agent provides a powerful skill system that lets you extend agent capabilities with reusable Python code. This guide explains how to create and use executable skills as Python packages—full Python modules that install into the agent's kernel and expose both programmatic and shell interfaces.
What Makes a Skill Executable
A skill becomes a Python-backed skill only when four requirements are met. According to the Prime Agent source code, missing any requirement degrades the skill to markdown-only mode with a load warning.
The detection contract in [packages/coding-agent/src/core/skills.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/core/skills.ts) requires:
| Requirement | Purpose |
|---|---|
SKILL.md with YAML front-matter |
Describes capability to the LLM |
pyproject.toml at skill root |
Drives editable installation |
Valid Python import name (- → _) |
Determines module exposure in kernel |
src/<import_name>/__init__.py |
Provides callable implementation |
Minimal Skill Directory Structure
Every executable skill follows this layout:
my-skill/
├── SKILL.md
├── pyproject.toml
└── src/
└── my_skill/
└── __init__.py
The directory name my-skill becomes the import name my_skill after hyphen-to-underscore conversion. This naming convention is enforced in the skill discovery logic.
SKILL.md: Defining the Contract
The SKILL.md file serves as the user-visible contract. Only name and description from the YAML front-matter are shown to the LLM; implementation details load on demand.
Example from [python-skills.md](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/skills/skill-creator/references/python-skills.md):
---
name: word-count
description: Count word frequencies in text and return the most common words.
---
# Word Count
Call directly from the kernel:
await word_count("some text to analyze", top=3)
Or from a shell cell:
!word_count "some text to analyze" --top 3
pyproject.toml: Package Configuration
The pyproject.toml drives the editable install and optional CLI registration:
[project]
name = "word-count"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = []
[project.scripts]
word_count = "rlm.skill:cli"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/word_count"]
Key points:
[project.scripts]creates the shell commandword_countviarlm.skill:cli- Hatchling is required when the distribution name differs from the package directory (common with hyphenated names)
- The wheel target explicitly maps
src/word_countto resolve path mismatches
Implementation: The run() Function
The core implementation lives in src/<import_name>/__init__.py. From the reference example:
from collections import Counter
async def run(text: str, top: int = 5) -> str:
"""Count words in text and return the most common ones."""
counts = Counter(text.lower().split())
return "\n".join(f"{word}: {count}" for word, count in counts.most_common(top))
Critical implementation rules from the source:
runcan be async or sync—the kernel always awaits it- The function's docstring and signature are copied to the module object for
help()visibility - Return values should be strings for clean REPL display
How the Kernel Exposes Your Skill
After installation into the persistent IPython kernel (default ~/.prime/agent/kernel-venv, override with PRIME_AGENT_KERNEL_VENV), the kernel:
- Imports the package under the derived import name
- Binds it to a matching variable in the REPL namespace
- Wraps the module to make it directly awaitable—calling
await word_count(...)invokesword_count.run(...) - Captures import failures: broken skills bind to a placeholder that raises
RuntimeErrorwith details
This behavior is implemented in [packages/coding-agent/src/core/skill-blocks.ts](https://github.com/PrimeIntellect-ai/prime-agent/blob/main/packages/coding-agent/src/core/skill-blocks.ts), which handles lazy loading of Python packages on demand.
Three Ways to Use Your Skill
| Context | Syntax | Notes |
|---|---|---|
| IPython REPL | await word_count("text", top=3) |
Direct await on the bound module |
| Shell cell | !word_count "text" --top 3 |
Uses [project.scripts] entry point |
| Other skills | import rlm; await rlm.run("subtask") |
Spawn sub-agents via rlm module |
Verification Steps
Follow this checklist to validate your executable skill:
1. Contract check
Verify the directory structure, valid Python identifier conversion, and wheel configuration.
2. Standalone test
Run outside the kernel before loading into Prime Agent:
cd <skill-dir> && uv run python -c \
"import asyncio, word_count; print(asyncio.run(word_count.run('a b a', top=1)))"
3. Kernel test
Start a fresh Prime Agent session, then verify:
help(word_count) # Shows docstring and signature
await word_count("test") # Executes or raises RuntimeError with details
If any step fails, Prime Agent logs a warning and falls back to markdown-only mode.
Summary
- Executable skills as Python packages require
SKILL.md,pyproject.toml, and asrc/package with__init__.pycontaining arun()function - Prime Agent installs packages editable into
~/.prime/agent/kernel-venv(configurable viaPRIME_AGENT_KERNEL_VENV) - The kernel makes modules directly awaitable:
await skill_name(...)callsskill_name.run(...) - Add
[project.scripts]to expose shell commands usable with!prefix - Use async
run()functions for consistency; the kernel awaits both sync and async variants
Frequently Asked Questions
What happens if pyproject.toml is missing?
Prime Agent degrades the skill to markdown-only mode with a load warning. The SKILL.md description remains visible to the LLM, but no Python code executes.
Why does the import name convert hyphens to underscores?
Python identifiers cannot contain hyphens. The conversion rule (my-skill → my_skill) ensures valid module names while preserving descriptive directory naming.
Can I use setuptools instead of hatchling?
Yes, any PEP 517 build backend works. Hatchling is documented in the reference because it cleanly handles cases where the distribution name (with hyphens) differs from the package directory name (with underscores).
How do skills handle dependencies?
List requirements under [project] dependencies in pyproject.toml. Prime Agent installs them during the editable install into the persistent kernel environment.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →