Ctrl K
ComunidadGuías…

pyproject.toml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
[build-system]
build-backend = "hatchling.build"
requires = [ "hatch-vcs", "hatchling" ]

[project]
name = "mindroom"
description = "A universal interface for AI agents with persistent memory, where every conversation has a home"
readme = "README.md"
license = "Apache-2.0"
requires-python = ">=3.13,<3.15"
classifiers = [
  "Programming Language :: Python :: 3 :: Only",
  "Programming Language :: Python :: 3.13",
  "Programming Language :: Python :: 3.14",
]
dynamic = [ "version" ]
dependencies = [
  "agno==3.0.9",
  "aiohttp>=3.13.3",
  # Claude SDK 2 moves requests to API version 2026-10-21, a migration of its own.
  "anthropic>=1.17,<2",
  "anyio>=4.10",
  "authlib>=1.6",
  "certifi>=2026.4.22",
  "cron-descriptor>=1.4.5",
  "croniter>=6",
  "cryptography>=47",
  # Tool descriptions and parameter descriptions come from docstrings (tool_system/tool_schema.py).
  "docstring-parser>=0.18",
  "fastapi>=0.136.3",
  "google-auth>=2.40.3",
  "google-genai>=2",
  "h11>=0.16",
  "httpx>=0.27",
  # 2.15.1 stops a long-lived client's TLS handshakes from growing slower on Linux.
  "httpx2>=2.15.1",
  "humanize>=4.12.3",
  "idna>=3.13",
  "jinja2>=3.1",
  "json5>=0.13",
  "jsonschema>=4.26",
  "markdown-it-py>=4",
  "mcp[cli]>=2.3,<3",
  "mdit-py-plugins>=0.5",
  # Owned to-device transport requires the durable NIO API.
  "mindroom-nio[e2e]==1.3",
  "ollama>=0.6.1",
  # 3.30 returns a streamed Chat Completions connection to the pool.
  "openai>=3.30",
  "packaging>=24",
  "pillow>=10.2",
  "pydantic>=2.12.5",
  "pydantic-settings>=2.10.1",
  "pygments>=2.20",
  "pyjwt>=2.13",
  # Request sizing reads a PDF attachment's page count (token_counting/requests.py).
  "pypdf>=6.21.4",
  "python-dotenv>=1",
  "python-multipart>=0.0.27",
  "pyyaml>=6",
  "questionary>=2.1.1",
  "referencing>=0.37",
  "rich",
  "segno>=1.6.6",
  "starlette>=1.3.1",
  "structlog>=24.1",
  "tiktoken>=0.12",
  "typer>=0.24",
  "uvicorn>=0.35",
  "watchfiles>=1",
  "websockets>=14",
]
[[project.authors]]
name = "mindroom team"
[project.optional-dependencies]
agent_manager = []
agentql = [
  "agentql",
  "playwright",
]
airflow = []
apify = [
  "apify-client>=1.12.2; platform_machine!='aarch64'",
]
approved_egress = []
arxiv = [
  "arxiv",
]
atlassian = []
attachments = []
aws_lambda = [
  "boto3>=1.40.8",
]
aws_ses = [
  "boto3>=1.40.8",
]
baidusearch = [
  "baidusearch",
  "pycountry",
]
aws_bedrock = [
  "boto3>=1.40.8",
]
bitbucket = [
  "requests",
]
brandfetch = [
  "httpx>=0.27",
]
brightdata = [
  "requests",
]
browser_mcp = []
browser = [
  "playwright",
]
browserbase = [
  "browserbase",
  "playwright",
]
cal_com = [
  "pytz",
  "requests",
]
calculator = []
callback_manager = []
cartesia = [
  "cartesia",
]
chat_ui = []
chromadb = [
  "chromadb>=1.5.8",
]
claude_agent = [
  "claude-agent-sdk>=0.2.140",
]
clickup = [
  "requests",
]
coding = []
compact_context = []
composio = [
  "composio-agno",
]
config_manager = [
  "pydantic>=2",
  "pyyaml>=6",
]
confluence = [
  "atlassian-python-api",
]
contacts = []
crawl4ai = [
  "crawl4ai>=0.7.3",
]
csv = [
  "duckdb",
]
custom_api = [
  "requests",
]
daytona = [
  "daytona",
]
delegate = []
discord = [
  "requests",
]
docker = [
  "docker",
]
duckdb = [
  "duckdb",
]
duckduckgo = [
  "ddgs",
]
dynamic_tools = []
dynamic_workflow = []
report_publishing = []
e2b = [
  "e2b-code-interpreter",
]
egress_credentials = []
eleven_labs = [
  "elevenlabs",
]
email = []
exa = [
  "exa-py",
]
external_trigger_manager = []
fal = [
  "fal-client",
]
file = []
file_generation = [
  "python-docx>=1.2",
  "reportlab",
]
financial_datasets_api = [
  "requests",
]
firecrawl = [
  "firecrawl-py>=3",
]
gemini = [
  "google-genai",
]
giphy = [
  "httpx>=0.27",
]
github = [
  # PyGithub 2.9 injects URL metadata into dictionary responses, breaking Agno's numeric language parser.
  "pygithub>=2.5,<2.9",
]
gmail = [
  "google-api-python-client>=2.178",
  "google-auth>=2.40.3",
  "google-auth-httplib2>=0.2",
  "google-auth-oauthlib>=1.2.2",
]
google_bigquery = [
  "google-api-python-client>=2.178",
  "google-auth>=2.40.3",
  "google-auth-httplib2>=0.2",
  "google-cloud-bigquery>=3.41",
]
google_calendar = [
  "google-api-python-client>=2.178",
  "google-auth>=2.40.3",
  "google-auth-httplib2>=0.2",
  "google-auth-oauthlib>=1.2.2",
]
google_drive = [
  "google-api-python-client>=2.178",
  "google-auth>=2.40.3",
  "google-auth-httplib2>=0.2",
  "google-auth-oauthlib>=1.2.2",
]
google_docs = [
  "google-api-python-client>=2.178",
  "google-auth>=2.40.3",
  "google-auth-httplib2>=0.2",
]
google_maps = [
  "google-maps-places",
  "googlemaps",
]
google_scholar = [
  "scholarly",
]
google_sheets = [
  "google-api-python-client>=2.178",
  "google-auth-httplib2>=0.2",
  "google-auth-oauthlib>=1.2.2",
]
google_tasks = [
  "google-api-python-client>=2.178",
  "google-auth>=2.40.3",
  "google-auth-httplib2>=0.2",
]
googlesearch = [
  "ddgs",
]
groq = [
  "groq>=0.31",
]
hackernews = [
  "httpx>=0.27",
]
homeassistant = [
  "httpx>=0.27",
]
invite_router = []
jina = [
  "httpx>=0.27",
  "pydantic>=2",
]
jira = [
  "jira>=3.10.5",
]
knowledge_graph = [
  "graphiti-core[falkordblite]==0.31.1",
  # C parser for FalkorDB replies; redis-py parses large ones in pure Python on the event loop otherwise.
  "hiredis",
  "psutil",
]
kubernetes = [
  "kubernetes>=28.1",
]
linear = [
  "requests",
]
linkup = [
  "linkup-sdk>=0.2.8",
]
lumalabs = [
  "lumaai",
]
matrix_api = []
matrix_calls = [
  # 1.8.9 runs on OpenAI SDK 3 and pins the livekit 1.1.21 audio mixer the call tests cover.
  "livekit-agents[openai]>=1.8.9",
]
matrix-e2ee = []
matrix_message = []
matrix_room = []
matrix_voice_message = []
mem0 = [
  "mem0ai>=2.2.1",
]
memory = []
microsoft_files = []
microsoft_meetings = []
microsoft_onenote = []
microsoft_people = []
microsoft_sharepoint = []
microsoft_teams = []
microsoft_todo = []
modelslabs = [
  "requests",
]
moviepy_video_tools = [
  "moviepy",
]
neo4j = [
  "neo4j",
]
newspaper = [
  "lxml-html-clean",
  "newspaper4k",
]
notion = [
  "notion-client",
]
numpy = [
  "numpy>=2",
]
oauth_connections = []
openai = [
  "openai",
]
openbb = [
  "openbb",
  "polars",
  "pyarrow",
]
openclaw_compat = []
openweather = [
  "requests",
]
outlook_calendar = []
outlook_mail = []
oxylabs = [
  "oxylabs",
]
pandas = [
  "pandas>=2.2",
]
postgres = [
  "psycopg[binary]",
]
pubmed = [
  "httpx>=0.27",
]
python = []
react = []
reasoning = []
reddit = [
  "praw",
]
redshift = [
  "redshift-connector",
]
replicate = [
  "replicate>=1.0.7",
]
resend = [
  "resend",
]
scheduler = []
script = []
scrapegraph = [
  "scrapegraph-py>=2.1",
]
searxng = []
self_config = [
  "pydantic>=2",
  "pyyaml>=6",
]
sentence-transformers = [
  "sentence-transformers>=6.1",
  "torchvision",
  "transformers>=5.19",
]
serpapi = [
  "google-search-results>=2.4.2",
]
serper = [
  "requests",
]
shared_directories = []
shell = []
shopify = [
  "httpx>=0.27",
]
skill_manage = []
slack = []
sleep = []
spider = [
  "spider-client",
]
spotify = [
  "httpx>=0.27",
]
sql = [
  "sqlalchemy",
]
stop_reply = []
supabase = [
  "supabase>=2.18.1",
]
tavily = [
  "tavily-python",
]
telegram = [
  "pytelegrambotapi>=4.32",
]
terminal = []
thread_model = []
thread_move = []
thread_resolution = []
thread_summary = []
thread_tags = []
todo = []
todoist = [
  "todoist-api-python",
]
trafilatura = [
  "trafilatura",
]
trello = [
  "py-trello",
]
twilio = [
  "twilio",
]
unsplash = []
update_awareness = []
usage_stats = []
visualization = [
  "matplotlib",
]
web_browser_tools = []
webex = [
  "webexpythonsdk",
]
website = [
  "beautifulsoup4",
  "httpx>=0.27",
]
whatsapp = [
  "httpx>=0.27",
]
wikipedia = [
  "wikipedia",
]
x = [
  "tweepy",
]
yfinance = [
  "yfinance",
]
youtube = [
  "youtube-transcript-api",
]
zendesk = [
  "requests",
]
zep = [
  "zep-cloud>=3.3",
]
zoom = [
  "requests",
]
desktop = [
  "pillow>=10.2",
  "pyautogui>=0.9.54",
  "pyobjc-framework-applicationservices>=12.2.1; sys_platform=='darwin'",
  "pyobjc-framework-cocoa>=12.2.1; sys_platform=='darwin'",
  "pyobjc-framework-screencapturekit>=12.2.1; sys_platform=='darwin'",
]
[project.scripts]
mindroom-agent = "mindroom.agent_cli.main:main"
mindroom = "mindroom.cli.main:main"
[project.urls]
documentation = "https://github.com/mindroom-ai/mindroom"
homepage = "https://github.com/mindroom-ai/mindroom"
repository = "https://github.com/mindroom-ai/mindroom"

[dependency-groups]
dev = [
  "aioresponses>=0.7.8",
  "hypothesis>=6.161.1",
  "markdown>=3.10.2",
  "markdown-code-runner>=2.4",
  "markdown-gfm-admonition",
  "pre-commit>=4.2",
  "pre-commit-uv>=4.1.4",
  "privata>=0.8",
  "pytest>=8.4.1",
  "pytest-asyncio>=1.1",
  "pytest-cov>=6.2.1",
  "pytest-mock>=3.14.1",
  "pytest-shm>=0.1.3",
  "pytest-timeout>=2.4",
  "pytest-xdist>=3.8",
  "requests>=2.32.4",
  "ruff>=0.12.5",
  "tach>=0.34.1",
  "ty>=0.0.17",
  "vulture>=2.16",
  "zensical",
]
# Only the frozen helper's dependencies; the backend's ML packages are not needed.
# uv resolves this group with the application's exact NIO pin in the same lockfile.
desktop-helper = [
  "certifi",
  "httpx>=0.27",
  "mcp[cli]>=2.3,<3",
  "mindroom-nio[e2e]",
  "pillow>=10.2",
  "pyautogui>=0.9.54",
  "pyinstaller==6.16",
  "pyobjc-framework-applicationservices>=12.2.1; sys_platform=='darwin'",
  "pyobjc-framework-cocoa>=12.2.1; sys_platform=='darwin'",
  "pyobjc-framework-screencapturekit>=12.2.1; sys_platform=='darwin'",
  "python-dotenv>=1.1.1",
  "pyyaml>=6.0.2",
  "structlog>=25.4",
]

[tool.hatch.build.targets.wheel]
packages = [ "src/mindroom" ]
[tool.hatch.build.targets.wheel.force-include]
skills = "mindroom/_bundled_skills"
[tool.hatch.build.targets.wheel.hooks.custom]
[tool.hatch.version]
source = "vcs"
[tool.hatch.version.raw-options]
version_scheme = "no-guess-dev"

[tool.uv]
override-dependencies = [
  # crawl4ai 0.8.6 declares lxml~=5.3, which caps lxml below 6.
  # The locked lxml 5.4.0 has no cp314 Linux wheels.
  # On Python 3.14 it source-builds against libxml2/libxslt, so use lxml 6.1+ there.
  "lxml>=5.3,<6; python_version < '3.14'",
  "lxml>=6.1.0; python_version >= '3.14'",
  # composio-core 0.7.21 declares Pillow<11,>=10.2.0.
  # The locked Pillow 10.4.0 has no cp314 Linux wheels.
  # On Python 3.14 it source-builds against zlib, so use Pillow 11.x there.
  "pillow>=10.2,<11; python_version < '3.14'",
  "pillow>=11,<12; python_version >= '3.14'",
]
# Exact version pins for everything uv installs into isolated build environments, so release, desktop-helper,
# and image builds install only the build package versions this revision names.
# uv checks no file hashes here, so a file later added to a pinned release on PyPI can still be installed.
# uv build, uv sync (through uv.lock), and uv pip run with --project all read these.
# hatchling, hatch-vcs, and their requirements build this project; editable installs add editables.
# Locked dependencies that publish only sdists build with setuptools; pyscreeze adds wheel,
# and googlemaps adds requests and its requirements.
build-constraint-dependencies = [
  "certifi==2026.7.22",
  "charset-normalizer==3.5.2",
  "editables==0.6",
  "hatch-vcs==0.5.0",
  "hatchling==1.32.4",
  "idna==3.20",
  "packaging==26.3",
  "pathspec==1.1.1",
  "pluggy==1.6.0",
  "requests==2.34.2",
  "setuptools-scm==10.3.4",
  "setuptools==84.0.0",
  "tomlkit==0.15.1",
  "trove-classifiers==2026.9.21.13",
  "urllib3==2.8.0",
  "vcs-versioning==2.5.0",
  "wheel==0.48.0",
]

[tool.ruff]
target-version = "py313"
line-length = 120
[tool.ruff.lint]
select = [
  "ALL",
]
ignore = [
  "ASYNC240", # Async pathlib guidance is too broad for this asyncio codebase/tests
  "ASYNC250", # Blocking input in async manual tests is intentional
  "B905",     # `zip()` without an explicit `strict=` parameter
  "BLE001",   # Do not catch blind exception
  "D203",     # Incompatible with D211; prefer no blank line before class docstrings
  "D107",     # Missing docstring in `__init__`
  "D213",     # Incompatible with D212; prefer multi-line summaries on the first line
  "D401",     # First line of docstring should be in imperative mood
  "D402",     # First line should not be the function's signature
  "E501",     # Line too long
  "FBT001",   # Boolean-typed positional argument in function definition
  "FBT002",   # Boolean default value
  "FBT003",   # Boolean positional value in call
  "FIX002",   # Line contains TODO
  "G004",     # Logging statement uses f-string
  "PLR0913",  # Too many arguments to function call (N > 5)
  "PLR2004",  # Magic value used
  "PLW0108",  # Lambda warnings from dependency injection and test doubles are not actionable here
  "PLW0603",  # Using the global statement to update `X` is discouraged
  "PYI034",   # `Self` guidance is not useful in concrete test doubles
  "S101",     # Use of assert detected
  "S603",     # `subprocess` call: check for execution of untrusted input
  "S607",     # Starting a process with a partial executable path
  "SLF001",   # Private member accessed
  "T20",      # flake8-print
  "TD002",    # Missing author in TODO; try: `# TODO(<author_name>): ...`
  "TD003",    # Missing issue link on the line following this TODO
  "UP042",    # `StrEnum` migration is outside the scope of hook maintenance
  "UP047",    # PEP 695 type-parameter migration is outside the scope of hook maintenance
]
per-file-ignores.".claude/skills/*/scripts/*" = [
  "INP001", # Part of an implicit namespace package (standalone skill scripts)
]
per-file-ignores.".github/scripts/*" = [
  "INP001", # Part of an implicit namespace package (standalone scripts)
]
per-file-ignores."cluster/k8s/kind/*" = [
  "INP001", # Part of an implicit namespace package (namespace package for python -m invocation)
]
per-file-ignores."tests/fixtures/*/*.py" = [
  "INP001", # Example plugins under test fixtures load by path, never as packages
]
per-file-ignores."src/mindroom/tools/*" = [
  "PLC0415", # `import` should be at the top-level of a file"
]
per-file-ignores."src/mindroom/tools/__init__.py" = [
  "F401", # the package imports each registration only so it registers its tool
]

[tool.vulture]
paths = [ "src/mindroom", "vulture_whitelist.py" ]
ignore_decorators = [ "@register_tool_with_metadata" ]
min_confidence = 60
sort_by_size = true

[tool.ty.environment]
python-version = "3.13"
# Mock patterns cause many false positives in tests (e.g., mock.call_args
# returns _Call | None, attribute access on MagicMock, passing mocks as typed
# arguments).
[[tool.ty.overrides]]
include = [ "tests/" ]
rules = { call-non-callable = "ignore", invalid-argument-type = "ignore", invalid-assignment = "ignore", invalid-return-type = "ignore", no-matching-overload = "ignore", not-iterable = "ignore", not-subscriptable = "ignore", too-many-positional-arguments = "ignore", unresolved-attribute = "ignore", unsupported-operator = "ignore" }

# The macOS accessibility backend imports pyobjc, declared
# `sys_platform=='darwin'` and so genuinely absent everywhere else. Checking on
# another platform cannot resolve it and should not pretend to; the alternative
# is declaring the whole project macOS-targeted, which would hide real errors in
# the paths that are not. The imports are already function-level.
#
# `unused-ignore-comment` goes with it: the per-attribute ignores in those files
# are load-bearing on macOS, where pyobjc resolves and ty sees real types, and
# necessarily unused wherever the import does not resolve. One file cannot
# satisfy both platforms, so the warning is scoped off rather than the
# directives deleted.
[[tool.ty.overrides]]
include = [ "src/mindroom/desktop/" ]
rules = { unresolved-import = "ignore", unused-ignore-comment = "ignore" }
[tool.ty.rules]
deprecated = "ignore"  # FastAPI on_event deprecation; refactor to lifespan separately
[tool.ty.src]
include = [ "src", "tests" ]
[tool.ty.terminal]
error-on-warning = true

[tool.pytest.ini_options]
testpaths = [ "tests" ]
python_files = "test_*.py"
asyncio_mode = "auto"
pythonpath = [ "src" ]
addopts = """
    -p no:tach
    -q
    -n auto
    --dist worksteal
    --asyncio-mode=strict
    --timeout 60
    --durations 20
"""
markers = [
  "e2e: marks end-to-end tests",
  "slow: marks tests as slow",
]
# A full run peaks at about 3 GiB of temporary files on /dev/shm, mostly worker virtualenvs.
shm_min_free_gib = 4

[tool.coverage.report]
exclude_lines = [
  "pragma: no cover",
  "raise NotImplementedError",
  "if TYPE_CHECKING",
  "if __name__ == .__main__.:",
]
exclude_also = [ '^\s*\.\.\.$' ]