From d9f5e53c6704e89c8905af9b846ca6c372eba876 Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Fri, 30 Oct 2026 17:02:45 +0900 Subject: [PATCH] chore: move the Claude Code plugin to pleaseai/claude-code-plugins The claude-code-docs plugin (skills/, hooks/, .claude-plugin/) now lives in pleaseai/claude-code-plugins under plugins/claude-code-docs, so installing it no longer clones this mirror. Remove the plugin files and point the README at the new location. The docs mirror and sync are unchanged, and the skill keeps resolving the docs here via `ask src`. --- .claude-plugin/plugin.json | 18 --------- README.md | 6 ++- hooks/hooks.json | 17 -------- hooks/rewrite-docs-url.sh | 42 ------------------- hooks/rewrite-docs-url.test.sh | 42 ------------------- skills/claude-code-docs/SKILL.md | 69 -------------------------------- 6 files changed, 4 insertions(+), 190 deletions(-) delete mode 100644 .claude-plugin/plugin.json delete mode 100644 hooks/hooks.json delete mode 100755 hooks/rewrite-docs-url.sh delete mode 100755 hooks/rewrite-docs-url.test.sh delete mode 100644 skills/claude-code-docs/SKILL.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json deleted file mode 100644 index 013d1e3..0000000 --- a/.claude-plugin/plugin.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "claude-code-docs", - "version": "1.0.0", - "description": "Fetch Claude Code docs as markdown - rewrites code.claude.com/docs page URLs to their .md source before WebFetch runs", - "author": { - "name": "PleaseAI", - "url": "https://github.com/pleaseai" - }, - "homepage": "https://github.com/pleaseai/claude-code-docs", - "license": "MIT", - "keywords": [ - "claude-code", - "docs", - "markdown", - "webfetch", - "hooks" - ] -} diff --git a/README.md b/README.md index c097612..b8088af 100644 --- a/README.md +++ b/README.md @@ -54,12 +54,14 @@ csp is optional: without it on `PATH`, `ask search` prints the resolved checkout ## Claude Code plugin: fetch docs as markdown -This repo is also a Claude Code plugin. A `PreToolUse` hook rewrites `code.claude.com/docs` page URLs to their `.md` source before WebFetch runs, so Claude reads the clean markdown twin instead of the HTML app shell: +The `claude-code-docs` Claude Code plugin now lives in [`pleaseai/claude-code-plugins`](https://github.com/pleaseai/claude-code-plugins/tree/main/plugins/claude-code-docs) (`plugins/claude-code-docs`). This repo is the docs mirror only. Moving the plugin out means installing it no longer clones this repo, which is large because of `docs/` and `llms-full.txt`. The install command is unchanged: ```bash /plugin install claude-code-docs@pleaseai ``` +A `PreToolUse` hook rewrites `code.claude.com/docs` page URLs to their `.md` source before WebFetch runs, so Claude reads the clean markdown twin instead of the HTML app shell: + | WebFetch input | Rewritten to | |---|---| | `https://code.claude.com/docs/en/agents` | `https://code.claude.com/docs/en/agents.md` | @@ -67,7 +69,7 @@ This repo is also a Claude Code plugin. A `PreToolUse` hook rewrites `code.claud Left untouched: URLs already ending in a file extension (`.md`, `llms.txt`, images), the docs root, and everything outside `code.claude.com/docs`. The hook returns [`updatedInput` with `permissionDecision: "allow"`](https://code.claude.com/docs/en/hooks#pretooluse-decision-control), so the rewritten fetch runs without an extra prompt. -Hook tests: `bash hooks/rewrite-docs-url.test.sh` +Source and hook tests: [`plugins/claude-code-docs`](https://github.com/pleaseai/claude-code-plugins/tree/main/plugins/claude-code-docs) in `pleaseai/claude-code-plugins`. ### Skill: `/claude-code-docs:claude-code-docs [question]` diff --git a/hooks/hooks.json b/hooks/hooks.json deleted file mode 100644 index fc0a342..0000000 --- a/hooks/hooks.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "description": "Rewrites code.claude.com/docs page URLs to their .md source so WebFetch gets clean markdown instead of the HTML app shell", - "hooks": { - "PreToolUse": [ - { - "matcher": "WebFetch", - "hooks": [ - { - "type": "command", - "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/rewrite-docs-url.sh", - "timeout": 5 - } - ] - } - ] - } -} diff --git a/hooks/rewrite-docs-url.sh b/hooks/rewrite-docs-url.sh deleted file mode 100755 index 1f6e895..0000000 --- a/hooks/rewrite-docs-url.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# PreToolUse hook for WebFetch: rewrite Claude Code docs page URLs to their -# markdown source (https://code.claude.com/docs/en/agents -> .../agents.md). -# Every docs page serves a clean markdown twin at .md; fetching it skips -# the HTML app shell entirely. Silent exit 0 = no opinion, normal flow. - -input=$(cat) -url=$(jq -r '.tool_input.url // empty' <<<"$input") -[ -z "$url" ] && exit 0 - -case "$url" in - https://code.claude.com/docs/*) ;; - *) exit 0 ;; -esac - -# Drop fragment and query: hooks#pretooluse-decision-control -> hooks -path="${url%%#*}" -path="${path%%\?*}" -path="${path%/}" - -# Already a raw file (page .md, llms.txt, images, ...) - leave untouched. -# Check the last path segment only; the domain always contains dots. -case "${path##*/}" in - *.*) exit 0 ;; -esac - -# Only rewrite real pages under a locale segment (/docs//), -# not the docs root itself -rest="${path#https://code.claude.com/docs/}" -case "$rest" in - */*) ;; - *) exit 0 ;; -esac - -jq --arg url "${path}.md" '{ - hookSpecificOutput: { - hookEventName: "PreToolUse", - permissionDecision: "allow", - permissionDecisionReason: ("Rewrote Claude Code docs URL to markdown source: " + $url), - updatedInput: (.tool_input | .url = $url) - } -}' <<<"$input" diff --git a/hooks/rewrite-docs-url.test.sh b/hooks/rewrite-docs-url.test.sh deleted file mode 100755 index 3f78d41..0000000 --- a/hooks/rewrite-docs-url.test.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# Tests for rewrite-docs-url.sh. Run: bash hooks/rewrite-docs-url.test.sh -set -u -cd "$(dirname "$0")" -pass=0 fail=0 - -run() { - echo "$1" | bash ./rewrite-docs-url.sh -} - -expect_rewrite() { # input-url expected-url - out=$(run "{\"tool_name\":\"WebFetch\",\"tool_input\":{\"url\":\"$1\",\"prompt\":\"p\"}}") - got=$(jq -r '.hookSpecificOutput.updatedInput.url // empty' <<<"$out") - if [ "$got" = "$2" ]; then pass=$((pass+1)); else fail=$((fail+1)); echo "FAIL: $1 -> '$got' (expected $2)"; fi -} - -expect_silent() { # input-url - out=$(run "{\"tool_name\":\"WebFetch\",\"tool_input\":{\"url\":\"$1\",\"prompt\":\"p\"}}") - if [ -z "$out" ]; then pass=$((pass+1)); else fail=$((fail+1)); echo "FAIL: $1 should pass through, got: $out"; fi -} - -expect_rewrite "https://code.claude.com/docs/en/agents" "https://code.claude.com/docs/en/agents.md" -expect_rewrite "https://code.claude.com/docs/en/agents/" "https://code.claude.com/docs/en/agents.md" -expect_rewrite "https://code.claude.com/docs/en/hooks#pretooluse-decision-control" "https://code.claude.com/docs/en/hooks.md" -expect_rewrite "https://code.claude.com/docs/en/agent-sdk/python" "https://code.claude.com/docs/en/agent-sdk/python.md" -expect_rewrite "https://code.claude.com/docs/en/hooks?foo=bar" "https://code.claude.com/docs/en/hooks.md" - -expect_silent "https://code.claude.com/docs/en/agents.md" -expect_silent "https://code.claude.com/docs/llms.txt" -expect_silent "https://code.claude.com/docs/llms-full.txt" -expect_silent "https://code.claude.com/docs/en" -expect_silent "https://code.claude.com/docs" -expect_silent "https://example.com/docs/en/agents" -expect_silent "https://docs.claude.com/en/api/overview" - -# prompt must survive updatedInput (it replaces the whole input object) -out=$(run '{"tool_name":"WebFetch","tool_input":{"url":"https://code.claude.com/docs/en/agents","prompt":"summarize"}}') -got=$(jq -r '.hookSpecificOutput.updatedInput.prompt' <<<"$out") -if [ "$got" = "summarize" ]; then pass=$((pass+1)); else fail=$((fail+1)); echo "FAIL: prompt lost: $got"; fi - -echo "passed: $pass, failed: $fail" -[ "$fail" -eq 0 ] diff --git a/skills/claude-code-docs/SKILL.md b/skills/claude-code-docs/SKILL.md deleted file mode 100644 index a5b33f1..0000000 --- a/skills/claude-code-docs/SKILL.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -name: claude-code-docs -description: Answer questions about Claude Code (features, hooks, plugins, skills, MCP, Agent SDK, settings, CLI) from the official docs. Uses the ask CLI to resolve a version-pinned local mirror and csp for semantic search, falling back to grep and WebFetch. Use when the user asks how Claude Code works, what a configuration field does, or whether Claude Code supports something. -argument-hint: [question] -arguments: [question] ---- - -Answer this question about Claude Code using the official documentation: - -**$question** - -## How to find the answer - -Work through these steps, falling back gracefully when a tool is missing. - -### 1. Resolve the docs mirror - -```bash -DOCS="$(ask src github:pleaseai/claude-code-docs)/docs" -``` - -`ask src` prints the root of a cached checkout of the docs mirror (clones on first use). If the `ask` CLI is not on PATH, run it via npx/bunx instead: - -```bash -DOCS="$(npx -y @pleaseai/ask src github:pleaseai/claude-code-docs)/docs" -``` - -Only fall back to step 4 (WebFetch) when neither works, such as offline sandboxes without npm registry access. - -### 2. Search for relevant pages - -Prefer semantic search with csp, scoped to the per-page markdown: - -```bash -csp search "$question" "$DOCS" --content docs --top-k 8 -``` - -Or equivalently via ask (requires csp on PATH): - -```bash -ask search github:pleaseai/claude-code-docs "$question" --content docs --top-k 8 -``` - -If csp is not on PATH, run it via npx/bunx: - -```bash -npx -y @pleaseai/csp search "$question" "$DOCS" --content docs --top-k 8 -``` - -If that fails too, fall back to grep over the mirror — search for 2-3 distinct keyword variants, not one long phrase: - -```bash -grep -ril "" "$DOCS" -``` - -The manifest at `$DOCS/../llms.txt` lists every page with a one-line summary; reading it is a fast way to shortlist pages when keyword search is noisy. - -### 3. Read and answer - -Read the top matching pages (whole pages — they are small). Ground every claim in what the pages actually say: - -- Answer in the user's language; keep code identifiers, field names, and flags verbatim. -- Cite each source page with its canonical URL: a mirror file `$DOCS/hooks.md` corresponds to `https://code.claude.com/docs/en/hooks`. -- Quote exact field names, JSON shapes, and version requirements (`min-version` markers) when they matter. -- If the docs do not answer the question, say so explicitly — do not fill gaps from memory. - -### 4. Fallback: WebFetch - -If the `ask` CLI is unavailable, fetch `https://code.claude.com/docs/llms.txt`, pick the relevant page URLs from the manifest, and fetch each as `.md` (this plugin's hook rewrites page URLs to `.md` automatically). Then answer as in step 3.