# RFC: .skills Manifest Pattern **Status**: Draft **Created**: 2024-11-30 **Author**: dan + claude ## Summary A lightweight pattern for per-repo skill deployment where projects declare desired skills in a `.skills` manifest file. This enables: - Team members get skills on clone + `direnv allow` - Agents can query installed skills without loading full docs - Agents can install skills by editing the manifest - Central skills repo remains single source of truth ## Motivation ### Current State - Skills live in central `skills` repo - Global deployment via Nix Home Manager to `~/.claude/skills/` - Per-repo deployment undocumented and manual ### Problems 1. **No per-repo differentiation** - all projects get same global skills 2. **Agent context bloat** - loading full skill docs is expensive 3. **No standard pattern** - each project reinvents .envrc setup 4. **Agent can't help** - no standard way for agent to install skills ### Goals 1. Projects declare which skills they need 2. Team members get skills automatically (via direnv) 3. Agents can answer "what skills do we have?" 4. Agents can add skills with minimal context ## Design ### The `.skills` Manifest A simple text file in project root: ``` # .skills - AI agent skills for this project # Run `direnv reload` after editing worklog web-search ``` **Format**: - One skill name per line - Lines starting with `#` are comments - Empty lines ignored - Skill names match flake package names ### The `.envrc` Integration Projects add to their `.envrc`: ```bash # AI Agent Skills if [[ -f .skills ]]; then SKILLS_REPO="${SKILLS_REPO:-git+file://$HOME/proj/skills}" mkdir -p .claude/skills .opencode/skills while IFS= read -r skill || [[ -n "$skill" ]]; do [[ -z "$skill" || "$skill" =~ ^[[:space:]]*# ]] && continue skill="${skill%%#*}" # strip inline comments skill="${skill// /}" # strip whitespace out=$(nix build --print-out-paths --no-link "${SKILLS_REPO}#${skill}" 2>/dev/null) if [[ -n "$out" ]]; then ln -sfn "$out" ".claude/skills/${skill}" ln -sfn "$out" ".opencode/skills/${skill}" fi done < .skills fi ``` Or source the helper: ```bash if [[ -f .skills ]]; then source ~/proj/skills/bin/use-skills.sh load_skills_from_manifest fi ``` ### The `.gitignore` Entries ``` .claude/skills/ .opencode/skills/ ``` The manifest (`.skills`) IS committed. The symlinks are not. ### Agent Context Blurb Add to project's `CLAUDE.md` or `AGENTS.md`: ```markdown ## Skills This project uses AI agent skills. Skills are declared in `.skills` and installed via direnv. **Installed**: See `.skills` **Available**: worklog, web-search, web-research, update-opencode, update-spec-kit, niri-window-capture, screenshot-latest, tufte-press **To add**: Edit `.skills`, then run `direnv reload` **Docs**: See ~/proj/skills for full skill documentation ``` This gives the agent enough context (~4 lines) to: - Answer "what skills do we have?" → read `.skills` - Add a skill → edit `.skills`, tell user to `direnv reload` - Know where to find full docs if needed ## Workflow ### Initial Setup (one-time per project) 1. Create `.skills` with desired skills 2. Add skills loader to `.envrc` 3. Add `.claude/skills/` to `.gitignore` 4. Add brief context to project's CLAUDE.md 5. Commit ### Team Member Onboarding 1. Clone repo 2. Run `direnv allow` 3. Skills are installed automatically ### Adding a Skill **Human workflow**: 1. Edit `.skills`, add skill name 2. Run `direnv reload` **Agent-assisted workflow**: 1. Human: "add the worklog skill" 2. Agent: edits `.skills`, adds `worklog` 3. Agent: "Added worklog to .skills. Run `direnv reload` to install." ### Querying Skills **"What skills do we have?"** - Agent reads `.skills` file - Or runs `ls .claude/skills/` **"What skills are available?"** - Agent references the list in CLAUDE.md context - Or runs `nix flake show $SKILLS_REPO` ## File Locations ``` project/ ├── .skills # Manifest (committed) ├── .envrc # Loads skills from manifest (committed) ├── .gitignore # Ignores .claude/skills/ (committed) ├── CLAUDE.md # Agent context blurb (committed) ├── .claude/ │ └── skills/ # Symlinks to nix store (NOT committed) │ ├── worklog -> /nix/store/xxx │ └── web-search -> /nix/store/yyy └── .opencode/ └── skills/ # Same symlinks (NOT committed) ``` ## Helper Script `skills/bin/use-skills.sh` provides: ```bash # Load skills from .skills manifest load_skills_from_manifest() { [[ ! -f .skills ]] && return mkdir -p .claude/skills .opencode/skills while IFS= read -r skill || [[ -n "$skill" ]]; do [[ -z "$skill" || "$skill" =~ ^[[:space:]]*# ]] && continue use_skill "${skill%%#*}" done < .skills } ``` ## Migration ### Existing Projects 1. Survey current `.envrc` files for skill-related setup 2. Extract skill list to `.skills` 3. Replace custom logic with standard pattern 4. Add CLAUDE.md context blurb ### New Projects Use the template: ```bash cp ~/proj/skills/templates/skills-envrc-snippet.sh .envrc.skills cat .envrc.skills >> .envrc echo "worklog" > .skills echo ".claude/skills/" >> .gitignore ``` ## Alternatives Considered ### Full flake.nix in each project - Heavier than needed - Not all projects want/have flake.nix - Decided: .envrc + nix build is lighter ### Central config mapping repos to skills - Single view of all projects - But adds indirection and sync complexity - Decided: per-repo manifest is simpler ### Agent edits .envrc directly - Fragile - .envrc has other content - Decided: separate .skills file is cleaner for agent editing ## Open Questions 1. **Should we validate skill names?** Currently fails silently if skill doesn't exist. 2. **Should we support skill versions?** e.g., `worklog@v1.2.0` 3. **Should there be a `skills` CLI?** e.g., `skills add worklog`, `skills list` ## Implementation Checklist - [x] Create `bin/use-skills.sh` helper - [x] Create `docs/PER-REPO-SKILLS.md` documentation - [x] Create this RFC - [ ] Update `bin/use-skills.sh` with `load_skills_from_manifest` - [ ] Create template `.skills` file - [ ] Create template CLAUDE.md blurb - [ ] Survey existing projects for migration - [ ] Migrate pilot project - [ ] Update AGENTS.md with pattern reference