Skip to content

Skills Reference

Skills declare specialist AI roles that participate in pipeline runs. Each skill is a directory under the configured skills root with two files:

  • SKILL.md — frontmatter (declarative metadata) + body (per-role prompts).
  • agentsmith.mdoptional, discussion-pipeline-only fields (display name, emoji, triggers, convergence criteria). The legacy ## orchestration section is no longer read.

SKILL.md frontmatter is the single source of truth for orchestration metadata as of phase p0111. See migration guide for before/after.

Directory layout

<skills-root>/
├── _index/                       # auto-generated, gitignored
│   ├── coding.yaml
│   └── security.yaml
├── concept-vocabulary.yaml       # operator-extensible vocabulary
├── coding/                       # used by fix-bug, add-feature
│   ├── architect/
│   │   ├── SKILL.md
│   │   └── references/...
│   └── tester/
├── security/                     # used by security-scan
├── api-security/                 # used by api-security-scan
├── legal/                        # discussion pipeline
└── mad/                          # discussion pipeline

Categories coding/ and security/ are strict modeSKILL.md files lacking roles_supported are rejected at boot with a migration hint. legal/ and mad/ are exempt; they default to roles_supported=[Analyst].

SKILL.md frontmatter

Full schema:

---
name: architect                  # unique within the skills root
display_name: Architect
emoji: 🏛️
description: System architect who plans architectural changes.

roles_supported: [lead, analyst, reviewer]   # which SkillRoles triage may assign

activation:                       # whether the skill participates at all
  positive:
    - { key: <vocab-key>, desc: "Why this key activates the skill." }
  negative:
    - { key: <vocab-key>, desc: "Why this key suppresses the skill." }

role_assignment:                  # per-role activation
  lead:
    positive:
      - { key: <vocab-key>, desc: "Why this skill leads in this case." }
    negative:
      - { key: <vocab-key>, desc: "Why this skill should not lead." }
  analyst:
    positive: [...]
  reviewer:
    positive: [...]

references:                       # citable from body via {{ref:<id>}}
  - { id: solid, path: "references/solid.md" }

output_contract:
  schema_ref: skill-observation.schema.json
  hard_limits:
    max_observations: 8
    max_chars_per_field: 500
  output_type:                    # per-role expected output shape
    lead: plan
    analyst: list
    reviewer: list
    filter: list                  # or "artifact"
---

activation and role_assignment keys must exist in the project's concept vocabulary. ConceptVocabularyValidator warns at boot for unknown keys (it does not fail).

Body — per-role sections

The body splits into ## as_<role> sections:

## as_lead

Instructions for when this skill is assigned the Lead role.

## as_analyst

Instructions for the Analyst role.

## as_reviewer

Compare the implementation against the plan: {{plan}}.

Cite references with {{ref:solid}}.

## as_filter

Instructions for the Filter role (output: list = reduce; artifact = synthesize).

Skills without per-role sections fall back to the whole body for any assigned role — used by legacy skills under legal/ and mad/.

The body is lazily resolved by SkillBodyResolver:

  • The ## as_<role> section matching the assigned role is selected (or the full body if none).
  • {{ref:<id>}} placeholders are inlined from the file at the matching references[].path.
  • {{plan}} (in ## as_reviewer sections) is substituted with the run's PlanArtifact. Reviewers without a same-run lead see (no plan provided).

The resolver caches per (skill, role) for the process lifetime; references are read once.

Output contract

output_contract.output_type[<role>] declares what the LLM is expected to return for that role:

Value Returned shape
list JSON array of SkillObservation objects.
plan Single structured plan object that reviewers compare against (Lead's typical output).
artifact Free-form text (Filter mode for synthesis, e.g. final security report).

hard_limits.max_observations caps how many observations the LLM may emit. max_chars_per_field caps each string field. Both are enforced by parsers downstream.

Per-provider overrides

Optional SKILL.<provider>.md files in a skill directory replace the base SKILL.md when the active provider matches. The active provider is read from primary_provider: at the root of agentsmith.yml; when unset (the default) the base SKILL.md always wins.

<skills-root>/coding/architect/
├── SKILL.md            # base — used unless an override matches
├── SKILL.openai.md     # used when primary_provider: openai
├── SKILL.claude.md     # used when primary_provider: claude
└── references/

File-naming convention

SKILL.<provider>.md where <provider> matches one of: claude, openai, azure-openai, gemini, ollama. Matching is exact; an openai override is ignored when primary_provider: claude.

Frontmatter merge rules

Top-level frontmatter keys merge shallowly between override and base:

  • A key declared in the override replaces base's value entirely (no deep merge inside activation.positive[], role_assignment[role].*, etc. — the operator manages a complete declaration when overriding a key).
  • A key omitted from the override inherits base's value as-is.
  • The body is taken from the override's file (after splitting on ## as_<role> headers).

name and roles_supported are special: the override must declare both, and they must match base exactly. Mismatched name or roles_supported is rejected at boot with a clear error — sibling skills with different identities should be different skill directories, not overrides of the same one.

Active-provider configuration

# agentsmith.yml
primary_provider: openai

projects:
  agent-smith:
    agent:
      type: openai
      model: gpt-4.1
      ...

Multi-provider deployments where, say, Planning uses Claude and Coding uses OpenAI use the single primary_provider for skill resolution — skill content is shared across the run, not partitioned by task. Operators with strong per-task tuning needs can author finer-grained config in a follow-up.

Boot-time logging

When an override loads, the framework logs at INFO level: Provider override loaded for skill 'architect' from .../SKILL.openai.md. Default behavior (no override matched, or no primary_provider set) is silent.

Zero overrides ship by default

The mechanism is the deliverable. No SKILL.<provider>.md files ship in the agent-smith-skills catalog. Provider-tuning is opt-in per skill, opt-in per operator — author the override locally, version it alongside the base in your project's skills directory, and set primary_provider to activate it.

Index files

SkillIndexBuilder writes a compact projection of each category's loaded skills to <skills-root>/_index/<category>.yaml at boot. The index is what the triage step reads; the LLM never sees the full body content of unassigned skills.

Read-only filesystems trigger a warning, not a crash — the index is best-effort cache, and the framework falls back to in-memory aggregation per process when writes fail. Operators who mount skills read-only can set SkillsConfig.IndexPath to a writable location.