Skip to content

Use Skills Subsystem

Use this when you want agents to discover and activate skill packages at runtime, loading instructions, resources, and scripts on demand.

  • A working awaken agent runtime (see First Agent)
  • Feature skills enabled on the awaken crate
[dependencies]
awaken = { git = "https://github.com/AwakenWorks/awaken", features = ["skills"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"
  1. Create skill directories.

Each skill lives in a directory with a SKILL.md file containing YAML frontmatter:

skills/
my-skill/
SKILL.md
another-skill/
SKILL.md

Example skills/my-skill/SKILL.md:

---
name: my-skill
description: Helps with data analysis tasks
allowed-tools: read_file web_search
---
# My Skill
When this skill is active, focus on data analysis.
Use read_file to load datasets and web_search for reference material.
  1. Discover filesystem skills.
use std::sync::Arc;
use awaken::ext_skills::{FsSkill, InMemorySkillRegistry, SkillSubsystem};
let result = FsSkill::discover("./skills").expect("skill discovery failed");
for warning in &result.warnings {
eprintln!("skill warning: {warning:?}");
}
let skills = FsSkill::into_arc_skills(result.skills);
let registry = Arc::new(InMemorySkillRegistry::from_skills(skills));
  1. Use embedded skills (alternative).

    For compile-time embedded skills, use EmbeddedSkill:

use std::sync::Arc;
use awaken::ext_skills::{EmbeddedSkill, EmbeddedSkillData, InMemorySkillRegistry};
const SKILL_MD: &str = "\
---
name: builtin-skill
description: A compiled-in skill
allowed-tools: read_file
---
Follow these instructions when active.
";
let skill = EmbeddedSkill::new(&EmbeddedSkillData {
skill_md: SKILL_MD,
references: &[],
assets: &[],
}).expect("valid skill");
let registry = Arc::new(InMemorySkillRegistry::from_skills(vec![Arc::new(skill)]));
  1. Wire into the runtime.
use std::sync::Arc;
use awaken::engine::GenaiExecutor;
use awaken::ext_skills::SkillSubsystem;
use awaken::registry_spec::ModelSpec;
use awaken::registry_spec::AgentSpec;
use awaken::{AgentRuntimeBuilder, Plugin};
let subsystem = SkillSubsystem::new(registry);
let mut agent_spec = AgentSpec::new("skills-agent")
.with_model_id("gpt-4o-mini")
.with_system_prompt("Discover and activate skills when specialized help is useful.")
.with_hook_filter("skills-discovery")
.with_hook_filter("skills-active-instructions");
agent_spec.plugin_ids.extend([
"skills-discovery".into(),
"skills-active-instructions".into(),
]);
let runtime = AgentRuntimeBuilder::new()
.with_provider("openai", Arc::new(GenaiExecutor::new()))
.with_model(ModelSpec::new("gpt-4o-mini", "openai", "gpt-4o-mini"))
.with_agent_spec(agent_spec)
.with_plugin(
"skills-discovery",
Arc::new(subsystem.discovery_plugin()) as Arc<dyn Plugin>,
)
.with_plugin(
"skills-active-instructions",
Arc::new(subsystem.active_instructions_plugin()) as Arc<dyn Plugin>,
)
.build()
.expect("failed to build runtime");

plugin_ids loads both skill plugins. The hook filter keeps discovery and active instruction injection enabled for this agent.

The SkillDiscoveryPlugin injects a skills catalog into the LLM context before inference and registers three tools:

ToolPurpose
skillActivate a skill by name
load_skill_resourceLoad a skill resource or reference
skill_scriptRun a skill script

A skill is more than instructions — it can also scope which tools the agent sees while the skill is active. Declare allowed_tools in the SKILL.md frontmatter (or SkillSpec.allowed_tools when you build the spec programmatically):

---
name: refund-flow
description: Process customer refunds against the billing system
allowed-tools: billing_lookup issue_refund send_receipt
---

Note that allowed-tools (hyphenated) is a space-delimited string in the SKILL.md frontmatter — not a YAML list — matching the Claude Code skills convention. The runtime parses it into SkillSpec.allowed_tools: Vec<String>.

While refund-flow is active, the agent’s tool catalog is intersected with this list, even if its AgentSpec.tool_loading_policy would normally include more. This lets one agent host many task-shaped skills without leaking unrelated tools (e.g. shell access) into a sensitive flow. Tuning allowed_tools from the admin-console skill editor (or /v1/config/skills/:id) is the recommended way to harden a workflow without recompiling the runtime.

  1. Run the agent and ask it to list available skills.
  2. The LLM should see the skills catalog in its context and use the skill tool to activate one.
  3. After activation, the ActiveSkillInstructionsPlugin injects the skill instructions into subsequent inference calls.
SymptomCauseFix
No skills discoveredWrong directory pathEnsure each skill has a SKILL.md in a subdirectory
SkillMaterializeErrorInvalid YAML frontmatterCheck that name and description fields are present in SKILL.md
Skill tools not availablePlugin not registeredRegister both discovery_plugin() and active_instructions_plugin()
Feature not foundMissing cargo featureEnable features = ["skills"] in Cargo.toml
  • crates/awaken-ext-skills/tests/
PathPurpose
crates/awaken-ext-skills/src/lib.rsModule root and public re-exports
crates/awaken-ext-skills/src/registry.rsFsSkill, InMemorySkillRegistry, SkillRegistry trait
crates/awaken-ext-skills/src/plugin/subsystem.rsSkillSubsystem facade
crates/awaken-ext-skills/src/plugin/discovery.rsSkillDiscoveryPlugin
crates/awaken-ext-skills/src/embedded.rsEmbeddedSkill for compile-time skills
crates/awaken-ext-skills/src/tools.rsSkill tool implementations