[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DER0VJS29J4SBMSVXPA40A":3,"skill-same:01M6DER0VJS29J4SBMSVXPA40A":100},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":36,"linkOnly":37,"markdownContent":38,"markdownBody":39,"frontMatter":40,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":6,"ownerHtmlUrl":59,"ownerBlogUrl":6,"ownerDescription":60,"updatedAt":61,"install":62,"resources":75},"01M6DER0VJS29J4SBMSVXPA40A","pinggy-tunnel",null,"Zero-install localhost tunnels over SSH via Pinggy.","zapabob\u002FSkills","zapabob","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F130830376?v=4","01M6DBMYZAGRTFQDSQYW3W764P","峯岸 亮","01M6DBMZ3GKDSJ01NZ9XTZD7JD",2,"MIT","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Farchive\u002Fskill-md-reviewed\u002Fsha256\u002F3f\u002F3fea1ca48b4e9fd7f4decd7e22c1bddfb61aceaea38241bb6349d6baaf2a0065\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35],"tunnel","pinggy tunnel","macos","linux","windows","networking","ZeRO","ssh","hermes","hermes agent","install","webhook","2026-11-10 10:12:30",false,"---\nname: pinggy-tunnel\ndescription: Zero-install localhost tunnels over SSH via Pinggy.\nversion: 0.1.0\nauthor: Teknium (teknium1), Hermes Agent\nlicense: MIT\nplatforms: [linux, macos, windows]\nmetadata:\n  hermes:\n    tags: [Pinggy, Tunnel, Networking, SSH, Webhook, Localhost]\n    related_skills: []\n---\n\n# Pinggy Tunnel Skill\n\nExpose a local service (dev server, webhook receiver, MCP endpoint, demo) to the public internet using a Pinggy SSH reverse tunnel. No daemon to install — the user's stock SSH client connects to `a.pinggy.io:443` and Pinggy hands back a public HTTP\u002FHTTPS URL.\n\nFree tier: 60-minute tunnels, random subdomain, no signup. Pro tier ($3\u002Fmo) is an opt-in with a token.\n\n## When to Use\n\n- User asks to \"expose this locally\", \"share my dev server\", \"make this URL public\", \"tunnel port N\", \"get a public URL for a webhook\"\n- Need to receive a webhook callback during a local task (Stripe, GitHub, Discord, AgentMail)\n- Sharing a one-off HTTP demo (MCP server, Ollama\u002FvLLM endpoint, dashboard) with a remote party\n- The host has SSH but no `cloudflared` \u002F `ngrok` binary, and installing one would be overkill\n\nIf the host already has `cloudflared` configured, prefer the `cloudflared-quick-tunnel` skill — Cloudflare quick tunnels don't expire after 60 minutes.\n\n## Prerequisites\n\n- `ssh` on PATH (`ssh -V`). Default on Linux, macOS, and Windows 10+. No other install.\n- A local service listening on `127.0.0.1:\u003Cport>` before the tunnel starts. Pinggy will return URLs but they'll 502 until the local origin is up.\n\nOptional:\n\n- `PINGGY_TOKEN` env var for paid Pro features (persistent subdomain, custom domain, multiple tunnels, no 60-minute cap). Free tier needs no credentials.\n\n## Quick Reference\n\n```bash\n# Plain HTTP\u002FHTTPS tunnel for port 8000 (free tier)\nssh -p 443 -o StrictHostKeyChecking=no -o ServerAliveInterval=30 \\\n    -R0:localhost:8000 [REDACTED_EMAIL]\n\n# TCP tunnel (databases, raw SSH, etc.)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:5432 [REDACTED_EMAIL]\n\n# TLS tunnel (Pinggy can't decrypt — bring your own certs at origin)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:443 [REDACTED_EMAIL]\n\n# Basic auth gate (b:user:pass)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \\\n    \"b:admin:[REDACTED_EMAIL]\"\n\n# Bearer token gate (k:token)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \\\n    \"k:[REDACTED_EMAIL]\"\n\n# IP whitelist (w:CIDR)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \\\n    \"w:203.0.113.0\u002F[REDACTED_EMAIL]\"\n\n# Enable CORS + force HTTPS redirect\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \\\n    \"co+x:[REDACTED_EMAIL]\"\n\n# Pro tier (persistent URL, no 60-min cap)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \"$PINGGY_TOKEN+a.pinggy.io\"\n```\n\n## Procedure — Start a Tunnel and Get the URL\n\nThe model SHOULD use the `terminal` tool. The tunnel must stay alive for the duration of the share, so run it as a background process and parse the public URL from stdout.\n\n### 1. Confirm a local origin is up\n\n```bash\ncurl -sI http:\u002F\u002F127.0.0.1:8000\u002F | head -1\n# expect HTTP\u002F1.x 200 (or any non-connection-refused response)\n```\n\nIf nothing is listening yet, start it first (e.g. `python -m http.server 8000 --bind 127.0.0.1`). Pinggy will happily return a URL pointed at nothing — the user will see 502 until the origin comes up.\n\n### 2. Launch the tunnel as a background process\n\nUse `terminal(background=True)` and capture output to a logfile (Pinggy prints the URLs on stdout, then keeps the connection open):\n\n```bash\nLOG=\u002Ftmp\u002Fpinggy-8000.log\nnohup ssh -p 443 \\\n    -o StrictHostKeyChecking=no \\\n    -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -o ServerAliveCountMax=3 \\\n    -R0:localhost:8000 [REDACTED_EMAIL] \\\n    > \"$LOG\" 2>&1 &\necho $! > \u002Ftmp\u002Fpinggy-8000.pid\n```\n\n`StrictHostKeyChecking=no` + `UserKnownHostsFile=\u002Fdev\u002Fnull` skips the first-run host-key prompt. `ServerAliveInterval=30` keeps the SSH session from getting torn down by an idle NAT.\n\n### 3. Parse the URL out of the log\n\n```bash\nsleep 4\ngrep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fpinggy-8000.log | head -1\n```\n\nExpected output looks like:\n\n```\nYou are not authenticated.\nYour tunnel will expire in 60 minutes.\nhttp:\u002F\u002Fyqycl-98-162-69-48.a.free.pinggy.link\nhttps:\u002F\u002Fyqycl-98-162-69-48.a.free.pinggy.link\n```\n\nHand the `https:\u002F\u002F...pinggy.link` URL to the user.\n\n### 4. Verify\n\n```bash\ncurl -sI https:\u002F\u002F\u003Cthe-url>\u002F | head -3\n# expect 200\u002F302\u002Fwhatever the local origin actually returns\n```\n\nIf you get `502 Bad Gateway`, the SSH session is up but the local origin isn't listening — fix step 1 first.\n\n### 5. Teardown\n\n```bash\nkill \"$(cat \u002Ftmp\u002Fpinggy-8000.pid)\"\n# or, if the pid file got lost:\npkill -f 'ssh -p 443 .* free@a\\.pinggy\\.io'\n```\n\nIf you have a session_id from `terminal(background=True)`, prefer `process(action='kill', session_id=...)`.\n\n## Access Control via Username Keywords\n\nPinggy stacks control flags into the SSH username separated by `+`. Always quote the whole `user@host` argument when it contains a `+`:\n\n| Keyword | Effect |\n|---------|--------|\n| `b:user:pass` | HTTP Basic auth gate |\n| `k:token` | Bearer-token header gate (`Authorization: Bearer \u003Ctoken>`) |\n| `w:CIDR` | IP whitelist (single IP or CIDR, repeatable) |\n| `co` | Add `Access-Control-Allow-Origin: *` (CORS) |\n| `x:https` | Force HTTPS — auto-redirect HTTP to HTTPS |\n| `a:Name:Value` | Add request header |\n| `u:Name:Value` | Update request header |\n| `r:Name` | Remove request header |\n| `qr` | Print a QR code of the URL to stdout (handy for mobile sharing) |\n\nCombine freely: `\"b:admin:secret+co+x:[REDACTED_EMAIL]\"`.\n\n## Web Debugger (optional)\n\nPinggy can mirror the inbound traffic to `localhost:4300` for inspection. Add a local forward to the SSH command:\n\n```bash\nssh -p 443 -L4300:localhost:4300 -R0:localhost:8000 [REDACTED_EMAIL]\n```\n\nThen open `http:\u002F\u002Flocalhost:4300` in a browser to see live request\u002Fresponse pairs.\n\n## Pitfalls\n\n- **60-minute hard cap on the free tier.** The SSH session terminates at the 60-minute mark; the URL goes dead. For longer shares, either use `PINGGY_TOKEN` (Pro) or auto-restart with a shell loop (note that the URL changes on every restart for free-tier).\n- **Free-tier URL is random and changes on restart.** Don't bookmark it, don't paste it into a config file. Re-parse from the log each time.\n- **Concurrent free tunnels are limited to one per source IP.** Starting a second tunnel from the same machine usually kills the first. Pro tier lifts this.\n- **`+` in usernames must be quoted.** Bare `ssh ... b:admin:[REDACTED_EMAIL]` works in bash but breaks under shells that treat `+` specially or when assembled programmatically. Always wrap in double quotes.\n- **Don't tunnel anything sensitive without an access-control flag.** A bare HTTP tunnel is reachable by anyone with the URL. Use `b:`, `k:`, or `w:` for non-public services.\n- **`process(action='log')` may miss SSH banner output.** Pinggy prints the URLs and then the SSH session goes interactive. Always redirect to a logfile and `grep` the file directly — same pattern as `cloudflared-quick-tunnel`.\n- **Host-key prompt on first run.** Default OpenSSH config asks the user to accept Pinggy's host key. Always pass `-o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull` for unattended runs.\n- **TCP and TLS tunnels return a `\u003Csubdomain>.a.pinggy.online:\u003Cport>` pair, not an https URL.** Parse with a different regex (`tcp:\u002F\u002F` and a port). Don't assume every Pinggy tunnel is HTTP.\n- **Pro mode requires the token as the username, not a flag.** Use `\"$PINGGY_TOKEN+a.pinggy.io\"` (no `free@`). With a token you can also add `:persistent` for a stable subdomain — see `pinggy.io\u002Fdocs\u002F`.\n\n## Recipes\n\nComposite patterns combining a local origin with a Pinggy tunnel. Each recipe is self-contained — start the origin, start the tunnel, parse the URL, hand it back to the user.\n\n### Recipe 1 — Receive a webhook callback\n\nUse this when an external service (Stripe, GitHub, Discord, AgentMail, etc.) needs to POST to a publicly reachable URL during a local task.\n\n```bash\n# 1. Tiny capturing server: every request gets appended to \u002Ftmp\u002Fwebhook-hits.log\ncat >\u002Ftmp\u002Fwebhook-server.py \u003C\u003C'PY'\nimport http.server, json, datetime, pathlib\nLOG = pathlib.Path(\"\u002Ftmp\u002Fwebhook-hits.log\")\nclass H(http.server.BaseHTTPRequestHandler):\n    def _capture(self):\n        n = int(self.headers.get(\"content-length\") or 0)\n        body = self.rfile.read(n).decode(\"utf-8\", \"replace\") if n else \"\"\n        rec = {\"t\": datetime.datetime.utcnow().isoformat(), \"path\": self.path,\n               \"method\": self.command, \"headers\": dict(self.headers), \"body\": body}\n        with LOG.open(\"a\") as f: f.write(json.dumps(rec) + \"\\n\")\n        self.send_response(200); self.send_header(\"content-type\",\"application\u002Fjson\")\n        self.end_headers(); self.wfile.write(b'{\"ok\":true}\\n')\n    def do_GET(self): self._capture()\n    def do_POST(self): self._capture()\n    def log_message(self,*a,**k): pass\nhttp.server.HTTPServer((\"127.0.0.1\", 18080), H).serve_forever()\nPY\nnohup python \u002Ftmp\u002Fwebhook-server.py >\u002Ftmp\u002Fwebhook-server.log 2>&1 &\necho $! >\u002Ftmp\u002Fwebhook-server.pid\n\n# 2. Tunnel — bearer-token-gate so randos can't pollute the capture log\nnohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -R0:localhost:18080 \"k:$(openssl rand -hex 12)[REDACTED_EMAIL]\" \\\n    >\u002Ftmp\u002Fwebhook-pinggy.log 2>&1 &\necho $! >\u002Ftmp\u002Fwebhook-pinggy.pid\nsleep 5\nURL=$(grep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fwebhook-pinggy.log | head -1)\necho \"Webhook URL: $URL\"\n\n# 3. While the agent works, watch hits land\ntail -f \u002Ftmp\u002Fwebhook-hits.log\n```\n\nHand `$URL` to the service that needs to call you. Teardown: `kill $(cat \u002Ftmp\u002Fwebhook-server.pid) $(cat \u002Ftmp\u002Fwebhook-pinggy.pid)`.\n\n### Recipe 2 — Expose an MCP server over HTTP\u002FSSE\n\nUse when a remote MCP client (Claude Desktop on another machine, a teammate's editor, etc.) needs to reach an MCP server running on the local box. Only works for MCP servers that speak HTTP transport — stdio-mode servers can't be tunneled.\n\n```bash\n# 1. Start the MCP server in HTTP mode (example: a FastMCP server on port 8765)\nnohup python my_mcp_server.py --transport http --port 8765 \\\n    >\u002Ftmp\u002Fmcp-server.log 2>&1 &\necho $! >\u002Ftmp\u002Fmcp-server.pid\n\n# 2. Tunnel with a bearer token — MCP traffic should not be open to the internet\nTOKEN=$(openssl rand -hex 16)\nnohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -R0:localhost:8765 \"k:$[REDACTED_EMAIL]\" \\\n    >\u002Ftmp\u002Fmcp-pinggy.log 2>&1 &\necho $! >\u002Ftmp\u002Fmcp-pinggy.pid\nsleep 5\nURL=$(grep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fmcp-pinggy.log | head -1)\necho \"MCP URL: $URL\"\necho \"Bearer token: $TOKEN\"\n```\n\nThe remote client connects to `$URL` with `Authorization: Bearer $TOKEN`. Hermes' own native MCP client config: `{\"transport\": \"http\", \"url\": \"\u003CURL>\", \"headers\": {\"Authorization\": \"Bearer \u003CTOKEN>\"}}`.\n\n### Recipe 3 — Expose a local LLM endpoint (Ollama \u002F vLLM \u002F llama.cpp)\n\nShare a local model with a remote caller (another agent, a phone, a teammate). Ollama listens on `:11434`, vLLM and llama.cpp typically on `:8000`.\n\n```bash\n# Pre-req: the model server is already running on 127.0.0.1:11434 (Ollama default)\nTOKEN=$(openssl rand -hex 16)\nnohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -R0:localhost:11434 \"k:$[REDACTED_EMAIL]\" \\\n    >\u002Ftmp\u002Fllm-pinggy.log 2>&1 &\necho $! >\u002Ftmp\u002Fllm-pinggy.pid\nsleep 5\nURL=$(grep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fllm-pinggy.log | head -1)\necho \"Endpoint: $URL\"\necho \"Token:    $TOKEN\"\n\n# Verify\ncurl -s \"$URL\u002Fapi\u002Ftags\" -H \"Authorization: Bearer $TOKEN\" | head\n```\n\n`co` enables CORS so a browser caller can hit the endpoint. Drop `co` for backend-only callers. For an OpenAI-compatible vLLM\u002Fllama.cpp endpoint, callers use base URL `$URL\u002Fv1` with `Authorization: Bearer $TOKEN` — but note Pinggy strips\u002Freplaces nothing in the body, so the model server itself sees Pinggy's token; the local server should be configured to ignore auth (it's already on `127.0.0.1`) and let Pinggy do the gating.\n\n### Recipe 4 — Share a dev server with a one-shot password\n\nThe fastest \"let a teammate poke at my running app\" pattern. Random password, prints once, dies when you Ctrl-C.\n\n```bash\nPASS=$(openssl rand -base64 12 | tr -d '+\u002F=' | head -c 12)\necho \"Dev server password: $PASS\"\nssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -R0:localhost:3000 \"b:dev:$PASS+co+x:[REDACTED_EMAIL]\"\n# URL prints to the terminal. Share URL + password. Ctrl-C to tear down.\n```\n\n`b:dev:$PASS` gates the URL with HTTP Basic auth. `x:https` forces TLS. `co` adds CORS for SPA frontends.\n\n## Verification\n\n```bash\n# End-to-end: spin up a trivial origin, tunnel it, hit it, tear down\npython -m http.server 18000 --bind 127.0.0.1 >\u002Ftmp\u002Forigin.log 2>&1 &\nORIGIN_PID=$!\n\nnohup ssh -p 443 \\\n    -o StrictHostKeyChecking=no \\\n    -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -R0:localhost:18000 [REDACTED_EMAIL] >\u002Ftmp\u002Fpinggy-verify.log 2>&1 &\nSSH_PID=$!\n\nsleep 5\nURL=$(grep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fpinggy-verify.log | head -1)\necho \"URL: $URL\"\ncurl -sI \"$URL\u002F\" | head -1\n\nkill \"$SSH_PID\" \"$ORIGIN_PID\"\n```\n\nExpected: a `pinggy.link` URL and `HTTP\u002F2 200` on the curl head.\n","# Pinggy Tunnel Skill\n\nExpose a local service (dev server, webhook receiver, MCP endpoint, demo) to the public internet using a Pinggy SSH reverse tunnel. No daemon to install — the user's stock SSH client connects to `a.pinggy.io:443` and Pinggy hands back a public HTTP\u002FHTTPS URL.\n\nFree tier: 60-minute tunnels, random subdomain, no signup. Pro tier ($3\u002Fmo) is an opt-in with a token.\n\n## When to Use\n\n- User asks to \"expose this locally\", \"share my dev server\", \"make this URL public\", \"tunnel port N\", \"get a public URL for a webhook\"\n- Need to receive a webhook callback during a local task (Stripe, GitHub, Discord, AgentMail)\n- Sharing a one-off HTTP demo (MCP server, Ollama\u002FvLLM endpoint, dashboard) with a remote party\n- The host has SSH but no `cloudflared` \u002F `ngrok` binary, and installing one would be overkill\n\nIf the host already has `cloudflared` configured, prefer the `cloudflared-quick-tunnel` skill — Cloudflare quick tunnels don't expire after 60 minutes.\n\n## Prerequisites\n\n- `ssh` on PATH (`ssh -V`). Default on Linux, macOS, and Windows 10+. No other install.\n- A local service listening on `127.0.0.1:\u003Cport>` before the tunnel starts. Pinggy will return URLs but they'll 502 until the local origin is up.\n\nOptional:\n\n- `PINGGY_TOKEN` env var for paid Pro features (persistent subdomain, custom domain, multiple tunnels, no 60-minute cap). Free tier needs no credentials.\n\n## Quick Reference\n\n```bash\n# Plain HTTP\u002FHTTPS tunnel for port 8000 (free tier)\nssh -p 443 -o StrictHostKeyChecking=no -o ServerAliveInterval=30 \\\n    -R0:localhost:8000 [REDACTED_EMAIL]\n\n# TCP tunnel (databases, raw SSH, etc.)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:5432 [REDACTED_EMAIL]\n\n# TLS tunnel (Pinggy can't decrypt — bring your own certs at origin)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:443 [REDACTED_EMAIL]\n\n# Basic auth gate (b:user:pass)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \\\n    \"b:admin:[REDACTED_EMAIL]\"\n\n# Bearer token gate (k:token)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \\\n    \"k:[REDACTED_EMAIL]\"\n\n# IP whitelist (w:CIDR)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \\\n    \"w:203.0.113.0\u002F[REDACTED_EMAIL]\"\n\n# Enable CORS + force HTTPS redirect\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \\\n    \"co+x:[REDACTED_EMAIL]\"\n\n# Pro tier (persistent URL, no 60-min cap)\nssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \"$PINGGY_TOKEN+a.pinggy.io\"\n```\n\n## Procedure — Start a Tunnel and Get the URL\n\nThe model SHOULD use the `terminal` tool. The tunnel must stay alive for the duration of the share, so run it as a background process and parse the public URL from stdout.\n\n### 1. Confirm a local origin is up\n\n```bash\ncurl -sI http:\u002F\u002F127.0.0.1:8000\u002F | head -1\n# expect HTTP\u002F1.x 200 (or any non-connection-refused response)\n```\n\nIf nothing is listening yet, start it first (e.g. `python -m http.server 8000 --bind 127.0.0.1`). Pinggy will happily return a URL pointed at nothing — the user will see 502 until the origin comes up.\n\n### 2. Launch the tunnel as a background process\n\nUse `terminal(background=True)` and capture output to a logfile (Pinggy prints the URLs on stdout, then keeps the connection open):\n\n```bash\nLOG=\u002Ftmp\u002Fpinggy-8000.log\nnohup ssh -p 443 \\\n    -o StrictHostKeyChecking=no \\\n    -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -o ServerAliveCountMax=3 \\\n    -R0:localhost:8000 [REDACTED_EMAIL] \\\n    > \"$LOG\" 2>&1 &\necho $! > \u002Ftmp\u002Fpinggy-8000.pid\n```\n\n`StrictHostKeyChecking=no` + `UserKnownHostsFile=\u002Fdev\u002Fnull` skips the first-run host-key prompt. `ServerAliveInterval=30` keeps the SSH session from getting torn down by an idle NAT.\n\n### 3. Parse the URL out of the log\n\n```bash\nsleep 4\ngrep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fpinggy-8000.log | head -1\n```\n\nExpected output looks like:\n\n```\nYou are not authenticated.\nYour tunnel will expire in 60 minutes.\nhttp:\u002F\u002Fyqycl-98-162-69-48.a.free.pinggy.link\nhttps:\u002F\u002Fyqycl-98-162-69-48.a.free.pinggy.link\n```\n\nHand the `https:\u002F\u002F...pinggy.link` URL to the user.\n\n### 4. Verify\n\n```bash\ncurl -sI https:\u002F\u002F\u003Cthe-url>\u002F | head -3\n# expect 200\u002F302\u002Fwhatever the local origin actually returns\n```\n\nIf you get `502 Bad Gateway`, the SSH session is up but the local origin isn't listening — fix step 1 first.\n\n### 5. Teardown\n\n```bash\nkill \"$(cat \u002Ftmp\u002Fpinggy-8000.pid)\"\n# or, if the pid file got lost:\npkill -f 'ssh -p 443 .* free@a\\.pinggy\\.io'\n```\n\nIf you have a session_id from `terminal(background=True)`, prefer `process(action='kill', session_id=...)`.\n\n## Access Control via Username Keywords\n\nPinggy stacks control flags into the SSH username separated by `+`. Always quote the whole `user@host` argument when it contains a `+`:\n\n| Keyword | Effect |\n|---------|--------|\n| `b:user:pass` | HTTP Basic auth gate |\n| `k:token` | Bearer-token header gate (`Authorization: Bearer \u003Ctoken>`) |\n| `w:CIDR` | IP whitelist (single IP or CIDR, repeatable) |\n| `co` | Add `Access-Control-Allow-Origin: *` (CORS) |\n| `x:https` | Force HTTPS — auto-redirect HTTP to HTTPS |\n| `a:Name:Value` | Add request header |\n| `u:Name:Value` | Update request header |\n| `r:Name` | Remove request header |\n| `qr` | Print a QR code of the URL to stdout (handy for mobile sharing) |\n\nCombine freely: `\"b:admin:secret+co+x:[REDACTED_EMAIL]\"`.\n\n## Web Debugger (optional)\n\nPinggy can mirror the inbound traffic to `localhost:4300` for inspection. Add a local forward to the SSH command:\n\n```bash\nssh -p 443 -L4300:localhost:4300 -R0:localhost:8000 [REDACTED_EMAIL]\n```\n\nThen open `http:\u002F\u002Flocalhost:4300` in a browser to see live request\u002Fresponse pairs.\n\n## Pitfalls\n\n- **60-minute hard cap on the free tier.** The SSH session terminates at the 60-minute mark; the URL goes dead. For longer shares, either use `PINGGY_TOKEN` (Pro) or auto-restart with a shell loop (note that the URL changes on every restart for free-tier).\n- **Free-tier URL is random and changes on restart.** Don't bookmark it, don't paste it into a config file. Re-parse from the log each time.\n- **Concurrent free tunnels are limited to one per source IP.** Starting a second tunnel from the same machine usually kills the first. Pro tier lifts this.\n- **`+` in usernames must be quoted.** Bare `ssh ... b:admin:[REDACTED_EMAIL]` works in bash but breaks under shells that treat `+` specially or when assembled programmatically. Always wrap in double quotes.\n- **Don't tunnel anything sensitive without an access-control flag.** A bare HTTP tunnel is reachable by anyone with the URL. Use `b:`, `k:`, or `w:` for non-public services.\n- **`process(action='log')` may miss SSH banner output.** Pinggy prints the URLs and then the SSH session goes interactive. Always redirect to a logfile and `grep` the file directly — same pattern as `cloudflared-quick-tunnel`.\n- **Host-key prompt on first run.** Default OpenSSH config asks the user to accept Pinggy's host key. Always pass `-o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull` for unattended runs.\n- **TCP and TLS tunnels return a `\u003Csubdomain>.a.pinggy.online:\u003Cport>` pair, not an https URL.** Parse with a different regex (`tcp:\u002F\u002F` and a port). Don't assume every Pinggy tunnel is HTTP.\n- **Pro mode requires the token as the username, not a flag.** Use `\"$PINGGY_TOKEN+a.pinggy.io\"` (no `free@`). With a token you can also add `:persistent` for a stable subdomain — see `pinggy.io\u002Fdocs\u002F`.\n\n## Recipes\n\nComposite patterns combining a local origin with a Pinggy tunnel. Each recipe is self-contained — start the origin, start the tunnel, parse the URL, hand it back to the user.\n\n### Recipe 1 — Receive a webhook callback\n\nUse this when an external service (Stripe, GitHub, Discord, AgentMail, etc.) needs to POST to a publicly reachable URL during a local task.\n\n```bash\n# 1. Tiny capturing server: every request gets appended to \u002Ftmp\u002Fwebhook-hits.log\ncat >\u002Ftmp\u002Fwebhook-server.py \u003C\u003C'PY'\nimport http.server, json, datetime, pathlib\nLOG = pathlib.Path(\"\u002Ftmp\u002Fwebhook-hits.log\")\nclass H(http.server.BaseHTTPRequestHandler):\n    def _capture(self):\n        n = int(self.headers.get(\"content-length\") or 0)\n        body = self.rfile.read(n).decode(\"utf-8\", \"replace\") if n else \"\"\n        rec = {\"t\": datetime.datetime.utcnow().isoformat(), \"path\": self.path,\n               \"method\": self.command, \"headers\": dict(self.headers), \"body\": body}\n        with LOG.open(\"a\") as f: f.write(json.dumps(rec) + \"\\n\")\n        self.send_response(200); self.send_header(\"content-type\",\"application\u002Fjson\")\n        self.end_headers(); self.wfile.write(b'{\"ok\":true}\\n')\n    def do_GET(self): self._capture()\n    def do_POST(self): self._capture()\n    def log_message(self,*a,**k): pass\nhttp.server.HTTPServer((\"127.0.0.1\", 18080), H).serve_forever()\nPY\nnohup python \u002Ftmp\u002Fwebhook-server.py >\u002Ftmp\u002Fwebhook-server.log 2>&1 &\necho $! >\u002Ftmp\u002Fwebhook-server.pid\n\n# 2. Tunnel — bearer-token-gate so randos can't pollute the capture log\nnohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -R0:localhost:18080 \"k:$(openssl rand -hex 12)[REDACTED_EMAIL]\" \\\n    >\u002Ftmp\u002Fwebhook-pinggy.log 2>&1 &\necho $! >\u002Ftmp\u002Fwebhook-pinggy.pid\nsleep 5\nURL=$(grep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fwebhook-pinggy.log | head -1)\necho \"Webhook URL: $URL\"\n\n# 3. While the agent works, watch hits land\ntail -f \u002Ftmp\u002Fwebhook-hits.log\n```\n\nHand `$URL` to the service that needs to call you. Teardown: `kill $(cat \u002Ftmp\u002Fwebhook-server.pid) $(cat \u002Ftmp\u002Fwebhook-pinggy.pid)`.\n\n### Recipe 2 — Expose an MCP server over HTTP\u002FSSE\n\nUse when a remote MCP client (Claude Desktop on another machine, a teammate's editor, etc.) needs to reach an MCP server running on the local box. Only works for MCP servers that speak HTTP transport — stdio-mode servers can't be tunneled.\n\n```bash\n# 1. Start the MCP server in HTTP mode (example: a FastMCP server on port 8765)\nnohup python my_mcp_server.py --transport http --port 8765 \\\n    >\u002Ftmp\u002Fmcp-server.log 2>&1 &\necho $! >\u002Ftmp\u002Fmcp-server.pid\n\n# 2. Tunnel with a bearer token — MCP traffic should not be open to the internet\nTOKEN=$(openssl rand -hex 16)\nnohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -R0:localhost:8765 \"k:$[REDACTED_EMAIL]\" \\\n    >\u002Ftmp\u002Fmcp-pinggy.log 2>&1 &\necho $! >\u002Ftmp\u002Fmcp-pinggy.pid\nsleep 5\nURL=$(grep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fmcp-pinggy.log | head -1)\necho \"MCP URL: $URL\"\necho \"Bearer token: $TOKEN\"\n```\n\nThe remote client connects to `$URL` with `Authorization: Bearer $TOKEN`. Hermes' own native MCP client config: `{\"transport\": \"http\", \"url\": \"\u003CURL>\", \"headers\": {\"Authorization\": \"Bearer \u003CTOKEN>\"}}`.\n\n### Recipe 3 — Expose a local LLM endpoint (Ollama \u002F vLLM \u002F llama.cpp)\n\nShare a local model with a remote caller (another agent, a phone, a teammate). Ollama listens on `:11434`, vLLM and llama.cpp typically on `:8000`.\n\n```bash\n# Pre-req: the model server is already running on 127.0.0.1:11434 (Ollama default)\nTOKEN=$(openssl rand -hex 16)\nnohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -R0:localhost:11434 \"k:$[REDACTED_EMAIL]\" \\\n    >\u002Ftmp\u002Fllm-pinggy.log 2>&1 &\necho $! >\u002Ftmp\u002Fllm-pinggy.pid\nsleep 5\nURL=$(grep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fllm-pinggy.log | head -1)\necho \"Endpoint: $URL\"\necho \"Token:    $TOKEN\"\n\n# Verify\ncurl -s \"$URL\u002Fapi\u002Ftags\" -H \"Authorization: Bearer $TOKEN\" | head\n```\n\n`co` enables CORS so a browser caller can hit the endpoint. Drop `co` for backend-only callers. For an OpenAI-compatible vLLM\u002Fllama.cpp endpoint, callers use base URL `$URL\u002Fv1` with `Authorization: Bearer $TOKEN` — but note Pinggy strips\u002Freplaces nothing in the body, so the model server itself sees Pinggy's token; the local server should be configured to ignore auth (it's already on `127.0.0.1`) and let Pinggy do the gating.\n\n### Recipe 4 — Share a dev server with a one-shot password\n\nThe fastest \"let a teammate poke at my running app\" pattern. Random password, prints once, dies when you Ctrl-C.\n\n```bash\nPASS=$(openssl rand -base64 12 | tr -d '+\u002F=' | head -c 12)\necho \"Dev server password: $PASS\"\nssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -o ServerAliveInterval=30 \\\n    -R0:localhost:3000 \"b:dev:$PASS+co+x:[REDACTED_EMAIL]\"\n# URL prints to the terminal. Share URL + password. Ctrl-C to tear down.\n```\n\n`b:dev:$PASS` gates the URL with HTTP Basic auth. `x:https` forces TLS. `co` adds CORS for SPA frontends.\n\n## Verification\n\n```bash\n# End-to-end: spin up a trivial origin, tunnel it, hit it, tear down\npython -m http.server 18000 --bind 127.0.0.1 >\u002Ftmp\u002Forigin.log 2>&1 &\nORIGIN_PID=$!\n\nnohup ssh -p 443 \\\n    -o StrictHostKeyChecking=no \\\n    -o UserKnownHostsFile=\u002Fdev\u002Fnull \\\n    -R0:localhost:18000 [REDACTED_EMAIL] >\u002Ftmp\u002Fpinggy-verify.log 2>&1 &\nSSH_PID=$!\n\nsleep 5\nURL=$(grep -oE 'https:\u002F\u002F[a-z0-9-]+\\.[a-z]+\\.pinggy\\.link' \u002Ftmp\u002Fpinggy-verify.log | head -1)\necho \"URL: $URL\"\ncurl -sI \"$URL\u002F\" | head -1\n\nkill \"$SSH_PID\" \"$ORIGIN_PID\"\n```\n\nExpected: a `pinggy.link` URL and `HTTP\u002F2 200` on the curl head.\n",{"name":5,"author":41,"license":15,"version":42,"metadata":43,"platforms":53,"description":7},"Teknium (teknium1), Hermes Agent","0.1.0",{"hermes":44},{"tags":45,"related_skills":52},[46,47,48,49,50,51],"Pinggy","Tunnel","Networking","SSH","Webhook","Localhost",[],[27,26,28],"main","0d1434f89f4bc6b07e9d272accd8c1013768820f","archive\u002Fskill-md-reviewed\u002Fsha256\u002F3f\u002F3fea1ca48b4e9fd7f4decd7e22c1bddfb61aceaea38241bb6349d6baaf2a0065",0,"https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills","https:\u002F\u002Fgithub.com\u002Fzapabob","The Open University of JAPAN　2019-now\r\n\r\nTokyo University of Science　2007-2010","2026-10-26 16:29:01",{"source":8,"skillName":5,"commands":63,"prompt":73,"zipAvailable":74},[64,67,70],{"tool":65,"command":66},"npx","npx skills add zapabob\u002FSkills --skill pinggy-tunnel",{"tool":68,"command":69},"bunx","bunx skills add zapabob\u002FSkills --skill pinggy-tunnel",{"tool":71,"command":72},"pnpm","pnpm dlx skills add zapabob\u002FSkills --skill pinggy-tunnel","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Farchive\u002Fskill-md-reviewed\u002Fsha256\u002F3f\u002F3fea1ca48b4e9fd7f4decd7e22c1bddfb61aceaea38241bb6349d6baaf2a0065\u002FSKILL.md",true,[76,82,86,90,94],{"path":77,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":80,"sourceHtmlUrl":81},"examples\u002F3p-updates.md","REFERENCE","参考文档",3274,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002FCopia de internal-comms\u002Fexamples\u002F3p-updates.md",{"path":83,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":84,"sourceHtmlUrl":85},"examples\u002Fcompany-newsletter.md",3295,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002FCopia de internal-comms\u002Fexamples\u002Fcompany-newsletter.md",{"path":87,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":88,"sourceHtmlUrl":89},"examples\u002Ffaq-answers.md",2366,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002FCopia de internal-comms\u002Fexamples\u002Ffaq-answers.md",{"path":91,"resourceType":78,"resourceTypeDesc":79,"sizeBytes":92,"sourceHtmlUrl":93},"examples\u002Fgeneral-comms.md",602,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002FCopia de internal-comms\u002Fexamples\u002Fgeneral-comms.md",{"path":95,"resourceType":96,"resourceTypeDesc":97,"sizeBytes":98,"sourceHtmlUrl":99},"LICENSE.txt","LICENSE","许可证",11345,"https:\u002F\u002Fgithub.com\u002Fagency-black\u002FSkills\u002Fblob\u002Fmain\u002FCopia de internal-comms\u002FLICENSE.txt",[101,130,165,192,219,236],{"skillNo":102,"name":103,"nameZh":6,"description":104,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":116,"publishedAt":36},"01M6GJTE1GESGGF9K028Y7753E","xurl","X\u002FTwitter via xurl CLI: post, search, DM, media, v2 API.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fxurl\u002Fvariants\u002Fhermes-agent\u002FSKILL.md",[107,110,111],{"categoryNo":108,"categoryName":109,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":112,"categoryName":113,"taxonomyType":114,"taxonomyTypeDesc":115},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[103,117,26,118,119,27,28,120,121,122,123,124,125,32,33,126,54,127,128,129],"openclaw","cli","github","official","search","https","social-media","api","Media","twitter","social","via","post",{"skillNo":131,"name":132,"nameZh":6,"description":133,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":147,"publishedAt":36},"01M6GJT8S1PXQ8WPXT1HSNBWH2","writing-plans","Write implementation plans: bite-sized tasks, paths, code.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fwriting-plans\u002Fvariants\u002Fhermes-agent\u002FSKILL.md",[136,139,142,143,144],{"categoryNo":137,"categoryName":138,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":140,"categoryName":141,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":112,"categoryName":113,"taxonomyType":114,"taxonomyTypeDesc":115},{"categoryNo":145,"categoryName":146,"taxonomyType":114,"taxonomyTypeDesc":115},"01JBSEEDCAT000000000000036","内容创作者",[148,149,150,151,26,152,27,153,28,154,155,156,157,158,159,160,161,162,163,164],"writing","writing plans","plans","design","review","workflow","documentation","tasks","development","code","planning","code-review","subagent","write","superpowers","paths","test-driven-development",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":169,"categories":170,"keywords":174,"publishedAt":36},"01M6GJST0H5X7WHBJ3BZK0DVKH","whisper","OpenAI's general-purpose speech recognition model. Supports 99 languages, transcription, translation to English, and language identification. Six model sizes from tiny (39M params) to large (1550M params). Use for speech-to-text, podcast transcription, or multilingual audio processing. Best for robust, multilingual ASR.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fwhisper\u002Fvariants\u002Fhermes-agent-optional\u002FSKILL.md",[171],{"categoryNo":172,"categoryName":173,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体",[167,26,27,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191],"openai","speech","multimodal","Transformers","ASR","Audio","text","model","speech recognition","use","general","multilingual","translation","english","identification","processing","Audio Processing",{"skillNo":193,"name":194,"nameZh":6,"description":195,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":196,"categories":197,"keywords":201,"publishedAt":36},"01M6GJSMRQ8EETZTYMG72P70EA","weights-and-biases","W&B: log ML experiments, sweeps, model registry, dashboards.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fweights-and-biases\u002Fvariants\u002Fhermes-agent\u002FSKILL.md",[198],{"categoryNo":199,"categoryName":200,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化",[202,26,203,204,28,205,206,207,208,209,210,182,211,212,213,214,215,216,217,218],"weights and biases","tensorflow","experiments","pytorch","visualization","registry","real-time","tuning","dashboards","experiment","log","time","Experiment Tracking","Model Registry","Hyperparameter Tuning","WandB","Real-Time Visualization",{"skillNo":220,"name":221,"nameZh":6,"description":222,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":223,"categories":224,"keywords":226,"publishedAt":36},"01M6GJS19KDPRY112JTR326S06","watchers","Poll RSS, JSON APIs, and GitHub with watermark dedup.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fwatchers\u002Fvariants\u002Fhermes-agent-optional\u002FSKILL.md",[225],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[221,26,227,119,27,228,229,230,231,232,233,32,33,234,235],"terminal","automation","http","monitoring","cron","json","rss","devops","with",{"skillNo":237,"name":238,"nameZh":6,"description":239,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":240,"categories":241,"keywords":244,"publishedAt":36},"01M6GJRHJD2A6Q830SWF9W48BC","serving-llms-vllm","vLLM: high-throughput LLM serving, OpenAI API, quantization.","https:\u002F\u002Fgithub.com\u002Fzapabob\u002FSkills\u002Fblob\u002Fmain\u002Fregistry\u002Fskills\u002Fvllm\u002Fvariants\u002Fhermes-agent\u002FSKILL.md",[242,243],{"categoryNo":108,"categoryName":109,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":112,"categoryName":113,"taxonomyType":114,"taxonomyTypeDesc":115},[245,246,247,27,248,175,249,250,251,178,252,124,253,254,255,256,257,258,259,260],"llms","vLLM","serving llms vllm","research","openai api","tensor","Inference Serving","Production","llm serving","High Throughput","PagedAttention","Continuous Batching","Quantization","Tensor Parallelism","high-throughput","throughput"]