Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
code-yeongyu avatar

Web Fetch

  • 2 installs
  • 4 repo stars
  • Updated June 12, 2026
  • code-yeongyu/web-fetch

Fetch and parse content from web URLs for processing and analysis

About

Fetches and parses content from URLs for agents to download pages and extract text. Enables web content processing and analysis.

  • URL content fetching
  • Content parsing

Web Fetch by the numbers

  • 2 all-time installs (skills.sh)
  • Ranked #1,839 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
  • Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/code-yeongyu/web-fetch --skill web-fetch

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs2
repo stars4
Last updatedJune 12, 2026
Repositorycode-yeongyu/web-fetch

What it does

Fetch and parse content from web URLs for processing and analysis

Files

SKILL.mdMarkdownGitHub ↗

web-fetch

Fetch a URL, write the body to $TMPDIR/web-fetch-<runid>/, print the path. Pipe the path through rg / jq / awk to surgically extract what you need.

Why this skill exists

The built-in webfetch tool dumps the whole rendered page into the conversation. For anything bigger than a few KB that drowns the context window. The fix is dead simple: write the page to disk, then grep it.

That is all this skill does. One curl call, one Cloudflare-aware retry, HTML → Markdown via stdlib, save to a temp dir, print the path. No providers, no fallback chain, no fancy machinery. The same shape as pi-webfetch and opencode/webfetch, but as a standalone skill that works from any agent (Claude Code, OpenCode, pi, hermes, openclaw, whatever speaks Bash).

When to use it

Trigger this skill any time the user hands you a URL and the goal is to read its content. Examples:

  • "Fetch <https://docs.python.org/3/library/asyncio.html> and tell me about TaskGroup."
  • "Read the README at <https://github.com/anthropics/anthropic-sdk-python>."
  • "What does this article say about <topic>? <URL>"
  • "Pull <PR url>, what's the key change?"
  • "Fetch the page and pull out only the deprecated section."

If the URL is https://example.com and you only need 3 lines, the built-in tool is fine. Use this skill when the page is non-trivially large or you want to filter before reading.

How to invoke it

The script is at scripts/web_fetch.py. It needs python3 (3.9+) and ideally curl (auto-detected; urllib fallback works too).

Basic fetch (markdown is default)

python3 <skill_dir>/scripts/web_fetch.py https://docs.python.org/3/library/asyncio.html

Stdout prints two lines:

/tmp/web-fetch-20260501-171120-abc123/result.md
/tmp/web-fetch-20260501-171120-abc123/result.json

result.md is the converted markdown. result.json is the same content plus a _meta envelope.

Pick format

python3 web_fetch.py https://example.com --format markdown   # default; HTML auto-converted
python3 web_fetch.py https://example.com --format text       # tags stripped, entities decoded
python3 web_fetch.py https://example.com --format html       # original HTML untouched
python3 web_fetch.py https://example.com --format raw        # bytes-as-they-came (no conversion)

Other flags

FlagDefaultPurpose
--timeout SEC30 (cap 120)Per-request timeout
--output-dir PATH$TMPDIR/web-fetch-<runid>Custom output dir for stable paths
--print-path {all,content,json}allWhat to print on stdout
--print-contentoffAlso dump rendered content to stdout (for direct piping)
--use-curl / --use-urllibautoForce the HTTP transport
--quiet / --verboseoffTrace verbosity

The pipe-and-grep pattern

This is the whole point. Resist the temptation to read the entire result.md. Use the path:

# Capture the content path
CONTENT=$(python3 web_fetch.py https://docs.python.org/3/library/asyncio.html --print-path content --quiet)

# Find the relevant section
rg -n "TaskGroup" "$CONTENT" | head -20

# Get N lines of context around a match
rg -B2 -A8 "asyncio.run" "$CONTENT" | head -40

# Multiple keywords
rg -in "deprecated|removed|since 3\.1[0-9]" "$CONTENT"

# Grab specific markdown sections (## or ### headings)
awk '/^## TaskGroup/,/^## /' "$CONTENT"

For headers / metadata extraction:

JSON=$(python3 web_fetch.py https://example.com --print-path json --quiet)
jq -r '._meta.final_url, ._meta.content_type, ._meta.bytes' "$JSON"
jq -r '._meta.attempts[] | "\(.user_agent): \(.status) (\(.duration_ms)ms)"' "$JSON"

For Windows PowerShell, see references/pipelines-windows.md.

What gets written

$TMPDIR/web-fetch-<runid>/
├── result.md          rendered markdown (or .txt / .html depending on --format)
├── result.json        { content, _meta }
├── trace.json         _meta only (faster to inspect)
└── raw.html           original response body (or raw.bin for non-text)

Useful when:

  • You want to compare rendered markdown against raw HTML (diff result.md raw.html).
  • You want to keep the raw bytes around for forensic / replay use.
  • You want the structured _meta separate from the content for cheap inspection.

The _meta envelope

Every successful fetch produces this metadata:

{
  "version": "0.1.0",
  "url": "https://docs.python.org/3/library/asyncio.html",
  "format": "markdown",
  "ok": true,
  "http_status": 200,
  "content_type": "text/html",
  "final_url": "https://docs.python.org/3/library/asyncio.html",
  "converted": true,
  "bytes": 41023,
  "raw_bytes": 198541,
  "attempts": [
    {"user_agent": "browser", "status": 200, "duration_ms": 187, "bytes": 198541,
     "content_type": "text/html", "final_url": "...", "cf_challenge": false}
  ],
  "duration_ms": 199,
  "started_at": "2026-05-01T08:11:20.045449+00:00",
  "raw_path": "/tmp/.../raw.html",
  "content_path": "/tmp/.../result.md",
  "output_dir": "/tmp/.../",
  "transport": "curl"
}

attempts[] shows the actual HTTP calls. If a Cloudflare challenge fired, you will see two entries (browser then honest). If you need to debug a fetch that "looks weird," dump this trace.

Cloudflare retry (built-in)

Some sites return HTTP 403 with a Cloudflare challenge page when called with a browser-like UA but a non-browser TLS fingerprint. The skill detects this case (status 403 or 503 plus body markers like <title>Just a moment...</title> or cf-mitigated) and retries once with a plain web-fetch/<version> UA. Some operators allow honest UAs through. This is the same trick pi-webfetch and opencode/webfetch use.

If both attempts fail, the script exits with code 2 and the trace records both attempts so you can see exactly why.

Limits

  • 5 MB response cap. Anything larger is rejected (curl uses --max-filesize; urllib reads N+1 then aborts).
  • 120 second timeout cap. --timeout larger than this is silently clamped.
  • Read-only. This skill never modifies remote state; all calls are GET.
  • Public HTTP/HTTPS only. No file://, no localhost shortcuts, no credentials in the URL.
  • No JS rendering. If the page needs a real browser to populate content, you will get the unhydrated shell. For SPAs / aggressively dynamic content, use a headless-browser tool (playwright, firecrawl, etc.) outside this skill.

Key invariants (do not break)

  • Content lives on disk, not in the conversation. Quote what is relevant from the file. Never paste a full fetched body into your response unless the user explicitly asked for the full content.
  • Always mention the path. When you tell the user "I fetched X", also mention where it is on disk so they can grep it themselves.
  • Pipe before reading. When the user asks a specific question about the page, run rg / jq / awk against the saved path and quote only matching lines. Do not pre-load the entire file.
  • Trace is machine-readable. If a fetch fails, surface the per-attempt error from trace.json, do not blindly retry the same URL with the same args.

More

  • references/pipelines-posix.md - rg/jq/awk worked examples for macOS / Linux / WSL / Git Bash.
  • references/pipelines-windows.md - PowerShell + cmd equivalents.
  • references/compat.md - per-OS support matrix, Python/curl version floor, Windows / WSL / Alpine / RHEL 7 setup.
  • references/troubleshooting.md - 403 / 429 / Cloudflare / TLS / proxy gotchas and how to read the trace.
  • README.md - install, packaging, registration into pi/senpi/.agents/skills/, project structure.

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.