# craftbag
Discover, list, load, and explain Agent Skills (`SKILL.md`) for CLI and MCP hosts.
[](https://github.com/craftbag/craftbag/actions/workflows/ci.yml)
[](https://github.com/craftbag/craftbag/actions/workflows/security.yml)
[](https://crates.io/crates/craftbag)
[](https://docs.rs/craftbag)
[](LICENSE)
[](https://www.bestpractices.dev/projects/14274)
[](https://securityscorecards.dev/viewer/?uri=github.com/craftbag/craftbag)
[](https://app.fossa.com/projects/custom%2B62586%2Fgithub.com%2Fcraftbag%2Fcraftbag?ref=badge_shield&issueType=license)
[](https://github.com/craftbag/craftbag/releases/latest)
## What it does
craftbag walks project and home skill trees (`.agents`, plus optional vendor trees for Claude, Cursor, Grok, and Bline). It then:
- catalogs skills (`list`)
- prints one skill body (`load`), or heading keys / one heading (`load --outline`, `load --section KEY`)
- explains why a skill would activate (`why`)
- checks a package (`validate`)
The same operations exist over MCP stdio (`skills_list`, `skills_load`, `skills_why`, `skills_validate`). Hosts can filter, rank, and load skills without taking a dependency on any one agent product.
## Install
macOS and Linux (Homebrew):
```bash
brew install craftbag/tap/craftbag
```
Windows (Scoop):
```powershell
scoop bucket add craftbag https://github.com/craftbag/scoop-bucket
scoop install craftbag/craftbag
```
Both commands install `craftbag` and `craftbag-mcp`. The MCP host then runs `craftbag-mcp` (on macOS GUI apps, use the full path if `PATH` is empty: `/opt/homebrew/bin/craftbag-mcp`).
From a Rust toolchain (crates.io):
```bash
cargo install --locked craftbag-cli
cargo install --locked craftbag-mcp
```
Library dependency:
```toml
craftbag = "0.2"
```
From git (unreleased tip):
```bash
cargo install --locked --git https://github.com/craftbag/craftbag craftbag-cli
cargo install --locked --git https://github.com/craftbag/craftbag craftbag-mcp
```
MSRV is 1.85.
## Getting started
Default `list` walks cwd-to-git `.agents/skills` and `$HOME/.agents/skills`. Claude, Cursor, Grok, and Bline trees stay out of that walk until you pass `--vendor`. When `.cursor/skills` (or the matching directory for another vendor) is present and that vendor is off, the empty list names the flag: `hint: .cursor/skills is present; pass --vendor cursor`. This clone has no project `.agents`. When the `.agents` directories are absent, `craftbag list` exits 0 and says no skills were found. `craftbag new NAME` writes `.agents/skills/NAME/SKILL.md` with a matching name and a placeholder description. Point `--path` at the demo tree (same catalog as the demo GIF):
```bash
git clone https://github.com/craftbag/craftbag
cd craftbag
craftbag list --no-implicit-roots --path demo/workspace/.agents/skills --catalog
craftbag load review-pr --no-implicit-roots --path demo/workspace/.agents/skills
craftbag load review-pr --no-implicit-roots --path demo/workspace/.agents/skills --outline
craftbag load review-pr --no-implicit-roots --path demo/workspace/.agents/skills --section review-a-pull-request
craftbag why review-pr --no-implicit-roots --path demo/workspace/.agents/skills --context review
craftbag validate demo/workspace/.agents/skills/review-pr
```
`--section review-a-pull-request` passes the outline key. `--outline` prints that key before the heading `Review a pull request`. `validate` takes the package directory that contains `SKILL.md`, here `demo/workspace/.agents/skills/review-pr`. The collection folder `demo/workspace/.agents/skills` has no `SKILL.md` of its own, so `validate` on it exits 1 with `directory is not a skill package (no SKILL.md)`. `list --path` on that folder still lists the packages inside it.
`--path`, `--user-dir`, and `--ignore` expand `~/` themselves, because MCP and a quoted command have no shell. `~//name` stays under your home directory, the same as `~/name`. A `~//` remainder that is still a Windows drive path is refused, so it does not replace your home directory. A path that is not there is an unreadable skip and says the path does not exist. A symlink whose target is gone says dangling symlink. Explicit `/` and `/..` are roots you named. A padded `..` that collapses to `/`, such as `/tmp/ ..`, is refused.
If `craftbag` is not on `PATH` yet, `cargo build -p craftbag-cli --locked` and use `./target/debug/craftbag` in those commands.
In a project that already has skills under `.agents/skills`:
```bash
craftbag list --catalog
craftbag load NAME
craftbag why NAME --context review
craftbag validate ./path/to/my-skill
```
Claude, Cursor, Grok, or Bline trees are opt-in:
```bash
craftbag list --vendor claude --catalog
```
## Demo

## MCP
`craftbag-mcp` speaks JSON-RPC on stdio. Tools: `skills_list`, `skills_load`, `skills_why`, `skills_validate`. `prompts/list` and `prompts/get` expose skills whose `user_invocable` is true (the default) as MCP prompts. `prompts/get` returns the same text envelope as `load`. After `brew install` or `scoop install`, `craftbag-mcp --help` names the tools. A request with `"id": null` is answered with that id. A message that omits `id` is a notification and gets no response.
Claude Desktop (`claude_desktop_config.json`) and other hosts that take a stdio command:
```json
{
"mcpServers": {
"craftbag": {
"command": "craftbag-mcp",
"args": ["--vendor", "claude"]
}
}
}
```
Launch `--path`, `--vendor`, `--user-dir`, and `--no-implicit-roots` are the walk when a tool call omits that field. The host cwd is still the implicit walk root unless you pass `--no-implicit-roots`. `skills_load` accepts `outline` and `section` (same as `load --outline` / `--section KEY`).
## Library
```rust
use craftbag::{discover, DiscoveryOptions};
fn main() -> std::io::Result<()> {
let cwd = std::env::current_dir()?;
let report = discover(&cwd, &DiscoveryOptions::default());
for skill in &report.skills {
println!("{} {}", skill.name, skill.description);
}
Ok(())
}
```
`implicit_roots` is on by default (cwd-to-git `.agents` and `$HOME/.agents`). Set it to `false` and put collection roots in `paths` for leftover-only hosts. `format_load_view` can print an outline or one heading instead of the whole body.
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md). Security reports go to [SECURITY.md](SECURITY.md). Roadmap and governance are in [ROADMAP.md](ROADMAP.md) and [GOVERNANCE.md](GOVERNANCE.md).
## License
Apache-2.0 or MIT. You may choose either. See `LICENSE` and `LICENSE-APACHE`.