# Migration Guide: ops-dev to Skills Flake Input **Objective**: Migrate ops-dev VM from local skill copies to consuming skills via Nix flake input **Current State**: tufte-press and worklog copied locally to `~/proj/ops-dev/skills/` **Target State**: All skills consumed from `dan/skills` flake input **Philosophy**: Skills repo is single source of truth ## Prerequisites - [x] Skills repo deployed to Forgejo: `http://192.168.1.108:3000/dan/skills` - [x] Skills repo has working flake with ai-skills module - [x] ops-dev VM running NixOS with flake-based configuration - [x] SSH access to ops-dev VM (192.168.1.73) ## Migration Steps ### Step 1: Add Skills Flake Input **File**: `~/proj/ops-dev/flake.nix` **Choose input URL based on your use case**: **Option A: Local path (recommended for development)**: ```nix { description = "ops-dev NixOS configuration"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; # Local path - works offline, great for development skills = { url = "path:/home/dan/proj/skills"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, skills }: { # ... rest of config }; } ``` **Option B: Git URL (for remote deployment)**: ```nix { description = "ops-dev NixOS configuration"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; # Git URL - explicit versioning, works remotely skills = { url = "git+http://192.168.1.108:3000/dan/skills.git"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, skills }: { # ... rest of config }; } ``` **When to use which**: - **`path:`** - Local development machine, offline work, fast iteration - **`git+http:`** - Remote VMs, explicit version control, shared deployments **Why `inputs.nixpkgs.follows`?** Ensures skills flake uses the same nixpkgs as ops-dev, avoiding duplicate dependencies and reducing closure size. **Network dependency note**: Both approaches fetch to `/nix/store` once, then work offline. Use `nix flake prefetch` to pre-cache. ### Step 2: Import ai-skills Module **File**: `~/proj/ops-dev/flake.nix` **In nixosConfigurations.dev.modules**: ```nix nixosConfigurations.dev = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ ./configuration.nix # Import skills module skills.nixosModules.ai-skills # Configure skills { services.ai-skills = { enable = true; selectedSkills = [ "tufte-press" "worklog" # Add more skills as needed: # "screenshot-latest" # "niri-window-capture" ]; deployTargets = [ "claude" "opencode" ]; }; } ]; }; ``` ### Step 3: Remove Local Skills Configuration **File**: `~/proj/ops-dev/flake.nix` **Remove these sections** (if present): ```nix # DELETE: Old local skills deployment environment.etc."opencode/skills" = { source = ./skills; }; environment.etc."claude/skills" = { source = ./skills; }; # DELETE: Old symlink activation script system.activationScripts.skills-symlinks = { text = '' # ... old symlink code ... ''; deps = [ "etc" ]; }; ``` **Why remove?** The ai-skills module handles all skill deployment. Keeping old config creates conflicts. ### Step 4: Remove Local Skills Directory **Commands** (on development machine): ```bash cd ~/proj/ops-dev # Backup first (just in case) tar czf skills-backup-$(date +%Y%m%d).tar.gz skills/ # Remove local skills rm -rf skills/ # Commit the change git add -A git commit -m "Switch to skills repo flake input - Add skills flake input from Forgejo - Import ai-skills NixOS module - Remove local skill copies (now from flake) - Enable tufte-press and worklog skills " ``` ### Step 5: Update Flake Lock **Command**: ```bash cd ~/proj/ops-dev nix flake lock ``` **This creates/updates** `flake.lock` with: - Skills repo commit hash - Input dependencies - Reproducible versions **Check the lock file**: ```bash cat flake.lock | jq '.nodes.skills' ``` Should show: ```json { "locked": { "lastModified": 1234567890, "narHash": "sha256-...", "ref": "refs/heads/master", "rev": "abc123...", "type": "git", "url": "http://192.168.1.108:3000/dan/skills.git" } } ``` ### Step 6: Deploy to VM **Option A: Via SCP (current method)**: ```bash # Copy updated config to VM scp -i ~/.ssh/id_ed25519_2025 flake.nix flake.lock root@192.168.1.73:/home/dev/ops-dev/ # Rebuild on VM ssh root@192.168.1.73 "cd /home/dev/ops-dev && nixos-rebuild switch --flake .#dev" ``` **Option B: Via Git (cleaner)**: ```bash # Push to Forgejo git push origin master # Pull and rebuild on VM ssh root@192.168.1.73 "cd /home/dev/ops-dev && git pull && nixos-rebuild switch --flake .#dev" ``` ### Step 7: Verify Deployment **Check skills are deployed**: ```bash ssh dev@192.168.1.73 "ls -la /etc/opencode/skills/" # Should show: tufte-press, worklog ssh dev@192.168.1.73 "ls -la /etc/claude/skills/" # Should show: tufte-press, worklog ssh dev@192.168.1.73 "cat /etc/opencode/skills/tufte-press/SKILL.md | head -5" # Should show skill content ``` **Check symlinks in user home**: ```bash ssh dev@192.168.1.73 "ls -la ~/.config/opencode/skills" # Should be symlink to /etc/opencode/skills ssh dev@192.168.1.73 "ls -la ~/.claude/skills" # Should be symlink to /etc/claude/skills ``` **Verify with agents** (if opencode-skills plugin installed): ```bash ssh dev@192.168.1.73 cd ~/some-project opencode # or claude-code # In agent, try: # "What skills are available?" # "Use tufte-press skill" ``` ## Updating Skills ### When Skills Repo Changes **Update to latest**: ```bash cd ~/proj/ops-dev # Update skills input to latest commit nix flake lock --update-input skills # Check what changed git diff flake.lock # Deploy to VM ssh root@192.168.1.73 "cd /home/dev/ops-dev && nixos-rebuild switch --flake .#dev" ``` ### Pin to Specific Commit **Lock to a known-good version**: ```bash cd ~/proj/ops-dev # Update flake.nix input to specific commit nix flake lock --override-input skills git+http://192.168.1.108:3000/dan/skills.git?rev=abc123... # Or edit flake.nix: inputs.skills.url = "git+http://192.168.1.108:3000/dan/skills.git?rev=abc123..."; ``` ### Add New Skills **Edit ops-dev flake.nix**: ```nix services.ai-skills = { enable = true; selectedSkills = [ "tufte-press" "worklog" "screenshot-latest" # Add new skill ]; deployTargets = [ "claude" "opencode" ]; }; ``` Then rebuild: ```bash ssh root@192.168.1.73 "cd /home/dev/ops-dev && nixos-rebuild switch --flake .#dev" ``` ## Rollback Plan ### If Migration Fails **Restore local skills**: ```bash cd ~/proj/ops-dev # Extract backup tar xzf skills-backup-YYYYMMDD.tar.gz # Revert flake.nix changes git revert HEAD # Rebuild with old config ssh root@192.168.1.73 "cd /home/dev/ops-dev && nixos-rebuild switch --flake .#dev" ``` ### If Specific Skill Broken **Remove from selectedSkills**: ```nix services.ai-skills = { enable = true; selectedSkills = [ "tufte-press" # "worklog" # Temporarily disabled ]; }; ``` **Or pin skills input to older commit**: ```bash nix flake lock --override-input skills git+http://192.168.1.108:3000/dan/skills.git?rev= ``` ## Troubleshooting ### Issue: "error: getting status of '/nix/store/.../skills': No such file or directory" **Cause**: Skills flake not properly fetched **Solution**: ```bash cd ~/proj/ops-dev nix flake lock --update-input skills ssh root@192.168.1.73 "cd /home/dev/ops-dev && nix flake update" ``` ### Issue: "error: attribute 'nixosModules.ai-skills' missing" **Cause**: Skills repo doesn't export the module **Solution**: ```bash # Check skills repo exports cd ~/proj/skills nix flake show # Should see: # └───nixosModules # └───ai-skills: NixOS module ``` ### Issue: Skills not appearing in /etc/opencode/skills **Cause**: Module not properly enabled or paths wrong **Check**: ```bash ssh root@192.168.1.73 "systemctl status" ssh root@192.168.1.73 "ls -la /etc/opencode/" ssh root@192.168.1.73 "readlink -f /etc/opencode/skills/tufte-press" # Should point to /nix/store/.../tufte-press ``` **Debug**: ```bash # Check what the module evaluated to ssh root@192.168.1.73 "nixos-option services.ai-skills" ``` ### Issue: Permission denied accessing skills **Cause**: Wrong ownership on symlinks **Solution**: Module should handle this, but manually fix: ```bash ssh root@192.168.1.73 "chown -h dev:users ~/.config/opencode/skills ~/.claude/skills" ``` ## Benefits After Migration ### Before (Local Copy) - ❌ Manual sync between repos required - ❌ Risk of divergence - ❌ No version control of deployment - ❌ Changes require copying files and rebuilding - ❌ Unclear which version is deployed ### After (Flake Input) - ✅ Single source of truth (skills repo) - ✅ Version controlled via flake.lock - ✅ Automatic updates via `nix flake lock --update-input skills` - ✅ Can pin to specific commits - ✅ Declarative deployment - ✅ Same pattern for all consuming projects - ✅ Reproducible builds ## Related Documentation - `NIX-FLAKE-USAGE.md` - How to consume the skills flake - `CROSS-REPO-SKILL-COLLABORATION.md` - Collaboration patterns - `modules/ai-skills.nix` - Module implementation details - `flake.nix` - Skills repo flake definition ## Next Steps After Migration 1. **Test thoroughly** - Verify all skills work in both Claude and OpenCode 2. **Document for team** - Update ops-dev README with new pattern 3. **Apply to other VMs** - Use same pattern for other NixOS systems 4. **Establish update cadence** - How often to update skills input? 5. **Monitor for issues** - Watch for skill loading problems