Skip to content

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: 1
name: threat-hunting
version: 0.1.0
description: Triage and report on threat indicators.
agents:
- agents/triage.md
tools:
- tools/intel.py
commands:
- name: nmap_scan
description: Scan one target with nmap
input_schema:
type: object
properties:
target: { type: string }
required: [target]
additionalProperties: false
executable: nmap
version_probe: [--version]
expected_version: 'Nmap version 7.95'
argv: [-sV, '{target}']
timeout_seconds: 120
working_directory: workspace
adapter_version: 1.0.0
skills:
- skills/report/
hooks:
- hooks/observer.py
mcp:
servers:
intel-server:
command: node
args: [mcp/intel.js]
flags:
verbose:
description: Emit extra diagnostic output
default: false
workers:
bridge:
path: workers/bridge.py
dependencies:
python: [requests]
scripts: [scripts/setup.sh]
checks:
- name: python-available
command: python --version

Unknown top-level keys are ignored silently — useful for future-proofing, but a typo in an optional key won’t error.

FieldTypeRule
schemaintegerMust equal 1. Any other value is a validation error.
namestringMatches ^[a-z0-9][a-z0-9-]*$. Becomes the capability’s registry name.
versionstringSemver X.Y.Z. Prereleases not accepted at publish time.
descriptionstringNon-empty. Shown in the catalog and TUI.

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 config

None of these directories is required. The loader only cares about what the manifest references or auto-discovers.

Component fields follow three states:

ValueBehavior
OmittedAuto-discover from the conventional directory.
Explicit listLoad 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 files
agents:
- agents/triage.md
- agents/responder.md
# Disable tools even if tools/ exists
tools: []
FieldAuto-discovery sourceEntry type
agentsagents/*.mdPath to markdown file
toolstools/*.pyPath to Python file
commandsno auto-discoveryExplicit command wrapper object
skillsskills/*/SKILL.mdPath to skill directory
hookshooks/*.pyPath to Python file
policiespolicies/*.pyPath to Python file
mcp.mcp.json or mcp.jsonSee mcp below
workersno auto-discoveryNamed map — see workers

Each component has its own page covering behavior and authoring. The schema fields below define what you put under that key in capability.yaml.

SectionCompanion page
agentsAgents
toolsTools
commandsTools
skillsSkills
hooksHooks
policiesPolicies
mcpMCP servers
flagsFlags
workersWorkers
outputsAgent Output
dependencies, checksDependencies & 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.

commands:
- name: nmap_scan
description: Scan one target with nmap
input_schema:
type: object
properties:
target: { type: string }
required: [target]
additionalProperties: false
executable: nmap
version_probe: [--version]
expected_version: 'Nmap version 7.95'
argv: [-sV, '{target}']
timeout_seconds: 120
working_directory: workspace
adapter_version: 1.0.0

Rules:

  • Command wrappers are explicit. Dreadnode never scans $PATH or parses commands passed to a broad execution tool.
  • name uses lowercase snake case and must be unique within the capability.
  • input_schema must be valid JSON Schema with an object root.
  • executable is one executable path or name. Shell strings and shell executables are rejected.
  • version_probe and argv are non-empty argument arrays. They are not shell command strings.
  • expected_version is the exact trimmed stdout required from the version probe.
  • timeout_seconds is greater than 0 and no more than 3600 seconds. working_directory is workspace or capability.
  • adapter_version is fixed semver, such as 1.0.0.
  • Validation and OCI packaging do not execute the command or version probe.
  • The native runtime re-runs the version probe before exposing the tool and before every call. Missing or changed executables remain unavailable.
  • Changing a wrapper requires a new capability version. Republishing changed content under the same version fails.
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 names

Rules:

  • Exactly one of command or url per server. Both is an error, neither is an error.
  • when: is valid on inline servers only. File-loaded servers cannot use when:.
  • ${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 false

Rules:

  • 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:
<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 names

Rules:

  • Exactly one of path: or command:. Both is a validation error.
  • <name> matches ^[a-z0-9][a-z0-9-]*$.
  • In-process: path must point to a file exporting a module-level Worker instance.
  • Subprocess: command is the executable; args and env are optional.
dependencies:
python: [string] # pip requirement strings
packages: [string] # apt package names
scripts: [string] # shell scripts, paths relative to capability root

Sandbox-only. Local installs ignore this section.

checks:
- name: string
command: string

Rules:

  • 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.

Optional fields that affect the registry listing but nothing at runtime:

author: Security Team
license: MIT
repository: https://github.com/acme/threat-hunting
keywords: [dfir, triage, indicators]
FieldTypeNotes
authorstringFree-form attribution.
licensestringSPDX identifier or free-form.
repositorystringURL.
keywords[string]Searchable tags.

Common errors:

  • name contains invalid characters — must match ^[a-z0-9][a-z0-9-]*$
  • Referenced path doesn’t exist (agents/triage.md missing)
  • Flag name referenced in when: not declared in flags:
  • Worker has both path: and command: set (mutually exclusive)
  • File-loaded MCP server uses when: (not allowed — inline only)
  • Command wrapper uses a shell string or omits required adapter metadata

Validation errors name the offending field and the rule it broke.