skills/docs/MIGRATION-GUIDE-ops-dev.md
dan 5fea49b7c0 feat(tufte-press): evolve skill to complete workflow with JSON generation and build automation
- Transform tufte-press from reference guide to conversation-aware generator
- Add JSON generation from conversation context following strict schema
- Create build automation scripts with Nix environment handling
- Integrate CUPS printing with duplex support
- Add comprehensive workflow documentation

Scripts added:
- skills/tufte-press/scripts/generate-and-build.sh (242 lines)
- skills/tufte-press/scripts/build-card.sh (23 lines)

Documentation:
- Updated SKILL.md with complete workflow instructions (370 lines)
- Updated README.md with usage examples (340 lines)
- Created SKILL-DEVELOPMENT-STRATEGY-tufte-press.md (450 lines)
- Added worklog: 2025-11-10-tufte-press-skill-evolution.org

Features:
- Agent generates valid JSON from conversation
- Schema validation before build (catches errors early)
- Automatic Nix shell entry for dependencies
- PDF build via tufte-press toolchain
- Optional print with duplex support
- Self-contained margin notes enforced
- Complete end-to-end testing

Workflow: Conversation → JSON → Validate → Build → Print

Related: niri-window-capture, screenshot-latest, worklog skills
2025-11-10 15:03:44 -08:00

9.5 KiB

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

  • Skills repo deployed to Forgejo: http://192.168.1.108:3000/dan/skills
  • Skills repo has working flake with ai-skills module
  • ops-dev VM running NixOS with flake-based configuration
  • 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):

{
  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):

{
  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:

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):

# 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):

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:

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:

cat flake.lock | jq '.nodes.skills'

Should show:

{
  "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):

# 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):

# 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:

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:

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):

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:

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:

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:

services.ai-skills = {
  enable = true;
  selectedSkills = [
    "tufte-press"
    "worklog"
    "screenshot-latest"  # Add new skill
  ];
  deployTargets = [ "claude" "opencode" ];
};

Then rebuild:

ssh root@192.168.1.73 "cd /home/dev/ops-dev && nixos-rebuild switch --flake .#dev"

Rollback Plan

If Migration Fails

Restore local skills:

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:

services.ai-skills = {
  enable = true;
  selectedSkills = [
    "tufte-press"
    # "worklog"  # Temporarily disabled
  ];
};

Or pin skills input to older commit:

nix flake lock --override-input skills git+http://192.168.1.108:3000/dan/skills.git?rev=<old-working-commit>

Troubleshooting

Issue: "error: getting status of '/nix/store/.../skills': No such file or directory"

Cause: Skills flake not properly fetched

Solution:

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:

# 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:

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:

# 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:

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
  • 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