diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..807d598 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ + +# Use bd merge for beads JSONL files +.beads/issues.jsonl merge=beads diff --git a/bin/use-skills.sh b/bin/use-skills.sh new file mode 100755 index 0000000..79b08e5 --- /dev/null +++ b/bin/use-skills.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +# Helper for per-repo skill deployment via direnv +# Source this from your .envrc or copy the functions +# +# Usage in .envrc: +# source /path/to/skills/bin/use-skills.sh +# use_skills worklog web-search +# +# Or without sourcing (copy-paste into .envrc): +# SKILLS_REPO="git+ssh://git@forgejo.example/dan/skills.git" +# use_skill() { ... } +# use_skill worklog + +# Default repo - uses local git, override with SKILLS_REPO for remote +# Local: git+file:///home/dan/proj/skills (default, works offline) +# Network: git+http://192.168.1.108:3000/dan/skills.git +SKILLS_REPO="${SKILLS_REPO:-git+file://$HOME/proj/skills}" + +# Install a single skill via nix build + symlink +use_skill() { + local skill="$1" + local out + + out=$(nix build --print-out-paths --no-link "${SKILLS_REPO}#${skill}" 2>/dev/null) + if [[ -z "$out" ]]; then + echo "use_skill: failed to build ${skill}" >&2 + return 1 + fi + + # Claude Code + if [[ -d .claude ]] || [[ -n "${SKILLS_CLAUDE:-}" ]]; then + mkdir -p .claude/skills + ln -sfn "$out" ".claude/skills/${skill}" + fi + + # OpenCode + if [[ -d .opencode ]] || [[ -n "${SKILLS_OPENCODE:-}" ]]; then + mkdir -p .opencode/skills + ln -sfn "$out" ".opencode/skills/${skill}" + fi + + echo "use_skill: ${skill} -> ${out}" +} + +# Install multiple skills +use_skills() { + # Ensure at least one target exists + mkdir -p .claude/skills .opencode/skills + + for skill in "$@"; do + use_skill "$skill" + done +} + +# Load skills from .skills manifest file +load_skills_from_manifest() { + [[ ! -f .skills ]] && return 0 + mkdir -p .claude/skills .opencode/skills + + while IFS= read -r skill || [[ -n "$skill" ]]; do + # Skip empty lines and comments + [[ -z "$skill" || "$skill" =~ ^[[:space:]]*# ]] && continue + # Strip inline comments and whitespace + skill="${skill%%#*}" + skill="${skill// /}" + [[ -n "$skill" ]] && use_skill "$skill" + done < .skills +} diff --git a/docs/PER-REPO-SKILLS.md b/docs/PER-REPO-SKILLS.md new file mode 100644 index 0000000..64dd9c2 --- /dev/null +++ b/docs/PER-REPO-SKILLS.md @@ -0,0 +1,144 @@ +# Per-Repo Skill Deployment + +Deploy selected skills to individual projects using direnv + Nix. + +## Overview + +Each project can declare which skills it needs. When team members enter the directory (via direnv), skills are symlinked from the Nix store into `.claude/skills/` and `.opencode/skills/`. + +``` +teammate clones repo + ↓ + direnv allow + ↓ + nix builds skills (cached) + ↓ + symlinks created in .claude/skills/ + ↓ + Claude Code sees project-local skills +``` + +## Quick Start + +### 1. Add to `.envrc` + +**Option A: Source the helper** (if skills repo is accessible) +```bash +source ~/proj/skills/bin/use-skills.sh +use_skills worklog web-search +``` + +**Option B: Self-contained** (copy-paste, no external dependency) +```bash +# AI Agent Skills +SKILLS_REPO="git+file://$HOME/proj/skills" # or git+http://... for remote + +use_skill() { + local skill="$1" + local out + out=$(nix build --print-out-paths --no-link "${SKILLS_REPO}#${skill}" 2>/dev/null) + if [[ -n "$out" ]]; then + mkdir -p .claude/skills .opencode/skills + ln -sfn "$out" ".claude/skills/${skill}" + ln -sfn "$out" ".opencode/skills/${skill}" + echo "use_skill: ${skill}" + fi +} + +use_skill worklog +use_skill web-search +``` + +### 2. Add to `.gitignore` + +``` +.claude/skills/ +.opencode/skills/ +``` + +### 3. Done + +Team members clone and run `direnv allow`. Skills appear. + +## Available Skills + +Run `nix flake show git+ssh://git@forgejo.delmore.io/dan/skills.git` to see all available skills. + +Current list: +- `worklog` - Create org-mode worklogs +- `web-search` - Search the web via Claude +- `web-research` - Deep research with multiple backends +- `update-opencode` - Update OpenCode via Nix +- `update-spec-kit` - Update spec-kit ecosystem +- `niri-window-capture` - Capture window screenshots +- `screenshot-latest` - Find latest screenshots +- `tufte-press` - Generate study card JSON + +## How It Works + +1. **direnv** triggers on directory entry +2. **nix build** fetches/builds the skill package (cached locally) +3. **symlink** points `.claude/skills/` to `/nix/store/xxx-ai-skill-` +4. **Claude Code** reads skills from `.claude/skills/` when in that directory + +Skills are always fetched from the latest commit on the skills repo. Nix caches builds locally, so subsequent loads are fast. + +## Customization + +### Different skills per project + +```bash +# Project A - .envrc +use_skill worklog +use_skill web-search + +# Project B - .envrc +use_skill worklog +use_skill tufte-press +``` + +### Claude Code only (no OpenCode) + +```bash +SKILLS_REPO="git+file://$HOME/proj/skills" +mkdir -p .claude/skills +for skill in worklog web-search; do + ln -sfn $(nix build --print-out-paths --no-link "${SKILLS_REPO}#${skill}") ".claude/skills/${skill}" +done +``` + +### Pin to specific version + +```bash +SKILLS_REPO="git+file://$HOME/proj/skills?rev=abc123def" # pin to commit +use_skill worklog # uses pinned revision +``` + +## Troubleshooting + +### Skills not appearing + +1. Check `direnv allow` was run +2. Check `.claude/skills/` exists and has symlinks +3. Restart Claude Code (it loads skills at startup) + +### nix build fails + +1. Check network access to skills repo +2. Check `nix flake show $SKILLS_REPO` works +3. Check skill name is correct + +### Symlinks broken after nix-collect-garbage + +Re-run `direnv reload` to rebuild and re-link. + +## Comparison with Global Skills + +| Aspect | Global (~/.claude/skills/) | Per-Repo (.claude/skills/) | +|--------|---------------------------|---------------------------| +| Scope | All projects | Single project | +| Deployment | Nix Home Manager | direnv + nix build | +| Team sharing | Via dotfiles | Via project .envrc | +| Selection | User-wide | Per-project | + +Use global for personal defaults. Use per-repo for project-specific or team-shared skills. diff --git a/docs/RFC-SKILLS-MANIFEST.md b/docs/RFC-SKILLS-MANIFEST.md new file mode 100644 index 0000000..5d1a6bb --- /dev/null +++ b/docs/RFC-SKILLS-MANIFEST.md @@ -0,0 +1,234 @@ +# 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 \ No newline at end of file diff --git a/docs/RFC-TEAM-SKILLS-ADOPTION.md b/docs/RFC-TEAM-SKILLS-ADOPTION.md new file mode 100644 index 0000000..120bb02 --- /dev/null +++ b/docs/RFC-TEAM-SKILLS-ADOPTION.md @@ -0,0 +1,133 @@ +# RFC: Per-Project AI Agent Skills + +**Status**: Proposal +**Date**: 2025-11-30 +**Audience**: All project teams using Claude Code or OpenCode + +## Summary + +A standard pattern for projects to declare which AI agent skills they need. Team members automatically get the right skills when they clone and enter the project directory. + +## Problem + +Currently, AI agent skills are deployed globally to everyone's machine. This means: +- All projects get all skills, whether they need them or not +- No way to share project-specific skills with teammates +- No visibility into what skills a project uses + +## Solution + +Projects declare their skills in a `.skills` file. When you enter the directory (via direnv), the skills are automatically installed. + +``` +# .skills +worklog +web-search +``` + +That's it. Clone the repo, run `direnv allow`, and you have the skills. + +## How It Works + +``` +You clone a repo with .skills file + ↓ +Run `direnv allow` + ↓ +direnv reads .skills, builds each skill via Nix + ↓ +Skills symlinked to .claude/skills/ and .opencode/skills/ + ↓ +Claude Code / OpenCode sees the skills +``` + +Skills come from the central skills repo (`~/proj/skills`), so everyone gets the same version. + +## Available Skills + +| Skill | Description | +|-------|-------------| +| `worklog` | Create org-mode worklogs documenting sessions | +| `web-search` | Search the web via Claude subprocess | +| `web-research` | Deep research with multiple backends | +| `update-opencode` | Update OpenCode version via Nix | +| `niri-window-capture` | Capture window screenshots (security-sensitive) | +| `tufte-press` | Generate Tufte-style study cards | + +## Adopting This Pattern + +### 1. Create `.skills` file + +```bash +echo "worklog" > .skills +``` + +### 2. Update `.envrc` + +Add to your project's `.envrc`: + +```bash +# AI Agent Skills +if [[ -f .skills ]]; then + source ~/proj/skills/bin/use-skills.sh + load_skills_from_manifest +fi +``` + +### 3. Update `.gitignore` + +```bash +echo ".claude/skills/" >> .gitignore +echo ".opencode/skills/" >> .gitignore +``` + +### 4. (Optional) Add agent context + +Add to your `AGENTS.md` or `CLAUDE.md`: + +```markdown +## Skills + +This project uses AI agent skills declared in `.skills`. +- **Installed**: See `.skills` +- **To add**: Edit `.skills`, run `direnv reload` +``` + +### 5. Commit and share + +```bash +git add .skills .envrc .gitignore +git commit -m "Add AI agent skills support" +``` + +Teammates will get the skills when they `direnv allow`. + +## FAQ + +**Q: Do I need Nix?** +A: Yes. Skills are built via Nix for reproducibility. + +**Q: What if I'm offline?** +A: Works fine. Skills build from the local `~/proj/skills` repo. + +**Q: Can I pin a specific version?** +A: Yes. Use `SKILLS_REPO="git+file://$HOME/proj/skills?rev=abc123"` in your `.envrc`. + +**Q: What if a skill doesn't exist?** +A: The build will fail silently for that skill. Check the name matches a skill in the repo. + +**Q: How do I see what skills are installed?** +A: `ls .claude/skills/` or `cat .skills` + +**Q: How do I add a skill after setup?** +A: Edit `.skills`, then run `direnv reload`. + +## Future Improvements + +1. **Global direnv helper** - Add `load_project_skills` to `~/.config/direnv/direnvrc` so `.envrc` only needs one line +2. **CLI tool** - `skills init` to set up a project, `skills add ` to add skills +3. **Validation** - Warn if a skill name doesn't exist + +## Questions / Feedback + +Open an issue in the skills repo or ask in the team channel. diff --git a/docs/worklogs/2025-11-30-per-repo-skill-deployment-design.org b/docs/worklogs/2025-11-30-per-repo-skill-deployment-design.org new file mode 100644 index 0000000..098f751 --- /dev/null +++ b/docs/worklogs/2025-11-30-per-repo-skill-deployment-design.org @@ -0,0 +1,211 @@ +#+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 diff --git a/flake.nix b/flake.nix index 12e68ef..78a676e 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,9 @@ "tufte-press" "worklog" "update-spec-kit" + "update-opencode" + "web-search" + "web-research" ]; in flake-utils.lib.eachDefaultSystem diff --git a/modules/ai-skills.nix b/modules/ai-skills.nix index 0f2a38e..4462e45 100644 --- a/modules/ai-skills.nix +++ b/modules/ai-skills.nix @@ -4,22 +4,6 @@ with lib; let cfg = config.services.ai-skills; - - # Helper to install opencode-skills npm package - opencodeSkillsPlugin = pkgs.buildNpmPackage rec { - pname = "opencode-skills"; - version = "0.1.0"; - - src = pkgs.fetchFromNpm { - name = pname; - version = version; - sha256 = ""; # TODO: Get actual hash - }; - - # Alternative: install from npm directly at runtime - # This is a placeholder - actual implementation would fetch from npm - }; - in { options.services.ai-skills = { enable = mkEnableOption "AI agent skills for Claude Code and OpenCode"; @@ -34,8 +18,11 @@ in { - tufte-press: Generate study card JSON - worklog: Create org-mode worklogs - update-spec-kit: Update spec-kit ecosystem + - update-opencode: Update OpenCode via Nix + - web-search: Search the web via Claude + - web-research: Deep web research with multiple backends ''; - example = [ "worklog" "screenshot-latest" ]; + example = [ "worklog" "web-search" ]; }; skillsPath = mkOption { @@ -55,12 +42,6 @@ in { default = true; description = "Deploy skills to OpenCode (~/.config/opencode/skills/)"; }; - - installOpencodePlugin = mkOption { - type = types.bool; - default = true; - description = "Install opencode-skills npm plugin"; - }; }; config = mkIf cfg.enable { @@ -91,43 +72,6 @@ in { }) cfg.skills ) )) - - # OpenCode plugin installation - (mkIf (cfg.enableOpenCode && cfg.installOpencodePlugin) { - ".config/opencode/package.json" = { - text = builtins.toJSON { - dependencies = { - "@opencode-ai/plugin" = "1.0.44"; - "opencode-skills" = "^0.1.0"; - }; - }; - }; - }) ]; - - # Ensure opencode-skills plugin is in config - home.activation.opencodeSkillsPlugin = mkIf (cfg.enableOpenCode && cfg.installOpencodePlugin) ( - lib.hm.dag.entryAfter [ "writeBoundary" ] '' - # Install npm dependencies for OpenCode - if [ -f "$HOME/.config/opencode/package.json" ]; then - cd "$HOME/.config/opencode" - if command -v bun &> /dev/null; then - ${pkgs.bun}/bin/bun install - elif command -v npm &> /dev/null; then - ${pkgs.nodejs}/bin/npm install - fi - fi - - # Ensure plugin is enabled in config - CONFIG_FILE="$HOME/.config/opencode/config.json" - if [ -f "$CONFIG_FILE" ]; then - # Check if plugin array includes opencode-skills - if ! ${pkgs.jq}/bin/jq -e '.plugin | index("opencode-skills")' "$CONFIG_FILE" &> /dev/null; then - echo "Warning: opencode-skills plugin not in config.json plugin array" - echo "Add it manually: { \"plugin\": [\"opencode-skills\"] }" - fi - fi - '' - ); }; }