catstack is a personal skill stack. Portable skills and hooks are welcome; project-specific Invoker/NiceSpeak rules belong in those repos.
- Put a standard
SKILL.mdunderproduct/skills/<name>/orcorpus/skills/<name>/. - Keep it agent-agnostic unless it truly cannot run elsewhere. Claude-only skills go in
CLAUDE_ONLY_SKILLSininstall.sh. - Optional (product only): add task-type files under
domains/(coding.md,equities.md). Paste the domain selector fromengine/skills/create-skill/SKILL.mdintoSKILL.md. Generic prose MUST NOT name repo CLIs; domain files only add triggers and cwd filename lookups. - If it came from another repo, add a sourcing note in docs/provenance.md.
- Write its
tests/dir: code skills need at least two real test functions; prose-only skills need a positive fixture and a negative fixture (e.g.tests/fires_example.md/tests/stays_silent_example.md). - Run
./install.shso the skill lands in Claude, Cursor, and Codex. Do not hand-link a single harness.
- Every new skill MUST ship a
tests/dir (positive + negative — seeengine/skills/create-skill/SKILL.md) before it's added. Checked byscripts/ci/check_skill_test_coverage.py; existing untested skills are grandfathered inscripts/ci/skill_test_debt_allowlist.txt, which is shrink-only. - Every new skill MUST apply to Claude, Cursor, and Codex unless it is listed in
CLAUDE_ONLY_SKILLS. ./install.shMUST remain the install path for portable skills. Manualln -sinto only~/.cursor/skillsor only~/.claude/skillsis a bug.- Project-skill home links (outside this repo) MUST use
scripts/install/link_skill_three_harnesses.sh(or equivalent links into all three roots). - Follow
engine/skills/create-skill/SKILL.md— not Cursor built-in create-skill text that only mentions~/.cursor/skills/. - Domain-aware product skills MUST include the selector phrase in
SKILL.mdand MUST keep repo CLIs out of the generic file.
bash scripts/test/run_all_tests.shDiscovers and runs every tests/ dir in the repo -- add a new hook or skill's tests/ dir and it's picked up automatically, no edit needed here or in CI.
If your hook has a detect.py (i.e. it decides whether to catch something), it also needs a positive test (proves the detector fires on the bad case) and a negative test (proves it stays silent on a clean case). Check with:
python3 scripts/ci/check_hook_test_coverage.pySession-mine / reflect detector scripts need the same positive+negative shape:
python3 scripts/ci/check_mine_repro_coverage.pyEvery skill needs its own positive+negative coverage too:
python3 scripts/ci/check_skill_test_coverage.py
python3 scripts/ci/check_skill_test_debt_no_growth.py # scripts/ci/skill_test_debt_allowlist.txt is shrink-onlyThree-harness skill install gate:
python3 scripts/ci/check_skills_three_harnesses.py
python3 scripts/ci/check_skills_three_harnesses.py --home # live personal roots./install.sh is safe to rerun. It will not clobber a real (non-symlink) file without --force.