diff --git a/third_party/x/.cursor-plugin/plugin.json b/third_party/x/.cursor-plugin/plugin.json index 129505b8..5ca54ee8 100644 --- a/third_party/x/.cursor-plugin/plugin.json +++ b/third_party/x/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "x", "displayName": "X", - "version": "2.1.0", + "version": "2.2.0", "minClientVersions": { "cursor": "3.13.0" }, diff --git a/third_party/x/CHANGELOG.md b/third_party/x/CHANGELOG.md index dcde62a2..5254dfe9 100644 --- a/third_party/x/CHANGELOG.md +++ b/third_party/x/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this plugin will be documented here. +## 2.2.0 — Credit balance on connect + +- Agents fetch `GET /2/usage/credits` on connect, at session start when X calls are needed, and when the user asks what they can do. The capabilities message now includes the dollar balance and 2–3 ideas that fit it. +- Added budget-tier workflows (from $0 through $1,000+) so suggestions scale with remaining credits. If a job would exceed the balance, offer a cheaper alternative and send the user to https://console.x.com. + ## 2.1.0 — X MCP guide skill - Added the X MCP guide skill: tells agents how to handle sign-in, onboarding, and out-of-credits errors with simple user-facing messages, plus session-start, search, pagination, and cost-aware workflow rules. diff --git a/third_party/x/skills/x-api-mcp-guide/SKILL.md b/third_party/x/skills/x-api-mcp-guide/SKILL.md index 1fb1d089..69e983eb 100644 --- a/third_party/x/skills/x-api-mcp-guide/SKILL.md +++ b/third_party/x/skills/x-api-mcp-guide/SKILL.md @@ -3,19 +3,50 @@ name: X MCP guide description: >- ALWAYS read this when a user connects the X plugin or any X MCP, before using any X connection, and again on any X error. Do not call an X tool until this - file has been read in the current turn. On first connect, send the user the - capabilities message defined here. Estimate the cost of every X call before - making it and confirm with the user before anything expensive. + file has been read in the current turn. On first connect, fetch the credit + balance, send the capabilities message defined here, and suggest work that + fits their balance. Estimate the cost of every X call before making it and + confirm with the user before anything expensive. --- # X MCP guide This plugin uses **X MCP**. The user taps Connect and signs in with X. They are not setting up an API app. -Probe the current user before search, timeline, bookmarks, or news. On a core error, stop. Name the simple issue, then the next step. Do not explain enrollment mechanics, billing internals, Connected vs enrolled, or pay-per-use. Never retry 401 / 403-enrollment / credits-blocked unchanged. Never ask for keys. Never tell them to create an app, Project, or Production env. +Probe the current user and their credit balance before search, timeline, bookmarks, or news. On a core error, stop. Name the simple issue, then the next step. Do not explain enrollment mechanics, billing internals, Connected vs enrolled, or pay-per-use. Never retry 401 / 403-enrollment / credits-blocked unchanged. Never ask for keys. Never tell them to create an app, Project, or Production env. + +## Credit balance + +Call **`get_usage_credits`** (`GET /2/usage/credits`). It is free. + +Response (values are **USD dollars and cents**; `20.0` = $20.00): + +```json +{ + "data": { + "free_balance": 20.0, + "free_grants": [ + { "amount": 10.0, "expires_at": "2026-11-19T02:14:28.000Z" }, + { "amount": 10.0, "expires_at": "2026-11-19T16:02:51.000Z" } + ], + "prepaid_balance": 0.0, + "total_balance": 20.0 + } +} +``` + +Use **`data.total_balance`** only. Cache it as `{credits}`. Quote it to the user in dollars (`$20.00`). Ignore `free_balance`, `free_grants`, and `prepaid_balance` — do not explain them or choose what to spend. + +Fetch it: + +1. **On connect** — before the capabilities message. +2. **When a session starts and X calls are required** — alongside `get_users_me`. +3. **When the user asks what they can do** — ideas, a setup, a budget, “what’s possible,” and similar. + +Do not fetch on every message. If this call hits error 1, 2, or 3, stop and say that error’s line. ## On connect -The first time the user connects X — or on their first X interaction in a session — send this capabilities message once. Adapt the wording to your voice, keep every line of content: +The first time the user connects X — or on their first X interaction in a session — fetch `{credits}`, then send this capabilities message once. Adapt the wording to your voice. Keep every capability bullet. Then state their balance and suggest **2–3** things from the matching [By budget](#by-budget) row (plus a cheaper starter if useful). Do not pitch work above `{credits}`. > You're connected to X. Here's what I can do: > @@ -26,9 +57,15 @@ The first time the user connects X — or on their first X interaction in a sess > - **News & trends** — search X news stories and get trends by location > - **Bookmarks** — list, add, and remove bookmarks, and organize them into folders > -> Requests use credits: you'll need to purchase credits at https://console.x.com for this to work. I'll show you a cost estimate before anything expensive. +> You have about $X.XX in credits. +> +> With that, we could: (2–3 ideas from the matching budget row). +> +> I'll show a cost estimate before anything expensive. Add credits anytime at https://console.x.com. + +If `{credits}` is ~$0, keep the bullets, say they have $0.00, suggest only free lookups, and send them to https://console.x.com — skip “With that, we could.” -Send it once per session, not on every message. If their first message already contains an ask, send this first, then do the ask. +Send it once per session, not on every message. If their first message already contains an ask, send this first, then do the ask if it fits the balance. ## The three errors @@ -62,7 +99,7 @@ Do not retry. Do not search. Do not mention apps, projects, or pay-per-use. If t > You're out of credits. Go to https://console.x.com and add credits, then I'll retry. -Stop. Do not retry. +Stop. Do not retry. Offer a free or cheaper alternative from [By budget](#by-budget) if one exists. If the payload is only `usage-capped` (no enrollment reason): @@ -103,18 +140,16 @@ If `user-not-enrolled` or `client-not-enrolled` is present, that is #2, not this ## Session start -Resolve the current user (`user.fields=id,name,username,description,public_metrics`). +When X calls are required this session, resolve the current user (`user.fields=id,name,username,description,public_metrics`) and fetch `{credits}`. | Result | Next | | ---------------- | ------------------------------------------------------------------------------------ | -| Success | Cache `id` as `{me}`. Do their ask. Prefer `{me}` for timeline, mentions, bookmarks. | +| Success | Cache `id` as `{me}` and `total_balance` as `{credits}`. Do their ask if it fits. Prefer `{me}` for timeline, mentions, bookmarks. | | Error 1, 2, or 3 | Stop. Say that error's line. Do not search. | | 200 + `errors[]` | Keep `data`. | - - ## Cost awareness Every X call can charge the user. Estimate the cost **before** calling. Read [references/pricing.md](references/pricing.md) — it has the tool-by-tool price table, per-endpoint prices, free endpoints, and cost-saving tips. Once per session, fetch live pricing from https://console.x.com/api/credits/pricing (plain GET, no auth); it wins over the reference file. @@ -123,11 +158,11 @@ The live payload: - `eventTypePricing` — price **per resource returned** (each post, user, news story…). - `requestTypePricing` — price **per request** (writes, counts, trends…). -- All prices are **USD dollars**: `0.005` = $0.005 = half a cent. Fractional cents to 3 decimal places are normal. $1.00 = 1,000 credits — that conversion is for your own math; quote costs to the user in dollars only. +- All prices are **USD dollars**: `0.005` = $0.005 = half a cent. Fractional cents to 3 decimal places are normal. $1.00 = 1,000 credits — that conversion is for your own math; quote costs to the user in dollars only. `{credits}` from `/2/usage/credits` is already dollars. Estimate = (resources requested × per-resource price) + per-request price. `max_results` bounds a read: a search with `max_results=100` returning posts + expanded authors can cost ~100 × $0.005 + 100 × $0.01. Each pagination page bills again. Only request expansions you'll use — expanded objects bill too. -**Under ~$0.25:** just do it — don't nag about pennies. Keep `max_results` small (10–25) unless they asked for more. +**Under ~$0.25, and it fits `{credits}`:** just do it — don't nag about pennies. Keep `max_results` small (10–25) unless they asked for more. **Over ~$0.25, or any pagination loop / bulk job:** stop first. Give a one-line estimate and ask: @@ -135,6 +170,8 @@ Estimate = (resources requested × per-resource price) + per-request price. `max Wait for a yes. Never silently run multi-page loops, full-archive searches, or bulk lookups. If they say yes, track spend as you go; if the running total will pass roughly double the estimate, stop and re-confirm. +**Estimate larger than `{credits}`:** do not run it. Offer a cheaper alternative from [By budget](#by-budget) that fits. Tell them this would run them out, and send them to https://console.x.com to add credits. If they top up, re-fetch `{credits}` before retrying. + ## Fields, pagination Request fields. If the tool takes `tweet.fields` or `post.fields`, send `created_at,public_metrics,author_id,lang,conversation_id`. Also `user.fields=created_at,description,public_metrics,verified,location` and `expansions=author_id,referenced_tweets.id`. @@ -166,7 +203,30 @@ Spaces = AND. Recent query max 512 characters; full-archive 1,024. Use `min_like ## Workflows -Current user first. Stop on errors 1–3. +Current user first. Stop on errors 1–3. Tailor suggestions to `{credits}`. + +### By budget + +Pick from the **matching row**, not above it. Larger jobs still need an estimate and a yes. `$0.005`/post, `$0.01`/user, expansions bill too. + + +| `{credits}` | Suggest | +| ----------- | ------- | +| ~$0 | `{me}` (free). Likers of a post (free). Bookmark folders (free). Then: add credits at https://console.x.com. | +| under ~$0.25 | One post from a link. One user by handle. Recent post counts on a topic. | +| ~$0.25–$1 | A small search (10–25 posts). One page of home or mentions. | +| ~$1–$5 | A few targeted searches. News on a topic plus trends for a location. Tidy bookmarks. | +| ~$5–$20 | Compare 2–3 accounts (profile + recent posts). A short research pass: counts, then a couple of search angles. | +| ~$20–$50 | Deeper research: several angles, a handful of accounts, news on the topic. One account’s recent posts across a few pages (confirm). | +| ~$50–$100 | A full-archive slice on one query. A competitive set of ~5–10 accounts. Paginated timelines (confirm). | +| ~$100–$500 | Large archive jobs. Many queries or many accounts. Broad topic monitoring across pages — always confirm. | +| ~$500–$1,000 | Org-scale historical pulls. Multi-query archive. Large comparative studies — confirm each large chunk. | +| $1,000+ | Very large archive / bulk historical. Long-running research. Never silent pagination; confirm every large chunk. | + + +When they ask what they can do, re-fetch `{credits}`, then give 2–3 ideas from the matching row. + +### Common tasks - Home / mentions / my posts: `{me}`, modest `max_results`. Paginate only if asked. - Handle: username → posts. Else user search, then ask. @@ -174,13 +234,11 @@ Current user first. Stop on errors 1–3. - Bookmarks: list `{me}`. Save: parse status id, create bookmark. - One post: parse status id, lookup. - - ## Don't -- Explain deep details (pay-per-use, Connected vs enrolled, billing internals). Do name the simple issue. +- Explain deep details (pay-per-use, Connected vs enrolled, billing internals, free vs prepaid grants). Do name the simple issue. - Say pay-per-use, Project, Production, or "create an app". - Ask for secrets. - Retry 403 or credits-blocked in a loop. +- Pitch or run work above `{credits}`. If it wouldn't fit, offer a cheaper alternative and send them to https://console.x.com. - Run an expensive request (over ~$0.25, pagination loops, bulk lookups) without giving an estimate and getting a yes. - diff --git a/third_party/x/skills/x-api-mcp-guide/references/pricing.md b/third_party/x/skills/x-api-mcp-guide/references/pricing.md index 07852593..f59240b5 100644 --- a/third_party/x/skills/x-api-mcp-guide/references/pricing.md +++ b/third_party/x/skills/x-api-mcp-guide/references/pricing.md @@ -14,6 +14,7 @@ Reference prices for cost estimates. May drift; the live endpoint https://consol | Tool | Wraps | Cost | |---|---|---| | `get_users_me` | `GET /2/users/me` | free | +| `get_usage_credits` | `GET /2/usage/credits` | free | | `get_users_by_id` / `get_users_by_username` / `get_users_by_usernames` / `search_users` | user lookup/search | $0.01/user | | `get_posts_by_id` / `get_posts_by_ids` / `search_posts_all` / `get_posts_quoted_posts` | post lookup/search | $0.005/post | | `get_users_posts` / `get_users_mentions` / `get_users_timeline` / `get_users_bookmarks` | user timelines | $0.005/post ($0.001 own data) | @@ -116,6 +117,7 @@ Reference prices for cost estimates. May drift; the live endpoint https://consol ## Free endpoints (no per-use charge) - `GET /2/users/me` +- `GET /2/usage/credits` (MCP: `get_usage_credits`) - `GET /2/tweets/:id/liking_users` - `GET /2/media` · `GET /2/media/:media_key` - Bookmark folders: `GET /2/users/:id/bookmarks/folders` (and by folder id) · folder create