Skills Reference
Skills are user-created Python tools that extend Odin at runtime. Trusted local creation and editing execute the Python module, then validate its runtime tool definition before publication. Edits hot-reload and successful skills are available immediately via invoke_skill. The separate AST validator does not execute code; URL installation additionally runs static validation and prohibited-construct checks before loading. These checks are not a sandbox and do not restrict the capabilities of the supplied context.
Creating a Skill
SKILL_DEFINITION = {
"name": "check_ssl", # Lowercase, underscores, max 50 chars
"description": "Check SSL certificate expiry for a domain",
"input_schema": {
"type": "object",
"properties": {
"domain": {
"type": "string",
"description": "Domain to check"
}
},
"required": ["domain"]
}
}
async def execute(inp: dict, context) -> str:
"""Entry point. Must be async. Returns a string result."""
result = await context.execute_tool(
"http_probe",
{"url": f"https://{inp['domain']}", "timeout": 10}
)
return f"SSL check for {inp['domain']}:\n{result}"Skill Lifecycle
| Tool | Description |
|---|---|
create_skill | Create from Python code. Validates, loads, immediately available. |
edit_skill | Replace code. Re-validates and hot-reloads. |
invoke_skill | Execute by name in the same turn it's created. |
delete_skill | Remove permanently. |
enable_skill / disable_skill | Toggle without deleting. |
install_skill | Download and load from a URL. |
export_skill | Export as a Python file attachment. |
skill_status | Version, author, dependencies, config, execution stats. |
list_skills | List all user-created skills. |
Context API
The context parameter passed to execute() provides:
Command Execution
run_on_host(alias, cmd)→str— Run shell command via SSHread_file(host, path, lines=200, start_line=1, raw=False)→str— Read a contiguous file range; useraw=Truefor byte-faithful UTF-8 text in a length-framed metadata envelope
Tool Execution
execute_tool(name, input)→str— Call read-only tools (http_probe, search_knowledge, browser_read_page, etc.)
HTTP
http_get(url, headers={})→dict | str | byteshttp_post(url, json={}, headers={})→dict | str | bytes
Memory & Knowledge
remember(key, value)— Store persistent factrecall(key)→str | None— Retrieve factsearch_knowledge(query, limit=5)→list[dict]— Search knowledge baseingest_document(content, source)→int— Add to knowledge basesearch_history(query, limit=10)→list[dict]— Search conversation history
Scheduling
schedule_task(description, action, channel_id, **kwargs)→dictlist_schedules()→list[dict]update_schedule(id, **kwargs)/delete_schedule(id)
Discord
post_message(text)— Send to invoking channelpost_file(data, filename, caption="")— Post file attachment
Utility
get_hosts()→list[str]— Available host aliasesget_config(key, default=None)— Read skill config valueget_all_config()→dict— All config for this skilllog(msg)— Log to skill logger
Limits
| Limit | Value |
|---|---|
| Execution timeout | 120 seconds |
| Output truncation | 50,000 characters |
| Tool calls | 50 per execution |
| HTTP requests | 20 per execution |
| Messages sent | 10 per execution |
| Files sent | 10 per execution |
| Dependencies | 10 max per skill |
Safe Tools
Skills can only call these tools via execute_tool():
read_file, search_history, search_audit, search_knowledge, list_knowledge, list_schedules, list_skills, list_tasks, memory_manage, parse_time, web_search, fetch_url, http_probe, browser_screenshot, browser_read_page, browser_read_table
Destructive tools (run_command, apply_patch, etc.) are blocked. Use run_on_host() for shell access.
Blocked Paths
Skills cannot read these files via read_file:
.env*,config.yml,config.yaml/etc/shadow, SSH keys,.ssh/credentials.json,.kube/config
Dependencies
Skills can declare pip dependencies:
SKILL_DEFINITION = {
...
"dependencies": ["requests>=2.0", "beautifulsoup4"],
}Dependencies are auto-installed via pip on skill creation (120s timeout). Max 10 per skill.
Skill Config
Skills can declare a config schema for operator-tunable settings:
SKILL_DEFINITION = {
...
"config_schema": {
"type": "object",
"properties": {
"timeout_seconds": {
"type": "integer",
"default": 10,
"minimum": 1,
"maximum": 120
}
}
}
}Access via context.get_config("timeout_seconds", 10). Set via web UI or skill_status API.