Skip to main content
Skills are pluggable tool bundles that extend agent capabilities in OpenFang. A skill packages one or more tools with their implementation, letting agents do things that built-in tools do not cover.

Overview

A skill consists of:

Manifest

skill.toml or SKILL.md that declares metadata, runtime, tools, and requirements

Entry Point

Python script, WASM module, Node.js module, or prompt-only Markdown
Skills are installed to ~/.openfang/skills/ and made available to agents through the skill registry. OpenFang ships with 60 bundled skills compiled into the binary and available immediately.

Supported Runtimes

RuntimeLanguageSandboxedNotes
pythonPython 3.8+No (subprocess with env_clear())Easiest to write. Uses stdin/stdout JSON protocol.
wasmRust, C, Go, etc.Yes (Wasmtime dual metering)Fully sandboxed. Best for security-sensitive tools.
nodeJavaScript/TypeScriptNo (subprocess)OpenClaw compatibility.
prompt_onlyMarkdownN/AExpert knowledge injected into system prompt. No code execution.
builtinRustN/ACompiled into the binary. For core tools only.

60 Bundled Skills

OpenFang includes 60 expert knowledge skills compiled into the binary:

DevOps & Infra

ci-cd, ansible, prometheus, nginx, kubernetes, terraform, helm, docker, sysadmin, shell-scripting, linux-networking

Cloud

aws, gcp, azure

Languages

rust-expert, python-expert, typescript-expert, golang-expert

Frontend

react-expert, nextjs-expert, css-expert

Databases

postgres-expert, redis-expert, sqlite-expert, mongodb, elasticsearch, sql-analyst

APIs & Web

graphql-expert, openapi-expert, api-tester, oauth-expert

AI/ML

ml-engineer, llm-finetuning, vector-db, prompt-engineer

Security

security-audit, crypto-expert, compliance

Dev Tools

github, git-expert, jira, linear-tools, sentry, code-reviewer, regex-expert

Writing

technical-writer, writing-coach, email-writer, presentation

Data

data-analyst, data-pipeline

Collaboration

slack-tools, notion, confluence, figma-expert

Career

interview-prep, project-manager

Advanced

wasm-expert, pdf-reader, web-search
These are prompt_only skills using the SKILL.md format — expert knowledge that gets injected into the agent’s system prompt.

SKILL.md Format

The SKILL.md format (also used by OpenClaw) uses YAML frontmatter and a Markdown body:
---
name: rust-expert
description: Expert Rust programming knowledge
---

# Rust Expert

## Key Principles
- Ownership and borrowing rules...
- Lifetime annotations...

## Common Patterns
...
SKILL.md files are automatically parsed and converted to prompt_only skills. All SKILL.md files pass through an automated prompt injection scanner that detects override attempts, data exfiltration patterns, and shell references before inclusion.

Skill Format

Directory Structure

my-skill/
  skill.toml          # Manifest (required)
  src/
    main.py           # Entry point (for Python skills)
  README.md           # Optional documentation

Manifest (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"
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(*)"]

Manifest Sections

FieldTypeRequiredDescription
namestringYesUnique skill name (used as install directory name)
versionstringNoSemantic version (default: "0.1.0")
descriptionstringNoHuman-readable description
authorstringNoAuthor name or organization
licensestringNoLicense identifier (e.g., "MIT", "Apache-2.0")
tagsarrayNoTags for discovery on FangHub
FieldTypeRequiredDescription
typestringYes"python", "wasm", "node", or "builtin"
entrystringYesRelative path to the entry point file
Each entry defines one tool that the skill provides:
FieldTypeRequiredDescription
namestringYesTool name (must be unique across all tools)
descriptionstringYesDescription shown to the LLM
input_schemaobjectYesJSON Schema defining the tool’s input parameters
FieldTypeDescription
toolsarrayBuilt-in tools this skill needs the host to provide
capabilitiesarrayCapability strings the agent must have

Python Skills

Python skills are the simplest to write. They run as subprocesses and communicate via JSON over stdin/stdout.

Protocol

1

OpenFang sends JSON to stdin

{
  "tool": "summarize_url",
  "input": {
    "url": "https://example.com"
  },
  "agent_id": "uuid-...",
  "agent_name": "researcher"
}
2

Script processes and writes to stdout

Success:
{
  "result": "- Point one\n- Point two\n- Point three"
}
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 more advanced skills, 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\nlink2"

if __name__ == "__main__":
    handler.run()

WASM Skills

WASM skills run inside a sandboxed Wasmtime environment. They are ideal for security-sensitive operations.

Building a WASM Skill

1

Write your skill in Rust

// src/lib.rs
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}));
}
2

Compile to WASM

cargo build --target wasm32-wasi --release
3

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 the capabilities granted to the agent apply
These are derived from the agent’s [resources] section in its manifest.

Installing Skills

From a 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 a Git Repository

openfang skill install https://github.com/user/openfang-skill-example.git

Listing Installed Skills

openfang skill list
Output:
3 skill(s) installed:

NAME                 VERSION    TOOLS    DESCRIPTION
----------------------------------------------------------------------
web-summarizer       0.1.0      2        Summarizes any web page into bullet points
data-analyzer        0.2.1      3        Statistical analysis tools
code-formatter       1.0.0      1        Format code in 20+ languages

Removing 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, merging them with the agent’s base capabilities.

Publishing to FangHub

FangHub is the community skill marketplace for OpenFang.

Preparing Your Skill

1

Complete metadata

Ensure your skill.toml has: name, version, description, author, license, tags
2

Add documentation

Include a README.md with usage instructions
3

Test locally

openfang skill install /path/to/my-skill
# Spawn an agent with the skill's tools and test them

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 will be available via:
openfang skill publish
This validates the manifest, packages the skill, and uploads it to the FangHub registry.

CLI Commands

Full Skill Command Reference

# Install a skill (local directory, FangHub name, or git URL)
openfang skill install <source>

# List all installed skills
openfang skill list

# Remove an installed skill
openfang skill remove <name>

# Search FangHub for skills
openfang skill search <query>

# Create a new skill scaffold (interactive)
openfang skill create

Creating a Skill Scaffold

openfang skill create
This interactive command prompts for:
  • Skill name
  • Description
  • Runtime type (python/node/wasm)
It generates:
~/.openfang/skills/my-skill/
  skill.toml        # Pre-filled manifest
  src/
    main.py         # Starter entry point (for Python)
The generated entry point includes a working template.

OpenClaw Compatibility

OpenFang can install and run OpenClaw-format skills. The skill installer auto-detects OpenClaw skills (by looking for package.json + index.ts/index.js) and converts them.

Automatic Conversion

openfang skill install /path/to/openclaw-skill
If the directory contains an OpenClaw-style skill, OpenFang:
1

Detect format

Identifies OpenClaw format by presence of Node.js package files
2

Generate manifest

Creates skill.toml from package.json
3

Map tool names

Converts tool names to OpenFang conventions
4

Install

Copies skill to OpenFang skills directory

Manual Conversion

If automatic conversion does not 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"] }
Place alongside the existing index.js/index.ts and install:
openfang skill install /path/to/skill-directory
Skills imported via openfang migrate --from openclaw are scanned and reported in the migration report, with instructions for manual reinstallation.

Best Practices

Keep Skills Focused

One skill should do one thing well

Declare Minimal Requirements

Only request tools and capabilities you actually need

Use Descriptive Names

LLM reads tool names to decide when to use them

Clear Input Schemas

Include descriptions for every parameter

Handle Errors Gracefully

Return JSON error objects rather than crashing

Version Carefully

Use semantic versioning; breaking changes require major bump

Test with Multiple Agents

Verify compatibility with different agent templates and providers

Include Documentation

Document setup steps, dependencies, and examples