Skip to main content

Writing Skills

A skill teaches FERAL a new capability — calling an API, transforming data, or controlling hardware. There are three ways to create one, depending on complexity.

Option 1: JSON Manifest (any REST API)

Drop a JSON file in ~/.feral/skills/. The Brain discovers it at startup and exposes the endpoints as agent tools.
{
  "skill_id": "weather_api",
  "version": "1.0.0",
  "description": "Real-time weather data for any city",
  "brand": {
    "name": "Weather",
    "icon": "cloud",
    "primary_color": "#3b82f6"
  },
  "auth": {
    "type": "api_key",
    "api_key_header": "X-API-Key"
  },
  "endpoints": [
    {
      "id": "current",
      "method": "GET",
      "url": "https://api.weather.example/current",
      "description": "Get current weather for a city. The LLM reads this to decide when to use the tool.",
      "params": [
        { "name": "city", "type": "string", "required": true, "description": "City name" },
        { "name": "units", "type": "string", "required": false, "description": "celsius or fahrenheit" }
      ]
    },
    {
      "id": "forecast",
      "method": "GET",
      "url": "https://api.weather.example/forecast",
      "description": "Get a 5-day forecast",
      "params": [
        { "name": "city", "type": "string", "required": true }
      ]
    }
  ],
  "trigger_phrases": ["weather", "temperature", "forecast"],
  "categories": ["weather", "utility"]
}
Set the API key securely:
export FERAL_KEY_weather_api=your-key-here
The Blind Vault stores this key and injects it into requests — the LLM never sees the raw value.

Manifest Fields

FieldRequiredDescription
skill_idyesUnique identifier
descriptionyesThe LLM reads this to decide when to invoke the skill
brandnoDisplay name, icon, and color in the dashboard
authnoAuthentication config (api_key, bearer, oauth2)
endpoints[]yesOne or more callable endpoints
trigger_phrasesnoHints for the LLM’s skill selection
categoriesnoFor marketplace and dashboard grouping

Option 2: Python Plugin

For tools that need custom logic (not just HTTP calls), use the SDK’s FeralPlugin base class.
from feral_sdk import FeralPlugin, feral_tool

class TranslatorPlugin(FeralPlugin):
    name = "translator"
    description = "Translate text between languages"
    version = "0.1.0"

    @feral_tool(description="Translate text to a target language")
    async def translate(self, text: str, target_lang: str) -> dict:
        translated = await self._call_translation_service(text, target_lang)
        return {"original": text, "translated": translated, "language": target_lang}

    async def _call_translation_service(self, text: str, lang: str) -> str:
        # Your implementation
        ...

    async def on_load(self):
        """Called once when the Brain loads this plugin."""
        print(f"Translator plugin v{self.version} loaded")

Plugin Lifecycle

MethodWhen
on_load()Brain starts or hot-reloads the plugin
on_unload()Brain shuts down
execute(endpoint_id, args, vault)Brain invokes a tool (called automatically)
to_manifest()Generates a skill manifest from @feral_tool decorators

Installing a Python Plugin

Place the module in ~/.feral/plugins/ or install it as a Python package. The Brain discovers plugins that subclass FeralPlugin.

Option 3: WASM Skill (sandboxed)

For untrusted or third-party skills, FERAL can execute WebAssembly modules in a Wasmtime sandbox.
# Scaffold a new WASM skill
cp -r templates/wasm-skill-assemblyscript my-skill
cd my-skill
npm install
npm run build    # produces build/skill.wasm
Place the .wasm file alongside a manifest:
{
  "skill_id": "my_wasm_skill",
  "description": "Sandboxed skill",
  "runtime": "wasm",
  "wasm_path": "skill.wasm",
  "endpoints": [
    { "id": "run", "description": "Execute the skill" }
  ]
}

Self-Learning Skills

FERAL can auto-detect repeated patterns and generate skill manifests from usage history. When the agent notices it keeps performing the same multi-step sequence, it proposes a new skill. You can review and approve pending skills:
# List pending auto-generated skills
curl http://localhost:9090/api/skills/pending

# Approve one
curl -X POST http://localhost:9090/api/skills/approve/skill_id

Skill Marketplace

Browse and install community skills from the registry:
feral marketplace search "weather"
feral marketplace install weather_api
Or via the API:
curl "http://localhost:9090/api/marketplace/search?q=weather"
curl -X POST http://localhost:9090/api/marketplace/install -d '{"skill_id": "weather_api"}'