Creating Capabilities
This guide walks you through creating a new capability from scratch, including all the files you might need and best practices for structuring your capability.
Subagents are optional. When you add them, prefer subagents/<name>/agent.toml plus subagents/<name>/prompt.md.
Quick start with capability new
Section titled “Quick start with capability new”The fastest way to create a capability is with the CLI:
omnidev capability new my-capabilityThe capability ID must be lowercase kebab-case (e.g., my-capability, api-client, tasks).
Output location
Section titled “Output location”By default, capabilities are created at capabilities/<id>. You can specify a custom path:
omnidev capability new my-cap --path ./custom/locationGenerated files
Section titled “Generated files”capabilities/my-capability/├── capability.toml # Capability metadata├── skills/│ └── getting-started/│ └── SKILL.md # Skill template├── rules/│ └── coding-standards.md # Rule template└── hooks/ ├── hooks.toml # Hook configuration └── example-hook.sh # Example hook scriptDelete any files you don’t need after creation.
Example output
Section titled “Example output”omnidev capability new api-client✓ Created capability: Api Client Location: capabilities/api-client
Files created: - capability.toml - skills/getting-started/SKILL.md - rules/coding-standards.md - hooks/hooks.toml - hooks/example-hook.sh
💡 To add this capability as a local source, run: omnidev add cap --local ./capabilities/api-clientWorkflow: Creating and using local capabilities
Section titled “Workflow: Creating and using local capabilities”-
Create a new capability:
Terminal window omnidev capability new my-cap -
Add it as a local source:
Terminal window omnidev add cap --local ./capabilities/my-cap -
The capability is now tracked in
omni.tomland synced to your agents.
Manual setup
Section titled “Manual setup”If you prefer to create capabilities manually, here’s what you need.
Required: capability.toml
Section titled “Required: capability.toml”Every capability needs a capability.toml file at its root:
[capability]id = "my-capability"name = "My Capability"version = "1.0.0"description = "A short description of what this capability does."Field notes:
- id: unique, kebab-case identifier. Avoid reserved names like
fs,path,react, ortypescript. - name: human-readable title.
- version: semantic version string.
- description: short summary shown in listings.
Optional: Programmatic exports (index.ts)
Section titled “Optional: Programmatic exports (index.ts)”For dynamic content, create an index.ts file:
import type { CapabilityExport } from "@omnidev-ai/core";
export default { cliCommands: { /* routes */ }, docs: [/* DocExport */], rules: [/* markdown strings */], skills: [/* SkillExport */], subagents: [/* SubagentExport */], gitignore: ["mycap/"], sync: async () => { /* setup */ }} satisfies CapabilityExport;JavaScript with JSDoc
Section titled “JavaScript with JSDoc”If you prefer JavaScript:
/** * @type {import("@omnidev-ai/core").CapabilityExport} */export default { gitignore: ["mycap/"]};TypeScript types
Section titled “TypeScript types”OmniDev exports types from @omnidev-ai/core for type-checking your capabilities:
import type { CapabilityExport, SkillExport, DocExport, FileContent} from "@omnidev-ai/core";Best practices
Section titled “Best practices”Naming
Section titled “Naming”- Use kebab-case for capability IDs (
my-capability). - Use lowercase command names (
deploy,status). - Avoid reserved names like
fs,path,react,typescript.
Structure
Section titled “Structure”- Keep CLI routes in
cli.tsand export them fromindex.ts. - Group related rules/docs/skills into focused subfolders.
- Use sync hooks sparingly and keep them idempotent.
Static vs programmatic
Section titled “Static vs programmatic”- Prefer static files for stable content.
- Use programmatic exports for dynamic or generated content.
- When both are used, ensure output is deterministic.
Capability-local .env
Section titled “Capability-local .env”Capabilities can include a gitignored .env next to capability.toml for local interpolation:
- MCP config resolves
${VAR}placeholders from that.env - skill content resolves
{OMNIDEV_VAR}placeholders from the same.env - shell environment variables override
.env
Example:
PROJECT_NAME=omnidev---name: plan-{OMNIDEV_PROJECT_NAME}description: Planning for {OMNIDEV_PROJECT_NAME}---Gitignore patterns
Section titled “Gitignore patterns”Add patterns via programmatic export so OmniDev can manage them:
export default { gitignore: ["mycap/", "*.mycap.log"]} satisfies CapabilityExport;Sync hooks
Section titled “Sync hooks”Use a sync hook for one-time setup (create directories, seed config). Keep it safe to run multiple times.
export default { sync: async () => { // create folders, write defaults, etc. }} satisfies CapabilityExport;Testing your capability
Section titled “Testing your capability”omnidev capability enable my-capabilityomnidev syncomnidev mycap --help # if you added CLI commandsPublishing your capability
Section titled “Publishing your capability”Once your capability is ready, you can share it by:
- Pushing to GitHub: Others can reference it with
github:user/repo - Sharing the directory: For local team use via
file://sources
See Capability Sources for how others can add your capability.