From 20a811aca006819d484a7dbc548aebc09924b1e6 Mon Sep 17 00:00:00 2001 From: rootiest Date: Wed, 13 May 2026 21:53:56 -0400 Subject: [PATCH] feat: add install.sh and README.md Introduces a standalone skill installer script and project landing page documentation covering all three skills in the repository. install.sh: - Downloads and installs SKILL.md files from the remote repository into the appropriate local directory for Claude Code (~/.claude/skills/) and/or Gemini CLI (~/.gemini/skills/) - Supports --claude/-c and --gemini/-g flags to target one or both tools; defaults to both when neither is specified - Accepts positional skill name arguments or --all/-a to install every available skill; named arguments always take precedence over --all - Discovers available skills at runtime via the Gitea contents API, with automatic fallback to a depth-1 sparse git clone when the API is unreachable or returns no results; JSON parsing uses jq, then python3, then an awk fallback in order of availability - Validates skill names against path traversal (../) and slash injection before any download is attempted - Supports CLAUDE_SKILLS_DIR and GEMINI_SKILLS_DIR environment variable overrides for non-default install locations - Checks for curl and git dependencies at startup and exits with a clear error listing any missing tools - Cleans up any temporary clone directory on exit via a trap on EXIT - Displays colorized output (Bold/Cyan headers, Green success, Yellow warnings, Red errors) when stdout is a terminal; disables all ANSI codes automatically when piped or redirected - Includes a fully formatted --help/-h page documenting all flags, environment variables, and usage examples README.md: - Landing page covering project purpose, all three skills with per-skill purpose and execution protocol summaries, and a full Installation section - Installation section documents the standard curl pipe form (curl -sL URL | bash -s -- args) with six ready-to-use one-liner examples covering all major flag combinations - Flags & Options table, Environment Variables table, and a Manual Install section for users who prefer to inspect before running - Table of contents with anchor links for all major sections - License section referencing GPL-3.0-or-later --- README.md | 197 +++++++++++++++++++++++++++++++++ install.sh | 314 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 511 insertions(+) create mode 100644 README.md create mode 100755 install.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..497c578 --- /dev/null +++ b/README.md @@ -0,0 +1,197 @@ +# Rootiest Skills Repository + +A collection of reusable AI skills (structured prompt protocols) for **Claude Code** and **Gemini CLI**. Each skill defines a precise execution protocol that guides the AI through complex, multi-step tasks — replacing ad-hoc prompting with consistent, auditable workflows. + +Skills are plain Markdown files. The included `install.sh` script handles discovery and installation in a single command. + +--- + +## Table of Contents + +- [Skills](#skills) + - [systematic-enumeration](#systematic-enumeration) + - [git-publish-workflow](#git-publish-workflow) + - [readme-sync-audit](#readme-sync-audit) +- [Installation](#installation) + - [Quick Install (curl)](#quick-install-curl) + - [Flags & Options](#flags--options) + - [Environment Variables](#environment-variables) + - [Examples](#examples) + - [Manual Install](#manual-install) +- [License](#license) + +--- + +## Skills + +### `systematic-enumeration` + +**Purpose:** Eliminate counting and membership errors caused by the model's tendency toward holistic pattern recognition. + +When invoked, the AI is required to work through three explicit phases: + +1. **Set Definition** — enumerate every member of the finite set before any analysis begins. +2. **Atomic Element Testing** — test each item individually, producing a `[Item] → [Logic] → [Boolean]` record for every element. For character-level checks, the string is split into individual characters to bypass tokenization bias. +3. **Reduction & Summation** — aggregate results and self-verify that the number of items tested exactly matches the set size; if there is a mismatch, Phase 2 restarts. + +**Use when:** counting characters in a string, verifying a property across a list of files or variables, or any membership test where a false negative carries real cost. + +--- + +### `git-publish-workflow` + +**Purpose:** Automate the full lifecycle from uncommitted local work to an open Pull Request, with built-in quality gates. + +The workflow runs three phases: + +1. **Scope Determination** — if staged changes exist, operate only on those; otherwise operate on all modified/untracked files. +2. **Safe-Commit Sequence** — generate a `kebab-case` branch name, compose a [Conventional Commits](https://www.conventionalcommits.org/) message, then run the project's primary test/lint/build command. If verification fails, the sequence stops — nothing is pushed. +3. **Remote Integration** — push the branch, open a PR against the default branch, and populate the description with a "Why/What" summary and a manual verification checklist (`- [ ]` items). + +**Use when:** you say "Ship this," "Make a PR," or invoke `/git-publish-workflow`. + +--- + +### `readme-sync-audit` + +**Purpose:** Keep `README.md` accurate by programmatically aligning it with the current state of the codebase. + +Three-phase execution: + +1. **Delta Analysis** — locate the last commit that touched `README.md`, diff all code changes from that point to `HEAD`, and extract undocumented environment variables, CLI flags, or API changes. +2. **Pruning & Update Audit** — remove stale setup steps or "Coming Soon" notes, correct version numbers and file paths, and synthesize documentation for newly discovered features. +3. **Structural Integrity Check** — verify that Quick Start commands still work, all config keys are listed, and code snippets match the current API. + +**Use when:** you say "Update the docs," "Sync the README," or invoke `/readme-sync-audit`. + +--- + +## Installation + +### Quick Install (curl) + +The intended usage is a single `curl | bash` command. The installer fetches and runs `install.sh` directly — no clone required. + +**Install all skills for both Claude Code and Gemini CLI:** + +```bash +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- --all +``` + +**Install all skills for Claude Code only:** + +```bash +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- --all --claude +``` + +**Install all skills for Gemini CLI only:** + +```bash +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- --all --gemini +``` + +**Install a single skill for both tools:** + +```bash +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- systematic-enumeration +``` + +**Install specific skills for Claude Code only:** + +```bash +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- --claude git-publish-workflow readme-sync-audit +``` + +**Install specific skills for Gemini CLI only:** + +```bash +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- --gemini systematic-enumeration git-publish-workflow +``` + +> **Note:** Providing explicit skill names alongside `--all` causes the named skills to take precedence — only those skills are installed. + +--- + +### Flags & Options + +| Flag | Description | +|---|---| +| `-c`, `--claude` | Install into Claude Code (`~/.claude/skills/`) | +| `-g`, `--gemini` | Install into Gemini CLI (`~/.gemini/skills/`) | +| `-a`, `--all` | Install every skill available in the repository | +| `SKILL...` | Install one or more named skills (positional arguments) | +| `-h`, `--help` | Show the help page | + +**Tool targeting:** if neither `--claude` nor `--gemini` is specified, the installer targets **both** tools by default. + +**Skill selection precedence:** explicit skill names always override `--all`. Passing `--all skill-name` installs only `skill-name`, not every skill. + +**Dependencies:** `curl` and `git` must be present on `PATH`. The installer checks for both and exits with a clear error if either is missing. + +--- + +### Environment Variables + +| Variable | Default | Description | +|---|---|---| +| `CLAUDE_SKILLS_DIR` | `~/.claude/skills` | Override the Claude Code install directory | +| `GEMINI_SKILLS_DIR` | `~/.gemini/skills` | Override the Gemini CLI install directory | + +Example — installing to a project-local skills directory: + +```bash +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh \ + | CLAUDE_SKILLS_DIR=./.claude/skills bash -s -- --claude systematic-enumeration +``` + +--- + +### Examples + +```bash +# Install everything, both tools (simplest possible invocation) +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- --all + +# Install one skill, Claude only +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- --claude git-publish-workflow + +# Install two skills, Gemini only +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh | bash -s -- --gemini systematic-enumeration readme-sync-audit + +# Override install directory, Claude only +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh \ + | CLAUDE_SKILLS_DIR=~/my-skills bash -s -- --claude --all +``` + +--- + +### Manual Install + +If you prefer to inspect the script before running it: + +```bash +# Download +curl -sL https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main/install.sh -o install.sh + +# Review +less install.sh + +# Run +bash install.sh --all +``` + +Or clone the repository and run locally: + +```bash +git clone https://git.rootiest.dev/rootiest/ai-skills.git +cd claude-skills +bash install.sh --all +``` + +--- + +## License + +This project is licensed under the **GNU General Public License v3.0 or later (GPL-3.0-or-later)**. + +See [LICENSE](LICENSE) for the full license text, or visit . diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..fffb9ad --- /dev/null +++ b/install.sh @@ -0,0 +1,314 @@ +#!/usr/bin/env bash +# install.sh — AI Skill Installer +# Install skills from rootiest/ai-skills into Claude Code and/or Gemini CLI +# +# Usage: bash <(curl -sL ) [OPTIONS] [SKILL...] + +set -euo pipefail + +# ── Constants ────────────────────────────────────────────────────────────────── +readonly BASE_URL="https://git.rootiest.dev/rootiest/ai-skills/raw/branch/main" +readonly REPO_URL="https://git.rootiest.dev/rootiest/ai-skills.git" +readonly API_URL="https://git.rootiest.dev/api/v1/repos/rootiest/ai-skills/contents/skills" + +# Overridable via environment +CLAUDE_SKILLS_DIR="${CLAUDE_SKILLS_DIR:-${HOME}/.claude/skills}" +GEMINI_SKILLS_DIR="${GEMINI_SKILLS_DIR:-${HOME}/.gemini/skills}" + +# ── ANSI Colors (only when writing to a terminal) ───────────────────────────── +if [[ -t 1 ]]; then + BOLD=$'\033[1m' + BOLD_CYAN=$'\033[1;36m' + BOLD_GREEN=$'\033[1;32m' + GREEN=$'\033[0;32m' + YELLOW=$'\033[0;33m' + RED=$'\033[0;31m' + DIM=$'\033[2m' + RESET=$'\033[0m' +else + BOLD='' BOLD_CYAN='' BOLD_GREEN='' GREEN='' YELLOW='' RED='' DIM='' RESET='' +fi + +# ── State ───────────────────────────────────────────────────────────────────── +INSTALL_CLAUDE=false +INSTALL_GEMINI=false +INSTALL_ALL=false +declare -a SKILLS=() +TMP_DIR="" + +# ── Cleanup ─────────────────────────────────────────────────────────────────── +cleanup() { + if [[ -n "${TMP_DIR:-}" && -d "${TMP_DIR:-}" ]]; then + rm -rf "$TMP_DIR" + fi +} +trap cleanup EXIT + +# ── Output Helpers ──────────────────────────────────────────────────────────── +info() { printf " ${BOLD_CYAN}→${RESET} %b\n" "$*"; } +ok() { printf " ${BOLD_GREEN}✓${RESET} %b\n" "$*"; } +warn() { printf " ${YELLOW}⚠${RESET} %b\n" "$*" >&2; } +die() { printf " ${RED}✗ ERROR:${RESET} %b\n" "$*" >&2; exit 1; } +sep() { printf "${BOLD_CYAN}%s${RESET}\n" "──────────────────────────────────────────"; } + +# ── Help ────────────────────────────────────────────────────────────────────── +show_help() { + printf "\n" + printf "${BOLD_CYAN} AI Skill Installer${RESET}\n" + printf "${DIM} Install skills from rootiest/ai-skills into Claude Code and Gemini CLI${RESET}\n" + printf "\n" + printf "${BOLD} USAGE${RESET}\n" + printf " install.sh [OPTIONS] [SKILL...]\n" + printf " bash <(curl -sL /install.sh) [OPTIONS] [SKILL...]\n" + printf "\n" + printf "${BOLD} TOOL TARGETS${RESET}\n" + printf " ${GREEN}-c, --claude${RESET} Install into Claude Code (\$CLAUDE_SKILLS_DIR)\n" + printf " ${GREEN}-g, --gemini${RESET} Install into Gemini CLI (\$GEMINI_SKILLS_DIR)\n" + printf " ${DIM} (default: install for both tools)${RESET}\n" + printf "\n" + printf "${BOLD} SKILL SELECTION${RESET}\n" + printf " ${GREEN}-a, --all${RESET} Install every skill in the repository\n" + printf " ${GREEN}SKILL...${RESET} One or more skill names (folder names under skills/)\n" + printf " ${DIM} Specific names always override --all${RESET}\n" + printf "\n" + printf "${BOLD} OTHER${RESET}\n" + printf " ${GREEN}-h, --help${RESET} Show this help page\n" + printf "\n" + printf "${BOLD} EXAMPLES${RESET}\n" + printf " ${DIM}# Install all skills for both tools${RESET}\n" + printf " install.sh --all\n" + printf "\n" + printf " ${DIM}# Install one skill, Claude Code only${RESET}\n" + printf " install.sh --claude my-skill\n" + printf "\n" + printf " ${DIM}# Install two skills, Gemini CLI only${RESET}\n" + printf " install.sh --gemini skill-one skill-two\n" + printf "\n" + printf " ${DIM}# Named skills override --all (only those listed are installed)${RESET}\n" + printf " install.sh --all --claude skill-name\n" + printf "\n" + printf "${BOLD} ENVIRONMENT${RESET}\n" + printf " ${GREEN}CLAUDE_SKILLS_DIR${RESET} Claude skills directory (default: ~/.claude/skills)\n" + printf " ${GREEN}GEMINI_SKILLS_DIR${RESET} Gemini skills directory (default: ~/.gemini/skills)\n" + printf "\n" + printf "${BOLD} REPOSITORY${RESET}\n" + printf " ${DIM}%s${RESET}\n" "$REPO_URL" + printf "\n" +} + +# ── Dependency Check ────────────────────────────────────────────────────────── +check_deps() { + local -a missing=() + command -v curl &>/dev/null || missing+=(curl) + command -v git &>/dev/null || missing+=(git) + if [[ ${#missing[@]} -gt 0 ]]; then + die "Missing required tools: ${missing[*]}" + fi +} + +# ── Validate Skill Name ─────────────────────────────────────────────────────── +validate_skill_name() { + local name="$1" + if [[ -z "$name" ]]; then die "Skill name cannot be empty."; fi + if [[ "$name" == *".."* ]]; then die "Invalid skill name (path traversal): '${name}'"; fi + if [[ "$name" == *"/"* ]]; then die "Invalid skill name (contains slash): '${name}'"; fi +} + +# ── Parse Directory Names from Gitea API JSON ───────────────────────────────── +# Supports jq, python3, or no-dep grep/awk fallback +parse_dir_names() { + local json="$1" + + if command -v jq &>/dev/null; then + printf '%s' "$json" | jq -r '.[] | select(.type == "dir") | .name' + return + fi + + if command -v python3 &>/dev/null; then + printf '%s' "$json" | python3 -c \ + "import sys,json; [print(e['name']) for e in json.load(sys.stdin) if e.get('type')=='dir']" + return + fi + + # Awk fallback: track name/type fields within each JSON object token stream. + # Reliable for single-line (minified) Gitea API responses. + printf '%s' "$json" | tr ',' '\n' | awk -F'"' ' + /^[[:space:]]*"name"/ { name = $4 } + /^[[:space:]]*"type".*"dir"/ { if (name != "") print name; name = "" } + ' +} + +# ── Discover Available Skills ───────────────────────────────────────────────── +discover_skills() { + info "Discovering available skills from repository..." + + # Attempt 1: Gitea contents API + local api_response + api_response=$(curl -sf --max-time 15 "$API_URL" 2>/dev/null) || api_response="" + + if [[ -n "$api_response" ]]; then + mapfile -t SKILLS < <(parse_dir_names "$api_response" 2>/dev/null | grep -v '^$' || true) + fi + + # Attempt 2: Sparse/no-checkout git clone — no JSON parsing required + if [[ ${#SKILLS[@]} -eq 0 ]]; then + warn "API unavailable or returned no results — falling back to git ls-tree..." + TMP_DIR=$(mktemp -d) + if ! git clone \ + --quiet \ + --depth=1 \ + --filter=blob:none \ + --no-checkout \ + "$REPO_URL" \ + "${TMP_DIR}/repo" 2>/dev/null; then + die "Cannot reach repository.\n URL: ${REPO_URL}\n Check your network connection." + fi + mapfile -t SKILLS < <( + git -C "${TMP_DIR}/repo" ls-tree --name-only HEAD "skills/" 2>/dev/null \ + | grep -v '^\.' \ + | grep -v '^$' \ + || true + ) + fi + + if [[ ${#SKILLS[@]} -eq 0 ]]; then + die "No skills found in repository. Verify the skills/ directory exists:\n ${REPO_URL}" + fi + + ok "Found ${#SKILLS[@]} skill(s): ${DIM}${SKILLS[*]}${RESET}" +} + +# ── Fetch a Single Skill's SKILL.md ────────────────────────────────────────── +fetch_skill() { + local skill_name="$1" + local url="${BASE_URL}/skills/${skill_name}/SKILL.md" + if ! curl -sf --max-time 30 "$url" 2>/dev/null; then + warn "Download failed: ${url}" + return 1 + fi +} + +# ── Install to Claude Code ──────────────────────────────────────────────────── +install_to_claude() { + local skill_name="$1" + local dest="${CLAUDE_SKILLS_DIR}/${skill_name}.md" + + info "[Claude] Downloading ${BOLD}${skill_name}${RESET}..." + + local content + if ! content=$(fetch_skill "$skill_name"); then + warn "[Claude] Skipping '${skill_name}' — download failed." + return 1 + fi + + mkdir -p "$CLAUDE_SKILLS_DIR" + printf '%s\n' "$content" > "$dest" + ok "[Claude] ${BOLD}${skill_name}${RESET} → ${DIM}${dest}${RESET}" +} + +# ── Install to Gemini CLI ───────────────────────────────────────────────────── +install_to_gemini() { + local skill_name="$1" + local dest="${GEMINI_SKILLS_DIR}/${skill_name}.md" + + info "[Gemini] Downloading ${BOLD}${skill_name}${RESET}..." + + local content + if ! content=$(fetch_skill "$skill_name"); then + warn "[Gemini] Skipping '${skill_name}' — download failed." + return 1 + fi + + mkdir -p "$GEMINI_SKILLS_DIR" + printf '%s\n' "$content" > "$dest" + ok "[Gemini] ${BOLD}${skill_name}${RESET} → ${DIM}${dest}${RESET}" +} + +# ── Main ────────────────────────────────────────────────────────────────────── +main() { + if [[ $# -eq 0 ]]; then show_help; exit 0; fi + + local -a positional=() + + # ── Parse Arguments ──────────────────────────────────────────────────────── + while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) show_help; exit 0 ;; + -c|--claude) INSTALL_CLAUDE=true ;; + -g|--gemini) INSTALL_GEMINI=true ;; + -a|--all) INSTALL_ALL=true ;; + -*) die "Unknown option: '${1}'. Run with -h for help." ;; + *) positional+=("$1") ;; + esac + shift + done + + # Default: install for both tools when neither is specified + if ! $INSTALL_CLAUDE && ! $INSTALL_GEMINI; then + INSTALL_CLAUDE=true + INSTALL_GEMINI=true + fi + + check_deps + + # ── Skill Resolution ─────────────────────────────────────────────────────── + # Named positional arguments always take precedence over --all + if [[ ${#positional[@]} -gt 0 ]]; then + SKILLS=("${positional[@]}") + for skill in "${SKILLS[@]}"; do + validate_skill_name "$skill" + done + elif $INSTALL_ALL; then + discover_skills + else + warn "No skills specified. Provide skill name(s) or use --all." + printf "\n" + show_help + exit 1 + fi + + # ── Target Label for Display ────────────────────────────────────────────── + local target_label + if $INSTALL_CLAUDE && $INSTALL_GEMINI; then + target_label="Claude Code + Gemini CLI" + elif $INSTALL_CLAUDE; then + target_label="Claude Code" + else + target_label="Gemini CLI" + fi + + # ── Header ──────────────────────────────────────────────────────────────── + printf "\n" + sep + printf " ${BOLD}%d skill(s)${RESET} → %s\n" "${#SKILLS[@]}" "$target_label" + sep + printf "\n" + + # ── Install Loop ────────────────────────────────────────────────────────── + local errors=0 + for skill in "${SKILLS[@]}"; do + printf " ${BOLD}%s${RESET}\n" "$skill" + if $INSTALL_CLAUDE; then + install_to_claude "$skill" || errors=$((errors + 1)) + fi + if $INSTALL_GEMINI; then + install_to_gemini "$skill" || errors=$((errors + 1)) + fi + printf "\n" + done + + # ── Summary ─────────────────────────────────────────────────────────────── + sep + if [[ $errors -eq 0 ]]; then + printf " ${BOLD_GREEN}✓ All skills installed successfully.${RESET}\n" + else + printf " ${YELLOW}⚠ %d installation(s) failed.${RESET} Review warnings above.\n" "$errors" + fi + sep + printf "\n" + + if [[ $errors -gt 0 ]]; then exit 1; fi + return 0 +} + +main "$@"