This document captures the canonical design of the tap registry. Read this before making any changes.
Agents declare capabilities, not MCP servers. This is mandatory. There is no other way.
Old (forbidden):
[roles.mcp]
server_refs = ["core", "octofs", "octocode"]
allowed_tools = ["core:*", "octofs:*", "octocode:*"]New (the only way):
capabilities = ["core", "filesystem", "codesearch"]bin/load <domain>:<spec> resolves capabilities at runtime and injects the full [roles.mcp] block automatically. Never write [roles.mcp] by hand in any manifest.
A capability is something an agent can do, achievable by different tools (providers). Agents declare capabilities; the runtime resolves providers and injects dependencies.
Each capability name maps to capabilities/<name>/default.toml (a symlink to the active provider).
Users can override providers via [capabilities] in their config (e.g. websearch = "brave").
Use prefix naming to group related capabilities: programming-python, programming-rust, etc.
agents/developer/rust.toml
└── capabilities = ["core", "filesystem", "codesearch", "programming-rust"]
│
▼
bin/load developer:rust
│
├── capabilities/core/default.toml (built-in)
├── capabilities/filesystem/default.toml → octofs.toml
├── capabilities/codesearch/default.toml → octocode.toml
└── capabilities/programming-rust/default.toml → cargo.toml
│
▼
Merged manifest with [deps], [roles.mcp], [[mcp.servers]] injected
Each capabilities/<name>/default.toml is either:
- A real file (built-ins:
core,agent) — no symlink needed - A symlink pointing to the active provider (e.g.
default.toml → tavily.toml)
Symlinks are managed by scripts/setup-symlinks.sh which always force-creates them (ln -sf).
| Capability | Providers | What it provides |
|---|---|---|
core |
default | plan task tracker |
agent |
default | agent_* delegation tools |
filesystem |
octofs | view, shell, text_editor, workdir |
codesearch |
octocode | semantic_search, structural_search, graphrag, view_signatures |
memory |
octobrain | remember, memorize |
websearch |
tavily | web search and content extraction |
versioning |
git | git operations |
programming-python |
uv | Python runtime (uv, uvx) |
programming-rust |
cargo | Rust toolchain (cargo, rustc, clippy, rustfmt) |
programming-nodejs |
node | Node.js runtime (node, npm, npx) |
docker |
docker | Docker CLI (docker, docker-compose) |
kubernetes |
kubernetes | Kubernetes CLI (kubectl, helm) |
svelte |
svelte | Svelte/SvelteKit documentation MCP server |
medical |
medical | medical references (PubMed, FDA, WHO, RxNorm) |
finance |
yfinance | financial data (Yahoo Finance) |
# capabilities/<name>/<provider>.toml
# Capability: <name>
# Provider: <provider-name>
# Title: <Short Capability Title (5–60 chars)>
# Description: <What this capability provides (20–160 chars)>
[deps]
require = ["muvon/octocode"]
[roles.mcp]
server_refs = ["octocode"]
allowed_tools = ["octocode:*"]
# Optional: [[mcp.servers]] if the provider needs a custom MCP server
[[mcp.servers]]
name = "octocode"
type = "stdio"
command = "octocode"
args = ["mcp"]capabilities = [...]is mandatory — every manifest must have it at the top level.- Never write
[roles.mcp]in an agent — injected bybin/loadfrom capabilities. - Never write
[deps]in an agent — deps belong in capability files only. - Never write
[[mcp.servers]]in an agent — MCP servers belong in capability files. - Never set
namein[[roles]]— injected from the tag at runtime. - One
[[roles]]per file — no multi-role manifests. - File path must match tag —
developer:rust→agents/developer/rust.toml.
# Switch websearch from Tavily to Brave
ln -sf brave.toml capabilities/websearch/default.toml
# Reset all defaults
bash scripts/setup-symlinks.shsetup-symlinks.sh behavior:
- Always force-creates symlinks (
ln -sf) — never skips - Reports
MISSING+ exits 1 if a provider.tomlfile doesn't exist - Reports
WARNfor capability dirs with no mapping declared in the script
- Create
capabilities/<name>/<provider>.tomlwith[deps],[roles.mcp], optional[[mcp.servers]] - Add a
link "<name>" "<provider>.toml"line toscripts/setup-symlinks.sh - Run
bash scripts/setup-symlinks.shto create the default symlink - Use
"<name>"(default provider) or"<name>:<provider>"(explicit) in any agent
To add an alternative provider to an existing capability:
- Create
capabilities/<name>/<new-provider>.toml - Use
"<name>:<new-provider>"in agents that need it
bin/load <domain>:<spec> (Python 3, no external deps):
- Reads
agents/<domain>/<spec>.toml - Extracts
capabilities = [...] - For each capability reference, resolves provider:
"name"→capabilities/<name>/default.toml"name:provider"→capabilities/<name>/<provider>.toml
- Merges:
[deps].require,server_refs,allowed_tools,[[mcp.servers]](deduplicated by name) - Strips
capabilities =line from agent file - Injects merged
[roles.mcp](creates section if absent) - Outputs final TOML to stdout
Skills are reusable instruction packs stored alongside agents in the tap. They follow the AgentSkills specification.
skills/
<skill-name>/
SKILL.md # Required: YAML frontmatter + instruction body
scripts/ # Optional: executable scripts the skill references
references/ # Optional: supplementary docs (REFERENCE.md, etc.)
assets/ # Optional: templates, config files, resources
| Field | Required | Constraints |
|---|---|---|
name |
✅ | Max 64 chars. Lowercase letters, numbers, hyphens. No leading/trailing hyphen. Must match directory name. |
title |
✅ | 5–60 chars. Short human-readable label for the skill. |
description |
✅ | 20–1024 chars. What the skill does and when to use it. |
license |
optional | License name or path to bundled license file. |
compatibility |
optional | Max 500 chars. Environment requirements (tools, OS, network). |
metadata |
optional | Arbitrary key-value mapping (author, version, tags). |
allowed-tools |
optional | Space-delimited pre-approved tools (experimental). |
- The
skillMCP tool (built into Octomind core) scans all active taps forskills/*/SKILL.md skill(action="list")returns all discovered skills with their metadataskill(action="use", name="<name>")reads the fullSKILL.mdand injects it into the session contextskill(action="forget", name="<name>")removes the skill and triggers conversation compression
Skills are not loaded automatically — the AI must explicitly activate them. This keeps context lean.
# Lint all skills
bash scripts/lint-skills.sh
# Lint a specific skill
bash scripts/lint-skills.sh skills/git-workflowThe lint script validates:
- Valid YAML frontmatter (delimited by
---) - Required fields:
name,title,description nameformat and length constraintsnamematches directory nametitlelength (5–60 chars)descriptionlength (20–1024 chars) andcompatibilitylength limits- Non-empty body after frontmatter
Skills and agents serve different purposes:
| Skill | Agent | |
|---|---|---|
| File | skills/<name>/SKILL.md |
agents/<domain>/<spec>.toml |
| Activation | skill(action="use", name="...") |
octomind run domain:spec |
| What it provides | Domain knowledge injected into context | Full role: model, tools, system prompt |
| Composable | Yes — multiple skills per session | No — one role per session |
# Lint all manifests (TOML validity, required fields, title/description, no name= set)
bash scripts/lint-manifests.sh
# Lint all capabilities (TOML validity, title/description, MCP server description)
bash scripts/lint-capabilities.sh
# Lint all skills (frontmatter validity, required fields incl. title)
bash scripts/lint-skills.sh
# Validate capability resolution for all agents
bash scripts/validate-capabilities.sh
# All four run in .github/workflows/lint.yml on every push/PRThe lint script skips the server_refs cross-check for capability-driven agents (those with capabilities = at top level), since MCP wiring is resolved at runtime.
All agents and capabilities require # Title: and # Description: comment lines:
| Entity | Field | Constraints |
|---|---|---|
| Agent | # Title: |
5–60 chars. Short human-readable label. |
| Agent | # Description: |
20–160 chars. What the agent does. |
| Capability | # Title: |
5–60 chars. Short capability label. |
| Capability | # Description: |
20–160 chars. What the capability provides. |
# agents/<domain>/<spec>.toml
# Agent: <domain>:<spec>
# Title: Short Agent Title
# Description: One-line description of what this agent does.
capabilities = ["core", "filesystem", "programming-python"] # REQUIRED
[[roles]]
system = """
You are a <persona> assistant.
Working directory: {{CWD}}
"""
welcome = "🔧 <Short greeting>. Working in {{CWD}}"
temperature = 0.3
top_p = 0.9
top_k = 0
# Optional: model override
# model = "openrouter:anthropic/claude-sonnet-4"