agents-skills 0.9.2

A minimal, stable, easy-to-understand skill installer and manager for AI agents
Documentation
# agents-skills Developer Guide

English | [简体中文]DEVELOPER.zh-CN.md

For **project developers**: project layout, development workflow, testing, and
releasing. For a feature overview and CLI usage see the
[README]../README.md, for the command reference see [CLI.md]CLI.md, for
the library API see [LIBRARY.md]LIBRARY.md.

## Architecture layers

The project is deliberately layered, with a strict separation between the
library and the CLI:

- **Library** (`src/lib.rs` + `src/manager.rs` + `src/core/`) — pure data:
  never prints, never calls `process::exit`, and surfaces errors through
  `Result`.
- **CLI** (`src/main.rs` + `src/cli.rs` + `src/commands/`) — a thin rendering
  layer on top of the library: it only splits clap arguments, hands request
  structs to the `Manager`, then renders results as human/machine-readable
  output and decides the exit code.

Every CLI command maps to one `Manager` method, and CLI flags map to
request-struct fields. When adding capabilities, implement them first in the
`core`/`Manager` layer, then render them in the CLI layer; never let the CLI
layer touch domain logic directly.

## Project layout

```
src/
├── lib.rs              Library root: Manager facade + request/result types + private core module
├── manager.rs          High-level Manager facade (add/list/remove/update/disable/enable/link)
├── error.rs            Unified error type and Result alias
├── core/               Domain logic (pure functions, injectable dependencies)
│   ├── mod.rs          Module organization and re-exports
│   ├── source.rs       Source-string parsing
│   ├── agents.rs       Declarative interpreter over the agent table (resolution + detection)
│   ├── agents.jsonl    The agent table: one JSON object per agent line
│   ├── discover.rs     SKILL.md discovery + frontmatter parsing
│   ├── fetch.rs        git clone / HTTP download / archive unpacking
│   ├── github.rs       GitHub API single-skill fast path
│   ├── install.rs      Install skills into the canonical directory + installed-skills listing
│   ├── link.rs         Directory-level agent linking (link/unlink/migrate)
│   ├── lock.rs         skills-lock.json read/write + content hashing
│   └── test_utils.rs   Shared unit-test fixtures
├── main.rs             bin entry point (thin CLI on top of the library)
├── cli.rs              clap command tree (commands, flags — no aliases)
└── commands/           CLI rendering layer (argument splitting + output only)
    ├── mod.rs
    ├── add.rs
    ├── remove.rs
    ├── list.rs
    ├── update.rs
    ├── disable.rs
    ├── enable.rs
    └── agent.rs

examples/
├── add_skill.rs        Install a skill via the Manager facade (real usage)
└── manage.rs           Demonstrates the add → list → remove lifecycle on a temp directory

tests/
├── common/mod.rs       Shared integration-test fixtures
├── lib_api.rs          Library API integration tests
├── cli_add.rs
├── cli_remove.rs
├── cli_list.rs
├── cli_agent.rs
├── cli_enable_disable.rs
└── cli_version.rs
```

## Adding an agent

The agent table lives in `src/core/agents.jsonl` — one JSON object per agent,
embedded into the binary at compile time (`include_str!`). Adding, changing, or
removing an agent is a one-line edit in that file; no Rust changes are required.
Blank lines and `#` comments are allowed, and the file order defines the
listing order.

```jsonc
{
  "name": "claude-code",      // required, unique identifier (used on the CLI)
  "display": "Claude Code",   // required, human-readable name
  "skills_dir": ".claude/skills", // required, project-level skills dir (relative to cwd)
  "global": { "env_home": { "var": "CLAUDE_CONFIG_DIR", "default": ".claude", "path": "skills" } },
  "detect": [ { "env_home": { "var": "CLAUDE_CONFIG_DIR", "default": ".claude" } } ],
  "hidden": false             // optional, hide from the universal agents list (default false)
}
```

`global` is a single path spec, and `detect` is a list of path specs — an agent
is detected as installed when any one of them resolves to an existing path.
Exactly one of these keys per spec:

| Key | Resolves to |
| --- | ----------- |
| `{"home": "..."}` | `home/<path>` |
| `{"config": "..."}` | `config/<path>` |
| `{"cwd": "..."}` | `cwd/<path>` |
| `{"env_home": {"var": "...", "default": "...", "path": "..."}}` | `$VAR \|\| home/<default>`, then `<path>` joined |
| `{"env_var": {"var": "...", "path": "..."}}` | `$VAR/<path>`; unmatched when the var is unset |
| `{"system": "/abs/path"}` | absolute path; only probed when system probing is on |

Universal agents (those whose `skills_dir` is `.agents/skills`) share the
canonical directory and need no symlinks; the `universal` pseudo-agent carries
`"detect": []` so it is never detected as installed.

## Development

```bash
cargo build            # build
cargo test             # run all tests
cargo clippy           # lint
cargo fmt              # format
```

## Testing

Tests follow the test pyramid:

- **Unit tests** — inline in the `src/` modules via `#[cfg(test)]`, fast and
  isolated; domain-layer fixtures live in `src/core/test_utils.rs`.
- **Integration tests** — black-box tests in `tests/` that drive the real CLI
  via `assert_cmd`; `lib_api.rs` covers the library API.

Example programs complement the tests:

```bash
cargo run --example manage      # demonstrates add → list → remove on a temp directory (no side effects)
cargo run --example add_skill   # installs into your real environment via the Manager
```

## Design trade-offs

- **Minimal and stable** — deliberately kept small and stable, with
  cross-platform care (macOS, Linux, Windows).
- **Pure data** — the library never prints, never calls `process::exit`;
  results are structured and errors surface through `Result`.
- **No telemetry** — no data ever leaves the user's machine.

## Releasing

Releases to crates.io always go through GitHub Actions (see
`.github/workflows/`) — never run `cargo publish` manually. Before releasing,
make sure the `version` in `Cargo.toml` has been bumped according to semantic
versioning, update the version numbers and API changes described in the
[README](../README.md) / [CLI.md](CLI.md) / [LIBRARY.md](LIBRARY.md), and keep
the Chinese translations (the `*.zh-CN.md` files alongside each document) in
sync.