Metronisys Tools & Skills Template"
You can build your own custom tools and skills and import them into the Metronisys Solution by building against this template.
Building a Custom Dynamic Skill
Follow this guide to develop, register, and deploy .skill files into the Metronisys runtime.
Overview
Dynamic skills are Python logic stored in .skill files within the SKILLS/ folder. The runtime loads them via loader.py, ensuring only files listed in allowed_manifest.json are executed.
1. The Contract (Required)
Every .skill file must define a register() function returning these core fields:
| Field | Type | Purpose |
|---|---|---|
name |
str | Unique tool ID (e.g., my_custom_tool). |
description |
str | Short description for the agent and selector. |
function |
callable | The actual logic function to be invoked. |
def actual_logic_function(**kwargs):
return {"answer": "Example dynamic skill ran.", "status": "ok"}
def register():
return {
"name": "example",
"description": "Example dynamic skill for testing.",
"function": actual_logic_function,
"input_schema": {"query": "string"}
}
2. Implementing Your Skill
Step 1: Logic
Define your_function(**kwargs) -> dict. Ensure it returns a "status" of "ok" or "error".
Step 2: Register
Set unique name, description, and map the input_schema for parameter validation.
3. Importing into Solution
-
1
Add File: Place
my_tool.skillin theSKILLS/directory. -
2
Manifest: Add
"my_tool"toallowed_manifest.json. -
3
Policy: Add
- my_toolto theallow_toolslist in yourbaseline.yml.
Quick Checklist
- ✅ Logic function returns
answerandstatus. - ✅
register()exported with correct metadata. - ✅ Filename matches Tool ID exactly.
- ✅ Security: Use Fernet encryption for production environments.
example.skill
{
# Example dynamic skill (plaintext; for dev only).
# In production, encrypt with Fernet and set METRONISYS_SKILLS_ENCRYPTION_KEY.
#
# CONTRACT:
# - Define register() returning {"name", "description", "function"} (required).
# - Add skill name to allowed_manifest.json "allowed" list.
# - Add skill name to policy allowed_tools (e.g. policies/default/baseline.yml).
#
# OPTIONAL register() fields (sub_agent fills missing params before calling your function):
# - default_params: dict of default kwarg values when task does not infer params.
# - params_from_current_datetime: {param_name: "current_datetime_result_key"}
# e.g. {"start_date": "current_date_utc"} — sub_agent calls built-in current_datetime and fills missing params.
# Valid keys: current_date_utc, current_time_utc, current_datetime_iso, etc.
# - params_from_default_location: list of param names for location/country. Standard way to get location params.
# Valid: ["location", "street", "city", "state", "country", "country_id", "country_code"]
# From prompt: parsed from " for " / " in " → street, city, state, country (name), country_id (code).
# location = street + city + state (concatenated). If prompt has no location, fallback to env:
# location = city + state, country = country. Env: METRONISYS_LOCATION_CITY, _STATE, _COUNTRY.
#
# RETURN: Your function should return a dict with at least "answer" or "message"; include "status": "ok" or "error".
def actual_logic_function(**kwargs):
# your code here #
return {"answer": "Example dynamic skill ran.", "status": "ok"}
def register():
return {
"name": "example",
"description": "Example dynamic skill for testing the loader. Params: query (optional).",
"function": actual_logic_function,
"input_schema": {"query": "string"},
"tags": ["example", "test"],
"capabilities": [],
"keywords": ["example", "test"],
"purpose": "example skill for loader and registry testing",
"use_when": "testing skill loading or tool selection",
"match_phrases": [],
"avoid_phrases": [],
"examples": ["run example skill", "test example"],
}
}