[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "free-claude-code" version = "4.0.0" description = "Local proxy connecting coding agents to OpenAI-compatible AI providers" readme = "README.md" requires-python = ">=3.14.0" dependencies = [ "fastapi[standard]>=0.139.0", "uvicorn>=0.50.0", "httpx[socks]>=0.28.1", "markdown-it-py>=4.2.0", "pydantic>=2.13.4", "python-dotenv>=1.2.2", "tiktoken>=0.13.0", "python-telegram-bot>=22.8", "discord.py>=2.7.1", "pydantic-settings>=2.14.2", "openai>=2.44.0", "loguru>=0.7.0", "aiohttp>=3.14.1", "jsonschema>=4.25.0", ] [project.scripts] fcc-server = "free_claude_code.cli.entrypoints:serve" free-claude-code = "free_claude_code.cli.entrypoints:serve" fcc-init = "free_claude_code.cli.entrypoints:init" fcc-claude = "free_claude_code.cli.launchers.claude:launch" fcc-codex = "free_claude_code.cli.launchers.codex:launch" fcc-pi = "free_claude_code.cli.launchers.pi:launch" [project.optional-dependencies] voice = [ "grpcio>=1.81.1", "grpcio-tools>=1.81.1", "nvidia-riva-client>=2.26.0", ] voice_local = [ "torch>=2.12.1", "transformers>=5.13.0", "accelerate>=1.14.0", "librosa>=0.10.0", ] [tool.hatch.build.targets.wheel] packages = ["src/free_claude_code"] [tool.hatch.build.targets.wheel.force-include] ".env.example" = "free_claude_code/config/env.example" [tool.uv] required-version = ">=0.11.0" [tool.uv.sources] torch = { index = "pytorch-cu130" } [[tool.uv.index]] name = "pytorch-cu130" url = "https://download.pytorch.org/whl/cu130" explicit = true [dependency-groups] dev = [ "pytest>=9.1.1", "pytest-asyncio>=1.4.0", "pytest-cov>=7.1.0", "ty>=0.0.56", "ruff>=0.15.20", "pytest-xdist>=3.8.0", ] [tool.ruff] target-version = "py314" line-length = 88 [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # Pyflakes (undefined names, unused imports) "I", # isort (import ordering) "UP", # pyupgrade (modernise syntax for target Python version) "B", # flake8-bugbear (common bugs and anti-patterns) "C4", # flake8-comprehensions (idiomatic comprehensions) "SIM", # flake8-simplify (simplifiable code patterns) "PERF", # Perflint (performance anti-patterns) "RUF", # Ruff-specific rules ] ignore = [ "E501", # line too long — enforced by the formatter instead "B008", # FastAPI Depends() in argument defaults is intentional "RUF006", # fire-and-forget tasks intentionally not awaited ] [tool.ruff.lint.isort] known-first-party = ["free_claude_code", "smoke"] [tool.ruff.format] quote-style = "double" indent-style = "space" line-ending = "auto" skip-magic-trailing-comma = false [tool.pytest.ini_options] pythonpath = ["src"] addopts = "-n auto" testpaths = ["tests"] markers = [ "live: opt-in local smoke tests that can touch real services", "interactive: smoke tests requiring manual user interaction", "provider: live provider checks", "messaging: live messaging platform checks", "cli: CLI integration checks", "clients: client compatibility checks", "voice: voice transcription checks", "contract: deterministic feature contract checks", "smoke_target(name): route a smoke test behind FCC_SMOKE_TARGETS", "xdist_group(name): group smoke provider items under pytest-xdist --dist=loadgroup", ] [tool.ty.environment] python-version = "3.14" [tool.ty.analysis] # Optional voice_local extra: torch, transformers, librosa for local whisper transcription # Optional voice extra: nvidia-riva-client for nvidia_nim transcription provider allowed-unresolved-imports = ["torch", "transformers", "librosa", "riva.client"]