Skip to main content

walrus_daemon/hook/skill/
handler.rs

1//! Walrus skill handler — initial load from disk.
2
3use crate::hook::skill::{SkillRegistry, loader};
4use anyhow::Result;
5use std::path::PathBuf;
6use tokio::sync::Mutex;
7
8/// Skill registry owner.
9///
10/// Implements [`Hook`] — `on_build_agent` enriches the system prompt with
11/// matching skills based on agent tags. Tools and dispatch are no-ops
12/// (skills inject behavior via prompt, not via tools).
13pub struct SkillHandler {
14    /// The skill registry (Mutex for interior-mutability from `dispatch_load_skill`).
15    pub registry: Mutex<SkillRegistry>,
16    /// Base directory from which skills are loaded.
17    pub skills_dir: PathBuf,
18}
19
20impl Default for SkillHandler {
21    fn default() -> Self {
22        Self {
23            registry: Mutex::new(SkillRegistry::new()),
24            skills_dir: PathBuf::new(),
25        }
26    }
27}
28
29impl SkillHandler {
30    /// Load skills from the given directory. Tolerates a missing directory
31    /// by creating an empty registry.
32    pub fn load(skills_dir: PathBuf) -> Result<Self> {
33        let registry = if skills_dir.exists() {
34            match loader::load_skills_dir(&skills_dir) {
35                Ok(r) => {
36                    tracing::info!("loaded {} skill(s)", r.len());
37                    r
38                }
39                Err(e) => {
40                    tracing::warn!("could not load skills from {}: {e}", skills_dir.display());
41                    SkillRegistry::new()
42                }
43            }
44        } else {
45            SkillRegistry::new()
46        };
47        Ok(Self {
48            registry: Mutex::new(registry),
49            skills_dir,
50        })
51    }
52}