What Is the Purpose of the skills.rs File in the LLM Wiki Agent?

The skills.rs file implements the skill-management subsystem that discovers, validates, loads, and exposes user-defined Markdown-based instruction bundles to the LLM Wiki agent runtime.

In the nashsu/llm_wiki repository, the skills.rs module located at src-tauri/src/agent/skills.rs serves as the core gateway between the file system and the agent runtime. It abstracts all file-system interactions to ensure only safe, well-formed skills are presented to the LLM while providing the front-end with a simple command to enumerate available capabilities.

Core Responsibilities of the skills.rs Module

The module manages the complete lifecycle of agent skills, from filesystem discovery to runtime injection into prompts.

Defining Skill Data Structures

At the heart of the system are two primary structs defined at lines 10-18. AgentSkill represents the heavyweight runtime format containing full instructions and metadata, while AvailableAgentSkill provides a lightweight metadata view intended for UI presentation.

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentSkill { 
    // Contains name, description, instructions, and file-system metadata
}

Discovering Skill Locations

The skill_roots function (lines 79-99) builds a prioritized list of directories to scan. It first checks for a local .llm-wiki/skills directory within the project path, then falls back to user-level skill folders located under the home directory, establishing the complete search path for subsequent discovery.

Scanning Directories Safely

discover_skill_candidates (lines 51-84) recursively walks the discovered roots up to MAX_SKILL_SCAN_DEPTH. It collects Markdown files matching either SKILL.md or {skill_name}.md patterns while explicitly ignoring hidden directories and skipping symlinked paths to prevent directory traversal attacks.

Validating Skill Identifiers

Security enforcement occurs through normalize_skill_name and is_portable_skill_name (lines 101-112). These functions enforce a strict whitelist of safe characters, reject Windows reserved names like CON or NUL, and block path traversal sequences (e.g., ../), ensuring skill identifiers remain portable and safe across operating systems.

Loading and Parsing Individual Skills

The load_one_skill function (lines 28-44) implements a three-tier resolution strategy: first attempting to read a single {name}.md file, then checking for a directory named {name} containing a SKILL.md entry point, and finally falling back to generic candidate discovery. It returns a fully populated AgentSkill struct containing the parsed instructions.

To extract metadata, split_frontmatter (lines 14-31) separates YAML front-matter from Markdown content. The helper yaml_string_field reads individual keys like name and description, allowing the system to distinguish between a skill's metadata and its executable instructions.

Runtime Integration and the Public API

The Tauri Command Interface

The module exposes agent_list_skills (lines 29-33) as a Tauri command, enabling the front-end to request a list of discoverable skills for any given project path. This function returns a Vec<AvailableAgentSkill> containing the id, name, description, and source location for each skill found in the search roots.

#[tauri::command]
pub fn agent_list_skills(project_path: String) -> Vec<AvailableAgentSkill> { 
    // Returns discoverable skills for UI presentation
}

Agent Runtime Integration

load_project_skills (lines 34-46) serves as the primary entry point for the agent runtime. When a user prompt requests specific skills (e.g., "reviewer" or "illustrator"), this function deduplicates the request list, normalizes all identifiers, and orchestrates loading via load_one_skill. It materializes the complete set of skills requested by the prompt, ready for injection into the LLM context.

Security Safeguards and Safety Limits

The skills.rs module implements defense-in-depth through multiple hardening layers:

  • File size enforcement: Rejects files exceeding MAX_SKILL_FILE_BYTES to prevent memory exhaustion.
  • Depth limitation: Respects MAX_SKILL_SCAN_DEPTH during directory traversal to avoid infinite recursion.
  • Symlink prohibition: Explicitly discards symlinked directories during discover_skill_candidates to prevent path escalation.
  • Content validation: Rejects skills lacking descriptions or containing empty instruction bodies.
  • Character sanitization: Blocks unsafe characters and reserved filenames during normalization.

These checks at lines 7-9, 38-44, 61-66, 70-71, 119-124, and 128-133 ensure that malicious or malformed skill files cannot compromise the agent or host system.

Practical Usage Examples

Listing Available Skills from the Front-End

To enumerate discoverable skills for a specific project:

let project_path = "/path/to/my/project".to_string();
let available = agent_list_skills(project_path);
// `available` is a Vec<AvailableAgentSkill> containing id, name, description, source

Loading Skills for Agent Execution

When the runtime needs to materialize requested capabilities:

let project_path = "/path/to/my/project";
let requested = vec!["reviewer".to_string(), "illustrator".to_string()];
let skills = load_project_skills(project_path, &requested);
// `skills` now holds fully parsed AgentSkill structs ready for LLM prompt injection

Manual Discovery for Tooling

For external tooling or debugging purposes:

let roots = skill_roots("/path/to/my/project");
for root in roots {
    let candidates = discover_skill_candidates(&root.path);
    for c in candidates {
        println!("Found skill id '{}' at {:?}", c.id, c.path);
    }
}

Summary

  • skills.rs at src-tauri/src/agent/skills.rs is the central skill-management subsystem handling discovery, validation, and loading.
  • It defines AgentSkill for runtime use and AvailableAgentSkill for UI metadata representation.
  • skill_roots and discover_skill_candidates locate potential skills while enforcing MAX_SKILL_SCAN_DEPTH and rejecting symlinks.
  • normalize_skill_name and is_portable_skill_name enforce strict security policies on skill identifiers.
  • load_one_skill and split_frontmatter handle secure Markdown parsing and YAML front-matter extraction.
  • agent_list_skills exposes capabilities to the Tauri front-end, while load_project_skills serves the agent runtime.
  • Comprehensive safety limits prevent directory traversal, resource exhaustion, and injection attacks.

Frequently Asked Questions

How does skills.rs prevent security vulnerabilities when loading external skill files?

The module implements defense-in-depth through multiple mechanisms. It rejects symlinks during directory traversal to prevent path escalation, enforces MAX_SKILL_FILE_BYTES and MAX_SKILL_SCAN_DEPTH to limit resource consumption, and validates all skill names against strict whitelists to block path traversal sequences and Windows reserved filenames.

What is the difference between AgentSkill and AvailableAgentSkill?

AgentSkill is the heavyweight runtime representation containing the full instructions, description, and file metadata needed by the LLM for execution. AvailableAgentSkill is a lightweight struct exposed to the front-end via agent_list_skills, containing only the id, name, description, and source path for UI enumeration without loading the actual instruction content.

Where does skills.rs look for skill definitions?

The skill_roots function establishes a prioritized search path beginning with .llm-wiki/skills in the current project directory, followed by user-level skill folders in the home directory. The discover_skill_candidates function then scans these locations recursively for Markdown files named SKILL.md or {skill_name}.md, respecting depth limits and safety checks.

What happens if a skill file is malformed or missing required fields?

The validation logic in load_one_skill and split_frontmatter silently rejects skills that lack a description field or contain empty instruction bodies. Files exceeding size limits, containing unsafe path components, or failing YAML parsing are discarded during the discovery phase, ensuring only valid, complete skills reach the agent runtime.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →