9 Commits

Author SHA1 Message Date
siujamo 4041a76cd4 chore: bump version to 0.3.0 2026-06-22 14:15:29 +08:00
siujamo f63687c43d docs: add v0.3.0 changelog entries 2026-06-22 13:55:10 +08:00
siujamo e5d8693cb2 docs: add marketplace creation guide to README 2026-06-22 13:44:43 +08:00
siujamo d817e51836 docs: update changelog with detailed --version feature 2026-06-22 13:43:56 +08:00
siujamo 0a138f6f11 feat: add detailed --version output with build-time version injection 2026-06-22 13:42:52 +08:00
siujamo eb05e27655 feat: support monorepo skills via path field
- Add optional path field to SkillEntry for subdirectory skills
- Deploy from subdirectory when path is specified in install and update
2026-06-22 11:46:16 +08:00
siujamo cdb593bca9 ci: upload build artifacts directly to release
- Replace upload-artifact with direct release upload via Gitea API
2026-06-22 11:13:54 +08:00
siujamo f6be25415b ci: trigger build on release published
- Replace push, pull_request, and tag triggers with release published event
2026-06-22 10:56:38 +08:00
siujamo bcb27abb96 docs: add README, CONTRIBUTING, and LICENCE
- Add project overview, installation, and usage guide
- Add contributing guidelines with setup and PR process
- Add MIT licence
2026-06-22 10:50:08 +08:00
11 changed files with 347 additions and 16 deletions
+15 -10
View File
@@ -1,11 +1,8 @@
name: Build
on:
push:
branches: [main]
tags: ["*"]
pull_request:
branches: [main]
release:
types: [published]
jobs:
build:
@@ -27,6 +24,12 @@ jobs:
steps:
- 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
run: |
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 }}"
fi
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.archive }}
path: target/${{ matrix.target }}/release/${{ matrix.archive }}
- name: Upload to release
run: |
curl --fail -X POST \
-H "Authorization: Bearer ${{ secrets.GITEA_TOKEN }}" \
-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 }}"
+56
View File
@@ -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.
+29
View File
@@ -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
View File
@@ -218,7 +218,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "claude-code-skill-manager"
version = "0.1.0"
version = "0.3.0"
dependencies = [
"clap",
"dirs",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "claude-code-skill-manager"
version = "0.1.0"
version = "0.3.0"
edition = "2021"
[[bin]]
+21
View File
@@ -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.
+177
View File
@@ -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)
+19
View File
@@ -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
View File
@@ -1,10 +1,18 @@
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)]
#[command(
name = "ccsm",
about = "Claude Code Skill Marketplace — discover and install skills from Git marketplaces",
version
version = VERSION_TEXT,
)]
pub struct Cli {
#[command(subcommand)]
+2
View File
@@ -19,6 +19,8 @@ pub struct SkillEntry {
pub repository: String,
#[serde(default)]
pub branch: Option<String>,
#[serde(default)]
pub path: Option<String>,
}
pub fn add(url: &str, name: Option<&str>) -> Result<MarketplaceEntry, String> {
+17 -3
View File
@@ -38,10 +38,20 @@ pub fn install(
let branch = entry.branch.as_deref().unwrap_or("main");
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 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 {
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) {
Ok(()) => {
let deploy_source = match &skill_entry.path {
Some(subdir) => old_path.join(subdir),
None => old_path.clone(),
};
// Redeploy if previously deployed
if deploy_mode.is_some() || config.default_mode != InstallMode::Copy {
let mode = deploy_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())),
Err(e) => results.push((skill_name.clone(), format!("Downloaded but deploy failed: {e}"))),
}