#+TITLE: Per-Repo Skill Deployment: Design and RFC #+DATE: 2025-11-30 #+KEYWORDS: skills, per-repo, direnv, nix, deployment, rfc, beads, manifest #+COMMITS: 0 (uncommitted work) #+COMPRESSION_STATUS: uncompressed * Session Summary ** Date: 2025-11-30 (Sunday) ** Focus Area: Designing and documenting per-repo skill deployment pattern * Accomplishments - [X] Explored skills repository structure and identified 9 outstanding issues - [X] Populated beads issue tracker with all identified work items - [X] Set up dependency relationships between design decisions and documentation tasks - [X] Fixed ai-skills.nix module - removed broken opencode-skills npm plugin code - [X] Updated flake.nix to include all 8 skills (was missing update-opencode, web-search, web-research) - [X] Designed per-repo skill deployment pattern using direnv + nix build - [X] Created bin/use-skills.sh helper script with use_skill, use_skills, load_skills_from_manifest - [X] Created docs/PER-REPO-SKILLS.md with quick start documentation - [X] Created docs/RFC-SKILLS-MANIFEST.md with full pattern specification - [X] Introduced .skills manifest file concept for agent-friendly skill configuration - [ ] Survey existing repos for .envrc patterns (next step) - [ ] Migrate pilot project to new pattern * Key Decisions ** Decision 1: Per-repo skills via direnv + nix build (not devShell) - Context: User has Nix but wanted something lighter than full flake.nix in each consumer project - Options considered: 1. Home Manager module - writes to global ~/.claude/skills/, no per-repo differentiation 2. devShell symlinks - requires flake.nix in every consumer project 3. direnv + nix build - lighter, just add to .envrc - Rationale: direnv already used in many repos, nix build caches builds, no new files needed - Impact: Each project can specify its own skill set via .envrc or .skills file ** Decision 2: .skills manifest file for agent editing - Context: Agent needs to be able to add/query skills without bloating context - Options considered: 1. Agent edits .envrc directly - fragile, .envrc has other content 2. Central config mapping repos to skills - indirection, sync complexity 3. Separate .skills file - clean for agent editing, .envrc reads it - Rationale: .skills is simple text (one skill per line), easy for agent to read/modify - Impact: Agent can answer "what skills do we have?" by reading .skills, can add skills by appending ** Decision 3: Keep both Claude Code and OpenCode support - Context: Asked whether to simplify to Claude Code only - Decision: Keep dual-agent support - Rationale: Infrastructure already supports both, minimal extra complexity - Impact: Skills symlinked to both .claude/skills/ and .opencode/skills/ ** Decision 4: Always latest from skills repo (no version pinning) - Context: User preference for simplicity over reproducibility here - Decision: Default to latest, optional rev pinning if needed - Impact: nix build fetches latest, caches locally for performance * Problems & Solutions | Problem | Solution | Learning | |---------|----------|----------| | ai-skills.nix had broken fetchFromNpm with empty sha256 | Removed entire opencode-skills npm plugin section | Keep modules simple, remove dead code | | availableSkills list in flake.nix was stale | Added update-opencode, web-search, web-research | Need process to keep lists in sync | | bd dep syntax confusion (from vs to) | bd dep add A B means "A depends on B" not "A blocks B" | Read help output carefully | | Home Manager module writes to global paths, not per-repo | Per-repo uses .claude/skills/ in project, not global | Different deployment targets, different mechanisms | * Technical Details ** Code Changes - Total files modified: 2 existing + 3 new - Key files changed: - `modules/ai-skills.nix` - Removed 60 lines of broken npm plugin code, updated skill list in docs - `flake.nix` - Added 3 skills to availableSkills list - New files created: - `bin/use-skills.sh` - Helper script with use_skill, use_skills, load_skills_from_manifest functions - `docs/PER-REPO-SKILLS.md` - Quick start documentation for per-repo deployment - `docs/RFC-SKILLS-MANIFEST.md` - Full RFC documenting the .skills manifest pattern ** Commands Used #+begin_src bash # Beads workflow bd ready # See available work bd create --title="..." --type=task --description="..." bd update --status=in_progress bd close --reason="..." bd dep add # from depends on to bd list bd stats # Nix validation nix flake check # Verified all packages build # Skill deployment pattern nix build --print-out-paths --no-link "git+ssh://...#worklog" ln -sfn "$out" ".claude/skills/worklog" #+end_src ** Architecture Notes - Skills repo flake exports individual packages per skill - Consumer projects don't need flake.nix, just .envrc with nix build calls - Symlinks point to /nix/store paths - Claude Code follows them fine - .skills manifest is committed, .claude/skills/ symlinks are gitignored - Brief context blurb in project CLAUDE.md tells agent about skills (~4 lines) * Process and Workflow ** What Worked Well - Beads for tracking issues - good visibility into work items - Plan mode for thinking through architecture before coding - Iterative questioning to clarify user requirements (Nix available? Source of truth?) - "Ultrathink" prompt to go deeper on design questions ** What Was Challenging - Initial confusion about what "per-repo" meant (global HM module vs project-local) - Getting beads dependency direction right (had to remove and re-add) - Balancing thoroughness with "don't overengineer" guidance * Learning and Insights ** Technical Insights - Claude Code loads skills from both ~/.claude/skills/ (global) AND .claude/skills/ (project-local) - Project-local skills add to or shadow global - good for per-repo customization - nix build --print-out-paths gives store path without building if cached - direnv + nix build is lighter than devShell for simple cases ** Process Insights - "Ultrathink" is a good trigger for deeper analysis - Questioning assumptions early ("do you need flake.nix in every project?") saves design churn - Agent-friendly design (like .skills manifest) is worth thinking about explicitly ** Architectural Insights - Separation of concerns: manifest (.skills) vs loader (.envrc) vs runtime (symlinks) - Agent context efficiency: brief blurb in CLAUDE.md, not full skill docs - The .skills file serves multiple purposes: human config, agent query, agent edit * Context for Future Work ** Open Questions - Should we validate skill names? Currently fails silently if skill doesn't exist - Should we support skill versions? e.g., `worklog@v1.2.0` - Should there be a `skills` CLI? e.g., `skills add worklog`, `skills list` - How to handle skills that need secrets (like web-research with KAGI_API_KEY)? ** Next Steps - Survey existing repos for .envrc patterns - Migrate pilot project to new .skills pattern - Clean up beads.left.jsonl merge artifact - Commit and push this session's work ** Related Work - Previous: [[file:2025-11-09-nix-flake-module-development-opencode-skills-integration.org][Nix Flake Module Development]] - original HM module design - Previous: [[file:2025-11-22-create-web-search-skill.org][Create Web Search Skill]] - skill that motivated this work - Related: docs/CROSS-REPO-SKILL-COLLABORATION.md - Nix flake input pattern (for HM deployments) - Created: docs/RFC-SKILLS-MANIFEST.md - this session's main artifact * Raw Notes Beads status at session end: - 4 closed: skills-3o7 (nix fix), skills-pu4 (cleanup), skills-cnc (helper), skills-39g (RFC) - 7 open: README updates, design decisions, code review items Key insight: The question "how does an agent help configure skills?" led to the .skills manifest design. Agent-friendly != human-friendly, need both. The pattern is intentionally minimal: 1. .skills file lists skill names 2. .envrc reads .skills and symlinks 3. CLAUDE.md tells agent about available skills 4. Agent can read/edit .skills, tell user to direnv reload * Session Continuation: Pilot Migration and Flow Design ** Pilot Migration: orch Successfully migrated orch project as pilot for .skills pattern: - Created `.skills` manifest with `worklog` - Updated `.envrc` to source helper and call `load_skills_from_manifest` - Updated `.gitignore` to exclude `.claude/skills/` and `.opencode/skills/` - Added Skills section to `AGENTS.md` ** Technical Fix: Local Nix Build - Original default URL `git+ssh://git@forgejo.delmore.io/dan/skills.git` didn't resolve - Changed to `git+file://$HOME/proj/skills` for offline/local development - `path:` scheme failed due to `.beads/bd.sock` (unsupported file type) - `git+file://` only includes git-tracked files, works correctly ** Verified Working #+begin_src orch/.claude/skills/worklog -> /nix/store/...-ai-skill-worklog orch/.opencode/skills/worklog -> /nix/store/...-ai-skill-worklog #+end_src ** Dotfiles Analysis Explored how dotfiles manages Claude Code: - `home/claude.nix` deploys 4 skills via Home Manager - `~/.claude/settings.json` has `bd prime` hooks (global, not Nix-managed) - Drift: dotfiles has 4 skills, skills repo has 8 - Global skills come from dotfiles copy, per-repo from skills repo directly ** Flow Design Discussion Identified need to simplify per-repo flow. Current requires 4 file changes. Options discussed: 1. Global direnv helper (add `load_project_skills` to direnvrc) 2. CLI tool (`skills init`, `skills add`) 3. Convention over configuration (auto-load if `.skills` exists) Direction: Simplify with global direnv helper + team-facing RFC. * Session Metrics - Commits made: 0 (uncommitted) - Files touched: 7+ (skills repo + orch pilot) - Lines added/removed: ~500 lines new content - New documentation: RFC-SKILLS-MANIFEST.md, PER-REPO-SKILLS.md - Beads created: 9 issues - Beads closed: 4 issues - Pilot project: orch migrated successfully