164 Commits
Author SHA1 Message Date
Jason ZhouandClaude Fable 5 8759aeff90 feat: request-a-tool — a 'the catalog doesn't have X' report, filed from web, CLI or MCP
New ToolRequest table + open, per-IP rate-limited POST /tool-requests. Identity
is attribution, never a gate: the usual filer is an agent that just got zero
search results and holds no token. Discovery lives where the gap is felt — the
zero-result search response in the API, the CLI no-match message (+ new
`treg catalog request` verb), and a new MCP catalog_request tool (forwarding
X-Forwarded-For so the in-process relay doesn't collapse the rate bucket).
Web: Request-a-tool button + modal on the catalog page, pre-filled from the
live search box.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 16:44:56 +10:00
Jason ZhouandClaude Fable 5 a873b29306 release: 0.10.0 — treg.to is the default everywhere a fresh install looks
New installs (pip/brew/npm/plugin) now default to https://treg.to; every existing install
keeps working against treg.superdesign.dev, which stays served in full forever.
Also ships the refused_by audit trail (#104).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 15:22:39 +10:00
Jason ZhouandClaude Fable 5 8ca54c0c6f 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>
2026-08-13 11:56:20 +10:00
Jason Zhou f0f908946b Merge branch 'main' into feat/x-oauth-metering 2026-08-13 10:16:34 +10:00
Jason ZhouandClaude Fable 5 58a0d1c000 feat(billing): meter X OAuth calls — the upstream bill is ours, so the ledger sees it
X dropped its plan tiers for prepaid pay-per-use billed to the APP OWNER
(docs.x.com/x-api/getting-started/pricing): every call on a registry X
connect spends treg's credits — reads per resource returned (posts $0.005,
users $0.010, own-account $0.001), writes per request ($0.015, $0.20 when
the text carries a URL). Until now those calls rode the "own tools are
never metered" rule and billed nobody.

- x.yaml repriced from the official page; reads are per_result and SETTLE
  BY COUNTING data[] — asked for 100, got 7, charged for 7; empty page $0
- OAuthProvider.platform_billed + default rates on X for the uncatalogued
  long tail; URL-passthrough calls match back to the catalog by path
  template so the direct URL is never a discount door
- _billed_marketplace routes flagged calls through the existing tier-4
  reserve→relay→settle path (ledger meta tier: oauth); BYO connects
  (secret.provider == "") are never metered — their upstream bill is theirs
- kill switch TREG_OAUTH_BILLED_PROVIDERS, default OFF: prod stays free
  until the deploy opts in; daily cap, demo refusal and an actionable 402
  ("bring your own X developer app") fence the rest
- price shown BEFORE consent (listing metered+billed_rates, connect modal),
  in the access dry-run and the CLI; llms.txt/skill.md carve the X
  exception out of the never-metered promise (plugin regenerated)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 21:43:07 +10:00
UncleCode 6518f091da release: 0.9.0 — idempotent calls reach pip/brew, and PyPI's links stop pointing at a dead repo
Two reasons, neither of them the CLI: this release ships an IDENTICAL command-line tool. Nothing in
cli.py or its siblings changed, so a `pip`/`brew` user gains nothing directly. Cutting it anyway
because:

  * **Self-hosters get idempotent calls.** Anyone running `pip install "tools-registry[server]"` has
    no `Idempotency-Key` support until a version ships. Hosted users already have it (deployed at
    04a1f2c); this is the only route for everyone else.
  * **PyPI's project page links to a repo that no longer exists.** The rename to superdesigndev/treg
    changed the URLs in pyproject, and the published 0.8.0 metadata still points at
    superdesigndev/tools-registry. Only a republish fixes a broken link on the package page.

Verified before publishing, per the runbook:

  * `treg --version` → 0.9.0 from a clean venv on the wheel alone
  * base install stays LIGHT: 12 deps, `import fastapi` fails — no server stack leaked into the CLI
  * `twine check` PASSED on both artifacts
  * the sdist contains no .env, no database, no key material (1931 files)
  * gitleaks on the PACKAGED content: clean. It reported 11 on the first pass because I ran it
    without the repo config; with .gitleaks.toml applied — which is what CI uses — none. All 11 were
    checked individually anyway: 8 are opaque provider ids in catalog/examples (entropy rules are
    scoped to that directory, provider-prefixed rules still apply), 1 is the sandbox demo
    placeholder, 2 are the redaction-test fixture.

plugin.json tracked in lockstep, as 0.8.0 did.
2026-08-12 17:23:30 +08:00
UncleCode 557ba910ca docs: the idempotency key, on every surface that describes calling treg
Six files. The line that appears in all of them is the one that costs something when a caller gets it
wrong: repeating a search to see what changed is NEW work, not a retry, and reusing the key there
returns yesterday's answer.

  * llms.txt — the agent-facing one: when to use it, when NOT to, the curl, the response headers.
  * skill.md — short guidance and the same warning; plugin/skills/treg/SKILL.md regenerated from it.
  * interface/api.md — the header, both refusals (422 reuse, 409 in flight), the MCP equivalent.
  * architecture/money.md — the reasoning: why remembering the charge is not enough (we would still
    make the second upstream call and just absorb the cost), the caller scoping, what is stored and
    for how long, the pending row as the lock, and why a failed call must give its label back.
  * architecture/mcp-oauth.md — the `idempotency_key` argument, and why it is NOT derived server-side.

Two things worth recording.

**The drift check had never known about mcp.py.** It reads MAP.md, not the fragment frontmatter, and
I added the mcp-oauth.md fragment without adding the map entry — so the entire MCP subsystem was
invisible to the pre-push check whose only job is catching stale docs. Added in both directions, plus
api.py → money.md which was also missing.

**Two of these edits silently did not apply on the first attempt** (money.md, mcp-oauth.md) because
Jason had changed those headings. Caught by checking `git status` and grepping the result rather than
trusting the script's own "done" output. Worth remembering: a string replace that matches nothing is
indistinguishable from success unless you look.

1327 pass.
2026-08-12 16:03:24 +08:00
Jason ZhouandClaude Fable 5 4eccbfdd37 chore: repo renamed to superdesigndev/treg — update all self-references
GitHub redirects the old slug, but every URL we publish (pyproject,
npm package, plugin manifest, issue templates, web pages, llms.txt)
now says the real name. PyPI package name stays tools-registry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 20:54:30 +10:00
Jason ZhouandClaude Fable 5 6a1b738bd5 copy: make treg the reflexive first choice for external/live data
An agent given both treg and a competitor MCP picked the competitor for a
TikTok-trending lookup — and said why: the competitor's description opens
with a hard "reach for these WHENEVER a task needs live/real-time data"
trigger, while treg's opened with a philosophy ("ask for the task") and
foregrounded the honest "treg compares, you choose, no routing" caveat —
which read as an extra step before results.

Reframes the agent-facing copy in all four places an agent reads it
(mcp.py server description + instructions, skill.md frontmatter, llms.txt
header, plugin.json interface) to:
  - lead with the trigger: "reach for treg FIRST for external/live data"
  - put breadth + your-team's-own-tools up front
  - shrink the no-routing caveat to "you pick" (still truthful — no
    auto-routing/failover is claimed, per the charter)

No behavior change; positioning only. Regenerated plugin/skills/treg/
SKILL.md from skill.md. The listing-does-not-promise-routing tests still
pass (no routing claim introduced).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9
2026-08-11 13:22:05 +10:00
Jason ZhouandClaude Fable 5 a3fcf114c3 release: 0.8.0 — treg mcp install ships to pip/brew
0.7.1 shipped the skill rename but not `treg mcp install` (that landed in
#82 after 0.7.1 was cut). Bumps the CLI so pip/brew/install.sh users get
the new headless MCP-setup command — without it, the deployed install.sh
one-shot calls a command the published CLI doesn't have.

No new deps (mcp_install.py is stdlib-only), so the Homebrew formula
needs only a url + sha256 bump. plugin.json version tracked in lockstep.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9
2026-08-11 12:22:00 +10:00
UncleCode 52e0ae0a68 docs: the MCP + OAuth subsystem, in the three places that were wrong by omission
`/tools-registry-context sync` was overdue: two days of work — the MCP server, the authorization
server, five tools, client registration, consent, refresh rotation — had NO fragment at all, and the
two agent-facing files never mentioned MCP once.

  * **New fragment** `architecture/mcp-oauth.md`. Records the reasoning rather than the surface: why
    five tools instead of 2,600 (a per-provider tool list buries the client and forces a re-connect
    every time the catalog grows), why in-process ASGI rather than reading the database directly (the
    enforcement rules live in those routes; a second path is a second copy of every one of them), why
    `aud` is load-bearing, why codes are deleted before validation, why a retired refresh row is
    KEPT, and why the consent screen shows balances. Ends with "what is deliberately NOT here" —
    no per-provider tools, no routing or failover, no second copy of the rules — because those are
    what a future reader is most likely to add by accident.
  * **llms.txt** gains an MCP section. An agent reading it could only learn the CLI and the /call/
    path; it had no idea treg speaks MCP. Covers the 401 + WWW-Authenticate contract, that discovery
    stays open, that the team is chosen once by a human, and that a catalog call spends while a call
    on the team's own tool does not.
  * **skill.md** gains a mapping section rather than a rewrite: an agent arriving over MCP has five
    tools and no shell, so the CLI-shaped instructions map onto them. Notes that `call` now returns
    `cost_usd`, so "state the price" can be REPORTED rather than estimated. The plugin's SKILL.md
    regenerated from it.
  * `data-model.md` gets the three tables, including why `OAuthClient` is NOT org-scoped while the
    other two are; `api.md` gets the routes and the new cost header; the fragment index gets a row.
  * The plan's status line said "planned, awaiting approval. Nothing built." It is all shipped.

1291 pass.
2026-08-10 20:13:44 +08:00
Jason ZhouandClaude Fable 5 d6122ae34d release: 0.7.1
Ships the skill rename (tools-registry → treg) to the CLI: `treg skill
bootstrap` now installs into <agent>/skills/treg/ and retires the old
tools-registry/ folder. Bundles the merged onboarding + catalog Try-it
work already live on the server.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9
2026-08-10 19:47:12 +10:00
Jason ZhouandClaude Fable 5 cebf8dd502 feat: agent-first onboarding, Getting started revamp, catalog Try-it, skill rename (#64)
* feat(web): first-run agent onboarding + Getting started revamp

New signups land on #connections (the default view for any signed-in
arrival with no deep link). The welcome modal grows two steps after
team creation: an agent picker (OpenClaw / Hermes / Claude.ai / Claude
Code / Codex + more) and the per-agent setup line. The old docked
"Getting started" stepper (onb.*) is removed entirely.

Getting started is rebuilt as numbered cards — ① Set up your <agent>
(setup line + the already-created API key, masked) and ② Try it out
(four copyable live-data prompts, each verified through the catalog,
plus OAuth connect chips for social/ads/site-SEO) — moved to the top
of the nav, above Catalog. Main content column is now centered;
"Your tools" renamed to "Your vault"; page titles reworded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9

* feat(skill): rename the installed skill tools-registry -> treg

The skill installed into agents was named/foldered "tools-registry",
which matched neither the `treg` command nor the brand agents see —
confusing both agents and humans. Now: skill.md frontmatter name is
treg, `treg skill bootstrap` writes <agent>/skills/treg/ (and retires
a leftover tools-registry/ folder when it holds only our SKILL.md),
install.sh's fallback path and the Claude plugin folder follow suit.

The PyPI package name (tools-registry) is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9

* feat(skill): sell the skill in its description, not describe it

The old description led with mechanics (catalog vs own-tools split).
Now it leads with when to reach for it — data access (SEO/SERP,
keyword volume, backlinks, social & trends, enrichment, ads,
scraping) and acting on connected accounts (posting, ad campaigns,
site SEO via OAuth) — and pitches treg as OpenRouter for agent
tools. Kept YAML-safe (no ": " inside the plain scalar).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9

* feat(agents): one setup line everywhere — llms.txt carries the flow

The ~30-line "Agent instruction" duplicated what llms.txt and the
skill already teach (catalog search, prices, scan/upload); the only
things a prompt can carry that a file cannot are the token, the team,
and the authorization to run. So the instruction everywhere is now
exactly:  set up treg — {BASE}/llms.txt with token <T>, team <slug>
(welcome modal, Getting started, sidebar copy row, preview modal —
all one buildAgentPrompt).

llms.txt absorbs the rest: a "set up treg" agent flow (permission
once, work straight through, prove it with one relevant call), the
star-the-repo ask after first real data, and its money rules drop
the confirm-price-with-the-human ritual — prices are visible, calls
are fractions of a cent, just call.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9

* feat(catalog): Try-it is the primary CTA, with agent/CLI/API/manual tabs

On an endpoint row, "▶ Try it" is now the ink-fill primary action and
the old "Connect {provider}" is demoted to a secondary "Bring your own
key" (its real meaning — your key wins over treg's and isn't metered).

The Try-it drawer gains four tabs (AI Agent default): AI Agent shows a
one-line setup (team + token embedded here only, a run-now context) and
a ready "Use treg to call <id>" prompt; CLI shows install/login →
catalog get → the filled treg call; API shows the curl /call/ form with
the token header (+ X-Treg-Org in session mode); Manual is the existing
live test form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9

* fix(catalog): OAuth endpoints keep Connect as primary; fix dead Manual Run

Which run action is primary now depends on the provider's auth_kind
(mkOauth): OAuth providers (act as your account, can't use treg's key)
keep Connect as the ink-fill primary with Try-it secondary; key/token
providers keep Try-it primary with "Bring your own key" secondary.

The Manual tab no longer strands a disabled Run hugging the tab bar
when the endpoint isn't callable from this org — it shows a banner
pointing at Connect / the AI Agent / CLI / API tabs instead, and a
"no parameters — just run it" hint for the param-less callable case.

Retitles the markup test to the new run-actions intent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9

* feat(landing): 0% additional fee band after pay-for-results

Centered pixel-type headline plus a dark mono equation card that types
out "provider rate + $0.000 markup = your price" on scroll, with a
one-line note that treg earns on vendor volume pricing, not markup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018UnVdcbzN8H4mXQaTkHdvD

* feat(web): billing — one-click fund cards + auto top-up toggle

Add funds is now four preset cards ($5/$10/$25/$50); clicking one goes
straight to Stripe checkout — no dropdown-then-button. Auto top-up is a
toggle: switching it on reveals the settings panel (amount, threshold,
the PSD2 consent mandate, confirm); the toggle alone can only disarm or
open the panel — arming still requires the recorded consent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D8t2aMqbfstGqStPLsoxDq

* feat(web): default landing is Getting started, not the catalog

New signups (after the welcome modal) and every signed-in arrival at
/app with no deep link or hash now land on #start (Getting started)
instead of #connections. welcomeFinish and both boot paths updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U72hGQwYvVSyzh7XGqNra9

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-10 16:18:31 +10:00
UncleCode e4de297ebb feat(plugin): the Codex/ChatGPT plugin — connector plus skill, like OpenAI's own
The listing is the point: traffic from the directory ChatGPT and Codex share, instead of needing to
already know to run install.sh. What it ships is BOTH halves, exactly as OpenAI's `github` plugin
declares `"skills"` and `"apps"` together:

  * `.mcp.json` — the connector, pointing at https://treg.superdesign.dev/mcp/ with the token read
    from TREG_TOKEN. This is what makes the plugin work the moment it is installed.
  * `skills/tools-registry/SKILL.md` — the judgement. Tools alone would tell a model HOW to call
    treg and nothing about WHEN it is the right move or how to choose between providers.

The skill is GENERATED from src/treg/web/skill.md by scripts/build_plugin.py, and a test fails if the
copy drifts. It gains one section the served version does not have: the served skill is written
around the `treg` command line, because that is how every other install path reaches treg — a plugin
user has no terminal, they have the connector's tools, so the top of the page maps one onto the other
and says what to do if the tools are absent (set TREG_TOKEN). Without it the first run is an agent
dutifully trying to run a shell command that does not exist, which is the listing's whole funnel
spent on an error.

`category` and `capabilities` are not guesses: read from OpenAI's own installed manifests under
~/.codex/plugins/cache — github is Developer Tools + ["Interactive","Write"], gmail is Communication.
The published docs list neither set of allowed values.

Two tests guard what a public listing cannot easily walk back: the copy may never claim routing or
automatic failover (treg compares, the agent chooses — the landing page needed that correction
once), and the connector must point at production over https, never a dev box or localhost.

docs/PLUGIN-SUBMISSION.md carries every field of the submission form, the five positive and three
negative test cases it requires, and the blockers — business identity verification, and a SUPPORT URL
that treg does not yet have (/support, /contact and /help are all 404).
2026-08-09 19:07:41 +08:00