AgentsSkillVault

A Ruby gem for managing a local vault of GitHub resources that contains Agent Skill specifications. Clone entire repositories or specific folders, keep them synced, and query them by username or repository name.

Currently works only with Github. Future plans will include to support any Git based repository.

Overview

AgentsSkillVault helps you maintain a local collection of GitHub resources (repositories, folders, or files) with:

  • Easy addition - Add resources via GitHub URL
  • Sparse checkout - Clone only the folders you need, not entire repos
  • Sync management - Pull latest changes with one command
  • Querying - Filter resources by username or repository name
  • Manifest tracking - All resources tracked in a JSON manifest for portability

Installation

Add this line to your application's Gemfile:

gem "agents_skill_vault"

And then execute:

bundle install

Or install it yourself:

gem install agents_skill_vault

Requirements:

  • Ruby 3.4+
  • Git 2.25.0+ (for sparse checkout support)

Quick Start

require "agents_skill_vault"

# Create a vault in a directory
vault = AgentsSkillVault::Vault.new(storage_path: "~/.my_vault")

# Add a full repository
vault.add("https://github.com/rails/rails")

# Add a specific folder with a custom label
vault.add(
  "https://github.com/user/dotfiles/tree/main/.claude/skills/deep-research",
  label: "deep-research"
)

# List all resources
vault.list.each do |resource|
  puts "#{resource.label} -> #{resource.local_path}"
end

# Sync a specific resource
result = vault.sync("rails/rails")
puts "Synced!" if result.success?

# Sync all resources
vault.sync_all

API Reference

Vault

The main interface for managing resources.

Creating a Vault

vault = AgentsSkillVault::Vault.new(storage_path: "/path/to/vault")

Adding Resources

# Add a repository (auto-generates label: "username/repo")
vault.add("https://github.com/user/repo")

# Add with custom label
vault.add("https://github.com/user/repo", label: "my-custom-label")

# Add a specific folder (uses sparse checkout)
vault.add("https://github.com/user/repo/tree/main/lib/skills")

# Add a specific file
vault.add("https://github.com/user/repo/blob/main/config.yml")

Querying Resources

# List all resources
resources = vault.list

# Find by label (returns nil if not found)
resource = vault.find_by_label("user/repo")

# Fetch by label (raises Errors::NotFound if not found)
resource = vault.fetch("user/repo")

# Filter by GitHub username
vault.filter_by_username("octocat")  # => [Resource, ...]

# Filter by repository name
vault.filter_by_repo("dotfiles")  # => [Resource, ...]

Syncing Resources

# Sync a single resource
result = vault.sync("user/repo")
if result.success?
  puts "Changes: #{result.changes?}"
else
  puts "Error: #{result.error}"
end

# Sync all resources
results = vault.sync_all
results.each do |label, result|
  status = result.success? ? "OK" : result.error
  puts "#{label}: #{status}"
end

Removing Resources

# Remove from manifest only (keep files on disk)
vault.remove("user/repo")

# Remove from manifest AND delete files
vault.remove("user/repo", delete_files: true)

Backup and Restore

# Export manifest for backup
vault.export_manifest("/backups/manifest.json")

# Import manifest (merges with existing resources)
vault.import_manifest("/shared/manifest.json")

# Re-download all resources from scratch
vault.redownload_all

Resource

Represents a tracked GitHub resource.

resource = vault.fetch("user/repo")

resource.label          # => "user/repo"
resource.url            # => "https://github.com/user/repo"
resource.username       # => "user"
resource.repo           # => "repo"
resource.type           # => :repo, :folder, or :file
resource.branch         # => "main"
resource.local_path     # => "/vault/user/repo"
resource.relative_path  # => nil (or path within repo for folders/files)
resource.added_at       # => Time
resource.synced_at      # => Time

SyncResult

Returned by sync operations.

result = vault.sync("user/repo")

result.success?  # => true/false
result.changes?  # => true/false (did the sync pull new changes?)
result.error     # => nil or error message string

Error Handling

begin
  vault.add("invalid-url")
rescue AgentsSkillVault::Errors::InvalidUrl => e
  puts "Bad URL: #{e.message}"
end

begin
  vault.fetch("nonexistent")
rescue AgentsSkillVault::Errors::NotFound => e
  puts "Not found: #{e.message}"
end

begin
  vault.add("https://github.com/user/repo")
  vault.add("https://github.com/other/thing", label: "user/repo")
rescue AgentsSkillVault::Errors::DuplicateLabel => e
  puts "Duplicate: #{e.message}"
end

Common Use Cases

Managing Claude Code Skills

vault = AgentsSkillVault::Vault.new(storage_path: "~/.claude/skill_vault")

# Add skills from various sources
vault.add("https://github.com/anthropics/claude-code/tree/main/skills/web-search")
vault.add("https://github.com/user/my-skills/tree/main/coding-assistant", label: "coding")

# Keep everything up to date
vault.sync_all

Sharing Resource Collections

# On machine A: Export your vault configuration
vault.export_manifest("~/Dropbox/vault-manifest.json")

# On machine B: Import and download
new_vault = AgentsSkillVault::Vault.new(storage_path: "~/.vault")
new_vault.import_manifest("~/Dropbox/vault-manifest.json")
new_vault.redownload_all

Selective Repository Checkout

# Instead of cloning a huge monorepo, just get the folder you need
vault.add(
  "https://github.com/big-org/monorepo/tree/main/packages/useful-lib",
  label: "useful-lib"
)

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests.

bundle exec rake test

You can also run bin/console for an interactive prompt.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/lucianghinda/agents_skill_vault.

License

The gem is available as open source under the terms of the Apache 2.0 License.