How to Extend or Add New Skills to OpenMAIC: A Complete Developer Guide
To add a new skill to OpenMAIC, create a self-contained directory containing a SKILL.md file with YAML front-matter (defining name, description, and title) and an optional outline-constraints.json file, then place it in the skills/ directory or upload it via the POST /api/agent/skills API endpoint.
OpenMAIC treats skills as modular, file-based components that the system discovers automatically without requiring code changes. Whether you are contributing to the core repository or extending an instance with user-specific capabilities, the skill system leverages the Pi-native read tool to load instructional content on demand.
Understanding the OpenMAIC Skill Architecture
OpenMAIC skills are self-contained directories that the runtime discovers through two primary mechanisms: builtin skills (loaded from the skills/ folder at startup) and user-uploaded skills (stored in a virtual file system). According to the source code in lib/server/agent-runtime/skills.ts, the system initializes by calling loadSkills() to populate a builtinCache, then merges user skills from the virtual root /__openmaic_user_skills__ when sessions are created【skills.ts】.
When the Pi agent invokes a skill, it uses the native read tool to access the SKILL.md file. The lib/workbench/skill-load.ts module detects these read operations and renders a "load skill" card in the workbench interface, providing visual feedback that the skill context has been injected into the conversation【skill-load.ts】.
Adding a Built-in Skill to the Repository
Built-in skills reside in the skills/ directory and are automatically discovered when the server starts or hot-reloads. Follow these steps to create a new built-in skill:
1. Create the Skill Directory
Create a new directory under skills/agent-runtime/ (or any sub-path within skills/). The directory name becomes the skill's stable id used for invocation.
mkdir skills/agent-runtime/my-awesome-skill
No registration or import statements are required—the listBuiltinSkills() function recursively scans the skills/ tree to discover new directories automatically【skills.ts】.
2. Write the SKILL.md File
Each skill must contain a SKILL.md file with a YAML front-matter block followed by instructional content. The front-matter must include name, description, and optionally title and metadata.title for proper discovery by the readSkillTitle helper【skills.ts】.
---
name: "my-awesome-skill"
title: "My Awesome Skill"
description: "A demo skill that generates a simple two-scene outline."
---
# My Awesome Skill
You are a helpful assistant that should produce a two-scene outline:
1. An *introductory* scene.
2. A *conclusion* scene.
Use the format `Scene <n>: <title>` for each scene.
The body content after the front-matter provides the actual instructions the language model receives when the skill is loaded.
3. (Optional) Define Outline Constraints
For skills that generate structured outlines, you can add an outline-constraints.json file to enforce machine-checkable rules such as scene counts or allowed widget types. The JSON schema follows the OutlineConstraints TypeScript interface defined in lib/server/agent-runtime/skills.ts【skills.ts-L52】.
{
"sceneCount": { "min": 2, "max": 2 },
"allowedTypes": ["introductory", "conclusion"]
}
This file is optional but recommended for skills that require strict structural validation of generated content.
4. Invoke the Skill
Once committed and deployed, invoke the skill from the UI by typing /my-awesome-skill (using the directory name as the id) at the start of a chat message. This triggers the Pi read tool with the following arguments:
{
"toolCall": {
"name": "read",
"arguments": { "path": "/skills/agent-runtime/my-awesome-skill/SKILL.md" }
}
}
The createNativeSkillReadTool function locates the file, parses the skill metadata, and returns the instructional content to the model【skills.ts-L59】. The workbench then displays a "Skill loaded" card via the skillLoadId handler in skill-load.ts【skill-load.ts-L26】.
Uploading User Skills via the API
For runtime-extensible deployments, OpenMAIC supports uploading skills without modifying the repository. Send a POST request to /api/agent/skills with the SKILL.md file (or a ZIP archive containing it):
curl -X POST https://your-openmaic-instance/api/agent/skills \
-F "file=@SKILL.md" \
-H "Authorization: Bearer <your-access-token>"
The server validates the front-matter, stores the skill under /__openmaic_user_skills__/<uuid>/, and makes it available in the UI skill picker【route.ts】. User skills are discovered alongside built-in skills in the availableSkillsPromptBlock function, which generates the system prompt component listing all accessible capabilities【skills.ts-L76】.
Key Source Files for Skill Development
Understanding these implementation files helps troubleshoot and extend skill functionality:
lib/server/agent-runtime/skills.ts— Core loader implementingloadSkills(),listBuiltinSkills(), andcreateNativeSkillReadTool; handles caching inbuiltinCacheand virtual file resolution for user skills【skills.ts-L97】.lib/workbench/skill-load.ts— Client-side detector that recognizesreadoperations targetingSKILL.mdfiles and renders the skill-load timeline card【skill-load.ts-L26】.app/api/agent/skills/route.ts— HTTP handler for thePOST /api/agent/skillsendpoint that manages user skill uploads and validation【route.ts】.lib/server/agent-runtime/user-skills.ts— ContainslistUserSkills()for retrieving uploaded skills from the virtual file system【user-skills.ts】.
Summary
- Skill structure requires a directory containing
SKILL.mdwith YAML front-matter (name,description,title) and optionaloutline-constraints.json. - Built-in skills are automatically discovered when placed in the
skills/tree and scanned bylistBuiltinSkills()without code changes. - User skills can be uploaded via
POST /api/agent/skillsand stored in the virtual root/__openmaic_user_skills__for immediate availability. - Invocation occurs through the Pi-native
readtool accessing the skill path, with visual feedback handled byskill-load.ts. - Constraints can be enforced using
outline-constraints.jsonfollowing theOutlineConstraintsschema defined in the runtime.
Frequently Asked Questions
Can I add a skill without restarting the OpenMAIC server?
Yes, for user-uploaded skills. When you upload via the POST /api/agent/skills endpoint, the skill is immediately available in the virtual file system under /__openmaic_user_skills__ and appears in the skill picker for new sessions. Built-in skills require a server restart or hot-reload to be picked up by listBuiltinSkills().
What happens if my SKILL.md is missing required front-matter fields?
The skill discovery mechanism relies on the name, description, and title fields in the YAML front-matter to populate the skill picker and system prompt. If these are missing, the readSkillTitle function may fail to properly index the skill, causing it to be omitted from the availableSkillsPromptBlock and unavailable for invocation via the / command.
How does OpenMAIC distinguish between built-in and user-uploaded skills?
The system uses path prefixes. Built-in skills reside in physical directories under skills/ and are cached in builtinCache at startup. User skills are stored in the virtual file system under /__openmaic_user_skills__/<uuid>/ and merged into the skill list by createNativeSkillReadTool, which handles both paths transparently when processing read tool calls【skills.ts-L82】.
Can I constrain the output format when using a custom skill?
Yes, by including an outline-constraints.json file in your skill directory. This JSON file follows the OutlineConstraints interface and can specify requirements like sceneCount (min/max) and allowedTypes for widgets or scenes. The runtime uses these constraints to validate or guide the agent's output structure【skills.ts-L52】.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →