feat: treg.to is the canonical domain — treg.superdesign.dev becomes the legacy alias

public_url/email_from defaults, render.yaml, CLI fallbacks, packaging (npm/plugin/pyproject),
web pages (+canonical tag), docs and context fragments all move to https://treg.to.

The legacy host keeps serving the FULL API forever — installed CLIs, skill.md files and
.mcp.json configs in the wild hold Bearer tokens pointed at it, and HTTP clients strip
Authorization on cross-host redirects. Only browser-facing marketing pages 301 to treg.to
(new middleware + tests).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jason Zhou
2026-08-13 11:56:20 +10:00
co-authored by Claude Fable 5
parent 506604f7b3
commit 8ca54c0c6f
42 changed files with 214 additions and 117 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ body:
- Web dashboard
- The API / proxy
- Self-hosted server
- Hosted (treg.superdesign.dev)
- Hosted (treg.to)
- Other / not sure
validations:
required: true
+8 -8
View File
@@ -11,7 +11,7 @@ agent without the credential ever leaving the server.
**Ask for the task, not the tool.** You do not need to know which vendor sells backlink data, or to
hold an account with them. Search for what you want to do, read the price, call it.
Built for the Superdesign team, live at [treg.superdesign.dev](https://treg.superdesign.dev) — anyone can self-host.
Built for the Superdesign team, live at [treg.to](https://treg.to) — anyone can self-host.
## Why it exists
@@ -44,7 +44,7 @@ The vocabulary for the second half:
# Part 1 · Using the registry
Visit [**treg.superdesign.dev**](https://treg.superdesign.dev) (hosted on Render) — the dashboard,
Visit [**treg.to**](https://treg.to) (hosted on Render) — the dashboard,
sign-in, and every URL below live there.
## Quickstart
@@ -53,7 +53,7 @@ Same flow as the dashboard's **Getting started** guide:
```bash
# 1. install the CLI — also points it at the registry
curl -fsSL https://treg.superdesign.dev/install.sh | sh
curl -fsSL https://treg.to/install.sh | sh
# 2. sign in (GitHub default · --email for a one-time code · --token for agents/CI)
treg login
@@ -132,7 +132,7 @@ treg resolves the tool by host, injects the credential, and relays everything el
```
Real request: GET https://api.intercom.io/conversations?per_page=5
Through treg: GET https://treg.superdesign.dev/call/https://api.intercom.io/conversations?per_page=5
Through treg: GET https://treg.to/call/https://api.intercom.io/conversations?per_page=5
header: X-Treg-Token: <your token>
```
@@ -212,9 +212,9 @@ treg org access <member> --tools a,b # per-member tool access (admin+)
## Going deeper
- [`USAGE.md`](USAGE.md) — the full `treg` CLI reference.
- [`/llms.txt`](https://treg.superdesign.dev/llms.txt) — the agent-onboarding file: call
- [`/llms.txt`](https://treg.to/llms.txt) — the agent-onboarding file: call
protocol, discovery, auth, CLI, skills. One fetch teaches an agent the whole registry.
- **The dashboard** at [treg.superdesign.dev](https://treg.superdesign.dev) — full CRUD, a guided
- **The dashboard** at [treg.to](https://treg.to) — full CRUD, a guided
tutorial (Help → Tutorial), and copyable setup instructions for your agents.
- **The API** — everything the CLI does is plain HTTP; interactive OpenAPI docs live at `/docs`.
The proxy endpoint is `/call/{...}`; all endpoints take the `X-Treg-Token` header.
@@ -253,7 +253,7 @@ uv run python -m treg keygen # print a fresh Fernet key for TREG_SECRET_KEY
> database drivers, and encryption. `pip install tools-registry` alone gives just the `treg` command for
> talking to an existing registry.
The team instance is hosted on **Render** (web service + Postgres) at `treg.superdesign.dev`.
The team instance is hosted on **Render** (web service + Postgres) at `treg.to`.
## Configuration
@@ -264,7 +264,7 @@ Environment variables (prefix `TREG_`, read from `.env`):
| ----------------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TREG_DATABASE_URL` | `sqlite+aiosqlite:///./treg.db` | DB URL (SQLite for dev, Postgres in prod) |
| `TREG_SECRET_KEY` | *(empty)* | Fernet key for secrets-at-rest; empty → an ephemeral key is minted (secrets won't survive a restart) |
| `TREG_PUBLIC_URL` | `https://treg.superdesign.dev` | treg's public base, used to build the OAuth callback URI |
| `TREG_PUBLIC_URL` | `https://treg.to` | treg's public base, used to build the OAuth callback URI |
| `TREG_SESSION_SECRET` | *(empty)* | signs the dashboard session cookie; falls back to `TREG_SECRET_KEY`. Set a real value in prod |
| `TREG_GITHUB_CLIENT_ID` / `_SECRET` | *(empty)* | GitHub OAuth sign-in (callback `<public_url>/auth/github/callback`); empty hides the button |
| `TREG_GOOGLE_CLIENT_ID` / `_SECRET` | *(empty)* | Google OAuth sign-in (redirect `<public_url>/auth/google/callback`); empty hides the button |
+5 -5
View File
@@ -2,7 +2,7 @@
`treg` is the command-line client for **tools-registry**: call shared team tools without holding
their credentials, and turn your local skills into shareable tools. It's a thin client over the
API (`https://treg.superdesign.dev`); the API is the only brain.
API (`https://treg.to`); the API is the only brain.
Every command reads `~/.treg/config.json` for the endpoint + your token. Get per-command detail
with `treg <command> --help` (e.g. `treg secret --help`, not `treg "secret add"`).
@@ -54,7 +54,7 @@ present a per-org token directly.
| `treg onboard` | `--mode guided\|quick` · `--name N` · `--yes` · `--reset` | colourful guided first-run — pick **guided build** (you create the team + invite a teammate, step by step) or **quick demo** (we seed a full demo team + tool + activity), ending on a no-key call. Offered `[Y/n]` after your first login; `--reset` removes demo teammates |
```bash
treg config --base-url https://treg.superdesign.dev
treg config --base-url https://treg.to
treg login # GitHub; or:
treg login --email you@example.com # emailed 6-digit code (register-or-login)
```
@@ -82,7 +82,7 @@ treg org create "Team A" # active org is now team-a
treg org invite bob@company.com --role member # prints e.g. inv_7Kd9x2LmQpR4 — send it to Bob
# Bob's side (no email is sent; he gets the code over Slack/DM)
treg config --base-url https://treg.superdesign.dev
treg config --base-url https://treg.to
treg org join inv_7Kd9x2LmQpR4 --email bob@company.com # joins + mints HIS own token
treg tool ls # sees only Team A's tools
treg org use team-a # switch orgs anytime; one token per org, never mixed
@@ -188,7 +188,7 @@ treg call posthog api/projects --method POST --data '{"name":"x"}'
**Agent-native (raw HTTP) form** — build the real upstream URL and prefix it; no CLI needed:
```
GET https://treg.superdesign.dev/call/https://api.intercom.io/conversations?per_page=5
GET https://treg.to/call/https://api.intercom.io/conversations?per_page=5
+ header: X-Treg-Token: <your token>
```
@@ -376,7 +376,7 @@ Idempotent — re-run any time (skips what's registered; `--replace` updates). N
| `treg health` | `--run` | show every credential's status; `--run` re-checks now (refresh oauth, probe tools, alert owners) |
```bash
# one-time: add https://treg.superdesign.dev/oauth/callback to your OAuth app's redirect URIs
# one-time: add https://treg.to/oauth/callback to your OAuth app's redirect URIs
treg oauth connect gads --client-secret ./client_secret.json \
--scopes https://www.googleapis.com/auth/adwords
treg health --run
+2 -2
View File
@@ -1,8 +1,8 @@
# tools-registry — dashboard tour
Everything you can do in the web UI, with a screenshot per step. The interactive version (Ledger style,
prev/next, theme toggle) is served at `https://treg.superdesign.dev/dashboard-tour/` (Help → Dashboard tour); the CLI walkthrough is
[`docs/TUTORIAL.md`](TUTORIAL.md) / `https://treg.superdesign.dev/tutorial`.
prev/next, theme toggle) is served at `https://treg.to/dashboard-tour/` (Help → Dashboard tour); the CLI walkthrough is
[`docs/TUTORIAL.md`](TUTORIAL.md) / `https://treg.to/tutorial`.
Screenshots are generated by `docs/dash-tour/capture.py` (Playwright) — re-run it after UI changes.
+2 -2
View File
@@ -1,12 +1,12 @@
# tools-registry — onboarding
The bootstrap an agent (or human) follows to start calling shared tools and to share its own.
The CLI is a thin client over the API at `https://treg.superdesign.dev`; the API is the only brain.
The CLI is a thin client over the API at `https://treg.to`; the API is the only brain.
## 1. Install the CLI
```bash
curl -fsSL https://treg.superdesign.dev/install.sh | sh # installs `treg`, points it at the registry
curl -fsSL https://treg.to/install.sh | sh # installs `treg`, points it at the registry
```
(Working from a clone instead? `uv sync && uv run treg --help`.)
+5 -5
View File
@@ -38,7 +38,7 @@ and all three normal doors fail that test: GitHub OAuth, Google OAuth, and an em
The way through already exists:
```bash
curl -fsSL https://treg.superdesign.dev/install.sh | sh
curl -fsSL https://treg.to/install.sh | sh
treg login --token <REVIEWER_TOKEN> # the agents/CI door — no browser, no email
```
@@ -55,10 +55,10 @@ whatever balance it can reach, and the token goes into a form.
| Long Description | *(use `interface.longDescription` from the manifest, verbatim)* |
| Logo | `plugin/assets/logo.png` (1024×1024) |
| Category | **Developer Tools** |
| Website URL | `https://treg.superdesign.dev` |
| Website URL | `https://treg.to` |
| Support URL | **decide — see above** |
| Privacy Policy URL | `https://treg.superdesign.dev/privacy` |
| Terms URL | `https://treg.superdesign.dev/terms` |
| Privacy Policy URL | `https://treg.to/privacy` |
| Terms URL | `https://treg.to/terms` |
| Developer Identity | the verified `superdesign` business identity |
## Skills tab
@@ -135,7 +135,7 @@ rather than jurisdiction-specific, so start narrow rather than selecting everywh
>
> To test: install the CLI and sign in with the reviewer token, which needs no browser or email:
>
> curl -fsSL https://treg.superdesign.dev/install.sh | sh
> curl -fsSL https://treg.to/install.sh | sh
> treg login --token <REVIEWER_TOKEN>
>
> That account has a prepaid balance, so calls in the test cases will complete. `treg catalog search
+8 -8
View File
@@ -6,8 +6,8 @@ The whole registry, end to end. Every step shows the **exact command**, the **ex
There are two companion versions of this same walkthrough, generated from one source
(`src/treg/web/tutorial.js`):
- **In the dashboard** → sign in at `https://treg.superdesign.dev/` and open **Help → Tutorial**.
- **Standalone** → `https://treg.superdesign.dev/tutorial`.
- **In the dashboard** → sign in at `https://treg.to/` and open **Help → Tutorial**.
- **Standalone** → `https://treg.to/tutorial`.
### Two focused, deep-dive tutorials
@@ -15,12 +15,12 @@ This main walkthrough covers the whole registry. Two features have their own det
those for the full, step-by-step treatment (each shows the exact commands, real output, and how it was
tested):
- **Import & shell** → `https://treg.superdesign.dev/tutorial-import-shell.md` — turn the CLIs already on your
- **Import & shell** → `https://treg.to/tutorial-import-shell.md` — turn the CLIs already on your
machine into team tools in one command (`treg upload clis`), and open a shell (`treg shell`) where
`stripe`, `gh`, `gcloud` … just work with the team key injected. Includes the local-run **security
sandbox** (the CLI runs as a locked-down user, can reach only its own API, and can't leave the key on
disk).
- **Team access control** → `https://treg.superdesign.dev/tutorial-access.md` — choose **which tools each member
- **Team access control** → `https://treg.to/tutorial-access.md` — choose **which tools each member
may use**, and whether they may run CLIs **locally** — set at invite time, changed any time.
---
@@ -70,7 +70,7 @@ the `HOME=` prefix.
```bash
for u in tom bob alice; do
mkdir -p ~/.treg-personas/$u
HOME=~/.treg-personas/$u treg config --base-url https://treg.superdesign.dev
HOME=~/.treg-personas/$u treg config --base-url https://treg.to
done
```
@@ -478,7 +478,7 @@ token header — any language, any agent, `curl`.
```bash
ATOK=$(python3 -c "import json;print(json.load(open('/Users/you/.treg-personas/alice/.treg/config.json'))['token'])")
curl -s -H "X-Treg-Token: $ATOK" \
"https://treg.superdesign.dev/call/https://postman-echo.com/get"
"https://treg.to/call/https://postman-echo.com/get"
```
```
# the postman-echo JSON again, "authorization": "Bearer sk-demo-secret-123" injected —
@@ -843,13 +843,13 @@ Admin panel lights up for him.
## Step 33 — The same registry, in the browser
Open **treg.superdesign.dev** and sign in with the **email code** door (the same one you used in the terminal):
Open **treg.to** and sign in with the **email code** door (the same one you used in the terminal):
type your email → click **Email me a sign-in code** → **check your inbox** for the 6-digit code → paste it
in and **Sign in**. You land on your team org — Tools shows the `echo` tool, Activity shows the call, and
(since Tom is now super-admin) an **Admin** panel appears.
```bash
open https://treg.superdesign.dev/
open https://treg.to/
```
```
# Sign in with email → land on Superdesign
+1 -1
View File
@@ -41,7 +41,7 @@ Strongly preferred (each one directly improves your listing):
The fastest route: paste the prompt from the **"List as vendor"** button on the dashboard's
Catalog page into your coding agent — it follows the hosted instructions at
[`/vendor-listing`](https://treg.superdesign.dev/vendor-listing) and opens the PR for you.
[`/vendor-listing`](https://treg.to/vendor-listing) and opens the PR for you.
Or open an issue or PR on this repo yourself, with:
0. **A contact email in the PR/issue description** (e.g. `Contact: partnerships@yourapi.com`) —
+1 -1
View File
@@ -36,7 +36,7 @@ What this means for anyone reading this fragment:
Money and metering: [money](../architecture/money.md). The endpoint data and its pricing rules:
[catalog](../architecture/catalog.md).
> **Status:** shipped and live on `treg.superdesign.dev` (Render, multi-tenant). This fragment records
> **Status:** shipped and live on `treg.to` (Render, multi-tenant; `treg.superdesign.dev` is the legacy alias). This fragment records
> the ORIGINAL vision from the 2026-06-30 kickoff and the "why" behind the proxy; the shipped detail
> lives in the architecture/interface fragments.
>
+5
View File
@@ -419,6 +419,11 @@ helpers `_secret_view` / `_tool_view` / `_bundle_view` never leak secret values
surfaced by `GET /tools` / `/bundles/{id}`).
## Cross-cutting hardening (bug-hunt)
- **Legacy-host redirect:** `_legacy_host_redirect` 301s GET/HEAD marketing pages (`_REDIRECT_PATHS`)
from `treg.superdesign.dev` (`_LEGACY_HOSTS`) to the canonical `public_url` host (`treg.to`).
Everything else is served in place on BOTH hosts, forever: installed CLIs/skills hold tokens
pointed at the legacy host, HTTP clients strip `Authorization` on a cross-host redirect, and
`curl {BASE}/install.sh | sh` runs without `-L`. Never remove the legacy domain from Render.
- **Security headers:** a `@app.middleware` adds `X-Content-Type-Options: nosniff`, `X-Frame-Options:
DENY`, `Referrer-Policy: no-referrer`, and HSTS to every response (`setdefault`, so the `/call`
proxy's stricter CSP/nosniff wins).
+6 -4
View File
@@ -36,7 +36,8 @@ keygen` prints a Fernet key for `TREG_SECRET_KEY`.
Render's `fromDatabase`-injected URL works unedited (the async engine needs the asyncpg driver).
- `secret_key` — the Fernet key; empty → an ephemeral key is minted at startup (secrets won't survive a
restart). See [auth-secrets](../architecture/auth-secrets.md).
- `public_url` — default `https://treg.superdesign.dev` (the reference deployment); self-hosters set
- `public_url` — default `https://treg.to` (the reference deployment; `treg.superdesign.dev` is the
legacy host — still served in full, marketing pages 301 to the canonical host); self-hosters set
`TREG_PUBLIC_URL`. Used to build the OAuth callback URI.
- `api_token` — a bootstrap caller token (MVP leftover; per-user tokens are the real auth).
- `admin_token` — the cross-tenant **super-admin** bearer (`TREG_ADMIN_TOKEN`); empty disables the env
@@ -107,8 +108,8 @@ keygen` prints a Fernet key for `TREG_SECRET_KEY`.
- `resend_api_key` / `email_from` — transactional email via **Resend** (`src/treg/email.py`): the OTP
sign-in code + team invitations. Empty key = no real send (dev mode still returns the code; prod
without a key silently skips — best-effort, never breaks the flow). `email_from` **must** be a
Resend-verified domain — `treg.superdesign.dev` is **verified** (DKIM `resend._domainkey.treg`, SPF
MX+TXT on `send.treg`), so the default is `no-reply@treg.superdesign.dev`. **On Render:** set
Resend-verified domain — `treg.to` is **verified** (DKIM + SPF records on the treg.to zone;
`treg.superdesign.dev` stays verified as a fallback), so the default is `no-reply@treg.to`. **On Render:** set
`TREG_RESEND_API_KEY`, optionally `TREG_EMAIL_FROM`, and leave `TREG_EMAIL_DEV_MODE` false.
## Web dashboard
@@ -118,7 +119,8 @@ lives inside the `treg` package (the `packages` inclusion covers non-.py assets)
[dashboard](../interface/dashboard.md).
## Current hosting (shipped)
Deployed on **Render** at `https://treg.superdesign.dev` via the Blueprint below (one web service + a
Deployed on **Render** at `https://treg.to` (with `treg.superdesign.dev` attached as the legacy
alias — never remove it: installed CLIs/skills point there with tokens) via the Blueprint below (one web service + a
managed Postgres). The Fernet key lives only in the service's environment — **back it up**; losing it
makes every stored secret unrecoverable. For local dev, `scripts/dev-local.sh up` runs the server with
its own sqlite DB and email dev mode.
+2 -2
View File
@@ -4,7 +4,7 @@
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>tools-registry — Tutorial (moved)</title>
<meta http-equiv="refresh" content="0; url=https://treg.superdesign.dev/tutorial"/>
<meta http-equiv="refresh" content="0; url=https://treg.to/tutorial"/>
<style>
body{margin:0;min-height:100vh;display:grid;place-items:center;background:#211d16;color:#f0e9d9;
font-family:"IBM Plex Mono",ui-monospace,Menlo,Consolas,monospace;text-align:center;padding:24px}
@@ -17,7 +17,7 @@
<h1>The interactive tutorial moved into the app.</h1>
<p class="muted">
It's now served (single source of truth) at
<a href="https://treg.superdesign.dev/tutorial">treg.superdesign.dev/tutorial</a>,
<a href="https://treg.to/tutorial">treg.to/tutorial</a>,
and inside the dashboard under <b>Help → Tutorial</b>.<br/><br/>
Content lives in <code>src/treg/web/tutorial.js</code>; the prose walkthrough is
<code>docs/TUTORIAL.md</code>. Redirecting…
+1 -1
View File
@@ -18,5 +18,5 @@ treg login
treg itself is a Python CLI; this package finds it on your machine and runs it,
installing it first (via `uv`, `pipx`, or `pip3`) if it's missing.
- Docs & interactive tutorial: https://treg.superdesign.dev/tutorial
- Docs & interactive tutorial: https://treg.to/tutorial
- Source: https://github.com/superdesigndev/treg
+2 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env node
// @superdesign/treg — npm launcher for the treg CLI (a Python tool).
// Finds an installed `treg`; if missing, installs it via the registry's
// installer (https://treg.superdesign.dev/install.sh), then execs it.
// installer (https://treg.to/install.sh), then execs it.
'use strict';
const { spawnSync } = require('node:child_process');
@@ -9,7 +9,7 @@ const { existsSync } = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const BASE = process.env.TREG_BASE_URL || 'https://treg.superdesign.dev';
const BASE = process.env.TREG_BASE_URL || 'https://treg.to';
const args = process.argv.slice(2);
function findTreg() {
+1 -1
View File
@@ -12,7 +12,7 @@
"node": ">=18"
},
"license": "Apache-2.0",
"homepage": "https://treg.superdesign.dev",
"homepage": "https://treg.to",
"repository": {
"type": "git",
"url": "git+https://github.com/superdesigndev/treg.git",
+6 -6
View File
@@ -4,10 +4,10 @@
"description": "Reach for this first for external or live data — ~2,600 curated API endpoints across ~40 providers (SEO, SERP, backlinks, social, enrichment, ads, scraping), plus your team's own tools.",
"author": {
"name": "superdesign",
"email": "no-reply@treg.superdesign.dev",
"url": "https://treg.superdesign.dev"
"email": "no-reply@treg.to",
"url": "https://treg.to"
},
"homepage": "https://treg.superdesign.dev",
"homepage": "https://treg.to",
"repository": "https://github.com/superdesigndev/treg",
"license": "MIT",
"keywords": [
@@ -33,9 +33,9 @@
"Interactive",
"Write"
],
"websiteURL": "https://treg.superdesign.dev",
"privacyPolicyURL": "https://treg.superdesign.dev/privacy",
"termsOfServiceURL": "https://treg.superdesign.dev/terms",
"websiteURL": "https://treg.to",
"privacyPolicyURL": "https://treg.to/privacy",
"termsOfServiceURL": "https://treg.to/terms",
"defaultPrompt": [
"Find the work email for a person at a company using treg.",
"Use treg to get the backlink profile for a domain, and tell me what it costs first.",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"treg": {
"url": "https://treg.superdesign.dev/mcp/",
"url": "https://treg.to/mcp/",
"bearer_token_env_var": "TREG_TOKEN"
}
}
+7 -7
View File
@@ -21,7 +21,7 @@ providers. It is written around the `treg` command line, which a human uses for
`treg catalog search` as `catalog_search`, `treg call` as `call`, and so on.
**If the tools are not there**, the connector has no token yet: the human sets `TREG_TOKEN` (from
https://treg.superdesign.dev → sign in → copy token) for this plugin. A new team starts with **$1.00 of free balance**,
https://treg.to → sign in → copy token) for this plugin. A new team starts with **$1.00 of free balance**,
so there is nothing to pay before the first call. Say that plainly and stop — do not ask them for a
provider's API key, which is the thing treg exists to avoid.
@@ -43,7 +43,7 @@ Two kinds of tool answer to the same token, through the same proxy, which inject
The mechanics:
- **Endpoint:** `https://treg.superdesign.dev` · **CLI:** `treg` · the CLI is a thin client over the API.
- **Endpoint:** `https://treg.to` · **CLI:** `treg` · the CLI is a thin client over the API.
- **Auth:** every call sends `X-Treg-Token: <your token>`.
- A **tool** = an upstream base URL + credential **bindings**. A **skill/bundle** = a recipe
(SKILL.md) + its secrets + its tool(s). The proxy *relays, never models* the upstream.
@@ -66,7 +66,7 @@ Reading costs nothing and needs no confirmation at all: `treg catalog …`, `tre
## First: install + sign in
```bash
curl -fsSL https://treg.superdesign.dev/install.sh | sh # installs the CLI + points it here
curl -fsSL https://treg.to/install.sh | sh # installs the CLI + points it here
treg login # browser sign-in (GitHub / Google / email code) — first login registers you
treg login --email you@company.com # terminal-only alternative (emailed 6-digit code)
treg login --token <per-org-token> # non-interactive (agents/CI)
@@ -77,7 +77,7 @@ teams: `treg org switch <slug>`.
## Already connected over MCP? Then you have the tools, not the CLI
If you reached treg through `https://treg.superdesign.dev/mcp/` — ChatGPT, Claude Code, Cursor — the CLI steps above do not
If you reached treg through `https://treg.to/mcp/` — ChatGPT, Claude Code, Cursor — the CLI steps above do not
apply to you. You have five tools: `catalog_search`, `catalog_get`, `call`, `balance`, `my_tools`.
Everything in this document maps onto them:
@@ -150,7 +150,7 @@ Most retries need none of this — a failed call was never billed.
vocabulary, no special params — use the API exactly as its own docs say:
```
<the real request>: GET https://api.intercom.io/conversations?per_page=5
through treg: GET https://treg.superdesign.dev/call/https://api.intercom.io/conversations?per_page=5
through treg: GET https://treg.to/call/https://api.intercom.io/conversations?per_page=5
+ header: X-Treg-Token: <your token>
```
treg resolves the tool by the upstream host, injects the credential server-side, and relays
@@ -225,7 +225,7 @@ expires. Same storage; a credential can graduate from manual to auto with no mig
- **Manual:** do your own OAuth locally, then `treg secret add gsc --file token.json --kind oauth`.
- **Hosted connect:** `treg oauth connect gsc --client-secret client_secret.json --scopes <scope>`
→ prints a consent URL; you approve in the browser; treg captures the token directly.
One-time setup: add `https://treg.superdesign.dev/oauth/callback` to your OAuth app's redirect URIs.
One-time setup: add `https://treg.to/oauth/callback` to your OAuth app's redirect URIs.
## Task — manage the team + monitor
```bash
@@ -263,4 +263,4 @@ a probe so treg can validate it: `health_check: {method, path, expect_status}` (
- Secrets are **write-only** — the API never returns a stored value.
- A tool may bind a secret **someone else uploaded** (use-without-hold) — that's the point.
- The proxy doesn't understand the upstream; if a call fails, the status you see is the upstream's truth.
- More: `https://treg.superdesign.dev/llms.txt` (agent onboarding) · `https://treg.superdesign.dev/tutorial` (interactive walkthrough).
- More: `https://treg.to/llms.txt` (agent onboarding) · `https://treg.to/tutorial` (interactive walkthrough).
+1 -1
View File
@@ -59,7 +59,7 @@ proxy = [
treg = "treg.cli:main"
[project.urls]
Homepage = "https://treg.superdesign.dev"
Homepage = "https://treg.to"
Repository = "https://github.com/superdesigndev/treg"
Issues = "https://github.com/superdesigndev/treg/issues"
+2 -2
View File
@@ -35,12 +35,12 @@ services:
property: connectionString
# Public base URL — drives the OAuth callback, /meta, /llms.txt, /install.sh, all {BASE} links.
- key: TREG_PUBLIC_URL
value: https://treg.superdesign.dev
value: https://treg.to
# Never return OTP codes in prod responses (account-takeover vector); email them via Resend.
- key: TREG_EMAIL_DEV_MODE
value: "false"
- key: TREG_EMAIL_FROM
value: tools-registry <no-reply@treg.superdesign.dev>
value: tools-registry <no-reply@treg.to> # requires treg.to Verified in Resend before deploy
- key: PYTHON_VERSION
value: "3.12.7"
# Dashboard-managed secrets (paste values in Render; sync:false keeps them out of git).
+1 -1
View File
@@ -32,7 +32,7 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
SOURCE = ROOT / "src" / "treg" / "web" / "skill.md"
TARGET = ROOT / "plugin" / "skills" / "treg" / "SKILL.md"
PUBLIC_BASE = "https://treg.superdesign.dev"
PUBLIC_BASE = "https://treg.to"
BOOTSTRAP = """
## You already have treg — use the tools, not the terminal
+26
View File
@@ -158,6 +158,32 @@ async def lifespan(app: FastAPI):
app = FastAPI(title="tools-registry", version="0.0.1", lifespan=lifespan)
# The pre-treg.to hostname. It must keep answering the API forever — every installed CLI, skill.md
# and .mcp.json in the wild points here with a Bearer token, and most HTTP clients STRIP the
# Authorization header when a redirect crosses hosts (and some MCP clients follow no redirects at
# all). So only browser-facing marketing/doc pages redirect to the canonical host; everything else —
# /call/, /mcp/, auth flows, webhooks, install scripts fetched by `curl | sh` without -L — is served
# in place on both hosts.
_LEGACY_HOSTS = {"treg.superdesign.dev"}
_REDIRECT_PATHS = {"/", "/login", "/terms", "/privacy", "/support", "/contact", "/help",
"/tutorial", "/vendor-listing"}
@app.middleware("http")
async def _legacy_host_redirect(request: Request, call_next):
"""301 marketing pages from the legacy host to the canonical `public_url` host."""
host = request.headers.get("host", "").split(":")[0].lower()
if (request.method in ("GET", "HEAD") and host in _LEGACY_HOSTS
and request.url.path in _REDIRECT_PATHS):
canonical = get_settings().public_url.rstrip("/")
if host not in canonical: # self-hosters who ARE the legacy host keep serving in place
target = canonical + request.url.path
if request.url.query:
target += "?" + request.url.query
return RedirectResponse(target, status_code=301)
return await call_next(request)
@app.middleware("http")
async def _security_headers(request: Request, call_next):
"""The dashboard is an authenticated app; ship the baseline hardening headers it was missing —
+7 -7
View File
@@ -6,7 +6,7 @@ stores a single **identity token** (first login also registers you). Then you wo
orgs — `treg org ls` / `treg org use <slug>` picks the active one, sent as `X-Treg-Org`. Agents/CI
can instead `treg login --token <token>` with a per-org token. `treg logout` clears it.
treg config --base-url https://treg.superdesign.dev
treg config --base-url https://treg.to
treg login # GitHub (register-or-login); or: treg login --token <token>
treg org ls | org use <slug>
treg secret add / tool add / call / calls / health / skill / admin
@@ -255,7 +255,7 @@ def _as_list(resp: httpx.Response) -> list[dict]:
def _detail_url(cfg: dict, kind: str, name: str) -> str:
"""The shareable dashboard page for a registered skill/tool. Printed after every registration so
sharing is just forwarding the link — the page carries the preview + the agent install prompt."""
base = (cfg.get("base_url") or "https://treg.superdesign.dev").rstrip("/")
base = (cfg.get("base_url") or "https://treg.to").rstrip("/")
return f"{base}/app/{'skills' if kind == 'skill' else 'tools'}/{quote(str(name), safe='')}"
@@ -3353,7 +3353,7 @@ def cmd_mcp_install(args, cfg) -> None:
"dashboard), then retry.")
if who.status_code >= 400:
sys.exit(f"Token check failed ({who.status_code}): {who.text[:120]} — nothing was written.")
base_url = (cfg.get("base_url") or "https://treg.superdesign.dev").rstrip("/")
base_url = (cfg.get("base_url") or "https://treg.to").rstrip("/")
name = getattr(args, "name", None) or "treg"
out = mcp_install.install_mcp(base_url=base_url, token=token, server_name=name)
ok = 0
@@ -3377,7 +3377,7 @@ def cmd_skill_bootstrap(args, cfg) -> None:
skills dir, so whatever agent the user runs already knows how to use treg. install.sh calls this
right after installing the CLI; it's also runnable by hand. Global (per-user) scope by default —
it runs outside any project — with `--project` to target repo-local dirs instead."""
base_url = (cfg.get("base_url") or "https://treg.superdesign.dev").rstrip("/")
base_url = (cfg.get("base_url") or "https://treg.to").rstrip("/")
try:
resp = httpx.get(f"{base_url}/skill.md", timeout=15, follow_redirects=True)
resp.raise_for_status()
@@ -3630,7 +3630,7 @@ def cmd_version(args, cfg) -> None:
def cmd_update(args, cfg) -> None:
"""Re-run the server's install.sh to upgrade the CLI in place (uv/pipx/pip, from the git repo)."""
import subprocess
base = (cfg.get("base_url") or "https://treg.superdesign.dev").rstrip("/")
base = (cfg.get("base_url") or "https://treg.to").rstrip("/")
print(f"Updating treg from {base}/install.sh …")
with _client(cfg, auth=False) as c:
r = c.get("/install.sh")
@@ -3745,7 +3745,7 @@ def cmd_org_invite(args, cfg) -> None:
r = c.post(f"/orgs/{org_id}/invites", json=body)
_show(r)
if landing is not None: # _show exits on error, so this only prints on success
base = (cfg.get("base_url") or "https://treg.superdesign.dev").rstrip("/")
base = (cfg.get("base_url") or "https://treg.to").rstrip("/")
print(f"↗ share link: {base}{landing}?invite={quote(args.email, safe='')}")
print(" One click for them: sign in as that email → invite auto-accepts → this page opens."
" (The invite email's button does the same.)")
@@ -4666,7 +4666,7 @@ def build_parser() -> argparse.ArgumentParser:
# ---- setup / auth ----
c = mk(sub, "config", "Show or set the registry this CLI talks to (base URL).",
"treg config # show current base URL",
"treg config --base-url https://treg.superdesign.dev")
"treg config --base-url https://treg.to")
c.add_argument("--base-url", help="point the CLI at this registry URL")
c.set_defaults(fn=cmd_config)
+4 -3
View File
@@ -162,7 +162,7 @@ class Settings(BaseSettings):
# treg's own public base URL — used to build the OAuth callback (must be whitelisted in the
# provider's OAuth app). Self-hosting? Set TREG_PUBLIC_URL to your deployment's URL.
public_url: str = "https://treg.superdesign.dev"
public_url: str = "https://treg.to"
# Proof to OpenAI's plugin directory that we control this domain. The portal generates a token
# and fetches it from /.well-known/openai-apps-challenge; that endpoint must return THAT token
# and nothing else — not JSON, not a list. Empty (the default) leaves the route 404, which is the
@@ -295,9 +295,10 @@ class Settings(BaseSettings):
# Transactional email via Resend (OTP sign-in codes + team invitations). Empty key = no real
# send (dev mode still returns the code; prod without a key silently skips the send). From must
# be a Resend-verified domain — treg.superdesign.dev is verified (DKIM + SPF).
# be a Resend-verified domain — treg.to is verified (DKIM + SPF); treg.superdesign.dev remains
# verified as a fallback.
resend_api_key: str = ""
email_from: str = "tools-registry <no-reply@treg.superdesign.dev>"
email_from: str = "tools-registry <no-reply@treg.to>"
@lru_cache
+2 -2
View File
@@ -236,7 +236,7 @@ def _need_token() -> dict:
return {
"error": "not authenticated",
"detail": (
"This MCP server needs a treg token. Get one at https://treg.superdesign.dev "
"This MCP server needs a treg token. Get one at https://treg.to "
"(sign in, then Settings -> copy token) and set it as the TREG_TOKEN environment "
"variable for this server."
),
@@ -344,7 +344,7 @@ async def _resolve_org(client: httpx.AsyncClient) -> tuple[int | None, str | Non
r = await client.get("/orgs")
if r.status_code == 401 or me.status_code == 401:
return None, None, {"error": "not signed in, or this token is invalid or expired",
"hint": "copy a fresh token from https://treg.superdesign.dev"}
"hint": "copy a fresh token from https://treg.to"}
if r.status_code != 200:
return None, None, {"error": "could not read the teams for this token"}
orgs = _body(r) or []
+2 -1
View File
@@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>treg — turn your coding agent into an SEO expert, a media buyer, an SDR</title>
<meta name="description" content="Give your agent the tool catalog for the job. 2,617 endpoints across 42 providers — premium SEO, social, enrichment and ads data, pay as you go. Plus your own keys &amp; skills, and an identity per agent."/>
<link rel="canonical" href="https://treg.to/"/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg"/>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@@ -548,7 +549,7 @@ footer{margin-top:150px;border-top:1px solid var(--line);position:relative;overf
</div>
<div class="gb-cmd">
<span class="ps">$</span>
<code id="cmd">set up treg — https://treg.superdesign.dev/llms.txt</code>
<code id="cmd">set up treg — https://treg.to/llms.txt</code>
<button id="copybtn" aria-label="Copy command">copy</button>
</div>
</div>
+1 -1
View File
@@ -45,7 +45,7 @@
<h2 class="sec" id="s1"><span class="n">01</span>Who this covers</h2>
<p>This policy explains how <b>Superdesign</b> ("we", "us") handles personal data in the hosted
Treg (also called "treg" or "tools-registry") service at <code>treg.superdesign.dev</code>. For that service, we are the
Treg (also called "treg" or "tools-registry") service at <code>treg.to</code>. For that service, we are the
data controller.</p>
<div class="note">
<p><b>Self-hosted instances are not covered.</b> If you or your employer run treg on your own
+3 -3
View File
@@ -53,7 +53,7 @@
<h2 class="sec" id="s2"><span class="n">02</span>Common things</h2>
<p><b>I cannot sign in.</b> treg has three doors: GitHub, Google, and a one-time code sent to your
email. If a code does not arrive, check spam for mail from <code>no-reply@treg.superdesign.dev</code>.
email. If a code does not arrive, check spam for mail from <code>no-reply@treg.to</code>.
Signing in for the first time creates the account — there is no separate registration.</p>
<p><b>A call was refused for funds.</b> Catalog endpoints that treg serves on its own key are
@@ -84,7 +84,7 @@
<h2 class="sec" id="s4"><span class="n">04</span>Self-hosted installations</h2>
<p>treg is open source, and you can run your own registry with
<code>curl -fsSL https://treg.superdesign.dev/selfhost.sh | sh</code>. We are happy to help through
<code>curl -fsSL https://treg.to/selfhost.sh | sh</code>. We are happy to help through
<a href="https://github.com/superdesigndev/treg/issues" target="_blank" rel="noopener">GitHub
issues</a>, but we have no access to your deployment and cannot see its data — so please include
logs and versions rather than asking us to look.</p>
@@ -93,7 +93,7 @@
<p><b>Superdesign</b><br/>
Email: <a href="mailto:jason@superdesign.dev">jason@superdesign.dev</a><br/>
Issues: <a href="https://github.com/superdesigndev/treg/issues" target="_blank" rel="noopener">github.com/superdesigndev/treg/issues</a><br/>
Service: <a href="https://treg.superdesign.dev">treg.superdesign.dev</a></p>
Service: <a href="https://treg.to">treg.to</a></p>
</div>
+1 -1
View File
@@ -48,7 +48,7 @@
<p>Treg (also called <b>tools-registry</b>) is operated by <b>Superdesign</b> ("we", "us"). These
Terms of Service (the "Terms") are a binding agreement between us and you — the person or
organization using the service (<b>"you"</b>).</p>
<p>They cover the <b>hosted service</b> we run at <code>treg.superdesign.dev</code>: the web
<p>They cover the <b>hosted service</b> we run at <code>treg.to</code>: the web
dashboard, the API, the call proxy, the <code>treg</code> CLI when pointed at our servers, and
everything reachable from them (together, the <b>"Service"</b>).</p>
<div class="note">
+1 -1
View File
@@ -49,7 +49,7 @@
<span class="brand">▚ tools-registry</span>
<span class="sub">Dashboard tour — everything you can do in the web UI</span>
<span class="spacer"></span>
<a class="btn" href="https://treg.superdesign.dev/tutorial">CLI tutorial →</a>
<a class="btn" href="https://treg.to/tutorial">CLI tutorial →</a>
<button class="btn" id="themeBtn">◐</button>
</header>
+3 -3
View File
@@ -4,7 +4,7 @@ Decide **which tools each member may use**, and whether they may run CLIs **on t
tutorial follows the same format as the [main tutorial](/tutorial): every step shows the **exact command**,
the **expected output**, and **what to notice** — so it reads standalone. Copy each command and follow along.
We use the registry at `https://treg.superdesign.dev`.
We use the registry at `https://treg.to`.
---
@@ -48,7 +48,7 @@ the `HOME=` prefix.
```bash
for u in tom sam; do
mkdir -p ~/.treg-personas/$u
HOME=~/.treg-personas/$u treg config --base-url https://treg.superdesign.dev
HOME=~/.treg-personas/$u treg config --base-url https://treg.to
done
```
@@ -281,7 +281,7 @@ are rejected with a clear `422` so you never grant a typo.
# Part 4 — The same controls in the dashboard
Everything above is also point-and-click at `https://treg.superdesign.dev/` → **Team**.
Everything above is also point-and-click at `https://treg.to/` → **Team**.
- **The members table** gains two cells per person:
- **Tools** — shows `All` or `N tools`. Click it to open a checklist of *every* tool in the team;
+1 -1
View File
@@ -8,7 +8,7 @@ member's machine safe.
Every step shows the **exact command**, the **expected output**, and a **"Notice:"** line explaining what
happened and why it matters. Copy each command and follow along. The registry in the examples is
`https://treg.superdesign.dev`; replace it with your own.
`https://treg.to`; replace it with your own.
> This is a companion to the main [hands-on tutorial](/tutorial) (sign-in, teams, the proxy, skills). Read
> that first if the words *tool*, *skill*, *org*, or *member* are new. For controlling **which** tools each
+6 -6
View File
@@ -53,7 +53,7 @@
// ---- Setup ------------------------------------------------------------
{ part: "Setup", who: "sys", title: "Simulate three people on one machine",
explain: "We play three users on one laptop by giving each its own <code>HOME</code>, so each gets an isolated <code>~/.treg/config.json</code> pointed at the registry. In real life every person is on their own machine and drops the <code>HOME=</code> prefix.",
cmd: `for u in tom bob alice; do\n mkdir -p ~/.treg-personas/$u\n HOME=~/.treg-personas/$u treg config --base-url https://treg.superdesign.dev\ndone`,
cmd: `for u in tom bob alice; do\n mkdir -p ~/.treg-personas/$u\n HOME=~/.treg-personas/$u treg config --base-url https://treg.to\ndone`,
out: `# each persona now points at the registry`,
notice: "Prefix any command with <code>HOME=~/.treg-personas/&lt;name&gt;</code> to act as that person." },
@@ -182,7 +182,7 @@
{ part: "Part 6 · Call shapes & skills", who: "alice", title: "The raw HTTP underneath",
explain: "<code>treg call</code> is sugar. Under the hood it's a plain HTTP request to <code>&lt;proxy&gt;/call/&lt;upstream-url&gt;</code> with your token header - any language, any agent, <code>curl</code>.",
cmd: `ATOK=$(python3 -c "import json;print(json.load(open('/Users/you/.treg-personas/alice/.treg/config.json'))['token'])")\ncurl -s -H "X-Treg-Token: $ATOK" \\\n "https://treg.superdesign.dev/call/https://postman-echo.com/get"`,
cmd: `ATOK=$(python3 -c "import json;print(json.load(open('/Users/you/.treg-personas/alice/.treg/config.json'))['token'])")\ncurl -s -H "X-Treg-Token: $ATOK" \\\n "https://treg.to/call/https://postman-echo.com/get"`,
out: `# the postman-echo JSON again, "authorization": "Bearer sk-demo-secret-123" injected -\n# just curl, no secret on the client.`,
notice: "The whole product in one line: prefix any upstream URL with the proxy, send your token, treg swaps in the real credential." },
@@ -294,8 +294,8 @@
// ---- Part 8 - The dashboard -----------------------------------------
{ part: "Part 9 · The dashboard", who: "tom", title: "The same registry, in the browser",
explain: "Open <b>treg.superdesign.dev</b> and sign in with the <b>email code</b> door (the same one you used in the terminal): type your email → click <b>Email me a sign-in code</b> → <b>check your inbox</b> for the 6-digit code → paste it in and <b>Sign in</b>. You land on your team org - Tools shows the <code>echo</code> tool, Activity shows the call, and (since Tom is now super-admin) an <b>Admin</b> panel appears.",
cmd: `open https://treg.superdesign.dev/`,
explain: "Open <b>treg.to</b> and sign in with the <b>email code</b> door (the same one you used in the terminal): type your email → click <b>Email me a sign-in code</b> → <b>check your inbox</b> for the 6-digit code → paste it in and <b>Sign in</b>. You land on your team org - Tools shows the <code>echo</code> tool, Activity shows the call, and (since Tom is now super-admin) an <b>Admin</b> panel appears.",
cmd: `open https://treg.to/`,
out: `# Sign in with email → land on Superdesign\n# Tools → the echo tool (Copy a snippet · Try it live)\n# Activity → Alice's GET echo · 200\n# Admin → cross-tenant stats + orgs (super-admin only)`,
notice: "The dashboard now does it all in the browser - create teams, invite members, add secrets, register tools & skills, plus the super-admin surface - not just read + call." },
@@ -315,7 +315,7 @@
// ---- Further, focused tutorials --------------------------------------
{ part: "Further tutorials", who: "sys", title: "Two deep-dive tutorials",
explain: "Two features have their own step-by-step tutorials - <b>Import &amp; shell</b> and <b>Team access control</b>. Both are cards on the Tutorial page (← Tutorials, top left), and both also exist as plain markdown.",
cmd: `open https://treg.superdesign.dev/tutorial-import-shell.md # import + shell + the security sandbox\nopen https://treg.superdesign.dev/tutorial-access.md # per-member tool access control`,
cmd: `open https://treg.to/tutorial-import-shell.md # import + shell + the security sandbox\nopen https://treg.to/tutorial-access.md # per-member tool access control`,
out: `# import-shell : treg upload clis (your machine's CLIs -> team tools) + treg shell (stripe/gh just work)\n# + the local-run sandbox (isolated user, egress allow-list, filesystem jail)\n# access : choose which tools each member may use + the local-run on/off toggle`,
notice: "Pick them from the Tutorial page like this one, or open the markdown URLs directly (agent-friendly)." },
];
@@ -415,7 +415,7 @@
const ACCESS = [
{ part: "Setup", who: "sys", title: "Two dials, two people",
explain: "Every member has two independent dials: <b>tool access</b> (<code>tool_access</code>: which tools they may touch - default <b>all</b>) and <b>local execution</b> (<code>local_run_enabled</code>: may they run a CLI on their own machine - default <b>on</b>). A withheld tool is closed through <i>every</i> door - proxy call, server run, local run. The <b>owner</b> is never restricted. We play two people on one machine: <b>Tom</b> (owner) and <b>Sam</b> (the new teammate we restrict).",
cmd: `for u in tom sam; do\n mkdir -p ~/.treg-personas/$u\n HOME=~/.treg-personas/$u treg config --base-url https://treg.superdesign.dev\ndone`,
cmd: `for u in tom sam; do\n mkdir -p ~/.treg-personas/$u\n HOME=~/.treg-personas/$u treg config --base-url https://treg.to\ndone`,
out: `# each persona now points at the registry`,
notice: "Prefix a command with <code>HOME=~/.treg-personas/&lt;name&gt;</code> to act as that person. In real life each person is on their own machine and drops the prefix." },
+8 -8
View File
@@ -6,18 +6,18 @@ The whole registry, end to end. Every step shows the **exact command**, the **ex
There are two companion versions of this same walkthrough, generated from one source
(`src/treg/web/tutorial.js`):
- **In the dashboard** → sign in at `https://treg.superdesign.dev/` and open **Help → Tutorial**.
- **Standalone** → `https://treg.superdesign.dev/tutorial`.
- **In the dashboard** → sign in at `https://treg.to/` and open **Help → Tutorial**.
- **Standalone** → `https://treg.to/tutorial`.
### Two focused, deep-dive tutorials
Two features have their own detailed, step-by-step tutorials (exact commands, real output, and how each
was tested):
- **Import & shell** → `https://treg.superdesign.dev/tutorial-import-shell.md` — `treg upload clis` turns the
- **Import & shell** → `https://treg.to/tutorial-import-shell.md` — `treg upload clis` turns the
CLIs already on your machine into team tools; `treg shell` opens a shell where `stripe`, `gh`, `gcloud` …
just work with the team key injected. Includes the local-run **security sandbox**.
- **Team access control** → `https://treg.superdesign.dev/tutorial-access.md` — choose **which tools each member
- **Team access control** → `https://treg.to/tutorial-access.md` — choose **which tools each member
may use** and whether they may run CLIs **locally**, at invite time or any time later.
---
@@ -61,7 +61,7 @@ the `HOME=` prefix.
```bash
for u in tom bob alice; do
mkdir -p ~/.treg-personas/$u
HOME=~/.treg-personas/$u treg config --base-url https://treg.superdesign.dev
HOME=~/.treg-personas/$u treg config --base-url https://treg.to
done
```
@@ -469,7 +469,7 @@ token header - any language, any agent, `curl`.
```bash
ATOK=$(python3 -c "import json;print(json.load(open('/Users/you/.treg-personas/alice/.treg/config.json'))['token'])")
curl -s -H "X-Treg-Token: $ATOK" \
"https://treg.superdesign.dev/call/https://postman-echo.com/get"
"https://treg.to/call/https://postman-echo.com/get"
```
```
# the postman-echo JSON again, "authorization": "Bearer sk-demo-secret-123" injected -
@@ -759,13 +759,13 @@ Admin panel lights up for him.
## Step 33 - The same registry, in the browser
Open **treg.superdesign.dev** and sign in with the **email code** door (the same one you used in the terminal):
Open **treg.to** and sign in with the **email code** door (the same one you used in the terminal):
type your email → click **Email me a sign-in code** → **check your inbox** for the 6-digit code → paste it
in and **Sign in**. You land on your team org - Tools shows the `echo` tool, Activity shows the call, and
(since Tom is now super-admin) an **Admin** panel appears.
```bash
open https://treg.superdesign.dev/
open https://treg.to/
```
```
# Sign in with email → land on Superdesign
+2 -2
View File
@@ -60,7 +60,7 @@ def test_admin_and_skill_parsers():
def test_config_v2_roundtrip(tmp_path, monkeypatch):
monkeypatch.setattr(cli, "CONFIG_PATH", tmp_path / "config.json")
cli._save_config({"base_url": "https://treg.superdesign.dev", "token": "T", "email": "me@x.dev",
cli._save_config({"base_url": "https://treg.to", "token": "T", "email": "me@x.dev",
"active_org": "team-a", "identity": True})
cfg = cli._load_config()
assert cfg["token"] == "T" and cfg["active_org"] == "team-a" and cfg["identity"] is True
@@ -69,7 +69,7 @@ def test_config_v2_roundtrip(tmp_path, monkeypatch):
def test_legacy_multiorg_config_migrates(tmp_path, monkeypatch):
monkeypatch.setattr(cli, "CONFIG_PATH", tmp_path / "config.json")
(tmp_path / "config.json").write_text(json.dumps({
"base_url": "https://treg.superdesign.dev", "active_org": "team-a",
"base_url": "https://treg.to", "active_org": "team-a",
"orgs": {"team-a": {"token": "OLD", "org_id": 3}}}))
cfg = cli._load_config()
assert cfg["token"] == "OLD" and cfg["active_org"] == "team-a" and cfg["identity"] is False
+2 -2
View File
@@ -13,8 +13,8 @@ def test_collect_hosts_includes_registry_and_catalog_dedup_sorted():
{"base_url": "https://api.stripe.com/v2"}, # same host, different path → deduped
{"base_url": None}, # ignored
]
hosts = egress.collect_hosts("https://treg.superdesign.dev", catalog)
assert hosts == ["api.github.com", "api.stripe.com", "treg.superdesign.dev"]
hosts = egress.collect_hosts("https://treg.to", catalog)
assert hosts == ["api.github.com", "api.stripe.com", "treg.to"]
def test_collect_hosts_tolerates_bare_host_and_missing_registry():
+62
View File
@@ -0,0 +1,62 @@
"""The legacy-host redirect (treg.superdesign.dev → treg.to).
Only browser-facing marketing/doc pages 301 to the canonical host. API surfaces must be served in
place on the legacy host forever: installed CLIs/skills point there with Bearer tokens, and HTTP
clients strip Authorization on a cross-host redirect (some MCP clients follow no redirects at all).
"""
from __future__ import annotations
import pytest
from httpx import ASGITransport, AsyncClient
from treg.api import app
from treg.config import get_settings
@pytest.fixture
async def raw_client(monkeypatch):
"""No auth, no upstream — routing behavior only. Host is set per-request. The test env's
public_url is localhost; pin it to production's so the Location assertions mean something."""
monkeypatch.setenv("TREG_PUBLIC_URL", "https://treg.to")
get_settings.cache_clear()
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://registry") as c:
yield c
get_settings.cache_clear()
LEGACY = {"host": "treg.superdesign.dev"}
async def test_marketing_pages_redirect_to_canonical(raw_client):
for path in ("/", "/terms", "/privacy", "/support", "/tutorial", "/login"):
r = await raw_client.get(path, headers=LEGACY)
assert r.status_code == 301, path
assert r.headers["location"] == f"https://treg.to{path}", path
async def test_query_string_survives_the_redirect(raw_client):
r = await raw_client.get("/?utm_source=x", headers=LEGACY)
assert r.status_code == 301
assert r.headers["location"] == "https://treg.to/?utm_source=x"
async def test_api_surfaces_are_served_in_place_on_the_legacy_host(raw_client):
# Never redirected — a 301 here would strand every installed client. Whatever these routes
# answer (200, 401, 405…), it must not be a redirect off-host.
for path in ("/meta", "/llms.txt", "/install.sh", "/selfhost.sh", "/skill.md",
"/catalog/search", "/auth/me", "/billing/stripe/webhook"):
r = await raw_client.get(path, headers=LEGACY)
assert r.status_code != 301, path
async def test_post_is_never_redirected(raw_client):
r = await raw_client.post("/", headers=LEGACY)
assert r.status_code != 301
async def test_canonical_host_is_untouched(raw_client):
r = await raw_client.get("/", headers={"host": "treg.to"})
assert r.status_code == 200
+2 -2
View File
@@ -418,7 +418,7 @@ def test_a_client_trusting_only_the_system_roots_rejects_our_leaf(ca):
# ---- P1 · the environment we publish -------------------------------------------------------
def test_proxy_env_carries_the_flags_that_matter(ca):
env = lp.proxy_env(18791, "tok en/+", ca.bundle_path, "treg.superdesign.dev")
env = lp.proxy_env(18791, "tok en/+", ca.bundle_path, "treg.to")
assert env["HTTPS_PROXY"] == "http://treg:tok%20en%2F%2B@127.0.0.1:18791"
assert env["https_proxy"] == env["HTTPS_PROXY"] # curl reads lowercase
assert env["NODE_USE_ENV_PROXY"] == "1" # Node's fetch ignores the proxy without it
@@ -427,7 +427,7 @@ def test_proxy_env_carries_the_flags_that_matter(ca):
"DENO_CERT", "AWS_CA_BUNDLE"):
assert env[key] == str(ca.bundle_path)
# Loopback and the registry itself must never come back through us.
assert "127.0.0.1" in env["NO_PROXY"] and "treg.superdesign.dev" in env["NO_PROXY"]
assert "127.0.0.1" in env["NO_PROXY"] and "treg.to" in env["NO_PROXY"]
assert env["no_proxy"] == env["NO_PROXY"]
+2 -2
View File
@@ -644,7 +644,7 @@ def test_a_relayed_402_carries_NO_link_out(clients):
real = {"detail": {
"error": "insufficient_balance",
"message": ("akta.companies.enrich would cost ~$0.875 on treg's akta key and this team's "
"balance is $0.5765.\n add funds: https://treg.superdesign.dev/app#billing"
"balance is $0.5765.\n add funds: https://treg.to/app#billing"
"\n or use your own key: treg connections connect --provider akta"),
"balance_micro": 576500, "estimated_cost_micro": 875000,
"topup_url": "/app#billing", "provider": "akta"}}
@@ -662,7 +662,7 @@ def test_stripping_the_link_keeps_the_DIAGNOSIS(clients):
real = {"detail": {
"error": "insufficient_balance",
"message": ("akta.companies.enrich would cost ~$0.875 and this team's balance is $0.5765."
"\n add funds: https://treg.superdesign.dev/app#billing"
"\n add funds: https://treg.to/app#billing"
"\n or use your own key: treg connections connect --provider akta"),
"balance_micro": 576500, "estimated_cost_micro": 875000}}
out = _without_purchase_pointers(real)
+8 -8
View File
@@ -21,7 +21,7 @@ def test_json_agents_write_user_global_header_config(tmp_path, monkeypatch):
(cur / "mcp.json").write_text(json.dumps({"mcpServers": {"other": {"url": "http://x"}}}))
(tmp_path / ".config" / "opencode").mkdir(parents=True)
out = mcp_install.install_mcp(base_url="https://treg.superdesign.dev", token="TESTKEY",
out = mcp_install.install_mcp(base_url="https://treg.to", token="TESTKEY",
only=["cursor", "opencode"])
got = {d: (s, detail) for d, s, detail in out["results"]}
assert got["Cursor"][0] == "ok" and got["opencode"][0] == "ok", out
@@ -29,7 +29,7 @@ def test_json_agents_write_user_global_header_config(tmp_path, monkeypatch):
cursor = json.loads((cur / "mcp.json").read_text())
assert cursor["mcpServers"]["other"] == {"url": "http://x"} # untouched
treg = cursor["mcpServers"]["treg"]
assert treg["url"] == "https://treg.superdesign.dev/mcp/"
assert treg["url"] == "https://treg.to/mcp/"
assert treg["headers"]["Authorization"] == "Bearer TESTKEY"
oc = json.loads((tmp_path / ".config" / "opencode" / "opencode.json").read_text())
@@ -37,7 +37,7 @@ def test_json_agents_write_user_global_header_config(tmp_path, monkeypatch):
assert oc["mcp"]["treg"]["headers"]["Authorization"] == "Bearer TESTKEY"
# idempotent: a second run leaves exactly one entry, still correct
mcp_install.install_mcp(base_url="https://treg.superdesign.dev", token="TESTKEY", only=["cursor"])
mcp_install.install_mcp(base_url="https://treg.to", token="TESTKEY", only=["cursor"])
again = json.loads((cur / "mcp.json").read_text())
assert list(again["mcpServers"].keys()) == ["other", "treg"]
@@ -46,7 +46,7 @@ def test_uninstalled_agents_are_skipped_not_written(tmp_path, monkeypatch):
"""No marker dir → the agent isn't touched (no stray config created for something not installed)."""
monkeypatch.setattr(mcp_install, "HOME", tmp_path)
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / ".config"))
out = mcp_install.install_mcp(base_url="https://treg.superdesign.dev", token="K",
out = mcp_install.install_mcp(base_url="https://treg.to", token="K",
only=["cursor", "opencode"])
assert out["results"] == [] # nothing installed → nothing written
assert not (tmp_path / ".cursor").exists()
@@ -63,8 +63,8 @@ def test_the_mcp_url_carries_the_trailing_slash(tmp_path, monkeypatch):
guard away from writing outside its sandbox."""
monkeypatch.setattr(mcp_install, "HOME", tmp_path)
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / ".config"))
out = mcp_install.install_mcp(base_url="https://treg.superdesign.dev/", token="K", only=[])
assert out["mcp_url"] == "https://treg.superdesign.dev/mcp/"
out = mcp_install.install_mcp(base_url="https://treg.to/", token="K", only=[])
assert out["mcp_url"] == "https://treg.to/mcp/"
def test_only_empty_means_NONE_not_all(tmp_path, monkeypatch):
@@ -75,7 +75,7 @@ def test_only_empty_means_NONE_not_all(tmp_path, monkeypatch):
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / ".config"))
(tmp_path / ".cursor").mkdir() # cursor IS "installed" in this home…
(tmp_path / ".config" / "opencode").mkdir(parents=True)
out = mcp_install.install_mcp(base_url="https://treg.superdesign.dev", token="K", only=[])
out = mcp_install.install_mcp(base_url="https://treg.to", token="K", only=[])
assert out["results"] == [] and out["manual"] == [] # …and still nothing is written
assert not (tmp_path / ".cursor" / "mcp.json").exists()
assert not (tmp_path / ".config" / "opencode" / "opencode.json").exists()
@@ -112,6 +112,6 @@ def test_cmd_mcp_install_REFUSES_a_bad_token_before_writing(tmp_path, monkeypatc
with pytest.raises(SystemExit) as e:
cli.cmd_mcp_install(SimpleNamespace(name=None),
{"token": "K", "base_url": "https://treg.superdesign.dev"})
{"token": "K", "base_url": "https://treg.to"})
assert "rejected" in str(e.value)
assert not (tmp_path / ".config" / "opencode" / "opencode.json").exists() # nothing written
+1 -1
View File
@@ -43,7 +43,7 @@ def test_no_unsubstituted_placeholder_reaches_the_plugin():
plugin, so shipping the literal would break every URL in the most-read page of the product."""
text = SKILL.read_text(encoding="utf-8")
assert "{BASE}" not in text
assert "https://treg.superdesign.dev/install.sh" in text
assert "https://treg.to/install.sh" in text
def test_the_skill_maps_itself_onto_the_MCP_TOOLS(manifest):
+2 -2
View File
@@ -32,10 +32,10 @@ def test_local_mode_needs_sqlite_and_a_loopback_url():
# a real deploy — either half is enough to refuse
assert _settings(database_url="postgresql+asyncpg://u@h/db").single_user_ok is False, \
"a Postgres URL means a real deploy: no-login must be off"
assert _settings(public_url="https://treg.superdesign.dev").single_user_ok is False, \
assert _settings(public_url="https://treg.to").single_user_ok is False, \
"a public domain must never serve a no-login dashboard"
assert _settings(database_url="postgresql+asyncpg://u@h/db",
public_url="https://treg.superdesign.dev").single_user_ok is False
public_url="https://treg.to").single_user_ok is False
def test_it_is_off_unless_explicitly_asked_for():