thoughtleaders-cli 0.6.52__tar.gz → 0.6.54__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.
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/.claude-plugin/plugin.json +1 -1
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/PKG-INFO +1 -1
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/pyproject.toml +1 -1
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl/SKILL.md +9 -2
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-import/SKILL.md +11 -11
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/SKILL.md +3 -1
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/intelligence_filterset_schema.json +15 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/SKILL.md +501 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/columns_brands.md +82 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/columns_channels.md +99 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/columns_content.md +78 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/columns_sponsorships.md +96 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/intelligence_filterset_schema.json +407 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/intelligence_widget_schema.json +193 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/report_glossary.md +145 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/sortable_columns.json +64 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/sponsorship_filterset_schema.json +217 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/sponsorship_widget_schema.json +165 -0
- thoughtleaders_cli-0.6.54/skills/tl-save-report/references/widgets.md +184 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/__init__.py +1 -1
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/reports.py +132 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/.claude-plugin/marketplace.json +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/.github/workflows/python-publish.yml +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/.gitignore +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/AGENTS.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/API.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/CLAUDE.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/LICENSE +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/README.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/agents/tl-analyst.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/hooks/hooks.json +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/hooks/scripts/load-tl-skill.mjs +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/hooks/scripts/post-usage.sh +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/hooks/scripts/pre-check.sh +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl/references/business-glossary.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl/references/elasticsearch-schema.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl/references/firebolt-schema.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl/references/postgres-schema.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-keyword-research/SKILL.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-keyword-research/scripts/probe.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/examples/e2e_findings.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/examples/golden_queries.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/columns_brands.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/columns_channels.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/columns_content.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/columns_sponsorships.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/intelligence_widget_schema.json +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/report_glossary.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/sortable_columns.json +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/sponsorship_filterset_schema.json +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/sponsorship_widget_schema.json +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/references/widgets.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/tools/column_builder.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/tools/database_query.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/tools/name_resolver.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/tools/sample_judge.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/tools/similar_channels.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/tools/topic_matcher.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/skills/tl-report-builder/tools/widget_builder.md +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/_completions.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/auth/__init__.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/auth/commands.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/auth/finalize.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/auth/login.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/auth/pkce.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/auth/token_store.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/client/__init__.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/client/errors.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/client/http.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/__init__.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/_comments_common.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/balance.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/brands.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/bulk_import.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/changelog.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/channels.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/credits.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/db.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/deals.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/describe.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/doctor.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/matches.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/proposals.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/recommender.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/schema.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/setup.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/snapshots.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/sponsorships.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/uploads.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/commands/whoami.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/config.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/filters.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/hints.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/main.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/output/__init__.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/output/formatter.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/src/tl_cli/self_update.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/tests/__init__.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/tests/test_auth.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/tests/test_filters.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/tests/test_http_auth.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/tests/test_output.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/tests/test_reports.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/tests/test_sponsorships.py +0 -0
- {thoughtleaders_cli-0.6.52 → thoughtleaders_cli-0.6.54}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: thoughtleaders-cli
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.54
|
|
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
|
|
@@ -140,7 +140,14 @@ Unless the user specifically asks for running a specific report or showing the r
|
|
|
140
140
|
3. **Decide the method of discovery**: If the user want to explore certain topics, use the recommender commands. If it's more about filtering, construct a query for PG or ES.
|
|
141
141
|
4. **Always use --json**: Parse JSON output for multi-step analysis.
|
|
142
142
|
5. **Chain commands**: For complex questions, chain multiple `tl` commands, shell commands, and other tools.
|
|
143
|
-
6. **Format results**: When the user asks for a list or tabular data, present the results as a well-formatted markdown table. Pick the most relevant columns and use clear headers. Sort the result by relevant criteria - if the user asked for "top performers", order by the performance metric; if the user asked for "most recent", sort by the pertinent date desc.
|
|
143
|
+
6. **Format results**: When the user asks for a list or tabular data, present the results as a well-formatted markdown table. Pick the most relevant columns and use clear headers. Sort the result by relevant criteria - if the user asked for "top performers", order by the performance metric; if the user asked for "most recent", sort by the pertinent date desc.
|
|
144
|
+
7. **Always offer to save the result as a report — if the rows fit a report type.** A "fits a report type" result is a table whose rows are **channels**, **brands**, **videos / uploads**, or **sponsorships / deals**. When that's the case, after the table close the reply with a save offer — don't wait for the user to ask. Suggested phrasing (adapt the noun to the entity):
|
|
145
|
+
|
|
146
|
+
> *Want me to save this as a saved TL report you can come back to? Say "save it as a report" and I'll ask whether you want a filter-style report (predicates re-evaluated on every run) or a list-style report (these exact IDs frozen).*
|
|
147
|
+
|
|
148
|
+
If the user says yes (or uses any of the save-trigger phrases, like `save it`, `save the list`, `make a report`, `persist this`, `turn this into a campaign`, `I want to come back to this`), invoke the `tl-save-report` skill — it owns the filter-vs-list decision flow, the FilterSet mapping, and the `tl reports create` / `tl reports save-list` save call. **Don't try to compose the report config yourself**; hand off to the skill.
|
|
149
|
+
|
|
150
|
+
Skip the save offer when the result clearly doesn't fit a report type — a single scalar count, an aggregate roll-up across entity types, view-curve time series, schema introspection output, or anything that isn't a list of channels / brands / videos / sponsorships. A trailing offer on those would just be noise.
|
|
144
151
|
|
|
145
152
|
Prefer writing shell code, `jq` commands, or `duckdb` commands that fetch or analysise large sets of data instead of analysing it yourself. On Mac and Linux, create temporary files in `/tmp` that can be analysed later in different ways. On Windows, create them in `%USERPROFILE%\AppData\Local\Temp`. Before analysing a potentially large result set, first try fetching just a single result with `LIMIT 1` without `jq` etc, to see the shape of the data and any error messages.
|
|
146
153
|
|
|
@@ -414,7 +421,7 @@ Load these on demand — don't read all upfront. Pick the one(s) relevant to the
|
|
|
414
421
|
|---|---|---|
|
|
415
422
|
| Arbitrary read-only `SELECT` on Postgres | **Available** via `tl db pg`. | SELECT-only, mandatory `LIMIT ≤ 500` + `OFFSET`, only certain SQL forms are allowed. See `references/postgres-schema.md`. |
|
|
416
423
|
| Cross-reference helpers ("channels proposed to brand X", "channels sponsored by MBN brands in last N days") | **Available** via `tl db pg`. | Write the join: `thoughtleaders_adlink` ↔ `adspot` ↔ `channel` ↔ `profile` ↔ `profile_brands` ↔ `brand`. Filter by `publish_status` for proposed/sold and by date range as needed. See `references/postgres-schema.md` for the exact column names. |
|
|
417
|
-
| **AdLink INSERT** with custom price/cost/owner/`weighted_price`/`created_where` | **Unavailable** — `tl sponsorships create` exists but only creates a
|
|
424
|
+
| **AdLink INSERT** with custom price/cost/owner/`weighted_price`/`created_where` | **Unavailable** — `tl sponsorships create` exists but only creates a *proposal* between a channel and a brand. The `tl db pg` sanitizer accepts SELECT only — no INSERT/UPDATE. | Done in the app or by a human with DB access. |
|
|
418
425
|
| Pre-insert validation queries (joining `adspot ↔ channel ↔ profile ↔ org` to confirm MSN, integration=1, persona, plan) | **Available** via `tl db pg`. | One SELECT joining the four tables. Use `thoughtleaders_channel.media_selling_network_join_date IS NOT NULL` for MSN, `thoughtleaders_adspot.integration = 1` for mention adspots, `thoughtleaders_profile.persona` for the persona code (see persona constants in `references/postgres-schema.md`). |
|
|
419
426
|
| Firebolt cross-table or join queries; filtering on non-indexed columns in WHERE | **Unavailable** — not accepted. | Fetch a wider slice keyed on `channel_id` (and optionally `id`), filter the rest in `jq`/Python. |
|
|
420
427
|
| ES `query_string`, `regexp`, `wildcard`, `fuzzy`, `more_like_this`, parent/child joins; any `script_*`; multiple aggregations in one body | **Unavailable** — not accepted. | Rewrite using `term`/`terms`/`match`/`bool`/`nested`. For multi-agg dashboards, run multiple `tl db es` calls and combine client-side. For "similar"-style queries, try `tl channels similar` / `tl brands similar` (server-implemented similarity search). |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tl-import
|
|
3
|
-
description: Import a list of channels, brands, uploads (videos), or sponsorships into a ThoughtLeaders report — either an existing report (caller supplies `campaign_id` or a TL report URL) or a fresh new one (skill creates a minimal container, then populates). Superuser-only. **Trigger on explicit intent to import the listed entities into a report**, NOT on the mere presence of a list (a user can paste a list and want analysis, comparison, or similar-channel discovery — those go to `tl-cli:tl
|
|
3
|
+
description: Import a list of channels, brands, uploads (videos), or sponsorships into a ThoughtLeaders report — either an existing report (caller supplies `campaign_id` or a TL report URL) or a fresh new one (skill creates a minimal container, then populates). Superuser-only. **Trigger on explicit intent to import the listed entities into a report**, NOT on the mere presence of a list (a user can paste a list and want analysis, comparison, or similar-channel discovery — those go to `tl-cli:tl`). The deciding question is: *would the user be satisfied if those exact entities ended up as the report's contents, no transformation?* If yes, this is the skill. Phrasings: "import these channels into report 1234", "add brands to campaign 5678", "exclude these channels from report Z", "bulk-add these videos to report X", "create a new report with these channels: <list>", "make a campaign containing these brands: <list>".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# tl-import
|
|
@@ -21,7 +21,7 @@ Trigger on:
|
|
|
21
21
|
- "Make a campaign containing these brands: \<list\>" → **new-report flow**
|
|
22
22
|
- "Build me a report from these adlinks: \<list\>" → **new-report flow** *(the verb "build" doesn't matter — what matters is that the user wants exactly those adlinks in the report.)*
|
|
23
23
|
|
|
24
|
-
**Do NOT trigger** when the user pastes a list but wants something other than direct import — those belong to `tl-cli:tl
|
|
24
|
+
**Do NOT trigger** when the user pastes a list but wants something other than direct import — those belong to `tl-cli:tl` (analysis / discovery) or `tl-cli:tl-save-report` (persist a session's result set):
|
|
25
25
|
|
|
26
26
|
- *"Find me channels similar to these: \<list\>"* — discovery using the list as a seed, not as the answer.
|
|
27
27
|
- *"Build a report of TPP channels in the same niche as these: \<list\>"* — discovery with filters and similarity expansion.
|
|
@@ -46,7 +46,7 @@ Never silently create a new report when the destination is ambiguous; never sile
|
|
|
46
46
|
|
|
47
47
|
## Create a fresh container first (new-report flow only)
|
|
48
48
|
|
|
49
|
-
The user wants the report to contain exactly the identifiers they're about to import — nothing else. No keyword research, no discovery query, no review pipeline. Just a minimal container that holds the list. **The persistence step
|
|
49
|
+
The user wants the report to contain exactly the identifiers they're about to import — nothing else. No keyword research, no discovery query, no review pipeline. Just a minimal container that holds the list. **The persistence step is `tl reports create --config-file`** with a tiny config — no upstream discovery / review phases.
|
|
50
50
|
|
|
51
51
|
Steps:
|
|
52
52
|
|
|
@@ -57,11 +57,11 @@ Steps:
|
|
|
57
57
|
- `brands` → **2** (BRANDS)
|
|
58
58
|
- `articles` (uploads/videos) → **1** (CONTENT)
|
|
59
59
|
- `sponsorships` (adlinks/deals) → **8** (CAMPAIGN_MANAGEMENT)
|
|
60
|
-
4. **Pick default columns.** Read the matching columns reference file in the sibling `tl-report
|
|
61
|
-
- channels → `../tl-report
|
|
62
|
-
- brands → `../tl-report
|
|
63
|
-
- articles → `../tl-report
|
|
64
|
-
- sponsorships → `../tl-report
|
|
60
|
+
4. **Pick default columns.** Read the matching columns reference file in the sibling `tl-save-report` skill and use its **"Defaults — always include"** section — that's where the canonical column list lives per type; do NOT restate it here. The four files:
|
|
61
|
+
- channels → `../tl-save-report/references/columns_channels.md`
|
|
62
|
+
- brands → `../tl-save-report/references/columns_brands.md`
|
|
63
|
+
- articles → `../tl-save-report/references/columns_content.md`
|
|
64
|
+
- sponsorships → `../tl-save-report/references/columns_sponsorships.md`
|
|
65
65
|
|
|
66
66
|
Convert each display name from the "Defaults — always include" list into a column entry shape **`{"display": true, "width": "default"}`** — the `width` field is required by the dashboard's column renderer; without it, columns sometimes resolve but cells render empty. Use `"wide"` for narrative columns (e.g. `TL Channel Summary`, `Channel Description`, `Topic Descriptions`); use `"narrow"` for short numeric columns (e.g. `Status`, `Country`); `"default"` everywhere else is safe.
|
|
67
67
|
|
|
@@ -75,7 +75,7 @@ Steps:
|
|
|
75
75
|
}
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
Per-type default sort. **Critical invariant:** the `sort` field must reference a `backend_code` whose display-name column is in the column set you emitted in step 4. The dashboard's renderer rejects sorts pointing at columns that aren't present in the report. So pick the intersection of (a) the type's "Defaults — always include" columns from `columns_<type>.md` and (b) sortable columns from `../tl-report
|
|
78
|
+
Per-type default sort. **Critical invariant:** the `sort` field must reference a `backend_code` whose display-name column is in the column set you emitted in step 4. The dashboard's renderer rejects sorts pointing at columns that aren't present in the report. So pick the intersection of (a) the type's "Defaults — always include" columns from `columns_<type>.md` and (b) sortable columns from `../tl-save-report/references/sortable_columns.json`:
|
|
79
79
|
|
|
80
80
|
| report_type | entity | default `sort` | maps to (must be in column set) |
|
|
81
81
|
|---|---|---|---|
|
|
@@ -101,7 +101,7 @@ Steps:
|
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
`type: 2` is DYNAMIC (the only valid campaign type for save). `filterset: {}` is intentional — no keyword/topic/demographic filters; the report's contents will come entirely from the include list bulk-import populates next. **`dataset_structure` is what makes the rows render with actual values** — leave it out and the dashboard shows row numbers but blank cells.
|
|
104
|
-
7. **Persist
|
|
104
|
+
7. **Persist with `tl reports create --config-file`.** Write the config dict to a temp file using your file-writing tool — **do not use shell `echo` or heredocs**, those break on titles containing apostrophes, dollar signs, backticks, etc. The whole point of `--config-file` is to bypass shell quoting entirely. Pick any temp path the agent's filesystem tool can write to (e.g. `/tmp/tl-import-container.json` on Unix, the OS temp dir on Windows).
|
|
105
105
|
|
|
106
106
|
Then run:
|
|
107
107
|
|
|
@@ -282,7 +282,7 @@ These are envelope-level failures, distinct from per-row `reason` values:
|
|
|
282
282
|
|
|
283
283
|
## What this skill does NOT do
|
|
284
284
|
|
|
285
|
-
- Doesn't run
|
|
285
|
+
- Doesn't run a discovery pipeline (keyword research, topic matching, validation cycles, review). When a user gives a fixed list of identifiers, they've already done the discovery themselves — the report is a container for their list, not a query result. Use the `tl` skill to *find* channels/brands/etc. by criteria first; if the user then wants to save those criteria as a live report, use `tl-save-report`.
|
|
286
286
|
- Doesn't change existing report metadata (title, description, columns, filters) after creation. For that, use the platform UI or a dedicated edit flow. The new-report flow in this skill sets minimum-required metadata once at creation and never revisits it.
|
|
287
287
|
- Doesn't validate identifiers ahead of time — submit and let the per-row `reason` tell the user which ones failed. Pre-checking with `tl channels show` / etc. is wasteful (metered) and adds latency.
|
|
288
288
|
- Doesn't sweep duplicates from the user's input list — submit them as-is. The response will mark the second occurrence as `Duplicate`, which is more informative than silently deduping.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tl-report-builder
|
|
3
3
|
description: |
|
|
4
|
-
|
|
4
|
+
**MANUAL-INVOCATION-ONLY skill — do NOT auto-trigger on natural-language report requests.** This skill is invoked explicitly by the user (via the `/tl-report-builder` slash command, by naming the skill directly, or via some other unambiguous indication). Phrases like "build me a report", "make a campaign", "find me channels with filters Y", or "save this as a report" do NOT route here automatically. Those phrases go to other skills: the `tl` skill (for analysis / exploration of channels / brands / videos / sponsorships), `tl-save-report` (for persisting an in-chat session's result set as a saved report — filter-style or list-style), or `tl-import` (for adding identifiers to an existing report). This skill itself builds a brand-new TL report config from scratch through a heavy four-phase orchestration (routing → schema + validation → columns → widgets), covering the four report types: content/videos (1), brands (2), channels (3), sponsorships/deals (8). Only fire it when the user has explicitly chosen this path — there's almost always a lighter skill that's the right answer.
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# TL Report Builder Skill
|
|
9
9
|
|
|
10
|
+
> **Manual invocation only.** This skill is heavy (four phases, multiple tool fires, sample validation against live data, FilterSet schema mapping). It is not the default for "I want a list of channels" or "save this as a report" — those are `tl` and `tl-save-report` respectively. Reach this skill only when the user has explicitly invoked it.
|
|
11
|
+
|
|
10
12
|
Translate natural-language report requests into the campaign config JSON the TL dashboard accepts (a `Campaign` + `FilterSet` payload, ready to commit). The skill owns the orchestration end-to-end; sub-tools are invoked conditionally from within the Schema phase based on explicit criteria. Every phase may pause for follow-up interaction with the user when input is ambiguous, incomplete, or invalid.
|
|
11
13
|
|
|
12
14
|
## Core Objective
|
|
@@ -349,6 +349,21 @@
|
|
|
349
349
|
"_tl_django_m2m": "FilterSet.exclude_brands via FilterSetExcludeBrand"
|
|
350
350
|
},
|
|
351
351
|
|
|
352
|
+
"articles": {
|
|
353
|
+
"type": ["array", "null"],
|
|
354
|
+
"items": { "type": "string", "minLength": 3, "pattern": "^[0-9]+:[A-Za-z0-9_-]+$" },
|
|
355
|
+
"uniqueItems": true,
|
|
356
|
+
"description": "Resolved article (video / upload) IDs in the composite form `<channel_id>:<youtube_id>` (matches ES `_id`). M2M list — when populated, the report returns exactly these IDs, no filter logic. Used for list-style report-type-1 (CONTENT) reports.",
|
|
357
|
+
"_tl_django_m2m": "FilterSet.articles via FiltersetArticles"
|
|
358
|
+
},
|
|
359
|
+
"exclude_articles": {
|
|
360
|
+
"type": ["array", "null"],
|
|
361
|
+
"items": { "type": "string", "minLength": 3, "pattern": "^[0-9]+:[A-Za-z0-9_-]+$" },
|
|
362
|
+
"uniqueItems": true,
|
|
363
|
+
"description": "Article IDs to exclude (composite `<channel_id>:<youtube_id>` form). Pairs with a predicate-style FilterSet — useful for 'videos matching X, except these specific ones'.",
|
|
364
|
+
"_tl_django_m2m": "FilterSet.exclude_articles via FiltersetExcludeArticles"
|
|
365
|
+
},
|
|
366
|
+
|
|
352
367
|
"networks": {
|
|
353
368
|
"type": ["array", "null"],
|
|
354
369
|
"items": { "type": "integer", "minimum": 1 },
|