Spaces:
Paused
Paused
|
Download AGENTS.md from oaklight/veilrender: direct link, hf CLI and curl.
- Browser
- Download file 6.41 kB
-
https://huggingface.co/spaces/oaklight/veilrender/resolve/main/AGENTS.md
- Command line
-
hf download hf://spaces/oaklight/veilrender/AGENTS.md
-
curl -L -o AGENTS.md https://huggingface.co/spaces/oaklight/veilrender/resolve/main/AGENTS.md
6.41 kB
| # AGENTS.md β VeilRender | |
| > Context file for AI coding assistants. Symlinked as `CLAUDE.md`. | |
| ## What this project is | |
| VeilRender is a **headless browser rendering API** β accepts a URL, renders it | |
| with a stealth Chromium browser (CloakBrowser + Patchright), returns | |
| HTML/Markdown/readability content. Designed as a fallback for fetch tools that | |
| fail on JavaScript-rendered pages. | |
| Supports two deployment modes: **single-instance** (embedded browser) and | |
| **gateway + worker pool** (browser containers scale independently). | |
| Only runtime dependency is `patchright`. Everything else is vendored from | |
| [zerodep](https://github.com/Oaklight/zerodep) β HTTP server, S3 client, HTML | |
| parsing, readability extraction. | |
| ## Architecture | |
| ### Request flow | |
| ``` | |
| HTTP request β auth β route handler β browser_manager.get_page() | |
| β | |
| LocalWorker (embedded CloakBrowser) | |
| RemoteWorker (CDP, Chromium) | |
| PlaywrightWorker (Playwright protocol, Firefox/Camoufox) | |
| ``` | |
| ### Key components | |
| | Component | File | Purpose | | |
| |-----------|------|---------| | |
| | HTTP server | `_vendor/httpserver` | Async HTTP framework (zerodep) | | |
| | Browser pool | `browser.py` | `LocalWorker`, `RemoteWorker`, `PlaywrightWorker`, `BrowserManager` | | |
| | Config | `config.py` | `VEILRENDER_*` env vars, worker protocol parsing | | |
| | Routes | `routes/*.py` | `/render`, `/screenshot`, `/health`, `/metrics`, `/stats`, `/` dashboard | | |
| | Storage | `storage.py` | L1 TTLCache + L2 S3 (vendored `S3Client`) | | |
| | Filters | `filters.py` | Outbound request blocklist (StevenBlack/hosts) | | |
| | CDP proxy | `cdp_proxy.py` | WebSocket proxy for direct CDP access | | |
| | Stats | `stats.py` | In-memory counters, p50/p95 latency | | |
| ### Worker types | |
| | Type | Connection | Browser | Stealth | | |
| |------|-----------|---------|---------| | |
| | `LocalWorker` | Local subprocess | CloakBrowser (auto-downloaded) | Browser-level + driver-level | | |
| | `RemoteWorker` | `chromium.connect_over_cdp()` | Any CDP-compatible Chromium | Driver-level (Patchright) | | |
| | `PlaywrightWorker` | `firefox.connect()` | Camoufox or Playwright-served Firefox | Browser-level (Camoufox) | | |
| ## Repository layout | |
| ``` | |
| src/veilrender/ | |
| βββ app.py # HTTP server + CDP WebSocket multiplexing | |
| βββ config.py # Settings from env vars (VEILRENDER_ prefix) | |
| βββ auth.py # Token verification | |
| βββ browser.py # Worker classes + BrowserManager pool coordinator | |
| βββ cdp_proxy.py # CDP WebSocket proxy | |
| βββ filters.py # Outbound request blocklist | |
| βββ models.py # Request/response dataclasses | |
| βββ stats.py # In-memory request counters and latency | |
| βββ storage.py # L1 (TTLCache) + L2 (S3) render cache | |
| βββ routes/ | |
| β βββ dashboard.py # GET / β stats dashboard with i18n (en/zh) | |
| β βββ health.py # GET /health | |
| β βββ metrics.py # GET /metrics β Prometheus exposition | |
| β βββ render.py # POST /render | |
| β βββ screenshot.py # POST /screenshot | |
| βββ _vendor/ # zerodep modules β DO NOT EDIT manually | |
| βββ httpserver.py # Async HTTP server | |
| βββ cache.py # TTLCache | |
| βββ s3.py # S3-compatible client | |
| βββ readability.py # Article extraction | |
| βββ soup.py # HTML parser | |
| deploy/ | |
| βββ compose.yaml # Single-instance (prod) | |
| βββ compose-dev.yaml # Dev instance (port 7861) | |
| βββ compose-pool.yaml # Gateway + CloakBrowser workers | |
| βββ compose-pool-mixed.yaml # Gateway + CloakBrowser + Camoufox | |
| βββ Dockerfile.camoufox # Camoufox server image | |
| scripts/ | |
| βββ download-cloakbrowser.py # Download CloakBrowser binary | |
| ``` | |
| ## Commands | |
| ```bash | |
| make dev # Run dev server on :7860 | |
| make build # Docker build (full target, with CloakBrowser) | |
| make build-gateway # Docker build (gateway target, no browser) | |
| make run # Docker run | |
| make lint # ruff check --fix && ruff format | |
| make typecheck # ty check | |
| make vendor # Re-vendor zerodep modules | |
| ``` | |
| ## Deployment | |
| ### Dev deployment | |
| ```bash | |
| make deploy-dev SSH_TARGET=oaklight.buttercup # single-instance | |
| make deploy-dev SSH_TARGET=oaklight.buttercup POOL=1 # gateway + workers | |
| ``` | |
| Builds from the **working tree** (not committed state), tags as `dev-test`, | |
| deploys to `veilrender-dev` stack (port 7861). Always verify no dirty files | |
| in `src/` before deploying. | |
| ### Release | |
| 1. Update `CHANGELOG.md` β move `[Unreleased]` to `[X.Y.Z]` | |
| 2. Bump `__version__` in `src/veilrender/__init__.py` | |
| 3. Commit: `git commit -m "bump version to X.Y.Z"` | |
| 4. Tag and push: `git tag vX.Y.Z && git push && git push origin vX.Y.Z` | |
| 5. Release workflow auto-publishes to PyPI, Docker Hub, GHCR, and creates | |
| GitHub Release from changelog | |
| ### Production | |
| Prod runs on `oaklight.buttercup` at `/dockervol/dockge/stacks/veilrender` | |
| (port 7860), exposed via NPS as `veilrender.service.oaklight.top`. | |
| Update prod to a released version: | |
| ```bash | |
| ssh oaklight.buttercup 'cd /dockervol/dockge/stacks/veilrender && \ | |
| docker compose pull && docker compose up -d' | |
| ``` | |
| ## Escalation | |
| - Browser won't start β check `_find_browser_binary()` cascade: | |
| `CLOAKBROWSER_BINARY` env β `~/.cloakbrowser/*/chrome` β auto-download | |
| - Remote worker won't connect β check `_resolve_to_ip()` (Chromium rejects | |
| non-IP Host headers), verify CDP port is accessible | |
| - Camoufox worker won't connect β check Playwright version compatibility | |
| (client/server major.minor must match) | |
| - Vendor module issue β never fix in-place; update upstream zerodep, re-vendor | |
| - Test failure after 3 attempts β stop, report full output | |
| - Never: delete files to fix errors, skip lint, modify `_vendor/` directly | |
| ## Files to never edit | |
| - `src/veilrender/_vendor/**` β vendored zerodep modules, update via | |
| `make vendor` or `zerodep add` from ~/projects/zerodep | |
| - `CLAUDE.md` β symlink to `AGENTS.md`, edit `AGENTS.md` instead | |
| ## Definition of done | |
| 1. `ruff check --fix && ruff format` on changed Python files | |
| 2. `ty check` passes | |
| 3. Server starts and `/health` returns 200 | |
| 4. `/render` returns valid content for a test URL | |
| 5. `/metrics` returns valid Prometheus output | |