Skip to main content
ClaudeWave
Skill1.1k repo starsupdated 2d ago

add-oauth-provider

Add a provider to treg's OAuth registry (the ones treg holds its own approved app for). Use when asked to "add YouTube/Notion/Meta OAuth", "support connecting X", "add a new OAuth provider", or when a connect flow, capability picker, channel/account picker, or provider health probe needs building. Covers the code changes, the platform-side approval steps, and the pitfalls that don't announce themselves.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/superdesigndev/treg /tmp/add-oauth-provider && cp -r /tmp/add-oauth-provider/.agents/skills/add-oauth-provider ~/.claude/skills/add-oauth-provider
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Adding an OAuth provider

Two connect modes exist. **BYO** (`POST /oauth/start` with a caller-supplied
client_id/secret) already works for any OAuth2 provider and needs no code. This
skill is the **registry** path: treg owns the registered app, so the user picks a
provider and supplies nothing. Only add a provider here if treg holds — or is
willing to go get — the platform approval behind it.

Read `src/treg/oauth_providers.py`'s module docstring first. The rule it states is
the one most easily broken: **scopes are per capability, never per provider.**

## The code changes

All of these, in order. Skipping any one produces a provider that looks fine in
`/oauth/providers` and fails somewhere the tests don't reach.

### 1. Credentials → `src/treg/config.py`

Add `<name>_client_id` / `<name>_client_secret` to `Settings`, loaded from
`TREG_<NAME>_CLIENT_ID` / `_SECRET`. **Reuse an existing pair when the platform
uses one app for several products** — all four Google providers plus YouTube
share `google_client_id`, because Google verification and API audits are scoped to
the *Cloud project*, not to the OAuth client. A second client in the same project
isolates nothing.

### 2. The provider → `src/treg/oauth_providers.py`

Add the `OAuthProvider` and **register it in `REGISTRY`** (easy to forget; the
provider silently doesn't exist until you do).

Capabilities are **cumulative supersets**, never swaps:

```python
scopes={
    "read":   [READ_SCOPES],
    "post":   [*READ_SCOPES, UPLOAD],           # post CONTAINS read
    "manage": [*READ_SCOPES, UPLOAD, WRITE],    # manage CONTAINS post
}
```

`satisfied_capabilities()` is set-containment, so a non-cumulative `write` yields a
connection that can write but reports "no read". `default_capability` is the
broadest (most scopes) — deliberately, see its docstring.

Split a capability whenever the platform splits the scope. YouTube needs
`read`/`post`/`manage` because uploading a video and being able to edit or delete
one are different Google scopes; collapsing them means a connection that can post
and then never fix a typo.

Per-provider quirks worth knowing: `auth_params={}` for providers that reject
Google's `access_type`/`prompt` (LinkedIn, Slack, X), `pkce=True` +
`token_endpoint_auth_method="client_secret_basic"` for X, `extra_credential_*` when
a second credential rides along (Google Ads' developer token).

### 3. Discovery — "which account does this connection act on?"

Set `discover_path` / `discover_key` / `discover_id_field` / `discover_label_field`.

- Label and id fields are **dotted paths** (`_dig`), so nested values work:
  `discover_label_field="snippet.title"`.
- `discover_base_url` when listing lives on a different host than the data API
  (GA4 reports come from analyticsdata, properties from analyticsadmin).
- `discover_nested_key` when the rows are nested one level down.
- `enrich_*` when the listing returns bare ids and a second call is needed for a
  human name (Google Ads).
- Query strings in `discover_path` are fine — discovery does not pass `params`.

Leave it unset if the credential acts on the whole account; the UI then says
"whole account" rather than showing an empty picker.

### 4. `probe_path` — health + the Tools "Use" prefill

A cheap authenticated GET **on `base_url`** (not `discover_base_url` — the probe
runs against the provisioned tool's own host). Without it the tool reads
"unchecked" forever and the Try panel opens blank.

Prefer the path that returns a *human-recognisable* field, and keep it identical to
the sample path in step 5 — `openUse` prefers `health_check.path` over the sample
map, so if they differ the prefill silently changes after a reconnect.

### 5. Dashboard → `src/treg/web/index.html`

Provider rows, the Connect button and the pickers are all data-driven from
`listing()`. **No new provider needs a UI change** — except:

- **A new capability name** must be added to `capLabel` / `capHelp` (~line 2762).
  An unknown name renders as the bare key plus "Requests the *x* scopes."
- **`samplePath`** (~line 3024) is a hardcoded host→path map used when a tool has
  no `health_check` yet. Add the host so the Try panel prefills for tools that were
  provisioned before the probe existed.

### 6. Tests

`tests/test_oauth_providers_m3.py::test_every_provider_is_registered` asserts an
**exact set** of service names. Add yours or the suite fails.

Then: `uv run pytest -q` (full suite — the registry touches health, tools and
connections).

## The platform side (the actual long pole)

The code is an afternoon. Approval is weeks. Do these in parallel, not in series.

1. **Enable the APIs** on the project *before* touching the consent screen — scope
   pickers usually only list scopes belonging to enabled APIs.
2. **Add the scopes.** Ask only for what you can *demonstrate*; see pitfalls.
3. **Redirect URI** must match `{TREG_PUBLIC_URL}/oauth/callback` exactly.
4. **Verification / app review**, where the platform gates sensitive scopes.
5. **Separate product audits** — these are extra and often slower than the OAuth
   review: YouTube's compliance audit + quota extension, Business Profile API
   access, the Google Ads developer token, LinkedIn's Community Management API.

### For the verification submission

- **App name, homepage, privacy policy and demo video must all agree.** The
  consent-screen brand is what reviewers compare everything against — a mismatch
  is a routine rejection.
- **The privacy policy must name the platform's data explicitly** and link the
  platform's ToS plus the provider's privacy policy.
- **The demo video must show each requested scope actually in use**, with the
  client id visible in the consent URL. This is the real constraint on scope
  count — see the first pitfall.

## Pitfalls

Each of these cost real time.

**Never request a scope you can't film.** "Requested scopes exceed what the demo
shows" is the standard rejection. YouTube's `youtubepartner` needs a YouTube CMS
account t
ads-conversion-trackingSkill

Use when setting up, changing or debugging treg's own conversion tracking — the ad-click capture, the AdConversion outbox, or the Data Manager uploader — and whenever asked whether conversions are "working", "live" or "verified". Also use before claiming any part of the pipeline is proven.

dev-localSkill

One-command local dev stack for tools-registry. Use when asked to "start the dev server", "run treg locally", "test login locally", "bring the stack up", or before any manual/browser test against localhost.

google-adsSkill

Traps when running Google Ads through treg — the API requirements and cleanup semantics that cost round-trips or money. Use whenever asked to analyse ad performance, audit spend, create or change campaigns, adjust budgets or bids, or do media buying.

google-analyticsSkill

Traps to avoid when querying Google Analytics 4 through treg — cases where the GA4 Data API returns a confident wrong answer instead of an error. Use whenever answering questions about site traffic, visitors, pageviews, channels, conversions, or revenue from GA4.

google-search-consoleSkill

Traps to avoid when querying Google Search Console through treg — cases where the API returns a confident wrong answer instead of an error, especially around totals and recent-date trends. Use whenever answering questions about organic search clicks, impressions, rankings, or index status.

tools-registry-contextSkill

tools-registry context + doc upkeep. Use to warm up a fresh session (orient on the architecture + recent commits) or when working on tools-registry — changing code, rules, content, data, or process (proxy · auth/secrets · API · CLI · the registry skill) — loads the relevant fragment(s) from docs/context so you act with accurate, cited context. Accepts an optional focus query (e.g. `/tools-registry-context <area>`). Also runs `/tools-registry-context sync` to update the doc fragments after changes (show → approve → apply). Mention it whenever a push to the main branch is near.

treg-pageSkill

Write a treg.to agent page (/agents/<client>) or use-case page (/use-cases/<category>/<job>). Researches the real problem on Reddit and X with agent-reach BEFORE writing, so the page targets the words buyers actually use and quotes their own questions. Use when adding a page from marketing/pseo-ship-plan.md, or when asked to "write the <job> page" / "add the <agent> page".

write-provider-skillSkill

Build a treg provider skill — the endpoint map + mistake map that lets an agent do real work on a platform API through treg's proxy. Use when adding a skill for a connected provider (Google Ads, LinkedIn, Meta Ads, TikTok, X, Instagram, Search Console), or when an existing provider skill needs verifying or extending.