Nous.Skill behaviour (nous v0.13.3)

View Source

Reusable instruction/capability packages for agents.

Skills inject domain knowledge, tools, and prompt fragments into an agent's context. They can be defined as Elixir modules, markdown files, or inline structs.

Skill Groups

Built-in categories for organizing skills:

GroupPurpose
:codingCode generation, implementation, refactoring
:reviewCode quality, security scanning
:testingTest creation and validation
:debugBug finding and systematic debugging
:gitVersion control operations
:docsDocumentation generation
:planningArchitecture and task decomposition

Activation Modes

  • :manual — only activated explicitly by name
  • :auto — activated at agent init, always on
  • {:on_match, fn} — activated when user input matches predicate
  • {:on_tag, tags} — activated when agent has matching tags
  • {:on_glob, patterns} — activated when working with matching file patterns

Module-Based Skills

defmodule MyApp.Skills.CodeReview do
  use Nous.Skill, tags: [:code, :quality], group: :review

  @impl true
  def name, do: "code_review"

  @impl true
  def description, do: "Reviews code for bugs, style, and quality"

  @impl true
  def instructions(_agent, _ctx) do
    "You are a code review specialist..."
  end

  @impl true
  def match?(input), do: String.contains?(input, "review")
end

File-Based Skills

Markdown files with YAML frontmatter in a skills directory:

---
name: code_review
description: Reviews code for quality and bugs
tags: [code, review]
group: review
activation: auto
---

You are a code review specialist...

Usage

agent = Agent.new("openai:gpt-4",
  skills: [
    MyApp.Skills.CodeReview,        # module
    "priv/skills/",                 # directory
    {:group, :testing}              # built-in group
  ]
)

Summary

Callbacks

Called to return the skill description (used for matching).

Return the skill group (:coding, :review, :testing, etc.).

Called to return the skill instructions injected into the system prompt.

Check if this skill should activate for the given user input.

Called to return the skill name.

Return tags for categorization and filtering.

Called to return tools provided by this skill.

Functions

Build a Skill.t() struct from a module implementing the Nous.Skill behaviour.

Types

activation()

@type activation() ::
  :manual
  | :auto
  | {:on_match, (String.t() -> boolean())}
  | {:on_tag, [atom()]}
  | {:on_glob, [String.t()]}

scope()

@type scope() :: :builtin | :project | :personal | :plugin

status()

@type status() :: :discovered | :loaded | :active | :inactive

t()

@type t() :: %Nous.Skill{
  activation: activation(),
  allowed_tools: [String.t()] | nil,
  description: String.t(),
  group: atom() | nil,
  instructions: String.t() | nil,
  model_override: String.t() | nil,
  name: String.t(),
  priority: integer(),
  scope: scope(),
  source: :module | :file | :inline,
  source_ref: module() | String.t() | nil,
  status: status(),
  tags: [atom()],
  tools: [Nous.Tool.t()]
}

Callbacks

description()

@callback description() :: String.t()

Called to return the skill description (used for matching).

group()

(optional)
@callback group() :: atom() | nil

Return the skill group (:coding, :review, :testing, etc.).

instructions(agent, ctx)

@callback instructions(agent :: Nous.Agent.t(), ctx :: Nous.Agent.Context.t()) ::
  String.t()

Called to return the skill instructions injected into the system prompt.

match?(input)

(optional)
@callback match?(input :: String.t()) :: boolean()

Check if this skill should activate for the given user input.

name()

@callback name() :: String.t()

Called to return the skill name.

tags()

(optional)
@callback tags() :: [atom()]

Return tags for categorization and filtering.

tools(agent, ctx)

(optional)
@callback tools(agent :: Nous.Agent.t(), ctx :: Nous.Agent.Context.t()) :: [Nous.Tool.t()]

Called to return tools provided by this skill.

Functions

from_module(module)

@spec from_module(module()) :: t()

Build a Skill.t() struct from a module implementing the Nous.Skill behaviour.