Skills are pluggable tool bundles that extend agent capabilities. A skill packages one or more tools with their implementation, letting agents do things that built-in tools don’t cover.
Overview
A skill consists of:
Manifest (skill.toml or SKILL.md) - Declares metadata, runtime, tools, and requirements
Entry Point - Python script, WASM module, Node.js module, or prompt-only Markdown
OpenFang ships with 60 bundled skills compiled into the binary and available immediately.
Supported Runtimes
Python Easiest to write
Uses stdin/stdout JSON protocol
Not sandboxed (subprocess with env_clear())
Supports Python 3.8+
WASM Most secure
Fully sandboxed (Wasmtime dual metering)
Resource limits enforced
Compile from Rust, C, Go, etc.
Node.js OpenClaw compatible
JavaScript/TypeScript support
Not sandboxed (subprocess)
Auto-converts OpenClaw skills
Prompt Only Expert knowledge
Markdown-based
Injected into system prompt
No code execution
60 bundled skills included
Bundled Skills
OpenFang includes 60 expert knowledge skills compiled into the binary:
Category Skills DevOps & Infra ci-cd, ansible, prometheus, nginx, kubernetes, terraform, helm, docker, sysadmin, shell-scripting, linux-networkingCloud aws, gcp, azureLanguages rust-expert, python-expert, typescript-expert, golang-expertFrontend react-expert, nextjs-expert, css-expertDatabases postgres-expert, redis-expert, sqlite-expert, mongodb, elasticsearch, sql-analystAPIs & Web graphql-expert, openapi-expert, api-tester, oauth-expertAI/ML ml-engineer, llm-finetuning, vector-db, prompt-engineerSecurity security-audit, crypto-expert, complianceDev Tools github, git-expert, jira, linear-tools, sentry, code-reviewer, regex-expertWriting technical-writer, writing-coach, email-writer, presentationData data-analyst, data-pipelineCollaboration slack-tools, notion, confluence, figma-expertCareer interview-prep, project-managerAdvanced wasm-expert, pdf-reader, web-search
Directory Structure
my-skill/
skill.toml # Manifest (required)
src/
main.py # Entry point
README.md # Optional documentation
skill.toml
[ skill ]
name = "web-summarizer"
version = "0.1.0"
description = "Summarizes any web page into bullet points"
author = "openfang-community"
license = "MIT"
tags = [ "web" , "summarizer" , "research" ]
[ runtime ]
type = "python" # python | wasm | node | builtin
entry = "src/main.py"
[[ tools . provided ]]
name = "summarize_url"
description = "Fetch a URL and return a concise bullet-point summary"
input_schema = {
type = "object" ,
properties = {
url = { type = "string" , description = "The URL to summarize" }
},
required = [ "url" ]
}
[[ tools . provided ]]
name = "extract_links"
description = "Extract all links from a web page"
input_schema = {
type = "object" ,
properties = {
url = { type = "string" }
},
required = [ "url" ]
}
[ requirements ]
tools = [ "web_fetch" ]
capabilities = [ "NetConnect(*)" ]
Creating a Python Skill
Python skills communicate via JSON over stdin/stdout.
Protocol
OpenFang sends JSON to stdin
{
"tool" : "summarize_url" ,
"input" : {
"url" : "https://example.com"
},
"agent_id" : "uuid-..." ,
"agent_name" : "researcher"
}
Script processes and writes result to stdout
{
"result" : "- Point one \n - Point two \n - Point three"
}
Or on error: {
"error" : "Failed to fetch URL: connection refused"
}
Example: Web Summarizer
#!/usr/bin/env python3
"""OpenFang skill: web-summarizer"""
import json
import sys
import urllib.request
def summarize_url ( url : str ) -> str :
"""Fetch a URL and return a basic summary."""
req = urllib.request.Request(url, headers = { "User-Agent" : "OpenFang-Skill/1.0" })
with urllib.request.urlopen(req, timeout = 30 ) as resp:
content = resp.read().decode( "utf-8" , errors = "replace" )
# Simple extraction: first 500 chars as summary
text = content[: 500 ].strip()
return f "Summary of { url } : \n { text } ..."
def extract_links ( url : str ) -> str :
"""Extract all links from a web page."""
import re
req = urllib.request.Request(url, headers = { "User-Agent" : "OpenFang-Skill/1.0" })
with urllib.request.urlopen(req, timeout = 30 ) as resp:
content = resp.read().decode( "utf-8" , errors = "replace" )
links = re.findall( r 'href=" ( https ? :// [ ^ " ] + ) "' , content)
unique_links = list ( dict .fromkeys(links))
return " \n " .join(unique_links[: 50 ])
def main ():
payload = json.loads(sys.stdin.read())
tool_name = payload[ "tool" ]
input_data = payload[ "input" ]
try :
if tool_name == "summarize_url" :
result = summarize_url(input_data[ "url" ])
elif tool_name == "extract_links" :
result = extract_links(input_data[ "url" ])
else :
print (json.dumps({ "error" : f "Unknown tool: { tool_name } " }))
return
print (json.dumps({ "result" : result}))
except Exception as e:
print (json.dumps({ "error" : str (e)}))
if __name__ == "__main__" :
main()
Using the OpenFang Python SDK
For cleaner code, use the Python SDK:
#!/usr/bin/env python3
from openfang_sdk import SkillHandler
handler = SkillHandler()
@handler.tool ( "summarize_url" )
def summarize_url ( url : str ) -> str :
# Your implementation here
return "Summary..."
@handler.tool ( "extract_links" )
def extract_links ( url : str ) -> str :
# Your implementation here
return "link1 \n link2"
if __name__ == "__main__" :
handler.run()
Creating a WASM Skill
WASM skills run in a sandboxed Wasmtime environment with enforced resource limits.
Building a WASM Skill
Write your skill in Rust
use std :: io :: { self , Read };
#[no_mangle]
pub extern "C" fn _start () {
let mut input = String :: new ();
io :: stdin () . read_to_string ( & mut input ) . unwrap ();
let payload : serde_json :: Value = serde_json :: from_str ( & input ) . unwrap ();
let tool = payload [ "tool" ] . as_str () . unwrap_or ( "" );
let input_data = & payload [ "input" ];
let result = match tool {
"my_tool" => {
let param = input_data [ "param" ] . as_str () . unwrap_or ( "" );
format! ( "Processed: {param}" )
}
_ => format! ( "Unknown tool: {tool}" ),
};
println! ( "{}" , serde_json :: json! ({ "result" : result }));
}
Compile to WASM
cargo build --target wasm32-wasi --release
Reference in manifest
[ runtime ]
type = "wasm"
entry = "target/wasm32-wasi/release/my_skill.wasm"
Sandbox Limits
The WASM sandbox enforces:
Fuel limit - Maximum computation steps (prevents infinite loops)
Memory limit - Maximum memory allocation
Capabilities - Only capabilities granted to the agent apply
Limits are derived from the agent’s [resources] section in its manifest.
The SKILL.md format uses YAML frontmatter and Markdown body:
---
name : rust-expert
description : Expert Rust programming knowledge
---
# Rust Expert
## Key Principles
- Ownership and borrowing rules...
- Lifetime annotations...
## Common Patterns
...
All SKILL.md files pass through an automated prompt injection scanner that detects override attempts, data exfiltration patterns, and shell references before inclusion.
Installing Skills
From Local Directory
openfang skill install /path/to/my-skill
Reads the skill.toml, validates the manifest, and copies to ~/.openfang/skills/my-skill/.
From FangHub
openfang skill install web-summarizer
Downloads from the FangHub marketplace registry.
From Git Repository
openfang skill install https://github.com/user/openfang-skill-example.git
List Installed Skills
Output:
3 skill(s) installed:
NAME VERSION TOOLS DESCRIPTION
----------------------------------------------------------------------
web-summarizer 0.1.0 2 Summarizes any web page
data-analyzer 0.2.1 3 Statistical analysis tools
code-formatter 1.0.0 1 Format code in 20+ languages
Remove Skills
openfang skill remove web-summarizer
Using Skills in Agents
Reference skills in the agent manifest’s skills field:
name = "my-assistant"
version = "0.1.0"
description = "An assistant with extra skills"
author = "openfang"
module = "builtin:chat"
skills = [ "web-summarizer" , "data-analyzer" ]
[ model ]
provider = "groq"
model = "llama-3.3-70b-versatile"
[ capabilities ]
tools = [ "file_read" , "web_fetch" , "summarize_url" ]
memory_read = [ "*" ]
memory_write = [ "self.*" ]
The kernel loads skill tools and prompts at agent spawn time.
Publishing to FangHub
FangHub is the community skill marketplace for OpenFang.
Preparing Your Skill
Complete metadata
Ensure skill.toml has: name, version, description, author, license, tags
Add documentation
Include a README.md with usage instructions
Test locally
openfang skill install /path/to/my-skill
# Spawn an agent and test the skill's tools
Searching FangHub
openfang skill search "web scraping"
Output:
Skills matching "web scraping":
web-summarizer (42 stars)
Summarizes any web page into bullet points
https://fanghub.dev/skills/web-summarizer
page-scraper (28 stars)
Extract structured data from web pages
https://fanghub.dev/skills/page-scraper
Publishing
Publishing to FangHub (coming soon):
Validates manifest, packages the skill, and uploads to the registry.
OpenClaw Compatibility
OpenFang can install and run OpenClaw-format skills.
Automatic Conversion
openfang skill install /path/to/openclaw-skill
If the directory contains an OpenClaw-style skill (Node.js package), OpenFang:
Detects the OpenClaw format
Generates a skill.toml from package.json
Maps tool names to OpenFang conventions
Copies the skill to the OpenFang skills directory
Manual Conversion
If automatic conversion doesn’t work, create a skill.toml manually:
[ skill ]
name = "my-openclaw-skill"
version = "1.0.0"
description = "Converted from OpenClaw"
[ runtime ]
type = "node"
entry = "index.js"
[[ tools . provided ]]
name = "my_tool"
description = "Tool description"
input_schema = {
type = "object" ,
properties = {
input = { type = "string" }
},
required = [ "input" ]
}
Skills imported via openfang migrate --from openclaw are scanned and reported in the migration report with reinstallation instructions.
Best Practices
Keep it Focused One skill should do one thing well
Minimal Requirements Only request the tools and capabilities you actually need
Descriptive Names The LLM reads tool names and descriptions to decide when to use them
Clear Schemas Include descriptions for every parameter so the LLM knows what to pass
Handle Errors Always return JSON error objects rather than crashing
Version Carefully Use semantic versioning; breaking changes require major version bumps
Test Thoroughly Verify your skill works with different agent templates and providers
Document Well Include setup steps, dependencies, and example usage
CLI Commands
# Install a skill (local directory, FangHub name, or git URL)
openfang skill install < sourc e >
# List all installed skills
openfang skill list
# Remove an installed skill
openfang skill remove < nam e >
# Search FangHub for skills
openfang skill search < quer y >
# Create a new skill scaffold (interactive)
openfang skill create
Creating a Skill Scaffold
Interactive prompts for:
Skill name
Description
Runtime type (python/node/wasm)
Generates:
~/.openfang/skills/my-skill/
skill.toml # Pre-filled manifest
src/
main.py # Starter entry point
Next Steps
Creating Agents Build custom agents that use your skills
API Reference Skill API endpoint documentation