1. Skill folder structure
~/.local/share/agent-code/skills/
└── hello_world/
├── skill.py
└── skill.mdFor compatibility with the project-local migration, legacy skills may also be found in a project's skills/ folder. The current global user location is preferred.
2. Required Python exports
The loader imports skill.py and reads these exports:
SKILL: metadata dictionary (at least a name and description are recommended).TOOL_SCHEMAS: list of OpenAI-compatible function tool schemas.TOOL_CALLABLES: mapping from each schema function name to a Python callable.COMMANDS: optional slash/natural-command mapping.HELP: optional help text fallback.
3. Minimal working example
"""A tiny Agent Code skill."""
SKILL = {
"name": "hello_world",
"description": "Returns a friendly greeting.",
}
def greet(name: str = "there") -> str:
return f"Hello, {name}!"
TOOL_SCHEMAS = [{
"type": "function",
"function": {
"name": "hello_world_greet",
"description": "Greet a person by name.",
"parameters": {
"type": "object",
"properties": {
"name": {"type": "string", "description": "Name to greet"}
},
"required": [],
},
},
}]
TOOL_CALLABLES = {
"hello_world_greet": greet,
}
4. Schema and callable rules
- Every
function.namemust exactly match a key inTOOL_CALLABLES. - Use unique tool names across all enabled Skills and Add-ons.
- Use JSON Schema types supported by your provider (string, number, integer, boolean, object, array).
- Validate arguments inside the Python function too; model-provided JSON is untrusted input.
- Return concise, useful text or JSON-serializable values.
- Catch expected errors and return a helpful error message rather than crashing the loader.
5. Optional commands
def configure(args, log):
# args is a list of words after the command.
log("Configuration command received", "dim")
COMMANDS = {
"configure": {
"handler": configure,
"description": "Configure this skill",
"aliases": ["hello configure"],
}
}A slash command is invoked as /configure if its name is not already reserved by another command. Natural aliases are dispatched only when the phrase matches the registered alias; they are not sent to the shell. Use clear, non-conflicting command names. Add-on commands are separately namespaced (for example /addon-name:status).
6. Optional skill.md metadata and help
---
name: hello_world
description: A sample greeting skill
version: 1.0.0
author: Your Name
---
# Hello World
Use this skill to greet a person by name.The text after the YAML-like frontmatter is shown as the skill's help page. The current loader parses simple key/value frontmatter; do not rely on advanced YAML features.
7. Test locally
- Create the skill folder in the user Skills directory.
- Run
python -m py_compile skill.pyfrom that folder. - Run
agent-code skills listto see bundled skills (this command does not list every installed custom skill). - Launch Agent Code and use the Skills interface to enable/reload it.
- Use
/skillsin chat to inspect loaded skills and commands. - Ask the agent to use the tool for a small harmless task.
8. Package and share a Skill
cd ~/.local/share/agent-code/skills
zip -r hello_world-1.0.0.zip hello_world \
-x '*/__pycache__/*' '*.pyc'Include only the skill folder, documentation and required assets. Document external dependencies and installation steps. Do not include API keys, tokens, personal data, virtual environments or caches.
9. Security and runtime
- Never use
evalorexecon model-supplied strings. - Validate file paths and restrict operations to the intended workspace.
- Keep secrets in the OS credential store or user configuration, not in the skill source.
- Use network timeouts and bounded retries.
- Explain what data is sent to external services.
- Review dependencies and pin versions where practical.
10. Current contract boundaries
Native Skills support SKILL, TOOL_SCHEMAS, TOOL_CALLABLES, optional COMMANDS, and optional HELP. This guide documents the loader contract implemented in this release; it does not promise an automatic dependency installer or per-Skill Local/Sandbox/SSH routing.