MCPcopy Create free account
hub / github.com/AI45Lab/Code / load_from_dir

Method load_from_dir

core/src/skills/registry.rs:124–179  ·  view source on GitHub ↗

Load skills from a directory Recursively scans the directory for skill files and attempts to parse them. Supported layouts: - `path/to/skill.md` - `path/to/skill/SKILL.md` Candidate files are processed in deterministic sorted order. Files that fail to parse are skipped with debug logging; validation failures are logged as warnings.

(&self, dir: impl AsRef<Path>)

Source from the content-addressed store, hash-verified

122 /// fail to parse are skipped with debug logging; validation failures are
123 /// logged as warnings.
124 pub fn load_from_dir(&self, dir: impl AsRef<Path>) -> anyhow::Result<usize> {
125 let dir = dir.as_ref();
126
127 if !dir.exists() {
128 return Ok(0);
129 }
130
131 if !dir.is_dir() {
132 anyhow::bail!("Path is not a directory: {}", dir.display());
133 }
134
135 let mut loaded = 0;
136 for candidate in Self::collect_skill_candidates(dir)? {
137 match Skill::from_file(&candidate) {
138 Ok(skill) => {
139 let name = skill.name.clone();
140 if skill.allowed_tools.is_none() {
141 tracing::warn!(
142 skill = %name,
143 path = %candidate.display(),
144 "Skill omits allowed-tools; Skill invocation is fail-secure and will deny tool use until allowed-tools is declared"
145 );
146 } else if skill.uses_legacy_allowed_tools_syntax() {
147 tracing::warn!(
148 skill = %name,
149 path = %candidate.display(),
150 "Skill uses legacy whitespace-separated allowed-tools; use comma-separated permissions such as Read(*), Write(*), Bash(*) or a YAML list"
151 );
152 }
153 let skill = Arc::new(skill);
154 if self.get(&name).is_some() {
155 tracing::warn!(
156 skill = %name,
157 path = %candidate.display(),
158 "Duplicate skill name encountered during directory load — overriding previous definition"
159 );
160 }
161 match self.register(skill) {
162 Ok(()) => loaded += 1,
163 Err(e) => {
164 tracing::warn!(
165 "Skill validation failed for {}: {}",
166 candidate.display(),
167 e
168 );
169 }
170 }
171 }
172 Err(e) => {
173 tracing::debug!("Skipped {}: {}", candidate.display(), e);
174 }
175 }
176 }
177
178 Ok(loaded)
179 }
180
181 fn collect_skill_candidates(dir: &Path) -> anyhow::Result<Vec<PathBuf>> {

Calls 5

existsMethod · 0.45
cloneMethod · 0.45
getMethod · 0.45
registerMethod · 0.45