Files
treg/pyproject.toml
T

181 lines
6.5 KiB
TOML

[project]
name = "tools-registry"
version = "0.12.1"
description = "A remote registry that turns team skills into shareable, callable tools via a credential-injecting proxy."
readme = "README.md"
license = { file = "LICENSE" }
requires-python = ">=3.12,<3.14" # keep in sync with PYREQ in src/treg/web/install.sh
authors = [
{ name = "Unclecode", email = "unclecode@superdesign.dev" },
{ name = "SuperDesign" },
]
maintainers = [{ name = "Unclecode", email = "unclecode@superdesign.dev" }]
keywords = ["registry", "cli", "proxy", "credentials", "secrets", "api", "tools", "agents"]
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: Other/Proprietary License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development",
"Topic :: Utilities",
]
# Base install = just the CLI. Light + pure-Python, so `pip install tools-registry` (and Homebrew) are
# fast. Everything needed to RUN a registry server lives in the `[server]` extra below.
dependencies = [
"httpx>=0.27",
"questionary>=2.0",
]
[project.optional-dependencies]
# The registry SERVER — host your own. The FastAPI app, the DB drivers, and encryption. Not needed to
# USE the CLI against a hosted registry, only to RUN one. Install with: pip install "tools-registry[server]"
server = [
"alembic>=1.16.5",
"fastapi>=0.115",
"uvicorn[standard]>=0.32",
"sqlmodel>=0.0.22",
"sqlalchemy[asyncio]>=2.0",
"aiosqlite>=0.20",
"asyncpg>=0.30",
"cryptography>=43",
"pydantic-settings>=2.5",
"pyyaml>=6", # the endpoint catalog's data files (src/treg/catalog/*.yaml) — server-side only
"stripe>=12", # balance top-ups (src/treg/billing.py) — the payment rail, server-side only
"mcp>=2", # the MCP front door (src/treg/mcp.py) — server-side only; pulls httpx2 ALONGSIDE
# httpx (they coexist), so the light CLI's dependency set is untouched
]
# The LOCAL PROXY (`treg shell` catching the agent's own outgoing calls). It needs to generate a
# certificate authority on the machine, and `cryptography` is a compiled package — putting it in the
# base install would end the light, pure-Python CLI. Install with: pip install "tools-registry[proxy]"
# A self-hoster already has it through [server]. Everything else the proxy uses is asyncio + ssl from
# the standard library plus httpx, which is already a base dependency.
proxy = [
"cryptography>=43",
]
[project.scripts]
treg = "treg.cli:main"
[project.urls]
Homepage = "https://treg.to"
Repository = "https://github.com/superdesigndev/treg"
Issues = "https://github.com/superdesigndev/treg/issues"
[dependency-groups]
dev = [
"import-linter>=2.13",
"pytest>=8.3",
"pytest-asyncio>=0.24",
"tools-registry[server]", # the test suite imports the server (api, models, …), so dev pulls it in
]
[tool.importlinter]
root_package = "treg"
include_external_packages = true
exclude_type_checking_imports = true
[[tool.importlinter.contracts]]
name = "Lightweight CLI modules do not import server dependencies"
type = "forbidden"
source_modules = [
"treg.cli",
"treg.convert",
"treg.skills",
"treg.providers",
"treg.localrun",
"treg.shell",
"treg.agents",
"treg.egress",
"treg.fsjail",
]
forbidden_modules = [
"aiosqlite",
"alembic",
"asyncpg",
"cryptography",
"fastapi",
"mcp",
"pydantic",
"pydantic_core",
"pydantic_settings",
"sqlalchemy",
"sqlmodel",
"starlette",
"stripe",
"uvicorn",
"yaml",
]
ignore_imports = [
# ensure_proxy_dependency imports this only after the user invokes the optional proxy feature.
"treg.cli -> cryptography",
# render_grant is a server-only path and imports SQLModel only when the server calls it.
"treg.localrun -> sqlmodel",
]
allow_indirect_imports = true
unmatched_ignore_imports_alerting = "error"
as_packages = false
[[tool.importlinter.contracts]]
name = "Money domain does not depend on best-effort audit"
type = "forbidden"
source_modules = ["treg.domain.money"]
forbidden_modules = ["treg.audit"]
as_packages = true
[[tool.importlinter.contracts]]
name = "Routers do not depend on the legacy API module"
type = "forbidden"
source_modules = ["treg.routers"]
forbidden_modules = ["treg.api"]
as_packages = true
[[tool.importlinter.contracts]]
name = "Identity domain does not depend on outer layers"
type = "forbidden"
source_modules = ["treg.domain.identity"]
forbidden_modules = ["treg.api", "treg.routers", "treg.application", "treg.domain.governance"]
as_packages = true
[[tool.importlinter.contracts]]
name = "Governance domain does not depend on outer layers"
type = "forbidden"
source_modules = ["treg.domain.governance"]
forbidden_modules = ["treg.api", "treg.routers", "treg.application"]
as_packages = true
[[tool.importlinter.contracts]]
name = "Governance policies do not import web frameworks"
type = "forbidden"
source_modules = ["treg.domain.governance"]
forbidden_modules = ["fastapi", "starlette"]
allow_indirect_imports = true
as_packages = true
[tool.pytest.ini_options]
asyncio_mode = "auto"
# asyncpg connections are bound to the event loop that created them. The test engine is module-level,
# so keep async tests and fixtures on one loop per pytest process instead of returning pooled Postgres
# connections to a new function-scoped loop. xdist workers remain isolated processes with their own loop.
asyncio_default_test_loop_scope = "session"
asyncio_default_fixture_loop_scope = "session"
# `scripts/` is standalone tooling, not part of the shipped package (the wheel is `src/treg` only),
# but tests import from it — `from scripts import catalog_drift`. Only `python -m pytest` puts the
# working directory on sys.path; CI runs plain `uv run pytest`, where that import is a
# ModuleNotFoundError at collection. Say it here so both invocations agree, rather than adding
# `scripts/__init__.py` and changing what the sdist thinks it contains.
pythonpath = ["."]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/treg"]
# The web/ dir lives inside the treg package, so `packages` already ships every asset
# (favicon.svg, index.html, tutorial.*, tour/, llms.txt, install.sh) — hatchling includes
# non-.py data files under a package by default. A force-include here would add each a SECOND
# time and break the wheel build (`A second file is being added ... at the same path`).