Metadata-Version: 2.5
Name: trio-town
Version: 0.12.1
Summary: A remote registry that turns team skills into shareable, callable tools via a credential-injecting proxy.
Project-URL: Homepage, https://trio.town
License: Proprietary
Keywords: agents,api,cli,credentials,proxy,registry,secrets,tools
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development
Classifier: Topic :: Utilities
Requires-Python: <3.14,>=3.12
Requires-Dist: httpx>=0.27
Requires-Dist: questionary>=2.0
Provides-Extra: proxy
Requires-Dist: cryptography>=43; extra == 'proxy'
Provides-Extra: server
Requires-Dist: aiosqlite>=0.20; extra == 'server'
Requires-Dist: alembic>=1.16.5; extra == 'server'
Requires-Dist: asyncpg>=0.30; extra == 'server'
Requires-Dist: cryptography>=43; extra == 'server'
Requires-Dist: fastapi>=0.115; extra == 'server'
Requires-Dist: mcp>=2; extra == 'server'
Requires-Dist: pydantic-settings>=2.5; extra == 'server'
Requires-Dist: pyyaml>=6; extra == 'server'
Requires-Dist: sqlalchemy[asyncio]>=2.0; extra == 'server'
Requires-Dist: sqlmodel>=0.0.22; extra == 'server'
Requires-Dist: stripe>=12; extra == 'server'
Requires-Dist: uvicorn[standard]>=0.32; extra == 'server'
Description-Content-Type: text/markdown

# Trio (OpenRouter for Tools)

![trio — the tool catalog for your agent](docs/assets/trio-hero.png)

**OpenRouter, but for agent tools instead of models.** Point an agent at one base URL with one token
and it can do the job: **2,835 catalogued endpoints across 59 providers** — SEO and backlinks,
social and trends, people and company enrichment, ads, scraping — **priced per call, from a cent**,
with no provider signup. Plus your own team's keys, skills and CLIs, callable by every teammate's
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 Trio team, live at [trio.town](https://trio.town) — anyone can self-host.

## Why it exists

The tools an agent needs for real work sit behind subscriptions nobody buys for a single run —
Semrush $139/mo, Moz $99/mo, Crunchbase $99/mo, Apollo $59/seat — behind signup walls, or behind no
public API at all (invite-only, partner-only, app-review-only). trio carries those accounts and
bills fractions of a cent per call.

## Two kinds of tool, one token

- **The catalog** — external endpoints trio can serve **on its own key**, metered against your
  team's prepaid balance (**$1.00 free** on every new team). No account with the provider needed.
- **Your own tools** — anything a teammate registered: a paid API account, an OAuth connection, a
  vendor CLI, a `SKILL.md`. **Your own key always wins over trio's, and those calls are never
  metered.**

The vocabulary for the second half:

- **tool** = something the registry calls for you with the org's credential. Two kinds:
  - **endpoint** — an upstream `base_url` + credential **bindings** (each binding injects one
  secret into the request; a request can carry several, e.g. an OAuth bearer *and* a
  `developer-token` header).
  - **CLI** — a vendor binary (`stripe`, `gh`, `vercel`, ...) run with the credential injected.
- **skill / bundle** = a recipe (`SKILL.md`) + its secrets + its tool(s), registered together.

**The one rule:** the proxy **relays, never models** the upstream, and **injects auth server-side**
— so it survives upstream API changes and callers never hold keys.

---

# Part 1 · Using the registry

Visit [**trio.town**](https://trio.town) (hosted on Render) — the dashboard,
sign-in, and every URL below live there.

## Quickstart

Same flow as the dashboard's **Getting started** guide:

```bash
# 1. install the CLI — also points it at the registry
curl -fsSL https://trio.town/install.sh | sh

# 2. sign in (GitHub default · --email for a one-time code · --token for agents/CI)
trio login

# 3. do something useful immediately — no key, nothing registered
trio catalog search "backlinks for a domain"     # find a tool by what it DOES
trio call tikhub.tiktok.user.profile --query uniqueId=tiktok
trio balance                                     # exactly what that cost

# (or `trio onboard` for the guided walkthrough)
```

Your token identifies you on every call (`X-Trio-Token` header) and is the same for all tools.
Discover what your team has shared: `trio tool ls` · check credential health: `trio health`.

### Or install it as a Claude Code plugin

```
/plugin marketplace add your-org/trio
/plugin install trio@trio
```

Installs with no token and no configuration. The skill loads as `trio:trio` and, on its first run,
walks your agent through the rest — the CLI, sign-in, then `trio mcp install` — so you end up with
the command line **and** trio's tools. Other agents: `npx skills add your-org/trio -s trio`
(the `-s` matters — without it you also get this repo's internal dev skills).
See [docs/CLAUDE-PLUGIN.md](docs/CLAUDE-PLUGIN.md). MiniMax Code / MiniMax Agent users: the same
skill ships via the MiniMax Plugin Marketplace ([docs/MINIMAX-PLUGIN.md](docs/MINIMAX-PLUGIN.md)).

## Call a tool you don't have a key for

The catalog is grouped by what endpoints **do**: keyword and rank tracking, backlinks and authority,
AI visibility, trending and discovery, publishing to socials, people and company enrichment, ads
management and creative, measurement.

```bash
trio catalog                                    # every platform, busiest first
trio catalog search "find a work email"         # by the job, not the vendor
trio catalog get hunter.people.email.find       # params, PRICE, example response
trio call hunter.people.email.find --query domain=reddit.com --query full_name="Alexis Ohanian"
```

**How a catalogued call is served** — the credential ladder, in order:

1. your team registered its own tool for that provider → that tool, that key;
2. your team stored a secret for the provider → injected through a virtual tool;
3. neither → **trio's own key**, billed to the team's prepaid balance.

Your own credential always beats trio's, so connecting a key you already pay for makes those calls
free of the balance rather than duplicating them. An endpoint trio has no published price for is
**refused**, not served free — you are told to connect your own key instead. Where several providers
serve one capability, `trio catalog search` shows them side by side with prices; **choosing is
yours** — trio does not silently pick or fail over for you.

```bash
trio balance          # credit left, calls in flight, recent spend
trio topup            # add funds, or set up automatic top-ups
```

Out of balance is an HTTP **402** carrying `balance_micro`, `estimated_cost_micro` and a `topup_url`,
so an agent can act on it without reading prose.

## Share & use your own tools

The zero-thought path — point trio at a project and it figures out what's shareable:

```bash
trio scan     # read-only preview: the keys, skills & CLIs upload would register
trio upload   # register them (encrypted server-side); idempotent, --replace to update
```

`trio upload` scans the `.env` (matching keys against ~80 known providers), every skill
subdirectory, and installed catalog CLIs. Three kinds of things go into the registry — here's how
to share and use each:

### 1. Endpoints (HTTP APIs)

**Share** — one upstream URL callable with a stored key, or bulk from a `.env`:

```bash
trio secret add STRIPE_KEY --value sk_live_123
trio add stripe --base-url https://api.stripe.com --secret STRIPE_KEY

trio upload env --select openai,stripe,resend     # or straight from the .env
```

**Use** — the agent-native way: build the **real** upstream request and prefix it with the proxy.
trio resolves the tool by host, injects the credential, and relays everything else faithfully
(your `X-Trio-Token` is stripped before the upstream sees it):

```
Real request:   GET https://api.intercom.io/conversations?per_page=5
Through trio:   GET https://trio.town/call/https://api.intercom.io/conversations?per_page=5
                    header:  X-Trio-Token: <your token>
```

Or the CLI shorthand — and `trio calls` for the audit log:

```bash
trio call intercom conversations --query per_page=5
trio call stripe v1/balance
```

### 2. CLIs

**Share** — automatic: `trio upload` detects installed catalog CLIs (`stripe`, `gh`, `vercel`, …)
and registers them; a recipe-only catalog CLI skill (e.g. `stripe-cli`) auto-becomes runnable too.

**Use** — `trio run` executes the vendor CLI **with the org's credential injected**, so you never
hold the key or log in:

```bash
trio run stripe -- get /v1/balance
trio run gh -- pr list
trio run --server agentmail-cli inboxes list   # runs on the registry server: the key never reaches you
```

`--local` (default) runs on your machine; `--server` runs on the registry and streams output back.
For a whole session, `trio shell start` opens a subshell where every registered CLI injects
automatically — just use `stripe`, `gh`, … normally; `exit` reverts. `trio runs` is the audit log.

### 3. Skills

**Share** — a skill is a whole capability (`SKILL.md` recipe + its secrets + its tool(s)),
registered together so the whole team runs the same skill, maintained in one place:

```bash
trio upload skills --dir ~/.claude/skills --all   # register a folder of skills in one pass
```

**Use** — pull any shared skill into your agent; its API calls go through trio with your token,
so the key stays on the server, never in the skill:

```bash
trio skill install seo-blog-writer      # writes into ./.claude/skills/  (--all for the library)
```

### Manual registration — when the heuristics can't figure a tool out

```bash
# multi-credential tool (e.g. google-ads: OAuth bearer + a developer-token header)
trio tool add google-ads --base-url https://googleads.googleapis.com \
  --bind "secret=<oauth-id>,injector=oauth" \
  --bind "secret=<dev-id>,name=developer-token,format={secret}"

# one skill, step by step
trio skill init --dir ./my-skill          # drafts trio.json (guesses base_url, finds secrets)
trio skill add  --dir ./my-skill          # registers recipe + secrets + tool, atomically

# OAuth via the browser (mints the first token, trio holds it and auto-refreshes)
trio oauth connect gsc --client-secret client_secret.json \
  --scopes https://www.googleapis.com/auth/webmasters.readonly
```

Full options for every command: [`USAGE.md`](USAGE.md).

## Teams

Everything is scoped to an **org**: a token = a `(user, org)` membership, and every secret, tool,
and skill belongs to the active org. Roles: **owner / admin / member / viewer**.

```bash
trio org create "Acme"                        # make a team, become owner
trio org invite teammate@acme.com             # invite by email (pick role + tool access)
trio org join <code> --email you@acme.com     # accept an invite (creates you if new)
trio org ls | use <slug> | members            # switch orgs, see the roster
trio org access <member> --tools a,b          # per-member tool access (admin+)
```

## Going deeper

- [`USAGE.md`](USAGE.md) — the full `trio` CLI reference.
- [`/llms.txt`](https://trio.town/llms.txt) — the agent-onboarding file: call
protocol, discovery, auth, CLI, skills. One fetch teaches an agent the whole registry.
- **The dashboard** at [trio.town](https://trio.town) — 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-Trio-Token` header.

---

# Part 2 · Self-hosting & development

## Run it locally

One command (needs `tmux` + [`uv`](https://docs.astral.sh/uv/); it syncs the venv itself):

```bash
scripts/dev-local.sh up        # server on http://localhost:8787, dev-safe settings
```

That runs the server in tmux with hot-reload, its own sqlite DB (`trio-dev.db`), and email OTP dev
mode (sign-in codes shown on the page — no mail sender needed). Day-to-day:

```bash
scripts/dev-local.sh cli login   # sandboxed CLI: never touches your real ~/.trio/config.json
scripts/dev-local.sh logs        # server output          · status / restart / down
scripts/dev-local.sh reset       # wipe the dev DB + CLI sandbox for a fresh start
```

Or run the server directly, without tmux:

```bash
uv sync                        # create the venv from uv.lock (pulls the server deps for dev)
uv run python -m trio          # serve on 0.0.0.0:8787 (add --reload for dev)
uv run python -m trio keygen   # print a fresh Fernet key for TRIO_SECRET_KEY
```

> **Installing to run a server (not from source):** the base package is the **CLI only**. To run a
> registry, install the server extra — `pip install "trio-town[server]"` — which adds FastAPI, the
> database drivers, and encryption. `pip install trio-town` alone gives just the `trio` command for
> talking to an existing registry.

The team instance is hosted on **Render** (web service + Postgres) at `trio.town`.

## Configuration

Environment variables (prefix `TRIO_`, read from `.env`):


| Var                                       | Default                         | Purpose                                                                                                                                                                    |
| ----------------------------------------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TRIO_DATABASE_URL`                       | `sqlite+aiosqlite:///./trio.db` | DB URL (SQLite for dev, Postgres in prod)                                                                                                                                  |
| `TRIO_SECRET_KEY`                         | *(empty)*                       | Fernet key for secrets-at-rest; empty → an ephemeral key is minted (secrets won't survive a restart)                                                                       |
| `TRIO_PUBLIC_URL`                         | `https://trio.town`  | trio's public base, used to build the OAuth callback URI                                                                                                                   |
| `TRIO_SESSION_SECRET`                     | *(empty)*                       | signs the dashboard session cookie; falls back to `TRIO_SECRET_KEY`. Set a real value in prod                                                                              |
| `TRIO_GITHUB_CLIENT_ID` / `_SECRET`       | *(empty)*                       | GitHub OAuth sign-in (callback `<public_url>/auth/github/callback`); empty hides the button                                                                                |
| `TRIO_GOOGLE_CLIENT_ID` / `_SECRET`       | *(empty)*                       | Google OAuth sign-in (redirect `<public_url>/auth/google/callback`); empty hides the button                                                                                |
| `TRIO_RESEND_API_KEY` / `TRIO_EMAIL_FROM` | *(empty)*                       | transactional email via Resend (OTP codes + invites); From must be a Resend-verified sender                                                                                |
| `TRIO_ADMIN_TOKEN`                        | *(empty)*                       | cross-tenant **super-admin** bearer; authorizes every `/admin/*` endpoint. Empty disables the env path (only `is_superadmin` users reach `/admin`). Keep it long + secret. |
| `TRIO_EMAIL_DEV_MODE`                     | `false`                         | when true, `/auth/email/start` returns the OTP in its response (no mail sender needed) — **dev/local only**, never in prod.                                                |


No `.env` is needed for local dev — every setting has a working default (ephemeral key, sqlite).

> **⚠️ Back these up before moving or redeploying:** the Fernet key (`TRIO_SECRET_KEY`) and the
> database (Postgres in prod; `trio.db` for a local sqlite run). Lose the Fernet key and every
> stored secret becomes unrecoverable.

## Architecture

**Request flow for `/call`:** resolve tool (by URL host + longest `base_url` prefix, or by name) →
decrypt its secret(s) → apply each binding's injector → stream to the upstream → fire-and-forget
audit record. The proxy does no business logic and never buffers the body.

**Module map** (`src/trio/`):


| Module                                     | Role                                                                                                             |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| `proxy.py`                                 | `relay()` — the whole product in one function: a faithful streaming proxy                                        |
| `injectors.py`                             | the auth-shape seam: `env`, `cli_auth`, `secret_file`, `oauth` place a secret into a header/query                |
| `oauth.py`                                 | token freshness (single-flight refresh) + the connect flow (consent URL, code exchange)                          |
| `health.py`                                | credential health: refresh oauth, probe tools, webhook the owner of anything broken                              |
| `convert.py`                               | scaffold a skill directory into a registerable bundle manifest                                                   |
| `api.py`                                   | the API — the only brain; CLI + skill are thin clients over it                                                   |
| `cli.py`                                   | the `trio` CLI                                                                                                   |
| `models.py`                                | SQLModel tables: `Org`, `User`, `Membership`, `Invite`, `Secret`, `Tool`, `Bundle`, `PendingOAuth`, `CallRecord` |
| `crypto.py` `config.py` `db.py` `audit.py` | Fernet encryption + tokens · settings · async DB · deferred audit writer                                         |


**The 4 auth shapes** (per binding `injector`): `env` (plain string / API key) · `secret_file` (a
JSON token file, pull a field) · `oauth` (a JSON OAuth token, auto-refreshed if refreshable) ·
`cli_auth` (material lifted from a CLI's keychain).

**Faithful-relay contract:** the proxy alters **only** three things, everything else is verbatim:

1. hop-by-hop transport headers (re-derived per hop),
2. trio's own control + edge-forwarding headers (`x-trio-token`, `x-trio-org`,
`ngrok-skip-browser-warning`, `x-forwarded-*`, `via`, …) and trio's session cookie — all stripped,
never leak upstream,
3. the injected credential(s).

**OAuth, three ways to get the first token:** *manual upload* (drop in a `token.json`) ·
*auto-refresh* (if the token carries `refresh_token` + client creds, trio keeps it fresh, you never
re-upload) · *hosted connect flow* (`trio oauth connect` → browser consent → trio captures the
token itself).

**Health checks:** give a tool an optional probe (`{method, path, expect_status}`); a periodic run
(on demand or via cron) validates every credential, refreshes OAuth, and webhooks the owner of any
that break.

Deep design lives in [`docs/context/`](docs/context/README.md) (per-subsystem fragments).

## Tests

```bash
uv run pytest -q     # 521 tests
```

Coverage: proxy walking-skeleton, all injector shapes, per-user auth + CRUD + audit, skill composer,
URL-passthrough + faithful relay, OAuth refresh + connect flow, health checks, `trio run`/shell,
upload/scan, orgs + invites, the dashboard API, CLI.

## Contributing & docs

```
trio/
├── src/trio/            # the package (api, cli, proxy, injectors, oauth, health, convert, models, …)
│   └── web/             # dashboard, landing, tutorial, llms.txt, skill.md, install.sh
├── tests/               # 521 tests
├── docs/
│   ├── context/         # design fragments (codemap system) + generated index
│   └── ONBOARDING.md    # first-time bootstrap
├── USAGE.md             # full trio CLI reference
└── pyproject.toml
```

Per-subsystem design docs are **fragments** in `docs/context/`, each citing its `src/trio/*`
sources. Working in this repo with an AI agent? The `/trio-town-context` skill loads the
right fragment for what you're touching and keeps the docs in sync — run
`/trio-town-context sync` before pushing.

**Roadmap:** MCP support · finer permission tiers · at-rest key-management hardening · possible
Loopni merge.

## License

Proprietary. This codebase is for the course team's own use; it is not licensed for redistribution.
