From PyPI Package to Agent Skill: Conversion Guide
Already have a useful Python package on PyPI? This step-by-step guide walks you through converting it into a portable, verified agent skill using the ANP format — unlocking discovery, cross-framework compatibility, and monetization.
You have spent months building a Python package. It is on PyPI. It has users. It works. But right now, AI agents cannot discover it, trust it, or use it without custom glue code written by every single developer who wants to integrate it into an agent workflow.
Converting your PyPI package into an ANP agent skill changes that. Your tool becomes discoverable in the AgentNode skill catalog, verified through automated sandbox testing, compatible with every major agent framework, and — if you choose — monetizable through the AgentNode marketplace.
This guide walks through the entire conversion process, from analyzing your existing package to publishing a fully verified agent skill. If you have a working Python package, you can have a working agent skill in under an hour.
Why Convert a PyPI Package to an Agent Skill?
Before diving into the technical steps, it helps to understand what you gain from conversion and why the agent ecosystem needs packaged skills rather than raw libraries.
Discovery
PyPI is a package registry for humans. Developers search by name, read documentation, and manually integrate. AgentNode is a capability registry for both humans and machines. AI agents can search by function ("I need web scraping"), find your skill, and install it — all programmatically. Your tool gets discovered by agents and developers who never would have found it on PyPI alone.
Verification and Trust
PyPI packages have no built-in quality signal. A package with 10 downloads and one with 10 million look structurally identical. AgentNode verifies every skill through a four-stage sandbox pipeline — install, import, smoke test, and unit test — and assigns a public trust score. When an agent evaluates your tool, it sees a concrete trust tier (Gold, Verified, Partial, or Unverified) rather than guessing based on star counts or download numbers.
Cross-Framework Compatibility
A PyPI package works in Python. An agent skill works in LangChain, CrewAI, AutoGPT, MCP, Semantic Kernel, and vanilla Python — all without modification. You write the conversion once, and every framework's users can leverage your tool immediately.
Monetization
PyPI packages are free to distribute. Agent skills on AgentNode can be free or paid. If you have built something genuinely valuable, you can monetize your agent tools through usage-based pricing, subscription tiers, or one-time purchase — all handled by the platform.
Structured Contracts
A PyPI package exposes functions that developers learn from docs. An agent skill exposes typed input and output schemas that machines can parse without reading documentation. This makes your tool usable by autonomous agents that select and invoke tools at runtime.
Before You Start: Assess Your Package
Not every PyPI package is a natural fit for agent skill conversion. The best candidates share these characteristics:
- Clear input/output contracts — functions that take defined parameters and return structured data.
- Stateless or minimally stateful — tools that can be called independently without managing complex session state.
- Self-contained operations — each function performs a complete unit of work rather than requiring multi-step orchestration.
- Reasonable execution time — tools that complete in seconds to minutes, not hours.
Examples of great conversion candidates:
- API wrapper libraries (weather, finance, search)
- Data processing utilities (PDF parsing, CSV transformation, image resizing)
- Text analysis tools (sentiment, summarization, translation)
- Code utilities (linting, formatting, static analysis)
- Scraping and extraction tools
Examples that need more thought:
- Full web frameworks (Django, Flask) — too broad, not tool-shaped
- Database ORMs — require persistent connections and configuration
- GUI libraries — agents do not have screens
Step 1: Identify Your Tool Functions
The first step is mapping your package's public API to individual agent capabilities. Open your package and list every function that an external user would call. Then filter for functions that are self-contained and produce useful output from defined input.
For example, imagine you have a package called textkit with this public API:
# textkit/__init__.py
from .analyzer import analyze_sentiment, extract_keywords, detect_language
from .summarizer import summarize_text
from .translator import translate
from .utils import clean_text, tokenize
The first five functions are strong agent skill candidates — each takes text input and returns structured output. The utility functions (clean_text, tokenize) are internal helpers that probably do not need their own capability declarations.
For each candidate function, document:
- Function name and module path
- Input parameters with types
- Return value structure
- Whether it needs network access, filesystem access, or external credentials
- Typical execution time
Step 2: Create the ANP Manifest
The manifest is the heart of your agent skill. It tells AgentNode — and every AI agent — what your tool does, what it needs, and how to call it. Create a manifest.json in your project root. Refer to the ANP manifest reference for the full specification.
Here is a complete manifest for converting our hypothetical textkit package:
{
"manifest_version": "0.2",
"name": "textkit",
"version": "1.0.0",
"summary": "Text analysis toolkit: sentiment, keywords, summarization, translation",
"author": {
"name": "Your Name",
"email": "you@example.com"
},
"license": "MIT",
"capabilities": [
{
"name": "analyze_sentiment",
"capability_type": "tool",
"description": "Analyze text sentiment and return a score from -1 to 1",
"entrypoint": "textkit.analyzer:analyze_sentiment",
"input_schema": {
"type": "object",
"properties": {
"text": {"type": "string", "description": "Text to analyze", "maxLength": 10000}
},
"required": ["text"]
},
"output_schema": {
"type": "object",
"properties": {
"score": {"type": "number", "minimum": -1.0, "maximum": 1.0},
"label": {"type": "string", "enum": ["positive", "negative", "neutral"]},
"confidence": {"type": "number", "minimum": 0, "maximum": 1}
}
}
},
{
"name": "summarize_text",
"capability_type": "tool",
"description": "Summarize a long document into key points",
"entrypoint": "textkit.summarizer:summarize_text",
"input_schema": {
"type": "object",
"properties": {
"text": {"type": "string", "description": "Document to summarize"},
"max_length": {"type": "integer", "description": "Maximum summary length", "default": 200}
},
"required": ["text"]
},
"output_schema": {
"type": "object",
"properties": {
"summary": {"type": "string"},
"key_points": {"type": "array", "items": {"type": "string"}},
"word_count": {"type": "integer"}
}
}
}
],
"permissions": {
"network": "none",
"filesystem": "none",
"code_execution": "none"
},
"compatibility": {
"frameworks": ["langchain", "crewai", "autogpt", "mcp", "vanilla"],
"python": ">=3.9"
}
}
Key decisions during manifest creation:
- One capability per tool function — do not try to merge multiple functions into a single capability. Each tool should do one thing clearly.
- Be precise with schemas — the more specific your input and output schemas, the better agents can use your tool. Include descriptions, constraints, defaults, and enums.
- Be honest about permissions — if your tool makes HTTP calls, declare
"network": "external". Lying about permissions will cause verification failures.
Step 3: Add Capability Declarations
Beyond the manifest, your tool functions may need minor adjustments to work cleanly as agent skills. The goal is not to rewrite your package — it is to ensure each function has a clean, predictable interface.
Input Handling
Agent skills receive input as a dictionary matching the declared input schema. If your existing function uses positional arguments, add a thin wrapper:
# Before (PyPI-style)
def analyze_sentiment(text: str, language: str = "en") -> dict:
...
# After (agent-skill wrapper — optional, only if needed)
def analyze_sentiment(params: dict) -> dict:
text = params["text"]
language = params.get("language", "en")
return _analyze_sentiment_impl(text, language)
Many packages already accept keyword arguments, which map naturally to dictionary input without any wrapper at all. The AgentNode SDK handles the mapping automatically in most cases.
Output Normalization
Ensure your function returns a JSON-serializable dictionary matching your declared output schema. If your function currently returns a custom object, add serialization:
# Before
def analyze_sentiment(text: str) -> SentimentResult:
...
# After
def analyze_sentiment(text: str) -> dict:
result = _analyze_impl(text)
return {
"score": result.score,
"label": result.label,
"confidence": result.confidence
}
Error Handling
Agent skills should raise clear exceptions with informative messages rather than returning error codes or silently failing. The AgentNode runtime catches exceptions and reports them to the calling agent in a structured format.
Step 4: Write Tests
Tests are optional but strongly recommended. Publisher-provided tests are worth significantly more in the verification scoring (15 points vs. 8 for auto-generated tests, up to 3 for no tests). More importantly, tests demonstrate that your tool works as declared.
Create a tests/ directory with pytest-compatible test files:
# tests/test_sentiment.py
from textkit.analyzer import analyze_sentiment
def test_positive_sentiment():
result = analyze_sentiment("I love this product, it is amazing!")
assert result["label"] == "positive"
assert result["score"] > 0.5
assert 0 <= result["confidence"] <= 1
def test_negative_sentiment():
result = analyze_sentiment("This is terrible and broken.")
assert result["label"] == "negative"
assert result["score"] < 0
def test_empty_input():
try:
analyze_sentiment("")
assert False, "Should have raised ValueError"
except ValueError:
pass
def test_output_schema():
result = analyze_sentiment("Neutral informational text.")
assert "score" in result
assert "label" in result
assert "confidence" in result
assert isinstance(result["score"], (int, float))
assert result["label"] in ["positive", "negative", "neutral"]
Focus tests on three areas: happy paths (expected inputs produce expected outputs), edge cases (empty strings, very long inputs, special characters), and schema compliance (outputs match the declared output schema).
Step 5: Publish to AgentNode
With your manifest, adjusted functions, and tests in place, publishing is straightforward. Follow the complete walkthrough in publish your first ANP package for detailed instructions, or use the quick path below.
Install the CLI and authenticate:
npm install -g agentnode-cli
agentnode login
Validate your manifest locally:
agentnode validate ./manifest.json
Publish:
agentnode publish .
AgentNode will upload your package, run the four-stage verification pipeline (install, import, smoke test, unit tests), and assign a trust score. You can watch the verification progress in real time on your dashboard or via the CLI.
Alternatively, use the web-based publish your converted skill page to upload directly through the browser.
Before and After: A Real Conversion
Let us look at a concrete before-and-after comparison for a real-world package — a currency conversion library.
Before: Standard PyPI Package
# currency_converter/converter.py
import requests
class CurrencyConverter:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.exchangerates.com/v1"
def convert(self, amount: float, from_currency: str, to_currency: str) -> float:
response = requests.get(
f"{self.base_url}/convert",
params={"from": from_currency, "to": to_currency, "amount": amount},
headers={"Authorization": f"Bearer {self.api_key}"}
)
return response.json()["result"]
Problems from an agent's perspective: requires instantiation with an API key, returns a bare float with no context, no typed schema, not discoverable, and only works in Python with manual integration.
After: ANP Agent Skill
# currency_converter/tools.py
import os
import requests
def convert_currency(params: dict) -> dict:
"""Convert an amount between currencies using live exchange rates."""
api_key = os.environ.get("EXCHANGE_API_KEY")
if not api_key:
raise ValueError("EXCHANGE_API_KEY environment variable not set")
amount = params["amount"]
from_currency = params["from_currency"].upper()
to_currency = params["to_currency"].upper()
response = requests.get(
"https://api.exchangerates.com/v1/convert",
params={"from": from_currency, "to": to_currency, "amount": amount},
headers={"Authorization": f"Bearer {api_key}"}
)
response.raise_for_status()
data = response.json()
return {
"converted_amount": data["result"],
"from_currency": from_currency,
"to_currency": to_currency,
"original_amount": amount,
"exchange_rate": data["info"]["rate"],
"timestamp": data["info"]["timestamp"]
}
Improvements: credential handling via environment variables (standard for agent runtimes), structured dictionary output matching the declared schema, clear error messages, and a flat function signature that maps directly to the capability declaration.
Common Patterns for Wrapping Existing Libraries
Most conversions follow one of these patterns. Understanding which pattern your package fits will speed up the process significantly.
Pattern 1: Direct Function Mapping
Your package already exposes clean functions with typed parameters. Conversion is nearly trivial — create a manifest pointing to your existing functions and ensure output is JSON-serializable.
# Already works as an agent skill with minimal changes
def detect_language(text: str) -> dict:
return {"language": "en", "confidence": 0.97}
Pattern 2: Class Instance Wrapping
Your package uses classes that need instantiation. Create a thin wrapper function that handles initialization internally.
# Wrapper for class-based packages
def scrape_page(params: dict) -> dict:
scraper = WebScraper(timeout=params.get("timeout", 30))
result = scraper.scrape(params["url"])
return {"content": result.text, "title": result.title}
Pattern 3: Multi-Step Pipeline Wrapping
Your package requires multiple calls in sequence. Bundle the pipeline into a single capability function.
# Bundle a multi-step pipeline
def process_document(params: dict) -> dict:
doc = load_document(params["file_path"])
cleaned = clean_document(doc)
extracted = extract_entities(cleaned)
return {"entities": extracted, "page_count": doc.page_count}
Pattern 4: Credential-Dependent Services
Your package wraps an external API requiring authentication. Use environment variables and declare network permissions honestly.
# Credential pattern — environment variables
def search_flights(params: dict) -> dict:
api_key = os.environ.get("FLIGHTS_API_KEY")
if not api_key:
raise ValueError("FLIGHTS_API_KEY not configured")
# ... API call logic
return {"flights": results}
Using the Import Tool for Faster Conversion
If you prefer a guided experience, AgentNode provides an import existing tools to AgentNode page. Paste your existing Python code — whether it is a LangChain tool, an MCP server, an OpenAI function definition, or a plain Python function — and the platform generates the ANP manifest and wrapper code automatically.
The import tool handles:
- Schema inference from type hints and docstrings
- Automatic permission detection based on imports (e.g.,
requestsimplies network access) - Framework-specific adapter removal (strips LangChain/CrewAI decorators and produces clean ANP functions)
- Test generation based on inferred schemas
This is the fastest path from existing code to published skill, often taking under ten minutes.
Keeping Your PyPI Package and Agent Skill in Sync
A common question: does converting to an agent skill mean abandoning your PyPI package? Absolutely not. Your PyPI package continues to work exactly as before. The ANP skill is an additional distribution channel that wraps or references the same underlying code.
Best practices for maintaining both:
- Single source of truth — keep your core logic in the PyPI package. Have the agent skill import from it.
- Version alignment — when you release a new PyPI version, update the ANP manifest version to match.
- CI integration — add
agentnode validateandagentnode publishto your CI/CD pipeline so both distributions stay synchronized. - Test sharing — run the same test suite for both the PyPI package and the agent skill.
Verification Checklist
Before publishing, run through this checklist to maximize your verification score:
- Manifest validates with
agentnode validate - All entrypoints are importable from a clean install
- Input schemas have types, descriptions, and required fields
- Output schemas match actual function return values
- Permissions accurately reflect resource usage
- Tests cover happy paths, edge cases, and schema compliance
- No hardcoded credentials (use environment variables)
- Functions return JSON-serializable dictionaries
- Error handling uses descriptive exceptions
- Dependencies are pinned in requirements.txt or pyproject.toml
Frequently Asked Questions
Can I convert a PyPI package to an agent skill?
Yes. Any Python package that exposes callable functions with defined inputs and outputs can be converted to an ANP agent skill. The process involves creating a manifest.json that describes your tool's capabilities, ensuring your functions return JSON-serializable output, and publishing through the AgentNode CLI or web interface. Packages that wrap APIs, process data, or perform text analysis are the most natural candidates.
How long does conversion take?
For a well-structured package with clean function signatures, conversion typically takes 30 to 60 minutes. Most of that time is spent writing the manifest and tests. If your functions already accept keyword arguments and return dictionaries, the code changes are minimal. The import tool can automate much of the manifest generation, reducing the process to under 15 minutes for simple packages.
Will my package still work on PyPI after conversion?
Absolutely. Converting to an agent skill does not modify your PyPI package in any way. The ANP manifest and any wrapper functions are additions to your project, not replacements. Your existing users continue installing from PyPI as usual. The agent skill is simply an additional distribution channel that makes your tool accessible to AI agents and compatible with agent frameworks.
What are the benefits of converting to ANP?
Converting to the ANP format provides five key benefits. First, your tool becomes discoverable by AI agents through semantic capability search. Second, automated verification gives your tool a public trust score. Third, cross-framework compatibility means your tool works in LangChain, CrewAI, AutoGPT, MCP, and more without modification. Fourth, typed schemas let agents understand and invoke your tool without reading documentation. Fifth, you gain access to monetization options through the AgentNode marketplace if you choose to charge for usage.