- 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
465 lines
11 KiB
Markdown
465 lines
11 KiB
Markdown
# Best Practices: Skills as Single Source of Truth
|
|
|
|
**Philosophy**: This repository is the canonical source for all AI agent skills. All deployments consume via Nix flake inputs.
|
|
|
|
## Core Principles
|
|
|
|
### 1. Skills Repo is Authoritative
|
|
|
|
**What this means**:
|
|
- All skill development happens in `dan/skills` repository
|
|
- No permanent local copies in consumer projects
|
|
- Changes must be committed here to be deployed
|
|
|
|
**Why**:
|
|
- Clear ownership and maintenance responsibility
|
|
- Version control provides audit trail
|
|
- Reproducible deployments across all environments
|
|
- Prevents drift and divergence
|
|
|
|
### 2. Modern Nix with Flakes
|
|
|
|
**What this means**:
|
|
- Use `flake.nix` for all configuration
|
|
- Consumers add skills repo as flake input
|
|
- Leverage flake.lock for reproducibility
|
|
- Use NixOS modules for deployment
|
|
|
|
**Why**:
|
|
- Declarative configuration
|
|
- Version pinning with flake.lock
|
|
- Reproducible builds
|
|
- Composable modules
|
|
|
|
### 3. Temporary Local Copies Only During Development
|
|
|
|
**What this means**:
|
|
- OK to copy skill to consumer for testing during initial development
|
|
- Must switch to flake input once skill is stable
|
|
- Duration: Hours to 1-2 days max, not weeks
|
|
- Always transition to production pattern (flake input)
|
|
|
|
**Why**:
|
|
- Fast iteration during development
|
|
- Clean production deployments
|
|
- Prevents forgetting to sync changes
|
|
- Clear distinction between dev and prod patterns
|
|
|
|
## Workflow Patterns
|
|
|
|
### Adding a New Skill
|
|
|
|
**Development phase** (1-2 days):
|
|
```bash
|
|
# 1. Create skill in skills repo
|
|
cd ~/proj/skills
|
|
mkdir -p skills/new-skill/{scripts,examples,templates}
|
|
# ... create SKILL.md, README.md, etc ...
|
|
|
|
# 2. Commit early (even if WIP)
|
|
git add skills/new-skill/
|
|
git commit -m "WIP: Add new-skill (initial structure)"
|
|
|
|
# 3. Optional: Copy to consumer for rapid testing
|
|
cp -r skills/new-skill ~/proj/ops-dev/skills/
|
|
# Test, iterate, modify in place
|
|
|
|
# 4. When working, sync back to skills repo
|
|
cp -r ~/proj/ops-dev/skills/new-skill skills/
|
|
git add skills/new-skill/
|
|
git commit -m "Complete new-skill implementation"
|
|
```
|
|
|
|
**Production phase** (permanent):
|
|
```bash
|
|
# 5. Add to flake packages (if not already)
|
|
# Edit flake.nix, add to packages output
|
|
|
|
# 6. Consumer switches to flake input
|
|
cd ~/proj/ops-dev
|
|
# Edit flake.nix:
|
|
# services.ai-skills.selectedSkills = [ "new-skill" ];
|
|
nix flake lock --update-input skills
|
|
# Deploy to VM
|
|
|
|
# 7. Remove local copy
|
|
rm -rf ~/proj/ops-dev/skills/new-skill
|
|
git add -A
|
|
git commit -m "Switch new-skill to flake input"
|
|
```
|
|
|
|
**Key point**: Don't skip step 6-7. Leaving skills as local copies defeats the purpose.
|
|
|
|
### Updating an Existing Skill
|
|
|
|
**Always in skills repo**:
|
|
```bash
|
|
# 1. Make changes in skills repo
|
|
cd ~/proj/skills
|
|
# Edit skills/tufte-press/SKILL.md or scripts
|
|
|
|
# 2. Commit with clear message
|
|
git commit -am "tufte-press: Add example for concurrent equations"
|
|
|
|
# 3. Push to remote (Forgejo)
|
|
git push origin master
|
|
|
|
# 4. Consumers update when ready
|
|
cd ~/proj/ops-dev
|
|
nix flake lock --update-input skills
|
|
# Deploy to VM
|
|
```
|
|
|
|
**Never**:
|
|
- ❌ Make changes in consumer's local copy
|
|
- ❌ Keep local modifications "just for us"
|
|
- ❌ Fork the skill for project-specific tweaks
|
|
|
|
**Instead**:
|
|
- ✅ Make changes in skills repo
|
|
- ✅ If change is project-specific, use configuration options
|
|
- ✅ If broadly useful, add to skills repo for everyone
|
|
|
|
### Testing Changes Before Committing
|
|
|
|
**Option A: Test in skills repo directly**:
|
|
```bash
|
|
cd ~/proj/skills
|
|
|
|
# Make changes
|
|
vim skills/worklog/scripts/suggest-filename.sh
|
|
|
|
# Test locally (if skill has test scripts)
|
|
./skills/worklog/scripts/suggest-filename.sh test-input.org
|
|
|
|
# Commit when working
|
|
git commit -am "worklog: Fix filename suggestion for long titles"
|
|
```
|
|
|
|
**Option B: Test in consumer with local override**:
|
|
```bash
|
|
# Temporarily point to local path for testing
|
|
cd ~/proj/ops-dev
|
|
# Edit flake.nix:
|
|
# inputs.skills.url = "path:/home/dan/proj/skills";
|
|
|
|
nix flake lock --update-input skills
|
|
# Deploy to VM and test
|
|
|
|
# When working, revert to git URL
|
|
# Edit flake.nix:
|
|
# inputs.skills.url = "git+http://192.168.1.108:3000/dan/skills.git";
|
|
nix flake lock --update-input skills
|
|
```
|
|
|
|
**Option C: Use a branch**:
|
|
```bash
|
|
cd ~/proj/skills
|
|
|
|
# Create feature branch
|
|
git checkout -b feature/worklog-improvements
|
|
|
|
# Make changes, commit
|
|
git commit -am "worklog: Add weekly summary aggregation"
|
|
git push origin feature/worklog-improvements
|
|
|
|
# Consumer tests the branch
|
|
cd ~/proj/ops-dev
|
|
# Edit flake.nix:
|
|
# inputs.skills.url = "git+http://192.168.1.108:3000/dan/skills.git?ref=feature/worklog-improvements";
|
|
nix flake lock --update-input skills
|
|
# Test on VM
|
|
|
|
# When stable, merge to master
|
|
cd ~/proj/skills
|
|
git checkout master
|
|
git merge feature/worklog-improvements
|
|
git push origin master
|
|
|
|
# Consumer switches back to master
|
|
cd ~/proj/ops-dev
|
|
# Edit flake.nix: back to master URL
|
|
nix flake lock --update-input skills
|
|
```
|
|
|
|
## Anti-Patterns (Don't Do This)
|
|
|
|
### ❌ Permanent Local Copies
|
|
|
|
**Wrong**:
|
|
```bash
|
|
# Consumer repo permanently has skills/ directory
|
|
ops-dev/
|
|
skills/
|
|
tufte-press/ # Local copy
|
|
worklog/ # Local copy
|
|
```
|
|
|
|
**Why wrong**:
|
|
- Must manually sync changes
|
|
- Risk of divergence
|
|
- Unclear which version is deployed
|
|
- Defeats purpose of single source of truth
|
|
|
|
**Right**:
|
|
```nix
|
|
# Consumer repo uses flake input
|
|
inputs.skills.url = "git+http://192.168.1.108:3000/dan/skills.git";
|
|
services.ai-skills.selectedSkills = [ "tufte-press" "worklog" ];
|
|
```
|
|
|
|
### ❌ Project-Specific Forks
|
|
|
|
**Wrong**:
|
|
```bash
|
|
# Creating modified copy for one project
|
|
ops-dev/skills/tufte-press-custom/
|
|
# Modified version just for ops-dev
|
|
```
|
|
|
|
**Why wrong**:
|
|
- Others can't benefit from improvements
|
|
- Maintenance burden (must merge upstream changes)
|
|
- Creates fragmentation
|
|
|
|
**Right**:
|
|
- Add configuration options to skill
|
|
- Make skill flexible via environment variables or config files
|
|
- Keep one version that works for everyone
|
|
|
|
### ❌ Manual File Copying
|
|
|
|
**Wrong**:
|
|
```bash
|
|
# Regularly doing this
|
|
scp skills/new-feature.sh root@vm:/etc/opencode/skills/worklog/scripts/
|
|
```
|
|
|
|
**Why wrong**:
|
|
- Bypasses version control
|
|
- Not reproducible
|
|
- No audit trail
|
|
- Breaks on next rebuild
|
|
|
|
**Right**:
|
|
```bash
|
|
# Commit to skills repo, update flake
|
|
cd ~/proj/skills
|
|
git commit -am "worklog: Add new feature"
|
|
git push
|
|
|
|
cd ~/proj/ops-dev
|
|
nix flake lock --update-input skills
|
|
# Deploy via nixos-rebuild
|
|
```
|
|
|
|
### ❌ Long-Lived Development Branches
|
|
|
|
**Wrong**:
|
|
```bash
|
|
# Branch exists for weeks/months
|
|
git checkout -b dan/experimental-features
|
|
# ... months pass ...
|
|
# Never merged, consumers stuck on old version
|
|
```
|
|
|
|
**Why wrong**:
|
|
- Others can't use improvements
|
|
- Becomes hard to merge later
|
|
- Defeats shared repository purpose
|
|
|
|
**Right**:
|
|
- Short-lived feature branches (days, not weeks)
|
|
- Merge to master frequently
|
|
- Use feature flags if needed for WIP features
|
|
- Or commit to master with "WIP" markers in docs
|
|
|
|
## Version Control Practices
|
|
|
|
### Commit Messages
|
|
|
|
**Good examples**:
|
|
```
|
|
tufte-press: Add support for margin figure citations
|
|
|
|
worklog: Fix filename generation for dates with slashes
|
|
|
|
screenshot-latest: Improve error handling when no screenshots found
|
|
|
|
niri-window-capture: Add security audit logging
|
|
```
|
|
|
|
**Pattern**: `<skill-name>: <brief description>`
|
|
|
|
**Why**: Clear which skill changed, easy to scan git log
|
|
|
|
### When to Commit
|
|
|
|
**Commit frequently**:
|
|
- ✅ After adding new script
|
|
- ✅ After fixing bug
|
|
- ✅ After updating documentation
|
|
- ✅ After testing confirms it works
|
|
|
|
**Don't wait for**:
|
|
- ❌ "Perfect" state (commit early, improve later)
|
|
- ❌ All skills to be updated (commit per-skill changes separately)
|
|
- ❌ "Big batch" of changes (many small commits better)
|
|
|
|
### Branching Strategy
|
|
|
|
**Simple approach**:
|
|
- `master` branch is always deployable
|
|
- Feature branches for significant changes
|
|
- Merge to master when working
|
|
- Delete branch after merge
|
|
|
|
**Example**:
|
|
```bash
|
|
# New skill
|
|
git checkout -b add-sql-formatter-skill
|
|
# ... work ...
|
|
git push origin add-sql-formatter-skill
|
|
# ... test ...
|
|
git checkout master
|
|
git merge add-sql-formatter-skill
|
|
git push origin master
|
|
git branch -d add-sql-formatter-skill
|
|
```
|
|
|
|
## Deployment Best Practices
|
|
|
|
### Pinning Versions
|
|
|
|
**Default: Track latest**:
|
|
```nix
|
|
inputs.skills.url = "git+http://192.168.1.108:3000/dan/skills.git";
|
|
# flake.lock tracks specific commit
|
|
# Update with: nix flake lock --update-input skills
|
|
```
|
|
|
|
**When to pin**: Production systems that need stability
|
|
```nix
|
|
inputs.skills.url = "git+http://192.168.1.108:3000/dan/skills.git?rev=abc123def";
|
|
# Locked to specific commit, won't change until manually updated
|
|
```
|
|
|
|
### Update Cadence
|
|
|
|
**Development VMs**: Update frequently
|
|
```bash
|
|
# Daily or when skills change
|
|
nix flake lock --update-input skills
|
|
```
|
|
|
|
**Production VMs**: Update intentionally
|
|
```bash
|
|
# Weekly or after testing in dev
|
|
nix flake lock --update-input skills
|
|
# Test thoroughly before deploying
|
|
```
|
|
|
|
### Rollback Strategy
|
|
|
|
**If skill breaks**:
|
|
```bash
|
|
# Option 1: Remove from selectedSkills temporarily
|
|
services.ai-skills.selectedSkills = [
|
|
"tufte-press"
|
|
# "worklog" # Disabled due to bug
|
|
];
|
|
|
|
# Option 2: Pin to older commit
|
|
cd ~/proj/ops-dev
|
|
nix flake lock --override-input skills git+http://.../skills.git?rev=<old-commit>
|
|
|
|
# Option 3: Fix in skills repo and update
|
|
cd ~/proj/skills
|
|
# Fix bug
|
|
git commit -am "worklog: Fix critical bug"
|
|
git push
|
|
|
|
cd ~/proj/ops-dev
|
|
nix flake lock --update-input skills
|
|
```
|
|
|
|
## Multi-User Coordination
|
|
|
|
### Communication
|
|
|
|
**Before making breaking changes**:
|
|
1. Announce in team chat/IRC
|
|
2. Create issue in Forgejo
|
|
3. Use feature branch for testing
|
|
4. Get feedback before merging
|
|
|
|
**After making significant changes**:
|
|
1. Update CHANGELOG in skill directory
|
|
2. Notify consumers
|
|
3. Document migration steps if needed
|
|
|
|
### Handling Conflicts
|
|
|
|
**If two people modify same skill**:
|
|
1. Coordinate via git (branches, PRs)
|
|
2. Use git merge/rebase to combine changes
|
|
3. Test combined changes before deploying
|
|
4. Modern git handles this well
|
|
|
|
### Shared vs Personal Skills
|
|
|
|
**Shared skills** (in skills repo):
|
|
- General-purpose capabilities
|
|
- Useful to multiple people/projects
|
|
- Maintained collaboratively
|
|
- Examples: tufte-press, worklog, screenshot-latest
|
|
|
|
**Personal skills** (project-local):
|
|
- Truly project-specific
|
|
- Not useful to others
|
|
- Rapid iteration needed
|
|
- Can live in `.opencode/command/` or `.claude/skills/` locally
|
|
|
|
**Default**: If in doubt, put in skills repo. Easy to share is better than hidden.
|
|
|
|
## Summary Checklist
|
|
|
|
**When developing new skill**:
|
|
- [x] Create in skills repo (even if WIP)
|
|
- [x] Commit frequently
|
|
- [x] OK to copy to consumer for testing (temporarily)
|
|
- [x] Switch to flake input when stable (within 1-2 days)
|
|
- [x] Remove local copy after switching
|
|
|
|
**When updating existing skill**:
|
|
- [x] Make changes in skills repo only
|
|
- [x] Commit with clear message
|
|
- [x] Push to remote
|
|
- [x] Consumers update via flake lock
|
|
- [x] Never modify in consumer's local copy
|
|
|
|
**When deploying**:
|
|
- [x] Use flake input (Model 1)
|
|
- [x] Import ai-skills module
|
|
- [x] Select skills via configuration
|
|
- [x] Update with `nix flake lock --update-input skills`
|
|
- [x] No manual file copying
|
|
|
|
**Red flags**:
|
|
- [ ] Permanent `skills/` directory in consumer repo
|
|
- [ ] Manual `scp` of skill files
|
|
- [ ] "Custom" versions of skills
|
|
- [ ] Long-lived local modifications
|
|
- [ ] Forgetting to sync changes back
|
|
|
|
**Good signs**:
|
|
- [x] All skills in skills repo
|
|
- [x] Consumers use flake inputs
|
|
- [x] Clear git history
|
|
- [x] Frequent small commits
|
|
- [x] Fast update cycle (commit → push → update → deploy)
|
|
|
|
---
|
|
|
|
**The goal**: Make skills as easy to use and update as possible, while maintaining single source of truth and version control.
|