Skills System
Understand how KRAIT skills are structured, validated, and tested as Elixir modules.
What Is a Skill?
A skill is an Elixir module that implements the Krait.Skill behaviour. Skills are the atomic unit of agent capability — each one handles a specific task like parsing a file format, calling an API, or transforming data. When KRAIT self-evolves, it produces new skill modules.
The Skill Behaviour
Every skill must implement three callbacks:
defmodule Krait.Skill do
@callback name() :: String.t()
@callback description() :: String.t()
@callback run(input :: map(), context :: Krait.Context.t()) ::
{:ok, result :: term()} | {:error, reason :: term()}
end
Here is a minimal skill that reverses a string:
defmodule MyAgent.Skills.ReverseString do
@behaviour Krait.Skill
@moduledoc "Reverses a given string."
@impl true
def name, do: "reverse_string"
@impl true
def description, do: "Reverses the characters in a string."
@impl true
def run(%{"text" => text}, _context) when is_binary(text) do
{:ok, String.reverse(text)}
end
def run(_input, _context) do
{:error, :invalid_input}
end
end
Validation Pipeline
Before any skill — whether hand-written or agent-generated — is loaded into the running system, it passes through the validation pipeline:
- Compilation check — The module must compile without warnings under
Mix.compile/1. - Behaviour conformance — All three callbacks must be implemented with correct arities.
- Narsil security scan — The module is scanned against the active rule set (see Configuration).
- Sandbox testing — Generated test cases are executed inside the Docker sandbox to verify the skill's
run/2returns expected results.
If any step fails, the skill is rejected with a structured error that the agent can use to iterate.
Writing Tests for Skills
KRAIT auto-generates tests during evolution, but you can also write them manually. Skill tests use standard ExUnit with a helper macro:
defmodule MyAgent.Skills.ReverseStringTest do
use Krait.SkillCase, skill: MyAgent.Skills.ReverseString
test "reverses a simple string" do
assert {:ok, "olleh"} = run_skill(%{"text" => "hello"})
end
test "returns error on invalid input" do
assert {:error, :invalid_input} = run_skill(%{"number" => 42})
end
end
The Krait.SkillCase macro provides run_skill/1, which constructs a test context and invokes the skill's run/2 callback.
Rust NIFs in Skills
For performance-critical skills, you can delegate to Rust NIFs. KRAIT includes a Krait.NIF helper that manages compilation and loading:
defmodule MyAgent.Skills.FastHash do
@behaviour Krait.Skill
use Krait.NIF, rust_module: "fast_hash"
@impl true
def name, do: "fast_hash"
@impl true
def description, do: "Computes a BLAKE3 hash using a Rust NIF."
@impl true
def run(%{"data" => data}, _context) do
{:ok, native_hash(data)}
end
end
The Rust source lives in native/fast_hash/src/lib.rs and is compiled automatically when the skill is loaded.
Next Steps
- Your First Evolution — see skills created through self-evolution
- Getting Started — set up the project from scratch