# Deployment Guide This guide covers all deployment methods for skills to both Claude Code and OpenCode. ## Quick Reference | Method | Use Case | Pros | Cons | |--------|----------|------|------| | Symlink | Active development | Live updates | Manual per-skill | | Copy | Testing specific version | Isolated | Must re-copy for updates | | Nix Home Manager | Production (NixOS) | Declarative, versioned | Requires rebuild | | Git Submodule | Multi-repo sharing | Centralized updates | More complexity | ## Method 1: Symlink Deployment (Development) Best for active development - changes in repo immediately available to agent. ### Claude Code ```bash # Single skill ln -s $(pwd)/skills/worklog ~/.claude/skills/worklog # All skills for skill in skills/*/; do skill_name=$(basename "$skill") if [ "$skill_name" != "template" ]; then ln -s "$(pwd)/skills/$skill_name" ~/.claude/skills/$skill_name fi done ``` ### OpenCode ```bash # Single skill ln -s $(pwd)/skills/worklog ~/.config/opencode/skills/worklog # All skills for skill in skills/*/; do skill_name=$(basename "$skill") if [ "$skill_name" != "template" ]; then ln -s "$(pwd)/skills/$skill_name" ~/.config/opencode/skills/$skill_name fi done ``` ### Verify Symlinks ```bash # Claude Code ls -la ~/.claude/skills/ # OpenCode ls -la ~/.config/opencode/skills/ ``` ### Remove Symlinks ```bash # Claude Code - single skill rm ~/.claude/skills/worklog # OpenCode - all skills (keeps directories, removes symlinks) find ~/.config/opencode/skills -type l -delete ``` ## Method 2: Copy Deployment (Testing) Best for testing specific versions without affecting your main deployment. ### Claude Code ```bash # Single skill cp -r skills/worklog ~/.claude/skills/ # All skills (excluding template) for skill in skills/*/; do skill_name=$(basename "$skill") if [ "$skill_name" != "template" ]; then cp -r "skills/$skill_name" ~/.claude/skills/ fi done ``` ### OpenCode ```bash # Single skill cp -r skills/worklog ~/.config/opencode/skills/ # All skills (excluding template) for skill in skills/*/; do skill_name=$(basename "$skill") if [ "$skill_name" != "template" ]; then cp -r "skills/$skill_name" ~/.config/opencode/skills/ fi done ``` ### Update After Changes ```bash # Must re-copy after making changes cp -r skills/worklog ~/.claude/skills/ cp -r skills/worklog ~/.config/opencode/skills/ ``` ## Method 3: Nix Home Manager (Production) Best for NixOS users - declarative, version-controlled, atomic deployments. ### Configuration Add to your `home.nix` or equivalent: ```nix { config, pkgs, ... }: { # Claude Code skills home.file.".claude/skills/worklog" = { source = /home/user/proj/skills/skills/worklog; recursive = true; }; home.file.".claude/skills/update-spec-kit" = { source = /home/user/proj/skills/skills/update-spec-kit; recursive = true; }; # OpenCode skills home.file.".config/opencode/skills/worklog" = { source = /home/user/proj/skills/skills/worklog; recursive = true; }; home.file.".config/opencode/skills/update-spec-kit" = { source = /home/user/proj/skills/skills/update-spec-kit; recursive = true; }; # OpenCode plugin configuration home.file.".config/opencode/config.json".text = builtins.toJSON { plugin = [ "opencode-skills" ]; # ... other config }; } ``` ### Deploy All Skills Programmatically For many skills, use a loop: ```nix { config, pkgs, lib, ... }: let skillsPath = /home/user/proj/skills/skills; # List of skills to deploy (exclude template) skills = [ "worklog" "update-spec-kit" # Add more skills here ]; # Generate home.file entries for a skill mkSkillDeployment = skillName: { ".claude/skills/${skillName}" = { source = "${skillsPath}/${skillName}"; recursive = true; }; ".config/opencode/skills/${skillName}" = { source = "${skillsPath}/${skillName}"; recursive = true; }; }; # Merge all skill deployments allSkillDeployments = lib.foldl' (acc: skill: acc // (mkSkillDeployment skill)) {} skills; in { home.file = allSkillDeployments // { # Other file configurations ".config/opencode/config.json".text = builtins.toJSON { plugin = [ "opencode-skills" ]; }; }; } ``` ### Apply Configuration ```bash # Home Manager standalone home-manager switch # NixOS with flake sudo nixos-rebuild switch --flake .#hostname # Test first sudo nixos-rebuild test --flake .#hostname ``` ### Rollback ```bash # Home Manager home-manager generations home-manager switch --rollback # NixOS sudo nixos-rebuild switch --rollback ``` ## Method 4: Git Submodule (Shared Projects) Best when multiple repositories need to share the same skills. ### Setup in Target Repository ```bash # In your project repository cd ~/proj/my-project # Add skills as submodule git submodule add https://github.com/yourusername/skills.git .skills # Initialize submodule git submodule update --init --recursive ``` ### Deploy from Submodule ```bash # Create deployment script: scripts/deploy-skills.sh #!/usr/bin/env bash set -euo pipefail SKILLS_DIR=".skills/skills" # Deploy to Claude Code for skill in "$SKILLS_DIR"/*; do skill_name=$(basename "$skill") if [ "$skill_name" != "template" ]; then ln -sf "$(realpath "$skill")" ~/.claude/skills/"$skill_name" fi done # Deploy to OpenCode for skill in "$SKILLS_DIR"/*; do skill_name=$(basename "$skill") if [ "$skill_name" != "template" ]; then ln -sf "$(realpath "$skill")" ~/.config/opencode/skills/"$skill_name" fi done echo "Skills deployed from submodule" ``` ### Update Submodule ```bash # Update to latest git submodule update --remote .skills # Or specific commit cd .skills git checkout main git pull cd .. git add .skills git commit -m "Update skills submodule" ``` ## OpenCode Plugin Setup OpenCode requires the `opencode-skills` plugin to discover skills. ### Manual Installation ```bash # Edit OpenCode config vim ~/.config/opencode/config.json ``` Add plugin: ```json { "plugin": ["opencode-skills"], "other-settings": "..." } ``` ### Verify Plugin Loaded ```bash # Start OpenCode and check for skills in output opencode # Or check logs for plugin loading # (Plugin installation happens on first start after config change) ``` ### Nix Configuration ```nix home.file.".config/opencode/config.json".text = builtins.toJSON { plugin = [ "opencode-skills" ]; }; ``` ## Verification ### Check Deployment ```bash # Claude Code ls -la ~/.claude/skills/ cat ~/.claude/skills/worklog/SKILL.md | head -5 # OpenCode ls -la ~/.config/opencode/skills/ cat ~/.config/opencode/skills/worklog/SKILL.md | head -5 ``` ### Test Skill Discovery **Claude Code:** ```bash # Start Claude Code claude # In chat, try triggering a skill # Example: "Create a worklog" ``` **OpenCode:** ```bash # Start OpenCode opencode # In chat, try triggering a skill # Example: "Document today's work" ``` ### Debug Discovery Issues **Claude Code:** - Check SKILL.md frontmatter is valid YAML - Verify file permissions are readable - Restart Claude Code - Check Claude logs (if available) **OpenCode:** - Verify opencode-skills plugin is installed - Check plugin loaded at startup - Restart OpenCode after config changes - Check SKILL.md frontmatter ## Multi-Environment Deployment Deploy same skills to multiple machines. ### Using Dotfiles Repository ```bash # In your dotfiles repo mkdir -p skills cd skills git submodule add https://github.com/yourusername/skills.git # Create deployment script in dotfiles cat > scripts/deploy-skills.sh << 'EOF' #!/usr/bin/env bash for skill in skills/skills/*; do skill_name=$(basename "$skill") [ "$skill_name" = "template" ] && continue ln -sf "$(realpath "$skill")" ~/.claude/skills/"$skill_name" ln -sf "$(realpath "$skill")" ~/.config/opencode/skills/"$skill_name" done EOF chmod +x scripts/deploy-skills.sh ``` ### Using Configuration Management **Ansible example:** ```yaml - name: Deploy agentic skills file: src: "{{ playbook_dir }}/skills/{{ item }}" dest: "~/.claude/skills/{{ item }}" state: link loop: - worklog - update-spec-kit ``` ## Cleanup ### Remove All Skills ```bash # Claude Code rm -rf ~/.claude/skills/* # OpenCode rm -rf ~/.config/opencode/skills/* ``` ### Remove Specific Skill ```bash # Claude Code rm -rf ~/.claude/skills/worklog # OpenCode rm -rf ~/.config/opencode/skills/worklog ``` ### Nix Cleanup Remove from `home.nix` and rebuild: ```bash # Edit home.nix to remove skill entries vim home.nix # Rebuild home-manager switch ``` ## Troubleshooting ### Symlink Target Not Found ```bash # Check symlink ls -la ~/.claude/skills/worklog # If broken, recreate rm ~/.claude/skills/worklog ln -s $(pwd)/skills/worklog ~/.claude/skills/worklog ``` ### Permission Denied ```bash # Fix permissions on scripts chmod +x skills/*/scripts/*.sh # Fix ownership chown -R $USER:$USER skills/ ``` ### Skills Not Updating (Nix) ```bash # Nix copies files, doesn't symlink by default # Changes to source won't appear until rebuild sudo nixos-rebuild switch --flake .#hostname ``` ### OpenCode Plugin Not Loading ```bash # Check config cat ~/.config/opencode/config.json | jq .plugin # Ensure valid JSON jq . ~/.config/opencode/config.json # Restart OpenCode pkill opencode opencode ``` ## Best Practices 1. **Development**: Use symlinks for instant updates 2. **Testing**: Use copies to test specific versions 3. **Production**: Use Nix for declarative, atomic deployments 4. **Multi-machine**: Use git submodules or dotfiles 5. **Version Control**: Always commit before deploying 6. **Documentation**: Keep deployment notes in project README 7. **Rollback Plan**: Know how to revert (especially for Nix) ## See Also - [README.md](./README.md) - Repository overview - [WORKFLOW.md](./WORKFLOW.md) - Development workflow - [Nix Home Manager Manual](https://nix-community.github.io/home-manager/) - [Claude Code Documentation](https://docs.claude.com/en/docs/claude-code) - [OpenCode Skills Plugin](https://github.com/opencode-ai/opencode-skills)