An open-source Agent Skill framework implementing the progressive disclosure architecture for AI agent skills.
-
Three-layer progressive disclosure architecture
- Layer 1 (Metadata): Always loaded for skill discovery
- Layer 2 (Instruction): Loaded on demand when skill is selected
- Layer 3 (Resources): Conditionally loaded References and Scripts
-
SKILL.md file format - Simple markdown-based skill definition
-
Smart Reference loading - Three modes (explicit/implicit/always) with LLM-based selection
-
Auto-discovery - Automatically discover references from
references/directory -
Script execution - Run scripts triggered by LLM via
[INVOKE:name] -
Multiple LLM providers - OpenAI, Azure OpenAI, Ollama, Together, Groq, DeepSeek
-
Auto skill invocation - Automatically match and invoke skills based on user queries
-
Multimodal support - Handle images via URL, base64, or file path
-
Sandbox execution - Secure script execution in isolated AIO Sandbox environment
-
Automatic file sync - Upload input files and download outputs automatically
pip install openskills-sdkimport asyncio
from openskills import create_agent
async def main():
# Create agent with infographic-skills
agent = await create_agent(
skill_paths=["./infographic-skills"],
api_key="your-api-key",
model="gpt-4",
)
# Chat with automatic skill invocation
response = await agent.chat("帮我总结会议")
print(response.content)
print(f"Used skill: {response.skill_used}")
asyncio.run(main())import asyncio
from openskills import create_agent
async def main():
# Create agent with sandbox enabled
agent = await create_agent(
skill_paths=["./skills"],
api_key="your-api-key",
model="gpt-4",
use_sandbox=True, # Enable sandbox execution
sandbox_base_url="http://localhost:8080",
auto_execute_scripts=True,
)
# Local file paths are automatically uploaded to sandbox
response = await agent.chat("请处理这个文件: /path/to/file.pdf")
print(response.content)
# Output files are automatically downloaded to skill_dir/output/
asyncio.run(main())from pathlib import Path
from openskills import SkillManager
manager = SkillManager([Path("./infographic-skills")])
# Discover infographic-skills (Layer 1 - Metadata)
await manager.discover()
# Match user query
skills = manager.match("summarize meeting")
# Load instruction (Layer 2)
if skills:
instruction = await manager.load_instruction(skills[0].name)
print(instruction.content)OpenSkills supports executing scripts in an isolated sandbox environment using AIO Sandbox. This provides:
- Security: Scripts run in isolated containers
- Dependency management: Auto-install Python packages defined in SKILL.md
- File synchronization: Automatic upload/download of files
# Pull and run the sandbox container
docker run -d --name aio-sandbox \
-p 8080:8080 \
ghcr.io/agent-infra/aio-sandbox:latest
# Verify it's running
curl http://localhost:8080/health# docker-compose.yml
version: '3.8'
services:
sandbox:
image: ghcr.io/agent-infra/aio-sandbox:latest
ports:
- "8080:8080"
volumes:
- sandbox-data:/home/gem
restart: unless-stopped
volumes:
sandbox-data:docker-compose up -dDefine dependencies in SKILL.md frontmatter:
dependency:
python:
- PyMuPDF==1.23.8
- pandas>=2.0.0
system:
- mkdir -p output/imagesDependencies are installed automatically when the skill is initialized.
- Upload: Local file paths in script input are auto-uploaded to
/home/gem/uploads/ - Download: Specify output directories in script config to auto-download results
scripts:
- name: process_file
path: scripts/process.py
description: Process uploaded files
timeout: 120
outputs:
- /home/gem/output # Auto-sync to local skill_dir/output/For advanced use cases, use the SandboxClient directly:
from openskills.sandbox import SandboxClient
async with SandboxClient("http://localhost:8080") as client:
# Execute commands
result = await client.exec_command("python --version")
print(result.output)
# File operations
await client.write_file("/home/gem/test.txt", "Hello World")
content = await client.read_file("/home/gem/test.txt")
# Upload/download files
await client.upload_file(local_bytes, "/home/gem/uploads/file.pdf")
data = await client.download_file("/home/gem/output/result.txt")
# List files
files = await client.list_files("/home/gem/output")
for f in files:
print(f"{f.name} (dir={f.is_dir})")my-skill/
├── SKILL.md # Skill definition (required)
├── references/ # Reference documents
│ └── handbook.md
└── scripts/ # Executable scripts
└── upload.py
---
name: meeting-summary
description: Summarize meetings in structured format
version: 1.0.0
triggers:
- "summarize meeting"
- "会议总结"
references:
- path: references/finance-handbook.md
condition: "When content involves finance or budget"
description: Financial guidelines
mode: explicit # LLM evaluates condition
- path: references/frameworks/
mode: implicit # LLM decides if useful (default)
- path: references/safety-policy.md
mode: always # Always loaded
scripts:
- name: upload
path: scripts/upload.py
description: Upload summary to cloud storage
---
# Meeting Summary Skill
You are a professional meeting assistant...
## Output Format
...┌─────────────────────────────────────────────────────────────┐
│ OpenSkills SDK │
├─────────────────────────────────────────────────────────────┤
│ Layer 1: Metadata (Always loaded) │
│ ├── name, description, triggers, tags │
│ └── Used for skill discovery and matching │
├─────────────────────────────────────────────────────────────┤
│ Layer 2: Instruction (On-demand) │
│ ├── SKILL.md body content │
│ └── Loaded when skill is selected │
├─────────────────────────────────────────────────────────────┤
│ Layer 3: Resources (Conditional) │
│ ├── Reference: Documents loaded based on conditions │
│ └── Script: Executed when LLM outputs [INVOKE:name] │
└─────────────────────────────────────────────────────────────┘
References support three loading modes:
| Mode | Behavior |
|---|---|
explicit |
Has condition, LLM evaluates whether condition is met |
implicit |
No condition, LLM decides if useful for current query (default) |
always |
Always loaded (e.g., safety guidelines, specs) |
References are automatically discovered from the references/ directory. You don't need to declare every file in frontmatter:
my-skill/
├── SKILL.md
└── references/
├── guide.md # Auto-discovered (implicit mode)
├── api-docs.md # Auto-discovered (implicit mode)
└── frameworks/
└── react.md # Auto-discovered (implicit mode)
You can still declare specific references in frontmatter to customize their behavior:
references:
# Override mode for specific file
- path: references/guide.md
mode: always # Now always loaded instead of implicit
# Add condition for another file
- path: references/api-docs.md
condition: "When user asks about API"
mode: explicitAuto-discovered files that aren't declared in frontmatter default to implicit mode, letting the LLM decide whether to load them based on the user's query.
export OPENAI_API_KEY=your-api-key
export OPENAI_BASE_URL=https://api.openai.com/v1 # Optional
export OPENAI_MODEL=gpt-4 # Optionalexport AZURE_OPENAI_API_KEY=your-azure-api-key
export AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
export AZURE_OPENAI_DEPLOYMENT=your-deployment-name
export AZURE_OPENAI_API_VERSION=2024-02-15-preview # Optionalfrom openskills import AzureOpenAIClient, SkillAgent
# Method 1: Using environment variables
client = AzureOpenAIClient()
# Method 2: Explicit configuration
client = AzureOpenAIClient(
api_key="your-api-key",
endpoint="https://your-resource.openai.azure.com",
deployment="gpt-4",
)
# Method 3: Using create_client helper
from openskills import create_client
client = create_client("azure", deployment="gpt-4")
# Use with SkillAgent
agent = SkillAgent(
skill_paths=["./infographic-skills"],
llm_client=client,
)See the examples directory for complete examples:
demo.py- Main demo showing reference auto-discovery and LLM selectionprompt-optimizer/- Prompt engineering skill with 57 frameworks (auto-discovered)meeting-summary/- Meeting summarization skill with finance referenceoffice-skills/- Word and Excel processing skillsfile-to-article-generator/- PDF/Word parsing with sandbox executionweekly-report-to-annual/- Weekly report aggregation skill
cd examples
export OPENAI_API_KEY=your-api-key
python demo.py# 1. Start sandbox first
docker run -d -p 8080:8080 ghcr.io/agent-infra/aio-sandbox:latest
# 2. Run demo with sandbox
cd examples/file-to-article-generator
export OPENAI_API_KEY=your-api-key
python demo.py /path/to/your/file.pdfThe sandbox demo will:
- Initialize sandbox environment and install dependencies
- Upload your file to sandbox automatically
- Execute parsing script in isolated environment
- Download generated images to local
output/directory - Generate article with proper image references
# List all infographic-skills
openskills list
# Show skill details
openskills show meeting-summary
# Validate a skill
openskills validate ./my-skill/
# Match query to infographic-skills
openskills match "summarize meeting"This project is licensed under the Apache License 2.0 - see the LICENSE file for details.