From 8508d3e183d1a25f7e4eba285d60de716a59f5ed Mon Sep 17 00:00:00 2001 From: Tian-yi Liang Date: Mon, 11 May 2026 00:25:32 +0800 Subject: [PATCH 1/2] Add git: as a third install source /skill-git:install now accepts git:/ shorthand or git: in addition to skillhub: and clawhub: identifiers. An optional @ suffix overrides the auto-derived name. Cloned .git is preserved so sg-init.sh re-tags idempotently and `git pull` works for upstream updates later. This unlocks installing skills from private repos (GitHub, GitLab, self-hosted) and any git host beyond the two public registries. - commands/install.md: parse git:, add Step 3c "Git URL" - scripts/sg-install-git.sh: new helper, normalizes shorthand to git@github.com, refuses non-empty targets, validates SKILL.md presence Co-Authored-By: Claude Opus 4.7 --- commands/install.md | 43 ++++++++++++++++++++++++++++----- scripts/sg-install-git.sh | 51 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 6 deletions(-) create mode 100755 scripts/sg-install-git.sh diff --git a/commands/install.md b/commands/install.md index a1d611e..7cd034c 100644 --- a/commands/install.md +++ b/commands/install.md @@ -1,7 +1,7 @@ --- name: skill-git:install -description: Install a skill from SkillHub (skills.sh) or ClawHub (clawhub.ai). Triggers on "install skill", "download skill from", or when called from /skill-git:search after the user confirms an install. Usage: /skill-git:install skillhub: or /skill-git:install clawhub:. -argument-hint: skillhub: | clawhub: [-a ] +description: Install a skill from SkillHub (skills.sh), ClawHub (clawhub.ai), or any git URL (public or private — including your own GitHub/GitLab/self-hosted). Triggers on "install skill", "download skill from", or when called from /skill-git:search after the user confirms an install. Usage: /skill-git:install skillhub: | clawhub: | git:[@] | git:[@]. +argument-hint: skillhub: | clawhub: | git:[@] [-a ] allowed-tools: Bash(bash *), AskUserQuestion --- @@ -37,6 +37,7 @@ If `$ARGUMENTS` is empty: Identifier required. Usage: /skill-git:install skillhub:/@ /skill-git:install clawhub: + /skill-git:install git:/[@] (also accepts a full git URL) Use /skill-git:search to find skills first. ``` @@ -46,7 +47,11 @@ Extract `registry` and `identifier` from the first non-flag token: - `skillhub:/@` → `registry = "skillhub"`, validate `identifier` contains `/` and `@` - `clawhub:` → `registry = "clawhub"`, validate slug is non-empty with no `/` or spaces -- Unknown prefix → `Unknown registry. Use "skillhub:" or "clawhub:" as prefix.` Stop. +- `git:` → `registry = "git"`. The spec is either: + - `/` shorthand (expanded to `git@github.com:/.git`), or + - a full git URL (`https://...`, `http://...`, `git@host:...`, `ssh://...`) + - and may end with `@` to override the auto-derived name +- Unknown prefix → `Unknown registry. Use "skillhub:", "clawhub:", or "git:" as prefix.` Stop. On validation failure, extract a best-effort search query from all non-flag tokens (e.g. `vercel/agent-browser` → `agent-browser`) and run a registry search to suggest the correct identifier: @@ -74,6 +79,7 @@ When the user selects a result, use that as the new `identifier` and `registry` Derive `install_name` immediately: - SkillHub: the `` part after `@` - ClawHub: the `` +- Git: parse the spec by checking if it ends in `@` where `` matches `[A-Za-z0-9_][A-Za-z0-9._-]*` (the suffix contains no `/` or `:`). If so, that suffix is `install_name` and the prefix is the URL. Otherwise the URL is the whole spec and `install_name` is the URL basename with any `.git` suffix stripped (e.g. `tianyilt/skill-paper-write` → `skill-paper-write`, `git@gitlab.com:foo/bar.git` → `bar`). Extract optional flags: - `-a `: target agent (`claude`, `gemini`, `codex`, `openclaw`). Pass through to prelude. @@ -181,7 +187,32 @@ Could not write SKILL.md to . ``` Stop. -### 3c. Validate +### 3c. Git URL + +For `registry = "git"`, hand the parsed spec to the helper script. It normalizes shorthand to a full URL and clones into `install_path`: + +```bash +bash "${CLAUDE_PLUGIN_ROOT}/scripts/sg-install-git.sh" "" "" 2>&1 +``` + +`` is the URL portion derived in Step 0 (i.e. without the optional trailing `@`). The script preserves the cloned `.git` and its history; `sg-init.sh` (Step 5) will detect the existing repo and either reuse its `v*` tags (Case D — already versioned) or add a `v1.0.0` tag at the first commit (Case C). Origin remote is left intact so the user can `git pull` updates later. + +If the command succeeds and `/SKILL.md` exists: +- Set `skill_source_dir` = `` (files already in place) +- Read `/SKILL.md` as `downloaded_content` + +If the command fails or `SKILL.md` is not found: +``` +Could not download skill from git URL. + URL: + + The repository may not exist, you may not have access, or the repo may not contain a SKILL.md at its root. + Verify access with: git ls-remote + For private GitHub repos, ensure your SSH key or gh auth is configured. +``` +Stop. + +### 3d. Validate Verify `downloaded_content` is non-empty and starts with `---`. If not: ``` @@ -206,7 +237,7 @@ Display the skill preview: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Install preview - Source : + Source : > Name : Install : / Desc : @@ -248,7 +279,7 @@ Installed ✅ v1.0.0 Path : /SKILL.md - From : + From : > Desc : Next steps: diff --git a/scripts/sg-install-git.sh b/scripts/sg-install-git.sh new file mode 100755 index 0000000..3c0b2b1 --- /dev/null +++ b/scripts/sg-install-git.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# sg-install-git.sh — clone a skill from any git URL into the install path. +# +# Used by /skill-git:install when registry = "git". +# Accepts shorthand "owner/repo" (defaults to GitHub SSH) or any full git URL +# (https://, http://, ssh://, git@host:...). The cloned `.git` and its history +# are preserved so /skill-git:init (Step 5 of install) can re-tag idempotently +# (Case C/D in sg-init.sh) and so the user can `git pull` updates from origin +# later. +# +# Usage: +# sg-install-git.sh + +set -euo pipefail + +if [ $# -lt 2 ]; then + echo "[skill-git] Error: sg-install-git.sh requires " >&2 + exit 1 +fi + +url="$1" +install_path="$2" + +# Shorthand "/" → full SSH GitHub URL. +# Matches when the entire string is a single owner/repo segment with no scheme, +# colon, multiple slashes, or whitespace. +if [[ "$url" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]*/[A-Za-z0-9_][A-Za-z0-9_.-]*$ ]]; then + url="git@github.com:${url}.git" +fi + +# Refuse to clone over a non-empty target — preserves existing skill folders. +if [ -e "$install_path" ] && [ -n "$(ls -A "$install_path" 2>/dev/null || true)" ]; then + echo "[skill-git] Error: install path already exists and is non-empty: $install_path" >&2 + exit 1 +fi + +mkdir -p "$(dirname "$install_path")" + +# Clone with full history. Origin remote is set automatically by `git clone`. +if ! git clone "$url" "$install_path"; then + echo "[skill-git] Error: git clone failed for $url" >&2 + exit 1 +fi + +# Sanity check: a skill must have a SKILL.md at the repo root. +if [ ! -f "$install_path/SKILL.md" ]; then + echo "[skill-git] Error: cloned repo has no SKILL.md at root: $install_path" >&2 + exit 1 +fi + +echo "[skill-git] Cloned $url → $install_path" From 278a1a504969ee7c1414be9bd6133f77f92421d2 Mon Sep 17 00:00:00 2001 From: Tian-yi Liang Date: Mon, 11 May 2026 00:33:10 +0800 Subject: [PATCH 2/2] Default git: shorthand to HTTPS instead of SSH HTTPS works for public repos with no setup and for private repos when the user has run `gh auth login` (gh registers a credential helper). Requiring SSH out of the box would block users who haven't uploaded an SSH public key to GitHub. SSH remains available via the full URL form (git:git@github.com:owner/repo.git). Co-Authored-By: Claude Opus 4.7 --- commands/install.md | 2 +- scripts/sg-install-git.sh | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/commands/install.md b/commands/install.md index 7cd034c..9cc65f7 100644 --- a/commands/install.md +++ b/commands/install.md @@ -48,7 +48,7 @@ Extract `registry` and `identifier` from the first non-flag token: - `skillhub:/@` → `registry = "skillhub"`, validate `identifier` contains `/` and `@` - `clawhub:` → `registry = "clawhub"`, validate slug is non-empty with no `/` or spaces - `git:` → `registry = "git"`. The spec is either: - - `/` shorthand (expanded to `git@github.com:/.git`), or + - `/` shorthand (expanded to `https://github.com//.git`; HTTPS works with gh's credential helper for private repos), or - a full git URL (`https://...`, `http://...`, `git@host:...`, `ssh://...`) - and may end with `@` to override the auto-derived name - Unknown prefix → `Unknown registry. Use "skillhub:", "clawhub:", or "git:" as prefix.` Stop. diff --git a/scripts/sg-install-git.sh b/scripts/sg-install-git.sh index 3c0b2b1..1033798 100755 --- a/scripts/sg-install-git.sh +++ b/scripts/sg-install-git.sh @@ -21,11 +21,12 @@ fi url="$1" install_path="$2" -# Shorthand "/" → full SSH GitHub URL. -# Matches when the entire string is a single owner/repo segment with no scheme, -# colon, multiple slashes, or whitespace. +# Shorthand "/" → HTTPS GitHub URL by default. HTTPS works for +# public repos out of the box and for private repos when the user has run +# `gh auth login` (gh registers a credential helper for git on first auth). +# Users who prefer SSH can pass the full URL: git:git@github.com:owner/repo.git if [[ "$url" =~ ^[A-Za-z0-9_][A-Za-z0-9_.-]*/[A-Za-z0-9_][A-Za-z0-9_.-]*$ ]]; then - url="git@github.com:${url}.git" + url="https://github.com/${url}.git" fi # Refuse to clone over a non-empty target — preserves existing skill folders.