Skip to main content

SkillStore

Struct SkillStore 

Source
pub struct SkillStore { /* private fields */ }
Expand description

Persistent storage for skills with in-memory caching.

Manages a collection of skills loaded from Markdown files on disk. Uses a RwLock<HashMap> for thread-safe concurrent access.

§Thread Safety

All operations use async/await with RwLock to allow multiple readers or a single writer, ensuring safe concurrent access from multiple tasks.

§Example

let store = SkillStore::new(SkillStoreConfig::default());
store.initialize().await?;

// Get a specific skill
let skill = store.get_skill("my-skill").await?;
println!("Skill: {}", skill.name);

Implementations§

Source§

impl SkillStore

Source

pub fn new(config: SkillStoreConfig) -> Self

Create a new skill store with the given configuration.

The store is created empty and must be initialized using initialize before it can be used.

§Arguments
  • config - Configuration specifying the skills directory path.
§Example
use bamboo_agent::skill::{SkillStore, SkillStoreConfig};
use std::path::PathBuf;

let config = SkillStoreConfig {
    skills_dir: PathBuf::from("./skills"),
};
let store = SkillStore::new(config);
Source

pub async fn initialize(&self) -> SkillResult<()>

Initialize the store, loading skills from disk.

This method performs the following steps:

  1. Creates the skills directory if it doesn’t exist.
  2. Attempts to load existing skills from disk.
  3. Creates built-in skills if no existing skills are found.
  4. Reloads skills into memory after initialization.
§Returns

Ok(()) on successful initialization.

§Errors

Returns SkillError if:

  • The skills directory cannot be created.
  • Skill files cannot be read or parsed.
  • Built-in skills cannot be written.
§Example
let store = SkillStore::new(SkillStoreConfig::default());
store.initialize().await.expect("Failed to initialize");
Source

pub async fn reload(&self) -> SkillResult<usize>

Reload skills from disk into the in-memory cache.

This is useful when skills have been modified on disk and you want to pick up the changes without restarting the application.

§Returns

The number of skills loaded.

§Example
// After editing a skill file externally
let count = store.reload().await?;
println!("Loaded {} skills", count);
Source

pub async fn list_skills( &self, filter: Option<SkillFilter>, refresh: bool, ) -> Vec<SkillDefinition>

List all skills with optional filtering.

Returns a sorted list of skills matching the specified filter criteria. Optionally refreshes the cache from disk before listing.

§Arguments
  • filter - Optional filter criteria (by category, tags, visibility, etc.).
  • refresh - If true, reload skills from disk before listing.
§Returns

A vector of matching skills, sorted alphabetically by name.

§Example
// List all public skills, refreshing from disk
let filter = SkillFilter {
    visibility: Some(SkillVisibility::Public),
    ..Default::default()
};
let skills = store.list_skills(Some(filter), true).await;
Source

pub async fn get_skill(&self, id: &str) -> SkillResult<SkillDefinition>

Get a single skill by its ID.

Retrieves a skill from the in-memory cache by its unique identifier.

§Arguments
  • id - The skill ID (e.g., “skill-creator”).
§Returns

The matching SkillDefinition if found.

§Errors

Returns SkillError::NotFound if no skill matches the given ID.

§Example
let skill = store.get_skill("my-skill").await?;
println!("Description: {}", skill.description);
Source

pub async fn create_skill( &self, _skill: SkillDefinition, ) -> SkillResult<SkillDefinition>

Create a new skill (not supported - read-only mode).

Skills must be created by writing Markdown files directly to the skills directory. This method always returns an error.

§Errors

Always returns SkillError::ReadOnly.

Source

pub async fn update_skill( &self, _id: &str, _updates: SkillUpdate, ) -> SkillResult<SkillDefinition>

Update an existing skill (not supported - read-only mode).

Skills must be edited by modifying Markdown files directly. This method always returns an error.

§Errors

Always returns SkillError::ReadOnly.

Source

pub async fn delete_skill(&self, _id: &str) -> SkillResult<()>

Delete a skill (not supported - read-only mode).

Skills must be deleted by removing their Markdown files directly. This method always returns an error.

§Errors

Always returns SkillError::ReadOnly.

Source

pub async fn enable_skill_global(&self, _id: &str) -> SkillResult<()>

Enable a skill globally (not supported - read-only mode).

Skill visibility must be configured in the Markdown file’s frontmatter. This method always returns an error.

§Errors

Always returns SkillError::ReadOnly.

Source

pub async fn disable_skill_global(&self, _id: &str) -> SkillResult<()>

Disable a skill globally (not supported - read-only mode).

Skill visibility must be configured in the Markdown file’s frontmatter. This method always returns an error.

§Errors

Always returns SkillError::ReadOnly.

Source

pub async fn enable_skill_for_chat( &self, _skill_id: &str, _chat_id: &str, ) -> SkillResult<()>

Enable a skill for a specific chat (not supported - read-only mode).

Skill chat associations are managed externally, not through this API. This method always returns an error.

§Errors

Always returns SkillError::ReadOnly.

Source

pub async fn disable_skill_for_chat( &self, _skill_id: &str, _chat_id: &str, ) -> SkillResult<()>

Disable a skill for a specific chat (not supported - read-only mode).

Skill chat associations are managed externally, not through this API. This method always returns an error.

§Errors

Always returns SkillError::ReadOnly.

Source

pub async fn get_all_skills(&self) -> Vec<SkillDefinition>

Get all skills from the cache.

Returns all loaded skills, sorted alphabetically by name. This is a convenience method equivalent to list_skills(None, false).

§Returns

A vector of all skills in the store.

§Example
let skills = store.get_all_skills().await;
println!("Total skills: {}", skills.len());
Source

pub fn skills_dir(&self) -> &PathBuf

Get the path to the skills directory.

Returns the configured directory where skill Markdown files are stored.

§Returns

Reference to the skills directory path.

Source

pub async fn get_categories(&self) -> Vec<String>

Get all unique categories across all skills.

Scans all loaded skills and extracts their category values, returning a deduplicated and sorted list.

§Returns

A sorted vector of unique category names.

§Example
let categories = store.get_categories().await;
for category in categories {
    println!("Category: {}", category);
}
Source

pub async fn get_all_tags(&self) -> Vec<String>

Get all unique tags across all skills.

Scans all loaded skills and aggregates their tags, returning a deduplicated and sorted list.

§Returns

A sorted vector of unique tag names.

§Example
let tags = store.get_all_tags().await;
println!("Available tags: {:?}", tags);
Source

pub async fn export_to_markdown( &self, skill_ids: Option<Vec<String>>, ) -> SkillResult<String>

Export skills to Markdown format.

Renders one or more skills as Markdown documents with YAML frontmatter. Useful for creating backups or sharing skills.

§Arguments
  • skill_ids - Optional list of skill IDs to export. If None, exports all skills.
§Returns

A Markdown string containing all exported skills, separated by blank lines.

§Errors

Returns SkillError if Markdown rendering fails.

§Example
// Export specific skills
let markdown = store.export_to_markdown(
    Some(vec!["skill-creator".to_string()])
).await?;
println!("{}", markdown);

// Export all skills
let all_markdown = store.export_to_markdown(None).await?;

Trait Implementations§

Source§

impl Default for SkillStore

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more