Platform

Access at the database level. Build what you want on it.

Teams do not stop at asking their agent questions. Because the access is at the database level, they build their own things on top: an internal dashboard for the creators they work with, a Sheets add-in, a Slack bot. The schema is documented, the output is JSON or CSV, and there is nothing to reverse engineer.

We shipped this ourselves first. TL Assistant, live on the Chrome Web Store, uses the same API backend your agent does. Same auth. Same balance. Same schema. Zero extra services to operate.

Read the schema → What your agent can do →

The integration surface

Two ways to call it.

  • Run the tool — easiest, zero ops. subprocess, Deno.Command, chrome.runtime with native messaging. Output is parseable JSON.
  • Hit the HTTP API directly — same bearer, same JSON envelope, same scoping. POST /api/cli/v1/raw/pg, POST /api/cli/v1/raw/es, POST /api/cli/v1/raw/fb.

There is also an MCP server for agents that only speak MCP.

What you don't have to build.

  • A YouTube scraper
  • A brand-mention classifier
  • A demographics pipeline
  • A 8.5B-row time-series store
  • A deals-and-pipeline data model
  • An inventory layer for the creators in our network
Why this makes a good backend

Auth is solved.

PKCE OAuth login lands a refreshing bearer in the OS keyring. TL_API_KEY overrides for CI and bots. You do not write an auth flow — you run the tool, or you reuse the same token in your own HTTP client.

The contract doesn't drift.

Every list endpoint returns { results, total, usage, _breadcrumbs }. Every detail endpoint returns the same thing for one row. JSON, CSV, Markdown and TOON are all native. tl schema pg prints the live column catalogue.

You pay for what you pull.

Your client does not pay a seat. It spends from your org's allowance, on the rows it actually reads. An app that sits idle does not draw on it. See pricing.

What's already being built
CHROME EXTENSION

TL Assistant — sponsorship intel where you already work.

Shipped, and live now on the Chrome Web Store — a Chrome MV3 extension that lights up sponsorship data on top of YouTube itself. Open a creator's channel page; the side panel asks for the channel's deal history, evergreenness and demographics in real time. The whole extension is ~4,000 lines of TypeScript. The backend is one tool on the user's PATH.

// background/proxy.ts
import { run } from "./tlcli";

chrome.runtime.onMessage.addListener(async (msg) => {
  if (msg.type !== "channel-detail") return;
  // Shells out to the user's installed `tl` tool.
  // Same auth, same balance, same response envelope.
  return await run([
    "db", "pg",
    `SELECT id, channel_name, subscribers, projected_views,
            demographic_usa_share, evergreenness
     FROM thoughtleaders_channel
     WHERE external_channel_id = '${msg.ucid}'`,
    "--json",
  ]);
});
SLACK BOT

An account manager that lives in #sponsorships.

A bot that listens for messages mentioning a brand or channel, asks for fresh intel, and replies inline with a vetting card. No new database. No new auth. The bot's account holds an API key, the bot's org pays for what it pulls. ~250 lines.

# slack_bot.py
@app.message(re.compile(r"vet (?P<channel>\d+) for (?P<brand>.+)"))
def on_vet(message, context, say):
    ch = context["matches"]["channel"]
    out = subprocess.check_output([
        "tl", "db", "pg", f"""
          SELECT b.name, COUNT(*) AS deals, AVG(a.price)::int AS avg_price
          FROM thoughtleaders_adlink a
          JOIN thoughtleaders_adspot s   ON a.ad_spot_id = s.id
          JOIN thoughtleaders_profile p  ON a.advertiser_profile_id = p.id
          JOIN thoughtleaders_profile_brands pb ON p.id = pb.profile_id
          JOIN thoughtleaders_brand b    ON pb.brand_id = b.id
          WHERE s.channel_id = {ch} AND a.publish_status = 3
          GROUP BY b.name ORDER BY deals DESC LIMIT 10
        """, "--md"
    ])
    say(f"```{out.decode()}```")
SHEETS / EXCEL ADD-IN

A live-data sponsorship workbook.

Apps Script (Sheets) or Office Scripts (Excel) calls a small proxy server you host yourself. Refresh the workbook and you get fresh deal history, fresh evergreenness, fresh CPM percentiles. Brokers and account managers already live in spreadsheets; meet them there.

function tlPg(sql) {
  const res = UrlFetchApp.fetch("https://my-proxy.example/tl-db-pg", {
    method: "post",
    contentType: "application/json",
    payload: JSON.stringify({ sql }),
    headers: { "X-Org-Key": SHEETS_ORG_KEY },
  });
  return JSON.parse(res.getContentText()).results;
}

// in a cell:
// =TL_PG("SELECT b.name, COUNT(*) FROM ...")
CRON SCRIPTS

Daily and weekly digests, no scheduler service required.

Pipeline freshness, a brand-mention sentinel, a competitor watch — every workflow on the cheatsheet page is a 30-line shell script. cron, Raycast, GitHub Actions, supercronic, anything that can run a command will run it.

# /etc/cron.weekly/brand-sentinel.sh
tl db es '{"size":50,
  "query":{"bool":{"filter":[
    {"term":{"sponsored_brand_mentions":"5612"}},
    {"range":{"publication_date":{"gte":"now-7d/d"}}}]}},
  "_source":["title","channel.id","views"]}' --md \
  | mail -s "New reads (week of $(date +%F))" team@me.io
MOBILE / NATIVE APPS

Same backend. Different surface.

iOS, Android, desktop Tauri or Electron — anything that can hold a bearer token and POST JSON. Today the CLI is the reference client; tomorrow yours is a peer client of the same API. The auth flow (PKCE OAuth) and the API contract do not change.

// Swift example — the only thing the app needs is the same bearer
let req = URLRequest(url: URL(string: "https://app.thoughtleaders.io/api/cli/v1/raw/pg")!)
  .post(json: ["query": "SELECT ..."])
  .bearer(token)
let (data, _) = try await URLSession.shared.data(for: req)
let envelope = try JSONDecoder().decode(Envelope.self, from: data)
AGENT HARNESS

Drop it into whatever agent you already run.

There is no SDK to integrate. There is a command. If your agent can run bash, it can run tl. tl setup claude, codex, gemini and opencode install the ready-made skills for the four agents we document; everything else runs in its own terminal.

Claude Code

What does this channel's sponsorship history look like?

used tl channels similar 12345 min-score:0.7 --limit 10

Ten neighbours, ranked by similarity, with what each one charges:

ChannelSubscribersCPM
Trailhead Weekly612,000$24
Backcountry Bench488,000$21
Ridge & River301,000$19

The agent read the JSON, saved it to a file, and kept working from there.

Reply to Claude Code Fable
A rendering of an agent session. Channel names and figures are placeholders.
The Chrome extension, in the wild

Same backend, totally different shape.

The Chrome extension never opens a terminal. It runs in MV3, side-panel first, and calls the user's installed tl tool via native messaging. The extension's job is layout, glanceable cards and YouTube DOM observation. The data layer is the same one your agent talks to.

If we want to add a new field to the side panel, the question is not "do we need a new endpoint?" — it is "which column?" The schema is the API.

  • chrome.runtime.connectNative('com.thoughtleaders.cli')
  • — Side panel surfaces deal history, evergreenness, demographics
  • — Reuses the user's own balance, no extension-side billing
  • — ~4k lines of TypeScript, no backend service to operate
// background/tlcli.ts
const port = chrome.runtime.connectNative("com.thoughtleaders.cli");

export function run(args: string[]): Promise<unknown> {
  return new Promise((resolve, reject) => {
    const id = crypto.randomUUID();
    const onMsg = (msg: any) => {
      if (msg.id !== id) return;
      port.onMessage.removeListener(onMsg);
      msg.error ? reject(msg.error) : resolve(JSON.parse(msg.stdout));
    };
    port.onMessage.addListener(onMsg);
    port.postMessage({ id, args });
  });
}

// later, on a YouTube channel page:
const ch = await run([
  "db", "pg",
  `SELECT id, channel_name, subscribers, evergreenness,
          demographic_usa_share, demographic_male_share,
          demographic_device, demographic_geo
   FROM thoughtleaders_channel
   WHERE external_channel_id = '${ucid}'`,
  "--json",
]);
The whole extension's data layer in one function. The rest is React.
Licensing

The CLI is open source (MIT).

Fork it, vendor it, embed it. The repo is at github.com/ThoughtLeaders-io/thoughtleaders-cli. PRs welcome — we shipped tl db pg|fb|es as a direct response to community asks.

The data is paid by what you read.

No platform fee, no white-label tax, no API tier. Whatever your client pulls, it pulls against your org's allowance. Want a scoped key for production traffic that will not auto-refresh? partnerships@thoughtleaders.io.

Ship a sponsorship product this weekend. We did.