thoughtleaders-cli 0.5.0__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/.claude-plugin/plugin.json +1 -1
  2. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/AGENTS.md +3 -1
  3. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/PKG-INFO +24 -13
  4. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/README.md +23 -12
  5. thoughtleaders_cli-0.6.0/agents/tl-analyst.md +112 -0
  6. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/commands/tl-sponsorships.md +9 -2
  7. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/commands/tl.md +4 -4
  8. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/docs/architecture.md +80 -59
  9. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/pyproject.toml +1 -1
  10. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/skills/tl/SKILL.md +123 -59
  11. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/skills/tl/references/firebolt-schema.md +6 -5
  12. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/__init__.py +1 -1
  13. thoughtleaders_cli-0.6.0/src/tl_cli/commands/doctor.py +134 -0
  14. thoughtleaders_cli-0.6.0/src/tl_cli/commands/recommender.py +247 -0
  15. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/setup.py +0 -2
  16. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/main.py +2 -0
  17. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/output/formatter.py +48 -6
  18. thoughtleaders_cli-0.6.0/tests/test_output.py +230 -0
  19. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/uv.lock +2 -2
  20. thoughtleaders_cli-0.5.0/agents/tl-analyst.md +0 -66
  21. thoughtleaders_cli-0.5.0/commands/tl-brands.md +0 -16
  22. thoughtleaders_cli-0.5.0/commands/tl-channels.md +0 -31
  23. thoughtleaders_cli-0.5.0/src/tl_cli/commands/doctor.py +0 -70
  24. thoughtleaders_cli-0.5.0/tests/test_output.py +0 -19
  25. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/.claude-plugin/marketplace.json +0 -0
  26. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/.github/workflows/python-publish.yml +0 -0
  27. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/.gitignore +0 -0
  28. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/CLAUDE.md +0 -0
  29. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/LICENSE +0 -0
  30. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/commands/tl-balance.md +0 -0
  31. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/commands/tl-reports.md +0 -0
  32. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/hooks/hooks.json +0 -0
  33. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/hooks/scripts/post-usage.sh +0 -0
  34. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/hooks/scripts/pre-check.sh +0 -0
  35. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/skills/tl/references/business-glossary.md +0 -0
  36. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/skills/tl/references/elasticsearch-schema.md +0 -0
  37. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/skills/tl/references/postgres-schema.md +0 -0
  38. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/_completions.py +0 -0
  39. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/auth/__init__.py +0 -0
  40. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/auth/commands.py +0 -0
  41. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/auth/login.py +0 -0
  42. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/auth/pkce.py +0 -0
  43. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/auth/token_store.py +0 -0
  44. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/client/__init__.py +0 -0
  45. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/client/errors.py +0 -0
  46. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/client/http.py +0 -0
  47. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/__init__.py +0 -0
  48. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/ask.py +0 -0
  49. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/balance.py +0 -0
  50. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/brands.py +0 -0
  51. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/changelog.py +0 -0
  52. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/channels.py +0 -0
  53. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/comments.py +0 -0
  54. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/db.py +0 -0
  55. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/deals.py +0 -0
  56. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/describe.py +0 -0
  57. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/matches.py +0 -0
  58. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/proposals.py +0 -0
  59. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/reports.py +0 -0
  60. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/schema.py +0 -0
  61. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/snapshots.py +0 -0
  62. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/sponsorships.py +0 -0
  63. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/uploads.py +0 -0
  64. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/commands/whoami.py +0 -0
  65. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/config.py +0 -0
  66. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/filters.py +0 -0
  67. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/hints.py +0 -0
  68. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/output/__init__.py +0 -0
  69. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/src/tl_cli/self_update.py +0 -0
  70. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/tests/__init__.py +0 -0
  71. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/tests/test_auth.py +0 -0
  72. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/tests/test_filters.py +0 -0
  73. {thoughtleaders_cli-0.5.0 → thoughtleaders_cli-0.6.0}/tests/test_sponsorships.py +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tl-cli",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "ThoughtLeaders CLI — query sponsorship deals, channels, brands, uploads, and intelligence from the terminal",
5
5
  "author": {
6
6
  "name": "ThoughtLeaders",
@@ -1,6 +1,6 @@
1
1
  # Project Overview
2
2
 
3
- **tl-cli** is a Python CLI for querying ThoughtLeaders sponsorship data (sponsorships, channels, brands, uploads, snapshots, reports). Built with Typer + Rich + httpx. Designed as an "agent-first tool" — the CLI handles structured commands and output, while the user's AI agent (Claude) provides intelligence.
3
+ **tl-cli** is a Python CLI for querying ThoughtLeaders sponsorship data (sponsorships, channels, brands, uploads, snapshots, reports, vector recommender). Built with Typer + Rich + httpx. Designed as an "agent-first tool" — the CLI handles structured commands and output, while the user's AI agent (Claude) provides intelligence.
4
4
 
5
5
  # Architecture
6
6
 
@@ -20,6 +20,8 @@ When adding a new data command, follow this pattern. See `sponsorships.py` for t
20
20
 
21
21
  `deals`, `matches`, and `proposals` are shortcut commands that delegate to sponsorships' `do_list`/`do_show`/`do_create` with a pre-set status filter. They reject explicit `status:` filters — users should use `tl sponsorships list` for finer-grained status filtering.
22
22
 
23
+ `recommender` (`commands/recommender.py`) wraps the vector-recommender API at `/api/cli/v1/recommender/*` — `tags` (free), `top`, `inspect-channel`, `inspect-brand`, `similar-to-profile` (all 50 credits flat, Intelligence-gated). Channel→channel and brand→brand similarity stay on `tl channels similar` / `tl brands similar`. When updating the SKILL or examples, prefer steering category/topic discovery (e.g. "Cooking channels") to `tl recommender top "<tag>"` rather than `WHERE content_category = <code>` SQL — the recommender is ranked, not equality-based, and returns matching brand profiles alongside channels. The underlying recommender code uses "element"/"field_name" terminology; the CLI/API layer renames these to "tag" at the boundary.
24
+
23
25
  ## Filter Parsing (`filters.py`)
24
26
 
25
27
  `parse_filters()` handles `key:value` and `key:"quoted value"` syntax. Returns `dict[str, str]` passed as query params. Date filter keys (listed in `DATE_FILTER_KEYS` — e.g. `since`, `created-at`, `created-at-start`, `publish-date-end`) accept keywords `today`, `yesterday`, `tomorrow`. Sponsorship date fields (`created-at`, `publish-date`, `purchase-date`, `send-date`) each expose three filter shapes: bare `<field>:<date>` matches within that date/period, and `<field>-start:` / `<field>-end:` give inclusive lower/upper bounds (both sides inclusive; partial dates expand to the whole period). Empty-string values result in `IS NULL` queries on the backend.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thoughtleaders-cli
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence
5
5
  Project-URL: Homepage, https://thoughtleaders.io
6
6
  Project-URL: Repository, https://github.com/ThoughtLeaders-io/thoughtleaders-cli
@@ -43,11 +43,11 @@ pip install -e .
43
43
  ### As a user
44
44
 
45
45
  ```bash
46
- pipx install git+https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git
46
+ pipx install thoughtleaders-cli
47
47
  # or
48
- uv tool install git+https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git
48
+ uv tool install thoughtleaders-cli
49
49
  # or (but try to avoid it because just "pip" will not create a new venv for the product - only "uv" and "pipx" will do that)
50
- pip install git+https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git
50
+ pip install thoughtleaders-cli
51
51
  ```
52
52
 
53
53
  Then set up:
@@ -81,13 +81,16 @@ tl uploads list q:code --csv
81
81
  # Show upload details (supports colon-containing IDs)
82
82
  tl uploads show 1174310:0BehkmVa7ak
83
83
 
84
- # Search channels. msn and tpp are tri-state filters (yes/no/both; default 'both').
85
- # msn = opted-in to receive sponsorship offers; tpp = exclusively TL-managed.
86
- # Both are also returned as boolean fields on every channel response.
87
- tl channels list category:cooking min-subs:100k
88
- tl channels list msn:yes # MSN channels only (~11k)
89
- tl channels list tpp:yes # TPP channels only (~169)
90
- tl channels list msn:no min-subs:500k # big non-MSN channels
84
+ # Search channels via raw SQL `tl db pg` against thoughtleaders_channel
85
+ # (run `tl schema pg` once to confirm the live column set).
86
+ tl db pg "SELECT id, channel_name, total_views FROM thoughtleaders_channel
87
+ WHERE content_category = <COOKING_CODE> AND total_views >= 100000
88
+ ORDER BY total_views DESC LIMIT 50 OFFSET 0"
89
+ tl db pg "SELECT id, channel_name FROM thoughtleaders_channel
90
+ WHERE is_tl_channel = TRUE LIMIT 200 OFFSET 0" # all TPP channels (~169)
91
+ # MSN status (media_selling_network_join_date) is scrubbed from the
92
+ # advertiser sandbox view — for MSN-only / non-MSN lookups, the
93
+ # structured filter is the right tool: `tl channels list msn:yes|no`.
91
94
 
92
95
  # Show channel detail — accepts numeric ID or channel name.
93
96
  # Names that match more than one active channel print a candidate list
@@ -102,6 +105,16 @@ tl channels show "Economics Explained"
102
105
  tl channels similar 12345 --limit 10
103
106
  tl channels similar "Tremending girls" min-score:0.85 --limit 5
104
107
 
108
+ # Vector recommender — discovery by category/demographic tag (Intelligence plan).
109
+ # `tags` is free; `top`, `inspect-*`, and `similar-to-profile` cost 50 credits flat.
110
+ tl recommender tags # List every tag (free)
111
+ tl recommender tags cooking # Search tag names by substring
112
+ tl recommender top "Cooking" msn:yes --limit 50 # Top channels & brand profiles for a tag
113
+ tl recommender top "USA share" mbn:yes # Demographic tag, MBN brands only
114
+ tl recommender inspect-channel 12345 # Per-tag breakdown of a channel's vector
115
+ tl recommender inspect-brand Nike # Per-tag breakdown of a brand's ideal vector
116
+ tl recommender similar-to-profile 842 # Channels closest to a brand profile
117
+
105
118
  # Brand intelligence
106
119
  tl brands show Nike
107
120
 
@@ -173,8 +186,6 @@ Talk naturally in Claude Code:
173
186
  Resource-specific slash commands:
174
187
  ```
175
188
  /tl-sponsorships pending with send dates in April
176
- /tl-channels cooking channels over 100k subscribers
177
- /tl-brands Nike
178
189
  /tl-reports run my Q1 pipeline
179
190
  /tl-balance
180
191
  ```
@@ -16,11 +16,11 @@ pip install -e .
16
16
  ### As a user
17
17
 
18
18
  ```bash
19
- pipx install git+https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git
19
+ pipx install thoughtleaders-cli
20
20
  # or
21
- uv tool install git+https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git
21
+ uv tool install thoughtleaders-cli
22
22
  # or (but try to avoid it because just "pip" will not create a new venv for the product - only "uv" and "pipx" will do that)
23
- pip install git+https://github.com/ThoughtLeaders-io/thoughtleaders-cli.git
23
+ pip install thoughtleaders-cli
24
24
  ```
25
25
 
26
26
  Then set up:
@@ -54,13 +54,16 @@ tl uploads list q:code --csv
54
54
  # Show upload details (supports colon-containing IDs)
55
55
  tl uploads show 1174310:0BehkmVa7ak
56
56
 
57
- # Search channels. msn and tpp are tri-state filters (yes/no/both; default 'both').
58
- # msn = opted-in to receive sponsorship offers; tpp = exclusively TL-managed.
59
- # Both are also returned as boolean fields on every channel response.
60
- tl channels list category:cooking min-subs:100k
61
- tl channels list msn:yes # MSN channels only (~11k)
62
- tl channels list tpp:yes # TPP channels only (~169)
63
- tl channels list msn:no min-subs:500k # big non-MSN channels
57
+ # Search channels via raw SQL `tl db pg` against thoughtleaders_channel
58
+ # (run `tl schema pg` once to confirm the live column set).
59
+ tl db pg "SELECT id, channel_name, total_views FROM thoughtleaders_channel
60
+ WHERE content_category = <COOKING_CODE> AND total_views >= 100000
61
+ ORDER BY total_views DESC LIMIT 50 OFFSET 0"
62
+ tl db pg "SELECT id, channel_name FROM thoughtleaders_channel
63
+ WHERE is_tl_channel = TRUE LIMIT 200 OFFSET 0" # all TPP channels (~169)
64
+ # MSN status (media_selling_network_join_date) is scrubbed from the
65
+ # advertiser sandbox view — for MSN-only / non-MSN lookups, the
66
+ # structured filter is the right tool: `tl channels list msn:yes|no`.
64
67
 
65
68
  # Show channel detail — accepts numeric ID or channel name.
66
69
  # Names that match more than one active channel print a candidate list
@@ -75,6 +78,16 @@ tl channels show "Economics Explained"
75
78
  tl channels similar 12345 --limit 10
76
79
  tl channels similar "Tremending girls" min-score:0.85 --limit 5
77
80
 
81
+ # Vector recommender — discovery by category/demographic tag (Intelligence plan).
82
+ # `tags` is free; `top`, `inspect-*`, and `similar-to-profile` cost 50 credits flat.
83
+ tl recommender tags # List every tag (free)
84
+ tl recommender tags cooking # Search tag names by substring
85
+ tl recommender top "Cooking" msn:yes --limit 50 # Top channels & brand profiles for a tag
86
+ tl recommender top "USA share" mbn:yes # Demographic tag, MBN brands only
87
+ tl recommender inspect-channel 12345 # Per-tag breakdown of a channel's vector
88
+ tl recommender inspect-brand Nike # Per-tag breakdown of a brand's ideal vector
89
+ tl recommender similar-to-profile 842 # Channels closest to a brand profile
90
+
78
91
  # Brand intelligence
79
92
  tl brands show Nike
80
93
 
@@ -146,8 +159,6 @@ Talk naturally in Claude Code:
146
159
  Resource-specific slash commands:
147
160
  ```
148
161
  /tl-sponsorships pending with send dates in April
149
- /tl-channels cooking channels over 100k subscribers
150
- /tl-brands Nike
151
162
  /tl-reports run my Q1 pipeline
152
163
  /tl-balance
153
164
  ```
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: tl-analyst
3
+ description: Use when the user asks to analyze, compare, investigate, or summarize ThoughtLeaders data across multiple dimensions. Chains tl CLI commands to answer complex questions that require multiple queries, cross-referencing, or aggregation. Triggers on "analyze", "compare", "investigate", "deep dive", "cross-reference", "trend", "correlation".
4
+ tools: [Bash, Read]
5
+ ---
6
+
7
+ # TL Data Analyst Agent
8
+
9
+ You are an autonomous data analyst for ThoughtLeaders. You answer complex questions that require cross-referencing, aggregation, or multi-step reasoning.
10
+
11
+ ## Default to raw database queries
12
+
13
+ For anything beyond a trivially simple lookup, write a single raw query against the right engine instead of chaining structured `tl <resource>` commands:
14
+
15
+ - **Postgres (`tl db pg`)** — joins, aggregations, multi-condition filters, fields the structured commands don't expose. Default for any deal/pipeline/brand/channel question that involves more than one filter or one aggregation.
16
+ - **Elasticsearch (`tl db es`)** — transcript / brand-mention text search, video-level aggregations, demographic country-share filters that compose with content predicates.
17
+ - **Firebolt (`tl db fb`)** — custom time-series shapes (multi-channel growth comparisons, milestone-age slices). For default shapes, prefer `tl snapshots`.
18
+
19
+ Reserve structured commands for: single-record `show` by ID, plain filtered `list` with one or two filters that the structured vocabulary already supports, `tl channels similar` / `tl brands similar` (vector KNN), `tl reports run`, and `tl snapshots`.
20
+
21
+ One raw query beats N paginated structured walks stitched in `jq`/Python — on cost, latency, and the ES `from+size = 10000` cap.
22
+
23
+ ## Before Starting Any Analysis
24
+
25
+ 1. **Check auth**: `tl auth status`
26
+ 2. **Check balance**: `tl balance --json` — estimate total cost for your planned queries
27
+ 3. **Discover schema**:
28
+ - For raw queries: `tl schema pg|fb|es` — live tables/columns visible to the caller.
29
+ - For structured commands: `tl describe show <resource> --json`.
30
+ 4. **Check saved reports**: `tl reports --json` — a saved report might already answer the question
31
+
32
+ If estimated cost > 200 credits, ask the user to confirm before proceeding.
33
+
34
+ ## Analysis Patterns
35
+
36
+ ### Aggregation / pipeline analysis (raw PG)
37
+ "What's our best performing brand this quarter?"
38
+ ```sql
39
+ tl db pg "SELECT b.name, SUM(a.weighted_price) AS pipeline, COUNT(*) AS deals
40
+ FROM thoughtleaders_adlink a
41
+ JOIN thoughtleaders_profile p ON a.creator_profile_id = p.id
42
+ JOIN thoughtleaders_profile_brands pb ON p.id = pb.profile_id
43
+ JOIN thoughtleaders_brand b ON pb.brand_id = b.id
44
+ WHERE a.publish_status = 3
45
+ AND a.purchase_date >= date_trunc('quarter', CURRENT_DATE)
46
+ GROUP BY b.name
47
+ ORDER BY pipeline DESC
48
+ LIMIT 20 OFFSET 0"
49
+ ```
50
+ One query → ranked list. No client-side aggregation, no paginated walk.
51
+
52
+ ### Cross-resource analysis (raw PG)
53
+ "Show me deal slippage this month"
54
+ ```sql
55
+ tl db pg "SELECT a.id, a.send_date, a.publish_status, b.name AS brand, ch.channel_name
56
+ FROM thoughtleaders_adlink a
57
+ JOIN thoughtleaders_adspot s ON a.ad_spot_id = s.id
58
+ JOIN thoughtleaders_channel ch ON s.channel_id = ch.id
59
+ JOIN thoughtleaders_profile p ON a.creator_profile_id = p.id
60
+ JOIN thoughtleaders_profile_brands pb ON p.id = pb.profile_id
61
+ JOIN thoughtleaders_brand b ON pb.brand_id = b.id
62
+ WHERE a.publish_status = 2
63
+ AND a.send_date < CURRENT_DATE
64
+ ORDER BY a.send_date
65
+ LIMIT 100 OFFSET 0"
66
+ ```
67
+ Then suggest `tl comments add <id> "..."` for each.
68
+
69
+ ### Multi-step research (mix raw + similarity)
70
+ "Find channels similar to the ones Nike sponsors and compare their pricing"
71
+ 1. `tl db pg` to find the top channels Nike has sponsored (one aggregation, ranked).
72
+ 2. `tl channels similar <top-channel-id> --json --limit 20` per seed — vector KNN is server-side and has no SQL equivalent. The `msn:` filter is tri-state with default `msn:yes` (MSN channels only); use `msn:both` to broaden, `msn:no` for non-MSN only.
73
+ 3. Union + dedupe + compile comparison table.
74
+
75
+ ### Report comparison (saved reports)
76
+ "Compare Q1 to Q4 performance"
77
+ 1. `tl reports --json` → find relevant report ID
78
+ 2. `tl reports run <id> --since 2026-01-01 --until 2026-03-31 --json`
79
+ 3. `tl reports run <id> --since 2025-10-01 --until 2025-12-31 --json`
80
+ 4. Compute deltas and trends
81
+
82
+ ### Channel deep dive (one raw query + targeted structured calls)
83
+ "Give me a full picture of channel 12345"
84
+ 1. `tl channels show 12345 --json` → profile, scores, demographics (structured — wraps several joins already)
85
+ 2. `tl snapshots channel 12345 --json` → growth over time (snapshots wrap interpolation logic)
86
+ 3. `tl db pg "SELECT id, send_date, publish_status, price FROM thoughtleaders_adlink WHERE ad_spot_id IN (SELECT id FROM thoughtleaders_adspot WHERE channel_id = 12345) ORDER BY send_date DESC LIMIT 100 OFFSET 0"` — deal history with the columns you actually want, no over-fetch.
87
+ 4. `tl uploads list channel:12345 --json` → recent content
88
+
89
+ ### Transcript / brand-mention search (raw ES)
90
+ "Where has 'NordVPN' been mentioned organically in the last 90 days?"
91
+ ```bash
92
+ tl db es '{"size": 0, "track_total_hits": true,
93
+ "query": {"bool": {"must": [
94
+ {"term": {"organic_brand_mentions": "5612"}},
95
+ {"range": {"publication_date": {"gte": "now-90d"}}}
96
+ ]}},
97
+ "aggs": {"by_channel": {"terms": {"field": "channel.id", "size": 50}}}}'
98
+ ```
99
+
100
+ ### Demographics screenshots check (trivially simple — structured)
101
+ "Does channel X have demographics screenshots uploaded?"
102
+ 1. `tl channels show <id-or-name> --json` → check `demographics_updated_at`. Non-null = screenshots on file (timestamp = last OCR pass). Null = none uploaded.
103
+
104
+ ## Rules
105
+
106
+ - **Always resolve numeric codes to human-readable labels** in your output. Never show "Status 3" — show "Sold". Status mapping: 0=Proposed, 1=Unavailable, 2=Pending, 3=Sold, 4=Rejected by Advertiser, 5=Rejected by Publisher, 6=Proposal Approved, 7=Matched, 8=Reached Out, 9=Rejected by Agency.
107
+ - Always use `--json` for output you need to parse
108
+ - For raw `tl db pg`, prefer one well-targeted query over multiple structured walks; remember the LIMIT/OFFSET injected defaults (LIMIT 50, OFFSET 0) and the OFFSET ≥ 10000 → 403 ceiling.
109
+ - Always include `--limit` on structured list queries to control credit spend
110
+ - For `tl snapshots video`, always include `--channel` (required for Firebolt performance)
111
+ - Present final results as a clear summary with tables when appropriate
112
+ - Show total credits consumed at the end of your analysis
@@ -7,17 +7,24 @@ description: Quick sponsorship lookup. Query, filter, or show details for sponso
7
7
 
8
8
  The user wants to query sponsorships.
9
9
 
10
- 1. Run `tl describe sponsorships --json` to discover filters
10
+ For **trivially simple lookups** (single ID, one or two filters the structured vocabulary already supports), use `tl sponsorships`:
11
+ 1. Run `tl describe show sponsorships --json` to discover filters
11
12
  2. Translate the user's request into a `tl sponsorships` command
12
13
  3. Execute and present results
13
14
 
15
+ For **anything non-trivial** — aggregations (totals, group-bys, percentiles), joins (sponsorship + brand + channel + owner), multi-condition filtering the structured filters can't express, or fields the structured commands don't expose (raw `publish_status`, `weighted_price`, `tx_data`, etc.) — drop down to `tl db pg` against `thoughtleaders_adlink`. Run `tl schema pg` first to see the live column list.
16
+
14
17
  If no specific request is given, run `tl sponsorships list --limit 10` to show recent sponsorships.
15
18
 
16
- Examples:
19
+ Examples (trivial — structured):
17
20
  - "/tl-sponsorships pending with send dates in April" → `tl sponsorships list status:pending send-date:2026-04`
18
21
  - "/tl-sponsorships Nike" → `tl sponsorships list brand:"Nike"`
19
22
  - "/tl-sponsorships sold deals on mobile-first channels" → `tl sponsorships list status:sold primary-device:mobile`
20
23
  - "/tl-sponsorships deals on channels with majority US audience" → `tl sponsorships list min-us-share:50`
21
24
  - "/tl-sponsorships 12345" → `tl sponsorships show 12345`
22
25
 
26
+ Examples (non-trivial — raw `tl db pg`):
27
+ - "/tl-sponsorships total weighted pipeline by sales rep" → `tl db pg "SELECT owner_sales_id, SUM(weighted_price) AS pipeline FROM thoughtleaders_adlink WHERE publish_status IN (0,2,6,7,8) GROUP BY owner_sales_id ORDER BY pipeline DESC LIMIT 100 OFFSET 0"`
28
+ - "/tl-sponsorships sold deals this month with brand and channel name" → join `thoughtleaders_adlink` ↔ `adspot` ↔ `channel` ↔ `profile` ↔ `profile_brands` ↔ `brand` (see `references/postgres-schema.md`).
29
+
23
30
  `tl sponsorships show <id> --json` returns extended detail fields beyond the list view, including: `impressions_guarantee`, `integration`, `publish_count`, `common_name`, `outreach_email`, nested `publisher` (first_name/last_name/email), nested `brand_contact` (first_name/last_name/email), and `brand.organization_name`.
@@ -10,16 +10,16 @@ The user wants to query ThoughtLeaders data. Translate their request into the ri
10
10
  ## Steps
11
11
 
12
12
  1. Identify which resource(s) the request is about (sponsorships, deals, channels, brands, uploads, snapshots, reports)
13
- 2. Run `tl describe show <resource> --json` to discover available filters
14
- 3. Translate the user's natural language into a `tl` command with appropriate filters
13
+ 2. Discover the appropriate database structure, with `tl schema pg` and other commands, and formulate a raw database query solution first. Only use other commands like `tl sponsorships` if the user query is simple enough for it (run `tl describe show sponsorships` to see what it can do).
14
+ 3. Translate the user's natural language into a `tl` command
15
15
  4. Execute the command
16
16
  5. Present results clearly
17
17
 
18
18
  ## Examples
19
19
 
20
20
  - "/tl sold sponsorships for Nike in Q1" → `tl sponsorships list status:sold brand:"Nike" purchase-date-start:2026-01-01 purchase-date-end:2026-03-31`
21
- - "/tl cooking channels over 100k subs" → `tl channels list category:cooking min-subs:100000`
22
- - "/tl mobile-first US cooking channels" → `tl channels list category:cooking primary-device:mobile min-us-share:50`
21
+ - "/tl cooking channels over 100k subs" → `tl db pg "SELECT id, channel_name, total_views FROM thoughtleaders_channel WHERE content_category = <COOKING_CODE> AND total_views >= 100000 ORDER BY total_views DESC LIMIT 50 OFFSET 0"`
22
+ - "/tl mobile-first US cooking channels" → `tl db pg "SELECT id, channel_name, demographic_usa_share FROM thoughtleaders_channel WHERE content_category = <COOKING_CODE> AND demographic_device_primary = 'mobile' AND demographic_usa_share >= 50 ORDER BY total_views DESC LIMIT 50 OFFSET 0"`
23
23
  - "/tl Nike's sponsorship activity" → `tl brands show Nike`
24
24
  - "/tl run my Q1 report" → `tl reports --json` then `tl reports run <id>`
25
25
  - "/tl check my balance" → `tl balance`
@@ -2,12 +2,14 @@
2
2
 
3
3
  ## Context
4
4
 
5
- We're building a Python CLI (`tl`) for ThoughtLeaders that lets external customers query their sponsorship data. Inspired by Basecamp's CLI approach — agent-first, pipe-friendly, distributed as both a PyPI package and a Claude Code plugin.
5
+ We're building a Python CLI (`tl`) for ThoughtLeaders that lets external customers query their sponsorship data. Inspired by Basecamp's CLI approach — agent-first, pipe-friendly, distributed as both a PyPI package (`thoughtleaders-cli`) and a Claude Code plugin.
6
6
 
7
7
  The CLI talks to Django API endpoints (not directly to databases) so permissions are enforced server-side and no DB credentials leave our infrastructure.
8
8
 
9
9
  **Design philosophy** (following Basecamp): The CLI is a dumb tool — structured commands are the primary interface. AI intelligence comes from the user's own agent (Claude Code, etc.) using the CLI as a tool. `tl ask` exists as an optional fallback for users without an AI agent. The skill file + `tl describe` teach agents how to use the CLI effectively.
10
10
 
11
+ **Intended audience: AI agents.** The primary user of `tl` is an AI coding agent (Claude Code, OpenCode) acting on behalf of a human. Every surface — the structured commands, the discovery commands (`tl describe`, `tl schema`), the breadcrumbs in JSON envelopes, the skill file — is shaped to be parseable and self-explanatory to an agent. Where the structured commands hit a ceiling (joins, aggregations, filters they don't expose), we steer agents toward **raw database queries** via `tl db pg|fb|es`. One server-side aggregation beats N client-side roll-ups on cost, latency, and the `from+size = 10000` cap; raw queries are the right tool for heavy data work, not a last-resort escape hatch. The skill file's "When to use raw vs structured" guidance and the live `tl schema pg|fb|es` output are how we teach agents to make this trade-off.
12
+
11
13
  **Business model**: Prepaid credit balance. Customers deposit funds, credits are deducted per result returned. Different data types cost different amounts based on value. No subscriptions — pure pay-as-you-go.
12
14
 
13
15
  ## Architecture
@@ -47,22 +49,38 @@ All data commands use explicit subcommands: `list`, `show`, `create`/`add`. Runn
47
49
  | `tl uploads list [filters...]` | List video uploads (ES) |
48
50
  | `tl uploads show <id> [<id>...]` | Show upload detail(s) by ID |
49
51
  | `tl channels list [filters...]` | Search channels. Responses carry boolean `msn` (Media Selling Network) and `tpp` (TL-managed) fields; filterable via `msn:` / `tpp:` tri-state (`yes` / `no` / `both`, default `both`). |
50
- | `tl channels show <id>` | Show channel detail, including active adspots with price/cost/CPM |
51
- | `tl channels similar <id-or-name>` | Vector-similarity recommender. 50 credits; Intelligence plan. Tri-state `msn:` filter (default `yes`) and `tpp:` filter (default `both`) — each takes `yes` / `no` / `both`. Ambiguous names return 400 + candidates list. Hidden `look-alike` alias. |
52
+ | `tl channels show <id-or-name>` | Channel detail, including active adspots with price/cost/CPM |
53
+ | `tl channels history <id-or-name>` | Sponsorship history (videos with detected sponsors) |
54
+ | `tl channels similar <id-or-name>` | Vector-similarity recommender. 50 credits; Intelligence plan. Tri-state `msn:` (default `yes`) and `tpp:` (default `both`) filters. Ambiguous names return 400 + candidates list. Hidden `look-alike` alias. |
52
55
  | `tl brands show <brand>` | Brand intelligence report |
53
- | `tl brands show <brand> --channel <id>` | Brand mentions on a specific channel |
56
+ | `tl brands history <brand> [--channel <id>]` | Brand sponsorship history; videos where the brand was detected |
57
+ | `tl brands similar <brand>` | Find similar brands (profile vector KNN, 50 credits) |
54
58
  | `tl snapshots channel <id>` | Channel metrics over time (Firebolt channel_metrics) |
55
59
  | `tl snapshots video <id> --channel <id>` | Video view curve (Firebolt article_metrics, --channel required) |
56
60
  | `tl comments list <adlink-id>` | List comments on a sponsorship (free) |
57
61
  | `tl comments add <adlink-id> "message"` | Add a comment (free) |
58
62
 
63
+ ### Raw database access (escape hatch for joins / aggregations / complex filters)
64
+
65
+ | Command | Description |
66
+ |---------|-------------|
67
+ | `tl db pg "<SQL>"` | Raw read-only PostgreSQL `SELECT`. LIMIT/OFFSET optional — server fills in `LIMIT 50 OFFSET 0` defaults; explicit OFFSET ≥ 10,000 returns 403. Single statement; sqlglot-validated against an allowlist of functions. |
68
+ | `tl db fb "<SQL>"` | Raw read-only Firebolt `SELECT`. Single-table only; WHERE must filter the leading index column with an equality or `IN` literal. |
69
+ | `tl db es '<json>'` | Raw Elasticsearch search body against the server-fixed index alias. Top-level keys, query types, size/depth limits all gated server-side. |
70
+ | `tl schema pg\|fb\|es` | Print live schema docs for the matching `tl db` engine (free). PG returns the role-scoped tables/columns from `information_schema`; FB returns the live column types of accepted tables; ES returns a maintained Markdown reference. |
71
+
59
72
  ### Flexible filtering (all list commands)
60
73
  Filters are passed as `key:value` pairs after `list`:
61
74
  ```bash
62
75
  tl sponsorships list status:sold brand:"Nike" purchase-date:2026-01
63
76
  tl sponsorships list status:pending send-date:2026-03
64
77
  tl uploads list channel:12345 type:longform since:2026-03
65
- tl channels list category:cooking min-subs:100k language:en
78
+ # Channel discovery is raw SQL — the structured `tl channels list` covers
79
+ # only narrow lookups. Default to:
80
+ tl db pg "SELECT id, channel_name, total_views FROM thoughtleaders_channel
81
+ WHERE content_category = <COOKING_CODE> AND language = 'en'
82
+ AND total_views >= 1000000
83
+ ORDER BY total_views DESC LIMIT 50 OFFSET 0"
66
84
  ```
67
85
 
68
86
  Sponsorship date filtering (on `created-at`, `publish-date`, `purchase-date`, `send-date`) exposes three shapes per field:
@@ -75,10 +93,10 @@ Ranges combine freely across fields (e.g. "created in Jan that published in Marc
75
93
  | Command | Description |
76
94
  |---------|-------------|
77
95
  | `tl describe` | List all resources with credit costs |
78
- | `tl describe sponsorships` | Show fields, filters, and credit rate for sponsorships |
79
- | `tl describe sponsorships --filters` | Just the valid filters |
80
- | `tl describe sponsorships --fields` | Just the data fields |
81
- | `tl docs` | Open full docs in browser |
96
+ | `tl describe show <resource>` | Show fields, filters, and credit rate for a resource |
97
+ | `tl describe show <resource> --filters` | Just the valid filters |
98
+ | `tl describe show <resource> --fields` | Just the data fields |
99
+ | `tl schema pg\|fb\|es` | Show schema docs for raw `tl db` queries (free) |
82
100
 
83
101
  Schema metadata from server (`GET /api/cli/v1/describe/<resource>`) — always in sync. Includes credit cost per result. Free, no credits charged. Agent-friendly: `tl describe sponsorships --json`.
84
102
 
@@ -106,9 +124,11 @@ Schema metadata from server (`GET /api/cli/v1/describe/<resource>`) — always i
106
124
  | `tl doctor` | Health check (auth, connectivity, version, balance) |
107
125
  | `tl whoami` | Show current user, profile, org, and brands (free) |
108
126
  | `tl balance` | Show credit balance and recent usage |
127
+ | `tl changelog` | Show release notes |
128
+ | `tl update` | Self-upgrade (when installed via pipx or `uv tool`) |
109
129
 
110
130
  ### Global flags (all commands)
111
- `--json`, `--csv`, `--md`, `--limit N`, `--offset N`
131
+ `--json`, `--csv`, `--md`, `--toon` (token-efficient for LLMs), `--limit N`, `--offset N`
112
132
 
113
133
  ### Agent support flag
114
134
  `--help --agent` returns structured JSON help (flags, gotchas, subcommands) for any command — optimized for AI agents to parse.
@@ -125,8 +145,6 @@ Schema metadata from server (`GET /api/cli/v1/describe/<resource>`) — always i
125
145
  |---------|-------------|
126
146
  | `/tl <request>` | Smart router — Claude interprets the request and runs the right `tl` command(s). E.g., `/tl sold sponsorships for Nike in Q1` → `tl sponsorships status:sold brand:"Nike" purchase-date-start:2026-01-01 purchase-date-end:2026-03-31` |
127
147
  | `/tl-sponsorships [query]` | Quick sponsorship lookup. E.g., `/tl-sponsorships pending with send dates in April` |
128
- | `/tl-channels [query]` | Channel search. E.g., `/tl-channels cooking channels over 100k subs` |
129
- | `/tl-brands [query]` | Brand intelligence. E.g., `/tl-brands Nike` |
130
148
  | `/tl-reports` | List and run saved reports |
131
149
  | `/tl-balance` | Check credit balance and recent usage |
132
150
 
@@ -136,12 +154,13 @@ Each slash command's markdown file instructs Claude to:
136
154
  3. Execute the command and present results
137
155
  4. Show breadcrumbs for follow-up actions
138
156
 
139
- #### Skill: `tl-data-analyst`
140
- Teaches Claude how to use the CLI effectively. Triggers on data questions about sponsorships, channels, brands, uploads, metrics.
157
+ #### Skill: `tl`
158
+ Teaches Claude how to use the CLI effectively. Triggers on data questions about sponsorships, channels, brands, uploads, metrics. Authoritative source lives at `skills/tl/SKILL.md` with engine-specific reference files under `skills/tl/references/` (`postgres-schema.md`, `firebolt-schema.md`, `elasticsearch-schema.md`, `business-glossary.md`).
141
159
 
142
160
  Key instructions in the skill:
143
- - Always run `tl describe show <resource> --json` first to discover fields, filters, and credit costs
144
- - Use structured commands, not `tl ask` (the user's Claude IS the AI layer)
161
+ - Always run `tl describe show <resource> --json` (or `tl schema pg|fb|es`) first to discover fields, filters, and credit costs
162
+ - Use structured commands for single-record lookups and simple filtered lists; **switch to `tl db pg|fb|es` for aggregations, joins, and complex filtering**
163
+ - Don't use `tl ask` — the user's Claude IS the AI layer
145
164
  - Check `tl balance --json` before expensive queries and warn the user about credit cost
146
165
  - Use `--json` output for parsing
147
166
  - Chain commands for multi-step analysis (e.g., get brand → find channels → check snapshots)
@@ -179,12 +198,6 @@ After a `tl` command completes:
179
198
  - If `balance_remaining` < 500 credits, emits a warning to stderr
180
199
  - If command returned 402, provides a clear "deposit more credits" message with link
181
200
 
182
- **Stop hook** (`hooks/scripts/session-summary.sh`):
183
- When Claude finishes a session:
184
- - Summarizes total credits consumed during the session
185
- - Shows starting vs ending balance
186
- - Lists the commands that were run (parsed from session)
187
-
188
201
  ## Usage Metering & Pricing
189
202
 
190
203
  ### Prepaid credit balance
@@ -194,26 +207,31 @@ When Claude finishes a session:
194
207
  - Customers can opt-in to allow overage (keep working, settle later) — configurable in dashboard
195
208
  - `tl auth status` and `tl balance` show current credit balance
196
209
 
197
- ### Credit rates by data value
198
-
199
- | Resource | List (per result) | Detail (single) | Rationale |
200
- |----------|-------------------|-----------------|-----------|
201
- | **Brand intelligence** | 5 credits | 8 credits | Core IP — competitive intelligence on who sponsors whom |
202
- | **Channel** | 3 credits | 5 credits | Rich profile data, demographics, scores |
203
- | **Sponsorship** | 2 credits | 3 credits | User's own sponsorship data |
204
- | **Snapshot** (Firebolt) | 1 credit | 1 credit | Time-series data points, high volume |
205
- | **Upload** (video) | 1 credit | 2 credits | Individual video data |
206
- | **Report run** | Sum of result credits | — | Charged based on what the report returns |
207
- | **Comment** | 0 | 0 | Operational — don't charge |
208
- | **Sponsorship create** | 0 | — | Free — more proposals = more future data consumption |
209
- | **Describe / auth / doctor** | 0 | 0 | System + discoverability must be free |
210
- | **`tl ask` surcharge** | +2 credits per result | — | LLM cost surcharge (waived if user provides own key) |
211
-
212
- ### Credit formula per request
210
+ ### Credit rates pricing intent
211
+
212
+ Detail and history endpoints charge a flat `rate × results` (linear). List endpoints (and raw `tl db`) use a non-linear curve so a 0-row pull still pays a small floor and a 500-row pull doesn't pay 500× a 1-row pull:
213
+
213
214
  ```
214
- credits = sum(results × rate_per_result) + surcharge_if_ask
215
+ list cost = setup + mult × scale × n^exp
215
216
  ```
216
217
 
218
+ `setup`, `scale`, and `exp` are global shape parameters; `mult` is a per-resource complexity factor (lighter reads use 1.0, raw `tl db` uses 1.4). The live values are in `thoughtleaders/cli_metering.py` (`CLI_LIST_COST_*` settings + `CREDIT_RATES`); the live values are reported by `tl describe`.
219
+
220
+ Rationale per resource — pricing follows data value:
221
+
222
+ | Resource | Why it's priced where it is |
223
+ |----------|-----------------------------|
224
+ | **Brand intelligence** | Core IP — competitive intelligence on who sponsors whom |
225
+ | **Channels** | Rich profile data, demographics, scores |
226
+ | **Sponsorships** | User's own sponsorship data |
227
+ | **Snapshots** (Firebolt) | Time-series data points, high volume → cheap |
228
+ | **Uploads** (video) | Individual video data |
229
+ | **Raw `tl db pg\|fb\|es`** | No role scoping, wider blast radius → 1.4× multiplier |
230
+ | **Reports run** | Charged on what the report returns |
231
+ | **Comments / proposal create** | Operational — free, more proposals = more future data consumption |
232
+ | **Describe / schema / auth / doctor / whoami / balance / changelog** | System + discoverability must be free |
233
+ | **`tl ask` surcharge** | LLM cost surcharge (waived if user provides own key via `--llm-key`) |
234
+
217
235
  ### Server-side metering implementation
218
236
 
219
237
  **New Django model**: `CliCreditAccount`
@@ -292,26 +310,29 @@ tl-cli/
292
310
  │ │ ├── matches.py # tl matches (shortcut: status:match)
293
311
  │ │ ├── proposals.py # tl proposals (shortcut: status:proposal)
294
312
  │ │ ├── uploads.py # tl uploads (list/show)
295
- │ │ ├── channels.py # tl channels (list/show)
296
- │ │ ├── brands.py # tl brands show (brand intelligence)
297
- │ │ ├── snapshots.py # tl snapshots (Firebolt metrics)
298
- │ │ ├── reports.py # tl reports / tl reports run
299
- │ │ ├── comments.py # tl comments (list/add)
300
- │ │ ├── describe.py # tl describe list/show (schema/filter/pricing discovery)
301
- │ │ ├── ask.py # tl ask (optional AI fallback)
302
- │ │ ├── setup.py # tl setup claude / tl setup opencode
303
- │ │ ├── balance.py # tl balance
304
- │ │ ├── doctor.py # tl doctor
305
- │ │ └── whoami.py # tl whoami
313
+ │ │ ├── channels.py # tl channels (list/show/history/similar)
314
+ │ │ ├── brands.py # tl brands (show/history/similar)
315
+ │ │ ├── snapshots.py # tl snapshots (Firebolt metrics)
316
+ │ │ ├── reports.py # tl reports / tl reports run
317
+ │ │ ├── comments.py # tl comments (list/add)
318
+ │ │ ├── db.py # tl db pg|fb|es (raw read-only queries)
319
+ │ │ ├── schema.py # tl schema pg|fb|es (live schema docs)
320
+ │ │ ├── describe.py # tl describe list/show (schema/filter/pricing discovery)
321
+ │ │ ├── changelog.py # tl changelog (release notes)
322
+ │ │ ├── ask.py # tl ask (optional AI fallback)
323
+ │ │ ├── setup.py # tl setup claude / tl setup opencode
324
+ │ │ ├── balance.py # tl balance
325
+ │ │ ├── doctor.py # tl doctor
326
+ │ │ └── whoami.py # tl whoami
327
+ │ ├── self_update.py # tl update (pipx/uv self-upgrade)
328
+ │ ├── hints.py # Inline tips & post-error suggestions
306
329
  │ ├── filters.py # key:value filter parser (parsing only)
307
- │ └── _completions.py # Shell completion helpers
330
+ │ └── _completions.py # Shell completion helpers
308
331
  ├── .claude-plugin/
309
332
  │ └── plugin.json # Claude Code plugin manifest
310
333
  ├── commands/ # Slash commands for Claude Code
311
334
  │ ├── tl.md # /tl — smart router
312
335
  │ ├── tl-sponsorships.md # /tl-sponsorships — quick sponsorship lookup
313
- │ ├── tl-channels.md # /tl-channels — channel search
314
- │ ├── tl-brands.md # /tl-brands — brand intelligence
315
336
  │ ├── tl-reports.md # /tl-reports — saved reports
316
337
  │ └── tl-balance.md # /tl-balance — credit balance
317
338
  ├── skills/
@@ -323,8 +344,7 @@ tl-cli/
323
344
  │ ├── hooks.json # Hook event bindings
324
345
  │ └── scripts/
325
346
  │ ├── pre-check.sh # Auth + credit guard before tl commands
326
- ├── post-usage.sh # Low balance warning after tl commands
327
- │ └── session-summary.sh # Credit usage summary on session end
347
+ └── post-usage.sh # Low balance warning after tl commands
328
348
  ├── tests/
329
349
  │ ├── __init__.py
330
350
  │ ├── test_auth.py
@@ -334,7 +354,7 @@ tl-cli/
334
354
  │ └── test_commands.py
335
355
  └── .github/
336
356
  └── workflows/
337
- └── release.yml # PyPI publish on tag
357
+ └── python-publish.yml # PyPI publish on release (Trusted Publishing)
338
358
  ```
339
359
 
340
360
  ### Server Side (in existing thoughtleaders repo)
@@ -450,17 +470,18 @@ Auth0 token → Django User → Profile → Organization → Plan. Plan types de
450
470
  ```toml
451
471
  [project]
452
472
  name = "thoughtleaders-cli"
453
- requires-python = ">=3.10"
473
+ requires-python = ">=3.12"
454
474
  dependencies = [
455
475
  "typer[all]>=0.12",
456
476
  "rich>=13.0",
457
477
  "httpx>=0.27",
458
478
  "keyring>=25.0",
459
479
  "authlib>=1.3",
480
+ "toon-format>=0.9.0b1",
460
481
  ]
461
482
  ```
462
483
 
463
- Entry point: `tl = "tl_cli.main:app"`
484
+ Entry point: `tl = "tl_cli.main:cli"`
464
485
 
465
486
  ## Auth Strategy
466
487
 
@@ -514,7 +535,7 @@ Build each command + its server endpoint together:
514
535
 
515
536
  ### Step 3: Plugin + commands + agent + hooks
516
537
  1. `.claude-plugin/plugin.json`
517
- 2. `commands/` — slash commands (`/tl`, `/tl-sponsorships`, `/tl-channels`, `/tl-brands`, `/tl-reports`, `/tl-balance`)
538
+ 2. `commands/` — slash commands (`/tl`, `/tl-sponsorships`, `/tl-reports`, `/tl-balance`)
518
539
  3. `skills/tl/SKILL.md` — comprehensive skill file
519
540
  4. `agents/tl-analyst.md` — multi-step analysis agent
520
541
  5. `hooks/` — pre-check, post-usage, session-summary
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "thoughtleaders-cli"
7
- version = "0.5.0"
7
+ version = "0.6.0"
8
8
  description = "ThoughtLeaders CLI — query sponsorship data, channels, brands, and intelligence"
9
9
  readme = "README.md"
10
10
  license = "MIT"