thoughtleaders.ai
PLATFORM

The CLI provides data.
Build whatever you want on top.

Every endpoint behind the CLI is a JSON-over-HTTP API with bearer auth, a stable response envelope, giving your agents hands-off access to structured data, with type hints and description, allowing you to dig into unobvious patterns and tailor the output to your use-case.

We are dogfooding this right now: a Chrome extension that lights up sponsorship intel on YouTube itself uses the same API backend as the CLI. Same auth. Same credit balance. Same schema. Zero extra services to operate.

01 THE INTEGRATION SURFACE

Two ways to call it.

  • Spawn the binary — 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 RLS scoping. POST /api/cli/v1/raw/pg, POST /api/cli/v1/raw/es, POST /api/cli/v1/raw/fb.

What you don't have to build.

  • A YouTube scraper
  • A brand-mention classifier
  • A demographics pipeline
  • A 7.4B-row time-series store
  • A deals-and-pipeline data model
  • An MSN / TPP inventory layer
02 WHY A CLI 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 don't write an auth flow — you spawn the CLI, 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, TOON, and CSV outputs are native citizens. Use tl schema <pg|db|es> to learn our DB schema.

Cost is per-result.

Your client doesn't pay a seat. It pays for the rows it pulls. Idle apps are free. Bots that pull a lot get billed exactly what they pull. Same curve, same balance, with built-in price discovery.

03 WHAT'S ALREADY BEING BUILT
01 · CHROME EXTENSION

TL Assistant — sponsorship intel where you already work.

We're shipping a Chrome MV3 extension that lights up sponsorship data on top of YouTube itself. Open a creator's channel page; the side panel asks the CLI 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 binary 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` binary.
  // Same auth, same credit balance, same response envelope as the CLI.
  return await run([
    "db", "pg",
    `SELECT id, channel_name, reach, impression,
            demographic_usa_share, evergreenness
     FROM thoughtleaders_channel
     WHERE external_channel_id = '${msg.ucid}'`,
    "--json",
  ]);
});
02 · SLACK BOT

An AM operator that lives in #sponsorships.

A bot that listens for messages mentioning a brand or channel, calls the CLI 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 the credits. ~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"]
    br = context["matches"]["brand"]
    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.creator_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()}```")
03 · SHEETS / EXCEL ADD-IN

A live-data sponsorship workbook.

Apps Script (Sheets) or Office Scripts (Excel) shells out via a small proxy server you host yourself. Refresh the workbook → fresh deal history, fresh evergreenness, fresh CPM percentiles. Brokers and AMs 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 ...")
04 · CRON SCRIPTS

Daily & weekly digests, no scheduler service required.

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

# /etc/cron.weekly/msn-joiners.sh
tl db pg "
  SELECT id, channel_name, reach, content_category
  FROM thoughtleaders_channel
  WHERE media_selling_network_join_date >=
        CURRENT_DATE - INTERVAL '7 days'
    AND content_category IN (10, 15, 16)
  ORDER BY reach DESC
  LIMIT 100 OFFSET 0" --md \
  | mail -s "New MSN joiners (week of $(date +%F))" team@me.io
05 · AGENT HARNESS

Drop the CLI into Claude Code, Cursor, Codex, OpenClaw — anything with a shell.

There is no SDK to integrate. There is no MCP server to spin up. There is a shell. If your agent can call bash, it can call tl. We ship a Claude Code plugin (tl setup claude) and an OpenCode skill (tl setup opencode) for the two harnesses we use most, but every other agent works the same way.

# in any harness with shell access:
$ tl whoami --json
$ tl describe show sponsorships --json
$ tl schema pg
$ tl db pg "SELECT ... LIMIT 50 OFFSET 0" --json
# the agent reads the JSON and decides what to do next
06 · MOBILE / NATIVE APPS

Same backend. Different surface.

iOS, Android, desktop Tauri/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 don't 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)
04 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 shells out to the user's installed tl binary via native messaging. The extension's job is layout, glanceable cards, and YouTube DOM observation. The CLI's job is the data.

If we want to add a new field to the side panel, the question isn't "do we need a new endpoint?" — the question 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 credit balance — no extension-side billing
  • — ~4k LOC 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, reach, 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.
05 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 the row.

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

Ship a sponsorship product this weekend. We did.