Skill: chunhualiao/skill-releaser (version 1.5.0)

--- name: skill-releaser description: Release skills to ClawhHub through the full publication pipeline — auto-scaffolding, OPSEC scan, dual review (agent + user), force-push release, security scan verification. Use when releasing a skill, preparing a skill for release, reviewing a skill for publication, or checking release readiness. version: 1.5.0 triggers: - release skill - publish skill - prepare for clawhub - release readiness - skill release review - publish to clawhub --- # Skill Releaser Orchestrates the full skill publication pipeline from internal repo to ClawhHub. ## When to Use - User says "release {skill}" or "publish {skill} to clawhub" - User says "prepare {skill} for release" or "check release readiness" - User says "review {skill} for publication" - Cron-triggered release check during refactory pipeline ## Assumptions **How OpenClaw and user interact during release:** - Agent runs on a machine with shell access (exec tool) for git and CLI operations - User communicates via messaging channel (Telegram, Discord, Signal, etc.) — likely on a phone - User reviews the private GitHub repo directly in their browser/phone — the repo IS the review artifact, not a text summary - User approves or rejects by replying to the agent's message (natural language: "approve", "revise: fix the readme", "reject") - Agent can create and manage GitHub repos via `gh` CLI on behalf of the user's authenticated account - Agent pushes to the private staging repo BEFORE requesting user review, so there is something to review - Agent does NOT publish anything publicly without explicit user approval — this is a hard gate - The repo starts private for staging and review. At release time, history is erased via orphan branch + force push (single clean commit), then flipped to public - The full release can span multiple sessions — the private staging repo preserves state so any agent can resume - Multiple skills can be in different stages of the pipeline simultaneously ## Prerequisites - `gh` CLI authenticated (for repo creation and visibility changes) - `clawhub` CLI installed (for ClawhHub publishing) - A skill directory with at least a `SKILL.md` file ## Scope & Boundaries **This skill handles:** The full release pipeline — structure scaffolding, OPSEC scanning, review, publishing. **This skill does NOT handle:** Skill content creation or design. The SKILL.md must already describe what the skill does. Everything else (boilerplate, structure, scaffolding) is this pipeline's job. A user with a finished SKILL.md should be able to say "release this skill" and this skill handles everything from there — including generating all missing structure files. ## Automation Model The pipeline has two fully automated phases separated by one human gate. **Both single and batch releases follow the same model.** ### Single Skill ``` Phase 1 (AUTO): Steps 1-7 — scaffold, validate, stage, scan, review, push ↓ GATE: User reviews private repo, replies "approve" / "revise" / "reject" ↓ Phase 2 (AUTO): Steps 9-12 — erase history, flip public, publish, verify scan, deliver ``` ### Batch Release (multiple skills) ``` Phase 1 (PARALLEL): Spawn subagents — one per skill, all run Phase 1 simultaneously ↓ GATE: ONE batch review message with all repo links User replies: "approve all" / "approve A,C; revise B: fix readme" ↓ Phase 2 (PARALLEL): Spawn subagents for approved skills, all publish simultaneously ↓ DELIVERY: ONE batch summary with all links and scan results ``` **Batch rules:** - Never serialize releases — spawn parallel subagents for Phase 1 - Never block on one approval to start the next Phase 1 - Assign each skill a short unique ID (A, B, C...) in the batch review message - Collect all Phase 1 results, present ONE batch review message with short IDs - Accept batch approvals: "approve all" / "approve A,C" / "revise B: fix readme" - Run all Phase 2s in parallel after approval **Design principles:** - User says "release these skills" once. Agent runs all Phase 1s in parallel without interruption. - Agent sends ONE message: all review links + recommendations. Then waits. - User replies once. Agent runs all Phase 2s in parallel without interruption. - Agent sends ONE delivery message with all results. - If any step fails, agent fixes it automatically and continues. Only report to user if unfixable. - Rate limits, retries, and delays are handled silently (sleep + retry, not "rate limited, should I try again?") **Anti-patterns (never do these):** - Do not serialize releases — always parallelize with subagents - Do not block on approval for skill A before starting Phase 1 for skill B - Do not send per-skill review messages — batch them - Do not ask "should I create the repo?" — just create it - Do not report intermediate steps — only the batch review and batch delivery - Do not ask about rate limits or transient errors — retry silently ## Process ### Step 1: Structure Scaffolding (Auto-Generate Boilerplate) Before any quality checks, generate all missing structure files from the existing SKILL.md: **Auto-generate if missing:** | File | Source | Generation Method | |------|--------|-------------------| | `skill.yml` | SKILL.md frontmatter + triggers | Extract name, description, version, triggers from SKILL.md | | `README.md` | SKILL.md description + usage | GitHub landing page for humans: what it does, how to install, future work. NOT agent instructions. | | `CHANGELOG.md` | Version from skill.yml + git log | `## v{version} — {date}` + summary of current state | | `tests/test-triggers.json` | SKILL.md triggers + "When to Use" | `shouldTrigger` from triggers list, `shouldNotTrigger` from anti-patterns | | `scripts/` | Create directory | Empty dir or placeholder README if no scripts needed | | `references/` | Create directory | Empty dir or placeholder README if no references needed | | `LICENSE` | Default MIT | Standard MIT license text | | `.gitignore` | Standard | `node_modules/`, `.DS_Store`, `*.log` | **Rules:** - Never overwrite existing files — only generate what's missing - All generated content derives from SKILL.md — no hallucinated features - If SKILL.md lacks enough info to generate a file, flag it as a content gap (user must fix SKILL.md first) - Generated README.md must make sense to a stranger who has never seen the skill before **Validation after scaffolding:** - Run `scripts/validate-structure.sh` — must score 8/8 - If not 8/8, identify what's still missing and fix it ### Step 1.5: Version Bump (updates only) If this skill has been published before, bump the version before proceeding: 1. **Check current published version:** ```bash clawhub inspect {slug} ``` 2. **Bump version** in both `skill.yml` and `SKILL.md` frontmatter: - Patch (1.0.0 → 1.0.1): bug fixes, typos, minor doc updates - Minor (1.0.0 → 1.1.0): new features, new sections, structural changes - Major (1.0.0 → 2.0.0): breaking changes, full rewrites 3. **Update CHANGELOG.md** with new version entry describing what changed 4. **Verify `display_name` is set in `skill.yml`** — this is the human-readable title shown on ClawhHub. It must be set explicitly; never derive it from the slug or guess it. If missing, add it now: ```yaml display_name: "Human Readable Title" # Required — used as ClawhHub listing title ``` Rules: - Title case, plain English, no jargon - Describes what the skill does, not how it's implemented - Example: slug `autonomous-task-runner` → `display_name: "Autonomous Task Runner"` - Example: slug `skill-releaser` → `display_name: "Skill Releaser"` Skip this step for first-time releases (but still verify `display_name` exists). ### Step 2: Readiness Check Verify the skill directory is complete: - `SKILL.md` exists with description and usage instructions - `skill.yml` exists with name, description, triggers - Structure score 8/8 (from Step 1) - No obvious OPSEC violations (quick scan) If any check fails, report what needs fixing. Do not proceed. ### Step 3: Create Private Staging Repo ```bash # Check if repo already exists gh repo view your-org/openclaw-skill-{name} 2>/dev/null # If not, create it — CRITICAL: use the SANITIZED description, not the source skill.yml # Run OPSEC scan on the description string BEFORE passing to gh repo create gh repo create your-org/openclaw-skill-{name} --private --description "{sanitized description}" ``` **OPSEC on repo metadata:** The description passed to `gh repo create` is public when the repo flips to public. It must be scanned for the same patterns as file contents (org names, personal info, internal project names). This is not covered by file-based scanners — it must be checked explicitly. ### Step 4: Prepare Release Content Copy ONLY the skill directory content to a clean staging area: ```bash mkdir -p /tmp/skill-release-{name} cp -r skills/{name}/* /tmp/skill-release-{name}/ # Remove internal-only files rm -f /tmp/skill-release-{name}/WORKSPACE.md rm -f /tmp/skill-release-{name}/.gitignore rm -rf /tmp/skill-release-{name}/_meta.json rm -rf /tmp/skill-release-{name}/.clawhub ``` **CRITICAL VALIDATION — verify before proceeding:** ```bash # The release directory must contain ONLY skill files. # If you see ANY of these, you copied from the wrong directory — STOP and fix: # - USER.md, MEMORY.md, AGENTS.md, SOUL.md (workspace/repo root files) # - audits/, shared/, scripts/ (repo directories) # - memory/, slides/, projects/ (personal data) # - .gitmodules (repo root) ls /tmp/skill-release-{name}/ # Expected: SKILL.md, skill.yml, README.md, CHANGELOG.md, LICENSE, tests/, references/, scripts/ # If file count exceeds ~15 files, something is wrong. Verify source path. ``` Add release files if missing: - `LICENSE` (MIT by default) - `README.md` (must work as GitHub landing page for strangers) - `.gitignore` ### Step 5: Release Content Validation (HARD GATE) ```bash bash scripts/validate-release-content.sh /tmp/skill-release-{name} ``` **This is a deterministic script that blocks pushes if the release directory contains repo-level files (USER.md, MEMORY.md, audits/, etc.), has too many files (>50), or contains suspicious file types (logs, images, PDFs).** Must return SAFE (exit 0). If BLOCKED, you copied from the wrong directory. **Do NOT proceed. Fix the source path and re-copy.** ### Step 6: OPSEC Deep Scan ```bash bash scripts/opsec-scan.sh /tmp/skill-release-{name} ``` Must return CLEAN (exit 0). If violations found, fix them in the release copy. Do NOT modify the source in openclaw-knowledge — keep the internal version as-is. ### Step 7: Agent Review Generate review document: ```markdown # Release Review: {skill-name} ## Checklist - [ ] SKILL.md clear and useful to a stranger - [ ] README.md works as GitHub landing page - [ ] skill.yml triggers accurate and complete - [ ] Scripts work without hardcoded dependencies - [ ] Tests present and described - [ ] CHANGELOG.md current - [ ] LICENSE present - [ ] No references to internal repos, infrastructure, or personal info - [ ] OPSEC scan: CLEAN - [ ] Competitive position: {novel|ahead} ## OPSEC Scan Output {paste scan output} ## Competitive Summary {from audits/{name}-competitive.md} ## Recommendation APPROVE / REVISE: {reasons} ``` Save to `openclaw-knowledge/reviews/{name}-release-review.md` ### Step 8: Push to Private Staging Repo Push sanitized content so user can review the actual repo on any device (phone, laptop): ```bash cd /tmp/skill-release-{name} git init git config user.email "agent@localhost" git config user.name "SkillEngineer" # Install OPSEC pre-commit hook — prevents sensitive data from entering git history cp /tmp/openclaw-knowledge/scripts/opsec-precommit-hook.sh .git/hooks/pre-commit chmod +x .git/hooks/pre-commit git add . git commit -m "v{version}: Initial release of {name}" git remote add origin https://github.com/your-org/openclaw-skill-{name}.git git branch -M main git push -u origin main ``` ### Step 9: User Review For single skills, send review link. For batch releases, collect all Phase 1 results and send ONE message. **Single skill:** ``` RELEASE REVIEW: {skill-name} {score} | OPSEC: CLEAN {1-line description} https://github.com/your-org/openclaw-skill-{name} Reply: approve / revise:{feedback} / reject ``` **Batch review (assign short IDs for easy approval):** ``` BATCH RELEASE REVIEW — {N} skills A. {skill-name} — {score} | CLEAN | {1-line description} https://github.com/your-org/openclaw-skill-{name} B. {skill-name} — {score} | CLEAN | {1-line description} https://github.com/your-org/openclaw-skill-{name} C. {skill-name} — {score} | CLEAN | {1-line description} https://github.com/your-org/openclaw-skill-{name} Reply: approve all / approve A,C / revise B:{feedback} ``` **Rules:** - Links on their own line (never in tables — not clickable on mobile) - Short IDs (A, B, C) for batch approval — user should never type full skill names - The repo IS the review artifact. User reviews actual files, not a summary. - Wait for user response. Do not proceed without explicit approval. ### Step 10: Erase History & Flip to Public (after user approval) Erase git history (may contain OPSEC fixes from earlier revisions) and make the repo public: ```bash cd /tmp/skill-release-{name} # Orphan branch erases all history git checkout --orphan clean git add -A git commit -m "v{version}: {name}" git branch -D main git branch -m main git push -f origin main # Flip visibility gh repo edit your-org/openclaw-skill-{name} --visibility public # Verify repo metadata is OPSEC-clean (description, topics are now public) gh repo view your-org/openclaw-skill-{name} --json description,repositoryTopics -q '.description + " " + (.repositoryTopics | join(" "))' # Manually check output for org names, personal info, internal project names # If dirty: gh repo edit your-org/openclaw-skill-{name} --description "{clean description}" ``` Single commit, clean history, one repo. No dual-repo complexity. ### Step 11: Prepare Publish Package and Request Approval **ClawhHub publish is an irreversible external action. It requires explicit user approval via a D-## ID before execution.** Extract the publish parameters and log an approval request — do NOT run `clawhub publish` yet: ```bash # Extract publish parameters directly from skill.yml SLUG=$(grep '^name:' /tmp/skill-release-{name}/skill.yml | awk '{print $2}') DISPLAY_NAME=$(grep '^display_name:' /tmp/skill-release-{name}/skill.yml | sed 's/display_name: *//' | tr -d '"') VERSION=$(grep '^version:' /tmp/skill-release-{name}/skill.yml | awk '{print $2}') echo "slug: $SLUG" echo "display_name: $DISPLAY_NAME" echo "version: $VERSION" if [ -z "$SLUG" ] || [ -z "$DISPLAY_NAME" ] || [ -z "$VERSION" ]; then echo "ERROR: Missing slug, display_name, or version in skill.yml — fix before proceeding" exit 1 fi ``` If `display_name` is missing from `skill.yml`, add it now (see Step 1.5). **Then add a pending publish entry to ESCALATIONS.md:** ``` D-##: Publish {display_name} v{version} (slug: {slug}) to ClawhHub? — yes/no ``` **Stop here. Wait for My Lord to reply "D-## yes" before proceeding to Step 11.5.** Only proceed to Step 11.5 if My Lord has explicitly approved this specific publish in the current session. ### Step 11.5: Execute Publish + Verify (APPROVAL REQUIRED) **Only run this step after receiving explicit "D-## yes" from My Lord.** ```bash clawhub publish /tmp/skill-release-{name} \ --slug "$SLUG" \ --name "$DISPLAY_NAME" \ --version "$VERSION" \ --changelog "{summary of changes from CHANGELOG.md}" ``` **Post-publish verification — verify the live listing matches skill.yml exactly:** After publishing, verify the live listing matches the source skill.yml exactly. **This step catches wrong titles, version mismatches, and stale metadata before delivery.** ```bash clawhub inspect "$SLUG" 2>&1 ``` Compare the output against skill.yml: | Field | Expected (from skill.yml) | Actual (from clawhub inspect) | Match? | |-------|--------------------------|-------------------------------|--------| | Display name | `display_name` value | First line of inspect output | ✅ / ❌ | | Version | `version` value | `Latest:` field | ✅ / ❌ | | Description | First sentence of `description` | `Summary:` field (truncated) | ✅ / ❌ | | Owner | your ClawhHub username | `Owner:` field | ✅ / ❌ | **If any field does not match:** 1. Do NOT proceed to Step 12 2. Identify the mismatch (wrong `--name`, wrong `--slug`, stale `skill.yml`) 3. Fix the source (skill.yml or publish command), bump patch version, republish 4. Re-run Step 11.5 until all fields match 5. Only proceed to Step 12 when the table shows ✅ on all rows **Common mismatches and fixes:** | Mismatch | Cause | Fix | |----------|-------|-----| | Wrong display name | `display_name` missing from skill.yml; name was guessed | Add `display_name` to skill.yml, republish | | Wrong version | skill.yml not updated before publish | Bump version in skill.yml, republish | | Wrong slug | `name` field in skill.yml doesn't match intended slug | Fix `name` in skill.yml or use correct `--slug` | | Wrong owner | Published under wrong account | Check `clawhub whoami`, re-authenticate if needed | ### Step 12: Verify Security Scan (Browser Required) ClawhHub automatically scans all published skills via VirusTotal (Code Insight) and OpenClaw's own scanner. **Do not consider the release complete until scans are reviewed.** **Use the browser tool to check scan results — ClawhHub pages require JS rendering:** 1. **Open the skill detail page with browser:** ``` browser start (profile=openclaw) browser navigate → https://clawhub.ai/{username}/{slug} browser snapshot (refs=aria) ``` 2. **Find the "Security Scan" section** in the snapshot. It shows: - **VirusTotal verdict:** Benign / Suspicious / Malicious / Pending - **OpenClaw verdict:** Benign / Suspicious / Malicious with confidence level - **Detail text:** Explanation of what was flagged (expand "Details" if collapsed) - **VirusTotal report link:** Direct URL to full analysis 3. **Interpret results and act:** | Verdict | Meaning | Action | |---------|---------|--------| | Benign (both) | Clean, auto-approved | Proceed to Step 13 | | Pending | Still processing | Wait 2 minutes, re-snapshot | | Suspicious (undeclared permissions) | Skill needs privileged access not in metadata | Add `permissions` to skill.yml, bump version, re-publish | | Suspicious (other) | Flagged behavior | Review detail text. If false positive, contact OpenClaw security team. If real, fix and re-publish | | Malicious | Blocked from download | Fix immediately, bump version, re-run from Step 1.5 | 4. **Common fix — undeclared permissions:** If flagged for privileged CLI access (gh, clawhub, git, filesystem), add a `permissions` field to `skill.yml`: ```yaml permissions: - exec: git, gh CLI (repo creation, visibility changes) - exec: clawhub CLI (publishing) - filesystem: read/write skill directories - browser: verify scan results on ClawhHub ``` Then bump version and re-publish. This declares intent and resolves the flag. 5. **If VirusTotal is still Pending** after 5 minutes, proceed to Step 12 but note it in the delivery. The scan completes asynchronously. ### Step 13: Deliver Confirm the release is live and deliver all links and scan status to the user: ``` RELEASED: {skill-name} v{version} GitHub: https://github.com/your-org/openclaw-skill-{name} ClawhHub: https://clawhub.ai/{username}/{slug} VirusTotal: {verdict} — {report link} OpenClaw Scan: {verdict} ({confidence}) {1-line description} ``` ### Pipeline Ends Here Skill-releaser scope ends at Step 13 (delivery). Post-release bookkeeping (STATUS.json updates, submodule conversion, memory logging) is a **refactory system responsibility**, not a release pipeline responsibility. See REFACTORY-SYSTEM.md "Post-Release Stage." ## Error Handling | Error | Cause | Fix | |-------|-------|-----| | Readiness check fails | Score too low or OPSEC dirty | Complete refactoring first | | OPSEC scan finds violations in release copy | Sanitization incomplete | Fix in release copy, re-scan | | gh repo create fails | Auth issue or name taken | Check `gh auth status`, try different name | | clawhub publish fails | CLI not installed or auth | Run `npm install -g clawhub`, authenticate | | User rejects | Feedback provided | Address feedback, restart from Step 4 | ## Configuration No persistent configuration required. The pipeline uses environment-level tools (`gh`, `clawhub`, `git`) that must be authenticated before use. **Required tools:** | Tool | Purpose | Check | |------|---------|-------| | `gh` CLI | GitHub repo creation, visibility changes | `gh auth status` | | `clawhub` CLI | Publish to ClawhHub registry | `clawhub whoami` | | `git` | Version control | Built-in | | `python3` | OPSEC scanner (optional) | `python3 --version` | **Pipeline scripts (in `scripts/`):** | Script | Purpose | |--------|---------| | `validate-structure.sh` | Score skill structure completeness (8 checks) | | `validate-release-content.sh` | Block placeholder text, empty files | | `opsec-scan.sh` | Scan for sensitive data before public release | **Org/username:** Update `your-org` in the pipeline steps to your GitHub username or org. The clawhub `--slug` argument uses the skill's `name` field from `skill.yml`. ## Examples **Release a specific skill:** "Release skill-engineer to clawhub" **Check readiness without releasing:** "Is evidence-based-investigation ready for release?" **Batch readiness check:** "Which skills are ready to publish?"

path: CHANGELOG.md
content: # Changelog

## [1.5.0] - 2026-02-17
### Changed
- Step 11 now prepares publish package and logs D-## approval request — does NOT execute publish
- Step 11.5 is the actual publish execution, gated on explicit "D-## yes" from My Lord
- ClawhHub publish is now a hard-gated external action, not an autonomous step

## 

## v1.4.2 — 2026-02-18

- **Step 11: parameter extraction from skill.yml** — `--slug`, `--name`, `--version` are now
  extracted directly from skill.yml before publish. Guards against wrong/guessed display names.
  Fails loudly if `display_name` is missing.
- **Step 11.5: post-publish verification** — after every publish, `clawhub inspect` is run and
  output compared against skill.yml (name, version, description, owner). Mismatch → fix and
  republish before proceeding to security scan or delivery.
- **Step 1.5: `display_name` field required** — added to scaffolding and version-bump checklist.
  Title case, plain English, must be set explicitly in skill.yml.
- Fixes root cause of "Skill Release Task Runner" wrong title incident (2026-02-18).

## v1.4.1 — 2026-02-17

- Add `scripts/` directory with validate-structure.sh, validate-release-content.sh, opsec-scan.sh
- Add `## Configuration` section

## v1.4.0 — 2026-02-16

- Define two-phase automation model: Phase 1 (auto) → User Gate → Phase 2 (auto)
- Add anti-patterns: no intermediate questions, no step-by-step confirmations
- Silent retry on rate limits and transient errors
- One message per phase: review request (Phase 1) and delivery (Phase 2)
- Fix hardcoded org name in Step 3 examples

## v1.3.0 — 2026-02-16

- Step 11: Use browser tool to verify ClawhHub security scan results (VirusTotal + OpenClaw)
- Add `permissions` field to skill.yml declaring required privileged access
- Add guidance for addressing "Suspicious" scan verdicts (undeclared permissions)
- Fix Step 10 publish path
- Fix ClawhHub URL pattern (clawhub.ai, not clawhub.com)
- Step 12 delivery now includes both scan verdicts and VirusTotal report link

## v1.2.0 — 2026-02-16

- Replace dual-repo model with single-repo force push (orphan branch erases history)
- One repo per skill: starts private, flipped to public at release
- Step 1.5: Version bump guidance for updates (patch/minor/major)

## v1.1.0 — 2026-02-16

- Add Step 1: Structure Scaffolding — auto-generate all boilerplate from SKILL.md
- Pipeline now 11 steps (was 10)
- "Release skill X" takes a bare SKILL.md to ClawhHub with no separate polish step
- Clarified scope: this skill handles everything after SKILL.md content is written

## v1.0.0 — 2026-02-16

- Initial release
- 10-step pipeline: readiness → staging → OPSEC → dual review → publish
- Private staging repo stays private forever (history safety)
- Clean public repo created at release time (single commit)
- Agent review checklist (10 items)
- User review via private repo link
- Error handling table
- Assumptions section documenting agent-user interaction model


path: README.md
content: # skill-releaser

Release agent skills to ClawhHub through a full publication pipeline.

## What It Does

Takes any skill with a finished SKILL.md and handles everything needed to publish it:

1. **Scaffolds** missing structure files (README, CHANGELOG, tests, skill.yml) from SKILL.md
2. **Scans** for OPSEC violations (secrets, personal info, hardcoded paths)
3. **Reviews** via dual process — agent checklist + user approval
4. **Stages** in a private repo for user review on any device
5. **Publishes** by erasing history (force push) and flipping repo to public, then ClawhHub

## When to Use

- "Release {skill-name} to ClawhHub"
- "Is {skill-name} ready for release?"
- "Which skills are ready to publish?"
- "Prepare {skill-name} for release"

## Key Design Decisions

- **History erased at release** — orphan branch + force push gives a single clean commit
- **One repo per skill** — starts private for staging, flipped to public at release
- **User approval is a hard gate** — nothing goes public without explicit "approve"
- **Boilerplate is auto-generated** — only SKILL.md content needs to be written by hand
- **Security scan verified** — uses browser to check VirusTotal + OpenClaw scan results on ClawhHub before declaring release complete

## Prerequisites

- `gh` CLI authenticated
- `clawhub` CLI installed
- Shell access for git operations
- Browser tool available (for ClawhHub security scan verification)

## License

MIT

## Future Work

### Multi-Agent Architecture
When release volume justifies it, refactor from single-agent to multi-agent:

```
Dispatcher (coordinator)
  ├── Scaffolder (Steps 1-2): boilerplate, validation → flash-lite
  ├── Publisher (Steps 3-10): git ops, staging, OPSEC, publish → flash-lite
  ├── Verifier (Step 11): browser-based scan verification → sonnet
  └── Dispatcher delivers Step 12 summary
```

**Triggers:** 5+ skills per session, browser failures cascading into re-runs, rate limit cascades.

**Prerequisite:** Ship 3-5 more skills through single-agent first. Refactor with evidence, not speculation.

### ClawhHub Version Purge
No per-version deletion exists. `delete` is soft-delete (preserves versions). If a version leaks PII: full delete + re-publish (loses download counts) or contact ClawhHub support. Monitor for `clawhub delete-version` in future CLI releases.


path: STATUS.json
content: {
  "_generated": "Auto-generated from root STATUS.json. Do not edit manually.",
  "skill": "skill-releaser",
  "stage": "test",
  "auditScore": 81,
  "auditDate": "2026-02-17",
  "competitivePosition": "novel",
  "competitiveAction": "maintain",
  "tier": "generic",
  "priority": "high",
  "lastRefactored": "2026-02-17",
  "testsPassing": null,
  "opsecClean": true,
  "notes": "Meta-skill for releasing skills — 20 views on ClawhHub. Novel — no equivalent on ClawhHub. | Scripts added 2026-02-17: validate-structure.sh, validate-release-content.sh, opsec-scan.sh. Republished as v1.4.1.",
  "id": "AK",
  "released": true,
  "clawhub": "https://clawhub.ai/chunhualiao/skill-releaser",
  "compositionRole": "standalone",
  "auditRubric": "rubric-audit-b4",
  "auditMaxScore": 90,
  "clawhubVersion": "1.4.2",
  "clawhubSlug": "skill-releaser"
}


path: scripts/README.md
content: # skill-releaser/scripts

Release pipeline validation scripts. Used by the skill-releaser pipeline to
gate skills before they are staged, reviewed, and published.

---

## validate-structure.sh

Validates that a skill directory has all required structural components.
Scores 1 point per check (8 total). Exits 0 only if the score is 8/8.

### Checks (8 total)

| # | Check | What it looks for |
|---|-------|-------------------|
| 1 | `SKILL.md` exists | File present |
| 2 | `skill.yml` exists | File present |
| 3 | `README.md` exists | File present |
| 4 | `skill.yml` required fields | `name`, `description`, `version`, `triggers` |
| 5 | `SKILL.md` has `## Configuration` section | Heading present |
| 6 | `SKILL.md` references trigger words | `trigger` keyword present |
| 7 | `tests/` has at least 1 file | Directory + ≥1 file |
| 8 | `CHANGELOG.md` exists | File present |

### Usage

```bash
bash scripts/validate-structure.sh <skill-dir>
```

### Example

```bash
bash scripts/validate-structure.sh /tmp/skill-release-my-skill

# Output:
# Structure validation: /tmp/skill-release-my-skill
# ──────────────────────────────────────────
#   ✅ SKILL.md exists
#   ✅ skill.yml exists
#   ✅ README.md exists
#   ✅ skill.yml has required fields (name, description, version, triggers)
#   ✅ SKILL.md has ## Configuration section
#   ✅ SKILL.md references trigger words
#   ✅ tests/ directory exists with 1 file(s)
#   ✅ CHANGELOG.md exists
# ──────────────────────────────────────────
# Score: 8/8
#
# ✅ PASS — structure complete
```

### Exit codes

- `0` — 8/8 score (PASS)
- `1` — score below 8/8 (FAIL)

---

## validate-release-content.sh

Checks that a release directory contains no unfinished placeholder text,
no empty files, and a substantive README.md. Guards against accidentally
publishing skeleton/template content.

### Checks

| # | Check | Criteria |
|---|-------|----------|
| 1 | No placeholder text | No `{{`, `TODO`, `FIXME`, or `YOUR_` in text files |
| 2 | No empty files | All files ≥ 50 bytes |
| 3 | README.md is substantive | `README.md` ≥ 200 characters |

### Usage

```bash
bash scripts/validate-release-content.sh <skill-dir>
```

### Example

```bash
bash scripts/validate-release-content.sh /tmp/skill-release-my-skill

# Output:
# Release content validation: /tmp/skill-release-my-skill
# ──────────────────────────────────────────
#   ✅ PASS — No placeholder text found ({{, TODO, FIXME, YOUR_)
#   ✅ PASS — No empty files (all files ≥ 50 bytes)
#   ✅ PASS — README.md has 842 chars (≥ 200 required)
# ──────────────────────────────────────────
#
# ✅ PASS — release content is clean
```

### Exit codes

- `0` — all checks pass
- `1` — one or more checks failed

---

## opsec-scan.sh

Scans a skill release directory for sensitive data before public release.

**Primary mode:** delegates to
`/tmp/openclaw-knowledge/refactory/scripts/validate-job-output.py`
(the full refactory OPSEC scanner).

**Fallback mode:** grep-based scan when the Python scanner is not available.

### Fallback patterns

| Pattern | Detects | Excluded |
|---------|---------|---------|
| Personal emails | `[REDACTED_SECRET]` | `@example.com`, `@localhost`, `@openclaw.ai` |
| IP addresses | `x.x.x.x` | `127.x`, `192.0.2.x`, `0.0.0.0`, `10.x`, `172.16-31.x` |
| Absolute paths | `/Users/<name>/`, `/home/<name>/` | Lines marked as examples/placeholders |
| Credential tokens | AWS keys, GitHub tokens, OpenAI keys, Google API keys | — |

### Usage

```bash
bash scripts/opsec-scan.sh <skill-dir>
```

### Example — clean

```bash
bash scripts/opsec-scan.sh /tmp/skill-release-my-skill

# OPSEC scan: /tmp/skill-release-my-skill
# ──────────────────────────────────────────
#   Using: refactory/scripts/validate-job-output.py
#
# ✅ CLEAN — refactory scanner found no violations
```

### Example — violations found

```bash
bash scripts/opsec-scan.sh /tmp/skill-release-my-skill

# OPSEC scan: /tmp/skill-release-my-skill
# ──────────────────────────────────────────
#   Refactory scanner not available — using fallback grep scan
#
#   ❌ Hardcoded absolute paths (/Users/, /home/) found:
#     README.md:12:  cp ~/skills/my-skill ~/.openclaw/skills/
#
# ❌ BLOCKED — OPSEC violations found (see above)
#    Fix violations in the release copy before proceeding.
#    Do NOT modify the source in openclaw-knowledge.
```

> **Important:** Fix violations in the **release copy** (`/tmp/skill-release-*/`)
> only. Never modify the source skill directory — internal notes and references
> are intentionally preserved in the internal repo.

### Exit codes

- `0` — CLEAN (no violations)
- `1` — BLOCKED (violations found)

---

## Pipeline Integration

These scripts are called in sequence during the skill-releaser pipeline:

```
Step 1:  validate-structure.sh      → must score 8/8
Step 5:  validate-release-content.sh → must exit 0
Step 6:  opsec-scan.sh              → must exit 0
```

All three must pass before the release is staged for user review.


path: scripts/opsec-scan.sh
content: #!/usr/bin/env bash
# opsec-scan.sh <skill-dir>
# OPSEC scan for a skill release directory.
# Primary: delegates to validate-job-output.py (refactory scanner).
# Fallback: grep-based scan for common sensitive patterns.
# Exits 0 if CLEAN, exits 1 if violations found.

set -euo pipefail

SKILL_DIR="${1:-}"
if [[ -z "$SKILL_DIR" ]]; then
  echo "Usage: $0 <skill-dir>" >&2
  exit 1
fi

if [[ ! -d "$SKILL_DIR" ]]; then
  echo "ERROR: Directory not found: $SKILL_DIR" >&2
  exit 1
fi

PYTHON_SCANNER="/tmp/openclaw-knowledge/refactory/scripts/validate-job-output.py"
VIOLATIONS=()
ALL_CLEAN=true

echo ""
echo "OPSEC scan: $SKILL_DIR"
echo "──────────────────────────────────────────"

# ── Primary: Python refactory scanner ─────────────────────────────────────────
# The refactory scanner expects a specific job-output directory format.
# We try it, but fall back to grep scan if it reports an unsupported type.
if [[ -f "$PYTHON_SCANNER" ]]; then
  echo "  Trying: refactory/scripts/validate-job-output.py"
  SCANNER_OUTPUT=$(python3 "$PYTHON_SCANNER" "$SKILL_DIR" 2>&1 || true)
  SCANNER_EXIT=$?

  # Fall back if the scanner doesn't recognize the directory type
  if echo "$SCANNER_OUTPUT" | grep -q "Unknown job type\|Valid types:"; then
    echo "  (refactory scanner does not support raw skill dirs — using fallback)"
    echo ""
  elif [[ "$SCANNER_EXIT" -eq 0 ]]; then
    echo "$SCANNER_OUTPUT"
    echo ""
    echo "✅ CLEAN — refactory scanner found no violations"
    exit 0
  else
    echo "$SCANNER_OUTPUT"
    echo ""
    echo "❌ BLOCKED — refactory scanner found violations (see above)"
    exit 1
  fi
fi

# ── Fallback: grep-based scan ─────────────────────────────────────────────────
echo "  Refactory scanner not available — using fallback grep scan"
echo ""

# Collect all text files to scan
SCAN_FILES=$(find "$SKILL_DIR" -type f \
  -not -path "*/.git/*" \
  \( -name "*.md" -o -name "*.yml" -o -name "*.yaml" -o -name "*.sh" \
     -o -name "*.py" -o -name "*.json" -o -name "*.txt" -o -name "*.js" \) \
  2>/dev/null)

if [[ -z "$SCAN_FILES" ]]; then
  echo "  No text files found to scan."
fi

record_violations() {
  local label="$1"
  local matches="$2"
  if [[ -n "$matches" ]]; then
    ALL_CLEAN=false
    VIOLATIONS+=("$label")
    while IFS= read -r line; do
      VIOLATIONS+=("  $line")
    done <<< "$matches"
  fi
}

# ── Pattern 1: Personal email addresses (non-example domains) ─────────────────
# Exclude: @example.com, @example.org, @example.net, @localhost
EMAILS=$(echo "$SCAN_FILES" | xargs grep -hEn \
  '[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}' 2>/dev/null \
  | grep -Ev '@(example\.(com|org|net)|localhost|127\.|openclaw\.ai|clawhub\.ai)' \
  | grep -Ev '^\s*#' \
  | head -20 || true)
record_violations "❌ Personal email addresses found:" "$EMAILS"

# ── Pattern 2: IP addresses (excluding safe/example ranges) ───────────────────
# Exclude: 127.x.x.x, 192.0.2.x (TEST-NET), 0.0.0.0, example patterns
IPS=$(echo "$SCAN_FILES" | xargs grep -hEn \
  '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' 2>/dev/null \
  | grep -Ev '\b(127\.|192\.0\.2\.|0\.0\.0\.0|10\.0\.0\.|172\.(1[6-9]|2[0-9]|3[01])\.)' \
  | grep -Ev '(example|placeholder|your-ip|x\.x\.x\.x)' \
  | grep -Ev '^\s*#' \
  | head -20 || true)
record_violations "❌ IP addresses (non-example) found:" "$IPS"

# ── Pattern 3: Hardcoded absolute paths /Users/ or /home/ ─────────────────────
# Exclude: lines that look like examples/placeholders
PATHS=$(echo "$SCAN_FILES" | xargs grep -hEn \
  '/(Users|home)/[a-zA-Z0-9_\-]+/' 2>/dev/null \
  | grep -Ev '(example|your-username|<user>|YOUR_|placeholder|e\.g\.|e\.g,)' \
  | grep -Ev '^\s*#.*example' \
  | head -20 || true)
record_violations "❌ Hardcoded absolute paths (/Users/, /home/) found:" "$PATHS"

# ── Pattern 4: Known identifier patterns ──────────────────────────────────────
# AWS keys, GitHub tokens, API keys
IDENTIFIERS=$(echo "$SCAN_FILES" | xargs grep -hEn \
  '(AKIA[0-9A-Z]{16}|ghp_[a-zA-Z0-9]{36}|gho_[a-zA-Z0-9]{36}|sk-[a-zA-Z0-9]{32,}|AIza[0-9A-Za-z\-_]{35})' \
  2>/dev/null | head -20 || true)
record_violations "❌ Known credential/token patterns found:" "$IDENTIFIERS"

# ── Report ─────────────────────────────────────────────────────────────────────
if [[ "$ALL_CLEAN" == "true" ]]; then
  echo "  ✅ No personal emails"
  echo "  ✅ No suspicious IP addresses"
  echo "  ✅ No hardcoded absolute paths"
  echo "  ✅ No credential/token patterns"
  echo ""
  echo "✅ CLEAN — fallback scan found no violations"
  exit 0
else
  for v in "${VIOLATIONS[@]}"; do echo "  $v"; done
  echo ""
  echo "❌ BLOCKED — OPSEC violations found (see above)"
  echo "   Fix violations in the release copy before proceeding."
  echo "   Do NOT modify the source in openclaw-knowledge."
  exit 1
fi


path: scripts/validate-release-content.sh
content: #!/usr/bin/env bash
# validate-release-content.sh <skill-dir>
# Validates that a skill release directory has no placeholder text, no empty
# files, and a substantive README.md.
# Prints PASS/FAIL per check. Exits 0 if all pass, exits 1 if any fail.

set -euo pipefail

SKILL_DIR="${1:-}"
if [[ -z "$SKILL_DIR" ]]; then
  echo "Usage: $0 <skill-dir>" >&2
  exit 1
fi

if [[ ! -d "$SKILL_DIR" ]]; then
  echo "ERROR: Directory not found: $SKILL_DIR" >&2
  exit 1
fi

ALL_PASS=true
RESULTS=()

pass() { RESULTS+=("  ✅ PASS — $1"); }
fail() { RESULTS+=("  ❌ FAIL — $1"); ALL_PASS=false; }

# ── Check 1: No placeholder text ─────────────────────────────────────────────
PLACEHOLDER_PATTERNS=('\{\{' 'TODO' 'FIXME' 'YOUR_')
PLACEHOLDER_HITS=()

# Scan content files only (not shell scripts — they may reference these
# patterns as search strings in grep commands).
for pattern in "${PLACEHOLDER_PATTERNS[@]}"; do
  MATCHES=$(grep -r "$pattern" "$SKILL_DIR" \
    --include="*.md" --include="*.yml" --include="*.yaml" \
    --include="*.json" --include="*.txt" \
    --exclude-dir=scripts \
    -l 2>/dev/null || true)
  if [[ -n "$MATCHES" ]]; then
    while IFS= read -r file; do
      PLACEHOLDER_HITS+=("$file (pattern: $pattern)")
    done <<< "$MATCHES"
  fi
done

if [[ ${#PLACEHOLDER_HITS[@]} -eq 0 ]]; then
  pass "No placeholder text found ({{, TODO, FIXME, YOUR_)"
else
  fail "Placeholder text found in:"
  for hit in "${PLACEHOLDER_HITS[@]}"; do
    RESULTS+=("       • $hit")
  done
fi

# ── Check 2: No empty files (< 50 bytes) ─────────────────────────────────────
EMPTY_FILES=()
while IFS= read -r -d '' f; do
  SIZE=$(wc -c < "$f" | tr -d ' ')
  if [[ "$SIZE" -lt 50 ]]; then
    EMPTY_FILES+=("$f ($SIZE bytes)")
  fi
done < <(find "$SKILL_DIR" -type f \
  -not -path "*/.git/*" \
  -not -name ".git" \
  -not -name ".gitmodules" \
  -print0)

if [[ ${#EMPTY_FILES[@]} -eq 0 ]]; then
  pass "No empty files (all files ≥ 50 bytes)"
else
  fail "Files smaller than 50 bytes:"
  for f in "${EMPTY_FILES[@]}"; do
    RESULTS+=("       • $f")
  done
fi

# ── Check 3: README.md has at least 200 chars ─────────────────────────────────
README="$SKILL_DIR/README.md"
if [[ -f "$README" ]]; then
  CHAR_COUNT=$(wc -c < "$README" | tr -d ' ')
  if [[ "$CHAR_COUNT" -ge 200 ]]; then
    pass "README.md has $CHAR_COUNT chars (≥ 200 required)"
  else
    fail "README.md too short: $CHAR_COUNT chars (need ≥ 200)"
  fi
else
  fail "README.md not found"
fi

# ── Summary ───────────────────────────────────────────────────────────────────
echo ""
echo "Release content validation: $SKILL_DIR"
echo "──────────────────────────────────────────"
for r in "${RESULTS[@]}"; do echo "$r"; done
echo "──────────────────────────────────────────"
echo ""

if [[ "$ALL_PASS" == "true" ]]; then
  echo "✅ PASS — release content is clean"
  exit 0
else
  echo "❌ FAIL — release content has issues (see above)"
  exit 1
fi


path: scripts/validate-structure.sh
content: #!/usr/bin/env bash
# validate-structure.sh <skill-dir>
# Validates that a skill directory has all required structural components.
# Scores 1 point per check (8 total). Exits 0 if 8/8, exits 1 otherwise.

set -euo pipefail

SKILL_DIR="${1:-}"
if [[ -z "$SKILL_DIR" ]]; then
  echo "Usage: $0 <skill-dir>" >&2
  exit 1
fi

if [[ ! -d "$SKILL_DIR" ]]; then
  echo "ERROR: Directory not found: $SKILL_DIR" >&2
  exit 1
fi

SCORE=0
TOTAL=8
RESULTS=()

pass() { SCORE=$((SCORE + 1)); RESULTS+=("  ✅ $1"); }
fail() {                        RESULTS+=("  ❌ $1"); }

# ── Check 1: SKILL.md exists ──────────────────────────────────────────────────
if [[ -f "$SKILL_DIR/SKILL.md" ]]; then
  pass "SKILL.md exists"
else
  fail "SKILL.md missing"
fi

# ── Check 2: skill.yml exists ─────────────────────────────────────────────────
if [[ -f "$SKILL_DIR/skill.yml" ]]; then
  pass "skill.yml exists"
else
  fail "skill.yml missing"
fi

# ── Check 3: README.md exists ─────────────────────────────────────────────────
if [[ -f "$SKILL_DIR/README.md" ]]; then
  pass "README.md exists"
else
  fail "README.md missing"
fi

# ── Check 4: skill.yml has required fields (name, description, version, triggers)
if [[ -f "$SKILL_DIR/skill.yml" ]]; then
  MISSING_FIELDS=()
  grep -q '^name:' "$SKILL_DIR/skill.yml"        || MISSING_FIELDS+=("name")
  grep -q '^description:' "$SKILL_DIR/skill.yml" || MISSING_FIELDS+=("description")
  grep -q '^version:' "$SKILL_DIR/skill.yml"     || MISSING_FIELDS+=("version")
  grep -q '^triggers:' "$SKILL_DIR/skill.yml"    || MISSING_FIELDS+=("triggers")
  if [[ ${#MISSING_FIELDS[@]} -eq 0 ]]; then
    pass "skill.yml has required fields (name, description, version, triggers)"
  else
    fail "skill.yml missing fields: ${MISSING_FIELDS[*]}"
  fi
else
  fail "skill.yml missing fields (file absent)"
fi

# ── Check 5: SKILL.md has ## Configuration section ───────────────────────────
if [[ -f "$SKILL_DIR/SKILL.md" ]]; then
  if grep -q '^## Configuration' "$SKILL_DIR/SKILL.md"; then
    pass "SKILL.md has ## Configuration section"
  else
    fail "SKILL.md missing ## Configuration section"
  fi
else
  fail "SKILL.md missing ## Configuration section (file absent)"
fi

# ── Check 6: SKILL.md has trigger words ──────────────────────────────────────
if [[ -f "$SKILL_DIR/SKILL.md" ]]; then
  # Check for trigger words either in frontmatter or in a triggers section
  if grep -q 'trigger' "$SKILL_DIR/SKILL.md"; then
    pass "SKILL.md references trigger words"
  else
    fail "SKILL.md has no trigger words"
  fi
else
  fail "SKILL.md has no trigger words (file absent)"
fi

# ── Check 7: tests/ directory exists with at least 1 file ────────────────────
if [[ -d "$SKILL_DIR/tests" ]]; then
  FILE_COUNT=$(find "$SKILL_DIR/tests" -maxdepth 2 -type f | wc -l | tr -d ' ')
  if [[ "$FILE_COUNT" -ge 1 ]]; then
    pass "tests/ directory exists with $FILE_COUNT file(s)"
  else
    fail "tests/ directory exists but is empty"
  fi
else
  fail "tests/ directory missing"
fi

# ── Check 8: CHANGELOG.md exists ─────────────────────────────────────────────
if [[ -f "$SKILL_DIR/CHANGELOG.md" ]]; then
  pass "CHANGELOG.md exists"
else
  fail "CHANGELOG.md missing"
fi

# ── Summary ───────────────────────────────────────────────────────────────────
echo ""
echo "Structure validation: $SKILL_DIR"
echo "──────────────────────────────────────────"
for r in "${RESULTS[@]}"; do echo "$r"; done
echo "──────────────────────────────────────────"
echo "Score: $SCORE/$TOTAL"
echo ""

if [[ "$SCORE" -eq "$TOTAL" ]]; then
  echo "✅ PASS — structure complete"
  exit 0
else
  echo "❌ FAIL — $((TOTAL - SCORE)) check(s) failed"
  exit 1
fi


path: skill.yml
content: name: skill-releaser
display_name: "Skill Releaser"
description: Release skills to ClawhHub through the full publication pipeline — auto-scaffolding, OPSEC scan, dual review (agent + user), force-push release, security scan verification.
version: 1.5.0
triggers:
  - release skill
  - publish skill
  - prepare for clawhub
  - release readiness
  - skill release review
  - publish to clawhub
  - which skills are ready to publish
permissions:
  - exec: git, gh CLI (repo creation, visibility changes, force push)
  - exec: clawhub CLI (publishing to ClawhHub registry)
  - filesystem: read/write skill directories and /tmp staging areas
  - browser: open ClawhHub skill pages to verify security scan results
  - message: send release status and links to user via messaging channel


path: tests/test-triggers.json
content: {
  "shouldTrigger": [
    "release skill-engineer",
    "publish skill-engineer to clawhub",
    "prepare x-extract for release",
    "is evidence-based-investigation ready for release?",
    "which skills are ready to publish?",
    "release readiness check",
    "skill release review for gitea-monitor",
    "publish this skill",
    "prepare for clawhub",
    "release this to clawhub"
  ],
  "shouldNotTrigger": [
    "create a new skill",
    "audit skill-engineer",
    "what skills do we have?",
    "fix the OPSEC scan",
    "design a skill for calendar management",
    "run the refactory pipeline",
    "check skill scores",
    "update SKILL.md",
    "write a skill for twitter extraction"
  ]
}


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)