mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
Service-level tests now exercise provider, permissions, project, journal, messaging, work_session, metrics, kanban, extraction, learning, notification, dashboard, llm_routing, a2a, task, repository_base, audit, db_seed, branch_name, indexed_document, query_helpers, agent. API route tests cover provider, journal, project, sessions, dashboard, work_session, tasks, a2a, groups, notifications, agents, channels, messages, kanban, api_resources. Pure-function helpers covered: handlers, deps_helpers, middleware, middleware_docs, transcription, pr templates, agents_config, errors, logging, journal/notification/channel/a2a access, task_lifecycle, streaming, converters, crypto, schemas (common + websocket), events, permissions extras. pyproject ruff per-file-ignores extended for tests so PLR2004 (status code magic values), PLC0415 (lazy imports), PLR0913 (fixture params), ARG001 (unused fixture deps), SIM105, and E501 don't fight test idioms.
432 lines
13 KiB
TOML
432 lines
13 KiB
TOML
[project]
|
|
name = "roboco"
|
|
version = "0.1.0"
|
|
description = "AI Agents Company - A virtual organization of AI agents functioning as a software development workforce"
|
|
authors = [
|
|
{name = "Renzo Franceschini", email = "rennf93@users.noreply.github.com"}
|
|
]
|
|
readme = "README.md"
|
|
license = { text = "MIT" }
|
|
requires-python = ">=3.10,<3.15"
|
|
|
|
dependencies = [
|
|
# Core
|
|
"pydantic",
|
|
"pydantic-settings",
|
|
# API
|
|
"fastapi",
|
|
"uvicorn[standard]",
|
|
"websockets",
|
|
# Database
|
|
"sqlalchemy[asyncio]",
|
|
"asyncpg", # PostgreSQL async driver
|
|
"alembic", # Migrations
|
|
|
|
# Cache/Queue
|
|
"redis",
|
|
"hiredis", # Redis performance
|
|
|
|
# RAG (piragi with PostgreSQL/pgvector backend)
|
|
"piragi[postgres]",
|
|
# AI/LLM
|
|
"anthropic",
|
|
"openai", # For embeddings
|
|
"tiktoken", # Token counting
|
|
"python-toon", # Token-efficient LLM serialization
|
|
|
|
# MCP (Model Context Protocol)
|
|
"mcp",
|
|
# Utilities
|
|
"httpx",
|
|
"python-multipart",
|
|
"python-jose[cryptography]", # JWT
|
|
"passlib[bcrypt]", # Password hashing
|
|
"tenacity", # Retry logic
|
|
"structlog", # Structured logging
|
|
|
|
# Streaming
|
|
"sse-starlette", # Server-Sent Events for A2A streaming
|
|
|
|
# Direct imports (promoted from transitive)
|
|
"cryptography", # utils/crypto.py — Fernet-encrypted project git tokens
|
|
|
|
# Build-time pin (not imported). Verified empirically: removing this
|
|
# entry causes uv to ignore the [tool.uv.sources.torch] CPU-only
|
|
# redirect and pull ~2.5GB of unused CUDA wheels. The entry has to
|
|
# appear in direct deps for the source override to bind. deptry's
|
|
# DEP002 ignore for `torch` below documents the same reality.
|
|
"torch",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
dev = [
|
|
# Testing
|
|
"pytest",
|
|
"pytest-asyncio",
|
|
"pytest-cov",
|
|
"pytest-xdist",
|
|
"httpx", # For TestClient
|
|
"factory-boy",
|
|
"faker",
|
|
|
|
# Code Quality
|
|
"ruff",
|
|
"mypy",
|
|
"vulture",
|
|
"bandit",
|
|
"pip-audit",
|
|
"radon",
|
|
"xenon",
|
|
"deptry",
|
|
"import-linter",
|
|
|
|
# Type Stubs
|
|
"types-redis",
|
|
"types-passlib",
|
|
"types-python-jose",
|
|
|
|
# Development
|
|
"ipython",
|
|
"rich",
|
|
]
|
|
|
|
docs = [
|
|
"mkdocs",
|
|
"mkdocs-material",
|
|
"mkdocstrings[python]",
|
|
]
|
|
|
|
[project.scripts]
|
|
roboco = "roboco.cli:main"
|
|
roboco-bootstrap = "roboco.bootstrap:cli"
|
|
|
|
[project.urls]
|
|
Homepage = "https://github.com/renzof/roboco"
|
|
Documentation = "https://roboco.dev/docs"
|
|
Repository = "https://github.com/renzof/roboco"
|
|
|
|
[build-system]
|
|
requires = ["hatchling"]
|
|
build-backend = "hatchling.build"
|
|
|
|
[tool.hatch.build.targets.wheel]
|
|
packages = ["roboco"]
|
|
|
|
[tool.hatch.metadata]
|
|
allow-direct-references = true
|
|
|
|
# =============================================================================
|
|
# uv: pin torch to the CPU-only wheel index
|
|
# =============================================================================
|
|
# `piragi` transitively depends on torch. Our stack uses Ollama over HTTP for
|
|
# all embeddings/LLM, so torch is never actually loaded at runtime — but uv
|
|
# would otherwise resolve torch from PyPI, which bundles the full NVIDIA CUDA
|
|
# stack (~2.5GB across nvidia-cublas, cudnn, cufft, cusolver, nccl, etc.).
|
|
# The CPU-only index provides a ~200MB torch wheel and drops every CUDA dep.
|
|
[[tool.uv.index]]
|
|
name = "pytorch-cpu"
|
|
url = "https://download.pytorch.org/whl/cpu"
|
|
explicit = true
|
|
|
|
[tool.uv.sources]
|
|
torch = [{ index = "pytorch-cpu" }]
|
|
|
|
# =============================================================================
|
|
# RUFF Configuration
|
|
# =============================================================================
|
|
[tool.ruff]
|
|
target-version = "py313"
|
|
src = ["src"]
|
|
exclude = ["vulture_whitelist.py", ".venv", "alembic"]
|
|
|
|
[tool.ruff.lint]
|
|
select = [
|
|
"E", # pycodestyle errors
|
|
"W", # pycodestyle warnings
|
|
"F", # Pyflakes
|
|
"I", # isort
|
|
"B", # flake8-bugbear
|
|
"C4", # flake8-comprehensions
|
|
"UP", # pyupgrade
|
|
"ARG", # flake8-unused-arguments
|
|
"SIM", # flake8-simplify
|
|
"TCH", # flake8-type-checking
|
|
"PTH", # flake8-use-pathlib
|
|
"PL", # Pylint
|
|
"RUF", # Ruff-specific
|
|
]
|
|
|
|
# Lazy imports to avoid circular dependencies
|
|
[tool.ruff.lint.per-file-ignores]
|
|
"roboco/mcp/**/*.py" = ["PLC0415"]
|
|
"roboco/services/*.py" = ["PLC0415"]
|
|
"roboco/api/routes/*.py" = ["PLC0415"]
|
|
"roboco/runtime/*.py" = ["PLC0415"]
|
|
# Tests freely use magic values (status codes, indices), lazy imports for
|
|
# dependency-isolation, and many fixture parameters — these style rules
|
|
# are noise in test files.
|
|
"tests/**/*.py" = [
|
|
"PLR2004", # magic values (status codes, indices) are normal in tests
|
|
"PLC0415", # lazy imports for dependency-isolation in tests
|
|
"PLR0913", # many fixture parameters are normal in tests
|
|
"ARG001", # unused fixture parameters (db_session for autouse, caplog) are normal
|
|
"SIM105", # contextlib.suppress vs try/except/pass — both fine in tests
|
|
"E501", # long lines in test fixtures/payloads are common
|
|
]
|
|
|
|
# =============================================================================
|
|
# MyPy Configuration
|
|
# =============================================================================
|
|
[tool.mypy]
|
|
python_version = "3.13"
|
|
warn_return_any = true
|
|
warn_unused_configs = true
|
|
disallow_untyped_defs = true
|
|
disallow_incomplete_defs = true
|
|
check_untyped_defs = true
|
|
disallow_untyped_decorators = true
|
|
no_implicit_optional = true
|
|
strict_optional = true
|
|
warn_redundant_casts = true
|
|
warn_unused_ignores = true
|
|
warn_no_return = true
|
|
warn_unreachable = true
|
|
exclude = ["vulture_whitelist.py", ".venv", "alembic"]
|
|
|
|
plugins = ["pydantic.mypy"]
|
|
|
|
[[tool.mypy.overrides]]
|
|
module = [
|
|
"redis.*",
|
|
"anthropic.*",
|
|
"tiktoken.*",
|
|
"piragi.*",
|
|
"toon.*",
|
|
"sse_starlette.*",
|
|
"asyncpg.*",
|
|
]
|
|
ignore_missing_imports = true
|
|
|
|
[tool.pydantic-mypy]
|
|
init_forbid_extra = true
|
|
init_typed = true
|
|
warn_required_dynamic_aliases = true
|
|
|
|
# =============================================================================
|
|
# Pytest Configuration
|
|
# =============================================================================
|
|
[tool.pytest.ini_options]
|
|
asyncio_mode = "auto"
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py"]
|
|
asyncio_default_fixture_loop_scope = "function"
|
|
addopts = "--cov=roboco --cov-report=term-missing"
|
|
|
|
[tool.coverage.run]
|
|
# Modules excluded from the coverage gate because they require live
|
|
# infrastructure (Ollama, real audio/video stacks, real workspaces,
|
|
# Docker daemon, Claude Code CLI) that the unit-coverage gate does not
|
|
# provision. They're covered by dedicated integration runs (smoke tests
|
|
# on the NAS) rather than the unit-coverage threshold.
|
|
omit = [
|
|
# RAG / proactive context — needs Ollama + real embedding model.
|
|
"roboco/services/proactive.py",
|
|
"roboco/services/optimal.py",
|
|
"roboco/services/optimal_brain/*",
|
|
# Audio transcription — needs Whisper-class model.
|
|
"roboco/services/transcription.py",
|
|
# Agent classes — instantiated by the orchestrator when spawning
|
|
# Docker containers running the Claude CLI. No usable unit-test
|
|
# surface; integration coverage is the smoke run.
|
|
"roboco/agents/*",
|
|
"roboco/agent_sdk/*",
|
|
# Container orchestration — drives Docker daemon, agent spawning,
|
|
# health/dispatch loops. Covered by smoke runs.
|
|
"roboco/runtime/orchestrator.py",
|
|
# MCP server entry points — modeled around the Claude CLI's STDIO
|
|
# MCP transport and only meaningful when running inside an agent
|
|
# container with the orchestrator reachable. Their _post() bridges
|
|
# ARE unit-tested separately (test_envelope_on_4xx, test_flow_server,
|
|
# test_do_server) — just not via direct module import here.
|
|
"roboco/mcp/*",
|
|
# WebSocket route — needs a running ASGI app + WS client.
|
|
"roboco/api/websocket.py",
|
|
# Event stream bus — wraps Redis Streams; tested via integration only.
|
|
"roboco/events/stream_bus.py",
|
|
# GitService — runs `git` subprocesses against per-agent workspaces.
|
|
# Unit-testable surface is < 5% of the module; covered via the
|
|
# _StubGit-based real-DB integration test + live smoke runs.
|
|
"roboco/services/git.py",
|
|
"roboco/services/workspace.py",
|
|
# Notification delivery — Redis Streams + push to MCP transport.
|
|
"roboco/services/notification_delivery.py",
|
|
# CLI entry point.
|
|
"roboco/cli.py",
|
|
# Auto-generated migrations.
|
|
"alembic/*",
|
|
]
|
|
markers = [
|
|
"asyncio: mark tests as async",
|
|
"slow: marks tests as slow",
|
|
"integration: marks tests as integration tests",
|
|
"unit: marks tests as unit tests",
|
|
]
|
|
|
|
# =============================================================================
|
|
# Vulture Configuration
|
|
# =============================================================================
|
|
[tool.vulture]
|
|
paths = ["roboco", "tests", "vulture_whitelist.py"]
|
|
exclude = ["**/conftest.py", ".venv", "alembic"]
|
|
min_confidence = 100
|
|
ignore_decorators = [
|
|
"@app.route",
|
|
"@app.get",
|
|
"@app.post",
|
|
"@app.put",
|
|
"@app.delete",
|
|
"@app.patch",
|
|
"@pytest.fixture",
|
|
"@pytest.mark.*",
|
|
"@validator",
|
|
"@root_validator",
|
|
"@field_validator",
|
|
"@model_validator",
|
|
]
|
|
ignore_names = [
|
|
"test_*",
|
|
"Test*",
|
|
"cleanup_*",
|
|
"mock_*",
|
|
"expected_*",
|
|
"exc_*",
|
|
"__*__",
|
|
"Config",
|
|
"Field",
|
|
]
|
|
sort_by_size = true
|
|
|
|
# =============================================================================
|
|
# Bandit Configuration
|
|
# =============================================================================
|
|
[tool.bandit]
|
|
skips = []
|
|
exclude_dirs = ["tests", ".venv", "vulture_whitelist.py", "alembic"]
|
|
severity = "medium"
|
|
|
|
# =============================================================================
|
|
# Radon Configuration
|
|
# =============================================================================
|
|
[tool.radon]
|
|
exclude = "tests/*,.venv/*,vulture_whitelist.py,alembic/*"
|
|
cc_min = "C"
|
|
mi_min = "A"
|
|
no_assert = false
|
|
show_closures = true
|
|
total_average = true
|
|
|
|
# =============================================================================
|
|
# Xenon Configuration
|
|
# =============================================================================
|
|
[tool.xenon]
|
|
max_absolute = "B"
|
|
max_modules = "A"
|
|
max_average = "A"
|
|
exclude = ["tests/*", ".venv/*", "vulture_whitelist.py", "alembic/*"]
|
|
ignore = []
|
|
|
|
# =============================================================================
|
|
# Deptry Configuration
|
|
# =============================================================================
|
|
[tool.deptry]
|
|
exclude = ["tests", ".venv", "vulture_whitelist.py", "alembic"]
|
|
extend_exclude = ["conftest.py", "setup.py"]
|
|
known_first_party = ["roboco"]
|
|
|
|
[tool.deptry.per_rule_ignores]
|
|
# DEP002: Dependencies not directly imported but used at runtime or via CLI
|
|
DEP002 = [
|
|
# Runtime server/driver dependencies (used by frameworks, not imported)
|
|
"uvicorn",
|
|
"websockets",
|
|
"asyncpg",
|
|
"hiredis",
|
|
"python-multipart",
|
|
# Database migrations (CLI tool)
|
|
"alembic",
|
|
# Auth libraries (used via passlib[bcrypt], python-jose[cryptography])
|
|
"python-jose",
|
|
"passlib",
|
|
# LLM utilities (embeddings/token counting)
|
|
"openai",
|
|
"tiktoken",
|
|
# Retry logic (used in production services)
|
|
"tenacity",
|
|
# Build-time pin, not imported — see the comment next to the torch
|
|
# entry in [project.dependencies] for the full rationale. Removing
|
|
# it from deps caused uv to pull the full CUDA stack.
|
|
"torch",
|
|
# Dev tools (CLI, not imported)
|
|
"pytest",
|
|
"pytest-asyncio",
|
|
"pytest-cov",
|
|
"pytest-xdist",
|
|
"factory-boy",
|
|
"faker",
|
|
"ruff",
|
|
"mypy",
|
|
"vulture",
|
|
"bandit",
|
|
"pip-audit",
|
|
"radon",
|
|
"xenon",
|
|
"deptry",
|
|
# CLI tool — invoked as `lint-imports` from the Makefile / quality gate
|
|
"import-linter",
|
|
"ipython",
|
|
"rich",
|
|
# Type stubs (used by mypy)
|
|
"types-redis",
|
|
"types-passlib",
|
|
"types-python-jose",
|
|
# Documentation (CLI tools)
|
|
"mkdocs",
|
|
"mkdocs-material",
|
|
"mkdocstrings",
|
|
]
|
|
# DEP003: Starlette is a transitive dep of FastAPI, but BaseHTTPMiddleware is needed
|
|
DEP003 = ["starlette"]
|
|
|
|
[dependency-groups]
|
|
dev = [
|
|
"pytest>=9.0.3",
|
|
"pytest-asyncio>=1.3.0",
|
|
"pytest-cov>=7.1.0",
|
|
]
|
|
|
|
# =============================================================================
|
|
# Import Linter (architectural boundaries)
|
|
# =============================================================================
|
|
[tool.importlinter]
|
|
root_package = "roboco"
|
|
|
|
[[tool.importlinter.contracts]]
|
|
name = "Gateway layer must not import from API routes or MCP servers"
|
|
type = "forbidden"
|
|
source_modules = ["roboco.services.gateway"]
|
|
forbidden_modules = ["roboco.api.routes", "roboco.mcp"]
|
|
|
|
[[tool.importlinter.contracts]]
|
|
name = "Services must not import from API routes"
|
|
type = "forbidden"
|
|
source_modules = ["roboco.services"]
|
|
forbidden_modules = ["roboco.api.routes"]
|
|
|
|
# =============================================================================
|
|
# Roboco Commit Validator
|
|
# =============================================================================
|
|
[tool.roboco.commits]
|
|
subject_min_chars = 20
|
|
banned_words = ["wip", "tmp", "asdf", "oops", "fix", "update", "change", "stuff", "things"]
|
|
prefer_conventional = true
|