{
  "markdown": "# HubVibe\n\n**Machine-payable site compliance audits.** WCAG 2.1 A/AA, SEO, security\nheaders, and performance — deterministic rules against the real rendered page,\npriced per call, payable by software with no account and no human in the loop.\n\nLive: **https://hubvibe-io.com**\n\nEvery check is a deterministic rule run against the live page. Nothing here is\na language model judging whether a site looks compliant, and a check that could\nnot run is returned as an error, never as a passing result.\n\nThere are two ways in. Both take under a minute.\n\n---\n\n## 1 — Gate your CI on it: one step, nothing to install\n\n```yaml\n- uses: Its-fortunatefolly/HubVibe@v1\n  with:\n    url: https://staging.example.com\n    api-key: ${{ secrets.HUBVIBE_API_KEY }}\n```\n\nThat is the entire integration. Every pull request now runs the full\ncompliance bundle against your deployed preview and **fails the build on the\nregression that caused it** — not in an audit six months later.\n\n- Findings render in the job summary: rule, impact, nodes hit, link to the fix.\n- A check that failed to *execute* is an error, never a silent pass — a green\n  build means the checks actually ran.\n- `fail-on-error: false` keeps our outage from ever blocking your deploy;\n  your real regressions still gate it.\n- **$0.10 per PR** for all four checks as one bundle, $0.03 for a single\n  check. A repo merging 100 PRs a month spends $10. No subscription, no seat\n  licence, no minimum.\n\nGate a promotion on it:\n\n```yaml\n- name: Audit staging\n  id: audit\n  uses: Its-fortunatefolly/HubVibe@v1\n  with:\n    url: https://staging.example.com\n    api-key: ${{ secrets.HUBVIBE_API_KEY }}\n\n- name: Promote to production\n  if: steps.audit.outputs.passed == 'true'\n  run: ./deploy-production.sh\n```\n\nKeys come from [`/billing/checkout`](https://hubvibe-io.com/billing/checkout).\nOr skip the key entirely — see the second way in.\n\n## 2 — Point your agent at it: no key, no signup, pay per call\n\nAn unauthenticated call is not an error here. It is the price sheet:\n\n```bash\ncurl -i -X POST https://hubvibe-io.com/audit/wcag \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\":\"https://example.com\"}'\n```\n\n```\nHTTP/1.1 402 Payment Required\nWWW-Authenticate: Payment ...\n\n{\n  \"error\": \"payment_required\",\n  \"price_usd\": 0.03,\n  \"accepts\": [ { \"protocol\": \"x402\", ... }, { \"protocol\": \"mpp\", ... } ],\n  \"docs\": \"/.well-known/agent.json\"\n}\n```\n\nAn agent reads the 402, signs an x402 payment (USDC on Base), retries with\n`X-PAYMENT`, and gets the audit. Payment is **verified before the audit runs\nand settled only after it produces a result** — a failed audit is never\ncharged: x402 is settled only after delivery, a prepaid key is refunded, and\nan MPP credential a failed audit consumed is accepted again on the retry.\n\nFor Python agents and swarms, the bundled tollbooth client does the whole\nloop — challenge, budget check, signing, retry — with two hard spending\nlimits enforced *before* anything is signed:\n\n```python\nfrom integrations.hubvibe_tollbooth import HubVibeTollbooth\n\nbooth = HubVibeTollbooth.from_env()          # HUBVIBE_WALLET_KEY or HUBVIBE_API_KEY\nresult = booth.audit(\"https://example.com\")  # full bundle, $0.10\nresult = booth.audit(\"https://example.com\", endpoint=\"wcag\")  # $0.03\n```\n\n`accepts` lists only the payment rails that can genuinely settle on this\ndeployment. A rail that is not configured is omitted rather than advertised\nwith a null recipient, so a paying agent never builds a payment that cannot\nland.\n\n**How machines find this node without being told the URL:** every 402\ncarries x402 Bazaar discovery data, so facilitators index it by capability\nand price; the MCP endpoint at [`/mcp`](https://hubvibe-io.com/mcp)\nis listed in the official registry as `io.github.Its-fortunatefolly/hubvibe`;\nand [`/.well-known/agent.json`](https://hubvibe-io.com/.well-known/agent.json)\nis generated from the same catalog the routes charge from, so the advertised\nprice is the charged price by construction.\n\n## Endpoints\n\n| Route | Price | Checks |\n|---|---|---|\n| `POST /audit/wcag` | $0.03 | WCAG 2.1 A/AA via axe-core, against the rendered page |\n| `POST /audit/seo` | $0.03 | Title, meta description, H1s, canonical, OpenGraph, structured data, lang |\n| `POST /audit/security` | $0.03 | HTTPS, HSTS, CSP, X-Content-Type-Options, clickjacking, Referrer-Policy, CORS |\n| `POST /audit/performance` | $0.03 | DOM nodes, transferred bytes, request count from one real page load |\n| `POST /audit/bundle` | $0.10 | All four against one URL, billed once |\n\nBody is `{\"url\": \"...\"}`; `wcag` and `seo` also accept raw `{\"html\": \"...\"}`.\n\n## Paying\n\nThree rails, all fail-closed — no valid credential means no audit runs:\n\n- **`X-API-Key`** — subscription key from `/billing/checkout`\n- **`X-PAYMENT`** — x402\n- **`Authorization: Payment ...`** — MPP (Stripe Shared Payment Tokens for\n  fiat, or Tempo for crypto)\n\nWhich are live is deployment-specific. Read `accepts` in any 402, or\n`payment.methods` in the agent manifest — both list only what actually works.\n\n### What you are charged for\n\nOnly an audit that produced a result.\n\n- An audit that could not run returns **502** with `billed: false` and is\n  never settled. x402 payments are *verified* to grant access but only\n  *settled* after the audit has delivered; a prepaid key debited for the\n  call is refunded, and a prepaid key bought by an MPP top-up is still\n  returned on the 502, holding everything it bought.\n- A rate-limited request returns **429** with `Retry-After`, checked before any\n  payment is touched, so it costs nothing.\n- A settled x402 payment gets a receipt: the facilitator's settle response\n  (transaction hash, network, payer) comes back on the 200 in the\n  `PAYMENT-RESPONSE` header (`X-PAYMENT-RESPONSE` for v1 clients), exactly\n  as the x402 spec describes. The x402 client libraries decode it; the\n  bundled `hubvibe_tollbooth.py` keeps it as `last_settlement`.\n- One signed payment buys one audit. A replayed x402 authorization is\n  refused with a 402 before it reaches the facilitator.\n\n### What this service will not fetch\n\nEvery audit loads the URL you send from inside the deployment, so the node\nrefuses, with a **400** and before any payment is read: addresses that are\nnot globally routable (loopback, private ranges, link-local, the cloud\nmetadata endpoint), internal hostnames, schemes other than `http`/`https`,\nand names that do not resolve. Raw `html` is capped at 2 MiB. None of that\ncosts the caller anything.\n\n## Discovery\n\nAgents shouldn't have to read documentation to use this:\n\n| | |\n|---|---|\n| [`/.well-known/agent.json`](https://hubvibe-io.com/.well-known/agent.json) | Full manifest — pricing, live rails, limits, per-endpoint examples |\n| [`/openapi.json`](https://hubvibe-io.com/openapi.json) | OpenAPI 3.1 |\n| [`/mcp.json`](https://hubvibe-io.com/mcp.json) | MCP tool definitions |\n| [`/llms.txt`](https://hubvibe-io.com/llms.txt) | Plain-text summary |\n| [`/docs`](https://hubvibe-io.com/docs) | Interactive reference |\n\n## Integrations\n\nIn [`wcag-audit-engine/integrations/`](wcag-audit-engine/integrations/):\n\n- **`mcp_server.py`** — MCP server exposing all five audits as tools, built on\n  the official SDK. Standalone, with its own `mcp_requirements.txt`: the `mcp`\n  package needs a newer Starlette than the deployed service pins for FastAPI,\n  so it is deliberately kept out of the service's dependency tree.\n- **`langchain_tool.py`** — LangChain tool wrapper. Subscription key only; it\n  raises on a 402 rather than paying.\n- **`hubvibe_tollbooth.py`** — the client for agents running unattended. Same\n  audits, but it settles the 402 itself from an EVM wallet via x402, so no\n  human has to go get a key. Enforces a per-call cap **and** a\n  process-lifetime budget, both before anything is signed — an autonomous\n  loop with an unbounded wallet is a drained wallet. Exposes LangChain/CrewAI\n  tools via `hubvibe_tools()`.\n- **`github_action.yml`** — a complete, copyable workflow file. It *calls* the\n  published action rather than curl-ing the API: a hand-rolled HTTP step has\n  to re-implement the retry policy, the 4xx no-retry rule and the JSON\n  encoding of the target URL, and then be maintained against the API by\n  whoever pasted it. One file, one URL to edit, `on: push` and\n  `on: pull_request`.\n\nAt the repo root:\n\n- **`action.yml`** — the composite GitHub Action, and the single copy of it.\n  It retries transient failures but never a 4xx (repeating a 402 on a metered\n  endpoint risks paying twice for one answer), renders findings into the job\n  summary via `scripts/render_audit_summary.py`, and can be adopted with\n  `fail-on-error: false` so an outage in this service cannot block someone\n  else's deploys.\n- **`scripts/publish-action-repo.sh`** — generates the standalone repo the\n  Marketplace listing needs (see below).\n- **`glama.json`** — listing metadata for the Glama MCP directory.\n\n## For people, not pipelines\n\nThe machine API is the product, and per call is the only price: there are no\nsubscriptions or human plans (retired 2026-09-06). A person can pay the same\nper-call rates through a $0.50 prepaid block where the MPP top-up rail is live.\nThere is deliberately **no free scan**: an audit costs a real browser page\nload, so giving them away funds strangers' compute and invites abuse.\n\n## Publishing the GitHub Action\n\nTwo separate things, with different rules:\n\n**Direct use works today.** An `action.yml` at a public repo's root is usable\nas-is, no Marketplace involved:\n\n```yaml\n- uses: Its-fortunatefolly/HubVibe@v1\n  with:\n    url: https://your-site.example.com\n    api-key: ${{ secrets.HUBVIBE_API_KEY }}\n```\n\n**A Marketplace listing needs a different repo.** GitHub requires an action\nrepository to contain a single root `action.yml` *and no workflow files at\nall*. This repo has `.github/workflows/`, so it can never be listed itself —\nmoving `action.yml` around does not help. Generate the clean standalone repo\ninstead:\n\n```bash\nbash scripts/publish-action-repo.sh /tmp/hubvibe-audit-action\n```\n\nIt copies `action.yml` and the summary renderer verbatim (so the published\naction cannot drift from the one in this repo), writes a listing README, and\nprints the exact push/tag/publish steps.\n\n## Publishing to the MCP registry\n\n`server.json` in this repo root registers the live `/mcp` endpoint as a\n**remote** server, so no package needs publishing anywhere.\n\n`mcp-publisher` is a Go binary from the registry's GitHub releases — it is\n**not** on npm (the `mcp-publisher` package on npm is an unrelated\nbrowser-automation tool):\n\n```bash\ncurl -L \"https://github.com/modelcontextprotocol/registry/releases/download/v1.8.1/mcp-publisher_linux_amd64.tar.gz\" \\\n  | tar xz mcp-publisher\n./mcp-publisher login github     # opens a browser; proves you own the namespace\n./mcp-publisher publish\n```\n\nThe `name` field is `io.github.its-fortunatefolly/hubvibe`, which the GitHub\nlogin authenticates against. `server.json` is validated against the official\nschema (note: `description` is capped at 100 characters).\n\n**Bump `version` before every publish.** The registry treats a version as\nimmutable and rejects a re-publish of one it already serves, so a corrected\n`server.json` left at its old version fails at the last step — after the\nbrowser login, which is the most annoying place to find out. Check what is\nactually live first; the registry is public and needs no auth:\n\n```bash\ncurl -s \"https://registry.modelcontextprotocol.io/v0/servers?search=hubvibe\"\n```\n\nCorrecting text without bumping the version is the trap: the file reads\nright in the repo, the registry keeps serving the old copy, and nothing\nreports a problem. On 2026-08-11 the registry took 1.1.0 whose header still\nread \"pay per call with x402/MPP\"; the repo dropped that rail assertion the\nsame week, and the two stayed out of sync because a republish of 1.1.0 could\nnever have landed.\n\n## Repository layout\n\n```\nwcag-audit-engine/        the audit service (this is the product)\n  app/                    FastAPI app, audit engines, payment rails\n  integrations/           MCP server, LangChain tool, GitHub Action\nscripts/verify-live.sh    verifies a deployed node from outside\nscripts/simulate-paid-call.py\n                          the whole x402 paid path, locally, for free\nscripts/first-paid-call.sh\n                          the same paid path against the live node, for $0.03\nscripts/payment-status.sh what the money is doing: wallet balances, live 402, verdict\nscripts/vps-install.sh    the whole service on any flat-rate box, one command\ndeploy/vps/               compose + Caddy TLS + SQLite key store (no Google)\ntests/\n```\n\n## Running the tests\n\n```bash\npip install -r requirements.txt\npytest tests/ -q\n```\n\n`scripts/verify-live.sh` checks a *deployed* node end to end — service up, the\nwhole discovery surface, every paid route answering 402 rather than 404, and\nthat the 402 is actually machine-actionable. Green unit tests do not prove a\ndeploy; this does.\n\n`scripts/simulate-paid-call.py` proves the paid path itself without spending\nanything: it boots the real service with the live x402 configuration against\na stub facilitator that recovers the EIP-712 signer from every payment it is\nsent, then drives it with the real client through `first-paid-call.sh`. It\nchecks that verify happens before the audit and settle after it, that the\nBazaar record rides the payment and passes the x402 validator, and that the\n200 carries the settlement receipt. Needs a Chromium Playwright can launch\n(`python -m playwright install chromium`).\n\n## Honest limits\n\nThese are narrow, disclosed, automated signals. They are not a substitute for\na manual accessibility audit, a penetration test, or a Lighthouse run, and\nautomated scanning is not a compliance certification. Each function's\ndocstring states exactly what it does and does not check.\n",
  "bytes": 13835,
  "sha": "06a35e47de33c12fc6a86e970476fb29cb2f0e9db22e1d36b769b8b6ef312d31",
  "repo_slug": "its-fortunatefolly/hubvibe",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_its_fortunatefolly_hubvibe_c04906bf/readme"
}