Manifest
capability.yaml structure, every field, validation rules, and auto-discovery behavior.
A capability is a directory with a capability.yaml at the root. The manifest declares the capability’s identity and points at its components; everything else is convention-driven.
schema: 1name: threat-huntingversion: 0.1.0description: Triage and report on threat indicators.
agents: - agents/triage.mdtools: - tools/intel.pyskills: - skills/report/hooks: - hooks/observer.pymcp: servers: intel-server: command: node args: [mcp/intel.js]flags: verbose: description: Emit extra diagnostic output default: falseworkers: bridge: path: workers/bridge.pydependencies: python: [requests] scripts: [scripts/setup.sh]checks: - name: python-available command: python --versionUnknown top-level keys are ignored silently — useful for future-proofing, but a typo in an optional key won’t error.
Required fields
Section titled “Required fields”| Field | Type | Rule |
|---|---|---|
schema | integer | Must equal 1. Any other value is a validation error. |
name | string | Matches ^[a-z0-9][a-z0-9-]*$. Becomes the capability’s registry name. |
version | string | Semver X.Y.Z. Prereleases not accepted at publish time. |
description | string | Non-empty. Shown in the catalog and TUI. |
Directory layout
Section titled “Directory layout”The conventional layout mirrors the manifest sections:
threat-hunting/ capability.yaml agents/ # *.md files with frontmatter tools/ # *.py files exporting @tool functions skills/ # subdirectories with SKILL.md hooks/ # *.py files exporting @hook-decorated handlers workers/ # *.py files defining Worker instances mcp/ # scripts or configs for inline MCP servers scripts/ # setup scripts referenced by dependencies.scripts .mcp.json # optional file-based MCP server configNone of these directories is required. The loader only cares about what the manifest references or auto-discovers.
Auto-discovery
Section titled “Auto-discovery”Component fields follow three states:
| Value | Behavior |
|---|---|
| Omitted | Auto-discover from the conventional directory. |
| Explicit list | Load exactly what’s listed; skip auto-discovery. |
Empty [] | Disable the component type entirely. |
# Auto-discover agents/, tools/, skills/agents: # (omit entirely)tools: # (omit entirely)
# Load only these filesagents: - agents/triage.md - agents/responder.md
# Disable tools even if tools/ existstools: []| Field | Auto-discovery source | Entry type |
|---|---|---|
agents | agents/*.md | Path to markdown file |
tools | tools/*.py | Path to Python file |
skills | skills/*/SKILL.md | Path to skill directory |
hooks | hooks/*.py | Path to Python file |
policies | policies/*.py | Path to Python file |
mcp | .mcp.json or mcp.json | See mcp below |
workers | no auto-discovery | Named map — see workers |
Component sections
Section titled “Component sections”Each component has its own page covering behavior and authoring. The schema fields below define what you put under that key in capability.yaml.
| Section | Companion page |
|---|---|
agents | Agents |
tools | Tools |
skills | Skills |
hooks | Hooks |
policies | Policies |
mcp | MCP servers |
flags | Flags |
workers | Workers |
outputs | Agent Output |
dependencies, checks | Dependencies & checks |
produces and items are deprecated aliases for outputs. The loader warns when either alias appears. If outputs appears with an alias, outputs takes precedence and the declarations do not merge.
outputs
Section titled “outputs”outputs: [finding, asset, attack_surface]outputs selects platform contracts by identifier. A specialized identifier must already be active in the platform-managed registry; publishing the capability pins the approved immutable version and never creates a type. New registry versions do not move that pin. See Agent Output for the complete grammar, lifecycle, and discovery flow.
mcp: files: # list of .mcp.json / mcp.json files - .mcp.json servers: # inline server definitions <name>: command: string # stdio transport args: [string] env: { <key>: string } cwd: string url: string # streamable-http transport headers: { <key>: string } timeout: number # seconds init_timeout: number # seconds when: [string] # flag namesRules:
- Exactly one of
commandorurlper server. Both is an error, neither is an error. when:is valid on inline servers only. File-loaded servers cannot usewhen:.${CAPABILITY_ROOT}resolves at parse time.${VAR}and${VAR:-default}resolve at connect time.- On name conflicts between file and inline, inline wins.
flags: <name>: description: string # required, non-empty default: bool # optional, defaults to falseRules:
- Flag names match
^[a-z0-9]([a-z0-9-]*[a-z0-9])?$. - Max 16 flags per capability.
- Unknown fields on a flag entry are a validation error.
workers
Section titled “workers”workers: <name>: # in-process path: string # path to .py file relative to capability root # subprocess command: string args: [string] env: { <key>: string } # gating when: [string] # flag namesRules:
- Exactly one of
path:orcommand:. Both is a validation error. <name>matches^[a-z0-9][a-z0-9-]*$.- In-process:
pathmust point to a file exporting a module-levelWorkerinstance. - Subprocess:
commandis the executable;argsandenvare optional.
dependencies
Section titled “dependencies”dependencies: python: [string] # pip requirement strings packages: [string] # apt package names scripts: [string] # shell scripts, paths relative to capability rootSandbox-only. Local installs ignore this section.
checks
Section titled “checks”checks: - name: string command: stringRules:
- Runs at capability load time.
- 5-second timeout per check.
- Exit 0 = pass, non-zero = fail.
- Failed checks surface in the TUI capability manager but do not block load.
Catalog metadata
Section titled “Catalog metadata”Optional fields that affect the registry listing but nothing at runtime:
author: Security Teamlicense: MITrepository: https://github.com/acme/threat-huntingkeywords: [dfir, triage, indicators]| Field | Type | Notes |
|---|---|---|
author | string | Free-form attribution. |
license | string | SPDX identifier or free-form. |
repository | string | URL. |
keywords | [string] | Searchable tags. |
Validation
Section titled “Validation”Common errors:
namecontains invalid characters — must match^[a-z0-9][a-z0-9-]*$- Referenced path doesn’t exist (
agents/triage.mdmissing) - Flag name referenced in
when:not declared inflags: - Worker has both
path:andcommand:set (mutually exclusive) - File-loaded MCP server uses
when:(not allowed — inline only)
Validation errors name the offending field and the rule it broke.