Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
4041a76cd4
|
|||
|
f63687c43d
|
|||
|
e5d8693cb2
|
|||
|
d817e51836
|
|||
|
0a138f6f11
|
|||
|
eb05e27655
|
|||
|
cdb593bca9
|
|||
|
f6be25415b
|
|||
|
bcb27abb96
|
|||
|
2ebf392bd2
|
|||
|
5bef4ef2ee
|
|||
|
9df82f99b5
|
|||
|
cfc20d4b89
|
|||
|
23af3f9c1d
|
|||
|
aef7d973ec
|
+15
-10
@@ -1,11 +1,8 @@
|
|||||||
name: Build
|
name: Build
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
release:
|
||||||
branches: [main]
|
types: [published]
|
||||||
tags: ["*"]
|
|
||||||
pull_request:
|
|
||||||
branches: [main]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -27,6 +24,12 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set version
|
||||||
|
run: |
|
||||||
|
VERSION="${{ github.event.release.tag_name }}"
|
||||||
|
VERSION="${VERSION#v}"
|
||||||
|
echo "CCSM_VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
run: |
|
run: |
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
|
||||||
@@ -64,8 +67,10 @@ jobs:
|
|||||||
tar czf "${{ matrix.archive }}" "${{ matrix.binary }}"
|
tar czf "${{ matrix.archive }}" "${{ matrix.binary }}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload to release
|
||||||
uses: actions/upload-artifact@v4
|
run: |
|
||||||
with:
|
curl --fail -X POST \
|
||||||
name: ${{ matrix.archive }}
|
-H "Authorization: Bearer ${{ secrets.GITEA_TOKEN }}" \
|
||||||
path: target/${{ matrix.target }}/release/${{ matrix.archive }}
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"target/${{ matrix.target }}/release/${{ matrix.archive }}" \
|
||||||
|
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/releases/${{ github.event.release.id }}/assets?name=${{ matrix.archive }}"
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## v0.3.0
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Detailed `--version` output** — shows version, commit SHA, project name, and attribution (`by OnixByte`); version can be injected at build time via `CCSM_VERSION` env var
|
||||||
|
- **Marketplace creation guide** — README now documents how to create and publish a skill marketplace, including the `skills.json` format, skill entry fields, monorepo `path` support, and skill repository structure
|
||||||
|
|
||||||
|
## v0.2.0
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **Monorepo skill support** — skills can now live in subdirectories of a single repository via the `path` field in `skills.json`
|
||||||
|
- **Release-triggered CI** — workflow runs on `release: published` and uploads built artifacts directly to the release
|
||||||
|
- **Project documentation** — README, CONTRIBUTING, and LICENCE (MIT) files
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- CI artifact upload compatibility with self-hosted Gitea (downgrade `upload-artifact` to v3)
|
||||||
|
- Cross-compilation for macOS and Windows targets via `cargo-zigbuild`
|
||||||
|
|
||||||
|
## v0.1.0
|
||||||
|
|
||||||
|
Initial release of Claude Code Skill Manager (CCSM) — a CLI tool for discovering, installing, and managing Claude Code skills from Git-based marketplace repositories.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- **Marketplace management** — register, list, update, and remove skill marketplaces from any Git repository exposing a `skills.json` manifest
|
||||||
|
- **Skill search** — browse and search available skills by name or description across all registered marketplaces
|
||||||
|
- **Skill installation** — download and deploy skills to `~/.claude/skills/` with copy or symlink modes
|
||||||
|
- **Skill lifecycle** — update installed skills to latest versions, remove unwanted skills, and inspect skill details
|
||||||
|
- **Cross-platform** — pre-built binaries for Linux, macOS, and Windows (amd64)
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
|---|---|
|
||||||
|
| `ccsm marketplace add <url>` | Register a skill marketplace |
|
||||||
|
| `ccsm marketplace remove <name>` | Unregister a marketplace |
|
||||||
|
| `ccsm marketplace list` | List registered marketplaces |
|
||||||
|
| `ccsm marketplace update [name]` | Refresh marketplace manifests |
|
||||||
|
| `ccsm search [query]` | Search available skills |
|
||||||
|
| `ccsm install <name>` | Install a skill |
|
||||||
|
| `ccsm list` | Show installed skills |
|
||||||
|
| `ccsm info <name>` | Show skill details |
|
||||||
|
| `ccsm update [name]` | Update installed skills |
|
||||||
|
| `ccsm remove <name>` | Uninstall a skill |
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo install --path .
|
||||||
|
```
|
||||||
|
|
||||||
|
Or download a pre-built binary from the [Releases](https://onixbyte.dev/onixbyte/claude-code-skill-manager/releases) page.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://onixbyte.dev/onixbyte/claude-code-skill-manager.git
|
||||||
|
cd claude-code-skill-manager
|
||||||
|
cargo build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Before submitting
|
||||||
|
|
||||||
|
- Run `cargo fmt` to format your code
|
||||||
|
- Run `cargo clippy` and fix any warnings
|
||||||
|
- Ensure `cargo build` succeeds
|
||||||
|
|
||||||
|
## Pull requests
|
||||||
|
|
||||||
|
- Keep changes focused and atomic
|
||||||
|
- Write clear commit messages following the [conventional commits](https://www.conventionalcommits.org/) format
|
||||||
|
- Open PRs against the `main` branch
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
|
||||||
|
Bug reports and feature requests are welcome. Please include steps to reproduce when reporting bugs.
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
By contributing, you agree that your contributions will be licensed under the [MIT Licence](LICENCE).
|
||||||
Generated
+1
-1
@@ -218,7 +218,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "claude-code-skill-manager"
|
name = "claude-code-skill-manager"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "claude-code-skill-manager"
|
name = "claude-code-skill-manager"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 OnixByte
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
# Claude Code Skill Manager (CCSM)
|
||||||
|
|
||||||
|
A CLI tool for discovering, installing, and managing [Claude Code](https://claude.ai/code) skills from Git-based marketplace repositories.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### From source
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://onixbyte.dev/onixbyte/claude-code-skill-manager.git
|
||||||
|
cd claude-code-skill-manager
|
||||||
|
cargo install --path .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pre-built binaries
|
||||||
|
|
||||||
|
Download the latest binary for your platform from the [Releases](https://onixbyte.dev/onixbyte/claude-code-skill-manager/releases) page.
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Register a skill marketplace
|
||||||
|
ccsm marketplace add https://github.com/example/skills
|
||||||
|
|
||||||
|
# Browse available skills
|
||||||
|
ccsm search
|
||||||
|
|
||||||
|
# Install a skill
|
||||||
|
ccsm install my-skill
|
||||||
|
|
||||||
|
# List installed skills
|
||||||
|
ccsm list
|
||||||
|
|
||||||
|
# See details about a skill
|
||||||
|
ccsm info my-skill
|
||||||
|
|
||||||
|
# Update installed skills
|
||||||
|
ccsm update
|
||||||
|
|
||||||
|
# Remove a skill
|
||||||
|
ccsm remove my-skill
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### Marketplace management
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
|---|---|
|
||||||
|
| `ccsm marketplace add <url>` | Register a Git repository as a skill marketplace |
|
||||||
|
| `ccsm marketplace remove <name>` | Unregister a marketplace |
|
||||||
|
| `ccsm marketplace list` | List registered marketplaces |
|
||||||
|
| `ccsm marketplace update [name]` | Refresh marketplace manifests |
|
||||||
|
|
||||||
|
### Skill management
|
||||||
|
|
||||||
|
| Command | Description |
|
||||||
|
|---|---|
|
||||||
|
| `ccsm search [query]` | Search available skills across all marketplaces |
|
||||||
|
| `ccsm install <name>` | Install a skill (supports `--copy` and `--link` modes) |
|
||||||
|
| `ccsm list` | Show installed skills |
|
||||||
|
| `ccsm info <name>` | Show details about an installed skill |
|
||||||
|
| `ccsm update [name]` | Update installed skills to latest |
|
||||||
|
| `ccsm remove <name>` | Uninstall a skill |
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
Skills are directories placed under `~/.claude/skills/` that Claude Code reads at startup. CCSM manages these directories by pulling skill definitions from marketplace repositories that expose a `skills.json` manifest:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "My Marketplace",
|
||||||
|
"skills": [
|
||||||
|
{
|
||||||
|
"name": "example-skill",
|
||||||
|
"description": "An example Claude Code skill",
|
||||||
|
"repository": "https://github.com/user/skill-repo",
|
||||||
|
"branch": "main"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating a skill marketplace
|
||||||
|
|
||||||
|
A marketplace is simply a public Git repository that contains a `skills.json` manifest at its root. CCSM reads this file to discover what skills are available.
|
||||||
|
|
||||||
|
### Repository structure
|
||||||
|
|
||||||
|
```
|
||||||
|
your-marketplace-repo/
|
||||||
|
skills.json ← manifest (required)
|
||||||
|
README.md ← optional landing page
|
||||||
|
```
|
||||||
|
|
||||||
|
### skills.json format
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "My Marketplace",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"skills": [
|
||||||
|
{
|
||||||
|
"name": "my-skill",
|
||||||
|
"description": "A short description shown in search results",
|
||||||
|
"repository": "https://github.com/user/skill-repo",
|
||||||
|
"branch": "main"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "another-skill",
|
||||||
|
"description": "A skill that lives in a monorepo subdirectory",
|
||||||
|
"repository": "https://github.com/user/monorepo",
|
||||||
|
"branch": "main",
|
||||||
|
"path": "skills/another-skill"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
| Field | Required | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `name` | Yes | Marketplace display name |
|
||||||
|
| `version` | No | Arbitrary version string for your own tracking |
|
||||||
|
| `skills` | No | Array of skill entries (defaults to `[]`) |
|
||||||
|
|
||||||
|
**Skill entry fields:**
|
||||||
|
|
||||||
|
| Field | Required | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `name` | Yes | Unique skill identifier (used with `ccsm install <name>`) |
|
||||||
|
| `description` | Yes | One-line summary shown in `ccsm search` output |
|
||||||
|
| `repository` | Yes | Public Git repository URL for the skill |
|
||||||
|
| `branch` | No | Git branch to install from (defaults to `main` or `master`, auto-detected by the marketplace host) |
|
||||||
|
| `path` | No | Subdirectory within the repository where the skill files live — use for monorepos hosting multiple skills |
|
||||||
|
|
||||||
|
### What goes in a skill repository
|
||||||
|
|
||||||
|
Each skill repository (the one referenced by `repository`) is a standard Claude Code skill directory. At minimum it should contain one of:
|
||||||
|
|
||||||
|
- `SKILL.md` — the skill manifest (preferred)
|
||||||
|
- `CLAUDE.md` — alternative manifest filename
|
||||||
|
- Supporting files referenced by the manifest (scripts, templates, etc.)
|
||||||
|
|
||||||
|
See the [Claude Code skills documentation](https://docs.anthropic.com/en/docs/claude-code/skills) for details on writing skill manifests.
|
||||||
|
|
||||||
|
### Publishing your marketplace
|
||||||
|
|
||||||
|
1. Create a public Git repository with a `skills.json` following the format above.
|
||||||
|
2. Push it — make sure `skills.json` is at the repository root.
|
||||||
|
3. Anyone can register it with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ccsm marketplace add https://github.com/your-username/your-marketplace
|
||||||
|
```
|
||||||
|
|
||||||
|
CCSM fetches `skills.json` from the raw `main` or `master` branch automatically, so both of those branch names work out of the box.
|
||||||
|
|
||||||
|
## Deploy modes
|
||||||
|
|
||||||
|
- **Copy** (default): Skill files are physically copied to `~/.claude/skills/<name>/`.
|
||||||
|
- **Link**: A symlink is created from `~/.claude/skills/<name>/` to the local store, useful for development.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
Cross-compilation targets: Linux (amd64), macOS (amd64), and Windows (amd64) via `cargo-zigbuild`.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
[MIT](LICENCE)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let version = std::env::var("CCSM_VERSION")
|
||||||
|
.unwrap_or_else(|_| env!("CARGO_PKG_VERSION").to_string());
|
||||||
|
|
||||||
|
let commit = Command::new("git")
|
||||||
|
.args(["rev-parse", "--short", "HEAD"])
|
||||||
|
.output()
|
||||||
|
.ok()
|
||||||
|
.and_then(|o| String::from_utf8(o.stdout).ok())
|
||||||
|
.map(|s| s.trim().to_string())
|
||||||
|
.unwrap_or_else(|| "unknown".to_string());
|
||||||
|
|
||||||
|
println!("cargo:rustc-env=CCSM_VERSION={version}");
|
||||||
|
println!("cargo:rustc-env=GIT_COMMIT_SHORT={commit}");
|
||||||
|
println!("cargo:rerun-if-changed=.git/HEAD");
|
||||||
|
println!("cargo:rerun-if-env-changed=CCSM_VERSION");
|
||||||
|
}
|
||||||
+9
-1
@@ -1,10 +1,18 @@
|
|||||||
use clap::{Args, Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
|
|
||||||
|
const VERSION_TEXT: &str = concat!(
|
||||||
|
env!("CCSM_VERSION"),
|
||||||
|
" -- Claude Code Skill Manager",
|
||||||
|
" -- ",
|
||||||
|
env!("GIT_COMMIT_SHORT"),
|
||||||
|
"\nby OnixByte"
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(
|
#[command(
|
||||||
name = "ccsm",
|
name = "ccsm",
|
||||||
about = "Claude Code Skill Marketplace — discover and install skills from Git marketplaces",
|
about = "Claude Code Skill Marketplace — discover and install skills from Git marketplaces",
|
||||||
version
|
version = VERSION_TEXT,
|
||||||
)]
|
)]
|
||||||
pub struct Cli {
|
pub struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ pub struct SkillEntry {
|
|||||||
pub repository: String,
|
pub repository: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub branch: Option<String>,
|
pub branch: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub path: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(url: &str, name: Option<&str>) -> Result<MarketplaceEntry, String> {
|
pub fn add(url: &str, name: Option<&str>) -> Result<MarketplaceEntry, String> {
|
||||||
|
|||||||
+17
-3
@@ -38,10 +38,20 @@ pub fn install(
|
|||||||
let branch = entry.branch.as_deref().unwrap_or("main");
|
let branch = entry.branch.as_deref().unwrap_or("main");
|
||||||
download::download_skill(&entry.repository, branch, &target)?;
|
download::download_skill(&entry.repository, branch, &target)?;
|
||||||
|
|
||||||
// Deploy to Claude skills directory (copy or link)
|
let deploy_source = match &entry.path {
|
||||||
|
Some(subdir) => {
|
||||||
|
let p = target.join(subdir);
|
||||||
|
if !p.exists() {
|
||||||
|
return Err(format!("Path '{}' not found in skill repository", subdir));
|
||||||
|
}
|
||||||
|
p
|
||||||
|
}
|
||||||
|
None => target.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
let config = Config::load().map_err(|e| format!("Cannot read config: {e}"))?;
|
let config = Config::load().map_err(|e| format!("Cannot read config: {e}"))?;
|
||||||
let deploy_mode = mode.unwrap_or_else(|| config.default_mode.clone());
|
let deploy_mode = mode.unwrap_or_else(|| config.default_mode.clone());
|
||||||
deploy_skill(name, &target, &deploy_mode)?;
|
deploy_skill(name, &deploy_source, &deploy_mode)?;
|
||||||
|
|
||||||
Ok(Skill {
|
Ok(Skill {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
@@ -233,12 +243,16 @@ pub fn update(name: Option<&str>) -> Result<Vec<(String, String)>, String> {
|
|||||||
|
|
||||||
match download::download_skill(&skill_entry.repository, branch, &old_path) {
|
match download::download_skill(&skill_entry.repository, branch, &old_path) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
|
let deploy_source = match &skill_entry.path {
|
||||||
|
Some(subdir) => old_path.join(subdir),
|
||||||
|
None => old_path.clone(),
|
||||||
|
};
|
||||||
// Redeploy if previously deployed
|
// Redeploy if previously deployed
|
||||||
if deploy_mode.is_some() || config.default_mode != InstallMode::Copy {
|
if deploy_mode.is_some() || config.default_mode != InstallMode::Copy {
|
||||||
let mode = deploy_mode
|
let mode = deploy_mode
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| config.default_mode.clone());
|
.unwrap_or_else(|| config.default_mode.clone());
|
||||||
match deploy_skill(skill_name, &old_path, &mode) {
|
match deploy_skill(skill_name, &deploy_source, &mode) {
|
||||||
Ok(()) => results.push((skill_name.clone(), "Updated".to_string())),
|
Ok(()) => results.push((skill_name.clone(), "Updated".to_string())),
|
||||||
Err(e) => results.push((skill_name.clone(), format!("Downloaded but deploy failed: {e}"))),
|
Err(e) => results.push((skill_name.clone(), format!("Downloaded but deploy failed: {e}"))),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user