From 077643098ba8ab2494a8d6323829c39cb93c8be7 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Fri, 10 Jul 2026 12:54:47 +0200 Subject: [PATCH] feat: add first-party skills, ponytail lock, and full lint suite - add ponytail skill set to skills-lock.json (14 locked skills total) - add first-party medusa skill under skills/, layered on install - make test now runs ruff, shellcheck, and markdownlint-cli2 - CI installs the lint tools before make test in both workflows - MIT license, funding buttons, thanks and donation sections in README - .markdownlint-cli2.jsonc config; ignore lint caches in .gitignore --- .github/workflows/test.yml | 18 ++++++++- .github/workflows/update.yml | 11 ++++++ .gitignore | 19 ++++++++-- .markdownlint-cli2.jsonc | 13 +++++++ LICENSE | 22 ++++++++++- Makefile | 4 +- README.md | 73 +++++++++++++++++++++++++++++++----- scripts/install.sh | 5 +++ skills-lock.json | 36 ++++++++++++++++++ skills/medusa/SKILL.md | 32 ++++++++++++++++ tests/test_lock.py | 20 ++++++++++ 11 files changed, 237 insertions(+), 16 deletions(-) create mode 100644 .markdownlint-cli2.jsonc create mode 100644 skills/medusa/SKILL.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3696040..009e521 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,11 +6,27 @@ on: jobs: test: - name: ๐Ÿงช Lock + scripts + name: ๐Ÿงช Lock + lint runs-on: ubuntu-latest steps: - name: โฌ‡๏ธ Checkout uses: actions/checkout@v7 + - name: ๐Ÿ Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: ๐ŸŸข Set up Node.js + uses: actions/setup-node@v6 + with: + node-version: lts/* + + - name: ๐Ÿ“ฆ Install lint tools + run: | + pip install ruff + sudo apt-get update && sudo apt-get install -y shellcheck + npm install -g markdownlint-cli2 + - name: ๐Ÿงช Run tests run: make test diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index 841d70f..44cf284 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -17,11 +17,22 @@ jobs: - name: โฌ‡๏ธ Checkout uses: actions/checkout@v7 + - name: ๐Ÿ Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + - name: ๐Ÿ”ง Set up Node.js uses: actions/setup-node@v6 with: node-version: lts/* + - name: ๐Ÿ“ฆ Install lint tools + run: | + pip install ruff + sudo apt-get update && sudo apt-get install -y shellcheck + npm install -g markdownlint-cli2 + - name: ๐Ÿ”„ Update skills run: make update diff --git a/.gitignore b/.gitignore index 2390cbf..3b3be5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,21 @@ +# Python .venv/ -dist/ -build/ __pycache__/ *.pyc +dist/ +build/ +.ruff_cache/ +.pytest_cache/ +.mypy_cache/ + +# Node +node_modules/ +npm-debug.log* + +# Rendered skill install targets .agents/ .claude/ -node_modules/ + +# Editor / OS +.DS_Store +*.swp diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc new file mode 100644 index 0000000..4b282be --- /dev/null +++ b/.markdownlint-cli2.jsonc @@ -0,0 +1,13 @@ +{ + "config": { + "default": true, + "MD013": false, + "MD033": false, + "MD041": false + }, + "ignores": [ + "node_modules", + ".agents", + ".claude" + ] +} diff --git a/LICENSE b/LICENSE index c30e6e6..7d80bdb 100644 --- a/LICENSE +++ b/LICENSE @@ -1 +1,21 @@ -All rights reserved by Kevin Veen-Birkenbach +MIT License + +Copyright (c) 2026 Kevin Veen-Birkenbach + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile index 2ddbc6a..99adb1c 100644 --- a/Makefile +++ b/Makefile @@ -9,10 +9,12 @@ project: @test -n "$(TARGET)" || { echo "usage: make project TARGET=/path/to/repo"; exit 2; } @TARGET="$(TARGET)" bash scripts/install.sh -# Validate skills-lock.json and shellcheck the scripts. +# Validate the lock, lint Python (ruff), scripts (shellcheck), and markdown. test: @python3 -m unittest discover -s tests -v + @if command -v ruff >/dev/null; then ruff check .; else echo "ruff not installed - skipped"; fi @if command -v shellcheck >/dev/null; then shellcheck scripts/*.sh; else echo "shellcheck not installed - skipped"; fi + @if command -v markdownlint-cli2 >/dev/null; then markdownlint-cli2 "**/*.md"; else echo "markdownlint-cli2 not installed - skipped"; fi # Update all skills to their latest versions and refresh skills-lock.json. update: diff --git a/README.md b/README.md index 586dc94..d305e57 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,73 @@ # skills ๐Ÿง  -Reproducible agent skill collection, pinned in `skills-lock.json`. -Works for Claude Code, Codex, Gemini CLI, Cursor, Copilot, Windsurf, Cline, and more. +[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-blue?logo=github)](https://github.com/sponsors/kevinveenbirkenbach) [![Patreon](https://img.shields.io/badge/Support-Patreon-orange?logo=patreon)](https://www.patreon.com/c/kevinveenbirkenbach) [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20me%20a%20Coffee-Funding-yellow?logo=buymeacoffee)](https://buymeacoffee.com/kevinveenbirkenbach) [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://s.veen.world/paypaldonate) -Homepage: [github.com/kevinveenbirkenbach/skills](https://github.com/kevinveenbirkenbach/skills) +The agent skill collection of Kevin Veen-Birkenbach. +Every skill is pinned in `skills-lock.json` for reproducible installs. +First-party skills live under `skills/` and are layered on top of the locked ones at install time. +Compatible with Claude Code, Codex, Gemini CLI, Cursor, Copilot, Windsurf, Cline, and other agents. -## Usage ๐Ÿš€ +## Requirements ๐Ÿ“ฆ -- `make install` installs the skills globally into your home (`~/.agents/skills` and `~/.claude/skills`). -- `make project TARGET=/path/to/repo` copies the skills into a project (`/.agents/skills` and `/.claude/skills`). -- `make update` refreshes every skill to its latest version and rewrites `skills-lock.json`. -- `make test` validates `skills-lock.json` and shellchecks the scripts; CI runs it on every push and after every update. +- Node.js (provides `npx skills`). +- `jq` (only required for `make update`). -Node.js is REQUIRED (`npx skills`); `make update` additionally needs `jq`. -Restart your agent after installing so it loads the new skills. +## Installation ๐Ÿš€ + +Install the skills globally into your home (`~/.agents/skills` and `~/.claude/skills`): + +```bash +make install +``` + +Copy the skills into a specific project (`/.agents/skills` and `/.claude/skills`): + +```bash +make project TARGET=/path/to/repo +``` + +Restart your agent afterwards so it loads the new skills. + +## Maintenance ๐Ÿ”ง + +Refresh every skill to its latest version and rewrite `skills-lock.json`: + +```bash +make update +``` + +Validate `skills-lock.json` and shellcheck the scripts (also run by CI on every push and after every update): + +```bash +make test +``` + +## Related Tools ๐Ÿงฐ + +This collection is part of a wider toolset for managing IT and infrastructure: + +- [alias](https://github.com/kevinveenbirkenbach/alias) โ€” shell aliases for common commands. +- [package-manager](https://github.com/kevinveenbirkenbach/package-manager) โ€” `pkgmgr`, a single command to install and manage these repositories. +- [infinito-nexus](https://github.com/kevinveenbirkenbach/infinito-nexus) โ€” automation platform for self-hosted infrastructure. + +## License ๐Ÿ“œ + +MIT License, Copyright (c) 2026 Kevin Veen-Birkenbach. ## Author ๐Ÿ‘ค Kevin Veen-Birkenbach [kevin@veen.world](mailto:kevin@veen.world) + +## Thanks ๐Ÿ™ + +Thanks to the [#ai:infinito.nexus](https://matrix.to/#/%23ai:infinito.nexus) community, and especially to [Paulinhx](https://github.com/Paulinhx) for the inspiration. + +## Donation โค๏ธ + +If these tools help you, consider supporting their development: + +- [GitHub Sponsors](https://github.com/sponsors/kevinveenbirkenbach) +- [Patreon](https://www.patreon.com/c/kevinveenbirkenbach) +- [Buy Me a Coffee](https://buymeacoffee.com/kevinveenbirkenbach) +- [PayPal](https://s.veen.world/paypaldonate) +- Bitcoin: [bc1qle7j8m9kvny2h2q3jzsnc64s4f5zme5re23pzc2lc2d7hhasc4dqachflp](bitcoin:bc1qle7j8m9kvny2h2q3jzsnc64s4f5zme5re23pzc2lc2d7hhasc4dqachflp?message=%E2%9D%A4%EF%B8%8F%20Help%20Build%20the%20Future%20-%20Donation%20to%20Kevin%20Veen-Birkenbach.) diff --git a/scripts/install.sh b/scripts/install.sh index 0cf926f..535db01 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -32,6 +32,11 @@ if [[ ! -d "${src}" ]]; then exit 1 fi +if [[ -d "${REPO_ROOT}/skills" ]]; then + log "skills: adding first-party skills from skills/..." + cp -a "${REPO_ROOT}/skills/." "${src}/" +fi + for dst in "${TARGET}/.agents/skills" "${TARGET}/.claude/skills"; do log "skills: copying -> ${dst}" rm -rf "${dst}" diff --git a/skills-lock.json b/skills-lock.json index b103d18..b038637 100644 --- a/skills-lock.json +++ b/skills-lock.json @@ -48,6 +48,42 @@ "sourceType": "github", "skillPath": "skills/compress/SKILL.md", "computedHash": "c91bdf427a68b686ee9d6f63766c72d164b16915434736edfedf13e24dae0e8c" + }, + "ponytail": { + "source": "DietrichGebert/ponytail", + "sourceType": "github", + "skillPath": "skills/ponytail/SKILL.md", + "computedHash": "210fa0831f649ce9f8a305f7b7c8cf2a0dd09ac4dd53067109941b96e7811d4e" + }, + "ponytail-audit": { + "source": "DietrichGebert/ponytail", + "sourceType": "github", + "skillPath": "skills/ponytail-audit/SKILL.md", + "computedHash": "8b8d72e6ff70b65b6c9518d470fcf29dc696eea93d28f3efa10fdcc60cbd696d" + }, + "ponytail-debt": { + "source": "DietrichGebert/ponytail", + "sourceType": "github", + "skillPath": "skills/ponytail-debt/SKILL.md", + "computedHash": "0099b82174e3a4261828b4ec04d2c068b1b294fdab14f76701c2acd1f7c99539" + }, + "ponytail-gain": { + "source": "DietrichGebert/ponytail", + "sourceType": "github", + "skillPath": "skills/ponytail-gain/SKILL.md", + "computedHash": "c45ecba7906960eea904218b623abf097ebff84ecbacca6d68da1d0687435f75" + }, + "ponytail-help": { + "source": "DietrichGebert/ponytail", + "sourceType": "github", + "skillPath": "skills/ponytail-help/SKILL.md", + "computedHash": "10e8382b1033c9a0fec0073de6d3de3846b4f5dca7d78b6df2d476a1f4cd43c6" + }, + "ponytail-review": { + "source": "DietrichGebert/ponytail", + "sourceType": "github", + "skillPath": "skills/ponytail-review/SKILL.md", + "computedHash": "4646594fcd75455533f7ff1425f4f1c5ba0fa65f88241bf262b1c4fc275f049a" } } } diff --git a/skills/medusa/SKILL.md b/skills/medusa/SKILL.md new file mode 100644 index 0000000..f79dd9f --- /dev/null +++ b/skills/medusa/SKILL.md @@ -0,0 +1,32 @@ +--- +name: medusa +description: > + Run the MEDUSA AI security scanner (medusa-security on PyPI) against a + repository, working tree, or secret stores. Use when the user asks for a + security scan, supply-chain vetting of a repo before cloning, leaked-secret + detection in AI chat or shell history, or invokes /medusa. Defensive scanning + only. +--- + +MEDUSA is a defensive AI-first security scanner (40,000+ patterns: CVEs, prompt injection, MCP tool poisoning, leaked secrets). + +## Setup + +Check availability with `medusa --version`. +If missing, install it with `pipx install medusa-security` (fallback: `pip install --user medusa-security`). + +## Commands + +| Task | Command | +| --- | --- | +| Scan the current project | `medusa scan .` | +| Vet a remote repo BEFORE cloning (supply chain, poisoned `.claude/` hooks, permissions, skills) | `medusa scan --git ` | +| Find leaked API keys in AI chat + shell history | `medusa secrets scan` | +| Scan one exported file | `medusa secrets scan --path ` | + +## Rules + +- Run scans read-only; never pass `--reveal` and never run `medusa secrets purge` unless the user explicitly asks for it. +- Summarize findings by severity with file/line references; do not paste secret values into the conversation, even redacted ones. +- Treat findings as signals for review, not verdicts; confirm true positives in the code before proposing fixes. +- Vet third-party agent repos (`medusa scan --git`) before recommending the user clone or install them. diff --git a/tests/test_lock.py b/tests/test_lock.py index b089bf3..d869455 100644 --- a/tests/test_lock.py +++ b/tests/test_lock.py @@ -50,6 +50,26 @@ class TestSkillsLock(unittest.TestCase): f"skills must be sorted ascending; expected {sorted(names)}", ) + def test_first_party_skills_have_valid_frontmatter(self): + for skill_md in sorted((REPO_ROOT / "skills").glob("*/SKILL.md")): + with self.subTest(skill=skill_md.parent.name): + text = skill_md.read_text(encoding="utf-8") + self.assertTrue(text.startswith("---\n"), "missing frontmatter") + frontmatter = text.split("---", 2)[1] + self.assertIn("name:", frontmatter, "frontmatter missing name") + self.assertIn( + "description:", frontmatter, "frontmatter missing description" + ) + + def test_first_party_skills_do_not_shadow_locked_skills(self): + locked = set(self.lock["skills"].keys()) + for skill_dir in sorted((REPO_ROOT / "skills").glob("*/")): + self.assertNotIn( + skill_dir.name.rstrip("/"), + locked, + f"first-party skill '{skill_dir.name}' collides with a locked skill", + ) + if __name__ == "__main__": unittest.main()