- use-skills.sh: symlink to $CODEX_HOME/skills when CODEX_HOME is set - docs: update PER-REPO-SKILLS.md and RFC-SKILLS-MANIFEST.md with Codex flow - hq: add model configuration section (sonnet-4.5, Claude Max) - hq: update launch commands with explicit --model flag Closes skills-legi Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4 KiB
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/ (and $CODEX_HOME/skills if set).
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)
source ~/proj/skills/bin/use-skills.sh
export CODEX_HOME="$PWD/.codex" # Optional: per-repo Codex skills
use_skills worklog web-search
Option B: Self-contained (copy-paste, no external dependency)
# 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}"
if [[ -n "${CODEX_HOME:-}" ]]; then
mkdir -p "${CODEX_HOME}/skills"
ln -sfn "$out" "${CODEX_HOME}/skills/${skill}"
fi
echo "use_skill: ${skill}"
fi
}
use_skill worklog
use_skill web-search
2. Add to .gitignore
.claude/skills/
.opencode/skills/
.codex/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 worklogsweb-search- Search the web via Claudeweb-research- Deep research with multiple backendsupdate-opencode- Update OpenCode via Nixupdate-spec-kit- Update spec-kit ecosystemniri-window-capture- Capture window screenshotsscreenshot-latest- Find latest screenshotstufte-press- Generate study card JSON
How It Works
- direnv triggers on directory entry
- nix build fetches/builds the skill package (cached locally)
- symlink points
.claude/skills/<name>to/nix/store/xxx-ai-skill-<name>(and$CODEX_HOME/skills/<name>if set) - 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
# 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)
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
SKILLS_REPO="git+file://$HOME/proj/skills?rev=abc123def" # pin to commit
use_skill worklog # uses pinned revision
Troubleshooting
Skills not appearing
- Check
direnv allowwas run - Check
.claude/skills/exists and has symlinks - Restart Claude Code (it loads skills at startup)
nix build fails
- Check network access to skills repo
- Check
nix flake show $SKILLS_REPOworks - 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.