forked from superdesigndev/treg
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
294 lines (271 loc) · 10.8 KB
/
Copy pathpyproject.toml
File metadata and controls
294 lines (271 loc) · 10.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
[project]
name = "tools-registry"
version = "0.15.0"
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/infra/stripe.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"
# Scheduled maintainer commands (worker profile) — needs the [server] extra; Render cron calls this.
treg-worker = "treg.worker: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
]
test = [
"playwright>=1.62.0",
]
[tool.uv]
# uv.lock is `revision = 3`; uv < 0.8.4 silently rewrites it to revision 2 (a ~650-line diff
# that changes no versions). Refuse to run on an old uv rather than teach everyone to avoid `uv lock`.
required-version = ">=0.12"
[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.importlinter.contracts]]
name = "Call application does not depend on HTTP adapters"
type = "forbidden"
source_modules = ["treg.application.call"]
forbidden_modules = ["treg.api", "treg.bootstrap", "treg.routers", "fastapi", "starlette"]
allow_indirect_imports = true
as_packages = true
[[tool.importlinter.contracts]]
name = "Connections domain does not depend on outer layers"
type = "forbidden"
source_modules = ["treg.domain.connections"]
forbidden_modules = [
"treg.api",
"treg.bootstrap",
"treg.routers",
"treg.application",
"fastapi",
"starlette",
]
allow_indirect_imports = true
as_packages = true
[[tool.importlinter.contracts]]
name = "Catalog domain is a leaf: no outer layers, no sibling domains"
type = "forbidden"
source_modules = ["treg.domain.catalog"]
forbidden_modules = [
"treg.api",
"treg.bootstrap",
"treg.routers",
"treg.application",
"treg.domain.connections",
"treg.domain.governance",
"treg.domain.identity",
"treg.domain.money",
"fastapi",
"starlette",
]
allow_indirect_imports = true
as_packages = true
[[tool.importlinter.contracts]]
name = "Tools domain does not depend on outer layers or unsanctioned domains"
type = "forbidden"
source_modules = ["treg.domain.tools"]
# tools → connections is the one sanctioned intra-domain edge, so it is absent here.
forbidden_modules = [
"treg.api",
"treg.bootstrap",
"treg.routers",
"treg.application",
"treg.domain.catalog",
"treg.domain.governance",
"treg.domain.identity",
"treg.domain.money",
"fastapi",
"starlette",
]
allow_indirect_imports = true
as_packages = true
[[tool.importlinter.contracts]]
name = "Upstream infrastructure does not depend on HTTP adapters"
type = "forbidden"
source_modules = ["treg.infra.upstream"]
forbidden_modules = ["treg.api", "treg.bootstrap", "treg.routers", "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.sdist]
# The sdist is PUBLISHED — everything it carries becomes public on PyPI. Hatchling's default is
# "every file git does not ignore", and `.git/info/exclude` is LOCAL-ONLY, so working material kept
# out of git that way (plan docs, evidence, probe dumps) still lands in the tarball. Caught on the
# 0.13.0 build: `docs/evidence/overflow-map-2026-08-26` — 127 MB of aggregator catalogs and probe
# request/response dumps — would have shipped, naming partners we deliberately do not name in
# public. The 0.11.0 release hit the same class of bug with `.codegraph/`. So the dangerous paths
# are excluded HERE, in a committed file, rather than trusted to anyone's local ignore rules.
exclude = [
"docs/evidence", # working evidence for a plan — never public
"docs/*-PLAN.md", # ditto: plan docs live locally
".import_linter_cache", # build cache (nested .gitignore hides it from git, not from hatchling)
".codegraph",
"videos", # git-excluded marketing renders
"*.db", "*.sqlite3", "scratch*", "body.json", # stray local artifacts
".env", ".env.*", # belt and braces: a credential file must never reach a tarball
]
[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`).
[[tool.importlinter.contracts]]
name = "Async task domain is a stdlib leaf shared with the light CLI"
type = "forbidden"
source_modules = ["treg.domain.asynctasks"]
forbidden_modules = ["treg.api", "treg.routers", "treg.application", "treg.bootstrap", "treg.audit", "treg.models", "treg.infra", "treg.config", "fastapi", "starlette", "sqlmodel", "sqlalchemy", "pydantic", "pydantic_settings", "yaml", "httpx"]
allow_indirect_imports = true
as_packages = true
[[tool.importlinter.contracts]]
name = "Capacity domain does not depend on outer layers"
type = "forbidden"
source_modules = ["treg.domain.capacity"]
forbidden_modules = ["treg.api", "treg.routers", "treg.application", "treg.bootstrap", "fastapi", "starlette", "treg.audit"]
allow_indirect_imports = true
as_packages = true