diff --git a/.github/workflows/validate-skills.yml b/.github/workflows/validate-skills.yml index 47e3606..e3c65d7 100644 --- a/.github/workflows/validate-skills.yml +++ b/.github/workflows/validate-skills.yml @@ -4,6 +4,12 @@ on: pull_request: paths: - 'skills/**' + - 'scripts/**' + - 'tests/**' + - 'install.sh' + - 'uninstall.sh' + - 'README.md' + - '.github/workflows/**' jobs: validate: @@ -13,3 +19,9 @@ jobs: - name: Validate skill structure run: ./scripts/validate-skills.sh + + - name: Check README metrics + run: ./scripts/check-readme-metrics.sh + + - name: Run repository smoke tests + run: bash ./tests/test-runner.sh diff --git a/README.md b/README.md index d7a3b7e..dac011b 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ [![Skills](https://img.shields.io/badge/skills-52-blue)](#skills-included) [![Security](https://img.shields.io/badge/security_skills-6-green)](#security--guardrails) -[![Cron](https://img.shields.io/badge/cron_scheduled-16-orange)](#openclaw-native-36-skills) -[![Scripts](https://img.shields.io/badge/companion_scripts-23-purple)](#companion-scripts) +[![Cron](https://img.shields.io/badge/cron_scheduled-19-orange)](#openclaw-native-36-skills) +[![Scripts](https://img.shields.io/badge/companion_scripts-36-purple)](#companion-scripts) [![License: MIT](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE) A plug-and-play skill library for [OpenClaw](https://github.com/openclaw/openclaw) — the open-source AI agent runtime. Gives your agent structured thinking, security guardrails, persistent memory, cron scheduling, self-recovery, and the ability to write its own new skills during conversation. @@ -24,7 +24,7 @@ Most AI agent frameworks give you a chatbot that forgets everything between sess - **Think before it acts** — brainstorming, planning, and systematic debugging skills prevent the "dive in and break things" failure mode - **Protect itself** — 6 security skills detect prompt injection, block dangerous actions, audit installed code, and scan for leaked credentials -- **Run unattended** — 12 cron-scheduled skills handle memory cleanup, health checks, budget tracking, and community monitoring while you sleep +- **Run unattended** — 19 cron-scheduled skills handle memory cleanup, health checks, budget tracking, and community monitoring while you sleep - **Recover from failures** — self-recovery, loop-breaking, and task handoff skills keep long-running work alive across crashes and restarts - **Never forget** — DAG-based memory compaction, integrity checking, context scoring, and SQLite session persistence ensure the agent preserves critical information even in month-long conversations - **Improve itself** — the agent can write new skills during normal conversation using `create-skill`, encoding your preferences as permanent behaviors @@ -46,12 +46,14 @@ The `community-skill-radar` skill takes this further: it scans Reddit every 3 da ## Quickstart ```bash -git clone https://github.com/ArchieIndian/openclaw-superpowers ~/.openclaw/extensions/superpowers -cd ~/.openclaw/extensions/superpowers && ./install.sh +git clone https://github.com/ArchieIndian/openclaw-superpowers ~/.openclaw/src/openclaw-superpowers +cd ~/.openclaw/src/openclaw-superpowers && ./install.sh openclaw gateway restart ``` -`install.sh` symlinks all 52 skills, creates state directories for stateful skills, and registers cron jobs — everything in one step. That's it. Your agent now has superpowers. +`install.sh` symlinks the repo's `skills/` directory into `~/.openclaw/extensions/superpowers`, creates state directories for stateful skills, and registers cron jobs. Clone the repo outside `~/.openclaw/extensions` so the installer never has to replace your checkout. + +Install `PyYAML` before using the stateful Python helpers: `python3 -m pip install PyYAML`. --- @@ -153,10 +155,10 @@ Six skills form a defense-in-depth security layer for autonomous agents: |---|---|---|---| | Skills included | **52** | 8 | 0 | | Self-modifying (agent writes new skills) | Yes | No | No | -| Cron scheduling | **16 scheduled skills** | No | No | +| Cron scheduling | **19 scheduled skills** | No | No | | Persistent state across sessions | **YAML state schemas** | No | No | | Security guardrails | **6 defense-in-depth skills** | No | No | -| Companion scripts with CLI | **23 scripts** | No | No | +| Companion scripts with CLI | **36 scripts** | No | No | | Memory graph / knowledge graph | Yes | No | No | | SQLite session persistence + FTS5 search | Yes | No | No | | Sub-agent recall with token-budgeted grants | Yes | No | No | @@ -203,7 +205,7 @@ Six skills form a defense-in-depth security layer for autonomous agents: Skills marked with a script ship a small executable alongside their `SKILL.md`: -- **23 Python scripts** (`run.py`, `audit.py`, `check.py`, `guard.py`, `bridge.py`, `onboard.py`, `sync.py`, `doctor.py`, `loadout.py`, `governor.py`, `detect.py`, `test.py`, `radar.py`, `graph.py`, `optimize.py`, `compact.py`, `intercept.py`, `score.py`, `integrity.py`, `persist.py`, `recall.py`) — run directly to manipulate state, generate reports, or trigger actions. No extra dependencies; `pyyaml` is optional but recommended. +- **35 Python scripts** (`run.py`, `audit.py`, `check.py`, `guard.py`, `bridge.py`, `onboard.py`, `sync.py`, `doctor.py`, `loadout.py`, `governor.py`, `detect.py`, `test.py`, `radar.py`, `graph.py`, `optimize.py`, `compact.py`, `intercept.py`, `score.py`, `integrity.py`, `persist.py`, `recall.py`) — run directly to manipulate state, generate reports, or trigger actions. Install `PyYAML` for any helper that reads or writes skill state. - **`vet.sh`** — Pure bash scanner; runs on any system with grep. - Every script supports `--help` and `--format json`. Dry-run mode available on scripts that make changes. - See the `example-state.yaml` in each skill directory for sample state and a commented walkthrough of cron behaviour. diff --git a/install.sh b/install.sh index 3f42234..0b75a2f 100755 --- a/install.sh +++ b/install.sh @@ -14,9 +14,24 @@ fi # --- Symlink --- mkdir -p "$OPENCLAW_DIR/extensions" -rm -rf "$INSTALL_TARGET" +if [ -e "$INSTALL_TARGET" ] && [ ! -L "$INSTALL_TARGET" ]; then + echo "Refusing to replace non-symlink path at $INSTALL_TARGET" + if [ "$REPO_DIR" = "$INSTALL_TARGET" ]; then + echo "This repository is checked out inside the extensions directory." + echo "Clone it somewhere else (for example: $OPENCLAW_DIR/src/openclaw-superpowers) and rerun ./install.sh." + else + echo "Remove or move the existing directory manually, then rerun ./install.sh." + fi + exit 1 +fi +rm -f "$INSTALL_TARGET" ln -s "$REPO_DIR/skills" "$INSTALL_TARGET" +if ! python3 -c "import yaml" >/dev/null 2>&1; then + echo "WARN: PyYAML is not installed. Stateful Python helpers can read less and may not persist updates correctly." + echo " Install it with: python3 -m pip install PyYAML" +fi + # --- Helper: register a stateful skill (create state dir + empty stub) --- register_stateful_skill() { local skill_name="$1" diff --git a/scripts/check-readme-metrics.sh b/scripts/check-readme-metrics.sh new file mode 100755 index 0000000..e2d1b8c --- /dev/null +++ b/scripts/check-readme-metrics.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +README="$REPO_DIR/README.md" + +SKILL_COUNT="$(git -C "$REPO_DIR" ls-files 'skills/*/*/SKILL.md' | wc -l | tr -d '[:space:]')" +CRON_COUNT="$(git -C "$REPO_DIR" grep -l '^cron:' -- 'skills/*/*/SKILL.md' | wc -l | tr -d '[:space:]')" +PYTHON_SCRIPT_COUNT="$(git -C "$REPO_DIR" ls-files 'skills/**/*.py' | wc -l | tr -d '[:space:]')" +COMPANION_SCRIPT_COUNT=$((PYTHON_SCRIPT_COUNT + 1)) + +assert_contains() { + local pattern="$1" + local message="$2" + if ! grep -Fq -- "$pattern" "$README"; then + echo "FAIL: $message" + echo " Expected to find: $pattern" + exit 1 + fi +} + +assert_contains "[![Skills](https://img.shields.io/badge/skills-$SKILL_COUNT-blue)]" "README skills badge is stale" +assert_contains "[![Cron](https://img.shields.io/badge/cron_scheduled-$CRON_COUNT-orange)]" "README cron badge is stale" +assert_contains "[![Scripts](https://img.shields.io/badge/companion_scripts-$COMPANION_SCRIPT_COUNT-purple)]" "README script badge is stale" +assert_contains "Install $SKILL_COUNT skills in one command" "README install summary count is stale" +assert_contains "**Run unattended** — $CRON_COUNT cron-scheduled skills" "README unattended count is stale" +assert_contains "| Cron scheduling | **$CRON_COUNT scheduled skills** | No | No |" "README comparison table cron count is stale" +assert_contains "| Companion scripts with CLI | **$COMPANION_SCRIPT_COUNT scripts** | No | No |" "README comparison table script count is stale" +assert_contains "- **$PYTHON_SCRIPT_COUNT Python scripts**" "README companion script count is stale" + +echo "README metrics are in sync." diff --git a/tests/test-runner.sh b/tests/test-runner.sh index 475473c..89baef4 100755 --- a/tests/test-runner.sh +++ b/tests/test-runner.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash -SKILLS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../skills" && pwd)" +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SKILLS_DIR="$REPO_DIR/skills" PASS=0; FAIL=0 for skill_dir in "$SKILLS_DIR"/**/*; do if [ -d "$skill_dir" ]; then @@ -13,14 +16,14 @@ for skill_dir in "$SKILLS_DIR"/**/*; do fi # Check stateful coherence: stateful: true requires STATE_SCHEMA.yaml - fm_stateful="$(sed -n '2,/^---$/p' "$skill_dir/SKILL.md" | grep '^stateful:' | sed 's/^stateful: *//' | tr -d '[:space:]')" + fm_stateful="$(sed -n '2,/^---$/p' "$skill_dir/SKILL.md" | grep '^stateful:' | sed 's/^stateful: *//' | tr -d '[:space:]' || true)" if [ "$fm_stateful" = "true" ] && [ ! -f "$skill_dir/STATE_SCHEMA.yaml" ]; then echo "FAIL: $skill_name stateful: true but STATE_SCHEMA.yaml missing"; FAIL=$((FAIL+1)) continue fi # Check cron format if present - fm_cron="$(sed -n '2,/^---$/p' "$skill_dir/SKILL.md" | grep '^cron:' | sed 's/^cron: *//' | tr -d '"'"'")" + fm_cron="$(sed -n '2,/^---$/p' "$skill_dir/SKILL.md" | grep '^cron:' | sed 's/^cron: *//' | tr -d '"'"'" || true)" if [ -n "$fm_cron" ]; then if ! echo "$fm_cron" | grep -qE '^[0-9*/,\-]+ [0-9*/,\-]+ [0-9*/,\-]+ [0-9*/,\-]+ [0-9*/,\-]+$'; then echo "FAIL: $skill_name invalid cron expression '$fm_cron'"; FAIL=$((FAIL+1)) @@ -36,5 +39,6 @@ for skill_dir in "$SKILLS_DIR"/**/*; do echo "PASS: $label"; PASS=$((PASS+1)) fi done +"$REPO_DIR/scripts/check-readme-metrics.sh" echo "Results: $PASS passed, $FAIL failed" [ $FAIL -eq 0 ] diff --git a/uninstall.sh b/uninstall.sh index 00478cc..11977ea 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -19,8 +19,14 @@ for skill_file in "$REPO_DIR/skills/openclaw-native"/*/SKILL.md; do done # --- Remove symlink --- -if [ -L "$INSTALL_TARGET" ] || [ -d "$INSTALL_TARGET" ]; then - rm -rf "$INSTALL_TARGET" +if [ -e "$INSTALL_TARGET" ] && [ ! -L "$INSTALL_TARGET" ]; then + echo "Refusing to remove non-symlink path at $INSTALL_TARGET" + echo "Remove it manually if this is an old checkout or custom install." + exit 1 +fi + +if [ -L "$INSTALL_TARGET" ]; then + rm -f "$INSTALL_TARGET" echo "openclaw-superpowers removed." else echo "Nothing to uninstall."