Skip to main content

vtcode_skills/
model.rs

1use crate::types::SkillManifest;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4use std::path::PathBuf;
5use vtcode_commons::MultiErrors;
6
7/// Skill scope indicating where the skill is defined
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default, Hash)]
9#[serde(rename_all = "snake_case")]
10pub enum SkillScope {
11    /// User-level skill (`~/.agents/skills`)
12    #[default]
13    User,
14    /// Repository-level skill (`.agents/skills`)
15    Repo,
16    /// System-level bundled skill
17    System,
18    /// Admin-level skill (`/etc/codex/skills`)
19    Admin,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct SkillMetadata {
24    pub name: String,
25    pub description: String,
26    #[serde(default)]
27    pub short_description: Option<String>,
28    pub path: PathBuf,
29    pub scope: SkillScope,
30    #[serde(default)]
31    pub manifest: Option<Box<SkillManifest>>,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35pub struct SkillErrorInfo {
36    pub path: PathBuf,
37    pub message: String,
38}
39
40impl fmt::Display for SkillErrorInfo {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(f, "{}: {}", self.path.display(), self.message)
43    }
44}
45
46impl std::error::Error for SkillErrorInfo {}
47
48#[derive(Debug, Clone, Default)]
49pub struct SkillLoadOutcome {
50    pub skills: Vec<SkillMetadata>,
51    pub errors: MultiErrors<SkillErrorInfo>,
52}
53
54#[cfg(test)]
55mod tests {
56    use super::SkillMetadata;
57    use crate::types::SkillManifest;
58
59    #[test]
60    fn boxed_manifest_is_smaller_than_inline_option() {
61        use std::mem::size_of;
62
63        assert!(size_of::<Option<Box<SkillManifest>>>() < size_of::<Option<SkillManifest>>());
64        assert!(size_of::<SkillMetadata>() < size_of::<SkillMetadataInlineManifest>());
65    }
66
67    #[expect(
68        dead_code,
69        reason = "Intentional compatibility, platform, test, or API-shape suppression."
70    )]
71    struct SkillMetadataInlineManifest {
72        name: String,
73        description: String,
74        short_description: Option<String>,
75        path: std::path::PathBuf,
76        scope: super::SkillScope,
77        manifest: Option<SkillManifest>,
78    }
79}