[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "vibatchium" # Single source of truth: the version is read from vibatchium/__init__.py # (see [tool.hatch.version]) so the packaging version can never drift from the # runtime __version__ again (it did, silently, at 0.9.2 and 0.9.3). dynamic = ["version"] description = "Stealth browser automation for AI agents — real Chrome, N parallel persistent logged-in sessions." readme = "README.md" requires-python = ">=3.11" license = { text = "Apache-2.0" } authors = [{ name = "monodev-eth" }] keywords = ["browser", "automation", "ai", "agent", "patchright", "stealth", "playwright", "mcp"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Testing", "Topic :: Internet :: WWW/HTTP :: Browsers", ] dependencies = [ # Upper bounds prevent surprise breakage when a major-version bump # changes APIs we depend on. Bump these floors+ceilings deliberately, # not implicitly via uv lock. # NB: 1.59.0 was never published — the 1.59 line starts at 1.59.1. "patchright>=1.61.2,<1.62", # floor: 1.60 kills the driver on a stale-handle evaluate; <1.62 until 1.62 clears the stealth gate (tests/test_stealth_drift_gate.py) "click>=8.1.7,<9.0", "mcp>=1.30.0,<2.0", # UTS #46 host normalisation for secret origin binding (already pulled in # by httpx; declared because secrets.py relies on it directly). "idna>=3.7,<4", ] [project.optional-dependencies] # Pillow is only needed for `screenshot --annotate`. annotate = ["pillow>=10.0,<13.0"] # Claude observe→act LLM backend (heuristic backend is always available). llm = ["anthropic>=0.40,<1.0"] # 0.9.0: authenticated out-of-browser HTTP lane. curl_cffi (lexiforest fork, # MIT) impersonates a Chrome JA3/HTTP2 fingerprint, so the `fetch` verb reuses a # session's cookies+proxy to hit JSON/API endpoints behind a login without a # renderer. No JS — static-fingerprint gate only. MIT is permissive (no copyleft). fetch = ["curl_cffi>=0.16.3,<1.0"] # Wave 5.4: nodriver backend for the hardest Cloudflare gates. AGPL-3.0 # (copyleft); commercial integrators should consult licensing. nodriver = ["nodriver>=0.50.0,<1.0"] # Wave 6.1a: live-view server (WebSocket frame stream + takeover). Pulls # aiohttp for the HTTP+WS surface; ~5 MB install footprint. liveview = ["aiohttp>=3.14.3,<4.0"] # Wave 6.3a: credential vault + TOTP. pynacl for XSalsa20-Poly1305 AEAD; # keyring for OS-native key storage (gnome-keyring, macOS Keychain, etc.). secrets = ["pynacl>=1.5,<2.0", "keyring>=24.0,<26.0"] # Wave 6.4a: REST shim — exposes daemon verbs over HTTP for non-shell clients # (Docker / hosted mode / language-agnostic agents). FastAPI + uvicorn. rest = ["fastapi>=0.110,<2.0", "uvicorn[standard]>=0.27,<1.0"] # Convenience meta-extras # `all` = every advertised feature except the GPL/AGPL `nodriver` backend. # Matches the README install guidance — keep these in sync. all = [ "pillow>=10.0,<13.0", # annotate "anthropic>=0.40,<1.0", # llm + vision "aiohttp>=3.14.3,<4.0", # liveview "pynacl>=1.5,<2.0", # secrets vault "keyring>=24.0,<26.0", # secrets vault key storage "fastapi>=0.110,<2.0", # rest shim "uvicorn[standard]>=0.27,<1.0", # rest shim "curl_cffi>=0.16.3,<1.0", # fetch lane (MIT — permissive) ] dev = ["pytest>=8.0", "pytest-asyncio>=0.23", "pytest-timeout>=2.3", "ruff>=0.6.0"] [project.scripts] vb = "vibatchium.cli:main" # `vibatchium` alias so MCP registries / clients can run `uvx vibatchium mcp` # (uvx runs the command named after the package); `vb mcp` stays the primary entry. vibatchium = "vibatchium.cli:main" [project.urls] Homepage = "https://github.com/trueoriginlabs/vibatchium" Issues = "https://github.com/trueoriginlabs/vibatchium/issues" Source = "https://github.com/trueoriginlabs/vibatchium" [tool.hatch.version] path = "vibatchium/__init__.py" [tool.hatch.build.targets.wheel] packages = ["vibatchium"] [tool.hatch.build.targets.sdist] include = [ "/vibatchium", "/README.md", "/LICENSE", "/pyproject.toml", "/tests", "/.github", # The committed agent skill + plugin manifests: not runtime code (the wheel # is packages=["vibatchium"] only), but tests/test_skill_file_sync.py reads # them, so the sdist's test suite needs them to pass. "/skills", "/.claude-plugin", "/scripts/sync_skill.py", ] exclude = [ "**/__pycache__", "**/*.pyc", "tests/**/*.png", "tests/**/*.json", ] [tool.hatch.envs.default] dependencies = [ "pytest>=8.0", "pytest-asyncio>=0.23", "pytest-timeout>=2.3", ] [tool.ruff] line-length = 100 target-version = "py311" [tool.ruff.lint] select = ["E", "F", "W", "B", "UP"] ignore = [ "E501", # line too long — keep readability "B008", # function call in default arg — Click idiom "E701", # multi-statement on one line (colon) — guard-clause idiom "E702", # multi-statement on one line (semicolon) — compact assigns "E731", # lambda assignment — accepted for tiny inline transformers "E402", # module-level import not at top — needed for opt-in deferred imports ] [tool.ruff.lint.per-file-ignores] "tests/*" = ["F841"] # unused locals in tests are fine (assertion of "doesn't raise") [tool.pytest.ini_options] asyncio_mode = "auto" testpaths = ["tests"]