Contributing to PEtFiSh¶
How to contribute skills, packs, and improvements to the PEtFiSh project.
Development Setup¶
Prerequisites¶
- Git — for version control
- uv — Python environment manager (required for all Python scripts)
- Python 3.11+ — for skill scripts and MCP servers
Clone and Branch¶
All development happens on the dev branch. Never commit directly to master.
Branching Strategy¶
dev: Active development branchmaster: Stable release branch — every merge gets a release tag- Feature branches: Branch from
dev, PR back todev
Version Numbers¶
| Change Type | Version Bump | Examples |
|---|---|---|
| Breaking changes | Major (X) | Pack structure change, installer API change |
| New features | Minor (Y) | New pack, new skill, new platform |
| Bug fixes | Patch (Z) | Fix, docs correction, small optimization |
Adding a New Skill¶
- Create the skill directory under the appropriate pack
- Write
SKILL.mdwith proper frontmatter - Add scripts, references, and schemas as needed
- Add trigger evaluation tests
- Run the quality gate:
/petfish gate path/to/skill/ - Fix any FAIL or CONDITIONAL issues
See the Skill Authoring Guide for detailed instructions.
Adding a New Pack¶
A new pack requires updating 9 touchpoints. Missing any one causes silent installation failures for users.
The 9-Touchpoint Checklist¶
| # | Touchpoint | File(s) | What to Do |
|---|---|---|---|
| 1 | Local installer aliases | install.ps1, install.sh |
Register pack alias in the pack mapping |
| 2 | Remote installer arrays | remote-install.ps1, remote-install.sh |
Manually add to $AllPacks / ALL_PACKS static array |
| 3 | Companion catalog | catalog_query.py PROFILES dict |
Add to relevant profiles (at minimum comprehensive) |
| 4 | Project initializer | project-initializer/SKILL.md + init_project.py |
Associate with profiles or add new profile |
| 5 | README | README.md |
Update Pack list and Profile → Auto-Install table |
| 6 | Website | website/index.html, pitch.html, blog.html |
Update pack cards, tables, counts |
| 7 | Install/upgrade docs | docs/agent-install.md, docs/agent-upgrade.md |
Update examples and pack lists |
| 8 | Chinese translation | docs/zh/README.md |
Sync Chinese version |
| 9 | Archive docs | docs/archive/ |
Update pack counts and lists |
Local vs Remote installer architecture
Local installers (install.ps1, install.sh) dynamically scan the packs/ directory — new packs are auto-discovered, but aliases still need registration.
Remote installers (remote-install.ps1, remote-install.sh) use hardcoded static arrays. If you don't manually add the pack name, --pack all will silently skip it.
This asymmetry has caused real incidents. Always test both install paths.
Verification¶
After adding a new pack:
- Search for the pack name across all 9 touchpoint files
- Test
--pack allwith both local and remote installers - Verify
/petfish cataloglists the new pack - Verify
/initprojectprofile selection includes it
The 4 Installers¶
PEtFiSh has 4 installer scripts that must stay synchronized:
| Script | Type | Architecture |
|---|---|---|
install.ps1 |
Local, PowerShell | Dynamic packs/ scan |
install.sh |
Local, Shell | Dynamic packs/ scan |
remote-install.ps1 |
Remote, PowerShell | Static array |
remote-install.sh |
Remote, Shell | Static array |
Any logic change must be evaluated for all 4 scripts. The implementation may differ (dynamic vs. static), but the functional behavior must be identical.
Testing¶
Smoke Tests¶
Pack-level smoke tests live in tests/ within each pack:
Trigger Evaluation¶
Test skill trigger accuracy:
uv run python .opencode/skills/skill-trigger-evaluator/scripts/evaluate_triggers.py \
--path packs/my-pack/.opencode/skills/my-skill/evals/trigger/my-skill.json
Quality Gate¶
Run the full publish gate before any PR:
uv run python .opencode/skills/quality-gate/scripts/run_gate.py \
--path packs/my-pack/.opencode/skills/ --recursive
Pull Request Process¶
- Branch from
dev - Make changes
- Run quality gate on affected skills
- Run smoke tests if applicable
- Update CHANGELOG if the pack has one
- Create PR to
dev - After merge to
devand testing, create PR fromdevtomaster - After merge to
master, immediately create a GitHub Release:
gh release create vX.Y.Z --target master \
--title "vX.Y.Z - Brief description" \
--notes "Changelog summary"
Code Conventions¶
Python¶
- Use
uvfor all virtual environment management — nopip install - Scripts with external dependencies use PEP 723 inline metadata
- MCP servers launch via
["uv", "run", "python", "server.py"] - Stdlib-only inline code (
python3 -c) is fine without uv
SKILL.md¶
- Frontmatter
descriptionmust cover ≥80% of body trigger keywords - Include both Chinese and English trigger phrases
- Keep description under 500 characters
- Schema field names must match SKILL.md field descriptions exactly
Naming¶
- Directories and files: lowercase
kebab-case - Skill names must match their directory names
- Avoid
final,new,v2in names
Bash in Scripts¶
When embedding Python in bash strings (python3 -c "..."), use chr() instead of escaped literals:
# Good — immune to shell escaping layers
sep = chr(47) # forward slash
bs = chr(92) # backslash
# Bad — breaks across SSH, PowerShell, and other proxy shells
sep = "/"
bs = "\\"
What Not to Do¶
- Don't commit directly to
master - Don't merge to
masterwithout creating a release tag - Don't use
pip installanywhere - Don't modify other repositories' code — file issues instead
- Don't delete published releases (unless security vulnerability)
- Don't skip the quality gate before PRs