[build-system] # Upper-bounded: hatchling >=1.30 emits core Metadata-Version 2.5, which # current twine and PyPI's upload validation reject. Pin below it so an # isolated `python -m build` produces 2.4 artifacts that upload cleanly. # Lift the cap once PyPI/twine accept 2.5. requires = ["hatchling>=1.27,<1.30"] build-backend = "hatchling.build" [project] name = "claude-code-bridge" description = "Local-first, cross-machine MCP relay for independent coding agents." readme = "README.md" license = { file = "LICENSE" } requires-python = ">=3.10" authors = [{ name = "Constripacity" }] keywords = ["mcp", "claude-code", "codex", "agent", "bridge", "relay"] classifiers = [ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Communications", "Topic :: Software Development :: Libraries", ] dynamic = ["version"] dependencies = [ # Every dependency is upper-bounded below its next major. CI installs deps # unpinned, so without caps a new major silently breaks a released line — # mcp 2.0 removed the low-level `@server.list_tools()`/`@server.call_tool()` # decorator API this server uses and made every prior 0.9.x wheel # uninstallable. Caps allow the current working majors; lift each one # deliberately (and re-test) when adopting the next. The mcp floor is 1.27 # for the Streamable HTTP session manager the /mcp endpoint relies on. "mcp>=1.27.0,<2", "starlette>=0.27.0,<2", "uvicorn>=0.24.0,<1", "anyio>=4.0,<5", "sse-starlette>=2.0,<4", ] [project.optional-dependencies] tui = [ "textual>=0.79.0,<9", "httpx>=0.27.0,<1", ] dev = [ # Dev deps are capped too so an unpinned upgrade can't turn CI red on # unchanged code (ruff 0.16 broadened its default rule set and did exactly # that; the lint selection is also pinned in [tool.ruff.lint]). "build>=1.2,<2", "pytest>=8.0,<10", "pytest-asyncio>=0.23,<2", # Hard per-test timeout so a hung test (e.g. a future streaming-response # deadlock) fails in seconds instead of burning CI's 6h job ceiling, as # the v0.8.0 SSE tests did before the broker-level rewrite. "pytest-timeout>=2.3,<3", "httpx>=0.27.0,<1", "ruff>=0.6,<0.17", "textual>=0.79.0,<9", ] [project.urls] Homepage = "https://github.com/constripacity/Claude-Bridge" Repository = "https://github.com/constripacity/Claude-Bridge" Issues = "https://github.com/constripacity/Claude-Bridge/issues" Changelog = "https://github.com/constripacity/Claude-Bridge/blob/main/CHANGELOG.md" Documentation = "https://github.com/constripacity/Claude-Bridge#readme" Security = "https://github.com/constripacity/Claude-Bridge/security/policy" [project.scripts] claude-bridge = "claude_bridge.cli:main" # Alias so the console command matches the PyPI distribution name — lets # `uvx claude-code-bridge` / `uvx claude-code-bridge --stdio` resolve directly # (uvx looks for an executable named after the package). Both commands are # identical entry points; `claude-bridge` stays the primary. claude-code-bridge = "claude_bridge.cli:main" [tool.hatch.version] path = "claude_bridge/_version.py" [tool.hatch.build.targets.wheel] packages = ["claude_bridge"] [tool.hatch.build.targets.sdist] include = [ "/claude_bridge", "/tests", "/README.md", "/LICENSE", "/CONTRIBUTING.md", "/CHANGELOG.md", "/SECURITY.md", "/CLAUDE.md", "/docs/COMPATIBILITY.md", "/docs/MIGRATING-0.9-TO-1.2.md", "/docs/PROTOCOL.md", "/docs/ROADMAP.md", "/Dockerfile", "/.dockerignore", "/server.json", "/package.json", "/package-lock.json", "/pyproject.toml", "/pytest.ini", "/start-bridge.bat", "/start-bridge.sh", "/start-tui.bat", "/start-tui.sh", ] [tool.ruff.lint] # Pin the lint rule set explicitly. The project has always relied on ruff's # historical default (E4/E7/E9/F). Because CI installs ruff unpinned, a ruff # release that broadens the *default* rule set would otherwise turn green CI red # on unchanged code — ruff 0.16 did exactly that by enabling I/UP/S/BLE/PL/RUF/ # PYI by default. Declaring the selection makes lint reproducible across ruff # versions. Adopting additional rule families is a deliberate, separate change. select = ["E4", "E7", "E9", "F"]